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.TestUtils;
013import org.javamoney.tck.tests.internal.TestAmount;
014import org.jboss.test.audit.annotations.SpecAssertion;
015import org.jboss.test.audit.annotations.SpecVersion;
016import org.testng.AssertJUnit;
017import org.testng.annotations.Test;
018
019import javax.money.CurrencyUnit;
020import javax.money.MonetaryAmount;
021import javax.money.MonetaryAmountFactory;
022import javax.money.Monetary;
023import javax.money.MonetaryContext;
024import javax.money.MonetaryContextBuilder;
025import javax.money.MonetaryException;
026import javax.money.UnknownCurrencyException;
027import java.math.BigDecimal;
028import java.util.Collection;
029import java.util.Currency;
030
031import static org.testng.AssertJUnit.assertNotNull;
032import static org.testng.AssertJUnit.assertTrue;
033
034/**
035 * Test class for creating new amounts.
036 */
037@SpecVersion(spec = "JSR 354", version = "1.0.0")
038public class CreatingMonetaryAmountsTest {
039
040    // ************************ A. Accessing MonetaryAmount Factories ************************
041
042    /**
043     * Access a MonetaryAmountFactory for each registered type.
044     */
045    @Test(description = "4.2.6 Ensure MonetaryAmountFactory instances are accessible for all amount types under test.")
046    @SpecAssertion(section = "4.2.6", id = "426-A1")
047    public void testAccessToMonetaryAmountFactory() {
048        for (Class type : Monetary.getAmountTypes()) {
049            assertNotNull("Section 4.2.6: No MonetaryAmountFactory available for " + type.getName(),
050                    Monetary.getAmountFactory(type));
051        }
052    }
053
054    /**
055     * For each MonetaryAmountFactory: Check if getAmountType returns the correct type.
056     */
057    @Test(description =
058            "4.2.6 Ensure MonetaryAmountFactory instances accessible for all amount types under test return " +
059                    "correct amount type.")
060    @SpecAssertion(section = "4.2.6", id = "426-A2")
061    public void testMonetaryAmountFactoryReturnsCorrectType() {
062        for (Class type : Monetary.getAmountTypes()) {
063            AssertJUnit.assertEquals(
064                    "Section 4.2.6: MonetaryAmountFactory declares invalid amount type for " + type.getName(), type,
065                    Monetary.getAmountFactory(type).getAmountType());
066        }
067    }
068
069    /**
070     * For each MonetaryAmountFactory: Check if capabilities of default MonetaryContext are less, or equal
071     * than Max
072     * MonetaryContext.
073     */
074    @Test(description =
075            "4.2.6 Ensure MonetaryAmountFactory instances accessible for all amount types under test return " +
076                    "correct min/max MonetaryContext.")
077    @SpecAssertion(section = "4.2.6", id = "426-A3")
078    public void testMonetaryAmountFactoryMinMaxCapabilities() {
079        for (Class type : Monetary.getAmountTypes()) {
080            MonetaryAmountFactory<?> f = Monetary.getAmountFactory(type);
081            MonetaryContext defCtx = f.getDefaultMonetaryContext();
082            MonetaryContext maxCts = f.getMaximalMonetaryContext();
083            assertTrue("Section 4.2.6: MonetaryAmountFactory default/max declares invalid precisions for " +
084                            type.getName(),
085                    maxCts.getPrecision() == 0 || defCtx.getPrecision() <= maxCts.getPrecision());
086            assertTrue(
087                    "Section 4.2.6: MonetaryAmountFactory default/max declares invalid scales for " + type.getName(),
088                    maxCts.getMaxScale() == -1 || defCtx.getMaxScale() <= maxCts.getMaxScale());
089        }
090    }
091
092    /**
093     * Checks if capabilities of default MonetaryContext are less than Max MonetaryContext.
094     */
095    @Test(description =
096            "4.2.6 Ensure MonetaryAmountFactory instances accessible for all amount types under test return " +
097                    "correct min/max MonetaryContext (min <= max).")
098    @SpecAssertion(section = "4.2.6", id = "426-A4")
099    public void testMonetaryAmountFactoryMinMaxCapabilities_Compare() {
100        for (Class type : Monetary.getAmountTypes()) {
101            MonetaryAmountFactory<?> f = Monetary.getAmountFactory(type);
102            MonetaryContext defCtx = f.getDefaultMonetaryContext();
103            MonetaryContext maxCtx = f.getMaximalMonetaryContext();
104            if (f.getDefaultMonetaryContext().getMaxScale() > -1) {
105                assertTrue(
106                        "Section 4.2.6: MonetaryAmountFactory maximal MonetaryContext cannot be less capable than the" +
107                                " default " +
108                                "(maxScale default/max=" +
109                                f.getDefaultMonetaryContext().getMaxScale() + '/' +
110                                f.getMaximalMonetaryContext().getMaxScale() + " for " + type.getName(),
111                        maxCtx.getMaxScale() == -1 || defCtx.getMaxScale() <= maxCtx.getMaxScale());
112            }
113            if (f.getDefaultMonetaryContext().getMaxScale() == -1) {
114                assertTrue(
115                        "Section 4.2.6: MonetaryAmountFactory maximal MonetaryContext cannot be less capable than the" +
116                                " default " +
117                                "(maxScale default/max=" +
118                                f.getDefaultMonetaryContext().getMaxScale() + '/' +
119                                f.getMaximalMonetaryContext().getMaxScale() + " for " + type.getName(),
120                        maxCtx.getMaxScale() == -1);
121            }
122            if (f.getDefaultMonetaryContext().getPrecision() > 0) {
123                assertTrue(
124                        "Section 4.2.6: MonetaryAmountFactory maximal MonetaryContext cannot be less capable than the" +
125                                " default " +
126                                "(precision default/max=" +
127                                f.getDefaultMonetaryContext().getPrecision() + '/' +
128                                f.getMaximalMonetaryContext().getPrecision() + " for " + type.getName(),
129                        maxCtx.getPrecision() == 0 || defCtx.getPrecision() <= maxCtx.getPrecision());
130            }
131            if (f.getDefaultMonetaryContext().getPrecision() == 0) {
132                assertTrue(
133                        "Section 4.2.6: MonetaryAmountFactory maximal MonetaryContext cannot be less capable than the" +
134                                " default " +
135                                "(precision default/max=" +
136                                f.getDefaultMonetaryContext().getPrecision() + '/' +
137                                f.getMaximalMonetaryContext().getPrecision() + " for " + type.getName(),
138                        maxCtx.getPrecision() == 0);
139            }
140        }
141    }
142
143    // **************** B. Testing Creation of Amounts with zero values ******************
144
145    /**
146     * For each MonetaryAmountFactory: Create zero amounts from a
147     * factory with currencies.
148     */
149    @Test(description = "4.2.6 Ensure MonetaryAmountFactory instances support creation of 0 amounts.")
150    @SpecAssertion(section = "4.2.6", id = "426-B1")
151    public void testMonetaryAmountFactoryCreateZeroAmountsWithDiffCurrencies() {
152        for (Class type : Monetary.getAmountTypes()) {
153            if (type.equals(TestAmount.class)) {
154                continue;
155            }
156            for (Currency cur : Currency.getAvailableCurrencies()) {
157                CurrencyUnit cu = Monetary.getCurrency(cur.getCurrencyCode());
158                MonetaryAmountFactory<?> f = Monetary.getAmountFactory(type);
159                f.setCurrency(cu);
160                f.setNumber(0);
161                MonetaryAmount m = f.create();
162                AssertJUnit.assertEquals(
163                        "Section 4.2.6: Amount created with factory has invalid currency for " + type.getName(), cu,
164                        m.getCurrency());
165                AssertJUnit.assertEquals(
166                        "Section 4.2.6: Amount created with factory returns invalid amount type " + type.getName(),
167                        type, m.getClass());
168                assertTrue(
169                        "Section 4.2.6: Amount created with factory has invalid value for " + type.getName(),
170                        m.isZero());
171                assertTrue("Amount created with factory has invalid value for " + type.getName(),
172                        m.signum() == 0);
173                assertTrue(
174                        "Section 4.2.6: Amount created with factory has invalid value for " + type.getName(),
175                        m.getNumber().intValueExact() == 0);
176            }
177        }
178    }
179
180    /**
181     * For each MonetaryAmount Factory: Create zero amounts from a
182     * factory with monetary contexts.
183     */
184    @Test(description = "4.2.6 Ensure MonetaryAmountFactory instances support creation of 0 amounts, with explicit " +
185            "MonetaryContext.")
186    @SpecAssertion(section = "4.2.6", id = "426-B2")
187    public void testMonetaryAmountFactoryCreateZeroAmountsWithDiffContexts() {
188        for (Class type : Monetary.getAmountTypes()) {
189            if (type.equals(TestAmount.class)) {
190                continue;
191            }
192            MonetaryAmountFactory<?> f = Monetary.getAmountFactory(type);
193            f.setCurrency("GBP");
194            f.setNumber(0);
195            MonetaryContext maxCtx = f.getMaximalMonetaryContext();
196            if (maxCtx.getPrecision() != 0) {
197                for (int p = maxCtx.getPrecision(); p > 0; p--) {
198                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setPrecision(p).build());
199                    MonetaryAmount m = f.create();
200                    assertTrue(
201                            "Section 4.2.6: Factory did not honor the precision set on the context for " +
202                                    type.getName(),
203                            m.getContext().getPrecision() == 0 || m.getContext().getPrecision() >= p);
204                }
205            } else {
206                for (int p = 0; p < 100; p += 10) {
207                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setPrecision(p).build());
208                    MonetaryAmount m = f.create();
209                    assertTrue(
210                            "Section 4.2.6: Factory did not honor the precision set on the context for " +
211                                    type.getName(),
212                            m.getContext().getPrecision() == 0 || m.getContext().getPrecision() >= p);
213                }
214            }
215            if (maxCtx.getMaxScale() != -1) {
216                for (int s = maxCtx.getMaxScale(); s >= 0; s--) {
217                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setMaxScale(s).build());
218                    MonetaryAmount m = f.create();
219                    assertTrue(
220                            "Section 4.2.6: Factory did not honor the scale set on the context for " + type.getName(),
221                            m.getContext().getMaxScale() == -1 || m.getContext().getMaxScale() >= s);
222                }
223            } else {
224                for (int s = 0; s < 100; s += 10) {
225                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setMaxScale(s).build());
226                    MonetaryAmount m = f.create();
227                    assertTrue(
228                            "Section 4.2.6: Factory did not honor the precision set on the context for " +
229                                    type.getName(),
230                            m.getContext().getMaxScale() == -1 || m.getContext().getMaxScale() >= s);
231                }
232            }
233        }
234    }
235
236    /**
237     * For each MonetaryAmount Factory: Create zero amounts from a
238     * factory with monetary contexts.
239     */
240    @Test(description = "4.2.6 Ensure MonetaryAmountFactory instances support creation of 0 amounts, with different " +
241            "explicit MonetaryContext.")
242    @SpecAssertion(section = "4.2.6", id = "426-B2")
243    public void testMonetaryAmountFactoryCreateZeroAmountsWithDiffContexts2() {
244        for (Class type : Monetary.getAmountTypes()) {
245            if (type.equals(TestAmount.class)) {
246                continue;
247            }
248            MonetaryAmountFactory<?> f = Monetary.getAmountFactory(type);
249            f.setCurrency("GBP");
250            f.setNumber(0.0d);
251            MonetaryContext maxCtx = f.getMaximalMonetaryContext();
252            if (maxCtx.getPrecision() != 0) {
253                for (int p = maxCtx.getPrecision(); p > 0; p--) {
254                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setPrecision(p).build());
255                    MonetaryAmount m = f.create();
256                    assertTrue(
257                            "Section 4.2.6: Factory did not honor the precision set on the context for " +
258                                    type.getName(),
259                            m.getContext().getPrecision() == 0 || m.getContext().getPrecision() >= p);
260                }
261            } else {
262                for (int p = 0; p < 100; p += 10) {
263                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setPrecision(p).build());
264                    MonetaryAmount m = f.create();
265                    assertTrue(
266                            "Section 4.2.6: Factory did not honor the precision set on the context for " +
267                                    type.getName(),
268                            m.getContext().getPrecision() == 0 || m.getContext().getPrecision() >= p);
269                }
270            }
271            if (maxCtx.getMaxScale() != -1) {
272                for (int s = maxCtx.getMaxScale(); s >= 0; s--) {
273                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setMaxScale(s).build());
274                    MonetaryAmount m = f.create();
275                    assertTrue(
276                            "Section 4.2.6: Factory did not honor the scale set on the context for " + type.getName(),
277                            m.getContext().getMaxScale() == -1 || m.getContext().getMaxScale() >= s);
278                }
279            } else {
280                for (int s = 0; s < 100; s += 10) {
281                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setMaxScale(s).build());
282                    MonetaryAmount m = f.create();
283                    assertTrue(
284                            "Section 4.2.6: Factory did not honor the precision set on the context for " +
285                                    type.getName(),
286                            m.getContext().getMaxScale() == -1 || m.getContext().getMaxScale() >= s);
287                }
288            }
289        }
290    }
291
292    /**
293     * For each MonetaryAmount Factory: Create zero amounts from a
294     * factory with monetary contexts.
295     */
296    @Test(description = "4.2.6 Ensure MonetaryAmountFactory instances support creation of 0 amounts, with different " +
297            "explicit MonetaryContext (precision, scale).")
298    @SpecAssertion(section = "4.2.6", id = "426-B2")
299    public void testMonetaryAmountFactoryCreateZeroAmountsWithDiffContexts3() {
300        for (Class type : Monetary.getAmountTypes()) {
301            if (type.equals(TestAmount.class)) {
302                continue;
303            }
304            MonetaryAmountFactory<?> f = Monetary.getAmountFactory(type);
305            f.setCurrency("GBP");
306            f.setNumber(BigDecimal.ZERO);
307            MonetaryContext maxCtx = f.getMaximalMonetaryContext();
308            if (maxCtx.getPrecision() != 0) {
309                for (int p = maxCtx.getPrecision(); p > 0; p--) {
310                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setPrecision(p).build());
311                    MonetaryAmount m = f.create();
312                    assertTrue(
313                            "Section 4.2.6: Factory did not honor the precision set on the context for " +
314                                    type.getName(),
315                            m.getContext().getPrecision() == 0 || m.getContext().getPrecision() >= p);
316                }
317            } else {
318                for (int p = 0; p < 100; p += 10) {
319                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setPrecision(p).build());
320                    MonetaryAmount m = f.create();
321                    assertTrue(
322                            "Section 4.2.6: Factory did not honor the precision set on the context for " +
323                                    type.getName(),
324                            m.getContext().getPrecision() == 0 || m.getContext().getPrecision() >= p);
325                }
326            }
327            if (maxCtx.getMaxScale() != -1) {
328                for (int s = maxCtx.getMaxScale(); s >= 0; s--) {
329                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setMaxScale(s).build());
330                    MonetaryAmount m = f.create();
331                    assertTrue(
332                            "Section 4.2.6: Factory did not honor the scale set on the context for " + type.getName(),
333                            m.getContext().getMaxScale() == -1 || m.getContext().getMaxScale() >= s);
334                }
335            } else {
336                for (int s = 0; s < 100; s += 10) {
337                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setMaxScale(s).build());
338                    MonetaryAmount m = f.create();
339                    assertTrue(
340                            "Section 4.2.6: Factory did not honor the precision set on the context for " +
341                                    type.getName(),
342                            m.getContext().getMaxScale() == -1 || m.getContext().getMaxScale() >= s);
343                }
344            }
345        }
346    }
347
348
349    /**
350     * For each MonetaryAmount Factory: Bad Case: Create zero amounts
351     * from a factory with an invalid currency.
352     */
353    @Test(description = "4.2.6 Bad case: For each MonetaryAmount Factory: Create zero amounts" +
354            " from a factory with an invalid currency.")
355    @SpecAssertion(section = "4.2.6", id = "426-B3")
356    public void testMonetaryAmountFactoryCreateAmountsWithInvalidCurrency() {
357        for (Class type : Monetary.getAmountTypes()) {
358            if (type.equals(TestAmount.class)) {
359                continue;
360            }
361            for (Currency cur : Currency.getAvailableCurrencies()) {
362                Monetary.getCurrency(cur.getCurrencyCode());
363                MonetaryAmountFactory<?> f = Monetary.getAmountFactory(type);
364                try {
365                    f.setCurrency("shjgssgsjgsj");
366                    AssertJUnit
367                            .fail("Section 4.2.6: Factory should throw UnknownCurrencyException for invalid currency," +
368                                    " type was " +
369                                    type.getName());
370                } catch (UnknownCurrencyException e) {
371                    // OK
372                }
373            }
374        }
375    }
376
377    /**
378     * For each MonetaryAmount Factory: Bad Case: Create zero amounts
379     * from a factory with an invalid contexts.
380     */
381    @Test(description = "4.2.6 Bad case: For each MonetaryAmount Factory: Create zero amounts" +
382            " from a factory with an invalid MonetaryContext.")
383    @SpecAssertion(section = "4.2.6", id = "426-B4")
384    public void testMonetaryAmountFactoryCreateAmountsWithInvalidMonetaryContext() {
385        for (Class type : Monetary.getAmountTypes()) {
386            if (type.equals(TestAmount.class)) {
387                continue;
388            }
389            MonetaryAmountFactory<?> f = Monetary.getAmountFactory(type);
390            try {
391                f.setCurrency("USD");
392                MonetaryContext maxCtx = f.getMaximalMonetaryContext();
393                if (maxCtx.getPrecision() != 0) {
394                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setPrecision(maxCtx.getPrecision() + 1)
395                            .build());
396                    AssertJUnit.fail("Section 4.2.6: Factory should throw MonetaryException for invalid context " +
397                            "(exceeding precision), " +
398                            "type was " +
399                            type.getName());
400                }
401                if (maxCtx.getMaxScale() != -1) {
402                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setMaxScale(maxCtx.getMaxScale() + 1)
403                            .build());
404                    AssertJUnit.fail("Section 4.2.6: Factory should throw MonetaryException for invalid context " +
405                            "(exceeding scale), " +
406                            "type was " +
407                            type.getName());
408                }
409            } catch (MonetaryException e) {
410                // OK
411            }
412        }
413    }
414
415
416    // ********************* C. Testing Creation of Amounts with positive values **************
417
418    /**
419     * For each MonetaryAmount Factory: Create positive amounts from
420     * a factory with currencies.
421     */
422    @Test(description = "4.2.6 For each MonetaryAmount Factory: Create positive amounts.")
423    @SpecAssertion(section = "4.2.6", id = "426-C1")
424    public void testMonetaryAmountFactoryCreatePositiveAmountsWitCurrencies() {
425        for (Class type : Monetary.getAmountTypes()) {
426            if (type.equals(TestAmount.class)) {
427                continue;
428            }
429            for (Currency cur : Currency.getAvailableCurrencies()) {
430                CurrencyUnit cu = Monetary.getCurrency(cur.getCurrencyCode());
431                MonetaryAmountFactory<?> f = Monetary.getAmountFactory(type);
432                f.setCurrency(cu);
433                f.setNumber(1);
434                MonetaryAmount m = f.create();
435                AssertJUnit.assertEquals(
436                        "Section 4.2.6: Amount created with factory has invalid currency for " + type.getName(), cu,
437                        m.getCurrency());
438                AssertJUnit.assertEquals(
439                        "Section 4.2.6: Amount created with factory returns invalid amount type " + type.getName(),
440                        type, m.getClass());
441                assertTrue(
442                        "Section 4.2.6: Amount created with factory has invalid value for " + type.getName(),
443                        m.isPositive());
444                assertTrue(
445                        "Section 4.2.6: Amount created with factory has invalid value for " + type.getName(),
446                        m.signum() == 1);
447                assertTrue(
448                        "Section 4.2.6: Amount created with factory has invalid value for " + type.getName(),
449                        m.getNumber().intValueExact() == 1);
450            }
451        }
452    }
453
454    /**
455     * For each MonetaryAmount Factory: Create positive amounts from
456     * a factory with monetary contexts.
457     */
458    @Test(description = "4.2.6 For each MonetaryAmount Factory: Create positive amounts with explicit MonetaryContext.")
459    @SpecAssertion(section = "4.2.6", id = "426-C2")
460    public void testMonetaryAmountFactoryCreatePositiveAmountsWithContexts() {
461        for (Class type : Monetary.getAmountTypes()) {
462            if (type.equals(TestAmount.class)) {
463                continue;
464            }
465            MonetaryAmountFactory<?> f = Monetary.getAmountFactory(type);
466            f.setCurrency("GBP");
467            f.setNumber(1);
468            MonetaryContext maxCtx = f.getMaximalMonetaryContext();
469            if (maxCtx.getPrecision() != 0) {
470                for (int p = maxCtx.getPrecision(); p > 0; p--) {
471                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setPrecision(p).build());
472                    MonetaryAmount m = f.create();
473                    assertTrue(
474                            "Section 4.2.6: Factory did not honor the precision set on the context for " +
475                                    type.getName(),
476                            m.getContext().getPrecision() == 0 || m.getContext().getPrecision() >= p);
477                }
478            } else {
479                for (int p = 0; p < 100; p += 10) {
480                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setPrecision(p).build());
481                    MonetaryAmount m = f.create();
482                    assertTrue(
483                            "Section 4.2.6: Factory did not honor the precision set on the context for " +
484                                    type.getName(),
485                            m.getContext().getPrecision() == 0 || m.getContext().getPrecision() >= p);
486                }
487            }
488            if (maxCtx.getMaxScale() != -1) {
489                for (int s = maxCtx.getMaxScale(); s >= 0; s--) {
490                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setMaxScale(s).build());
491                    MonetaryAmount m = f.create();
492                    assertTrue(
493                            "Section 4.2.6: Factory did not honor the scale set on the context for " + type.getName(),
494                            m.getContext().getMaxScale() == -1 || m.getContext().getMaxScale() >= s);
495                }
496            } else {
497                for (int s = 0; s < 100; s += 10) {
498                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setMaxScale(s).build());
499                    MonetaryAmount m = f.create();
500                    assertTrue(
501                            "Section 4.2.6: Factory did not honor the precision set on the context for " +
502                                    type.getName(),
503                            m.getContext().getMaxScale() == -1 || m.getContext().getMaxScale() >= s);
504                }
505            }
506        }
507    }
508
509    /**
510     * For each MonetaryAmount Factory: Create positive amounts from
511     * a factory with monetary contexts.
512     */
513    @Test(description =
514            "4.2.6 For each MonetaryAmount Factory: Create positive amounts using doubles with explicit " +
515                    "MonetaryContext " +
516                    "(precision/scale).")
517    @SpecAssertion(section = "4.2.6", id = "426-C2")
518    public void testMonetaryAmountFactoryCreatePositiveAmountsWithContexts2() {
519        for (Class type : Monetary.getAmountTypes()) {
520            if (type.equals(TestAmount.class)) {
521                continue;
522            }
523            MonetaryAmountFactory<?> f = Monetary.getAmountFactory(type);
524            f.setCurrency("GBP");
525            f.setNumber(1.0d);
526            MonetaryContext maxCtx = f.getMaximalMonetaryContext();
527            if (maxCtx.getPrecision() != 0) {
528                for (int p = maxCtx.getPrecision(); p > 0; p--) {
529                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setPrecision(p).build());
530                    MonetaryAmount m = f.create();
531                    assertTrue(
532                            "Section 4.2.6: Factory did not honor the precision set on the context for " +
533                                    type.getName(),
534                            m.getContext().getPrecision() == 0 || m.getContext().getPrecision() >= p);
535                }
536            } else {
537                for (int p = 0; p < 100; p += 10) {
538                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setPrecision(p).build());
539                    MonetaryAmount m = f.create();
540                    assertTrue(
541                            "Section 4.2.6: Factory did not honor the precision set on the context for " +
542                                    type.getName(),
543                            m.getContext().getPrecision() == 0 || m.getContext().getPrecision() >= p);
544                }
545            }
546            if (maxCtx.getMaxScale() != -1) {
547                for (int s = maxCtx.getMaxScale(); s >= 0; s--) {
548                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setMaxScale(s).build());
549                    MonetaryAmount m = f.create();
550                    assertTrue(
551                            "Section 4.2.6: Factory did not honor the scale set on the context for " + type.getName(),
552                            m.getContext().getMaxScale() == -1 || m.getContext().getMaxScale() >= s);
553                }
554            } else {
555                for (int s = 0; s < 100; s += 10) {
556                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setMaxScale(s).build());
557                    MonetaryAmount m = f.create();
558                    assertTrue(
559                            "Section 4.2.6: Factory did not honor the precision set on the context for " +
560                                    type.getName(),
561                            m.getContext().getMaxScale() == -1 || m.getContext().getMaxScale() >= s);
562                }
563            }
564        }
565    }
566
567    /**
568     * For each MonetaryAmount Factory: Create positive amounts from
569     * a factory with monetary contexts.
570     */
571    @Test(description =
572            "4.2.6 For each MonetaryAmount Factory: Create positive amounts using BigDecimal with explicit " +
573                    "MonetaryContext " +
574                    "(precision/scale).")
575    @SpecAssertion(section = "4.2.6", id = "426-C2")
576    public void testMonetaryAmountFactoryCreatePositiveAmountsWithContexts3() {
577        for (Class type : Monetary.getAmountTypes()) {
578            if (type.equals(TestAmount.class)) {
579                continue;
580            }
581            MonetaryAmountFactory<?> f = Monetary.getAmountFactory(type);
582            f.setCurrency("GBP");
583            f.setNumber(BigDecimal.ONE);
584            MonetaryContext maxCtx = f.getMaximalMonetaryContext();
585            if (maxCtx.getPrecision() != 0) {
586                for (int p = maxCtx.getPrecision(); p > 0; p--) {
587                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setPrecision(p).build());
588                    MonetaryAmount m = f.create();
589                    assertTrue(
590                            "Section 4.2.6: Factory did not honor the precision set on the context for " +
591                                    type.getName(),
592                            m.getContext().getPrecision() == 0 || m.getContext().getPrecision() >= p);
593                }
594            } else {
595                for (int p = 0; p < 100; p += 10) {
596                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setPrecision(p).build());
597                    MonetaryAmount m = f.create();
598                    assertTrue(
599                            "Section 4.2.6: Factory did not honor the precision set on the context for " +
600                                    type.getName(),
601                            m.getContext().getPrecision() == 0 || m.getContext().getPrecision() >= p);
602                }
603            }
604            if (maxCtx.getMaxScale() != -1) {
605                for (int s = maxCtx.getMaxScale(); s >= 0; s--) {
606                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setMaxScale(s).build());
607                    MonetaryAmount m = f.create();
608                    assertTrue(
609                            "Section 4.2.6: Factory did not honor the scale set on the context for " + type.getName(),
610                            m.getContext().getMaxScale() == -1 || m.getContext().getMaxScale() >= s);
611                }
612            } else {
613                for (int s = 0; s < 100; s += 10) {
614                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setMaxScale(s).build());
615                    MonetaryAmount m = f.create();
616                    assertTrue(
617                            "Section 4.2.6: Factory did not honor the precision set on the context for " +
618                                    type.getName(),
619                            m.getContext().getMaxScale() == -1 || m.getContext().getMaxScale() >= s);
620                }
621            }
622        }
623    }
624
625    /**
626     * For each MonetaryAmount Factory: Bad Case: Create positive
627     * amounts from a factory with an invalid numeric value (exceeding max
628     * MonetaryContext).
629     */
630    @Test(description =
631            "4.2.6 Bad case: For each MonetaryAmount Factory: Create positive amounts using invalid numbers," +
632                    " expecting ArithemticException thrown.")
633    @SpecAssertion(section = "4.2.6", id = "426-C3")
634    public void testMonetaryAmountFactoryCreatePositiveAmountsWithInvalidNumber() {
635        for (Class type : Monetary.getAmountTypes()) {
636            if (type.equals(TestAmount.class)) {
637                continue;
638            }
639            MonetaryAmountFactory f = Monetary.getAmountFactory(type);
640            f.setCurrency("INR");
641            MonetaryContext ctx = f.getMaximalMonetaryContext();
642            if (ctx.getPrecision() != 0) {
643                try {
644                    f.setNumber(TestUtils.createNumberWithPrecision(ctx.getPrecision() + 5));
645                    f.create();
646                    AssertJUnit.fail("Section 4.2.6: MonetaryAmountFactory must throw an ArithmeticException, " +
647                            "when an amount with exceeding precision is " +
648                            "tried" +
649
650                            " being created, type: " +
651                            type.getName());
652                } catch (ArithmeticException e) {
653                    // OK
654                }
655            }
656            if (ctx.getMaxScale() != -1) {
657                try {
658                    f.setNumber(TestUtils.createNumberWithScale(ctx.getMaxScale() + 5));
659                    f.create();
660                    AssertJUnit.fail("Section 4.2.6: MonetaryAmountFactory must throw an ArithmeticException, " +
661                            "when an amount with exceeding scale is tried" +
662                            " being created, type: " +
663                            type.getName());
664                } catch (ArithmeticException e) {
665                    // OK
666                }
667            }
668        }
669    }
670
671    /**
672     * For each MonetaryAmount Factory: Bad Case: Create negative amounts from a factory with an no currency.
673     */
674    @Test(description = "4.2.6 Bad case: For each MonetaryAmount Factory: Create negative amounts without currency," +
675            " expecting MonetaryException thrown.")
676    @SpecAssertion(section = "4.2.6", id = "426-C4")
677    public void testMonetaryAmountFactoryCreatePositiveNoCurrency_BadCase() {
678        for (Class type : Monetary.getAmountTypes()) {
679            if (type.equals(TestAmount.class)) {
680                continue;
681            }
682            MonetaryAmountFactory f = Monetary.getAmountFactory(type);
683            try {
684                if (f.getDefaultMonetaryContext().getPrecision() == 0) {
685                    f.setNumber(TestUtils.createNumberWithPrecision(5));
686                } else {
687                    f.setNumber(TestUtils.createNumberWithPrecision(f.getDefaultMonetaryContext().getPrecision()));
688                }
689                f.create();
690                AssertJUnit.fail("Section 4.2.6: MonetaryAmountFactory must throw a MonetaryException, " +
691                        "when a positive amount without a currency" +
692                        " is" +
693                        " tried to be created, type: " +
694                        type.getName());
695            } catch (MonetaryException e) {
696                // OK
697            } catch (Exception e) {
698                AssertJUnit.fail("Section 4.2.6: MonetaryAmountFactory must throw a MonetaryException, " +
699                        "when a positive amount without a currency" +
700                        " is" +
701                        " tried to be created, but threw " + e.getClass() + " type: " +
702                        type.getName());
703            }
704        }
705    }
706
707    /**
708     * For each MonetaryAmount Factory: Bad Case: Create negative amounts from a factory with an invalid currency.
709     */
710    @Test(description =
711            "4.2.6 Bad case: For each MonetaryAmount Factory: Create negative amounts with an invalid currency," +
712                    " expecting MonetaryException thrown.")
713    @SpecAssertion(section = "4.2.6", id = "426-C4")
714    public void testMonetaryAmountFactoryCreatePositiveInvalidCurrency_BadCase() {
715        for (Class type : Monetary.getAmountTypes()) {
716            if (type.equals(TestAmount.class)) {
717                continue;
718            }
719            MonetaryAmountFactory f = Monetary.getAmountFactory(type);
720            try {
721                if (f.getDefaultMonetaryContext().getPrecision() == 0) {
722                    f.setNumber(TestUtils.createNumberWithPrecision(5));
723                } else {
724                    f.setNumber(TestUtils.createNumberWithPrecision(f.getDefaultMonetaryContext().getPrecision()));
725                }
726                f.setCurrency("FooBar_foobar_fOobAr_foObaR");
727                f.create();
728                AssertJUnit.fail("Section 4.2.6: MonetaryAmountFactory must throw a MonetaryException, " +
729                        "when a positive amount with an invalid " +
730                        "currency" +
731                        " is" +
732                        " tried to be created, type: " +
733                        type.getName());
734            } catch (MonetaryException e) {
735                // OK
736            }
737        }
738    }
739
740    /**
741     * For each MonetaryAmount Factory: Bad Case: Create negative amounts from a factory with an invalid currency.
742     */
743    @Test(description =
744            "4.2.6 Bad case: For each MonetaryAmount Factory: Create negative amounts with an invalid currency," +
745                    " expecting MonetaryException thrown.")
746    @SpecAssertion(section = "4.2.6", id = "426-C5")
747    public void testMonetaryAmountFactoryCreatePositiveInvalidContext_BadCase() {
748        for (Class type : Monetary.getAmountTypes()) {
749            if (type.equals(TestAmount.class)) {
750                continue;
751            }
752            MonetaryAmountFactory f = Monetary.getAmountFactory(type);
753            MonetaryContext mc = f.getMaximalMonetaryContext();
754            try {
755                MonetaryContextBuilder b = mc.toBuilder();
756                boolean runTest = false; // only run check, if we are able to construct an exceeding MonetaryContext
757                if (mc.getMaxScale() != -1) {
758                    b.setMaxScale(mc.getMaxScale() + 10);
759                    runTest = true;
760                }
761                if (mc.getPrecision() != -0) {
762                    b.setPrecision(mc.getPrecision() + 10);
763                    runTest = true;
764                }
765                if (runTest) {
766                    f.setNumber(TestUtils.createNumberWithPrecision(f.getDefaultMonetaryContext().getPrecision()));
767                    f.setCurrency("FooBar_foobar_fOobAr_foObaR");
768                    f.create();
769                    AssertJUnit.fail("Section 4.2.6: MonetaryAmountFactory must throw a MonetaryException, " +
770                            "when a positive amount without an " +
771                            "invalid MonetaryContext is" +
772                            " tried to be created, type: " +
773                            type.getName());
774                }
775            } catch (MonetaryException e) {
776                // OK
777            }
778        }
779    }
780
781
782    // **************  D. Testing Creation of Amounts with negative values *******************
783
784    /**
785     * For each MonetaryAmount Factory: Create negative amounts from
786     * a factory with currencies.
787     */
788    @Test(description = "4.2.6 For each MonetaryAmount Factory: Create negative amounts.")
789    @SpecAssertion(section = "4.2.6", id = "426-D1")
790    public void testMonetaryAmountFactoryNegativePositiveAmountsWitCurrencies() {
791        for (Class type : Monetary.getAmountTypes()) {
792            if (type.equals(TestAmount.class)) {
793                continue;
794            }
795            for (Currency cur : Currency.getAvailableCurrencies()) {
796                CurrencyUnit cu = Monetary.getCurrency(cur.getCurrencyCode());
797                MonetaryAmountFactory<?> f = Monetary.getAmountFactory(type);
798                f.setCurrency(cu);
799                f.setNumber(-3);
800                MonetaryAmount m = f.create();
801                AssertJUnit.assertEquals(
802                        "Section 4.2.6: Amount created with factory has invalid currency for " + type.getName(), cu,
803                        m.getCurrency());
804                AssertJUnit.assertEquals(
805                        "Section 4.2.6: Amount created with factory returns invalid amount type " + type.getName(),
806                        type, m.getClass());
807                assertTrue(
808                        "Section 4.2.6: Amount created with factory has invalid value for " + type.getName(),
809                        m.isNegative());
810                assertTrue(
811                        "Section 4.2.6: Amount created with factory has invalid value for " + type.getName(),
812                        m.signum() == -1);
813                assertTrue(
814                        "Section 4.2.6: Amount created with factory has invalid value for " + type.getName(),
815                        m.getNumber().intValueExact() == -3);
816            }
817        }
818    }
819
820    /**
821     * For each MonetaryAmount Factory: Create negative amounts from
822     * a factory with monetary contexts.
823     */
824    @Test(description = "4.2.6 For each MonetaryAmount Factory: Create negative amounts, with explicit" +
825            " MonetaryContext.")
826    @SpecAssertion(section = "4.2.6", id = "426-D2")
827    public void testMonetaryAmountFactoryNegativePositiveAmountsWithContexts() {
828        for (Class type : Monetary.getAmountTypes()) {
829            if (type.equals(TestAmount.class)) {
830                continue;
831            }
832            MonetaryAmountFactory<?> f = Monetary.getAmountFactory(type);
833            f.setCurrency("GBP");
834            f.setNumber(1);
835            MonetaryContext maxCtx = f.getMaximalMonetaryContext();
836            if (maxCtx.getPrecision() != 0) {
837                for (int p = maxCtx.getPrecision(); p > 0; p--) {
838                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setPrecision(p).build());
839                    MonetaryAmount m = f.create();
840                    assertTrue(
841                            "Section 4.2.6: Factory did not honor the precision set on the context for " +
842                                    type.getName(),
843                            m.getContext().getPrecision() == 0 || m.getContext().getPrecision() >= p);
844                }
845            } else {
846                for (int p = 0; p < 100; p += 10) {
847                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setPrecision(p).build());
848                    MonetaryAmount m = f.create();
849                    assertTrue(
850                            "Section 4.2.6: Factory did not honor the precision set on the context for " +
851                                    type.getName(),
852                            m.getContext().getPrecision() == 0 || m.getContext().getPrecision() >= p);
853                }
854            }
855            if (maxCtx.getMaxScale() != -1) {
856                for (int s = maxCtx.getMaxScale(); s >= 0; s--) {
857                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setMaxScale(s).build());
858                    MonetaryAmount m = f.create();
859                    assertTrue(
860                            "Section 4.2.6: Factory did not honor the scale set on the context for " + type.getName(),
861                            m.getContext().getMaxScale() == -1 || m.getContext().getMaxScale() >= s);
862                }
863            } else {
864                for (int s = 0; s < 100; s += 10) {
865                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setMaxScale(s).build());
866                    MonetaryAmount m = f.create();
867                    assertTrue(
868                            "Section 4.2.6: Factory did not honor the precision set on the context for " +
869                                    type.getName(),
870                            m.getContext().getMaxScale() == -1 || m.getContext().getMaxScale() >= s);
871                }
872            }
873        }
874    }
875
876    /**
877     * For each MonetaryAmount Factory: Create negative amounts from
878     * a factory with monetary contexts.
879     */
880    @Test(description = "4.2.6 For each MonetaryAmount Factory: Create negative amounts, with explicit " +
881            "MonetaryContext.")
882    @SpecAssertion(section = "4.2.6", id = "426-D2")
883    public void testMonetaryAmountFactoryNegativePositiveAmountsWithContexts2() {
884        for (Class type : Monetary.getAmountTypes()) {
885            if (type.equals(TestAmount.class)) {
886                continue;
887            }
888            MonetaryAmountFactory<?> f = Monetary.getAmountFactory(type);
889            f.setCurrency("GBP");
890            f.setNumber(11.2);
891            MonetaryContext maxCtx = f.getMaximalMonetaryContext();
892            if (maxCtx.getPrecision() != 0) {
893                for (int p = maxCtx.getPrecision(); p > 0; p--) {
894                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setPrecision(p).build());
895                    MonetaryAmount m = f.create();
896                    assertTrue(
897                            "Section 4.2.6: Factory did not honor the precision set on the context for " +
898                                    type.getName(),
899                            m.getContext().getPrecision() == 0 || m.getContext().getPrecision() >= p);
900                }
901            } else {
902                for (int p = 0; p < 100; p += 10) {
903                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setPrecision(p).build());
904                    MonetaryAmount m = f.create();
905                    assertTrue(
906                            "Section 4.2.6: Factory did not honor the precision set on the context for " +
907                                    type.getName(),
908                            m.getContext().getPrecision() == 0 || m.getContext().getPrecision() >= p);
909                }
910            }
911            if (maxCtx.getMaxScale() != -1) {
912                for (int s = maxCtx.getMaxScale(); s >= 0; s--) {
913                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setMaxScale(s).build());
914                    MonetaryAmount m = f.create();
915                    assertTrue(
916                            "Section 4.2.6: Factory did not honor the scale set on the context for " + type.getName(),
917                            m.getContext().getMaxScale() == -1 || m.getContext().getMaxScale() >= s);
918                }
919            } else {
920                for (int s = 0; s < 100; s += 10) {
921                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setMaxScale(s).build());
922                    MonetaryAmount m = f.create();
923                    assertTrue(
924                            "Section 4.2.6: Factory did not honor the precision set on the context for " +
925                                    type.getName(),
926                            m.getContext().getMaxScale() == -1 || m.getContext().getMaxScale() >= s);
927                }
928            }
929        }
930    }
931
932    /**
933     * For each MonetaryAmount Factory: Create negative amounts from
934     * a factory with monetary contexts.
935     */
936    @Test(description = "4.2.6 For each MonetaryAmount Factory: Create negative amounts, with explicit " +
937            "MonetaryContext.")
938    @SpecAssertion(section = "4.2.6", id = "426-D2")
939    public void testMonetaryAmountFactoryNegativePositiveAmountsWithContexts3() {
940        for (Class type : Monetary.getAmountTypes()) {
941            if (type.equals(TestAmount.class)) {
942                continue;
943            }
944            MonetaryAmountFactory<?> f = Monetary.getAmountFactory(type);
945            f.setCurrency("GBP");
946            f.setNumber(BigDecimal.TEN);
947            MonetaryContext maxCtx = f.getMaximalMonetaryContext();
948            if (maxCtx.getPrecision() != 0) {
949                for (int p = maxCtx.getPrecision(); p > 0; p--) {
950                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setPrecision(p).build());
951                    MonetaryAmount m = f.create();
952                    assertTrue(
953                            "Section 4.2.6: Factory did not honor the precision set on the context for " +
954                                    type.getName(),
955                            m.getContext().getPrecision() == 0 || m.getContext().getPrecision() >= p);
956                }
957            } else {
958                for (int p = 0; p < 100; p += 10) {
959                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setPrecision(p).build());
960                    MonetaryAmount m = f.create();
961                    assertTrue(
962                            "Section 4.2.6: Factory did not honor the precision set on the context for " +
963                                    type.getName(),
964                            m.getContext().getPrecision() == 0 || m.getContext().getPrecision() >= p);
965                }
966            }
967            if (maxCtx.getMaxScale() != -1) {
968                for (int s = maxCtx.getMaxScale(); s >= 0; s--) {
969                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setMaxScale(s).build());
970                    MonetaryAmount m = f.create();
971                    assertTrue(
972                            "Section 4.2.6: Factory did not honor the scale set on the context for " + type.getName(),
973                            m.getContext().getMaxScale() == -1 || m.getContext().getMaxScale() >= s);
974                }
975            } else {
976                for (int s = 0; s < 100; s += 10) {
977                    f.setContext(MonetaryContextBuilder.of(MonetaryAmount.class).setMaxScale(s).build());
978                    MonetaryAmount m = f.create();
979                    assertTrue(
980                            "Section 4.2.6: Factory did not honor the precision set on the context for " +
981                                    type.getName(),
982                            m.getContext().getMaxScale() == -1 || m.getContext().getMaxScale() >= s);
983                }
984            }
985        }
986    }
987
988    /**
989     * For each MonetaryAmount Factory: Bad Case: Create negative
990     * amounts from a factory with an invalid numeric value (exceeding max
991     * MonetaryContext).
992     */
993    @Test(description = "4.2.6 Bad case: For each MonetaryAmount Factory: Create negative amounts, with invalid " +
994            "numeric value, expect ArithmeticException.")
995    @SpecAssertion(section = "4.2.6", id = "426-D3")
996    public void testMonetaryAmountFactoryNegativePositiveAmountsWithInvalidNumber() {
997        for (Class type : Monetary.getAmountTypes()) {
998            if (type.equals(TestAmount.class)) {
999                continue;
1000            }
1001            MonetaryAmountFactory f = Monetary.getAmountFactory(type);
1002            f.setCurrency("INR");
1003            MonetaryContext ctx = f.getMaximalMonetaryContext();
1004            if (ctx.getPrecision() != 0) {
1005                try {
1006                    f.setNumber(TestUtils.createNumberWithPrecision(ctx.getPrecision() + 5).negate());
1007                    f.create();
1008                    AssertJUnit.fail("Section 4.2.6: MonetaryAmountFactory must throw an ArithmeticException, " +
1009                            "when an amount with exceeding precision is " +
1010                            "tried" +
1011
1012                            " being created, type: " +
1013                            type.getName());
1014                } catch (ArithmeticException e) {
1015                    // OK
1016                }
1017            }
1018            if (ctx.getMaxScale() != -1) {
1019                try {
1020                    f.setNumber(TestUtils.createNumberWithScale(ctx.getMaxScale() + 5).negate());
1021                    f.create();
1022                    AssertJUnit.fail("Section 4.2.6: MonetaryAmountFactory must throw an ArithmeticException, " +
1023                            "when an amount with exceeding scale is tried" +
1024                            " being created, type: " +
1025                            type.getName());
1026                } catch (ArithmeticException e) {
1027                    // OK
1028                }
1029            }
1030        }
1031    }
1032
1033    /**
1034     * For each MonetaryAmount Factory: Bad Case: Create negative amounts from a factory with an no currency.
1035     */
1036    @Test(description = "4.2.6 Bad case: For each MonetaryAmount Factory: Create negative amounts, with no " +
1037            "currency, expect MonetaryException.")
1038    @SpecAssertion(section = "4.2.6", id = "426-D4")
1039    public void testMonetaryAmountFactoryCreateNegativeNoCurrency_BadCase() {
1040        for (Class type : Monetary.getAmountTypes()) {
1041            if (type.equals(TestAmount.class)) {
1042                continue;
1043            }
1044            MonetaryAmountFactory f = Monetary.getAmountFactory(type);
1045            try {
1046                if (f.getDefaultMonetaryContext().getPrecision() == 0) {
1047                    f.setNumber(TestUtils.createNumberWithPrecision(5).negate());
1048                } else {
1049                    f.setNumber(TestUtils.createNumberWithPrecision(f.getDefaultMonetaryContext().getPrecision())
1050                            .negate());
1051                }
1052                f.create();
1053                AssertJUnit.fail("Section 4.2.6: MonetaryAmountFactory must throw a MonetaryException, " +
1054                        "when an amount without a currency is" +
1055                        " tried to be created, type: " +
1056                        type.getName());
1057            } catch (MonetaryException e) {
1058                // OK
1059            } catch (Exception e) {
1060                AssertJUnit.fail("Section 4.2.6: MonetaryAmountFactory must throw a MonetaryException, " +
1061                        "when an amount without a currency is" +
1062                        " tried to be created, but threw " + e.getClass() + " type: " +
1063                        type.getName());
1064            }
1065        }
1066    }
1067
1068    /**
1069     * For each MonetaryAmount Factory: Bad Case: Create negative amounts from a factory with an invalid currency.
1070     */
1071    @Test(description = "4.2.6 Bad case: For each MonetaryAmount Factory: Create negative amounts, with invalid " +
1072            "currency, expect MonetaryException.")
1073    @SpecAssertion(section = "4.2.6", id = "426-D4")
1074    public void testMonetaryAmountFactoryCreateNegativeInvalidCurrency_BadCase() {
1075        for (Class type : Monetary.getAmountTypes()) {
1076            if (type.equals(TestAmount.class)) {
1077                continue;
1078            }
1079            MonetaryAmountFactory f = Monetary.getAmountFactory(type);
1080            try {
1081                if (f.getDefaultMonetaryContext().getPrecision() == 0) {
1082                    f.setNumber(TestUtils.createNumberWithPrecision(5).negate());
1083                } else {
1084                    f.setNumber(TestUtils.createNumberWithPrecision(f.getDefaultMonetaryContext().getPrecision())
1085                            .negate());
1086                }
1087                f.setCurrency("Section 4.2.6: FooBar_foobar_fOobAr_foObaR");
1088                f.create();
1089                AssertJUnit.fail("Section 4.2.6: MonetaryAmountFactory must throw a MonetaryException, " +
1090                        "when an amount with an invalid " +
1091                        "currency is tried to be created, type: " +
1092                        type.getName());
1093            } catch (MonetaryException e) {
1094                // OK
1095            }
1096        }
1097    }
1098
1099    /**
1100     * For each MonetaryAmount Factory: Bad Case: Create negative amounts from a factory with an invalid currency.
1101     */
1102    @Test(description = "4.2.6 Bad case: For each MonetaryAmount Factory: Create negative amounts, with no " +
1103            "currency, expect MonetaryException.")
1104    @SpecAssertion(section = "4.2.6", id = "426-D5")
1105    public void testMonetaryAmountFactoryCreateNegativeInvalidContext_BadCase() {
1106        for (Class type : Monetary.getAmountTypes()) {
1107            if (type.equals(TestAmount.class)) {
1108                continue;
1109            }
1110            MonetaryAmountFactory f = Monetary.getAmountFactory(type);
1111            MonetaryContext mc = f.getMaximalMonetaryContext();
1112            try {
1113                MonetaryContextBuilder b = mc.toBuilder();
1114                boolean runTest = false; // only run check, if we are able to construct an exceeding MonetaryContext
1115                if (mc.getMaxScale() != -1) {
1116                    b.setMaxScale(mc.getMaxScale() + 10);
1117                    runTest = true;
1118                }
1119                if (mc.getPrecision() != -0) {
1120                    b.setPrecision(mc.getPrecision() + 10);
1121                    runTest = true;
1122                }
1123                if (runTest) {
1124                    if (f.getDefaultMonetaryContext().getPrecision() == 0) {
1125                        f.setNumber(TestUtils.createNumberWithPrecision(5).negate());
1126                    } else {
1127                        f.setNumber(TestUtils.createNumberWithPrecision(f.getDefaultMonetaryContext().getPrecision())
1128                                .negate());
1129                    }
1130                    f.setCurrency("FooBar_foobar_fOobAr_foObaR");
1131                    f.create();
1132                    AssertJUnit.fail("Section 4.2.6: MonetaryAmountFactory must throw a MonetaryException, " +
1133                            "when an amount with an invalid " +
1134                            "MonetaryContext is tried to be created, type: " +
1135                            type.getName());
1136                }
1137            } catch (MonetaryException e) {
1138                // OK
1139            }
1140        }
1141    }
1142
1143    /**
1144     * For each MonetaryAmount Factory: Bad Case: Create negative amounts from a factory with an invalid currency.
1145     */
1146    @Test(description = "4.2.7 Ensure the types available, must be at least one type.")
1147    @SpecAssertion(section = "4.2.7", id = "427-B1")
1148    public void testMonetaryAmountTypes_Available() {
1149        Collection<Class<? extends MonetaryAmount>> types = Monetary.getAmountTypes();
1150        assertNotNull("Section 4.2.6: Monetary returns null for amount implementations.", types);
1151        assertTrue("Section 4.2.6: Monetary does not provide any amount implementations.", !types.isEmpty());
1152    }
1153
1154}