001/*
002 * Copyright (c) 2012, 2013, Werner Keil, Credit Suisse (Anatole Tresch). Licensed under the Apache
003 * License, Version 2.0 (the "License"); you may not use this file except in compliance with the
004 * License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
005 * Unless required by applicable law or agreed to in writing, software distributed under the License
006 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
007 * or implied. See the License for the specific language governing permissions and limitations under
008 * the License. Contributors: Anatole Tresch - initial version.
009 */
010package org.javamoney.tck.tests;
011
012import org.javamoney.tck.TCKTestSetup;
013import org.javamoney.tck.TestUtils;
014import org.javamoney.tck.tests.internal.TestAmount;
015import org.jboss.test.audit.annotations.SpecAssertion;
016import org.jboss.test.audit.annotations.SpecVersion;
017import org.mutabilitydetector.unittesting.MutabilityAssertionError;
018import org.testng.AssertJUnit;
019import org.testng.annotations.Test;
020
021import javax.money.*;
022import java.math.BigDecimal;
023import java.math.RoundingMode;
024import java.util.ArrayList;
025import java.util.Currency;
026import java.util.List;
027
028import static javax.money.MonetaryAmounts.getAmountFactory;
029
030@SpecVersion(spec = "JSR 354", version = "1.0.0")
031public class ModellingMonetaryAmountsTest {
032
033    private final static String DEFAULT_CURRENCY = "CHF";
034
035    private final static String ADDITIONAL_CURRENCY = "USD";
036
037    /**
038     * Ensure at least one javax.money.MonetaryAmount implementation is registered,
039     * by calling MonetaryAmounts.getAmountTypes();
040     */
041    @SpecAssertion(section = "4.2.2", id = "422-0")
042    @Test(description = "4.2.2 Ensure MonetaryAmounts.getAmountTypes() is not null and not empty.")
043    public void testEnsureMonetaryAmount() {
044        AssertJUnit.assertNotNull("Section 4.2.2: MonetaryAmounts.getAmountTypes() must never return null.",
045                MonetaryAmounts.getAmountTypes());
046        AssertJUnit.assertTrue(
047                "Section 4.2.2: At least one type must be registered with MonetaryAmounts (see getAmountTypes()).",
048                MonetaryAmounts.getAmountTypes().size() > 0);
049    }
050
051    /**
052     * For each MonetaryAmount implementation: Ensure getCurrencyCode
053     * returns correct results.
054     */
055    @SpecAssertion(section = "4.2.2", id = "422-A1")
056    @Test(description = "4.2.2 Ensure amount can be created with all default currencies.")
057    public void testCurrencyCode() {
058        for (Class type : MonetaryAmounts.getAmountTypes()) {
059            for (Currency jdkCur : Currency.getAvailableCurrencies()) {
060                MonetaryAmount amount =
061                        MonetaryAmounts.getDefaultAmountFactory().setCurrency(jdkCur.getCurrencyCode()).setNumber(10.15)
062                                .create();
063                AssertJUnit.assertNotNull(
064                        "Section 4.2.2: Amount factory returned null for new amount type: " + type.getName(), amount);
065                AssertJUnit.assertNotNull(
066                        "Section 4.2.2: Amount factory returned new amount with null currency, type: " + type.getName(),
067                        amount.getCurrency());
068                AssertJUnit.assertEquals(
069                        "Section 4.2.2: Amount factory returned new amount with invalid currency, type: " +
070                                type.getName(), jdkCur.getCurrencyCode(), amount.getCurrency().getCurrencyCode());
071            }
072        }
073    }
074
075    /**
076     * For each MonetaryAmount implementation: Ensure getNumber()
077     * returns correct results.
078     */
079    @SpecAssertion(section = "4.2.2", id = "422-A2")
080    @Test(description = "4.2.2 Ensure amounts created return correct getNumber().")
081    public void testGetNumber() {
082        for (Class type : MonetaryAmounts.getAmountTypes()) {
083            if (type.equals(TestAmount.class)) {
084                continue;
085            }
086            MonetaryAmountFactory<MonetaryAmount> f = getAmountFactory(type);
087            f.setCurrency("CHF");
088            MonetaryAmount[] moneys = new MonetaryAmount[]{f.setNumber(100).create(),
089                    f.setNumber(new BigDecimal("23123213.435")).create(),
090                    f.setNumber(new BigDecimal("-23123213.435")).create(), f.setNumber(-23123213).create(),
091                    f.setNumber(0).create()};
092            BigDecimal[] numbers = new BigDecimal[]{new BigDecimal("100"), new BigDecimal("23123213.435"),
093                    new BigDecimal("-23123213.435"), new BigDecimal("-23123213"), BigDecimal.ZERO};
094            int[] intNums = new int[]{100, 23123213, -23123213, -23123213, 0};
095            long[] longNums = new long[]{100, 23123213, -23123213, -23123213, 0};
096            double[] doubleNums = new double[]{100, 23123213.435, -23123213.435, -23123213, 0};
097            float[] floatNums = new float[]{100f, 23123213.435f, -23123213.435f, -23123213, 0f};
098
099            for (int i = 0; i < moneys.length; i++) {
100                NumberValue nv = moneys[i].getNumber();
101                AssertJUnit.assertNotNull("Section 4.2.2: Amount returned returns null for getNumber(), type: " +
102                        moneys[i].getClass().getName(), nv);
103                AssertJUnit.assertEquals(
104                        "Section 4.2.2: getNumber().numberValue(BigDecimal.class) incorrect for " + type.getName(),
105                        numbers[i].stripTrailingZeros(), nv.numberValue(BigDecimal.class).stripTrailingZeros());
106                AssertJUnit.assertEquals("Section 4.2.2: getNumber().intValue() incorrect for " + type.getName(),
107                        intNums[i], nv.intValue());
108                AssertJUnit.assertEquals("Section 4.2.2: getNumber().longValue() incorrect for " + type.getName(),
109                        longNums[i], nv.longValue());
110                AssertJUnit.assertEquals("Section 4.2.2: getNumber().doubleValue() incorrect for " + type.getName(),
111                        doubleNums[i], nv.doubleValue(), 0.0d);
112                AssertJUnit.assertEquals("Section 4.2.2: getNumber().floatValue() incorrect for " + type.getName(),
113                        floatNums[i], nv.floatValue(), 0.0d);
114            }
115        }
116    }
117
118    /**
119     * For each MonetaryAmount implementation: Ensure
120     * getContext() returns correct results.
121     */
122    @SpecAssertion(section = "4.2.2", id = "422-A3")
123    @Test(description = "4.2.2 Ensure amounts created return correct getContext().")
124    public void testGetMonetaryContext() {
125        for (Class type : MonetaryAmounts.getAmountTypes()) {
126            if (type.equals(TestAmount.class)) {
127                continue;
128            }
129            MonetaryAmountFactory<MonetaryAmount> f = getAmountFactory(type);
130            f.setCurrency("CHF");
131            MonetaryContext defCtx = f.getDefaultMonetaryContext();
132            MonetaryContext maxCtx = f.getMaximalMonetaryContext();
133            MonetaryContext mc = f.setNumber(1).create().getContext();
134            AssertJUnit.assertEquals("Section 4.2.2: Invalid MonetaryContext(amountType) for " + type.getName(),
135                    mc.getAmountType(), type);
136            if (maxCtx.getPrecision() > 0) {
137                AssertJUnit.assertTrue("Section 4.2.2: Invalid MonetaryContext(precision) for " + type.getName(),
138                        mc.getPrecision() <= maxCtx.getPrecision());
139            }
140            if (maxCtx.getMaxScale() > 0) {
141                AssertJUnit.assertTrue("Section 4.2.2: Invalid MonetaryContext(maxScale) for " + type.getName(),
142                        mc.getMaxScale() <= maxCtx.getMaxScale());
143            }
144            AssertJUnit.assertEquals("Section 4.2.2: Invalid MonetaryContext(amountType) for " + type.getName(),
145                    f.setNumber(0.34746d).create().getContext().getAmountType(), type);
146            mc = f.setNumber(0).create().getContext();
147            AssertJUnit.assertEquals("Section 4.2.2: Invalid MonetaryContext(amountType) for " + type.getName(),
148                    mc.getAmountType(), type);
149            if (maxCtx.getPrecision() > 0) {
150                AssertJUnit.assertTrue("Section 4.2.2: Invalid MonetaryContext(precision) for " + type.getName(),
151                        mc.getPrecision() <= maxCtx.getPrecision());
152            }
153            if (maxCtx.getMaxScale() > 0) {
154                AssertJUnit.assertTrue("Section 4.2.2: Invalid MonetaryContext(maxScale) for " + type.getName(),
155                        mc.getMaxScale() <= maxCtx.getMaxScale());
156            }
157            AssertJUnit.assertEquals("Section 4.2.2: Invalid MonetaryContext(amountType) for " + type.getName(),
158                    f.setNumber(100034L).create().getContext().getAmountType(), type);
159            mc = f.setNumber(0).create().getContext();
160            AssertJUnit.assertEquals("Section 4.2.2: Invalid MonetaryContext(amountType) for " + type.getName(),
161                    mc.getAmountType(), type);
162            if (maxCtx.getPrecision() > 0) {
163                AssertJUnit.assertTrue("Section 4.2.2: Invalid MonetaryContext(precision) for " + type.getName(),
164                        mc.getPrecision() <= maxCtx.getPrecision());
165            }
166            if (maxCtx.getMaxScale() > 0) {
167                AssertJUnit.assertTrue("Section 4.2.2: Invalid MonetaryContext(maxScale) for " + type.getName(),
168                        mc.getMaxScale() <= maxCtx.getMaxScale());
169            }
170        }
171    }
172
173    /**
174     * For each MonetaryAmount implementation: Ensure isNegative()
175     * returns correct results.
176     */
177    @SpecAssertion(section = "4.2.2", id = "422-A4")
178    @Test(description = "4.2.2 For each amount class, test isNegative().")
179    public void testIsNegative() {
180        for (Class type : MonetaryAmounts.getAmountTypes()) {
181            if (type.equals(TestAmount.class)) {
182                continue;
183            }
184            MonetaryAmountFactory<MonetaryAmount> f = getAmountFactory(type);
185            f.setCurrency("CHF");
186            MonetaryAmount[] moneys = new MonetaryAmount[]{f.setNumber(0).create(), f.setNumber(0.0).create(),
187                    f.setNumber(BigDecimal.ZERO).create(), f.setNumber(new BigDecimal("0.00000000000000000")).create(),
188                    f.setNumber(100).create(), f.setNumber(34242344).create(), f.setNumber(23123213.435).create()};
189            for (MonetaryAmount m : moneys) {
190                AssertJUnit.assertFalse("Section 4.2.2: Invalid isNegative (expected false) for " + type.getName(),
191                        m.isNegative());
192            }
193            moneys = new MonetaryAmount[]{f.setNumber(-100).create(), f.setNumber(-34242344).create(),
194                    f.setNumber(-23123213.435).create()};
195            for (MonetaryAmount m : moneys) {
196                AssertJUnit.assertTrue("Section 4.2.2: Invalid isNegative (expected true) for " + type.getName(),
197                        m.isNegative());
198            }
199        }
200    }
201
202    /**
203     * For each MonetaryAmount implementation: Ensure isPositive()
204     * returns correct results.
205     */
206    @SpecAssertion(section = "4.2.2", id = "422-A5")
207    @Test(description = "4.2.2 For each amount class, test isPositive().")
208    public void testIsPositive() {
209        for (Class type : MonetaryAmounts.getAmountTypes()) {
210            if (type.equals(TestAmount.class)) {
211                continue;
212            }
213            MonetaryAmountFactory<MonetaryAmount> f = getAmountFactory(type);
214            f.setCurrency("CHF");
215            MonetaryAmount[] moneys = new MonetaryAmount[]{f.setNumber(100).create(), f.setNumber(34242344).create(),
216                    f.setNumber(23123213.435).create()};
217            for (MonetaryAmount m : moneys) {
218                AssertJUnit.assertTrue("Section 4.2.2: Invalid isPositive (expected true) for " + type.getName(),
219                        m.isPositive());
220            }
221            moneys = new MonetaryAmount[]{f.setNumber(0).create(), f.setNumber(0.0).create(),
222                    f.setNumber(BigDecimal.ZERO).create(), f.setNumber(new BigDecimal("0.00000000000000000")).create(),
223                    f.setNumber(-100).create(), f.setNumber(-34242344).create(), f.setNumber(-23123213.435).create()};
224            for (MonetaryAmount m : moneys) {
225                AssertJUnit.assertFalse("Section 4.2.2: Invalid isPositive (expected false) for " + type.getName(),
226                        m.isPositive());
227            }
228        }
229    }
230
231
232    /**
233     * For each MonetaryAmount implementation: Ensure isZero()
234     * returns correct results.
235     */
236    @SpecAssertion(section = "4.2.2", id = "422-A6")
237    @Test(description = "4.2.2 For each amount class, test isZero().")
238    public void testIsZero() {
239        for (Class type : MonetaryAmounts.getAmountTypes()) {
240            if (type.equals(TestAmount.class)) {
241                continue;
242            }
243            MonetaryAmountFactory<MonetaryAmount> f = getAmountFactory(type);
244            f.setCurrency("CHF");
245            MonetaryAmount[] moneys = new MonetaryAmount[]{f.setNumber(100).create(), f.setNumber(34242344).create(),
246                    f.setNumber(23123213.435).create(), f.setNumber(-100).create(),
247                    f.setNumber(-723527.36532).create()};
248            for (MonetaryAmount m : moneys) {
249                AssertJUnit.assertFalse("Section 4.2.2: Invalid isZero (expected false) for " + type.getName(),
250                        m.isZero());
251            }
252            moneys = new MonetaryAmount[]{f.setNumber(0).create(), f.setNumber(0.0).create(),
253                    f.setNumber(BigDecimal.ZERO).create(), f.setNumber(new BigDecimal("0.00000000000000000")).create()};
254            for (MonetaryAmount m : moneys) {
255                AssertJUnit
256                        .assertTrue("Section 4.2.2: Invalid isZero (expected true) for " + type.getName(), m.isZero());
257            }
258        }
259    }
260
261    /**
262     * For each MonetaryAmount implementation: Ensure isZero()
263     * returns correct results (-0, +0 == 0).
264     */
265    @SpecAssertion(section = "4.2.2", id = "422-A6")
266    @Test(description = "4.2.2 For each amount class, test isZero(), advanced.")
267    public void testIsZeroAdvanced() {
268        for (Class type : MonetaryAmounts.getAmountTypes()) {
269            if (type.equals(TestAmount.class)) {
270                continue;
271            }
272            MonetaryAmountFactory<MonetaryAmount> f = getAmountFactory(type);
273            f.setCurrency("CHF");
274            MonetaryAmount[] moneys =
275                    new MonetaryAmount[]{f.setNumber(-0).create(), f.setNumber(0).create(), f.setNumber(-0.0f).create(),
276                            f.setNumber(0.0f).create(), f.setNumber(-0.0d).create(), f.setNumber(0.0d).create()};
277            for (MonetaryAmount m : moneys) {
278                AssertJUnit
279                        .assertTrue("Section 4.2.2: Invalid isZero (expected true) for " + type.getName(), m.isZero());
280            }
281        }
282    }
283
284    /**
285     * For each MonetaryAmount implementation: signum() function is
286     * implemented correctly.
287     */
288    @SpecAssertion(section = "4.2.2", id = "422-A7")
289    @Test(description = "4.2.2 For each amount class, test signum().")
290    public void testSignum() {
291        for (Class type : MonetaryAmounts.getAmountTypes()) {
292            MonetaryAmountFactory<MonetaryAmount> f = getAmountFactory(type);
293            f.setCurrency("CHF");
294            MonetaryAmount m = f.setNumber(100).create();
295            AssertJUnit.assertEquals("Section 4.2.2: Invalid signum of 100 for " + type.getName(), 1, m.signum());
296            m = f.setNumber(-100).create();
297            AssertJUnit.assertEquals("Section 4.2.2: signum of -100 for " + type.getName(), -1, m.signum());
298            m = f.setNumber(100.3435).create();
299            AssertJUnit.assertEquals("Section 4.2.2: signum of 100.3435 for " + type.getName(), 1, m.signum());
300            m = f.setNumber(-100.3435).create();
301            AssertJUnit.assertEquals("Section 4.2.2: signum of -100.3435 for " + type.getName(), -1, m.signum());
302            m = f.setNumber(0).create();
303            AssertJUnit.assertEquals("Section 4.2.2: signum of 0 for " + type.getName(), 0, m.signum());
304            m = f.setNumber(-0).create();
305            AssertJUnit.assertEquals("Section 4.2.2: signum of - for " + type.getName(), 0, m.signum());
306        }
307    }
308
309    /**
310     * For each MonetaryAmount implementation: Ensure isNegativeOrZero()
311     * returns correct results.
312     */
313    @SpecAssertion(section = "4.2.2", id = "422-A8")
314    @Test(description = "4.2.2 For each amount class, test isNegativeOrZero().")
315    public void testIsNegativeOrZero() {
316        for (Class type : MonetaryAmounts.getAmountTypes()) {
317            if (type.equals(TestAmount.class)) {
318                continue;
319            }
320            MonetaryAmountFactory<MonetaryAmount> f = getAmountFactory(type);
321            f.setCurrency("CHF");
322            MonetaryAmount[] moneys = new MonetaryAmount[]{f.setNumber(100).create(), f.setNumber(34242344).create(),
323                    f.setNumber(23123213.435).create()};
324            for (MonetaryAmount m : moneys) {
325                AssertJUnit.assertFalse("Section 4.2.2: Invalid negativeOrZero (expected false) for " + type.getName(),
326                        m.isNegativeOrZero());
327            }
328            moneys = new MonetaryAmount[]{f.setNumber(0).create(), f.setNumber(0.0).create(),
329                    f.setNumber(BigDecimal.ZERO).create(), f.setNumber(new BigDecimal("0.0000")).create(),
330                    f.setNumber(-100).create(), f.setNumber(-34242344).create(), f.setNumber(-23123213.435).create()};
331            for (MonetaryAmount m : moneys) {
332                AssertJUnit.assertTrue("Section 4.2.2: Invalid negativeOrZero (expected true) for " + type.getName(),
333                        m.isNegativeOrZero());
334            }
335        }
336    }
337
338    /**
339     * For each MonetaryAmount implementation: Ensure isPositiveOrZero()
340     * returns correct results.
341     */
342    @SpecAssertion(section = "4.2.2", id = "422-A9")
343    @Test(description = "4.2.2 For each amount class, test isPositiveOrZero().")
344    public void testIsPositiveOrZero() {
345        for (Class type : MonetaryAmounts.getAmountTypes()) {
346            if (type.equals(TestAmount.class)) {
347                continue;
348            }
349            MonetaryAmountFactory<MonetaryAmount> f = getAmountFactory(type);
350            f.setCurrency("CHF");
351            MonetaryAmount[] moneys = new MonetaryAmount[]{f.setNumber(0).create(), f.setNumber(0.0).create(),
352                    f.setNumber(BigDecimal.ZERO).create(), f.setNumber(new BigDecimal("0.00000000000000000")).create(),
353                    f.setNumber(100).create(), f.setNumber(34242344).create(), f.setNumber(23123213.435).create()};
354            for (MonetaryAmount m : moneys) {
355                AssertJUnit.assertTrue("Section 4.2.2: Invalid positiveOrZero (expected true): for " + type.getName(),
356                        m.isPositiveOrZero());
357            }
358            moneys = new MonetaryAmount[]{f.setNumber(-100).create(), f.setNumber(-34242344).create(),
359                    f.setNumber(-23123213.435).create()};
360            for (MonetaryAmount m : moneys) {
361                AssertJUnit
362                        .assertFalse("Section 4.2.2: Invalid positiveOrZero (expected false) for " + type.getName() + m,
363                                m.isPositiveOrZero());
364            }
365        }
366    }
367
368
369    // ********************* B. Prototyping Support *****************************
370
371    /**
372     * Ensure getFactory returns a MonetaryAmountFactory and that
373     * instances created are of the same type.
374     */
375    @SpecAssertion(section = "4.2.2", id = "422-B1")
376    @Test(description = "4.2.2 For each amount class, access factory and of amounts.")
377    public void testMonetaryAmountFactories() {
378        for (Class type : MonetaryAmounts.getAmountTypes()) {
379            MonetaryAmountFactory<MonetaryAmount> f = getAmountFactory(type);
380            AssertJUnit.assertNotNull(f);
381            MonetaryAmount m = f.setCurrency("CHF").setNumber(10).create();
382            AssertJUnit.assertEquals("Section 4.2.2: Invalid class for created amount, expected: " + type.getName(),
383                    m.getClass(), type);
384            m = f.setCurrency("CHF").setNumber(-10).create();
385            AssertJUnit.assertEquals("Section 4.2.2: Invalid class for created amount, expected: " + type.getName(),
386                    m.getClass(), type);
387            m = f.setCurrency("CHF").setNumber(10.3).create();
388            AssertJUnit.assertEquals("Section 4.2.2: Invalid class for created amount, expected: " + type.getName(),
389                    m.getClass(), type);
390            m = f.setCurrency("CHF").setNumber(-10.3).create();
391            AssertJUnit.assertEquals("Section 4.2.2: Invalid class for created amount, expected: " + type.getName(),
392                    m.getClass(), type);
393            m = f.setCurrency("CHF").setNumber(0.0).create();
394            AssertJUnit.assertEquals("Section 4.2.2: Invalid class for created amount, expected: " + type.getName(),
395                    m.getClass(), type);
396            m = f.setCurrency("CHF").setNumber(-0.0).create();
397            AssertJUnit.assertEquals("Section 4.2.2: Invalid class for created amount, expected: " + type.getName(),
398                    m.getClass(), type);
399        }
400    }
401
402    /**
403     * Call getFactory(), of a new MonetaryAmount instance, with
404     * same input. The instances must
405     * be equal (or even be identical!).
406     */
407    @SpecAssertion(section = "4.2.2", id = "422-B2")
408    @Test(description = "4.2.2 For each amount class, access factory and of amounts, ensure amounts are equal if they" +
409            "should.")
410    public void testMonetaryAmountFactories_InstancesMustBeEqual() {
411        for (Class type : MonetaryAmounts.getAmountTypes()) {
412            if (type.equals(TestAmount.class)) {
413                continue;
414            }
415            MonetaryAmountFactory<MonetaryAmount> f = getAmountFactory(type);
416            MonetaryAmount m1 = f.setCurrency("CHF").setNumber(10).create();
417            f = getAmountFactory(type);
418            MonetaryAmount m2 = f.setCurrency("CHF").setNumber(10).create();
419            AssertJUnit.assertEquals("Section 4.2.2: Expected equal instances for " + type.getName(), m1, m2);
420        }
421
422        for (Class type : MonetaryAmounts.getAmountTypes()) {
423            if (type.equals(TestAmount.class)) {
424                continue;
425            }
426            MonetaryAmountFactory<MonetaryAmount> f = getAmountFactory(type);
427            MonetaryAmount m1 = f.setCurrency("CHF").setNumber(10.5d).create();
428            f = getAmountFactory(type);
429            MonetaryAmount m2 = f.setCurrency("CHF").setNumber(10.5d).create();
430            AssertJUnit
431                    .assertEquals("Section 4.2.2: Expected equal types created by same factory for " + type.getName(),
432                            m1, m2);
433        }
434
435        for (Class type : MonetaryAmounts.getAmountTypes()) {
436            if (type.equals(TestAmount.class)) {
437                continue;
438            }
439            MonetaryAmountFactory<MonetaryAmount> f = getAmountFactory(type);
440            MonetaryAmount m1 = f.setCurrency("CHF").setNumber(new BigDecimal("10.52")).create();
441            f = getAmountFactory(type);
442            MonetaryAmount m2 = f.setCurrency("CHF").setNumber(new BigDecimal("10.52")).create();
443            AssertJUnit
444                    .assertEquals("Section 4.2.2: Expected equal types created by same factory for " + type.getName(),
445                            m1, m2);
446        }
447    }
448
449    /**
450     * Call getFactory(), of a new MonetaryAmount instance with a
451     * new number
452     * value. The instances must
453     * be non equal and have the
454     * according
455     * numeric value.
456     */
457    @SpecAssertion(section = "4.2.2", id = "422-B3")
458    @Test(description = "4.2.2 For each amount class, check new amounts are not equal.")
459    public void testMonetaryAmountFactories_InstantesMustBeNotEqual() {
460        for (Class type : MonetaryAmounts.getAmountTypes()) {
461            MonetaryAmountFactory<MonetaryAmount> f = getAmountFactory(type);
462            MonetaryAmount m1 = f.setCurrency("CHF").setNumber(10).create();
463            f = getAmountFactory(type);
464            MonetaryAmount m2 = f.setCurrency("CHF").setNumber(11).create();
465            AssertJUnit.assertNotSame("Section 4.2.2: Expected non equal instances for " + type.getName(), m1, m2);
466        }
467
468        for (Class type : MonetaryAmounts.getAmountTypes()) {
469            MonetaryAmountFactory f = getAmountFactory(type);
470            MonetaryAmount m1 = f.setCurrency("CHF").setNumber(10.5d).create();
471            f = getAmountFactory(type);
472            MonetaryAmount m2 = f.setCurrency("CHF").setNumber(10.4d).create();
473            AssertJUnit.assertNotSame("Section 4.2.2: Expected non equal instances for " + type.getName(), m1, m2);
474        }
475
476        for (Class type : MonetaryAmounts.getAmountTypes()) {
477            MonetaryAmountFactory<MonetaryAmount> f = getAmountFactory(type);
478            MonetaryAmount m1 = f.setCurrency("CHF").setNumber(new BigDecimal("10.52")).create();
479            f = getAmountFactory(type);
480            MonetaryAmount m2 = f.setCurrency("CHF").setNumber(new BigDecimal("10.11")).create();
481            AssertJUnit.assertNotSame("Section 4.2.2: Expected non equal instances for " + type.getName(), m1, m2);
482        }
483    }
484
485    /**
486     * Call getFactory(),of a new MonetaryAmount instance
487     * with a new currency value.The instances must
488     * be non  equal and have the according currency value .Do this by passing a literal code
489     * and by passing a CurrencyUnit.
490     */
491    @SpecAssertion(section = "4.2.2", id = "422-B4")
492    @Test(description = "4.2.2 For each amount class, check multiple instances are not equal.")
493    public void testMonetaryAmountFactories_CreateWithCurrencies() {
494        for (Class type : MonetaryAmounts.getAmountTypes()) {
495            MonetaryAmountFactory<MonetaryAmount> f = getAmountFactory(type);
496            MonetaryAmount m1 = f.setCurrency("CHF").setNumber(10).create();
497            f = getAmountFactory(type);
498            MonetaryAmount m2 = f.setCurrency("USD").setNumber(10).create();
499            AssertJUnit.assertNotSame("Section 4.2.2: Expected non equal instances for " + type.getName(), m1, m2);
500        }
501
502        for (Class type : MonetaryAmounts.getAmountTypes()) {
503            MonetaryAmountFactory<MonetaryAmount> f = getAmountFactory(type);
504            MonetaryAmount m1 = f.setCurrency("CHF").setNumber(10.5d).create();
505            f = getAmountFactory(type);
506            MonetaryAmount m2 = f.setCurrency("USD").setNumber(10.5d).create();
507            AssertJUnit.assertNotSame("Section 4.2.2: Expected non equal instances for " + type.getName(), m1, m2);
508        }
509
510        for (Class type : MonetaryAmounts.getAmountTypes()) {
511            MonetaryAmountFactory<MonetaryAmount> f = getAmountFactory(type);
512            MonetaryAmount m1 = f.setCurrency("CHF").setNumber(new BigDecimal("10.52")).create();
513            f = getAmountFactory(type);
514            MonetaryAmount m2 = f.setCurrency("USD").setNumber(new BigDecimal("10.52")).create();
515            AssertJUnit.assertNotSame("Section 4.2.2: Expected non equal instances for " + type.getName(), m1, m2);
516        }
517    }
518
519    /**
520     * Call getFactory(),of a  new MonetaryAmount instance
521     * with a new  monetary context(if possible-check the max context). The
522     * instances must be non equal and have the same currency and number value.
523     */
524    @SpecAssertion(section = "4.2.2", id = "422-B5")
525    @Test(description = "4.2.2 For each amount class, check new amounts with explcit MonetaryContext.")
526    public void testMonetaryAmountFactories_CreateWithMonetaryContext() {
527        for (Class type : MonetaryAmounts.getAmountTypes()) {
528            MonetaryAmountFactory<MonetaryAmount> f = getAmountFactory(type);
529            MonetaryContext mc1 = f.getDefaultMonetaryContext();
530            MonetaryContext mc2 = f.getMaximalMonetaryContext();
531            MonetaryAmount m1;
532            MonetaryAmount m2;
533            if (mc1.equals(mc2)) {
534                // In this cases both amount must be equals
535                m1 = f.setCurrency("CHF").setContext(mc1).setNumber(10).create();
536                m2 = f.setCurrency("CHF").setContext(mc2).setNumber(10).create();
537                AssertJUnit.assertNotSame("Section 4.2.2: Expected non equal instances for " + type.getName(), m1, m2);
538            } else {
539                // In this cases both amount must be non equals
540                m1 = f.setCurrency("CHF").setContext(mc1).setNumber(10).create();
541                m2 = f.setCurrency("CHF").setContext(mc2).setNumber(10).create();
542                AssertJUnit.assertNotSame("Section 4.2.2: Expected non equal instances for " + type.getName(), m1, m2);
543            }
544            AssertJUnit.assertTrue("Section 4.2.2: Expected equality for " + type.getName(), m1.equals(m1));
545            AssertJUnit.assertTrue("Section 4.2.2: Expected equality for " + type.getName(), m2.equals(m2));
546        }
547    }
548
549    /**
550     * Call getFactory(),of a new MonetaryAmount instance with a new monetary context, a
551     * new number and a new currency. The instances must be non equal.
552     */
553    @SpecAssertion(section = "4.2.2", id = "422-B6")
554    @Test(description = "4.2.2 For each amount class, check new amounts are not equal for different currencies and " +
555            "contexts.")
556    public void testMonetaryAmountFactories_CreateWithMonetaryContextNumberAndCurrency() {
557        for (Class type : MonetaryAmounts.getAmountTypes()) {
558            if (type.equals(TestAmount.class)) {
559                continue;
560            }
561            MonetaryAmountFactory<MonetaryAmount> f = getAmountFactory(type);
562            MonetaryContext mc1 = f.getDefaultMonetaryContext();
563            MonetaryContext mc2 = f.getMaximalMonetaryContext();
564            MonetaryAmount m1 = f.setCurrency("CHF").setContext(mc1).setNumber(10).create();
565            MonetaryAmount m2 = f.setCurrency("USD").setContext(mc2).setNumber(11).create();
566            AssertJUnit.assertNotSame("Section 4.2.2: Expected not same for " + type.getName(), m1, m2);
567            AssertJUnit.assertTrue("Section 4.2.2: Expected isEqualTo==true for " + type.getName(), m1.isEqualTo(m1));
568            AssertJUnit.assertTrue("Section 4.2.2: Expected isEqualTo==true for " + type.getName(), m2.isEqualTo(m2));
569            AssertJUnit.assertTrue("Section 4.2.2: Expected equality for " + type.getName(), m1.equals(m1));
570            AssertJUnit.assertTrue("Section 4.2.2: Expected equality for " + type.getName(), m2.equals(m2));
571        }
572    }
573
574    // ***************************** C.Comparison Methods *********************************
575
576    /**
577     * Test isGreaterThan() is implemented correctly for each amount type regardless of trailing zeroes.
578     */
579    @SpecAssertion(section = "4.2.2", id = "422-C1")
580    @Test(description = "4.2.2 For each amount class, check isGreaterThan().")
581    public void testMonetaryAmount_isGreaterThan() {
582        for (Class type : MonetaryAmounts.getAmountTypes()) {
583            MonetaryAmountFactory<MonetaryAmount> f = getAmountFactory(type);
584            f.setCurrency("CHF");
585            AssertJUnit.assertFalse("Section 4.2.2: isGreaterThan failed for " + type.getName(),
586                    f.setNumber(BigDecimal.valueOf(0d)).create()
587                            .isGreaterThan(f.setNumber(BigDecimal.valueOf(0)).create()));
588            AssertJUnit.assertTrue("Section 4.2.2: isGreaterThan failed for " + type.getName(),
589                    f.setNumber(BigDecimal.valueOf(0.00001d)).create()
590                            .isGreaterThan(f.setNumber(BigDecimal.valueOf(0d)).create()));
591            AssertJUnit.assertTrue("Section 4.2.2: isGreaterThan failed for " + type.getName(),
592                    f.setNumber(15).create().isGreaterThan(f.setNumber(10).create()));
593            AssertJUnit.assertTrue("Section 4.2.2: isGreaterThan failed for " + type.getName(),
594                    f.setNumber(15.546).create().isGreaterThan(f.setNumber(10.34).create()));
595            AssertJUnit.assertFalse("Section 4.2.2: isGreaterThan failed for " + type.getName(),
596                    f.setNumber(5).create().isGreaterThan(f.setNumber(10).create()));
597            AssertJUnit.assertFalse("Section 4.2.2: isGreaterThan failed for " + type.getName(),
598                    f.setNumber(5.546).create().isGreaterThan(f.setNumber(10.34).create()));
599        }
600    }
601
602    /**
603     * Test isGreaterThanOrEquals() is implemented correctly for each amount type regardless of trailing
604     * zeroes.
605     */
606    @SpecAssertion(section = "4.2.2", id = "422-C2")
607    @Test(description = "4.2.2 For each amount class, check isGreaterThanOrEquals().")
608    public void testMonetaryAmount_isGreaterThanOrEquals() {
609        for (Class type : MonetaryAmounts.getAmountTypes()) {
610            MonetaryAmountFactory<MonetaryAmount> f = getAmountFactory(type);
611            f.setCurrency("CHF");
612            AssertJUnit.assertTrue("Section 4.2.2: isGreaterThanOrEqualTo failed for " + type.getName(),
613                    f.setNumber(BigDecimal.valueOf(0d)).create()
614                            .isGreaterThanOrEqualTo(f.setNumber(BigDecimal.valueOf(0)).create()));
615            AssertJUnit.assertTrue("Section 4.2.2: isGreaterThanOrEqualTo failed for " + type.getName(),
616                    f.setNumber(BigDecimal.valueOf(0.00001d)).create()
617                            .isGreaterThanOrEqualTo(f.setNumber(BigDecimal.valueOf(0d)).create()));
618            AssertJUnit.assertTrue("Section 4.2.2: isGreaterThanOrEqualTo failed for " + type.getName(),
619                    f.setNumber(15).create().isGreaterThanOrEqualTo(f.setNumber(10).create()));
620            AssertJUnit.assertTrue("Section 4.2.2: isGreaterThanOrEqualTo failed for " + type.getName(),
621                    f.setNumber(15.546).create().isGreaterThanOrEqualTo(f.setNumber(10.34).create()));
622            AssertJUnit.assertFalse("Section 4.2.2: isGreaterThanOrEqualTo failed for " + type.getName(),
623                    f.setNumber(5).create().isGreaterThanOrEqualTo(f.setNumber(10).create()));
624            AssertJUnit.assertFalse("Section 4.2.2: isGreaterThanOrEqualTo failed for " + type.getName(),
625                    f.setNumber(5.546).create().isGreaterThanOrEqualTo(f.setNumber(10.34).create()));
626        }
627    }
628
629    /**
630     * Test isLessThan() is implemented correctly for each amount type regardless of trailing
631     * zeroes.
632     */
633    @SpecAssertion(section = "4.2.2", id = "422-C3")
634    @Test(description = "4.2.2 For each amount class, check isLessThan().")
635    public void testMonetaryAmount_isLessThan() {
636        for (Class type : MonetaryAmounts.getAmountTypes()) {
637            MonetaryAmountFactory<MonetaryAmount> f = getAmountFactory(type);
638            f.setCurrency("CHF");
639            AssertJUnit.assertFalse("Section 4.2.2: isLessThan failed for " + type.getName(),
640                    f.setNumber(BigDecimal.valueOf(0d)).create()
641                            .isLessThan(f.setNumber(BigDecimal.valueOf(0)).create()));
642            AssertJUnit.assertFalse("Section 4.2.2: isLessThan failed for " + type.getName(),
643                    f.setNumber(BigDecimal.valueOf(0.00001d)).create()
644                            .isLessThan(f.setNumber(BigDecimal.valueOf(0d)).create()));
645            AssertJUnit.assertFalse("Section 4.2.2: isLessThan failed for " + type.getName(),
646                    f.setNumber(15).create().isLessThan(f.setNumber(10).create()));
647            AssertJUnit.assertFalse("Section 4.2.2: isLessThan failed for " + type.getName(),
648                    f.setNumber(15.546).create().isLessThan(f.setNumber(10.34).create()));
649            AssertJUnit.assertTrue("Section 4.2.2: isLessThan failed for " + type.getName(),
650                    f.setNumber(5).create().isLessThan(f.setNumber(10).create()));
651            AssertJUnit.assertTrue("Section 4.2.2: isLessThan failed for " + type.getName(),
652                    f.setNumber(5.546).create().isLessThan(f.setNumber(10.34).create()));
653        }
654    }
655
656    /**
657     * Test isLessThanOrEquals() is implemented correctly for each amount type regardless of trailing
658     * zeroes.
659     */
660    @SpecAssertion(section = "4.2.2", id = "422-C4")
661    @Test(description = "4.2.2 For each amount class, check isLessThanOrEqualTo().")
662    public void testMonetaryAmount_isLessThanOrEqualTo() {
663        for (Class type : MonetaryAmounts.getAmountTypes()) {
664            if (type.equals(TestAmount.class)) {
665                continue;
666            }
667            MonetaryAmountFactory<MonetaryAmount> f = getAmountFactory(type);
668            f.setCurrency("CHF");
669            AssertJUnit.assertTrue("Section 4.2.2: isLessThanOrEqualTo failed for " + type.getName(),
670                    f.setNumber(BigDecimal.valueOf(0d)).create()
671                            .isLessThanOrEqualTo(f.setNumber(BigDecimal.valueOf(0)).create()));
672            AssertJUnit.assertFalse("Section 4.2.2: isLessThanOrEqualTo failed for " + type.getName(),
673                    f.setNumber(BigDecimal.valueOf(0.00001d)).create()
674                            .isLessThanOrEqualTo(f.setNumber(BigDecimal.valueOf(0d)).create()));
675            AssertJUnit.assertFalse("Section 4.2.2: isLessThanOrEqualTo failed for " + type.getName(),
676                    f.setNumber(15).create().isLessThanOrEqualTo(f.setNumber(10).create()));
677            AssertJUnit.assertFalse("Section 4.2.2: isLessThan failed for " + type.getName(),
678                    f.setNumber(15.546).create().isLessThan(f.setNumber(10.34).create()));
679            AssertJUnit.assertTrue("Section 4.2.2: isLessThanOrEqualTo failed for " + type.getName(),
680                    f.setNumber(5).create().isLessThanOrEqualTo(f.setNumber(10).create()));
681            AssertJUnit.assertTrue("Section 4.2.2: isLessThanOrEqualTo failed for " + type.getName(),
682                    f.setNumber(5.546).create().isLessThanOrEqualTo(f.setNumber(10.34).create()));
683        }
684    }
685
686    /**
687     * Test isEqualTo() is implemented correctly for each amount type regardless of trailing
688     * zeroes.
689     */
690    @SpecAssertion(section = "4.2.2", id = "422-C5")
691    @Test(description = "4.2.2 For each amount class, check isEqualTo().")
692    public void testMonetaryAmount_isEqualTo() {
693        for (Class type : MonetaryAmounts.getAmountTypes()) {
694            if (type.equals(TestAmount.class)) {
695                continue;
696            }
697            MonetaryAmountFactory<MonetaryAmount> f = getAmountFactory(type);
698            f.setCurrency("CHF");
699            AssertJUnit.assertTrue("Section 4.2.2: isEqualTo failed for " + type.getName(),
700                    f.setNumber(BigDecimal.valueOf(0d)).create()
701                            .isEqualTo(f.setNumber(BigDecimal.valueOf(0)).create()));
702            AssertJUnit.assertFalse("Section 4.2.2: isEqualTo failed for " + type.getName(),
703                    f.setNumber(BigDecimal.valueOf(0.00001d)).create()
704                            .isEqualTo(f.setNumber(BigDecimal.valueOf(0d)).create()));
705            AssertJUnit.assertTrue("isEqualTo failed for " + type.getName(),
706                    f.setNumber(BigDecimal.valueOf(5d)).create()
707                            .isEqualTo(f.setNumber(BigDecimal.valueOf(5)).create()));
708            AssertJUnit.assertTrue("Section 4.2.2: isEqualTo failed for " + type.getName(),
709                    f.setNumber(BigDecimal.valueOf(1d)).create()
710                            .isEqualTo(f.setNumber(BigDecimal.valueOf(1.00)).create()));
711            AssertJUnit.assertTrue("Section 4.2.2: isEqualTo failed for " + type.getName(),
712                    f.setNumber(BigDecimal.valueOf(1d)).create()
713                            .isEqualTo(f.setNumber(BigDecimal.ONE).create()));
714            AssertJUnit.assertTrue("Section 4.2.2: isEqualTo failed for " + type.getName(),
715                    f.setNumber(BigDecimal.valueOf(1)).create()
716                            .isEqualTo(f.setNumber(BigDecimal.ONE).create()));
717            AssertJUnit.assertTrue("Section 4.2.2: isEqualTo failed for " + type.getName(),
718                    f.setNumber(new BigDecimal("1.0000")).create()
719                            .isEqualTo(f.setNumber(new BigDecimal("1.00")).create()));
720            // Test with different scales, but numeric equal values
721            AssertJUnit.assertTrue("Section 4.2.2: isEqualTo failed for " + type.getName(),
722                    f.setNumber(BigDecimal.valueOf(0d)).create()
723                            .isEqualTo(f.setNumber(BigDecimal.valueOf(0)).create()));
724            AssertJUnit.assertTrue("Section 4.2.2: isEqualTo failed for " + type.getName(),
725                    f.setNumber(BigDecimal.ZERO).create()
726                            .isEqualTo(f.setNumber(BigDecimal.valueOf(0)).create()));
727            AssertJUnit.assertTrue("Section 4.2.2: isEqualTo failed for " + type.getName(),
728                    f.setNumber(BigDecimal.valueOf(5)).create()
729                            .isEqualTo(f.setNumber(new BigDecimal("5.0")).create()));
730            AssertJUnit.assertTrue("Section 4.2.2: isEqualTo failed for " + type.getName(),
731                    f.setNumber(BigDecimal.valueOf(5)).create()
732                            .isEqualTo(f.setNumber(new BigDecimal("5.00")).create()));
733            AssertJUnit.assertTrue("Section 4.2.2: isEqualTo failed for " + type.getName(),
734                    f.setNumber(BigDecimal.valueOf(5)).create()
735                            .isEqualTo(f.setNumber(new BigDecimal("5.000")).create()));
736            AssertJUnit.assertTrue("Section 4.2.2: isEqualTo failed for " + type.getName(),
737                    f.setNumber(BigDecimal.valueOf(5)).create()
738                            .isEqualTo(f.setNumber(new BigDecimal("5.0000")).create()));
739            AssertJUnit.assertTrue("Section 4.2.2: isEqualTo failed for " + type.getName(),
740                    f.setNumber(new BigDecimal("-1.23")).create()
741                            .isEqualTo(f.setNumber(new BigDecimal("-1.23")).create()));
742            try {
743                AssertJUnit.assertTrue("Section 4.2.2: isEqualTo failed for " + type.getName(),
744                        f.setNumber(new BigDecimal("-1.23")).create()
745                                .isEqualTo(f.setNumber(new BigDecimal("-1.230")).create()));
746                AssertJUnit.assertTrue("Section 4.2.2: isEqualTo failed for " + type.getName(),
747                        f.setNumber(new BigDecimal("-1.23")).create()
748                                .isEqualTo(f.setNumber(new BigDecimal("-1.2300")).create()));
749                AssertJUnit.assertTrue("Section 4.2.2: isEqualTo failed for " + type.getName(),
750                        f.setNumber(new BigDecimal("-1.23")).create()
751                                .isEqualTo(f.setNumber(new BigDecimal("-1.23000")).create()));
752                AssertJUnit.assertTrue("Section 4.2.2: isEqualTo failed for " + type.getName(),
753                        f.setNumber(new BigDecimal("-1.23")).create().isEqualTo(
754                                f.setNumber(new BigDecimal("-1.230000000000000000000")).create()));
755            } catch (MonetaryException e) {
756                // happens if we exceed the limits...
757            }
758        }
759    }
760
761    /**
762     * For two amounts with same numeric value and currency:
763     * {@code }isEqualTo()} return true, regardless of MonetaryContext.
764     */
765    @SpecAssertion(section = "4.2.2", id = "422-C6")
766    @Test(description = "4.2.2 For each amount class, check isEqualTo(), regardless different MonetaryContext " +
767            "instances.")
768    public void testMonetaryAmount_isEqualToRegardlessMonetaryContext() {
769        for (Class type : MonetaryAmounts.getAmountTypes()) {
770            if (type.equals(TestAmount.class)) {
771                continue;
772            }
773            MonetaryAmountFactory<MonetaryAmount> f = getAmountFactory(type);
774            MonetaryContext mc1 = f.getDefaultMonetaryContext();
775            MonetaryContext mc2 = f.getMaximalMonetaryContext();
776            MonetaryAmount m1;
777            MonetaryAmount m2;
778            if (mc1.equals(mc2)) {
779                // In this cases both amount must be equals
780                m1 = f.setCurrency("CHF").setContext(mc1).setNumber(10).create();
781                m2 = f.setCurrency("CHF").setContext(mc2).setNumber(10).create();
782                AssertJUnit.assertEquals("Section 4.2.2: m1.equals(m2) must be true for m1=" + m1 + " and m2=" + m2, m1,
783                        m2);
784                m1 = f.setCurrency("CHF").setContext(mc1).setNumber(10.5d).create();
785                m2 = f.setCurrency("CHF").setContext(mc2).setNumber(10.5d).create();
786                AssertJUnit.assertEquals("Section 4.2.2: m1.equals(m2) must be true for m1=" + m1 + " and m2=" + m2, m1,
787                        m2);
788                m1 = f.setCurrency("CHF").setContext(mc1).setNumber(BigDecimal.TEN).create();
789                m2 = f.setCurrency("CHF").setContext(mc2).setNumber(BigDecimal.TEN).create();
790                AssertJUnit.assertEquals("Section 4.2.2: m1.equals(m2) must be true for m1=" + m1 + " and m2=" + m2, m1,
791                        m2);
792            } else {
793                // In this cases both amount must be non equals
794                m1 = f.setCurrency("CHF").setContext(mc1).setNumber(10).create();
795                m2 = f.setCurrency("CHF").setContext(mc2).setNumber(10).create();
796                AssertJUnit
797                        .assertNotSame("Section 4.2.2: m1.equals(m2) must be false for m1=" + m1 + " and m2=" + m2, m1,
798                                m2);
799                AssertJUnit.assertTrue("Section 4.2.2: m1.isEqualTo(m2) must be true for m1=" + m1 + " and m2=" + m2,
800                        m1.isEqualTo(m2));
801                AssertJUnit.assertTrue("Section 4.2.2: m1.isEqualTo(m2) must be true for m1=" + m2 + " and m2=" + m1,
802                        m2.isEqualTo(m1));
803                m1 = f.setCurrency("CHF").setContext(mc1).setNumber(10.5d).create();
804                m2 = f.setCurrency("CHF").setContext(mc2).setNumber(10.5d).create();
805                AssertJUnit
806                        .assertNotSame("Section 4.2.2: m1.equals(m2) must be false for m1=" + m1 + " and m2=" + m2, m1,
807                                m2);
808                AssertJUnit.assertTrue("Section 4.2.2: m1.isEqualTo(m2) must be true for m1=" + m1 + " and m2=" + m2,
809                        m1.isEqualTo(m2));
810                AssertJUnit.assertTrue("Section 4.2.2: m1.isEqualTo(m2) must be true for m1=" + m2 + " and m2=" + m1,
811                        m2.isEqualTo(m1));
812                m1 = f.setCurrency("CHF").setContext(mc1).setNumber(BigDecimal.TEN).create();
813                m2 = f.setCurrency("CHF").setContext(mc2).setNumber(BigDecimal.TEN).create();
814                AssertJUnit
815                        .assertNotSame("Section 4.2.2: m1.equals(m2) must be false for m1=" + m1 + " and m2=" + m2, m1,
816                                m2);
817                AssertJUnit.assertTrue("Section 4.2.2: m1.isEqualTo(m2) must be true for m1=" + m1 + " and m2=" + m2,
818                        m1.isEqualTo(m2));
819                AssertJUnit.assertTrue("Section 4.2.2: m1.isEqualTo(m2) must be true for m1=" + m2 + " and m2=" + m1,
820                        m2.isEqualTo(m1));
821            }
822            AssertJUnit.assertTrue("Section 4.2.2: m.isEqualTo(m) must be true for " + m1, m1.isEqualTo(m1));
823            AssertJUnit.assertTrue("Section 4.2.2: m.isEqualTo(m) must be true for " + m2, m2.isEqualTo(m2));
824        }
825    }
826
827    /**
828     * For two amounts with same numeric value and currency:
829     * {@code }isEqualTo()} return true, regardless of iumplementation type.
830     */
831    @SpecAssertion(section = "4.2.2", id = "422-C7")
832    @Test(description = "4.2.2 For each amount class, check isEqualTo(), regardless implementation type.")
833    public void testMonetaryAmount_isEqualToRegardlessType() {
834        List<MonetaryAmount> instances = new ArrayList<>();
835        for (Class type : MonetaryAmounts.getAmountTypes()) {
836            MonetaryAmountFactory f = getAmountFactory(type);
837            f.setCurrency("CHF");
838            instances.add(f.setNumber(10).create());
839            instances.add(f.setNumber(10.0d).create());
840            instances.add(f.setNumber(BigDecimal.TEN).create());
841        }
842        // compare each other...
843        for (int i = 0; i < instances.size(); i++) {
844            for (int j = 0; j < instances.size(); j++) {
845                MonetaryAmount mi = instances.get(i);
846                MonetaryAmount mj = instances.get(j);
847                AssertJUnit
848                        .assertTrue("Section 4.2.2: isEqualTo must be true for " + mi + " and " + mj, mi.isEqualTo(mj));
849            }
850        }
851    }
852
853    /**
854     * Tests that add() correctly adds two values, using positive integers.
855     */
856    @SpecAssertion(section = "4.2.2", id = "422-D1")
857    @Test(description = "4.2.2 For each amount class, check m1.add(m2), m1 >0, m2>0.")
858    public void testAddPositiveIntegers() {
859        for (Class type : MonetaryAmounts.getAmountTypes()) {
860            if (type.equals(TestAmount.class)) {
861                continue;
862            }
863            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
864            MonetaryAmount mAmount2 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(20).create();
865            MonetaryAmount mActualResult = mAmount1.add(mAmount2);
866            MonetaryAmount mExpectedResult =
867                    getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(30).create();
868            AssertJUnit.assertEquals(
869                    "Section 4.2.2: Adding two simple ammounts failed, " + mAmount1 + " + " + mAmount2 + " != " +
870                            mExpectedResult, mExpectedResult, mActualResult);
871        }
872    }
873
874    /**
875     * Tests that add() correctly adds two values, using negative integers.
876     */
877    @SpecAssertion(section = "4.2.2", id = "422-D1")
878    @Test(description = "4.2.2 For each amount class, check m1.add(m2), m1 <0, m2<0.")
879    public void testAddNegativeIntegers() {
880        for (Class type : MonetaryAmounts.getAmountTypes()) {
881            if (type.equals(TestAmount.class)) {
882                continue;
883            }
884            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(-10).create();
885            MonetaryAmount mAmount2 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(-20).create();
886            MonetaryAmount mActualResult = mAmount1.add(mAmount2);
887            MonetaryAmount mExpectedResult =
888                    getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(-30).create();
889            AssertJUnit.assertEquals("Section 4.2.2: Adding two simple ammounts", mExpectedResult, mActualResult);
890        }
891    }
892
893    /**
894     * Tests that add() correctly adds two values, using fractions.
895     */
896    @SpecAssertion(section = "4.2.2", id = "422-D1")
897    @Test(description = "4.2.2 For each amount class, check m1.add(m2), m2 is fraction.")
898    public void testAddPositiveFractions() {
899        for (Class type : MonetaryAmounts.getAmountTypes()) {
900            if (type.equals(TestAmount.class)) {
901                continue;
902            }
903            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(1.5).create();
904            MonetaryAmount mAmount2 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(2.85).create();
905            MonetaryAmount mActualResult = mAmount1.add(mAmount2);
906            MonetaryAmount mExpectedResult =
907                    getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(4.35).create();
908            AssertJUnit.assertEquals("Section 4.2.2: Adding two simple ammounts", mExpectedResult, mActualResult);
909        }
910    }
911
912    /**
913     * Tests that add() correctly adds two values, using positive and negative integers.
914     */
915    @SpecAssertion(section = "4.2.2", id = "422-D1")
916    @Test(description = "4.2.2 For each amount class, check m1.add(m2), m1, m2 = mixed ints.")
917    public void testAddMixedIntegers() {
918        for (Class type : MonetaryAmounts.getAmountTypes()) {
919            if (type.equals(TestAmount.class)) {
920                continue;
921            }
922            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(-10).create();
923            MonetaryAmount mAmount2 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(20).create();
924            MonetaryAmount mActualResult = mAmount1.add(mAmount2);
925            MonetaryAmount mExpectedResult =
926                    getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
927            AssertJUnit.assertEquals("Section 4.2.2: Adding two simple ammounts", mExpectedResult, mActualResult);
928        }
929        for (Class type : MonetaryAmounts.getAmountTypes()) {
930            if (type.equals(TestAmount.class)) {
931                continue;
932            }
933            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(-20).create();
934            MonetaryAmount mAmount2 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
935            MonetaryAmount mActualResult = mAmount1.add(mAmount2);
936            MonetaryAmount mExpectedResult =
937                    getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(-10).create();
938            AssertJUnit.assertEquals("Section 4.2.2: Adding two simple ammounts", mExpectedResult, mActualResult);
939        }
940        for (Class type : MonetaryAmounts.getAmountTypes()) {
941            if (type.equals(TestAmount.class)) {
942                continue;
943            }
944            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(-10).create();
945            MonetaryAmount mAmount2 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
946            MonetaryAmount mActualResult = mAmount1.add(mAmount2);
947            MonetaryAmount mExpectedResult = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(0).create();
948            AssertJUnit.assertEquals("Section 4.2.2: Adding two simple ammounts", mExpectedResult, mActualResult);
949        }
950    }
951
952    /**
953     * Tests that add() correctly adds two values, using positive and negative fractions.
954     */
955    @SpecAssertion(section = "4.2.2", id = "422-D1")
956    @Test(description = "4.2.2 For each amount class, check m1.add(m2), m1, m2 = mixed fractions.")
957    public void testAddMixedFractions() {
958        for (Class type : MonetaryAmounts.getAmountTypes()) {
959            if (type.equals(TestAmount.class)) {
960                continue;
961            }
962            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(1.5).create();
963            MonetaryAmount mAmount2 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(-2.85).create();
964            MonetaryAmount mActualResult = mAmount1.add(mAmount2);
965            MonetaryAmount mExpectedResult =
966                    getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(-1.35).create();
967            AssertJUnit.assertEquals("Section 4.2.2: Adding two simple ammounts", mExpectedResult, mActualResult);
968        }
969        for (Class type : MonetaryAmounts.getAmountTypes()) {
970            if (type.equals(TestAmount.class)) {
971                continue;
972            }
973            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(-1.5).create();
974            MonetaryAmount mAmount2 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(+2.85).create();
975            MonetaryAmount mActualResult = mAmount1.add(mAmount2);
976            MonetaryAmount mExpectedResult =
977                    getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(1.35).create();
978            AssertJUnit.assertEquals("Section 4.2.2: Adding two simple ammounts", mExpectedResult, mActualResult);
979        }
980        for (Class type : MonetaryAmounts.getAmountTypes()) {
981            if (type.equals(TestAmount.class)) {
982                continue;
983            }
984            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(-2.85).create();
985            MonetaryAmount mAmount2 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(+2.85).create();
986            MonetaryAmount mActualResult = mAmount1.add(mAmount2);
987            MonetaryAmount mExpectedResult = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(0).create();
988            AssertJUnit.assertEquals("Section 4.2.2: Adding two simple ammounts", mExpectedResult, mActualResult);
989        }
990    }
991
992    /**
993     * Tests that add() with non matching currencies throws a
994     * MonetaryException.
995     */
996    @SpecAssertion(section = "4.2.2", id = "422-D2")
997    @Test(description = "4.2.2 For each amount class, ensure currency compatibility is working.")
998    public void testAdd_IncompatibleCurrencies() {
999        for (Class type : MonetaryAmounts.getAmountTypes()) {
1000            if (type.equals(TestAmount.class)) {
1001                continue;
1002            }
1003            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
1004            MonetaryAmount mAmount2 = getAmountFactory(type).setCurrency(ADDITIONAL_CURRENCY).setNumber(20).create();
1005            try {
1006                mAmount1.add(mAmount2);
1007                AssertJUnit.fail("Section 4.2.2: Exception expected");
1008            } catch (MonetaryException ex) {
1009                // Expected
1010            }
1011        }
1012    }
1013
1014    /**
1015     * Tests that add(0) should return itself.
1016     */
1017    @SpecAssertion(section = "4.2.2", id = "422-D3")
1018    @Test(description = "4.2.2 For each amount class, ensure m2 = m1,add(0) -> m1==m2.")
1019    public void testAdd_Zero() {
1020        for (Class type : MonetaryAmounts.getAmountTypes()) {
1021            if (type.equals(TestAmount.class)) {
1022                continue;
1023            }
1024            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
1025            MonetaryAmount mAmount2 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(0).create();
1026            MonetaryAmount mActualResult = mAmount1.add(mAmount2);
1027            AssertJUnit.assertEquals("Section 4.2.2: Adding zero", mAmount1, mActualResult);
1028        }
1029    }
1030
1031    /**
1032     * Tests that add(), which results in an amount exceeding the max MonetaryContext throws
1033     * a MonetaryException.
1034     */
1035    @SpecAssertion(section = "4.2.2", id = "422-D4")
1036    @Test(description = "4.2.2 For each amount class, ensure ArithemticException is thrown when adding exceeding " +
1037            "values.")
1038    public void testAdd_ExceedsCapabilities() {
1039        for (Class type : MonetaryAmounts.getAmountTypes()) {
1040            if (type.equals(TestAmount.class)) {
1041                continue;
1042            }
1043            MonetaryAmountFactory<MonetaryAmount> f = getAmountFactory(type);
1044            f.setCurrency("CHF");
1045            MonetaryContext maxCtx = f.getMaximalMonetaryContext();
1046            if (maxCtx.getPrecision() > 0) {
1047                MonetaryAmount m = f.setNumber(f.getMaxNumber()).create();
1048                MonetaryAmount ms = m;
1049                try {
1050                    for (int i = 0; i < 20; i++) {
1051                        ms = ms.add(ms);
1052                    }
1053                    AssertJUnit.fail("Section 4.2.2: ArithmeticException expected, since adding 20x " + m + " to " + m +
1054                            " exceeds capabilities (precision) for " +
1055                            type.getName());
1056                } catch (ArithmeticException ex) {
1057                    // Expected
1058                } catch (Exception e) {
1059                    AssertJUnit.fail("Section 4.2.2: Addition of amount " + ms + " to " + ms +
1060                            " exceeds max monetary context(scale), " +
1061                            "but did not throw an ArithmeticException (exception thrown was " +
1062                            e.getClass().getName() + "), type was " +
1063                            type);
1064                }
1065            }
1066        }
1067        for (Class type : MonetaryAmounts.getAmountTypes()) {
1068            if (type.equals(TestAmount.class)) {
1069                continue;
1070            }
1071            MonetaryAmountFactory<MonetaryAmount> f = getAmountFactory(type);
1072            f.setCurrency("CHF");
1073            MonetaryContext maxCtx = f.getMaximalMonetaryContext();
1074            if (maxCtx.getMaxScale() >= 0) {
1075                try {
1076                    MonetaryAmount m = f.setNumber(1).create();
1077                    MonetaryAmount m2 =
1078                            f.setNumber(TestUtils.createNumberWithScale(f, maxCtx.getMaxScale() + 5)).create();
1079                    m.add(m2);
1080                    AssertJUnit.fail("Section 4.2.2: Exception expected, since adding " + m2 + " to " + m +
1081                            " exceeds capabilities (scale) for " +
1082                            type.getName());
1083                } catch (ArithmeticException ex) {
1084                    // Expected
1085                }
1086            }
1087        }
1088    }
1089
1090
1091    /**
1092     * Tests that add(), which results in an amount exceeding the max MonetaryContext throws
1093     * a MonetaryException.
1094     */
1095    @SpecAssertion(section = "4.2.2", id = "422-D5")
1096    @Test(description = "4.2.2 For each amount class, ensure NullPointerException is thrown when calling m.add(null).")
1097    public void testAdd_Null() {
1098        for (Class type : MonetaryAmounts.getAmountTypes()) {
1099            if (type.equals(TestAmount.class)) {
1100                continue;
1101            }
1102            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
1103            try {
1104                MonetaryAmount mActualResult = mAmount1.add(null);
1105                AssertJUnit.fail("Section 4.2.2: MonetaryAmount.add(null): NullPointerException expected");
1106            } catch (NullPointerException ex) {
1107                // Expected
1108            }
1109        }
1110    }
1111
1112
1113    /**
1114     * Tests that subtract() correctly adds two values, using positive integers.
1115     */
1116    @SpecAssertion(section = "4.2.2", id = "422-D6")
1117    @Test(description = "4.2.2 For each amount class, ensure correct subtraction of positive ints.")
1118    public void testSubtractPositiveIntegers() {
1119        for (Class type : MonetaryAmounts.getAmountTypes()) {
1120            if (type.equals(TestAmount.class)) {
1121                continue;
1122            }
1123            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
1124            MonetaryAmount mAmount2 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(20).create();
1125            MonetaryAmount mActualResult = mAmount1.subtract(mAmount2);
1126            MonetaryAmount mExpectedResult =
1127                    getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(-10).create();
1128            AssertJUnit.assertEquals("Section 4.2.2: Subtracting two simple ammounts", mExpectedResult, mActualResult);
1129        }
1130    }
1131
1132    /**
1133     * Tests that subtract() correctly adds two values, using negative integers.
1134     */
1135    @SpecAssertion(section = "4.2.2", id = "422-D6")
1136    @Test(description = "4.2.2 For each amount class, ensure correct subtraction of negative ints.")
1137    public void testSubtractNegativeIntegers() {
1138        for (Class type : MonetaryAmounts.getAmountTypes()) {
1139            if (type.equals(TestAmount.class)) {
1140                continue;
1141            }
1142            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(-10).create();
1143            MonetaryAmount mAmount2 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(-20).create();
1144            MonetaryAmount mActualResult = mAmount1.subtract(mAmount2);
1145            MonetaryAmount mExpectedResult =
1146                    getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
1147            AssertJUnit.assertEquals("Section 4.2.2: Subtracting two simple ammounts", mExpectedResult, mActualResult);
1148        }
1149    }
1150
1151    /**
1152     * Tests that subtract() correctly adds two values, using fractions.
1153     */
1154    @SpecAssertion(section = "4.2.2", id = "422-D6")
1155    @Test(description = "4.2.2 For each amount class, ensure correct subtraction of positive fractions.")
1156    public void testSubtractPositiveFractions() {
1157        for (Class type : MonetaryAmounts.getAmountTypes()) {
1158            if (type.equals(TestAmount.class)) {
1159                continue;
1160            }
1161            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(1.5).create();
1162            MonetaryAmount mAmount2 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(2.85).create();
1163            MonetaryAmount mActualResult = mAmount1.subtract(mAmount2);
1164            MonetaryAmount mExpectedResult =
1165                    getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(-1.35).create();
1166            AssertJUnit.assertEquals("Section 4.2.2: Adding two simple ammounts", mExpectedResult, mActualResult);
1167        }
1168    }
1169
1170    /**
1171     * Tests that subtract() correctly adds two values, using positive and negative integers.
1172     */
1173    @SpecAssertion(section = "4.2.2", id = "422-D6")
1174    @Test(description = "4.2.2 For each amount class, ensure correct subtraction of mixed ints.")
1175    public void testSubtractMixedIntegers() {
1176        for (Class type : MonetaryAmounts.getAmountTypes()) {
1177            if (type.equals(TestAmount.class)) {
1178                continue;
1179            }
1180            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(20).create();
1181            MonetaryAmount mAmount2 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
1182            MonetaryAmount mActualResult = mAmount1.subtract(mAmount2);
1183            MonetaryAmount mExpectedResult =
1184                    getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
1185            AssertJUnit.assertEquals("Section 4.2.2: Adding two simple ammounts", mExpectedResult, mActualResult);
1186        }
1187        for (Class type : MonetaryAmounts.getAmountTypes()) {
1188            if (type.equals(TestAmount.class)) {
1189                continue;
1190            }
1191            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
1192            MonetaryAmount mAmount2 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
1193            MonetaryAmount mActualResult = mAmount1.subtract(mAmount2);
1194            MonetaryAmount mExpectedResult = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(0).create();
1195            AssertJUnit.assertEquals("Section 4.2.2: Adding two simple ammounts", mExpectedResult, mActualResult);
1196        }
1197        for (Class type : MonetaryAmounts.getAmountTypes()) {
1198            if (type.equals(TestAmount.class)) {
1199                continue;
1200            }
1201            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(-10).create();
1202            MonetaryAmount mAmount2 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
1203            MonetaryAmount mActualResult = mAmount1.subtract(mAmount2);
1204            MonetaryAmount mExpectedResult =
1205                    getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(-20).create();
1206            AssertJUnit.assertEquals("Section 4.2.2: Adding two simple ammounts", mExpectedResult, mActualResult);
1207        }
1208    }
1209
1210    /**
1211     * Tests that subtract() correctly adds two values, using positive and negative fractions.
1212     */
1213    @SpecAssertion(section = "4.2.2", id = "422-D6")
1214    @Test(description = "4.2.2 For each amount class, ensure correct subtraction of mixed fractions.")
1215    public void testSubtractMixedFractions() {
1216        for (Class type : MonetaryAmounts.getAmountTypes()) {
1217            if (type.equals(TestAmount.class)) {
1218                continue;
1219            }
1220            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(1.5).create();
1221            MonetaryAmount mAmount2 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(-2.85).create();
1222            MonetaryAmount mActualResult = mAmount1.subtract(mAmount2);
1223            MonetaryAmount mExpectedResult =
1224                    getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(4.35).create();
1225            AssertJUnit.assertEquals("Section 4.2.2: Adding two simple ammounts", mExpectedResult, mActualResult);
1226        }
1227        for (Class type : MonetaryAmounts.getAmountTypes()) {
1228            if (type.equals(TestAmount.class)) {
1229                continue;
1230            }
1231            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(-1.5).create();
1232            MonetaryAmount mAmount2 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(+2.85).create();
1233            MonetaryAmount mActualResult = mAmount1.subtract(mAmount2);
1234            MonetaryAmount mExpectedResult =
1235                    getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(-4.35).create();
1236            AssertJUnit.assertEquals("Section 4.2.2: Adding two simple ammounts", mExpectedResult, mActualResult);
1237        }
1238        for (Class type : MonetaryAmounts.getAmountTypes()) {
1239            if (type.equals(TestAmount.class)) {
1240                continue;
1241            }
1242            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(2.85).create();
1243            MonetaryAmount mAmount2 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(+2.85).create();
1244            MonetaryAmount mActualResult = mAmount1.subtract(mAmount2);
1245            MonetaryAmount mExpectedResult = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(0).create();
1246            AssertJUnit.assertEquals("Section 4.2.2: Adding two simple ammounts", mExpectedResult, mActualResult);
1247        }
1248    }
1249
1250    /**
1251     * Tests that subtract() with non matching currencies throws a
1252     * MonetaryException.
1253     */
1254    @SpecAssertion(section = "4.2.2", id = "422-D8")
1255    @Test(description = "4.2.2 For each amount class, ensure subtraction with invalid currency throws " +
1256            "MonetaryException.")
1257    public void testSubtract_IncompatibleCurrencies() {
1258        for (Class type : MonetaryAmounts.getAmountTypes()) {
1259            if (type.equals(TestAmount.class)) {
1260                continue;
1261            }
1262            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
1263            MonetaryAmount mAmount2 = getAmountFactory(type).setCurrency(ADDITIONAL_CURRENCY).setNumber(20).create();
1264            try {
1265                MonetaryAmount mActualResult = mAmount1.subtract(mAmount2);
1266                AssertJUnit.fail("Section 4.2.2: Exception expected");
1267            } catch (MonetaryException ex) {
1268                // Expected
1269            }
1270        }
1271    }
1272
1273    /**
1274     * Tests that subtract(0) should return itself.
1275     */
1276    @SpecAssertion(section = "4.2.2", id = "422-D7")
1277    @Test(description = "4.2.2 For each amount class, ensure subtraction of 0 returns same instance.")
1278    public void testSubtract_Zero() {
1279        for (Class type : MonetaryAmounts.getAmountTypes()) {
1280            if (type.equals(TestAmount.class)) {
1281                continue;
1282            }
1283            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
1284            MonetaryAmount mAmount2 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(0).create();
1285            MonetaryAmount mActualResult = mAmount1.subtract(mAmount2);
1286            AssertJUnit.assertEquals("Section 4.2.2: Subtract zero", mAmount1, mActualResult);
1287        }
1288    }
1289
1290    /**
1291     * Tests that subtract(), which results in an amount exceeding the max MonetaryContext throws
1292     * a MonetaryException.
1293     */
1294    @SpecAssertion(section = "4.2.2", id = "422-D9")
1295    @Test(description = "4.2.2 For each amount class, ensure subtraction with exceeding capabilities throws " +
1296            "ArithmeticException.")
1297    public void testSubtract_ExceedsCapabilities() {
1298        for (Class type : MonetaryAmounts.getAmountTypes()) {
1299            if (type.equals(TestAmount.class)) {
1300                continue;
1301            }
1302            MonetaryAmountFactory f = getAmountFactory(type);
1303            f.setCurrency("CHF");
1304            MonetaryContext maxCtx = f.getMaximalMonetaryContext();
1305            MonetaryAmount m = null;
1306            if (maxCtx.getPrecision() > 0) {
1307                MonetaryAmount mAmount1 = null;
1308                try {
1309                    mAmount1 = f.setNumber(f.getMinNumber()).create().negate();
1310                    m = TestUtils.createAmountWithPrecision(maxCtx.getPrecision() + 1);
1311                    mAmount1 = mAmount1.subtract(m);
1312                    AssertJUnit.fail("Section 4.2.2: ArithmeticException expected on subtraction that exceeds " +
1313                            "capabilities for " +
1314                            type.getName());
1315                } catch (ArithmeticException ex) {
1316                    // Expected
1317                } catch (Exception e) {
1318                    AssertJUnit.fail("Section 4.2.2: Subtraction of amount " + m + " from " + mAmount1 +
1319                            " exceeds max monetary context(scale), " +
1320                            "but did not throw an ArithmeticException (exception thrown was " +
1321                            e.getClass().getName() + "), type was " +
1322                            type);
1323                }
1324            }
1325        }
1326
1327        for (Class type : MonetaryAmounts.getAmountTypes()) {
1328            if (type.equals(TestAmount.class)) {
1329                continue;
1330            }
1331            MonetaryAmountFactory<MonetaryAmount> f = getAmountFactory(type);
1332            f.setCurrency("CHF");
1333            MonetaryAmount mAmount1 = f.setNumber(0).create();
1334            MonetaryContext maxCtx = f.getMaximalMonetaryContext();
1335            MonetaryAmount m = null;
1336            if (maxCtx.getMaxScale() >= 0) {
1337                m = TestUtils.createAmountWithScale(maxCtx.getMaxScale() + 1);
1338            }
1339            if (m != null) {
1340                try {
1341                    mAmount1.subtract(m);
1342                    AssertJUnit.fail("Section 4.2.2: ArithmeticException expected on subtraction that exceeds " +
1343                            "capabilities for " +
1344                            type.getName());
1345                } catch (ArithmeticException ex) {
1346                    // Expected
1347                } catch (Exception e) {
1348                    AssertJUnit.fail("Section 4.2.2: Subtraction of amount " + m + " from " + mAmount1 +
1349                            " exceeds max monetary context(scale), " +
1350                            "but did not throw an ArithmeticException (exception thrown was " +
1351                            e.getClass().getName() + "), type was " +
1352                            type);
1353                }
1354            }
1355        }
1356    }
1357
1358    /**
1359     * Tests that subtract(), which results in an amount exceeding the max MonetaryContext throws
1360     * a MonetaryException.
1361     */
1362    @SpecAssertion(section = "4.2.2", id = "422-D10")
1363    @Test(description = "4.2.2 For each amount class, ensure subtraction with null throws NullPointerException.")
1364    public void testSubtract_Null() {
1365        for (Class type : MonetaryAmounts.getAmountTypes()) {
1366            if (type.equals(TestAmount.class)) {
1367                continue;
1368            }
1369            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
1370            try {
1371                mAmount1.subtract(null);
1372                AssertJUnit.fail("Section 4.2.2: MonetaryAmount.subtract(null): NullPointerException expected");
1373            } catch (NullPointerException ex) {
1374                // Expected
1375            }
1376        }
1377    }
1378
1379    /**
1380     * Test multiply() allow to multiply numbers.
1381     */
1382    @SpecAssertion(section = "4.2.2", id = "422-D11")
1383    @Test(description = "4.2.2 For each amount class, ensure correct multiplication of int values.")
1384    public void testMultiply_Integral() {
1385        for (Class type : MonetaryAmounts.getAmountTypes()) {
1386            if (type.equals(TestAmount.class)) {
1387                continue;
1388            }
1389            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
1390            MonetaryAmount mActualResult = mAmount1.multiply(2L);
1391            AssertJUnit.assertTrue(
1392                    "Section 4.2.2: Multiplication with 2 does not return correct value for " + type.getName(),
1393                    mActualResult.getNumber().longValueExact() == 20);
1394            mActualResult = mAmount1.multiply(Double.valueOf(-3));
1395            AssertJUnit.assertTrue(
1396                    "Section 4.2.2: Multiplication with -3 does not return correct value for " + type.getName(),
1397                    mActualResult.getNumber().longValueExact() == -30);
1398            mActualResult = mAmount1.multiply(BigDecimal.ONE);
1399            AssertJUnit.assertTrue(
1400                    "Section 4.2.2: Multiplication with 1 does not return correct value for " + type.getName(),
1401                    mActualResult.getNumber().longValueExact() == 10);
1402            AssertJUnit.assertTrue(
1403                    "Section 4.2.2: Multiplication with 1 does not return identity value for " + type.getName(),
1404                    mActualResult == mAmount1);
1405            mActualResult = mAmount1.multiply(BigDecimal.ZERO);
1406            AssertJUnit.assertTrue(
1407                    "Section 4.2.2: Multiplication with 0 does not return correct value for " + type.getName(),
1408                    mActualResult.getNumber().longValueExact() == 0);
1409        }
1410    }
1411
1412    /**
1413     * Test multiply() allow to multiply numbers.
1414     */
1415    @SpecAssertion(section = "4.2.2", id = "422-D11")
1416    @Test(description = "4.2.2 For each amount class, ensure correct multiplication of decimal values.")
1417    public void testMultiply_Decimals() {
1418        for (Class type : MonetaryAmounts.getAmountTypes()) {
1419            if (type.equals(TestAmount.class)) {
1420                continue;
1421            }
1422            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
1423            MonetaryAmount mActualResult = mAmount1.multiply(1.5d);
1424            AssertJUnit.assertTrue(
1425                    "Section 4.2.2: Multiplication with 1.5 does not return correct value for " + type.getName(),
1426                    mActualResult.getNumber().longValueExact() == 15);
1427            mActualResult = mAmount1.multiply(Double.valueOf(-1.5));
1428            AssertJUnit.assertTrue(
1429                    "Section 4.2.2: Multiplication with -3 does not return correct value for " + type.getName(),
1430                    mActualResult.getNumber().longValueExact() == -15);
1431            mActualResult = mAmount1.multiply(0.0);
1432            AssertJUnit.assertTrue(
1433                    "Section 4.2.2: Multiplication with 0 does not return correct value for " + type.getName(),
1434                    mActualResult.getNumber().longValueExact() == 0);
1435            mActualResult = mAmount1.multiply(1.0);
1436            AssertJUnit.assertTrue(
1437                    "Section 4.2.2: Multiplication with 0 does not return correct value for " + type.getName(),
1438                    mActualResult.getNumber().longValueExact() == 10);
1439            AssertJUnit.assertTrue(
1440                    "Section 4.2.2: Multiplication with 0 does not return identity value for " + type.getName(),
1441                    mActualResult == mAmount1);
1442        }
1443    }
1444
1445    /**
1446     * Test multiply(1) returns this.
1447     */
1448    @SpecAssertion(section = "4.2.2", id = "422-D12")
1449    @Test(description = "4.2.2 For each amount class, ensure multiplication by one returns same instance.")
1450    public void testMultiplyOne() {
1451        for (Class type : MonetaryAmounts.getAmountTypes()) {
1452            if (type.equals(TestAmount.class)) {
1453                continue;
1454            }
1455            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
1456            MonetaryAmount mActualResult = mAmount1.multiply(1);
1457            AssertJUnit.assertTrue(
1458                    "Section 4.2.2: Multiplication with 1 does not return identity value for " + type.getName(),
1459                    mActualResult == mAmount1);
1460            mActualResult = mAmount1.multiply(1.0);
1461            AssertJUnit.assertTrue(
1462                    "Section 4.2.2: Multiplication with 1 does not return identity value for " + type.getName(),
1463                    mActualResult == mAmount1);
1464            mActualResult = mAmount1.multiply(BigDecimal.ONE);
1465            AssertJUnit.assertTrue(
1466                    "Section 4.2.2: Multiplication with 1 does not return identity value for " + type.getName(),
1467                    mActualResult == mAmount1);
1468        }
1469    }
1470
1471
1472    /**
1473     * Test multiply, which results in an amount exceeding the max
1474     * MonetaryContext must throw a
1475     * ArithmeticException.
1476     */
1477    @SpecAssertion(section = "4.2.2", id = "422-D13")
1478    @Test(description = "4.2.2 For each amount class, ensure multiplication with exceeding values throws " +
1479            "ArithmeticException.")
1480    public void testMultiplyExceedsCapabilities() {
1481        for (Class type : MonetaryAmounts.getAmountTypes()) {
1482            if (type.equals(TestAmount.class)) {
1483                continue;
1484            }
1485            MonetaryAmountFactory<?> f = getAmountFactory(type);
1486            MonetaryContext ctx = f.getMaximalMonetaryContext();
1487            if (ctx.getMaxScale() >= 0) {
1488                BigDecimal num = TestUtils.createNumberWithScale(f, ctx.getMaxScale() + 5);
1489                MonetaryAmount m = f.setNumber(10).setCurrency("USD").create();
1490                try {
1491                    m.multiply(num);
1492                } catch (ArithmeticException e) {
1493                    // OK!
1494                } catch (Exception e) {
1495                    AssertJUnit.fail("Section 4.2.2: Multiplication of amount 10 with " + num +
1496                            " exceeds max monetary context(scale), should be rounded, " +
1497                            "but did throw an Exception (exception thrown was " +
1498                            e.getClass().getName() + "), type was " +
1499                            type);
1500                }
1501            }
1502        }
1503        for (Class type : MonetaryAmounts.getAmountTypes()) {
1504            if (type.equals(TestAmount.class)) {
1505                continue;
1506            }
1507            MonetaryAmountFactory<?> f = getAmountFactory(type);
1508            MonetaryContext ctx = f.getMaximalMonetaryContext();
1509            if (ctx.getPrecision() > 0) {
1510                BigDecimal num = TestUtils.createNumberWithPrecision(f, ctx.getPrecision() + 5);
1511                MonetaryAmount m = f.setNumber(10).setCurrency("USD").create();
1512                try {
1513                    m.multiply(num);
1514                    AssertJUnit.fail("Section 4.2.2: Multiplication of amount " + num +
1515                            " with 10000000 exceeds max monetary context(precision), " +
1516                            "but did not throw an ArithmeticException, type was " +
1517                            type.getName());
1518                } catch (ArithmeticException e) {
1519                    // OK
1520                } catch (Exception e) {
1521                    AssertJUnit.fail("Section 4.2.2: Multiplication of amount " + num +
1522                            " with 10000000 exceeds max monetary context(precision), " +
1523                            "but did not throw an ArithmeticException (exception thrown was " +
1524                            e.getClass().getName() + "), type was " +
1525                            type.getName());
1526                }
1527            }
1528        }
1529    }
1530
1531    /**
1532     * Test multiply(null) must throw an NullPointerException.
1533     */
1534    @SpecAssertion(section = "4.2.2", id = "422-D14")
1535    @Test(description = "4.2.2 For each amount class, ensure multiplication of null throws NullPointerException.")
1536    public void testMultiplyNull() {
1537        for (Class type : MonetaryAmounts.getAmountTypes()) {
1538            if (type.equals(TestAmount.class)) {
1539                continue;
1540            }
1541            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
1542            try {
1543                MonetaryAmount mActualResult = mAmount1.multiply(null);
1544                AssertJUnit
1545                        .fail("Section 4.2.2: NullPointerException expected for multiplication with null, type was " +
1546                                type.getName());
1547            } catch (NullPointerException e) {
1548                // expected
1549            }
1550        }
1551    }
1552
1553    /**
1554     * Test multiply(Double.NaN) must throw an ArithmeticException.
1555     */
1556    @SpecAssertion(section = "4.2.2", id = "422-D14")
1557    @Test(description = "4.2.2 For each amount class, ensure multiplication of Double.NaN throws ArithmeticException.")
1558    public void testMultiply_DoubleNaN() {
1559        for (Class type : MonetaryAmounts.getAmountTypes()) {
1560            if (type.equals(TestAmount.class)) {
1561                continue;
1562            }
1563            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
1564            try {
1565                MonetaryAmount mActualResult = mAmount1.multiply(Double.NaN);
1566                AssertJUnit
1567                        .fail("Section 4.2.2: ArithmeticException expected for multiplication with Double.NaN, type was " +
1568                                type.getName());
1569            } catch (ArithmeticException e) {
1570                // expected
1571            }
1572        }
1573    }
1574
1575    /**
1576     * Test multiply(Double.POSITIVE_INFINITY) must throw an ArithmeticException.
1577     */
1578    @SpecAssertion(section = "4.2.2", id = "422-D14")
1579    @Test(description = "4.2.2 For each amount class, ensure multiplication of Double.POSITIVE_INFINITY throws ArithmeticException.")
1580    public void testMultiply_DoublePOSITIVE_INFINITY() {
1581        for (Class type : MonetaryAmounts.getAmountTypes()) {
1582            if (type.equals(TestAmount.class)) {
1583                continue;
1584            }
1585            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
1586            try {
1587                MonetaryAmount mActualResult = mAmount1.multiply(Double.POSITIVE_INFINITY);
1588                AssertJUnit
1589                        .fail("Section 4.2.2: ArithmeticException expected for multiplication with Double.POSITIVE_INFINITY, type was " +
1590                                type.getName());
1591            } catch (ArithmeticException e) {
1592                // expected
1593            }
1594        }
1595    }
1596
1597    /**
1598     * Test multiply(Double.POSITIVE_INFINITY) must throw an ArithmeticException.
1599     */
1600    @SpecAssertion(section = "4.2.2", id = "422-D14")
1601    @Test(description = "4.2.2 For each amount class, ensure multiplication of Double.NEGATIVE_INFINITY throws ArithmeticException.")
1602    public void testMultiply_DoubleNEGATIVE_INFINITY() {
1603        for (Class type : MonetaryAmounts.getAmountTypes()) {
1604            if (type.equals(TestAmount.class)) {
1605                continue;
1606            }
1607            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
1608            try {
1609                MonetaryAmount mActualResult = mAmount1.multiply(Double.NEGATIVE_INFINITY);
1610                AssertJUnit
1611                        .fail("Section 4.2.2: ArithmeticException expected for multiplication with Double.NEGATIVE_INFINITY, type was " +
1612                                type.getName());
1613            } catch (ArithmeticException e) {
1614                // expected
1615            }
1616        }
1617    }
1618
1619    /**
1620     * Test divide() function allow to divide numbers.
1621     */
1622    @SpecAssertion(section = "4.2.2", id = "422-D15")
1623    @Test(description = "4.2.2 For each amount class, ensure correct division.")
1624    public void testDivide() {
1625        for (Class type : MonetaryAmounts.getAmountTypes()) {
1626            if (type.equals(TestAmount.class)) {
1627                continue;
1628            }
1629            MonetaryAmount m = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
1630            MonetaryAmount m2 = m.divide(10);
1631            AssertJUnit.assertEquals("Section 4.2.2: Currency not equal after division, type was " + type.getName(),
1632                    DEFAULT_CURRENCY, m2.getCurrency().getCurrencyCode());
1633            AssertJUnit.assertEquals("Section 4.2.2: Division result is not correct for " + type.getName(), 1,
1634                    m2.getNumber().longValueExact());
1635            // TODO iterate over array of different numbers and divisors, use BD to check results
1636        }
1637    }
1638
1639    /**
1640     * Test divideToIntegralValue() function allow to divide numbers.
1641     */
1642    @SpecAssertion(section = "4.2.2", id = "422-D15")
1643    @Test(description = "4.2.2 For each amount class, ensure correct division with int values.")
1644    public void testDivideToIntegralValue() {
1645        for (Class type : MonetaryAmounts.getAmountTypes()) {
1646            if (type.equals(TestAmount.class)) {
1647                continue;
1648            }
1649            CurrencyUnit euro = MonetaryCurrencies.getCurrency("EUR");
1650            MonetaryAmount money1 = getAmountFactory(type).setNumber(BigDecimal.ONE).setCurrency(euro).create();
1651            MonetaryAmount result = money1.divideToIntegralValue(new BigDecimal("0.5001"));
1652            AssertJUnit.assertEquals(
1653                    "Section 4.2.2: divideToIntegralValue returned incorrect result for " + type.getName(),
1654                    result.getNumber().numberValue(BigDecimal.class).stripTrailingZeros(),
1655                    new BigDecimal("1.0").stripTrailingZeros());
1656            result = money1.divideToIntegralValue(new BigDecimal("0.2001"));
1657            AssertJUnit.assertEquals(
1658                    "Section 4.2.2: divideToIntegralValue returned incorrect result for " + type.getName(),
1659                    result.getNumber().numberValue(BigDecimal.class).stripTrailingZeros(),
1660                    new BigDecimal("4.0").stripTrailingZeros());
1661            result = money1.divideToIntegralValue(new BigDecimal("5.0"));
1662            AssertJUnit
1663                    .assertTrue("Section 4.2.2: divideToIntegralValue returned incorrect result for " + type.getName(),
1664                            result.getNumber().numberValue(BigDecimal.class).intValueExact() == 0);
1665        }
1666    }
1667
1668    /**
1669     * Test divide(0) function must throw an ArithmeticException.
1670     */
1671    @SpecAssertion(section = "4.2.2", id = "422-D16")
1672    @Test(description = "4.2.2 For each amount class, ensure divide(0) throws ArithmeticException.")
1673    public void testDivideZero() {
1674        for (Class type : MonetaryAmounts.getAmountTypes()) {
1675            if (type.equals(TestAmount.class)) {
1676                continue;
1677            }
1678            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
1679            try {
1680                MonetaryAmount mActualResult = mAmount1.divide(0);
1681                AssertJUnit.fail("Section 4.2.2: ArithmeticException expected on division by 0, type was " +
1682                        type.getName());
1683            } catch (ArithmeticException ex) {
1684                // expected
1685            }
1686        }
1687    }
1688
1689    /**
1690     * Test divide(0) function must throw an ArithmeticException.
1691     */
1692    @SpecAssertion(section = "4.2.2", id = "422-D16")
1693    @Test(description = "4.2.2 For each amount class, ensure divide(Double.NaN) throws ArithmeticException.")
1694    public void testDivideDoubleNaN() {
1695        for (Class type : MonetaryAmounts.getAmountTypes()) {
1696            if (type.equals(TestAmount.class)) {
1697                continue;
1698            }
1699            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
1700            try {
1701                MonetaryAmount mActualResult = mAmount1.divide(Double.NaN);
1702                AssertJUnit.fail("Section 4.2.2: ArithmeticException expected on division by Double.NaN, type was " +
1703                        type.getName());
1704            } catch (ArithmeticException ex) {
1705                // expected
1706            }
1707        }
1708    }
1709
1710    /**
1711     * Test divide(0) function must return ZERO amount.
1712     */
1713    @SpecAssertion(section = "4.2.2", id = "422-D16")
1714    @Test(description = "4.2.2 For each amount class, ensure divide(Double.POSITIVE_INFINITY) return ZERO amount.")
1715    public void testDivideDoublePOSITIVE_INFINITY() {
1716        for (Class type : MonetaryAmounts.getAmountTypes()) {
1717            if (type.equals(TestAmount.class)) {
1718                continue;
1719            }
1720            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
1721            MonetaryAmount mActualResult = mAmount1.divide(Double.POSITIVE_INFINITY);
1722            AssertJUnit.assertEquals("Section 4.2.2: ZERO amount expected on division by Double.POSITIVE_INFINITY, type was " +
1723                    type.getName(), mActualResult, getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(0).create());
1724        }
1725    }
1726
1727    /**
1728     * Test divide(Double.NEGATIVE_INFINITY) function must return ZERO amount.
1729     */
1730    @SpecAssertion(section = "4.2.2", id = "422-D16")
1731    @Test(description = "4.2.2 For each amount class, ensure divide(Double.NEGATIVE_INFINITY) return ZERO amount.")
1732    public void testDivideDoubleNEGATIVE_INFINITY() {
1733        for (Class type : MonetaryAmounts.getAmountTypes()) {
1734            if (type.equals(TestAmount.class)) {
1735                continue;
1736            }
1737            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
1738            MonetaryAmount mActualResult = mAmount1.divide(Double.NEGATIVE_INFINITY);
1739            AssertJUnit.assertEquals("Section 4.2.2: ZERO amount expected on division by Double.POSITIVE_INFINITY, type was " +
1740                    type.getName(), mActualResult, getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(0).create());
1741        }
1742    }
1743
1744    /**
1745     * Test divide(1) should return this.
1746     */
1747    @SpecAssertion(section = "4.2.2", id = "422-D17")
1748    @Test(description = "4.2.2 For each amount class, ensure divide 1 returns same instance.")
1749    public void testDivideOne() {
1750        for (Class type : MonetaryAmounts.getAmountTypes()) {
1751            if (type.equals(TestAmount.class)) {
1752                continue;
1753            }
1754            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
1755            MonetaryAmount mActualResult = mAmount1.divide(1);
1756            AssertJUnit.assertTrue("Section 4.2.2: Division by 1 does not return identity value for " + type.getName(),
1757                    mActualResult == mAmount1);
1758            mActualResult = mAmount1.divide(1.0);
1759            AssertJUnit.assertTrue("Section 4.2.2: Division by 1 does not return identity value for " + type.getName(),
1760                    mActualResult == mAmount1);
1761            mActualResult = mAmount1.divide(BigDecimal.ONE);
1762            AssertJUnit.assertTrue("Section 4.2.2: Division by 1 does not return identity value for " + type.getName(),
1763                    mActualResult == mAmount1);
1764        }
1765    }
1766
1767    /**
1768     * Test  divide(null)must throw a NullPointerException.
1769     */
1770    @SpecAssertion(section = "4.2.2", id = "422-D18")
1771    @Test(description = "4.2.2 For each amount class, ensure divide by null throws NullPointerException.")
1772    public void testDivideNull() {
1773        for (Class type : MonetaryAmounts.getAmountTypes()) {
1774            if (type.equals(TestAmount.class)) {
1775                continue;
1776            }
1777            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
1778            try {
1779                MonetaryAmount mActualResult = mAmount1.divide(null);
1780                AssertJUnit.fail("Section 4.2.2: NullPointerException expected for division by null, type was " +
1781                        type.getName());
1782            } catch (NullPointerException e) {
1783                // expected
1784            }
1785        }
1786    }
1787
1788    /**
1789     * Test  remainder()allow to calculate the remainder.
1790     */
1791    @SpecAssertion(section = "4.2.2", id = "422-D19")
1792    @Test(description = "4.2.2 For each amount class, ensure correct results for remainder.")
1793    public void testRemainder() {
1794        for (Class type : MonetaryAmounts.getAmountTypes()) {
1795            if (type.equals(TestAmount.class)) {
1796                continue;
1797            }
1798            MonetaryAmountFactory<?> f = getAmountFactory(type);
1799            f.setCurrency("CHF");
1800            MonetaryAmount[] moneys = new MonetaryAmount[]{f.setNumber(100).create(), f.setNumber(34242344).create(),
1801                    f.setNumber(23123213.435).create(), f.setNumber(0).create(), f.setNumber(-100).create(),
1802                    f.setNumber(-723527.36532).create()};
1803            for (MonetaryAmount m : moneys) {
1804                AssertJUnit.assertEquals("Section 4.2.2: Invalid remainder of " + 10.50 + " for " + type.getName(),
1805                        m.getFactory().setNumber(m.getNumber().numberValue(BigDecimal.class)
1806                                .remainder(BigDecimal.valueOf(10.50)))
1807                                .create(), m.remainder(10.50));
1808                AssertJUnit.assertEquals("Section 4.2.2: Invalid remainder of " + -30.20 + " for " + type.getName(),
1809                        m.getFactory().setNumber(m.getNumber().numberValue(BigDecimal.class)
1810                                .remainder(BigDecimal.valueOf(-30.20)))
1811                                .create(), m.remainder(-30.20));
1812                AssertJUnit.assertEquals("Section 4.2.2: Invalid remainder of " + -3 + " for " + type.getName(),
1813                        m.getFactory().setNumber(m.getNumber().numberValue(BigDecimal.class)
1814                                .remainder(BigDecimal.valueOf(-3))).create(),
1815                        m.remainder(-3));
1816                AssertJUnit.assertEquals("Section 4.2.2: Invalid remainder of " + 3 + " for " + type.getName(),
1817                        m.getFactory().setNumber(m.getNumber().numberValue(BigDecimal.class)
1818                                .remainder(BigDecimal.valueOf(3))).create(),
1819                        m.remainder(3));
1820            }
1821        }
1822    }
1823
1824    /**
1825     * Test remainder(0) must throw an ArithmeticException
1826     */
1827    @SpecAssertion(section = "4.2.2", id = "422-D20")
1828    @Test(description = "4.2.2 For each amount class, ensure remainder(0), double, throws ArithmeticException.")
1829    public void testRemainderZero_Double() {
1830        for (Class type : MonetaryAmounts.getAmountTypes()) {
1831            if (type.equals(TestAmount.class)) {
1832                continue;
1833            }
1834            MonetaryAmount m = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
1835            try {
1836                m.remainder(0.0d);
1837                AssertJUnit
1838                        .fail("Section 4.2.2: remainder(0) did not throw an ArithmeticException for " + type.getName());
1839            } catch (ArithmeticException e) {
1840                // OK, ignore
1841            } catch (Exception e) {
1842                AssertJUnit.fail("Section 4.2.2: remainder(0.0d) did not throw an ArithmeticException for " +
1843                        type.getName() + ", but " +
1844                        e);
1845            }
1846        }
1847    }
1848
1849    /**
1850     * Test remainder(0) must throw an ArithmeticException
1851     */
1852    @SpecAssertion(section = "4.2.2", id = "422-D20")
1853    @Test(description = "4.2.2 For each amount class, ensure remainder(0), long, throws ArithmeticException.")
1854    public void testRemainderZero_Long() {
1855        for (Class type : MonetaryAmounts.getAmountTypes()) {
1856            if (type.equals(TestAmount.class)) {
1857                continue;
1858            }
1859            MonetaryAmount m = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
1860            try {
1861                m.remainder(0L);
1862                AssertJUnit.fail("Section 4.2.2: remainder(0L) did not throw an ArithmeticException for " +
1863                        type.getName());
1864            } catch (ArithmeticException e) {
1865                // OK, ignore
1866            } catch (Exception e) {
1867                AssertJUnit.fail("Section 4.2.2: remainder(0L) did not throw an ArithmeticException for " +
1868                        type.getName() + ", but " +
1869                        e);
1870            }
1871        }
1872    }
1873
1874    /**
1875     * Test remainder(0) must throw an ArithmeticException
1876     */
1877    @SpecAssertion(section = "4.2.2", id = "422-D20")
1878    @Test(description = "4.2.2 For each amount class, ensure remainder(0), Number, throws ArithmeticException.")
1879    public void testRemainderZero_Number() {
1880        for (Class type : MonetaryAmounts.getAmountTypes()) {
1881            if (type.equals(TestAmount.class)) {
1882                continue;
1883            }
1884            MonetaryAmount m = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
1885            try {
1886                m.remainder(BigDecimal.ZERO);
1887                AssertJUnit.fail("Section 4.2.2: remainder(BigDecimal.ZERO) did not throw an ArithmeticException for " +
1888                        type.getName());
1889            } catch (ArithmeticException e) {
1890                // OK, ignore
1891            } catch (Exception e) {
1892                AssertJUnit.fail("Section 4.2.2: remainder(BigDecimal.ZERO) did not throw an ArithmeticException for " +
1893                        type.getName() +
1894                        ", but " + e);
1895            }
1896        }
1897    }
1898
1899    /**
1900     * Test remainder(null) must throw a NullPointerException
1901     */
1902    @SpecAssertion(section = "4.2.2", id = "422-D21")
1903    @Test(description = "4.2.2 For each amount class, ensure remainder(null), throws NullPointerException.")
1904    public void testRemainderNull() {
1905        for (Class type : MonetaryAmounts.getAmountTypes()) {
1906            if (type.equals(TestAmount.class)) {
1907                continue;
1908            }
1909            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
1910            try {
1911                MonetaryAmount mActualResult = mAmount1.remainder(null);
1912                AssertJUnit.fail("Section 4.2.2: NullPointerException expected for remainder with null, type was " +
1913                        type.getName());
1914            } catch (NullPointerException e) {
1915                // expected
1916            }
1917        }
1918    }
1919
1920    /**
1921     * Test remainder(null) must throw a NullPointerException
1922     */
1923    @SpecAssertion(section = "4.2.2", id = "422-D21")
1924    @Test(description = "4.2.2 For each amount class, ensure remainder(Double.NaN), throws ArithmeticException.")
1925    public void testRemainder_DoubleNaN() {
1926        for (Class type : MonetaryAmounts.getAmountTypes()) {
1927            if (type.equals(TestAmount.class)) {
1928                continue;
1929            }
1930            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
1931            try {
1932                MonetaryAmount mActualResult = mAmount1.remainder(Double.NaN);
1933                AssertJUnit.fail("Section 4.2.2: ArithmeticException expected for remainder(Double.NaN), type was " +
1934                        type.getName());
1935            } catch (ArithmeticException e) {
1936                // expected
1937            }
1938        }
1939    }
1940
1941    /**
1942     * Test remainder(null) must throw a NullPointerException
1943     */
1944    @SpecAssertion(section = "4.2.2", id = "422-D21")
1945    @Test(description = "4.2.2 For each amount class, ensure remainder(Double.POSITIVE_INFINITY), throws ArithmeticException.")
1946    public void testRemainder_DoublePOSITIVE_INFINITY() {
1947        for (Class type : MonetaryAmounts.getAmountTypes()) {
1948            if (type.equals(TestAmount.class)) {
1949                continue;
1950            }
1951            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
1952            MonetaryAmount mActualResult = mAmount1.remainder(Double.POSITIVE_INFINITY);
1953            AssertJUnit.assertEquals(getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(0).create(), mActualResult);
1954        }
1955    }
1956
1957    /**
1958     * Test remainder(null) must throw a NullPointerException
1959     */
1960    @SpecAssertion(section = "4.2.2", id = "422-D21")
1961    @Test(description = "4.2.2 For each amount class, ensure remainder(Double.NEGATIVE_INFINITY), throws ArithmeticException.")
1962    public void testRemainder_DoubleNEGATIVE_INFINITY() {
1963        for (Class type : MonetaryAmounts.getAmountTypes()) {
1964            if (type.equals(TestAmount.class)) {
1965                continue;
1966            }
1967            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
1968            MonetaryAmount mActualResult = mAmount1.remainder(Double.NEGATIVE_INFINITY);
1969            AssertJUnit.assertEquals(getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(0).create(), mActualResult);
1970        }
1971    }
1972
1973
1974    /**
1975     * Test  divideAndRemainder()allow to divide/remind numbers.
1976     */
1977    @SpecAssertion(section = "4.2.2", id = "422-D22")
1978    @Test(description = "4.2.2 For each amount class, ensure correct divideAndRemainder().")
1979    public void testDivideAndRemainder() {
1980        for (Class type : MonetaryAmounts.getAmountTypes()) {
1981            if (type.equals(TestAmount.class)) {
1982                continue;
1983            }
1984            MonetaryAmountFactory<?> f = getAmountFactory(type);
1985            MonetaryAmount money1 = f.setNumber(BigDecimal.ONE).setCurrency("EUR").create();
1986            if (f.getDefaultMonetaryContext().getMaxScale() < 5) {
1987                MonetaryAmount[] divideAndRemainder = money1.divideAndRemainder(new BigDecimal("0.6"));
1988                AssertJUnit.assertEquals("Section 4.2.2: divideAndRemainder(0.6)[0] failed for " + type.getName(),
1989                        divideAndRemainder[0].getNumber().numberValue(BigDecimal.class)
1990                                .stripTrailingZeros(), BigDecimal.ONE.stripTrailingZeros());
1991                AssertJUnit.assertEquals("Section 4.2.2: divideAndRemainder(0.6)[1] failed for " + type.getName(),
1992                        divideAndRemainder[1].getNumber().numberValue(BigDecimal.class)
1993                                .stripTrailingZeros(), new BigDecimal("0.4").stripTrailingZeros());
1994            } else {
1995                MonetaryAmount[] divideAndRemainder = money1.divideAndRemainder(new BigDecimal("0.50001"));
1996                AssertJUnit.assertEquals("Section 4.2.2: divideAndRemainder(0.50001)[0] failed for " + type.getName(),
1997                        divideAndRemainder[0].getNumber().numberValue(BigDecimal.class)
1998                                .stripTrailingZeros(), BigDecimal.ONE.stripTrailingZeros());
1999                AssertJUnit.assertEquals("Section 4.2.2: divideAndRemainder(0.50001)[1] failed for " + type.getName(),
2000                        divideAndRemainder[1].getNumber().numberValue(BigDecimal.class)
2001                                .stripTrailingZeros(), new BigDecimal("0.49999").stripTrailingZeros());
2002            }
2003        }
2004    }
2005
2006    /**
2007     * Test  divideAndRemainder(0) throws an ArithmeticException.
2008     */
2009    @SpecAssertion(section = "4.2.2", id = "422-D23")
2010    @Test(description = "4.2.2 For each amount class, ensure correct divideAndRemainderZero().")
2011    public void testDivideAndRemainderZero() {
2012        for (Class type : MonetaryAmounts.getAmountTypes()) {
2013            if (type.equals(TestAmount.class)) {
2014                continue;
2015            }
2016            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
2017            try {
2018                mAmount1.divideAndRemainder(BigDecimal.ZERO);
2019                AssertJUnit.fail("Section 4.2.2: divideAndRemainder(0) for " + type.getName() +
2020                        ", should throw ArithmeticException!");
2021            } catch (ArithmeticException e) {
2022                // expected
2023            } catch (Exception e) {
2024                AssertJUnit.fail("Section 4.2.2: Unexpected exception for divideAndRemainder(0) for " + type.getName() +
2025                        ", should be ArithmeticException, but was " + e);
2026            }
2027        }
2028    }
2029
2030    /**
2031     * Test  divideAndRemainder(null) throws an NullPointerException.
2032     */
2033    @SpecAssertion(section = "4.2.2", id = "422-D24")
2034    @Test(description = "4.2.2 For each amount class, ensure divideAndRemainder(null) throws a NullPointerException.")
2035    public void testDivideAndRemainderNull() {
2036        for (Class type : MonetaryAmounts.getAmountTypes()) {
2037            if (type.equals(TestAmount.class)) {
2038                continue;
2039            }
2040            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
2041            try {
2042                MonetaryAmount[] mActualResult = mAmount1.divideAndRemainder(null);
2043                AssertJUnit.fail("Section 4.2.2: NullPointerException expected for divideAndRemainder with null, " +
2044                        "type was " +
2045                        type.getName());
2046            } catch (NullPointerException e) {
2047                // expected
2048            }
2049        }
2050    }
2051
2052    /**
2053     * Test  divideAndRemainder(null) throws an NullPointerException.
2054     */
2055    @SpecAssertion(section = "4.2.2", id = "422-D24")
2056    @Test(description = "4.2.2 For each amount class, ensure divideAndRemainder(Double.NaN) throws a ArithmeticException.")
2057    public void testDivideAndRemainderDoubleNaN() {
2058        for (Class type : MonetaryAmounts.getAmountTypes()) {
2059            if (type.equals(TestAmount.class)) {
2060                continue;
2061            }
2062            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
2063            try {
2064                MonetaryAmount[] mActualResult = mAmount1.divideAndRemainder(Double.NaN);
2065                AssertJUnit.fail("Section 4.2.2: ArithmeticException expected for divideAndRemainder with Double.NaN, " +
2066                        "type was " +
2067                        type.getName());
2068            } catch (ArithmeticException e) {
2069                // expected
2070            }
2071        }
2072    }
2073
2074    /**
2075     * Test  divideAndRemainder(null) throws an NullPointerException.
2076     */
2077    @SpecAssertion(section = "4.2.2", id = "422-D24")
2078    @Test(description = "4.2.2 For each amount class, ensure divideAndRemainder(Double.POSITIVE_INFINITY) returns ZERO amount.")
2079    public void testDivideAndRemainderDoublePOSITIVE_INFINITY() {
2080        for (Class type : MonetaryAmounts.getAmountTypes()) {
2081            if (type.equals(TestAmount.class)) {
2082                continue;
2083            }
2084            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
2085            MonetaryAmount[] mActualResult = mAmount1.divideAndRemainder(Double.POSITIVE_INFINITY);
2086            MonetaryAmount zero = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(0).create();
2087            AssertJUnit.assertEquals("Section 4.2.2: ZERO amount expected for divideAndRemainder with Double.POSITIVE_INFINITY, " +
2088                            "type was " +
2089                            type.getName(), zero,
2090                    mActualResult[0]);
2091            AssertJUnit.assertEquals("Section 4.2.2: ZERO amount expected for divideAndRemainder with Double.POSITIVE_INFINITY, " +
2092                            "type was " +
2093                            type.getName(), zero,
2094                    mActualResult[1]);
2095        }
2096    }
2097
2098    /**
2099     * Test  divideAndRemainder(null) throws an NullPointerException.
2100     */
2101    @SpecAssertion(section = "4.2.2", id = "422-D24")
2102    @Test(description = "4.2.2 For each amount class, ensure divideAndRemainder(Double.NEGATIVE_INFINITY) returns ZERO amount.")
2103    public void testDivideAndRemainderDoubleNEGATIVE_INFINITY() {
2104        for (Class type : MonetaryAmounts.getAmountTypes()) {
2105            if (type.equals(TestAmount.class)) {
2106                continue;
2107            }
2108            MonetaryAmount mAmount1 = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
2109            MonetaryAmount[] mActualResult = mAmount1.divideAndRemainder(Double.NEGATIVE_INFINITY);
2110            MonetaryAmount zero = getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(0).create();
2111            AssertJUnit.assertEquals("Section 4.2.2: ZERO amount expected for divideAndRemainder with Double.NEGATIVE_INFINITY, " +
2112                            "type was " +
2113                            type.getName(), zero,
2114                    mActualResult[0]);
2115            AssertJUnit.assertEquals("Section 4.2.2: ZERO amount expected for divideAndRemainder with Double.NEGATIVE_INFINITY, " +
2116                            "type was " +
2117                            type.getName(), zero,
2118                    mActualResult[1]);
2119        }
2120    }
2121
2122
2123    /**
2124     * Test  divideAndRemainder(1) returns this/ZERO.
2125     */
2126    @SpecAssertion(section = "4.2.2", id = "422-D25")
2127    @Test(description = "4.2.2 For each amount class, ensure divideAndRemainder(1) returns same instance.")
2128    public void testDivideAndRemainderOne() {
2129        for (Class type : MonetaryAmounts.getAmountTypes()) {
2130            if (type.equals(TestAmount.class)) {
2131                continue;
2132            }
2133            MonetaryAmountFactory<?> f = getAmountFactory(type);
2134            MonetaryAmount m = f.setNumber(100).setCurrency("CHF").create();
2135            AssertJUnit.assertEquals(
2136                    "Section 4.2.2: DivideAndRemainder not returning correct result for type: " + type.getName(),
2137                    BigDecimal.valueOf(33),
2138                    m.divideAndRemainder(3)[0].getNumber().numberValue(BigDecimal.class).stripTrailingZeros());
2139            AssertJUnit.assertEquals(
2140                    "Section 4.2.2: DivideAndRemainder not returning correct result for type: " + type.getName(),
2141                    BigDecimal.valueOf(1),
2142                    m.divideAndRemainder(3)[1].getNumber().numberValue(BigDecimal.class).stripTrailingZeros());
2143            AssertJUnit.assertEquals(
2144                    "Section 4.2.2: DivideAndRemainder not returning correct result for type: " + type.getName(),
2145                    BigDecimal.ONE,
2146                    m.divideAndRemainder(BigDecimal.valueOf(3))[1].getNumber().numberValue(BigDecimal.class)
2147                            .stripTrailingZeros());
2148        }
2149    }
2150
2151    /**
2152     * Test scaleByPowerOfTen()allow to scale by power of 10.
2153     */
2154    @SpecAssertion(section = "4.2.2", id = "422-D26")
2155    @Test(description = "4.2.2 For each amount class, ensure scaleByPowerOfTen(1) returns correct results.")
2156    public void testScaleByPowerOfTen() {
2157        for (Class type : MonetaryAmounts.getAmountTypes()) {
2158            if (type.equals(TestAmount.class)) {
2159                continue;
2160            }
2161            MonetaryAmountFactory<?> f = getAmountFactory(type);
2162            f.setCurrency("CHF");
2163            MonetaryAmount[] amounts = new MonetaryAmount[]{f.setNumber(100).create(), f.setNumber(342444).create(),
2164                    f.setNumber(2312213.435).create(), f.setNumber(BigDecimal.ZERO).create(),
2165                    f.setNumber(-100).create(), f.setNumber(-723527.3653).create()};
2166
2167            for (MonetaryAmount m : amounts) {
2168                for (int p = -3; p < 3; p++) {
2169                    BigDecimal bdExpected = m.scaleByPowerOfTen(p).getNumber().numberValue(BigDecimal.class);
2170                    BigDecimal bdCalculated = m.getNumber().numberValue(BigDecimal.class).scaleByPowerOfTen(p);
2171                    bdCalculated = bdCalculated.setScale(m.getContext().getMaxScale(), RoundingMode.HALF_EVEN);
2172                    if (bdExpected.signum() == 0) {
2173                        AssertJUnit.assertTrue("Section 4.2.2: Invalid " + m + " -> scaleByPowerOfTen(" + p + ") for " +
2174                                type.getName(), bdCalculated.signum() == 0);
2175                    } else {
2176                        AssertJUnit
2177                                .assertEquals("Section 4.2.2: Invalid " + m + " -> scaleByPowerOfTen(" + p + ") for " +
2178                                                type.getName(), bdExpected
2179                                                .setScale(m.getContext().getMaxScale() - 1,
2180                                                        RoundingMode.HALF_EVEN).stripTrailingZeros(),
2181                                        bdCalculated.setScale(m.getContext().getMaxScale() - 1,
2182                                                RoundingMode.HALF_EVEN).stripTrailingZeros());
2183                    }
2184                }
2185            }
2186        }
2187    }
2188
2189    /**
2190     * Test abs() for getting the absolute value.
2191     */
2192    @SpecAssertion(section = "4.2.2", id = "422-D27")
2193    @Test(description = "4.2.2 For each amount class, test absolute().")
2194    public void testAbsolute() {
2195        for (Class type : MonetaryAmounts.getAmountTypes()) {
2196            if (type.equals(TestAmount.class)) {
2197                continue;
2198            }
2199            MonetaryAmountFactory<MonetaryAmount> f = getAmountFactory(type);
2200            f.setCurrency("CHF");
2201            MonetaryAmount m = f.setNumber(10).create();
2202            AssertJUnit
2203                    .assertEquals("Section 4.2.2: abs(m) !equals m, if m > 0 for type: " + type.getName(), m, m.abs());
2204            AssertJUnit.assertTrue("Section 4.2.2: abs(m) != m, if m > 0 for type: " + type.getName(), m == m.abs());
2205            m = f.setNumber(0).create();
2206            AssertJUnit
2207                    .assertEquals("Section 4.2.2: abs(m) != equals, if m == 0 for type: " + type.getName(), m, m.abs());
2208            AssertJUnit.assertTrue("Section 4.2.2: abs(m) != m, if m == 0 for type: " + type.getName(), m == m.abs());
2209            m = f.setNumber(-10).create();
2210            AssertJUnit.assertEquals("Section 4.2.2: abs(m) == m, if m < 0 for type: " + type.getName(), m.negate(),
2211                    m.abs());
2212            AssertJUnit.assertTrue("Section 4.2.2: abs(m) == m, if m < 0 for type: " + type.getName(), m != m.abs());
2213        }
2214    }
2215
2216    /**
2217     * Test negate() for negating a value.
2218     */
2219    @SpecAssertion(section = "4.2.2", id = "422-D28")
2220    @Test(description = "4.2.2 For each amount class, test negate().")
2221    public void testNegate() {
2222        for (Class type : MonetaryAmounts.getAmountTypes()) {
2223            if (type.equals(TestAmount.class)) {
2224                continue;
2225            }
2226            MonetaryAmountFactory<MonetaryAmount> f = getAmountFactory(type);
2227            f.setCurrency("CHF");
2228            MonetaryAmount m = f.setNumber(100).create();
2229            AssertJUnit
2230                    .assertEquals("Section 4.2.2: negate(-x) failed for " + type.getName(), f.setNumber(-100).create(),
2231                            m.negate());
2232            m = f.setNumber(-123.234).create();
2233            AssertJUnit.assertEquals("Section 4.2.2: negate(+x) failed for " + type.getName(),
2234                    f.setNumber(123.234).create(), m.negate());
2235        }
2236    }
2237
2238    /**
2239     * Ensure with(MonetaryOperator) can be called and produces
2240     * amounts of the same type and correct value.
2241     */
2242    @SpecAssertion(section = "4.2.2", id = "422-E1")
2243    @Test(description = "4.2.2 For each amount class, test with().")
2244    public void testWith() {
2245        MonetaryOperator op = (amount) -> amount;
2246        for (Class type : MonetaryAmounts.getAmountTypes()) {
2247            if (type.equals(TestAmount.class)) {
2248                continue;
2249            }
2250            MonetaryAmount amount = getAmountFactory(type).setCurrency("CHF").setNumber(10).create();
2251            MonetaryAmount amount2 = amount.with(op);
2252            AssertJUnit.assertTrue(
2253                    "Section 4.2.2: MonetaryAmount returned from operator is wrapped by implementation of type: " +
2254                            type.getName(), amount == amount2);
2255            final MonetaryAmount result = getAmountFactory(type).setCurrency("CHF").setNumber(4).create();
2256            MonetaryOperator op2 = (m) -> result;
2257            amount2 = amount.with(op);
2258            AssertJUnit.assertTrue(
2259                    "Section 4.2.2: MonetaryAmount returned from operator is wrapped by implementation of type: " +
2260                            type.getName(), amount == amount2);
2261        }
2262    }
2263
2264    /**
2265     * Ensure with(MonetaryOperator) can be called and produces
2266     * amounts of the same type and correct value, testing operators provided by TCKTestSetup.
2267     */
2268    @SpecAssertion(section = "4.2.2", id = "422-E1")
2269    @Test(description = "4.2.2 For each amount class, test with().")
2270    public void testWith4ProvidedOperators() {
2271        for (MonetaryOperator op : TCKTestSetup.getTestConfiguration().getMonetaryOperators4Test()) {
2272            for (Class type : MonetaryAmounts.getAmountTypes()) {
2273                if (type.equals(TestAmount.class)) {
2274                    continue;
2275                }
2276                MonetaryAmount amount = getAmountFactory(type).setCurrency("CHF").setNumber(10).create();
2277                MonetaryAmount amount2 = amount.with(op);
2278                AssertJUnit.assertTrue(
2279                        "Section 4.2.2: MonetaryAmount returned from operator is wrapped by implementation of type: " +
2280                                type.getName(), amount.getClass() == amount2.getClass());
2281                final MonetaryAmount result = getAmountFactory(type).setCurrency("CHF").setNumber(4).create();
2282                MonetaryOperator op2 = (m) -> m;
2283                amount2 = amount.with(op2);
2284                AssertJUnit.assertTrue(
2285                        "Section 4.2.2: MonetaryAmount returned from operator is wrapped by implementation of type: " +
2286                                type.getName(), amount == amount2);
2287            }
2288        }
2289    }
2290
2291    /**
2292     * Test with(m) throws a MonetaryException, if m throws any exception.
2293     */
2294    @SpecAssertion(section = "4.2.2", id = "422-E2")
2295    @Test(description = "4.2.2 Bad case: For each amount class, test with(), operator throws exception.")
2296    public void testWithInvalidOperator() {
2297        MonetaryOperator op = new MonetaryOperator() {
2298            @Override
2299            public MonetaryAmount apply(MonetaryAmount value) {
2300                throw new IllegalStateException();
2301            }
2302        };
2303        for (Class type : MonetaryAmounts.getAmountTypes()) {
2304            if (type.equals(TestAmount.class)) {
2305                continue;
2306            }
2307            MonetaryAmountFactory factory = getAmountFactory(type);
2308            MonetaryAmount amount = factory.setCurrency("XXX").setNumber(1).create();
2309            try {
2310                amount.with(op);
2311                AssertJUnit.fail("Section 4.2.2: MonetaryException expected as operator fails, type was " +
2312                        type.getName());
2313            } catch (MonetaryException e) {
2314                // OK, everything else makes the test fail!
2315            }
2316        }
2317    }
2318
2319    /**
2320     * Test with(null) throws a NullPointerException.
2321     */
2322    @SpecAssertion(section = "4.2.2", id = "422-E2")
2323    @Test(description = "4.2.2 Bad case: For each amount class, test with(null), expected NullPointerException.")
2324    public void testWithNull() {
2325        for (Class type : MonetaryAmounts.getAmountTypes()) {
2326            if (type.equals(TestAmount.class)) {
2327                continue;
2328            }
2329            MonetaryAmountFactory factory = getAmountFactory(type);
2330            MonetaryAmount amount = factory.setCurrency("XXX").setNumber(1).create();
2331            try {
2332                amount.with(null);
2333                AssertJUnit.fail("Section 4.2.2: NullPointerException expected as operator applied is null, type was " +
2334                        type.getName());
2335            } catch (NullPointerException e) {
2336                // OK, everything else makes the test fail!
2337            }
2338        }
2339    }
2340
2341    /**
2342     * Test with(null) throws a NullPointerException.
2343     */
2344    @SpecAssertion(section = "4.2.2", id = "422-E2")
2345    @Test(description = "4.2.2 Bad case: For each amount class, test with(), operator throws exception.")
2346    public void testWithNull4ProvidedOperators() {
2347        for (MonetaryOperator op : TCKTestSetup.getTestConfiguration().getMonetaryOperators4Test()) {
2348            try {
2349                op.apply(null);
2350                AssertJUnit.fail("Section 4.2.2: NullPointerException expected as operator was applied on null, " +
2351                        "operator was " +
2352                        op.getClass().getName());
2353            } catch (NullPointerException e) {
2354                // OK, everything else makes the test fail!
2355            }
2356        }
2357    }
2358
2359    /**
2360     * Ensure query(MonetaryQUery) can be called and produces
2361     * valuable results.
2362     */
2363    @SpecAssertion(section = "4.2.2", id = "422-E3")
2364    @Test(description = "4.2.2 For each amount class, test query().")
2365    public void testQuery() {
2366        MonetaryQuery<Integer> query = new MonetaryQuery<Integer>() {
2367            @Override
2368            public Integer queryFrom(MonetaryAmount amount) {
2369                return amount.getNumber().intValue();
2370            }
2371        };
2372        for (Class type : MonetaryAmounts.getAmountTypes()) {
2373            if (type.equals(TestAmount.class)) {
2374                continue;
2375            }
2376            MonetaryAmount amount = getAmountFactory(type).setCurrency("CHF").setNumber(10).create();
2377            Integer value = amount.query(query);
2378            AssertJUnit.assertTrue(
2379                    "Section 4.2.2: Value returned from MonetaryAmount Query is not correct for " + type.getName(),
2380                    value == 10);
2381            amount = getAmountFactory(type).setCurrency("CHF").setNumber(4.5).create();
2382            value = amount.query(query);
2383            AssertJUnit.assertTrue(
2384                    "Section 4.2.2: Value returned from MonetaryAmount Query is not correct for " + type.getName(),
2385                    value == 4);
2386        }
2387    }
2388
2389    /**
2390     * Test query(q) throws a MonetaryException, if q throws any exception.
2391     */
2392    @SpecAssertion(section = "4.2.2", id = "422-E4")
2393    @Test(description = "4.2.2 For each amount class, test query(), MonetaryQuery throws exception, " +
2394            "MonetaryException expected.")
2395    public void testQueryInvalidQuery() {
2396        MonetaryQuery<Integer> query = new MonetaryQuery<Integer>() {
2397            @Override
2398            public Integer queryFrom(MonetaryAmount amount) {
2399                throw new IllegalStateException();
2400            }
2401        };
2402        for (Class type : MonetaryAmounts.getAmountTypes()) {
2403            if (type.equals(TestAmount.class)) {
2404                continue;
2405            }
2406            TestUtils.testComparable("Section 4.2.2", type);
2407            MonetaryAmountFactory factory = getAmountFactory(type);
2408            MonetaryAmount amount = factory.setCurrency("XXX").setNumber(1).create();
2409            try {
2410                amount.query(query);
2411                AssertJUnit.fail("Section 4.2.2: MonetaryException expected as query applied is failing, type was " +
2412                        type.getName());
2413            } catch (MonetaryException e) {
2414                // OK, everything else makes the test fail!
2415            }
2416        }
2417    }
2418
2419    /**
2420     * Test query(null) throws a NullPointerException.
2421     */
2422    @SpecAssertion(section = "4.2.2", id = "422-E4")
2423    @Test(description = "4.2.2 For each amount class, test query(null), NullPointerException expected.")
2424    public void testQueryNull() {
2425        for (Class type : MonetaryAmounts.getAmountTypes()) {
2426            if (type.equals(TestAmount.class)) {
2427                continue;
2428            }
2429            TestUtils.testComparable("Section 4.2.2", type);
2430            MonetaryAmountFactory factory = getAmountFactory(type);
2431            MonetaryAmount amount = factory.setCurrency("XXX").setNumber(1).create();
2432            try {
2433                amount.query(null);
2434                AssertJUnit.fail("Section 4.2.2: NullPointerException expected as query applied is null, type was " +
2435                        type.getName());
2436            } catch (NullPointerException e) {
2437                // OK, everything else makes the test fail!
2438            }
2439        }
2440    }
2441
2442    /**
2443     * Implementations of MonetaryAmount must implement hashCode,
2444     * considering number, currency and implementation type,
2445     * monetary
2446     * context.
2447     */
2448    @SpecAssertion(section = "4.2.2", id = "422-F1")
2449    @Test(description = "4.2.2 For each amount class, test implements hashCode().")
2450    public void testImplementsHashCode() {
2451        for (Class type : MonetaryAmounts.getAmountTypes()) {
2452            if (type.equals(TestAmount.class)) {
2453                continue;
2454            }
2455            MonetaryAmount amount = getAmountFactory(type).setCurrency("USD").setNumber(0).create();
2456            TestUtils.testHasPublicMethod("Section 4.2.2", type, type, "hashCode");
2457            MonetaryAmount amount2 = getAmountFactory(type).setCurrency("USD").setNumber(0).create();
2458            AssertJUnit.assertEquals("Section 4.2.2: hashCode() for equal amounts differ for type " + type.getName(),
2459                    amount.hashCode(), amount2.hashCode());
2460        }
2461    }
2462
2463    /**
2464     * Implementations of MonetaryAmount must implement
2465     * equals,
2466     * considering number, currency and implementation type,
2467     * monetary
2468     * context.
2469     */
2470    @SpecAssertion(section = "4.2.2", id = "422-F2")
2471    @Test(description = "4.2.2 For each amount class, test implements equals().")
2472    public void testImplementsEquals() {
2473        for (Class type : MonetaryAmounts.getAmountTypes()) {
2474            if (type.equals(TestAmount.class)) {
2475                continue;
2476            }
2477            MonetaryAmount amount = getAmountFactory(type).setCurrency("XXX").setNumber(0).create();
2478            TestUtils.testHasPublicMethod("Section 4.2.2", type, type, "equals", Object.class);
2479            MonetaryAmount amount2 = getAmountFactory(type).setCurrency("XXX").setNumber(0).create();
2480            AssertJUnit
2481                    .assertEquals("Section 4.2.2: equals(Object) for equal amounts returns false for " + type.getName(),
2482                            amount, amount2);
2483        }
2484    }
2485
2486    /**
2487     * Implementations of MonetaryAmount must be Comparable.
2488     */
2489    @SpecAssertion(section = "4.2.2", id = "422-F3")
2490    @Test(description = "4.2.2 For each amount class, test is Comparable.")
2491    public void testImplementComparable() {
2492        for (Class type : MonetaryAmounts.getAmountTypes()) {
2493            if (type.equals(TestAmount.class)) {
2494                continue;
2495            }
2496            TestUtils.testComparable("Section 4.2.2", type);
2497            MonetaryAmountFactory factory = getAmountFactory(type);
2498            MonetaryAmount amount = factory.setCurrency("XXX").setNumber(0).create();
2499            MonetaryAmount amount2 = factory.setCurrency("XXX").setNumber(0).create();
2500            MonetaryAmount amount3 = factory.setCurrency("CHF").setNumber(1).create();
2501            MonetaryAmount amount4 = factory.setCurrency("XXX").setNumber(1).create();
2502
2503            AssertJUnit.assertTrue("Section 4.2.2: Comparable failed for: " + type.getName(),
2504                    ((Comparable) amount).compareTo(amount3) > 0);
2505
2506            AssertJUnit.assertTrue("Section 4.2.2: Comparable failed for: " + type.getName(),
2507                    ((Comparable) amount3).compareTo(amount) < 0);
2508
2509            AssertJUnit.assertTrue("Section 4.2.2: Comparable failed for: " + type.getName(),
2510                    ((Comparable) amount).compareTo(amount4) < 0);
2511
2512            AssertJUnit.assertTrue("Section 4.2.2: Comparable failed for: " + type.getName(),
2513                    ((Comparable) amount4).compareTo(amount) > 0);
2514        }
2515    }
2516
2517    /**
2518     * Implementations of MonetaryAmount must be Serializable.
2519     */
2520    @SpecAssertion(section = "4.2.2", id = "422-F4")
2521    @Test(description = "4.2.2 For each amount class, test iis immutable.")
2522    public void testImmutable() {
2523        for (Class type : TCKTestSetup.getTestConfiguration().getAmountClasses()) {
2524            if (type.equals(TestAmount.class)) {
2525                continue;
2526            }
2527            TestUtils.testImmutable("Section 4.2.2", type);
2528        }
2529        for (Class type : MonetaryAmounts.getAmountTypes()) {
2530            if (type.equals(TestAmount.class)) {
2531                continue;
2532            }
2533            try {
2534                TestUtils.testImmutable("Section 4.2.2", type);
2535            } catch (MutabilityAssertionError e) {
2536                System.out
2537                        .println("Warning: found non immutable MonetaryAmountType: " + type.getName() + ", details: " +
2538                                e.getMessage());
2539            }
2540        }
2541    }
2542
2543
2544}