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