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.tests.internal.TestAmount;
013import org.jboss.test.audit.annotations.SpecAssertion;
014import org.jboss.test.audit.annotations.SpecVersion;
015import org.testng.AssertJUnit;
016import org.testng.annotations.Test;
017
018import javax.money.MonetaryAmount;
019import javax.money.MonetaryAmounts;
020import javax.money.MonetaryException;
021import javax.money.NumberValue;
022import java.math.BigDecimal;
023import java.math.BigInteger;
024
025/**
026 * Testing Numeric Externalization for numeric values of MonetaryAmount instances.
027 * Created by Anatole on 10.03.14.
028 */
029@SpecVersion(spec = "JSR 354", version = "1.0.0")
030public class ExternalizingNumericValueTest {
031
032    private final static String DEFAULT_CURRENCY = "CHF";
033
034    private Class[] requiredJdkTykes =
035            new Class[]{Integer.class, Long.class, Double.class, BigDecimal.class, BigInteger.class};
036
037
038    /**
039     * Checks if number type is not null.
040     */
041    @SpecAssertion(section = "4.2.3", id = "423-A1")
042    @Test(description = "4.2.3 Amount types do not return a NumberValue of null.")
043    public void testReturningNumberValueIsNotNull() {
044        for (Class type : MonetaryAmounts.getAmountTypes()) {
045            if (type.equals(TestAmount.class)) {
046                continue;
047            }
048            MonetaryAmount mAmount1 =
049                    MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(10).create();
050            NumberValue result = mAmount1.getNumber();
051            AssertJUnit.assertNotNull("Section 4.2.3: Amount type does not return a NumberValue (null); " + type.getName(), result);
052        }
053    }
054
055    /**
056     * Check if a correct integer value is returned, no truncation is
057     * allowed to be performed.
058     */
059    @SpecAssertion(section = "4.2.3", id = "423-A2")
060    @Test(description = "4.2.3 Ensure NumberValue intValue(), intValueExact() provide correct values.")
061    public void testValidInteger() {
062        int[] nums = new int[]{-3, -1, 0, 1, 3};
063        for (int num : nums) {
064            for (Class type : MonetaryAmounts.getAmountTypes()) {
065                if (type.equals(TestAmount.class)) {
066                    continue;
067                }
068                MonetaryAmount mAmount1 =
069                        MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(num).create();
070                NumberValue result = mAmount1.getNumber();
071                AssertJUnit.assertNotNull("Section 4.2.3: Amount creation failed for " + type, result);
072                AssertJUnit.assertEquals("Section 4.2.3: Number value (int) returned is not correct for " + type.getName(), num,
073                        result.intValue());
074                AssertJUnit.assertEquals("Section 4.2.3: Exact number value (int) returned is not correct for " + type.getName(), num,
075                        result.intValueExact());
076            }
077        }
078    }
079
080    /**
081     * Check if a correct long value is returned, no truncation is
082     * allowed to be performed.
083     */
084    @SpecAssertion(section = "4.2.3", id = "423-A3")
085    @Test(description = "4.2.3 Ensure NumberValue longValue(), longValueExact() provide correct values.")
086    public void testValidLong() {
087        long[] nums = new long[]{1, 3, 11, 123, 12345, 1223345566, 1234523462532753243L};
088        for (long num : nums) {
089            for (Class type : MonetaryAmounts.getAmountTypes()) {
090                if (type.equals(TestAmount.class)) {
091                    continue;
092                }
093                MonetaryAmount mAmount1;
094                try {
095                    mAmount1 = MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(num)
096                            .create();
097                } catch (ArithmeticException | MonetaryException e) {
098                    // could be that the number exceeds the amount's capabilities...
099                    continue;
100                }
101                NumberValue result = mAmount1.getNumber();
102                AssertJUnit.assertNotNull("Section 4.2.3: Amount creation failed for " + type, result);
103                AssertJUnit.assertEquals("Section 4.2.3: Number value (long) returned is not correct for " + type.getName(), num,
104                        result.longValue());
105                AssertJUnit
106                        .assertEquals("Section 4.2.3: Exact number (long) (double) returned is not correct for " + type.getName(), num,
107                                result.longValueExact());
108            }
109        }
110    }
111
112
113    /**
114     * Check if a correct double value is returned, no truncation is
115     * allowed to be performed.
116     */
117    @SpecAssertion(section = "4.2.3", id = "423-A4")
118    @Test(description = "4.2.3 Ensure NumberValue doubleValue(), doubleValueExact() provide correct values.")
119    public void testValidDouble() {
120        double[] nums = new double[]{0, 0.3, 1, 1.3453};
121        for (double num : nums) {
122            for (Class type : MonetaryAmounts.getAmountTypes()) {
123                if (type.equals(TestAmount.class)) {
124                    continue;
125                }
126                MonetaryAmount mAmount1 =
127                        MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(num).create();
128                NumberValue result = mAmount1.getNumber();
129                AssertJUnit.assertNotNull("Section 4.2.3: Amount creation failed for " + type, result);
130                AssertJUnit.assertEquals("Section 4.2.3: Number value (double) returned is not correct for " + type.getName(), num,
131                        result.doubleValue(), 0d);
132                AssertJUnit
133                        .assertEquals("Section 4.2.3: Exact number value (double) returned is not correct for " + type.getName(), num,
134                                result.doubleValueExact(), 0d);
135            }
136        }
137    }
138
139    /**
140     * Check if a correct number value is returned, no truncation is
141     * allowed to be performed.
142     * Check should be done for every JDK type
143     * supported.
144     */
145    @SpecAssertion(section = "4.2.3", id = "423-A5")
146    @Test(description = "4.2.3 Ensure NumberValue asType(BigDecimal.class) provides correct values.")
147    public void testValidNumberBD() {
148        Number[] nums = new Number[]{-3, -3.5f - 1L, -1.2d, (short) 0, 0.3, (byte) 1, 1.3453};
149        for (Number num : nums) {
150            for (Class type : MonetaryAmounts.getAmountTypes()) {
151                if (type.equals(TestAmount.class)) {
152                    continue;
153                }
154                MonetaryAmount mAmount1 =
155                        MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(num).create();
156                NumberValue result = mAmount1.getNumber();
157                AssertJUnit.assertEquals("Section 4.2.3: Number value (BigDecimal) returned is not correct for " + type.getName(),
158                        new BigDecimal(String.valueOf(num)).stripTrailingZeros(),
159                        result.numberValue(BigDecimal.class).stripTrailingZeros());
160                AssertJUnit
161                        .assertEquals("Section 4.2.3: Exact number value (BigDecimal) returned is not correct for " + type.getName(),
162                                new BigDecimal(String.valueOf(num)).stripTrailingZeros(),
163                                result.numberValue(BigDecimal.class).stripTrailingZeros());
164            }
165        }
166    }
167
168    /**
169     * Check if a correct number value is returned, no truncation is
170     * allowed to be performed.
171     * Check should be done for every JDK type
172     * supported.
173     */
174    @SpecAssertion(section = "4.2.3", id = "423-A5")
175    @Test(description = "4.2.3 Ensure NumberValue asType(BigInteger.class) provides correct values.")
176    public void testValidNumberBI() {
177        Number[] nums = new Number[]{-3, -1L, (short) 0, (byte) 1};
178        for (Number num : nums) {
179            for (Class type : MonetaryAmounts.getAmountTypes()) {
180                if (type.equals(TestAmount.class)) {
181                    continue;
182                }
183                MonetaryAmount mAmount1 =
184                        MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(num).create();
185                NumberValue result = mAmount1.getNumber();
186                AssertJUnit.assertEquals("Section 4.2.3: Number value (BigInteger) returned is not correct for " + type.getName(),
187                        new BigInteger(String.valueOf(num)), result.numberValue(BigInteger.class));
188                AssertJUnit
189                        .assertEquals("Section 4.2.3: Exact number value (BigInteger) returned is not correct for " + type.getName(),
190                                new BigInteger(String.valueOf(num)), result.numberValue(BigInteger.class));
191            }
192        }
193    }
194
195    /**
196     * Check if a correct Integer value is returned, truncation is
197     * allowed to be performed.
198     */
199    @SpecAssertion(section = "4.2.3", id = "423-A6")
200    @Test(description = "4.2.3 Ensure NumberValue intValue() is truncated.")
201    public void testValidIntegerWithTruncation() {
202        double[] nums = new double[]{-3.12334, -1.23345, 0.4343, 1.3343435, 5.345454};
203        for (double num : nums) {
204            for (Class type : MonetaryAmounts.getAmountTypes()) {
205                if (type.equals(TestAmount.class)) {
206                    continue;
207                }
208                MonetaryAmount mAmount1;
209                try {
210                    mAmount1 = MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(num)
211                            .create();
212                } catch (MonetaryException | ArithmeticException e) {
213                    // It is possible, that our test may exceed the capabilities, so in that case, we just continue
214                    continue;
215                }
216                NumberValue result = mAmount1.getNumber();
217                AssertJUnit.assertEquals("Section 4.2.3: Number value (int, truncated) returned is not correct for " + type.getName(),
218                        (int) num, result.intValue());
219                try {
220                    result.intValueExact();
221                    AssertJUnit
222                            .fail("Section 4.2.3: Number value (int, exact -> truncated) must throw ArithemticException on truncation for " +
223                                    type.getName());
224                } catch (ArithmeticException e) {
225                    // OK
226                }
227            }
228        }
229    }
230
231    /**
232     * Check if a correct Long value is returned, truncation is
233     * allowed to be performed.
234     */
235    @SpecAssertion(section = "4.2.3", id = "423-A7")
236    @Test(description = "4.2.3 Ensure NumberValue longValue() is truncated.")
237    public void testValidLongWithTruncation() {
238        double[] nums = new double[]{0.4343, 1.3343435, 5.345454};
239        for (double num : nums) {
240            for (Class type : MonetaryAmounts.getAmountTypes()) {
241                if (type.equals(TestAmount.class)) {
242                    continue;
243                }
244                MonetaryAmount mAmount1;
245                try {
246                    mAmount1 = MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(num)
247                            .create();
248                } catch (MonetaryException | ArithmeticException e) {
249                    // It is possible, that our test may exceed the capabilities, so in that case, we just continue
250                    continue;
251                }
252                NumberValue result = mAmount1.getNumber();
253                AssertJUnit.assertEquals("Section 4.2.3: Number value (long, truncated) returned is not correct for " + type.getName(),
254                        (long) num, result.intValue());
255                try {
256                    result.longValueExact();
257                    AssertJUnit
258                            .fail("Section 4.2.3: Number value (long, exact -> truncated) must throw ArithemticException on truncation for " +
259                                    type.getName());
260                } catch (ArithmeticException e) {
261                    // OK
262                }
263            }
264        }
265    }
266
267    /**
268     * Check if a correct Double value is returned, truncation is
269     * allowed to be performed.
270     */
271    @SpecAssertion(section = "4.2.3", id = "423-A8")
272    @Test(description = "4.2.3 Ensure NumberValue doubleValue() is truncated.")
273    public void testValidDoubleWithTruncation() {
274        Number[] nums = new Number[]{new BigDecimal("26353527352735725372357.287362873287362836283"), 3232232334423L,
275                33434243242342342434.5d, 1L, 1.24355354543534545d, (short) 0, 0.3, (byte) 1, 1.3453, 32432532};
276        for (Number num : nums) {
277            for (Class type : MonetaryAmounts.getAmountTypes()) {
278                if (type.equals(TestAmount.class)) {
279                    continue;
280                }
281                MonetaryAmount mAmount1;
282                try {
283                    mAmount1 = MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(num)
284                            .create();
285                } catch (ArithmeticException | MonetaryException e) {
286                    // can happen if capabilities are exceeded
287                    continue;
288                }
289                NumberValue result = mAmount1.getNumber();
290                AssertJUnit
291                        .assertEquals("Section 4.2.3: Number value (Double, truncating) returned is not correct for " + type.getName(),
292                                new BigDecimal(String.valueOf(num)).doubleValue(), result.doubleValue(), 0.0d);
293            }
294        }
295    }
296
297    /**
298     * Check if a correct Number value is returned, truncation is
299     * allowed to be performed.
300     */
301    @SpecAssertion(section = "4.2.3", id = "423-A9")
302    @Test(description = "4.2.3 Ensure NumberValue byteValue() is truncated.")
303    public void testValidNumberWithTruncation_Byte() {
304        Number[] nums = new Number[]{-3232423, -3.5f - 1L, -1.2d, (short) 0, 0.3, (byte) 1, 1.3453, 32432532};
305        for (Number num : nums) {
306            for (Class type : MonetaryAmounts.getAmountTypes()) {
307                if (type.equals(TestAmount.class)) {
308                    continue;
309                }
310                MonetaryAmount mAmount1;
311                try {
312                    mAmount1 = MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(num)
313                            .create();
314                } catch (ArithmeticException | MonetaryException e) {
315                    // can happen if capabilities are exceeded
316                    continue;
317                }
318                NumberValue result = mAmount1.getNumber();
319                AssertJUnit
320                        .assertEquals("Section 4.2.3: Number value (Byte, truncating) returned is not correct for " + type.getName(),
321                                new BigDecimal(String.valueOf(num)).byteValue(),
322                                result.numberValue(Byte.class).byteValue());
323            }
324        }
325    }
326
327    /**
328     * Check if a correct Number value is returned, truncation is
329     * allowed to be performed.
330     */
331    @SpecAssertion(section = "4.2.3", id = "423-A9")
332    @Test(description = "4.2.3 Ensure NumberValue shortValue() is truncated.")
333    public void testValidNumberWithTruncation_Short() {
334        Number[] nums = new Number[]{-3232423, -3.5f - 1L, -1.2d, (short) 0, 0.3, (byte) 1, 1.3453, 32432532};
335        for (Number num : nums) {
336            for (Class type : MonetaryAmounts.getAmountTypes()) {
337                if (type.equals(TestAmount.class)) {
338                    continue;
339                }
340                MonetaryAmount mAmount1;
341                try {
342                    mAmount1 = MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(num)
343                            .create();
344                } catch (ArithmeticException | MonetaryException e) {
345                    // can happen if capabilities are exceeded
346                    continue;
347                }
348                NumberValue result = mAmount1.getNumber();
349                AssertJUnit
350                        .assertEquals("Section 4.2.3: Number value (Short, truncating) returned is not correct for " + type.getName(),
351                                new BigDecimal(String.valueOf(num)).shortValue(),
352                                result.numberValue(Short.class).shortValue());
353            }
354        }
355    }
356
357    /**
358     * Check if a correct Number value is returned, truncation is
359     * allowed to be performed.
360     */
361    @SpecAssertion(section = "4.2.3", id = "423-A9")
362    @Test(description = "4.2.3 Ensure NumberValue floatValue() is truncated.")
363    public void testValidNumberWithTruncation_Float() {
364        Number[] nums =
365                new Number[]{-3232232334423L, -33434243242342342434.5d - 1L, -1.24355354543534545d, (short) 0, 0.3,
366                        (byte) 1, 1.3453, 32432532};
367        for (Number num : nums) {
368            for (Class type : MonetaryAmounts.getAmountTypes()) {
369                if (type.equals(TestAmount.class)) {
370                    continue;
371                }
372                MonetaryAmount mAmount1;
373                try {
374                    mAmount1 = MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(num)
375                            .create();
376                } catch (ArithmeticException | MonetaryException e) {
377                    // can happen if capabilities are exceeded
378                    continue;
379                }
380                NumberValue result = mAmount1.getNumber();
381                AssertJUnit
382                        .assertEquals("Section 4.2.3: Number value (Float, truncating) returned is not correct for " + type.getName(),
383                                new BigDecimal(String.valueOf(num)).floatValue(),
384                                result.numberValue(Float.class).floatValue(), 0.0f);
385            }
386        }
387    }
388
389    /**
390     * Check if a correct Number value is returned, truncation is
391     * allowed to be performed.
392     */
393    @SpecAssertion(section = "4.2.3", id = "423-A9")
394    @Test(description = "4.2.3 Ensure NumberValue doubleValue() is truncated.")
395    public void testValidNumberWithTruncation_Double() {
396        Number[] nums = new Number[]{new BigDecimal("26353527352735725372357.287362873287362836283"),
397                new BigDecimal("-26353527352735725372357.287362873287362836283"), -3232232334423L,
398                -33434243242342342434.5d - 1L, -1.24355354543534545d, (short) 0, 0.3, (byte) 1, 1.3453, 32432532};
399        for (Number num : nums) {
400            for (Class type : MonetaryAmounts.getAmountTypes()) {
401                if (type.equals(TestAmount.class)) {
402                    continue;
403                }
404                MonetaryAmount mAmount1;
405                try {
406                    mAmount1 = MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(num)
407                            .create();
408                } catch (ArithmeticException | MonetaryException e) {
409                    // can happen if capabilities are exceeded
410                    continue;
411                }
412                NumberValue result = mAmount1.getNumber();
413                AssertJUnit
414                        .assertEquals("Section 4.2.3: Number value (Double, truncating) returned is not correct for " + type.getName(),
415                                new BigDecimal(String.valueOf(num)).doubleValue(),
416                                result.numberValue(Double.class), 0.0d);
417            }
418        }
419    }
420
421
422    /**
423     * Check if a correct Number value is returned, truncation is
424     * allowed to be performed.
425     */
426    @SpecAssertion(section = "4.2.3", id = "423-A9")
427    @Test(description = "4.2.3 Ensure NumberValue intValue() is truncated correctly.")
428    public void testValidNumberWithTruncation_Integer() {
429        Number[] nums = new Number[]{-3232423, -3.5f - 1L, -1.2d, (short) 0, 0.3, (byte) 1, 1.3453, 32432532};
430        for (Number num : nums) {
431            for (Class type : MonetaryAmounts.getAmountTypes()) {
432                if (type.equals(TestAmount.class)) {
433                    continue;
434                }
435                MonetaryAmount mAmount1;
436                try {
437                    mAmount1 = MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(num)
438                            .create();
439                } catch (ArithmeticException | MonetaryException e) {
440                    // can happen if capabilities are exceeded
441                    continue;
442                }
443                NumberValue result = mAmount1.getNumber();
444                AssertJUnit
445                        .assertEquals("Section 4.2.3: Number value (short, truncating) returned is not correct for " + type.getName(),
446                                new BigDecimal(String.valueOf(num)).intValue(),
447                                result.numberValue(Integer.class).intValue());
448            }
449        }
450    }
451
452    /**
453     * Test correct precision values, including border cases.
454     */
455    @SpecAssertion(section = "4.2.3", id = "423-A10")
456    @Test(description = "4.2.3 Ensure NumberValue getPrecision() works correctly.")
457    public void testPrecisionValues() {
458        String[] nums =
459                new String[]{"1.12", "1.12", "1.123", "1.1234", "1.12345", "1.123456", "1.1234567", "1.12345678",
460                        "1.123456789", "12.12", "123.12", "1234.123", "12345.1234", "123456.12345", "123456.123456",
461                        "12345678.1234567", "12345678.12345678", "-123456789.123456789", "1", "12", "123", "1234",
462                        "12345", "123456", "1234567", "12345678", "123456789"};
463
464        for (String num : nums) {
465            for (Class type : MonetaryAmounts.getAmountTypes()) {
466                if (type.equals(TestAmount.class)) {
467                    continue;
468                }
469                MonetaryAmount mAmount1;
470                BigDecimal bd = new BigDecimal(num);
471                try {
472                    mAmount1 =
473                            MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(bd).create();
474                } catch (MonetaryException | ArithmeticException e) {
475                    // It is possible, that our test may exceed the capabilities, so in that case, we just continue
476                    continue;
477                }
478                NumberValue result = mAmount1.getNumber();
479                AssertJUnit
480                        .assertEquals("Section 4.2.3: Amount's precision does not match for " + bd + " correct for " + type.getName(),
481                                bd.precision(), result.getPrecision());
482            }
483        }
484    }
485
486    /**
487     * Test correct precision values, including border cases.
488     */
489    @SpecAssertion(section = "4.2.3", id = "423-A11")
490    @Test(description = "4.2.3 Ensure NumberValue getScale() works correctly.")
491    public void testScaleValues() {
492        String[] nums =
493                new String[]{"1.12", "1.12", "1.123", "1.1234", "1.12345", "1.123456", "1.1234567", "1.12345678",
494                        "1.123456789", "12.12", "123.12", "1234.123", "12345.1234", "123456.12345", "123456.123456",
495                        "12345678.1234567", "12345678.12345678", "-123456789.123456789", "1", "12", "123", "1234",
496                        "12345", "123456", "1234567", "12345678", "123456789"};
497        for (String num : nums) {
498            for (Class type : MonetaryAmounts.getAmountTypes()) {
499                if (type.equals(TestAmount.class)) {
500                    continue;
501                }
502                MonetaryAmount mAmount1;
503                BigDecimal bd = new BigDecimal(num);
504                try {
505                    mAmount1 =
506                            MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(bd).create();
507                } catch (MonetaryException | ArithmeticException e) {
508                    // It is possible, that our test may exceed the capabilities, so in that case, we just continue
509                    continue;
510                }
511                NumberValue result = mAmount1.getNumber();
512                AssertJUnit
513                        .assertEquals("Section 4.2.3: Amount's precision does not match for " + bd + " correct for " + type.getName(),
514                                bd.scale(), result.getScale());
515            }
516        }
517    }
518
519    // ********************** B. Testing Numeric Externalization for negative values *******************
520
521    /**
522     * Checks if number type is not null and returning a concrete (no
523     * abstract class or interface).
524     */
525    @SpecAssertion(section = "4.2.3", id = "423-B1")
526    @Test(description = "4.2.3 Ensure NumberValue numberValue() works correnctly.")
527    public void testNumberTypeNegative() {
528        Number[] nums = new Number[]{-1213243544435L, -3, -3.5f - 1L, -1.2d, -21323234324324.23};
529        for (Number num : nums) {
530            for (Class type : MonetaryAmounts.getAmountTypes()) {
531                if (type.equals(TestAmount.class)) {
532                    continue;
533                }
534                MonetaryAmount mAmount1 =
535                        MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(num).create();
536                NumberValue result = mAmount1.getNumber();
537                AssertJUnit.assertEquals("Section 4.2.3: Number value (BigDecimal) returned is not correct for " + type.getName(),
538                        new BigDecimal(String.valueOf(num)).stripTrailingZeros(),
539                        result.numberValue(BigDecimal.class).stripTrailingZeros());
540                AssertJUnit
541                        .assertEquals("Section 4.2.3: Exact number value (BigDecimal) returned is not correct for " + type.getName(),
542                                new BigDecimal(String.valueOf(num)).stripTrailingZeros(),
543                                result.numberValue(BigDecimal.class).stripTrailingZeros());
544            }
545        }
546    }
547
548    /**
549     * Checks if a correct negative Integer value is returned, no truncation is
550     * allowed to be performed.
551     */
552    @SpecAssertion(section = "4.2.3", id = "423-B2")
553    @Test(description = "4.2.3 Checks if a correct Integer value is returned, no truncation is" +
554            " allowed to be performed.")
555    public void testIntegerNegative() {
556        int[] nums = new int[]{-1, -3, -11, -123, -12345, -1223345566};
557        for (long num : nums) {
558            for (Class type : MonetaryAmounts.getAmountTypes()) {
559                if (type.equals(TestAmount.class)) {
560                    continue;
561                }
562                MonetaryAmount mAmount1 =
563                        MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(num).create();
564                NumberValue result = mAmount1.getNumber();
565                AssertJUnit.assertNotNull("Section 4.2.3: Amount creation failed for " + type, result);
566                AssertJUnit.assertEquals("Section 4.2.3: Number value (int) returned is not correct for " + type.getName(), num,
567                        result.intValue());
568                AssertJUnit.assertEquals("Section 4.2.3: Exact number (int) returned is not correct for " + type.getName(), num,
569                        result.intValueExact());
570            }
571        }
572    }
573
574    /**
575     * Checks if a correct Long value is returned, no truncation is
576     * allowed to be performed.
577     */
578    @SpecAssertion(section = "4.2.3", id = "423-B3")
579    @Test(description = "4.2.3 Checks if a correct negative long value is returned, no truncation is" +
580            " allowed to be performed.")
581    public void testLongNegative() {
582        long[] nums = new long[]{-1, -3, -11, -123, -12345, -1223345566, -1234523462532753243L};
583        for (long num : nums) {
584            for (Class type : MonetaryAmounts.getAmountTypes()) {
585                if (type.equals(TestAmount.class)) {
586                    continue;
587                }
588                MonetaryAmount mAmount1;
589                try {
590                    mAmount1 = MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(num)
591                            .create();
592                } catch (ArithmeticException | MonetaryException e) {
593                    // can happen, if number exceeds capabilities.
594                    continue;
595                }
596                NumberValue result = mAmount1.getNumber();
597                AssertJUnit.assertNotNull("Section 4.2.3: Amount creation failed for " + type, result);
598                AssertJUnit.assertEquals("Section 4.2.3: Number value (long) returned is not correct for " + type.getName(), num,
599                        result.longValue());
600                AssertJUnit.assertEquals("Section 4.2.3: Exact number (long) returned is not correct for " + type.getName(), num,
601                        result.longValueExact());
602            }
603        }
604    }
605
606    /**
607     * Checks if a correct Double value is returned, no truncation is
608     * allowed to be performed.
609     */
610    @SpecAssertion(section = "4.2.3", id = "423-B4")
611    @Test(description = "4.2.3 Checks if a correct Double value is returned, no truncation is " +
612            "allowed to be performed.")
613    public void testDoubleNegative() {
614        double[] nums = new double[]{-3.12334, -1.235, -0.43, -1.35, -52.4, -12345, 123, -1223243.342325435};
615        for (double num : nums) {
616            for (Class type : MonetaryAmounts.getAmountTypes()) {
617                if (type.equals(TestAmount.class)) {
618                    continue;
619                }
620                MonetaryAmount mAmount1;
621                try {
622                    mAmount1 = MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(num)
623                            .create();
624                } catch (MonetaryException | ArithmeticException e) {
625                    // It is possible, that our test may exceed the capabilities, so in that case, we just continue
626                    continue;
627                }
628                NumberValue result = mAmount1.getNumber();
629                AssertJUnit
630                        .assertEquals("Section 4.2.3: Number value (double, truncated) returned is not correct for " + type.getName(),
631                                num, result.doubleValue(), 0.0d);
632            }
633        }
634    }
635
636    /**
637     * Check if a correct number value is returned, truncation is
638     * allowed to be performed.
639     * Check should be done for every JDK type
640     * supported.
641     */
642    @SpecAssertion(section = "4.2.3", id = "423-B5")
643    @Test(description = "4.2.3 Check if a correct number value is returned, truncation is " +
644            " allowed to be performed. Check should be done for every JDK type supported.")
645    public void testNumberWithTruncationNegative() {
646        double[] nums = new double[]{-1, -1.1, -1111111111111111111111111111111111111111.11111111111111111111111d};
647        for (double num : nums) {
648            for (Class type : MonetaryAmounts.getAmountTypes()) {
649                if (type.equals(TestAmount.class)) {
650                    continue;
651                }
652                MonetaryAmount mAmount1;
653                BigDecimal dec = new BigDecimal(String.valueOf(num));
654                try {
655                    mAmount1 = MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(num)
656                            .create();
657                } catch (ArithmeticException | MonetaryException e) {
658                    // can hhappen if number exceeds capabilities
659                    continue;
660                }
661                NumberValue result = mAmount1.getNumber();
662                for (Class numType : requiredJdkTykes) {
663                    if (Byte.class.equals(numType)) {
664                        AssertJUnit.assertEquals("Section 4.2.3: Truncating conversion to byte failed for type " + type.getName(),
665                                dec.byteValue(), result.byteValue());
666                    } else if (Short.class.equals(numType)) {
667                        AssertJUnit.assertEquals("Section 4.2.3: Truncating conversion to short failed for type " + type.getName(),
668                                dec.shortValue(), result.shortValue());
669                    } else if (Integer.class.equals(numType)) {
670                        AssertJUnit.assertEquals("Section 4.2.3: Truncating conversion to int failed for type " + type.getName(),
671                                dec.intValue(), result.intValue());
672                    } else if (Long.class.equals(numType)) {
673                        AssertJUnit.assertEquals("Section 4.2.3: Truncating conversion to long failed for type " + type.getName(),
674                                dec.longValue(), result.longValue());
675                    } else if (Float.class.equals(numType)) {
676                        AssertJUnit.assertEquals("Section 4.2.3: Truncating conversion to float failed for type " + type.getName(),
677                                dec.floatValue(), result.floatValue(), 0.0f);
678                    } else if (Double.class.equals(numType)) {
679                        AssertJUnit.assertEquals("Section 4.2.3: Truncating conversion to double failed for type " + type.getName(),
680                                dec.doubleValue(), result.doubleValue(), 0.0d);
681                    } else if (BigDecimal.class.equals(numType)) {
682                        AssertJUnit
683                                .assertEquals("Section 4.2.3: Truncating conversion to BigDecimal failed for type " + type.getName(),
684                                        dec.stripTrailingZeros(),
685                                        result.numberValue(BigDecimal.class).stripTrailingZeros());
686                    } else if (BigInteger.class.equals(numType)) {
687                        AssertJUnit
688                                .assertEquals("Section 4.2.3: Truncating conversion to BigInteger failed for type " + type.getName(),
689                                        dec.toBigInteger(), result.numberValue(BigInteger.class));
690                    }
691                }
692            }
693        }
694    }
695
696    /**
697     * Check if a correct integer value is returned, truncation is
698     * allowed to be performed.
699     */
700    @SpecAssertion(section = "4.2.3", id = "423-B6")
701    @Test(description = "4.2.3 Check if a correct integer value is returned, truncation is" +
702            " allowed to be performed..")
703    public void testIntegerWithTruncationNegative() {
704        double[] nums = new double[]{-1.1, -3.12, -11.123, -123.1234, -12345.12233, -1223345566.2332432};
705        for (double num : nums) {
706            for (Class type : MonetaryAmounts.getAmountTypes()) {
707                if (type.equals(TestAmount.class)) {
708                    continue;
709                }
710                MonetaryAmount mAmount1;
711                try {
712                    mAmount1 = MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(num)
713                            .create();
714                } catch (ArithmeticException | MonetaryException e) {
715                    // can hhappen if number exceeds capabilities
716                    continue;
717                }
718                NumberValue result = mAmount1.getNumber();
719                AssertJUnit.assertEquals("Section 4.2.3: Number value (int) returned is not correct for " + type.getName(), (int) num,
720                        result.intValue());
721            }
722        }
723    }
724
725    /**
726     * Check if a correct long value is returned, truncation is
727     * allowed to be performed.
728     */
729    @SpecAssertion(section = "4.2.3", id = "423-B7")
730    @Test(description = "4.2.3 Checks if a correct long value is returned, truncation is" +
731            " allowed to be performed.")
732    public void testLongWithTruncationNegative() {
733        double[] nums = new double[]{-3.12334, -1.23345, -1223234.23};
734        for (double num : nums) {
735            for (Class type : MonetaryAmounts.getAmountTypes()) {
736                if (type.equals(TestAmount.class)) {
737                    continue;
738                }
739                MonetaryAmount mAmount1;
740                try {
741                    mAmount1 = MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(num)
742                            .create();
743                } catch (MonetaryException | ArithmeticException e) {
744                    // It is possible, that our test may exceed the capabilities, so in that case, we just continue
745                    continue;
746                }
747                NumberValue result = mAmount1.getNumber();
748                AssertJUnit.assertEquals("Section 4.2.3: Number value (long, truncated) returned is not correct for " + type.getName(),
749                        (long) num, result.intValue());
750                try {
751                    result.longValueExact();
752                    AssertJUnit
753                            .fail("Section 4.2.3: Number value (long, exact -> truncated) must throw ArithemticException on truncation for " +
754                                    type.getName());
755                } catch (ArithmeticException e) {
756                    // OK
757                }
758            }
759        }
760    }
761
762    /**
763     * Check if a correct double value is returned, truncation is
764     * allowed to be performed.
765     */
766    @SpecAssertion(section = "4.2.3", id = "423-B8")
767    @Test(description = "4.2.3 Checks if a correct double value is returned, truncation is" +
768            " allowed to be performed.")
769    public void testDoubleWithTruncationNegative() {
770        Number[] nums = new Number[]{new BigDecimal("-26353527352735725372357.287362873287362836283"), -3232232334423L,
771                -33434243242342342434.5d, -1L, -1.24355354543534545d, (short) -0, -0.3, (byte) -1, -1.3453, 32432532};
772        for (Number num : nums) {
773            for (Class type : MonetaryAmounts.getAmountTypes()) {
774                if (type.equals(TestAmount.class)) {
775                    continue;
776                }
777                MonetaryAmount mAmount1;
778                try {
779                    mAmount1 = MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(num)
780                            .create();
781                } catch (ArithmeticException | MonetaryException e) {
782                    // can happen if capabilities are exceeded
783                    continue;
784                }
785                NumberValue result = mAmount1.getNumber();
786                AssertJUnit
787                        .assertEquals("Section 4.2.3: Number value (Double, truncating) returned is not correct for " + type.getName(),
788                                new BigDecimal(String.valueOf(num)).doubleValue(), result.doubleValue(), 0.0d);
789            }
790        }
791    }
792
793    /**
794     * Check if a correct double value is returned, truncation is
795     * allowed to be performed. Check should be done for every JDK type
796     * supported.
797     */
798    @SpecAssertion(section = "4.2.3", id = "423-B9")
799    @Test(description = "4.2.3 Checks if a correct long value is returned, truncation is" +
800            " allowed to be performed. Check should be done for every JDK type.")
801    public void testNumberValueWithTruncationNegative() {
802        Number[] nums = new Number[]{-1213243544435L, -3234, -3.5f - 1.1, -1.2d, -21323234324324.23};
803        for (Number num : nums) {
804            for (Class type : MonetaryAmounts.getAmountTypes()) {
805                if (type.equals(TestAmount.class)) {
806                    continue;
807                }
808                MonetaryAmount mAmount1 =
809                        MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(num).create();
810                NumberValue result = mAmount1.getNumber();
811                AssertJUnit
812                        .assertEquals("Section 4.2.3: Number value (BigDecimal -> byte) returned is not correct for " + type.getName(),
813                                (long) new BigDecimal(String.valueOf(num)).byteValue(),
814                                (long) result.numberValue(Byte.class));
815            }
816        }
817    }
818
819    /**
820     * Check if a correct double value is returned, truncation is
821     * allowed to be performed. Check should be done for every JDK type
822     * supported.
823     */
824    @SpecAssertion(section = "4.2.3", id = "423-B9")
825    @Test(description = "4.2.3 Checks if a correct double value is returned, truncation is" +
826            " allowed to be performed. Check should be done for every JDK type.")
827    public void testNumberValueWithTruncationNegative_Short() {
828        Number[] nums = new Number[]{-1213243544435L, -3234, -3.5f - 1.1, -1.2d, -21323234324324.23};
829        for (Number num : nums) {
830            for (Class type : MonetaryAmounts.getAmountTypes()) {
831                if (type.equals(TestAmount.class)) {
832                    continue;
833                }
834                MonetaryAmount mAmount1 =
835                        MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(num).create();
836                NumberValue result = mAmount1.getNumber();
837                AssertJUnit
838                        .assertEquals("Section 4.2.3: Number value (BigDecimal -> byte) returned is not correct for " + type.getName(),
839                                (long) new BigDecimal(String.valueOf(num)).shortValue(),
840                                (long) result.numberValue(Short.class));
841                AssertJUnit
842                        .assertEquals("Section 4.2.3: Number value (BigDecimal -> byte) returned is not correct for " + type.getName(),
843                                (long) new BigDecimal(String.valueOf(num)).shortValue(),
844                                (long) result.shortValue());
845            }
846        }
847    }
848
849    /**
850     * Check if a correct double value is returned, truncation is
851     * allowed to be performed. Check should be done for every JDK type
852     * supported.
853     */
854    @SpecAssertion(section = "4.2.3", id = "423-B9")
855    @Test(description = "4.2.3 Checks if a correct int value is returned, truncation is" +
856            " allowed to be performed. Check should be done for every JDK type.")
857    public void testNumberValueWithTruncationNegative_Integer() {
858        Number[] nums = new Number[]{-1213243544435L, -3234, -3.5f - 1.1, -1.2d, -21323234324324.23};
859        for (Number num : nums) {
860            for (Class type : MonetaryAmounts.getAmountTypes()) {
861                if (type.equals(TestAmount.class)) {
862                    continue;
863                }
864                MonetaryAmount mAmount1 =
865                        MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(num).create();
866                NumberValue result = mAmount1.getNumber();
867                AssertJUnit
868                        .assertEquals("Section 4.2.3: Number value (BigDecimal -> byte) returned is not correct for " + type.getName(),
869                                (long) new BigDecimal(String.valueOf(num)).intValue(),
870                                (long) result.numberValue(Integer.class));
871                AssertJUnit
872                        .assertEquals("Section 4.2.3: Number value (BigDecimal -> byte) returned is not correct for " + type.getName(),
873                                (long) new BigDecimal(String.valueOf(num)).intValue(), (long) result.intValue());
874            }
875        }
876    }
877
878    /**
879     * Check if a correct number value is returned, truncation is
880     * allowed to be performed. Check should be done for every JDK type
881     * supported.
882     */
883    @SpecAssertion(section = "4.2.3", id = "423-B9")
884    @Test(description = "4.2.3 Checks if a correct Number value is returned, truncation is" +
885            " allowed to be performed. Check should be done for every JDK type.")
886    public void testNumberValueWithTruncationNegative_Long() {
887        Number[] nums = new Number[]{-1213243544435L, -3234, -3.5f - 1.1, -1.2d, -21323234324324.23};
888        for (Number num : nums) {
889            for (Class type : MonetaryAmounts.getAmountTypes()) {
890                if (type.equals(TestAmount.class)) {
891                    continue;
892                }
893                MonetaryAmount mAmount1 =
894                        MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(num).create();
895                NumberValue result = mAmount1.getNumber();
896                AssertJUnit
897                        .assertEquals("Section 4.2.3: Number value (BigDecimal -> byte) returned is not correct for " + type.getName(),
898
899                                new BigDecimal(String.valueOf(num)).longValue(),
900                                (long) result.numberValue(Long.class));
901                AssertJUnit
902                        .assertEquals("Section 4.2.3: Number value (BigDecimal -> byte) returned is not correct for " + type.getName(),
903
904                                new BigDecimal(String.valueOf(num)).longValue(), result.longValue());
905            }
906        }
907    }
908
909    /**
910     * Check if a correct double value is returned, truncation is
911     * allowed to be performed. Check should be done for every JDK type
912     * supported.
913     */
914    @SpecAssertion(section = "4.2.3", id = "423-B9")
915    @Test(description = "4.2.3 Checks if a correct double value is returned, truncation is" +
916            " allowed to be performed. Check should be done for every JDK type.")
917    public void testNumberValueWithTruncationNegative_Float() {
918        Number[] nums = new Number[]{-1213243544435L, -3234, -3.5f - 1.1, -1.2d, -21323234324324.23};
919        for (Number num : nums) {
920            for (Class type : MonetaryAmounts.getAmountTypes()) {
921                if (type.equals(TestAmount.class)) {
922                    continue;
923                }
924                MonetaryAmount mAmount1 =
925                        MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(num).create();
926                NumberValue result = mAmount1.getNumber();
927                AssertJUnit.assertEquals(
928                        "Section 4.2.3: Number value (BigDecimal -> float) returned is not correct for " + type.getName(),
929                        new BigDecimal(String.valueOf(num)).floatValue(), result.numberValue(Float.class).floatValue(),
930                        0.0f);
931                AssertJUnit.assertEquals(
932                        "Section 4.2.3: Number value (BigDecimal -> float) returned is not correct for " + type.getName(),
933                        new BigDecimal(String.valueOf(num)).floatValue(), result.floatValue(), 0.0f);
934            }
935        }
936    }
937
938    /**
939     * Check if a correct double value is returned, truncation is
940     * allowed to be performed. Check should be done for every JDK type
941     * supported.
942     */
943    @SpecAssertion(section = "4.2.3", id = "423-B9")
944    @Test(description = "4.2.3 Checks if a correct double value is returned, truncation is" +
945            " allowed to be performed. Check should be done for every JDK type.")
946    public void testNumberValueWithTruncationNegative_Double() {
947        Number[] nums = new Number[]{-1213243544435L, -3234, -3.5f - 1.1, -1.2d, -21323234324324.23};
948        for (Number num : nums) {
949            for (Class type : MonetaryAmounts.getAmountTypes()) {
950                if (type.equals(TestAmount.class)) {
951                    continue;
952                }
953                MonetaryAmount mAmount1 =
954                        MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(num).create();
955                NumberValue result = mAmount1.getNumber();
956                AssertJUnit.assertEquals(
957                        "Section 4.2.3: Number value (BigDecimal -> double) returned is not correct for " + type.getName(),
958                        new BigDecimal(String.valueOf(num)).doubleValue(), result.numberValue(Double.class), 0.0d);
959                AssertJUnit.assertEquals(
960                        "Section 4.2.3: Number value (BigDecimal -> double) returned is not correct for " + type.getName(),
961                        new BigDecimal(String.valueOf(num)).doubleValue(), result.doubleValue(), 0.0d);
962            }
963        }
964    }
965
966    /**
967     * Test correct precision values, including border cases.
968     */
969    @SpecAssertion(section = "4.2.3", id = "423-B10")
970    @Test(description = "4.2.3 Test correct precision values, including border cases.")
971    public void testPrecisionNegative() {
972        String[] nums = new String[]{"-1.12", "-1.12", "-1.123", "-1.1234", "-1.12345", "-1.123456", "-1.1234567",
973                "-1.12345678", "-1.123456789", "-12.12", "-123.12", "-1234.123", "-12345.1234", "-123456.12345",
974                "-123456.123456", "-12345678.1234567", "-12345678.12345678", "-123456789.123456789", "-1", "-12",
975                "-123", "-1234", "-12345", "-123456", "-1234567", "-12345678", "-123456789"};
976        for (String num : nums) {
977            for (Class type : MonetaryAmounts.getAmountTypes()) {
978                if (type.equals(TestAmount.class)) {
979                    continue;
980                }
981                MonetaryAmount mAmount1;
982                BigDecimal bd = new BigDecimal(num);
983                try {
984                    mAmount1 =
985                            MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(bd).create();
986                } catch (MonetaryException | ArithmeticException e) {
987                    // It is possible, that our test may exceed the capabilities, so in that case, we just continue
988                    continue;
989                }
990                NumberValue result = mAmount1.getNumber();
991                AssertJUnit
992                        .assertEquals("Section 4.2.3: Amount's precision does not match for " + bd + " correct for " + type.getName(),
993                                bd.precision(), result.getPrecision());
994            }
995        }
996    }
997
998    /**
999     * Test correct scale values, including border cases.
1000     */
1001    @SpecAssertion(section = "4.2.3", id = "423-B11")
1002    @Test(description = "4.2.3 Test correct scale values, including border cases.")
1003    public void testScaleNegative() {
1004        String[] nums = new String[]{"-1.12", "-1.12", "-1.123", "-1.1234", "-1.12345", "-1.123456", "-1.1234567",
1005                "-1.12345678", "-1.123456789", "-12.12", "-123.12", "-1234.123", "-12345.1234", "-123456.12345",
1006                "-123456.123456", "-12345678.1234567", "-12345678.12345678", "-123456789.123456789", "-1", "-12",
1007                "-123", "-1234", "-12345", "-123456", "-1234567", "-12345678", "-123456789"};
1008        for (String num : nums) {
1009            for (Class type : MonetaryAmounts.getAmountTypes()) {
1010                if (type.equals(TestAmount.class)) {
1011                    continue;
1012                }
1013                MonetaryAmount mAmount1;
1014                BigDecimal bd = new BigDecimal(num);
1015                try {
1016                    mAmount1 =
1017                            MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(bd).create();
1018                } catch (MonetaryException | ArithmeticException e) {
1019                    // It is possible, that our test may exceed the capabilities, so in that case, we just continue
1020                    continue;
1021                }
1022                NumberValue result = mAmount1.getNumber();
1023                AssertJUnit.assertEquals("Section 4.2.3: Amount's scale does not match for " + bd + " correct for " + type.getName(),
1024                        bd.scale(), result.getScale());
1025            }
1026        }
1027    }
1028
1029    // ********************* C. Testing Numeric Externalization for zero values **************
1030
1031    /**
1032     * Checks if number type is not null and returning a concrete (no
1033     * abstract class or interface).
1034     */
1035    @SpecAssertion(section = "4.2.3", id = "423-C1")
1036    @Test(description = "4.2.3 Checks if number type is not null and returning a concrete (no" +
1037            " abstract class or interface).")
1038    public void testNumberTypeZero() {
1039        Number[] nums =
1040                new Number[]{new BigDecimal("-0.0"), new BigDecimal("0"), new BigInteger("0"), 0, 0L, (byte) 0, 0.0f,
1041                        0.0d};
1042        for (Number num : nums) {
1043            for (Class type : MonetaryAmounts.getAmountTypes()) {
1044                if (type.equals(TestAmount.class)) {
1045                    continue;
1046                }
1047                MonetaryAmount mAmount1;
1048                try {
1049                    mAmount1 = MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(num)
1050                            .create();
1051                } catch (ArithmeticException | MonetaryException e) {
1052                    // can happen if capabilities are exceeded
1053                    continue;
1054                }
1055                NumberValue result = mAmount1.getNumber();
1056                AssertJUnit.assertEquals("Section 4.2.3: Number value (byte) returned is not correct for " + type.getName(),
1057                        new BigDecimal(String.valueOf(num)).byteValue(), (byte) 0,
1058                        result.numberValue(Byte.class).byteValue());
1059                AssertJUnit.assertEquals("Section 4.2.3: Number value (short) returned is not correct for " + type.getName(),
1060                        new BigDecimal(String.valueOf(num)).shortValue(), (short) 0,
1061                        result.numberValue(Short.class).shortValue());
1062                AssertJUnit.assertEquals("Section 4.2.3: Number value (int) returned is not correct for " + type.getName(),
1063                        new BigDecimal(String.valueOf(num)).intValue(), 0,
1064                        result.numberValue(Integer.class).intValue());
1065                AssertJUnit.assertEquals("Section 4.2.3: Number value (long) returned is not correct for " + type.getName(),
1066                        new BigDecimal(String.valueOf(num)).longValue(), (long) 0,
1067                        result.numberValue(Long.class).longValue());
1068                AssertJUnit.assertEquals("Section 4.2.3: Number value (float) returned is not correct for " + type.getName(),
1069                        new BigDecimal(String.valueOf(num)).floatValue(), 0.0f,
1070                        result.numberValue(Float.class).floatValue());
1071                AssertJUnit.assertEquals("Section 4.2.3: Number value (double) returned is not correct for " + type.getName(),
1072                        new BigDecimal(String.valueOf(num)).doubleValue(), 0.0f,
1073                        result.numberValue(Double.class));
1074            }
1075        }
1076    }
1077
1078    /**
1079     * Check if a correct integer value is returned, no truncation is
1080     * allowed to be performed.
1081     */
1082    @SpecAssertion(section = "4.2.3", id = "423-C2")
1083    @Test(description = "4.2.3 Check if a correct integer value is returned, no truncation is " +
1084            " allowed to be performed.")
1085    public void testIntegerZero() {
1086        Number[] nums = new Number[]{0, 0.0, -0.0, new BigDecimal("0.000000000000000000000000000001"),
1087                new BigDecimal("-0.000000000000000000000000000001"), new BigInteger("0")};
1088        for (Number num : nums) {
1089            for (Class type : MonetaryAmounts.getAmountTypes()) {
1090                if (type.equals(TestAmount.class)) {
1091                    continue;
1092                }
1093                MonetaryAmount mAmount1;
1094                try {
1095                    mAmount1 = MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(num)
1096                            .create();
1097                } catch (MonetaryException | ArithmeticException e) {
1098                    // It is possible, that our test may exceed the capabilities, so in that case, we just continue
1099                    continue;
1100                }
1101                NumberValue result = mAmount1.getNumber();
1102                AssertJUnit
1103                        .assertEquals("Section 4.2.3: Number value (int, truncating) returned is not correct for " + num + ", type; " +
1104                                type.getName(), 0, result.intValue());
1105            }
1106        }
1107    }
1108
1109    /**
1110     * Check if a correct long value is returned, no truncation is
1111     * allowed to be performed.
1112     */
1113    @SpecAssertion(section = "4.2.3", id = "423-C3")
1114    @Test(description = "4.2.3 Check if a correct long zero value is returned, no truncation is " +
1115            " allowed to be performed.")
1116    public void testLongZero() {
1117        Number[] nums = new Number[]{0, 0.0, -0.0, new BigDecimal("0.00000000000000000000000000000"),
1118                new BigDecimal("-0.00000000000000000000000000000"), new BigInteger("0")};
1119        for (Number num : nums) {
1120            for (Class type : MonetaryAmounts.getAmountTypes()) {
1121                if (type.equals(TestAmount.class)) {
1122                    continue;
1123                }
1124                MonetaryAmount mAmount1;
1125                try {
1126                    mAmount1 = MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(num)
1127                            .create();
1128                } catch (MonetaryException | ArithmeticException e) {
1129                    // It is possible, that our test may exceed the capabilities, so in that case, we just continue
1130                    continue;
1131                }
1132                NumberValue result = mAmount1.getNumber();
1133                AssertJUnit.assertEquals(
1134                        "Section 4.2.3: Number value (long, truncating) returned is not correct for " + num + ", type; " +
1135                                type.getName(), 0L, result.longValue());
1136                AssertJUnit.assertEquals("Section 4.2.3: Number value (long, exact) returned is not correct for " + num + ", type; " +
1137                        type.getName(), 0L, result.longValue());
1138            }
1139        }
1140    }
1141
1142
1143    /**
1144     * Check if a correct number value is returned, no truncation is
1145     * allowed to be performed.
1146     * Check should be done for every JDK type
1147     * supported.
1148     */
1149    @SpecAssertion(section = "4.2.3", id = "423-C4")
1150    @Test(description = "4.2.3 Check if a correct long zero value is returned, no truncation is " +
1151            " allowed to be performed.")
1152    public void testNumberValueZero() {
1153        Number[] nums = new Number[]{0.0, -0.0, new BigDecimal("0.00000"), new BigDecimal("-0.000000000000000000000"),
1154                new BigInteger("0")};
1155        for (Number num : nums) {
1156            for (Class type : MonetaryAmounts.getAmountTypes()) {
1157                if (type.equals(TestAmount.class)) {
1158                    continue;
1159                }
1160                MonetaryAmount mAmount1;
1161                try {
1162                    mAmount1 = MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(num)
1163                            .create();
1164                } catch (MonetaryException | ArithmeticException e) {
1165                    // It is possible, that our test may exceed the capabilities, so in that case, we just continue
1166                    continue;
1167                }
1168                NumberValue result = mAmount1.getNumber();
1169                AssertJUnit.assertEquals("Section 4.2.3: Number value (Number, long) returned is not correct for " + num + ", type; " +
1170                                type.getName(), 0L,
1171                        result.numberValue(BigDecimal.class).longValueExact());
1172                AssertJUnit
1173                        .assertEquals("Section 4.2.3: Number value (Number, short) returned is not correct for " + num + ", type; " +
1174                                type.getName(), 0.0f, result.numberValue(Short.class).floatValue(), 0.0f);
1175                AssertJUnit.assertEquals("Section 4.2.3: Number value (Number, int) returned is not correct for " + num + ", type; " +
1176                        type.getName(), 0, result.numberValue(Short.class).intValue());
1177                AssertJUnit
1178                        .assertEquals("Section 4.2.3: Number value (Number, double) returned is not correct for " + num + ", type; " +
1179                                        type.getName(), 0.0d, result.numberValue(Double.class),
1180                                0.0f);
1181                AssertJUnit.assertEquals(
1182                        "Section 4.2.3: Number value (Number, BigInteger) returned is not correct for " + num + ", type; " +
1183                                type.getName(), 0L, result.numberValue(BigInteger.class).longValueExact());
1184                AssertJUnit.assertEquals(
1185                        "Section 4.2.3: Number value (Number, BigDecimal) returned is not correct for " + num + ", type; " +
1186                                type.getName(), 0L, result.numberValue(BigDecimal.class).longValueExact());
1187                result.numberValueExact(BigDecimal.class);
1188            }
1189        }
1190    }
1191
1192    /**
1193     * Check if a correct integer value is returned, truncation is
1194     * allowed to be performed.
1195     * Check should be done for every JDK type
1196     * supported.
1197     */
1198    @SpecAssertion(section = "4.2.3", id = "423-C5")
1199    @Test(description = "4.2.3 Check if a correct integer value is returned, truncation is " +
1200            "allowed to be performed. " +
1201            "Check should be done for every JDK type " +
1202            "supported.")
1203    public void testIntegerValueWithTruncationZero() {
1204        Number[] nums =
1205                new Number[]{0.01, -0.02, new BigDecimal("0.000001"), new BigDecimal("-0.0000000000000000000001")};
1206        for (Number num : nums) {
1207            for (Class type : MonetaryAmounts.getAmountTypes()) {
1208                if (type.equals(TestAmount.class)) {
1209                    continue;
1210                }
1211                MonetaryAmount mAmount1;
1212                try {
1213                    mAmount1 = MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(num)
1214                            .create();
1215                } catch (MonetaryException | ArithmeticException e) {
1216                    // It is possible, that our test may exceed the capabilities, so in that case, we just continue
1217                    continue;
1218                }
1219                NumberValue result = mAmount1.getNumber();
1220                AssertJUnit
1221                        .assertEquals("Section 4.2.3: Number value (int, truncating) returned is not correct for " + num + ", type; " +
1222                                type.getName(), 0L, result.intValue());
1223                try {
1224                    result.intValueExact();
1225                    AssertJUnit
1226                            .fail("Section 4.2.3: Number value (int, exact) should throw ArithmeticException for " + num + ", type; " +
1227                                    type.getName());
1228                } catch (ArithmeticException e) {
1229                    // OK, as expected!
1230                }
1231            }
1232        }
1233    }
1234
1235    /**
1236     * Check if a correct long value is returned, truncation is
1237     * allowed to be performed.
1238     * Check should be done for every JDK type
1239     * supported.
1240     */
1241    @SpecAssertion(section = "4.2.3", id = "423-C6")
1242    @Test(description = "4.2.3 Check if a correct long value is returned, truncation is " +
1243            "allowed to be performed. " +
1244            "Check should be done for every JDK type " +
1245            "supported.")
1246    public void testLongValueWithTruncationZero() {
1247        Number[] nums =
1248                new Number[]{0.01, -0.02, new BigDecimal("0.000001"), new BigDecimal("-0.0000000000000000000001")};
1249        for (Number num : nums) {
1250            for (Class type : MonetaryAmounts.getAmountTypes()) {
1251                if (type.equals(TestAmount.class)) {
1252                    continue;
1253                }
1254                MonetaryAmount mAmount1;
1255                try {
1256                    mAmount1 = MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(num)
1257                            .create();
1258                } catch (MonetaryException | ArithmeticException e) {
1259                    // It is possible, that our test may exceed the capabilities, so in that case, we just continue
1260                    continue;
1261                }
1262                NumberValue result = mAmount1.getNumber();
1263                AssertJUnit.assertEquals(
1264                        "Section 4.2.3: Number value (long, truncating) returned is not correct for " + num + ", type; " +
1265                                type.getName(), 0L, result.longValue());
1266                try {
1267                    result.longValueExact();
1268                    AssertJUnit.fail("Section 4.2.3: Number value (long, exact) should throw ArithmeticException for " + num +
1269                            ", type; " +
1270                            type.getName());
1271                } catch (ArithmeticException e) {
1272                    // OK, as expected!
1273                }
1274            }
1275        }
1276    }
1277
1278    /**
1279     * Check if a correct double value is returned, truncation is
1280     * allowed to be performed (but is not necessary).
1281     */
1282    @SpecAssertion(section = "4.2.3", id = "423-C7")
1283    @Test(description = "4.2.3 Check if a correct double value is returned, truncation is " +
1284            "allowed to be performed (but is not necessary).")
1285    public void testDoubleValueWithTruncationZero() {
1286        Number[] nums = new Number[]{new BigDecimal("-0.000000000000000000000000000000000000000000000000000000000000000" +
1287                "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" +
1288                "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" +
1289                "000000000000000000000000000001234")};
1290        for (Number num : nums) {
1291            for (Class type : MonetaryAmounts.getAmountTypes()) {
1292                if (type.equals(TestAmount.class)) {
1293                    continue;
1294                }
1295                MonetaryAmount mAmount1;
1296                try {
1297                    mAmount1 = MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(num)
1298                            .create();
1299                } catch (ArithmeticException | MonetaryException e) {
1300                    // can happen if capabilities are exceeded
1301                    continue;
1302                }
1303                NumberValue result = mAmount1.getNumber();
1304                AssertJUnit
1305                        .assertEquals("Section 4.2.3: Number value (Double, truncating) returned is not correct for " + type.getName(),
1306                                new BigDecimal(String.valueOf(num)).doubleValue(), result.doubleValue(), 0.0d);
1307            }
1308        }
1309    }
1310
1311
1312    /**
1313     * Check if a correct Number value is returned, truncation is
1314     * allowed to be performed.
1315     * Check should be done for every JDK type
1316     * supported.
1317     */
1318    @SpecAssertion(section = "4.2.3", id = "423-C8")
1319    @Test(description = "4.2.3 Check if a correct Number value is returned, truncation is " +
1320            "allowed to be performed. " +
1321            "Check should be done for every JDK type " +
1322            "supported.")
1323    public void testNumberValueWithTruncationZero() {
1324        Number[] nums = new Number[]{new BigDecimal("-0000000000000000.00000000000000000000000000000000000001234")};
1325        for (Number num : nums) {
1326            for (Class type : MonetaryAmounts.getAmountTypes()) {
1327                if (type.equals(TestAmount.class)) {
1328                    continue;
1329                }
1330                MonetaryAmount mAmount1;
1331                try {
1332                    mAmount1 = MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(num)
1333                            .create();
1334                } catch (ArithmeticException | MonetaryException e) {
1335                    // can happen if capabilities are exceeded
1336                    continue;
1337                }
1338                NumberValue result = mAmount1.getNumber();
1339                AssertJUnit
1340                        .assertEquals("Section 4.2.3: Number value (Double, truncating) returned is not correct for " + type.getName(),
1341                                new BigDecimal(String.valueOf(num)).doubleValue(), result.doubleValue(), 0.0d);
1342            }
1343        }
1344    }
1345
1346    /**
1347     * Check if a correct precision value is returned.
1348     * Check should be done for every JDK type
1349     * supported.
1350     */
1351    @SpecAssertion(section = "4.2.3", id = "423-C9")
1352    @Test(description = "4.2.3 Check if a correct precision value is returned. Check should be done for every JDK type " +
1353            "supported.")
1354    public void testPrecisionZero() {
1355        String[] nums =
1356                new String[]{"-0", "0", "-0.0", "0.0", "-0.00", "0.00", "-0.000", "0.0000", "0.00000", "-0.0000000",
1357                        "-0.000000000", "-0.00000000000"};
1358        for (String num : nums) {
1359            for (Class type : MonetaryAmounts.getAmountTypes()) {
1360                if (type.equals(TestAmount.class)) {
1361                    continue;
1362                }
1363                MonetaryAmount mAmount1;
1364                BigDecimal bd = new BigDecimal(num);
1365                try {
1366                    mAmount1 =
1367                            MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(bd).create();
1368                } catch (MonetaryException | ArithmeticException e) {
1369                    // It is possible, that our test may exceed the capabilities, so in that case, we just continue
1370                    continue;
1371                }
1372                NumberValue result = mAmount1.getNumber();
1373                AssertJUnit.assertEquals("Section 4.2.3: Amount's scale does not match for " + bd + " correct for " + type.getName(),
1374                        bd.precision(), result.getPrecision());
1375            }
1376        }
1377    }
1378
1379    /**
1380     * Check if a correct scale value is returned. For 0 the scale should always be 0.
1381     */
1382    @SpecAssertion(section = "4.2.3", id = "423-C10")
1383    @Test(description = "4.2.3 Check if a correct scale value is returned. Check should be done for every JDK type " +
1384            "supported.")
1385    public void testScaleZero() {
1386        String[] nums =
1387                new String[]{"-0", "-0.0", "-0.00", "-0.000", "-0.0000", "-0.00000", "-0.000000", "-0.00000000"};
1388        for (String num : nums) {
1389            for (Class type : MonetaryAmounts.getAmountTypes()) {
1390                if (type.equals(TestAmount.class)) {
1391                    continue;
1392                }
1393                MonetaryAmount mAmount1;
1394                BigDecimal bd = new BigDecimal(num);
1395                try {
1396                    mAmount1 =
1397                            MonetaryAmounts.getAmountFactory(type).setCurrency(DEFAULT_CURRENCY).setNumber(bd).create();
1398                } catch (MonetaryException | ArithmeticException e) {
1399                    // It is possible, that our test may exceed the capabilities, so in that case, we just continue
1400                    continue;
1401                }
1402                NumberValue result = mAmount1.getNumber();
1403                AssertJUnit.assertTrue("Section 4.2.3: Amount's scale is < 0 for " + num + ", was " +
1404                        result.getScale() + " for " + type.getName(), 0 <= result.getScale());
1405            }
1406        }
1407    }
1408
1409}