File: BigDecimalCompatibilityTest.java

package info (click to toggle)
openjdk-21 21.0.8%2B9-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 823,976 kB
  • sloc: java: 5,613,338; xml: 1,643,607; cpp: 1,296,296; ansic: 420,291; asm: 404,850; objc: 20,994; sh: 15,271; javascript: 11,245; python: 6,895; makefile: 2,362; perl: 357; awk: 351; sed: 172; jsp: 24; csh: 3
file content (180 lines) | stat: -rw-r--r-- 7,193 bytes parent folder | download | duplicates (10)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
/*
 * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

/*
 * @test
 * @bug 4018937
 * @summary Confirm that DecimalFormat.parse() parses BigDecimal and BigInteger
 *          string values as expected. Specifically, ensure a ParseException is
 *          not thrown as well as the parsed value being numerically correct.
 *          Tests large String values with combinations of multipliers and exponents.
 * @run junit BigDecimalCompatibilityTest
 */

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Locale;
import java.util.stream.Stream;

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;

public class BigDecimalCompatibilityTest {

    private static DecimalFormat df = new DecimalFormat();
    // Save JVM default Locale
    private static final Locale savedLocale = Locale.getDefault();

    // ---- Used for the test data (start) ----

    // Both ArrayList composed of Arguments(String longString, int multiplier)
    private static final ArrayList<Arguments> bigIntegers = new ArrayList<Arguments>();
    private static final ArrayList<Arguments> bigDecimals = new ArrayList<Arguments>();

    // Long string data to generate combinations of test values
    private static final String[] inputData = {
            "0".repeat(400),
            "1234567890".repeat(40)};

    // Variety of exponents to test parse() against
    private static final String[] exponents = {
            "E-100", "E100", "E-900", "E900", ""
    };

    // Variety of multipliers that DecimalFormat can apply
    private static final int[] multipliers = {
            -1, 1, -100, 100, -9999, 9999
    };
    // ---- Used for the test data (end) ----

    // Set JVM default Locale to US and populate the test arrayLists
    @BeforeAll
    static void initAll() {
        Locale.setDefault(Locale.US);
        buildTestData();
    }

    /*
     * Uses inputData and exponents to build long string
     * decimal and integer values and populate bigDecimals and bigIntegers
     * accordingly. Attaches a multiplier value as well to the test data.
     */
    private static void buildTestData() {
        for (String longString1 : inputData) {
            for (String longString2 : inputData) {
                String bigInteger = longString1 + longString2;
                for (int multiplier : multipliers) {
                    bigIntegers.add(Arguments.of(bigInteger, multiplier));
                    bigIntegers.add(Arguments.of('-' + bigInteger, multiplier));
                }
                for (String longString3 : inputData) {
                    for (String longString4 : inputData) {
                        for (String exponent : exponents) {
                            String bigDecimal = longString1 + longString2 + '.'
                                    + longString3 + longString4 + exponent;
                            for (int multiplier : multipliers) {
                                bigDecimals.add(Arguments.of(bigDecimal, multiplier));
                                bigDecimals.add(Arguments.of('-' + bigDecimal, multiplier));
                            }
                        }
                    }
                }
            }
        }
    }

    // Restore JVM default Locale
    @AfterAll
    static void tearDownAll() {
        Locale.setDefault(savedLocale);
    }

    // Tests strings with length 1600+. See test() for specific details.
    @ParameterizedTest
    @MethodSource("bigDecimalProvider")
    public void bigDecimalParseTest(String longString, int multiplier) {
        test(longString, multiplier);
    }

    // Returns 960 arrangements of bigDecimal string values and multipliers
    // In the form of (String, int).
    private static Stream<Arguments> bigDecimalProvider() {
        return bigDecimals.stream();
    }

    // Tests strings with length 800+. See test() for specific details.
    @ParameterizedTest
    @MethodSource("bigIntegerProvider")
    public void bigIntegerParseTest(String longString, int multiplier) {
        test(longString, multiplier);
    }

    // Returns 48 arrangements of bigInteger string values and multipliers
    // In the form of (String, int).
    private static Stream<Arguments> bigIntegerProvider() {
        return bigIntegers.stream();
    }

    /*
     * Tests that parsing a large BigDecimal/BigInteger string value
     * will not throw a ParseException with setParseBigDecimal as true.
     * Parses with a variety of multiplier values. Then ensures that the parsed
     * value is the expected number.
     */
    private static void test(String longString, int multiplier) {
        // Reset DecimalFormat for a clean test
        df = new DecimalFormat();
        df.setParseBigDecimal(true);
        // wide enough to support the long string test data
        df.setMaximumFractionDigits(Integer.MAX_VALUE);
        df.setMultiplier(multiplier);

        // Check parse and returned value. This was originally intended to ensure
        // a ParseException is not thrown
        Number parsedValue = assertDoesNotThrow(()-> df.parse(longString),
                "Should not throw an Exception");
        BigDecimal expectedValue = getExpected(longString, multiplier);
        assertEquals(expectedValue, parsedValue, "With multiplier: " + multiplier);
    }

    // Utility to get a numerically correct value of a long string.
    // Dependent on BigDecimal implementation
    private static BigDecimal getExpected(String longString, int multiplier) {
        BigDecimal expected = new BigDecimal(longString);
        try {
            expected = expected.divide(new BigDecimal(multiplier));
        }
        catch (ArithmeticException e) {
            expected = expected.divide(new BigDecimal(multiplier), RoundingMode.HALF_EVEN);
        }
        return expected;
    }
}