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