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;
}
}
|