001/* 002 * Copyright (c) 2012, 2013, Werner Keil, Credit Suisse (Anatole Tresch). Licensed under the Apache 003 * License, Version 2.0 (the "License"); you may not use this file except in compliance with the 004 * License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 005 * Unless required by applicable law or agreed to in writing, software distributed under the License 006 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 007 * or implied. See the License for the specific language governing permissions and limitations under 008 * the License. Contributors: Anatole Tresch - initial version. 009 */ 010package org.javamoney.tck.tests; 011 012import org.javamoney.tck.TCKTestSetup; 013import org.javamoney.tck.tests.internal.TestAmount; 014import org.javamoney.tck.tests.internal.TestCurrencyUnit; 015import org.javamoney.tck.tests.internal.TestMonetaryAmountBuilder; 016import org.jboss.test.audit.annotations.SpecAssertion; 017import org.jboss.test.audit.annotations.SpecVersion; 018import org.testng.AssertJUnit; 019import org.testng.annotations.Test; 020 021import javax.money.CurrencyUnit; 022import javax.money.MonetaryAmount; 023import javax.money.MonetaryAmountFactory; 024import javax.money.MonetaryAmountFactoryQuery; 025import javax.money.MonetaryAmountFactoryQueryBuilder; 026import javax.money.Monetary; 027import javax.money.MonetaryException; 028import javax.money.MonetaryOperator; 029import javax.money.MonetaryRounding; 030import javax.money.RoundingQuery; 031import javax.money.RoundingQueryBuilder; 032import java.math.BigDecimal; 033import java.math.RoundingMode; 034import java.util.Collection; 035import java.util.Currency; 036import java.util.Locale; 037import java.util.Set; 038 039import static org.junit.Assert.assertNotNull; 040 041 042/** 043 * Test class for accessing currencies and amounts. 044 */ 045@SpecVersion(spec = "JSR 354", version = "1.0.0") 046public class AccessingCurrenciesAmountsRoundingsTest { 047 048 // ****************** A. Accessing Currencies ******************* 049 050 /** 051 * Test if Monetary provides all ISO related entries, 052 * similar to the JDK. 053 */ 054 @Test(description = "4.2.7 Test if Monetary provides all ISO related entries similar to " + 055 "java.util.Currency.") 056 @SpecAssertion(section = "4.2.7", id = "427-A1") 057 public void testAllISOCurrenciesAvailable() { 058 for (Currency currency : Currency.getAvailableCurrencies()) { 059 AssertJUnit.assertTrue( 060 "Section 4.2.7: Currency not available [Monetary#isCurrencyAvailable(String)] for JDK " + 061 "currency code: " + 062 currency.getCurrencyCode(), 063 Monetary.isCurrencyAvailable(currency.getCurrencyCode())); 064 AssertJUnit.assertNotNull( 065 "Section 4.2.7: Currency null [Monetary#igetCurrency(String)] for JDK currency code: " + 066 currency.getCurrencyCode(), Monetary.getCurrency(currency.getCurrencyCode())); 067 } 068 } 069 070 /** 071 * Test if Monetary provides all Locale related 072 * entries, similar to the JDK (for all ISO countries). 073 */ 074 @Test(description = "4.2.7 Test if Monetary provides all locale related entries similar to " + 075 "java.util.Currency.") 076 @SpecAssertion(section = "4.2.7", id = "427-A2") 077 public void testAllLocaleCurrenciesAvailable() { 078 for (String country : Locale.getISOCountries()) { 079 Locale locale = new Locale("", country); 080 if (Currency.getInstance(locale) != null) { 081 AssertJUnit.assertTrue( 082 "Section 4.2.7: Currency not available [Monetary#isCurrencyAvailable(Locale)] for " + 083 "locale: " + 084 locale, Monetary.isCurrencyAvailable(locale)); 085 AssertJUnit 086 .assertNotNull("Currency null [Monetary#igetCurrency(Locale)] for locale: " + locale, 087 Monetary.getCurrencies(locale)); 088 Collection<CurrencyUnit> units = Monetary.getCurrencies(locale); 089 CurrencyUnit requiredCurrency = null; 090 for (CurrencyUnit cu : units) { 091 if (Currency.getInstance(locale).getCurrencyCode().equals(cu.getCurrencyCode())) { 092 requiredCurrency = cu; 093 break; 094 } 095 } 096 AssertJUnit.assertNotNull( 097 "Section 4.2.7: No Currency returned from [Monetary#getCurrencies(Locale)] for " + 098 "locale: " + 099 locale, requiredCurrency); 100 AssertJUnit.assertEquals( 101 "Section 4.2.7: Invalid Currency returned from [Monetary#getCurrencies(Locale)] for" + 102 " " + 103 "locale: " + 104 locale + 105 ", expected: " + Currency.getInstance(locale) + ", found: " + requiredCurrency, 106 Monetary.getCurrency(Currency.getInstance(locale).getCurrencyCode()), 107 requiredCurrency); 108 } 109 } 110 } 111 112 /** 113 * Test if Monetary provides correct instance with ISO 114 * codes. 115 */ 116 @Test(description = "4.2.7 Test if Monetary provides correct ISO related entries similar to " + 117 "java.util.Currency.") 118 @SpecAssertion(section = "4.2.7", id = "427-A3") 119 public void testCorrectISOCodes() { 120 for (Currency currency : Currency.getAvailableCurrencies()) { 121 CurrencyUnit unit = Monetary.getCurrency(currency.getCurrencyCode()); 122 AssertJUnit.assertEquals( 123 "Section 4.2.7: Invalid Currency code returned from [Monetary#igetCurrency(String)] for" + 124 " currency code:" + 125 " " + 126 currency.getCurrencyCode() + ", expected: " + 127 Currency.getInstance(currency.getCurrencyCode()).getCurrencyCode() + 128 ", found: " + unit.getCurrencyCode(), 129 Currency.getInstance(currency.getCurrencyCode()).getCurrencyCode(), unit.getCurrencyCode()); 130 AssertJUnit.assertEquals( 131 "Section 4.2.7: Invalid numeric code returned from [Monetary#igetCurrency(String)] for " + 132 "currency code: " + 133 currency.getCurrencyCode() + ", expected: " + 134 Currency.getInstance(currency.getCurrencyCode()).getNumericCode() + 135 ", found: " + unit.getNumericCode(), 136 Currency.getInstance(currency.getCurrencyCode()).getNumericCode(), unit.getNumericCode()); 137 AssertJUnit.assertEquals( 138 "Section 4.2.7: Invalid default fraction unit returned from [Monetary#igetCurrency" + 139 "(String)] for " + 140 "currency code: " + 141 currency.getCurrencyCode() + ", expected: " + 142 Currency.getInstance(currency.getCurrencyCode()).getDefaultFractionDigits() + 143 ", found: " + unit.getDefaultFractionDigits(), 144 Currency.getInstance(currency.getCurrencyCode()).getDefaultFractionDigits(), 145 unit.getDefaultFractionDigits()); 146 } 147 } 148 149 /** 150 * Test if Monetary provides correct instance with 151 * Locales. 152 */ 153 @Test(description = "4.2.7 Test if Monetary provides correct locale related entries similar to " + 154 "java.util.Currency.") 155 @SpecAssertion(section = "4.2.7", id = "427-A4") 156 public void testCorrectLocales() { 157 158 Monetary.getCurrencies(new Locale("", "AD")); 159 160 for (String country : Locale.getISOCountries()) { 161 Locale locale = new Locale("", country); 162 if (Currency.getInstance(locale) == null) { 163 continue; 164 } 165 Set<CurrencyUnit> units = Monetary.getCurrencies(locale); 166 AssertJUnit.assertNotNull( 167 "Section 4.2.7: Invalid Currencies (null) returned from [Monetary#igetCurrencies" + 168 "(Locale)] for" + 169 " locale: " + 170 locale, units); 171 AssertJUnit.assertFalse( 172 "Section 4.2.7 Empty Currencies returned from [Monetary#igetCurrencies(Locale)] for" + 173 " locale: " + 174 locale, units.isEmpty()); 175 CurrencyUnit requiredCurrency = null; 176 for (CurrencyUnit cu : units) { 177 if (Currency.getInstance(locale).getCurrencyCode().equals(cu.getCurrencyCode())) { 178 requiredCurrency = cu; 179 break; 180 } 181 } 182 AssertJUnit.assertNotNull("Section 4.2.7: Required Currency missing in result returned from " + 183 "[Monetary#igetCurrency(Locale)] for" + 184 " locale: " + 185 locale + ", expected: " + Currency.getInstance(locale).getCurrencyCode() + 186 ", found: " + units, requiredCurrency); 187 AssertJUnit.assertEquals( 188 "Section 4.2.7: Invalid numeric code returned from [Monetary#igetCurrency(Locale)] for " + 189 "locale: " + 190 locale + ", expected: " + Currency.getInstance(locale).getNumericCode() + 191 ", found: " + requiredCurrency.getNumericCode(), 192 Currency.getInstance(locale).getNumericCode(), requiredCurrency.getNumericCode()); 193 AssertJUnit.assertEquals( 194 "Section 4.2.7: Invalid default fraction unit returned from [Monetary#igetCurrency" + 195 "(Locale)] for " + 196 "locale: " + 197 locale + ", expected: " + Currency.getInstance(locale).getDefaultFractionDigits() + 198 ", found: " + requiredCurrency.getDefaultFractionDigits(), 199 Currency.getInstance(locale).getDefaultFractionDigits(), 200 requiredCurrency.getDefaultFractionDigits()); 201 } 202 } 203 204 /** 205 * Test for custom Monetary provided, based on the TCK 206 * TestProvider. 207 */ 208 @Test(description = "4.2.7 Test if Monetary provides customized locale identified currencies.") 209 @SpecAssertion(section = "4.2.7", id = "427-A5") 210 public void testCustomCurrencies() { 211 Locale testLocale = new Locale("lang", "count", "test"); 212 Set<CurrencyUnit> cus = Monetary.getCurrencies(testLocale); 213 AssertJUnit.assertNotNull("Section 4.2.7: TestCurrency not returned for locale: " + testLocale, cus); 214 AssertJUnit.assertFalse("Section 4.2.7: TestCurrency not returned for locale: " + testLocale, cus.isEmpty()); 215 AssertJUnit.assertEquals("Section 4.2.7: Unexpected CurrencyUnit class returned.", TestCurrencyUnit.class, 216 cus.iterator().next().getClass()); 217 CurrencyUnit cu = Monetary.getCurrency("FOOLS_test"); 218 AssertJUnit.assertNotNull("Section 4.2.7: TestCurrency not returned for currency code: FOOLS_test", cu); 219 AssertJUnit.assertEquals("Section 4.2.7: Unexpected CurrencyUnit class returned.", TestCurrencyUnit.class, 220 cu.getClass()); 221 } 222 223 // ********************************* B. Accessing Monetary Amount Factories *********************** 224 225 /** 226 * Ensure amount factories are accessible for all types 227 * available, 228 * providing also the 229 * some test implementations with the 230 * TCK. 231 */ 232 @Test(description = "4.2.7 Ensure amount classes to test are setup and registered/available in Monetary.") 233 @SpecAssertion(section = "4.2.7", id = "427-B2") 234 public void testAmountTypesProvided() { 235 Collection<Class> amountClasses = TCKTestSetup.getTestConfiguration().getAmountClasses(); 236 AssertJUnit.assertNotNull(amountClasses); 237 AssertJUnit.assertFalse(amountClasses.isEmpty()); 238 Collection<Class<? extends MonetaryAmount>> providedClasses = Monetary.getAmountTypes(); 239 for (Class amountType : amountClasses) { 240 AssertJUnit.assertTrue("Section 4.2.7: Amount class not registered: " + amountType.getName(), 241 providedClasses.contains(amountType)); 242 } 243 AssertJUnit.assertTrue("Section 4.2.7: TCK Amount class not registered: " + TestAmount.class, 244 providedClasses.contains(TestAmount.class)); 245 } 246 247 /** 248 * Ensure amount factories are accessible for all types 249 * available, 250 * providing also the 251 * some test implementations with the 252 * TCK, 253 * and that 254 * every factory accessed 255 * is a new instance. 256 */ 257 @Test(description = "4.2.7 Ensure amount factories are accessible for all types available in Monetary.") 258 @SpecAssertion(section = "4.2.7", id = "427-B3") 259 public void testAmountTypesInstantiatable() { 260 Collection<Class> amountClasses = TCKTestSetup.getTestConfiguration().getAmountClasses(); 261 for (Class amountType : amountClasses) { 262 MonetaryAmountFactory<?> f = Monetary.getAmountFactory(amountType); 263 AssertJUnit.assertNotNull("Section 4.2.7: MonetaryAmountFactory returned by Monetary is null for " + 264 amountType.getName(), f); 265 MonetaryAmountFactory<?> f2 = Monetary.getAmountFactory(amountType); 266 AssertJUnit.assertNotNull("Section 4.2.7: MonetaryAmountFactory returned by Monetary is null for " + 267 amountType.getName(), f2); 268 AssertJUnit.assertNotSame("MonetaryAmountFactory instances are not distinct for " + amountType.getName(), f, 269 f2); 270 TestCurrencyUnit tc = new TestCurrencyUnit(); 271 MonetaryAmount m1 = f.setNumber(0L).setCurrency(tc).create(); 272 AssertJUnit.assertNotNull( 273 "Section 4.2.7: MonetaryAmountFactory creates null amounts for " + amountType.getName(), m1); 274 AssertJUnit.assertTrue( 275 "Section 4.2.7: MonetaryAmountFactory creates non zero amounts for " + amountType.getName(), 276 m1.isZero()); 277 AssertJUnit.assertEquals( 278 "Section 4.2.7: MonetaryAmountFactory creates non zero amounts for " + amountType.getName(), 0L, 279 m1.getNumber().longValue()); 280 AssertJUnit.assertTrue( 281 "Section 4.2.7: MonetaryAmountFactory creates non assignable amounts instances for " + 282 amountType.getName(), amountType.isAssignableFrom(m1.getClass())); 283 } 284 MonetaryAmountFactory<?> f = Monetary.getAmountFactory(TestAmount.class); 285 AssertJUnit.assertNotNull("Section 4.2.7: MonetaryAmountFactory returned by Monetary is null for " + 286 TestAmount.class.getName(), f); 287 AssertJUnit.assertEquals("MonetaryAmountFactory returned by Monetary is obfuscated or proxied for " + 288 TestMonetaryAmountBuilder.class.getName(), TestMonetaryAmountBuilder.class, 289 f.getClass()); 290 } 291 292 /** 293 * Ensure correct query function implementations, providing also 294 * the some test implementations with the TCK. 295 */ 296 @Test(description = 297 "4.2.7 Ensure correct query function, Monetary.getAmountFactories should return factory" + 298 "for explicit acquired amount types.") 299 @SpecAssertion(section = "4.2.7", id = "427-B4") 300 public void testAmountQueryType() { 301 MonetaryAmountFactoryQuery ctx = MonetaryAmountFactoryQueryBuilder.of().setTargetType(TestAmount.class).build(); 302 Collection<MonetaryAmountFactory<?>> factories = Monetary.getAmountFactories(ctx); 303 AssertJUnit.assertNotNull("Section 4.2.7: Amount factory query should return explicitly queried factories", 304 factories); 305 boolean found = false; 306 for (MonetaryAmountFactory<?> f : factories) { 307 if (f.getAmountType().equals(TestAmount.class)) { 308 found = true; 309 break; 310 } 311 } 312 AssertJUnit.assertTrue("Section 4.2.7: Amount type query should return same explicitly queried factory", found); 313 ctx = MonetaryAmountFactoryQueryBuilder.of().build(); 314 MonetaryAmountFactory<?> factory = Monetary.getAmountFactory(ctx); 315 AssertJUnit.assertNotNull("Section 4.2.7: Amount type must be provided", factory); 316 } 317 318 /** 319 * Ensure a default factory is returned. Test javamoney.config 320 * for configuring default value. 321 */ 322 @Test(description = "4.2.7 Ensure a default MonetaryAmountFactory is available.") 323 @SpecAssertion(section = "4.2.7", id = "427-B5") 324 public void testAmountDefaultType() { 325 AssertJUnit.assertNotNull("Section 4.2.7: No default MonetaryAmountFactory found.", 326 Monetary.getDefaultAmountFactory()); 327 } 328 329 // ********************************* C. Accessing Roundings ***************************** 330 331 /** 332 * Access roundings using all defined currencies, including TCK 333 * custom currencies. 334 */ 335 @Test(description = "4.2.7 Ensure Monetary instances are available, for all registered currencies.") 336 @SpecAssertion(section = "4.2.7", id = "427-C1") 337 public void testAccessRoundingsForCustomCurrencies_Default() { 338 // Using default roundings... 339 TestCurrencyUnit cu = new TestCurrencyUnit("ASDF", 3); 340 MonetaryRounding r = Monetary.getDefaultRounding(); 341 MonetaryAmount m = 342 new TestMonetaryAmountBuilder().setNumber(new BigDecimal("12.123456789101222232323")).setCurrency(cu) 343 .create(); 344 AssertJUnit.assertEquals( 345 "Section 4.2.7 Expected ASDF 12.123 with default rounding from ASDF 12.123456789101222232323", 346 "ASDF 12.123", m.with(r).toString()); 347 // should not throw an error! 348 for (Currency currency : Currency.getAvailableCurrencies()) { 349 m = new TestMonetaryAmountBuilder().setNumber(new BigDecimal("12.123456789101222232323")) 350 .setCurrency(currency.getCurrencyCode()).create(); 351 if (currency.getDefaultFractionDigits() >= 0) { 352 MonetaryAmount rounded = m.with(r); // should not throw an error 353 AssertJUnit.assertEquals( 354 "Section 4.2.7: Returned amount class must be the same as the input class to the rounding " + 355 "operator.", TestAmount.class, rounded.getClass()); 356 AssertJUnit.assertEquals("Section 4.2.7: Rounding did change currency: " + rounded.getClass().getName(), 357 currency.getCurrencyCode(), rounded.getCurrency().getCurrencyCode()); 358 AssertJUnit.assertNotSame( 359 "Section 4.2.7: Rounding did not have any effect, should use scale==2 as default.", 360 m.getNumber().getScale(), rounded.getNumber().getScale()); 361 } 362 } 363 } 364 365 /** 366 * Access roundings using all defined currencies, including TCK 367 * custom currencies. 368 */ 369 @Test(description = "4.2.7 Ensure Monetary instances are available, also for any custom currency " + 370 "(not registered).") 371 @SpecAssertion(section = "4.2.7", id = "427-C1") 372 public void testAccessRoundingsForCustomCurrencies_Explicit() { 373 // Using default roundings... 374 TestCurrencyUnit cu = new TestCurrencyUnit("ASDF", 3); 375 MonetaryOperator r = Monetary.getRounding(cu); 376 MonetaryAmount m = 377 new TestMonetaryAmountBuilder().setNumber(new BigDecimal("12.123456789101222232323")).setCurrency(cu) 378 .create(); 379 AssertJUnit.assertEquals("Section 4.2.7 Expected ASDF 12.123 for custom rounding 12.123456789101222232323.", 380 "ASDF 12.123", m.with(r).toString()); 381 // should not throw an error! 382 for (Currency currency : Currency.getAvailableCurrencies()) { 383 if (currency.getDefaultFractionDigits() >= 0) { 384 r = Monetary.getRounding(cu); 385 m = m.with(r); // should not throw an error 386 AssertJUnit.assertEquals( 387 "Section 4.2.7 Expected ASDF 12.123 for rounding for Currency" + cu.getCurrencyCode(), 388 "ASDF 12.123", m.with(r).toString()); 389 } else { 390 try { 391 r = Monetary.getRounding(cu); 392 AssertJUnit.assertNotNull(r); 393 } catch (MonetaryException e) { 394 // OK 395 } 396 } 397 } 398 } 399 400 /** 401 * Access roundings using all defined currencies, including TCK 402 * custom currencies. 403 */ 404 @Test(expectedExceptions = NullPointerException.class, 405 description = "4.2.7 Expected NullPointerException accessing a rounding with " + 406 "'Monetary.getRounding(null)'.") 407 @SpecAssertion(section = "4.2.7", id = "427-C1") 408 public void testAccessRoundingsForCustomCurrencies_Explicit_Null() { 409 Monetary.getRounding((CurrencyUnit) null); 410 } 411 412 413 /** 414 * Access roundings using a MonetaryContext. Use different 415 * MathContext/RoundingMode, as an attribute, when running 416 * on the JDK. 417 */ 418 @Test(description = "4.2.7 Ensure correct MonetaryRounding returned for a mathematical RoundingQuery.") 419 @SpecAssertion(section = "4.2.7", id = "427-C2") 420 public void testAccessRoundingsWithRoundingContext() { 421 RoundingQuery ctx = RoundingQueryBuilder.of().setScale(1).set(RoundingMode.UP).build(); 422 MonetaryOperator r = Monetary.getRounding(ctx); 423 AssertJUnit.assertNotNull("Section 4.2.7: No rounding provided for RoundingQuery: " + ctx, r); 424 MonetaryAmount m = 425 new TestMonetaryAmountBuilder().setNumber(new BigDecimal("12.123456789101222232323")).setCurrency("CHF") 426 .create(); 427 AssertJUnit.assertEquals("Section 4.2.7: Invalid rounding provided for RoundingQuery: " + ctx, "CHF 12.2", 428 m.with(r).toString()); 429 } 430 431 /** 432 * Access roundings using a RoundingContext, that is null. 433 */ 434 @Test(expectedExceptions = NullPointerException.class, 435 description = "4.2.7 Ensure NullPointerException is thrown for " + 436 "'Monetary.getRounding((RoundingContext) null)'.") 437 @SpecAssertion(section = "4.2.7", id = "427-C2") 438 public void testAccessRoundingsWithMonetaryContext_Null() { 439 Monetary.getRounding(null); 440 } 441 442 /** 443 * Access custom roundings and ensure TCK custom roundings are 444 * registered. 445 */ 446 @Test(description = "4.2.7 Access named roundings and ensure TCK named roundings are " + "registered.") 447 @SpecAssertion(section = "4.2.7", id = "427-C3") 448 public void testAccessCustomRoundings() { 449 Set<String> ids = Monetary.getRoundingNames(); 450 AssertJUnit.assertNotNull("Section 4.2.7: Custom Rounding key are null", ids); 451 AssertJUnit 452 .assertTrue("Section 4.2.7: At least NOSCALE custom rounding must be present", ids.contains("NOSCALE")); 453 } 454 455 /** 456 * Test TCK custom roundings. 457 */ 458 @Test(description = "4.2.7 Access custom roundings and ensure correct functionality.") 459 @SpecAssertion(section = "4.2.7", id = "427-C4") 460 public void testCustomRoundings() { 461 MonetaryOperator r = Monetary.getRounding("NOSCALE"); 462 AssertJUnit.assertNotNull(r); 463 MonetaryAmount m = 464 new TestMonetaryAmountBuilder().setNumber(new BigDecimal("12.123456789101222232323")).setCurrency("CHF") 465 .create(); 466 AssertJUnit.assertEquals("Section 4.2.7 Expected CHF 12 for NOSCALE operator on " + m, "CHF 12", 467 m.with(r).toString()); 468 } 469 470 /** 471 * Test TCK custom roundings. 472 */ 473 @Test(expectedExceptions = NullPointerException.class, 474 description = "4.2.7 Ensure NullPointerException is thrown for Monetary.getRounding((String) null).") 475 @SpecAssertion(section = "4.2.7", id = "427-C4") 476 public void testCustomRoundings_Null() { 477 Monetary.getRounding((String) null); 478 } 479 480 /** 481 * Test TCK custom roundings. 482 */ 483 @Test(expectedExceptions = MonetaryException.class, 484 description = "4.2.7 Ensure MonetaryException is thrown for " + "accessing invalid named rounding.") 485 @SpecAssertion(section = "4.2.7", id = "427-C4") 486 public void testCustomRoundings_Foo() { 487 assertNotNull("Section 4.2.7 Expected custom rounding with name 'foo'.", Monetary.getRounding("foo")); 488 } 489 490}