8317372: Refactor some NumberFormat tests to use JUnit
Reviewed-by: naoto
This commit is contained in:
parent
72c4dcbfee
commit
9622de2aa8
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -24,58 +24,85 @@
|
||||
/*
|
||||
* @test
|
||||
* @bug 4018937
|
||||
* @summary Confirm that DecimalFormat.parse() parses BigDecimal and BigInteger as expected.
|
||||
* @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.*;
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
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 {
|
||||
|
||||
static boolean err = false;
|
||||
private static DecimalFormat df = new DecimalFormat();
|
||||
// Save JVM default Locale
|
||||
private static final Locale savedLocale = Locale.getDefault();
|
||||
|
||||
static final String[] input_data = {
|
||||
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
|
||||
};
|
||||
static final String[] exponents = {
|
||||
"E-100", "E100", "E-900", "E900", ""
|
||||
};
|
||||
static final int[] multipliers = {
|
||||
-1, 1, -100, 100, -9999, 9999
|
||||
// ---- 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", ""
|
||||
};
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Locale loc = Locale.getDefault();
|
||||
// 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);
|
||||
|
||||
testBigDecimal();
|
||||
testBigInteger();
|
||||
|
||||
Locale.setDefault(loc);
|
||||
|
||||
if (err) {
|
||||
throw new RuntimeException("Error: Unexpected value");
|
||||
}
|
||||
buildTestData();
|
||||
}
|
||||
|
||||
static private void testBigDecimal() {
|
||||
DecimalFormat df = new DecimalFormat();
|
||||
df.setParseBigDecimal(true);
|
||||
df.setMaximumFractionDigits(Integer.MAX_VALUE);
|
||||
|
||||
for (int i = 0; i < input_data.length; i++) {
|
||||
for (int j = 0; j < input_data.length; j++) {
|
||||
for (int k = 0; k < input_data.length; k++) {
|
||||
for (int l = 0; l < input_data.length; l++) {
|
||||
for (int m = 0; m < exponents.length; m++) {
|
||||
String s = input_data[i] + input_data[j] + '.' +
|
||||
input_data[k] + input_data[l] +
|
||||
exponents[m];
|
||||
for (int n = 0; n < multipliers.length; n++) {
|
||||
test(df, s, multipliers[n]);
|
||||
test(df, '-'+s, multipliers[n]);
|
||||
/*
|
||||
* 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -84,51 +111,70 @@ public class BigDecimalCompatibilityTest {
|
||||
}
|
||||
}
|
||||
|
||||
static private void testBigInteger() {
|
||||
DecimalFormat df = new DecimalFormat();
|
||||
df.setParseBigDecimal(true);
|
||||
df.setMaximumFractionDigits(Integer.MAX_VALUE);
|
||||
|
||||
for (int i = 0; i < input_data.length; i++) {
|
||||
for (int j = 0; j < input_data.length; j++) {
|
||||
String s = input_data[i] + input_data[j];
|
||||
for (int k = 0; k < multipliers.length; k++) {
|
||||
test(df, s, multipliers[k]);
|
||||
test(df, '-'+s, multipliers[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Restore JVM default Locale
|
||||
@AfterAll
|
||||
static void tearDownAll() {
|
||||
Locale.setDefault(savedLocale);
|
||||
}
|
||||
|
||||
static void test(DecimalFormat df, String s, int multiplier) {
|
||||
// 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);
|
||||
|
||||
Number num = null;
|
||||
try {
|
||||
num = df.parse(s);
|
||||
}
|
||||
catch (ParseException e) {
|
||||
err = true;
|
||||
System.err.println("Failed: Exception occurred: " + e.getMessage());
|
||||
return;
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
|
||||
BigDecimal bd = new BigDecimal(s);
|
||||
// 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 {
|
||||
bd = bd.divide(new BigDecimal(multiplier));
|
||||
expected = expected.divide(new BigDecimal(multiplier));
|
||||
}
|
||||
catch (ArithmeticException e) {
|
||||
bd = bd.divide(new BigDecimal(multiplier), RoundingMode.HALF_EVEN);
|
||||
}
|
||||
check(num, bd, multiplier);
|
||||
}
|
||||
|
||||
static void check(Number got, BigDecimal expected, int multiplier) {
|
||||
if (!got.equals(expected)) {
|
||||
err = true;
|
||||
System.err.println("Failed: got:" + got +
|
||||
", expected: " + expected +
|
||||
", multiplier=" + multiplier);
|
||||
expected = expected.divide(new BigDecimal(multiplier), RoundingMode.HALF_EVEN);
|
||||
}
|
||||
return expected;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -23,105 +23,164 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @summary Confirm that the decimal separator is shown when explicitly requested.
|
||||
* @summary Confirm that the decimal separator is shown when explicitly requested
|
||||
* (or not shown if not requested). Tests against double, long, BigDecimal,
|
||||
* and BigInteger with a combination of different patterns.
|
||||
* @bug 4208135
|
||||
* @run junit Bug4208135
|
||||
*/
|
||||
|
||||
import java.math.*;
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.text.DecimalFormat;
|
||||
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;
|
||||
|
||||
public class Bug4208135 {
|
||||
|
||||
static DecimalFormat df;
|
||||
private static DecimalFormat df;
|
||||
// Save JVM default Locale
|
||||
private static final Locale savedLocale = Locale.getDefault();
|
||||
|
||||
static boolean err = false;
|
||||
|
||||
static public void main(String[] args){
|
||||
|
||||
Locale defaultLoc = Locale.getDefault();
|
||||
// Set JVM default locale to US
|
||||
@BeforeAll
|
||||
static void init() {
|
||||
Locale.setDefault(Locale.US);
|
||||
|
||||
df = new DecimalFormat();
|
||||
|
||||
df.applyPattern("0.#E0");
|
||||
|
||||
df.setDecimalSeparatorAlwaysShown(true);
|
||||
checkFormat(0.0, "0.E0");
|
||||
checkFormat(10.0, "1.E1");
|
||||
checkFormat(1000.0, "1.E3");
|
||||
checkFormat(0L, "0.E0");
|
||||
checkFormat(10L, "1.E1");
|
||||
checkFormat(1000L, "1.E3");
|
||||
checkFormat(new BigDecimal("0.0"), "0.E0");
|
||||
checkFormat(new BigDecimal("10.0"), "1.E1");
|
||||
checkFormat(new BigDecimal("1000.0"), "1.E3");
|
||||
checkFormat(new BigInteger("00"), "0.E0");
|
||||
checkFormat(new BigInteger("10"), "1.E1");
|
||||
checkFormat(new BigInteger("1000"), "1.E3");
|
||||
|
||||
df.setDecimalSeparatorAlwaysShown(false);
|
||||
checkFormat(0.0, "0E0");
|
||||
checkFormat(10.0, "1E1");
|
||||
checkFormat(1000.0, "1E3");
|
||||
checkFormat(0L, "0E0");
|
||||
checkFormat(10L, "1E1");
|
||||
checkFormat(1000L, "1E3");
|
||||
checkFormat(new BigDecimal("0.0"), "0E0");
|
||||
checkFormat(new BigDecimal("10.0"), "1E1");
|
||||
checkFormat(new BigDecimal("1000.0"), "1E3");
|
||||
checkFormat(new BigInteger("0"), "0E0");
|
||||
checkFormat(new BigInteger("10"), "1E1");
|
||||
checkFormat(new BigInteger("1000"), "1E3");
|
||||
|
||||
df.applyPattern("0.###");
|
||||
|
||||
df.setDecimalSeparatorAlwaysShown(true);
|
||||
checkFormat(0.0, "0.");
|
||||
checkFormat(10.0, "10.");
|
||||
checkFormat(1000.0, "1000.");
|
||||
checkFormat(0L, "0.");
|
||||
checkFormat(10L, "10.");
|
||||
checkFormat(1000L, "1000.");
|
||||
checkFormat(new BigDecimal("0.0"), "0.");
|
||||
checkFormat(new BigDecimal("10.0"), "10.");
|
||||
checkFormat(new BigDecimal("1000.0"), "1000.");
|
||||
checkFormat(new BigInteger("0"), "0.");
|
||||
checkFormat(new BigInteger("10"), "10.");
|
||||
checkFormat(new BigInteger("1000"), "1000.");
|
||||
|
||||
df.setDecimalSeparatorAlwaysShown(false);
|
||||
checkFormat(0.0, "0");
|
||||
checkFormat(10.0, "10");
|
||||
checkFormat(1000.0, "1000");
|
||||
checkFormat(0L, "0");
|
||||
checkFormat(10L, "10");
|
||||
checkFormat(1000L, "1000");
|
||||
checkFormat(new BigDecimal("0.0"), "0");
|
||||
checkFormat(new BigDecimal("10.0"), "10");
|
||||
checkFormat(new BigDecimal("1000.0"), "1000");
|
||||
checkFormat(new BigInteger("0"), "0");
|
||||
checkFormat(new BigInteger("10"), "10");
|
||||
checkFormat(new BigInteger("1000"), "1000");
|
||||
|
||||
Locale.setDefault(defaultLoc);
|
||||
|
||||
if (err) {
|
||||
throw new RuntimeException("Wrong format/parse with DecimalFormat");
|
||||
}
|
||||
}
|
||||
|
||||
static void checkFormat(Number num, String expected) {
|
||||
String got = df.format(num);
|
||||
if (!got.equals(expected)) {
|
||||
err = true;
|
||||
System.err.println(" DecimalFormat format(" +
|
||||
num.getClass().getName() +
|
||||
") error:" +
|
||||
"\n\tnumber: " + num +
|
||||
"\n\tSeparatorShown? : " + df.isDecimalSeparatorAlwaysShown() +
|
||||
"\n\tgot: " + got +
|
||||
"\n\texpected: " + expected);
|
||||
}
|
||||
// Restore JVM default locale
|
||||
@AfterAll
|
||||
static void tearDown() {
|
||||
Locale.setDefault(savedLocale);
|
||||
}
|
||||
|
||||
// Confirm that decimal separator shown when formatting a number
|
||||
@ParameterizedTest
|
||||
@MethodSource("fractionalDigitsWithSeparatorProvider")
|
||||
public void fractionalDigitsWithSeparatorTest(Number num, String expected) {
|
||||
df = getDF("0.#E0", true);
|
||||
String actualFormatted = df.format(num);
|
||||
assertEquals(expected, actualFormatted, getErrMsg("0.#E0", true));
|
||||
}
|
||||
|
||||
// Combination of numbers and a fractional exponent pattern with a separator
|
||||
private static Stream<Arguments> fractionalDigitsWithSeparatorProvider() {
|
||||
return Stream.of(
|
||||
Arguments.of(0.0, "0.E0"),
|
||||
Arguments.of(10.0, "1.E1"),
|
||||
Arguments.of(1000.0, "1.E3"),
|
||||
Arguments.of(0L, "0.E0"),
|
||||
Arguments.of(10L, "1.E1"),
|
||||
Arguments.of(1000L, "1.E3"),
|
||||
Arguments.of(new BigDecimal("0.0"), "0.E0"),
|
||||
Arguments.of(new BigDecimal("10.0"), "1.E1"),
|
||||
Arguments.of(new BigDecimal("1000.0"), "1.E3"),
|
||||
Arguments.of(new BigInteger("00"), "0.E0"),
|
||||
Arguments.of(new BigInteger("10"), "1.E1"),
|
||||
Arguments.of(new BigInteger("1000"), "1.E3")
|
||||
);
|
||||
}
|
||||
|
||||
// Confirm that decimal separator not shown when formatting a number
|
||||
@ParameterizedTest
|
||||
@MethodSource("fractionalDigitsNoSeparatorProvider")
|
||||
public void fractionalDigitsNoSeparatorTest(Number num, String expected) {
|
||||
df = getDF("0.#E0", false);
|
||||
String actualFormatted = df.format(num);
|
||||
assertEquals(expected, actualFormatted, getErrMsg("0.#E0", false));
|
||||
}
|
||||
|
||||
// Combination of numbers and a fractional exponent pattern with no separator
|
||||
private static Stream<Arguments> fractionalDigitsNoSeparatorProvider() {
|
||||
return Stream.of(
|
||||
Arguments.of(0.0, "0E0"),
|
||||
Arguments.of(10.0, "1E1"),
|
||||
Arguments.of(1000.0, "1E3"),
|
||||
Arguments.of(0L, "0E0"),
|
||||
Arguments.of(10L, "1E1"),
|
||||
Arguments.of(1000L, "1E3"),
|
||||
Arguments.of(new BigDecimal("0.0"), "0E0"),
|
||||
Arguments.of(new BigDecimal("10.0"), "1E1"),
|
||||
Arguments.of(new BigDecimal("1000.0"), "1E3"),
|
||||
Arguments.of(new BigInteger("00"), "0E0"),
|
||||
Arguments.of(new BigInteger("10"), "1E1"),
|
||||
Arguments.of(new BigInteger("1000"), "1E3")
|
||||
);
|
||||
}
|
||||
|
||||
// Confirm that decimal separator shown when formatting a number
|
||||
@ParameterizedTest
|
||||
@MethodSource("noFractionalDigitsWithSeparatorProvider")
|
||||
public void noFractionalDigitsWithSeparatorTest(Number num, String expected) {
|
||||
df = getDF("0.###", true);
|
||||
String actualFormatted = df.format(num);
|
||||
assertEquals(expected, actualFormatted, getErrMsg("0.###", true));
|
||||
}
|
||||
|
||||
// Combination of numbers and a non-fractional exponent pattern with a separator
|
||||
private static Stream<Arguments> noFractionalDigitsWithSeparatorProvider() {
|
||||
return Stream.of(
|
||||
Arguments.of(0.0, "0."),
|
||||
Arguments.of(10.0, "10."),
|
||||
Arguments.of(1000.0, "1000."),
|
||||
Arguments.of(0L, "0."),
|
||||
Arguments.of(10L, "10."),
|
||||
Arguments.of(1000L, "1000."),
|
||||
Arguments.of(new BigDecimal("0.0"), "0."),
|
||||
Arguments.of(new BigDecimal("10.0"), "10."),
|
||||
Arguments.of(new BigDecimal("1000.0"), "1000."),
|
||||
Arguments.of(new BigInteger("00"), "0."),
|
||||
Arguments.of(new BigInteger("10"), "10."),
|
||||
Arguments.of(new BigInteger("1000"), "1000.")
|
||||
);
|
||||
}
|
||||
|
||||
// Confirm that decimal separator not shown when formatting a number
|
||||
@ParameterizedTest
|
||||
@MethodSource("noFractionalDigitsNoSeparatorProvider")
|
||||
public void noFractionalDigitsNoSeparatorTest(Number num, String expected) {
|
||||
df = getDF("0.###", false);
|
||||
String actualFormatted = df.format(num);
|
||||
assertEquals(expected, actualFormatted, getErrMsg("0.###", false));
|
||||
}
|
||||
|
||||
// Combination of numbers and a non-fractional exponent pattern with no separator
|
||||
private static Stream<Arguments> noFractionalDigitsNoSeparatorProvider() {
|
||||
return Stream.of(
|
||||
Arguments.of(0.0, "0"),
|
||||
Arguments.of(10.0, "10"),
|
||||
Arguments.of(1000.0, "1000"),
|
||||
Arguments.of(0L, "0"),
|
||||
Arguments.of(10L, "10"),
|
||||
Arguments.of(1000L, "1000"),
|
||||
Arguments.of(new BigDecimal("0.0"), "0"),
|
||||
Arguments.of(new BigDecimal("10.0"), "10"),
|
||||
Arguments.of(new BigDecimal("1000.0"), "1000"),
|
||||
Arguments.of(new BigInteger("00"), "0"),
|
||||
Arguments.of(new BigInteger("10"), "10"),
|
||||
Arguments.of(new BigInteger("1000"), "1000")
|
||||
);
|
||||
}
|
||||
|
||||
// Creates clean DF and sets the pattern and separatorShown value
|
||||
private static DecimalFormat getDF(String pattern, boolean separatorShown) {
|
||||
df = new DecimalFormat();
|
||||
df.applyPattern(pattern);
|
||||
df.setDecimalSeparatorAlwaysShown(separatorShown);
|
||||
return df;
|
||||
}
|
||||
|
||||
// Utility to get a helpful error message when values are not as expected
|
||||
private static String getErrMsg(String pattern, boolean separatorShown) {
|
||||
return String.format("Fails with pattern= %s, with separatorShown = %s",
|
||||
pattern, separatorShown);
|
||||
}
|
||||
}
|
||||
|
@ -24,228 +24,259 @@
|
||||
/*
|
||||
* @test
|
||||
* @bug 4838107 8008577
|
||||
* @summary Confirm that DecimalFormat can format a number with negative exponent number correctly.
|
||||
* @summary Confirm that DecimalFormat can format a number with a negative
|
||||
* exponent number correctly. Tests also involve using a DecimalFormat
|
||||
* with a custom pattern or a custom minus sign.
|
||||
* @run junit/othervm -Djava.locale.providers=COMPAT,SPI Bug4838107
|
||||
*/
|
||||
|
||||
import java.math.*;
|
||||
import java.util.*;
|
||||
import java.text.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.util.Locale;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
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.fail;
|
||||
|
||||
/*
|
||||
* This bug is about exponential formatting. But I added test cases for:
|
||||
* - Double and BigDecimal numbers which don't have exponent parts.
|
||||
* - Long and BigInteger numbers which don't support exponential
|
||||
* notation.
|
||||
* because there are few test cases for suffix and prefix.
|
||||
* And also, I added test cases to guarantee further formatting and
|
||||
* parsing using the same DecimalFormat instance will not change the
|
||||
* Number's value anymore.
|
||||
*/
|
||||
public class Bug4838107 {
|
||||
|
||||
static DecimalFormat df;
|
||||
static DecimalFormatSymbols dfs;
|
||||
static boolean err = false;
|
||||
// Save JVM default Locale
|
||||
private static final Locale savedLocale = Locale.getDefault();
|
||||
|
||||
static public void main(String[] args) {
|
||||
Locale defaultLoc = Locale.getDefault();
|
||||
// Set JVM default Locale to US
|
||||
@BeforeAll
|
||||
static void init() {
|
||||
Locale.setDefault(Locale.US);
|
||||
|
||||
/**
|
||||
* This bug is about exponential formatting. But I added test cases for:
|
||||
* - Double and BigDecimal numbers which don't have exponent parts.
|
||||
* - Long and BigInteger numbers which don't support exponential
|
||||
* notation.
|
||||
* because there are few test cases for suffix and prefix.
|
||||
* And also, I added test cases to guarantee further formatting and
|
||||
* parsing using the same DecimalFormat instance will not change the
|
||||
* Number's value anymore.
|
||||
*/
|
||||
|
||||
test_double();
|
||||
test_long();
|
||||
test_BigDecimal();
|
||||
test_BigInteger();
|
||||
|
||||
Locale.setDefault(defaultLoc);
|
||||
|
||||
if (err) {
|
||||
throw new RuntimeException("Wrong format with DecimalFormat");
|
||||
}
|
||||
}
|
||||
|
||||
static void test_double() {
|
||||
df = new DecimalFormat();
|
||||
dfs = df.getDecimalFormatSymbols();
|
||||
|
||||
/* Test with default pattern */
|
||||
test(1234D, "1,234");
|
||||
test(0.1234, "0.123"); // rounded
|
||||
test(-1234D, "-1,234");
|
||||
test(-0.1234, "-0.123"); // rounded
|
||||
|
||||
test(Double.POSITIVE_INFINITY, "\u221e");
|
||||
test(Double.NEGATIVE_INFINITY, "-\u221e");
|
||||
test(Double.NaN, "\ufffd"); // without prefix and suffix
|
||||
test(0.0, "0");
|
||||
test(-0.0, "-0"); // with the minus sign
|
||||
|
||||
/* Specify a pattern and the minus sign. */
|
||||
prepareFormatter("<P>#.###E00<S>", 'm');
|
||||
test(1234D, "<P>1.234E03<S>");
|
||||
test(0.1234, "<P>1.234Em01<S>");
|
||||
test(-1234D, "m<P>1.234E03<S>");
|
||||
test(-0.1234, "m<P>1.234Em01<S>");
|
||||
|
||||
prepareFormatter("<P>#.###E00<S>;#.###E00", 'm');
|
||||
test(1234D, "<P>1.234E03<S>");
|
||||
test(0.1234, "<P>1.234Em01<S>");
|
||||
test(-1234D, "1.234E03");
|
||||
test(-0.1234, "1.234Em01");
|
||||
|
||||
prepareFormatter("#.###E00;<P>#.###E00<S>", 'm');
|
||||
test(1234D, "1.234E03");
|
||||
test(0.1234, "1.234Em01");
|
||||
test(-1234D, "<P>1.234E03<S>");
|
||||
test(-0.1234, "<P>1.234Em01<S>");
|
||||
|
||||
prepareFormatter("<P>#.###E00<S>;<p>-#.###E00<s>", 'm');
|
||||
test(1234D, "<P>1.234E03<S>");
|
||||
test(0.1234, "<P>1.234Em01<S>");
|
||||
test(-1234D, "<p>m1.234E03<s>");
|
||||
test(-0.1234, "<p>m1.234Em01<s>");
|
||||
|
||||
test(Double.POSITIVE_INFINITY, "<P>\u221e<S>");
|
||||
test(Double.NEGATIVE_INFINITY, "<p>m\u221e<s>");
|
||||
test(Double.NaN, "\ufffd"); // without prefix and suffix
|
||||
test(0.0, "<P>0E00<S>");
|
||||
test(-0.0, "<p>m0E00<s>"); // with the minus sign
|
||||
// Restore the original JVM default locale
|
||||
@AfterAll
|
||||
static void tearDown() {
|
||||
Locale.setDefault(savedLocale);
|
||||
}
|
||||
|
||||
static void test_BigDecimal() {
|
||||
df = new DecimalFormat();
|
||||
dfs = df.getDecimalFormatSymbols();
|
||||
|
||||
/* Test with default pattern */
|
||||
test(new BigDecimal("123456789012345678901234567890"),
|
||||
"123,456,789,012,345,678,901,234,567,890");
|
||||
test(new BigDecimal("0.000000000123456789012345678901234567890"),
|
||||
"0");
|
||||
test(new BigDecimal("-123456789012345678901234567890"),
|
||||
"-123,456,789,012,345,678,901,234,567,890");
|
||||
test(new BigDecimal("-0.000000000123456789012345678901234567890"),
|
||||
"-0");
|
||||
|
||||
test(new BigDecimal("0"), "0");
|
||||
test(new BigDecimal("-0"), "0");
|
||||
|
||||
/* Specify a pattern and the minus sign. */
|
||||
prepareFormatter("<P>#.####################E00<S>;<p>-#.####################E00<s>", 'm');
|
||||
test(new BigDecimal("123456789012345678901234567890"),
|
||||
"<P>1.23456789012345678901E29<S>");
|
||||
test(new BigDecimal("0.000000000123456789012345678901234567890"),
|
||||
"<P>1.23456789012345678901Em10<S>");
|
||||
test(new BigDecimal("-123456789012345678901234567890"),
|
||||
"<p>m1.23456789012345678901E29<s>");
|
||||
test(new BigDecimal("-0.000000000123456789012345678901234567890"),
|
||||
"<p>m1.23456789012345678901Em10<s>");
|
||||
|
||||
test(new BigDecimal("0"), "<P>0E00<S>");
|
||||
test(new BigDecimal("-0"), "<P>0E00<S>");
|
||||
// Check that negative exponent number recognized for doubles
|
||||
@ParameterizedTest
|
||||
@MethodSource("doubles")
|
||||
public void doubleTest(Number num, String str, DecimalFormat df) {
|
||||
test(num, str, df);
|
||||
}
|
||||
|
||||
static void test_long() {
|
||||
df = new DecimalFormat();
|
||||
dfs = df.getDecimalFormatSymbols();
|
||||
|
||||
/* Test with default pattern */
|
||||
test(123456789L, "123,456,789");
|
||||
test(-123456789L, "-123,456,789");
|
||||
|
||||
test(0L, "0");
|
||||
test(-0L, "0");
|
||||
|
||||
/* Specify a pattern and the minus sign. */
|
||||
prepareFormatter("<P>#,###<S>;<p>-#,###<s>", 'm');
|
||||
test(123456789L, "<P>123,456,789<S>");
|
||||
test(-123456789L, "<p>m123,456,789<s>");
|
||||
|
||||
test(0L, "<P>0<S>");
|
||||
test(-0L, "<P>0<S>");
|
||||
// Provides a double to be formatted, which is compared to the expected String.
|
||||
// Additionally, provides a DecimalFormat to do the formatting (can have a custom
|
||||
// pattern and minus sign). Given in the form (double, String, DecimalFormat).
|
||||
private static Stream<Arguments> doubles() {
|
||||
DecimalFormat defaultDf = new DecimalFormat();
|
||||
DecimalFormat customDf1 = getDecimalFormat("<P>#.###E00<S>", 'm');
|
||||
DecimalFormat customDf2 = getDecimalFormat("<P>#.###E00<S>;#.###E00", 'm');
|
||||
DecimalFormat customDf3 = getDecimalFormat("#.###E00;<P>#.###E00<S>", 'm');
|
||||
DecimalFormat customDf4 = getDecimalFormat("<P>#.###E00<S>;<p>-#.###E00<s>", 'm');
|
||||
return Stream.of(
|
||||
// Test with default pattern
|
||||
Arguments.of(1234D, "1,234", defaultDf),
|
||||
Arguments.of(0.1234, "0.123", defaultDf), // rounded
|
||||
Arguments.of(-1234D, "-1,234", defaultDf),
|
||||
Arguments.of(-0.1234, "-0.123", defaultDf), // rounded
|
||||
Arguments.of(Double.POSITIVE_INFINITY, "\u221e", defaultDf),
|
||||
Arguments.of(Double.NEGATIVE_INFINITY, "-\u221e", defaultDf),
|
||||
Arguments.of(Double.NaN, "\ufffd", defaultDf), // without prefix and suffix
|
||||
Arguments.of(0.0, "0", defaultDf),
|
||||
Arguments.of(-0.0, "-0", defaultDf), // with the minus sign
|
||||
// Test with a pattern and the minus sign
|
||||
Arguments.of(1234D, "<P>1.234E03<S>", customDf1),
|
||||
Arguments.of(0.1234, "<P>1.234Em01<S>", customDf1),
|
||||
Arguments.of(-1234D, "m<P>1.234E03<S>", customDf1),
|
||||
Arguments.of(-0.1234, "m<P>1.234Em01<S>", customDf1),
|
||||
Arguments.of(1234D, "<P>1.234E03<S>", customDf2),
|
||||
Arguments.of(0.1234, "<P>1.234Em01<S>", customDf2),
|
||||
Arguments.of(-1234D, "1.234E03", customDf2),
|
||||
Arguments.of(-0.1234, "1.234Em01", customDf2),
|
||||
Arguments.of(1234D, "1.234E03", customDf3),
|
||||
Arguments.of(0.1234, "1.234Em01", customDf3),
|
||||
Arguments.of(-1234D, "<P>1.234E03<S>", customDf3),
|
||||
Arguments.of(-0.1234, "<P>1.234Em01<S>", customDf3),
|
||||
Arguments.of(1234D, "<P>1.234E03<S>", customDf4),
|
||||
Arguments.of(0.1234, "<P>1.234Em01<S>", customDf4),
|
||||
Arguments.of(-1234D, "<p>m1.234E03<s>", customDf4),
|
||||
Arguments.of(-0.1234, "<p>m1.234Em01<s>", customDf4),
|
||||
Arguments.of(Double.POSITIVE_INFINITY, "<P>\u221e<S>", customDf4),
|
||||
Arguments.of(Double.NEGATIVE_INFINITY, "<p>m\u221e<s>", customDf4),
|
||||
Arguments.of(Double.NaN, "\ufffd", customDf4), // without prefix and suffix
|
||||
Arguments.of(0.0, "<P>0E00<S>", customDf4),
|
||||
Arguments.of(-0.0, "<p>m0E00<s>", customDf4) // with the minus sign
|
||||
);
|
||||
}
|
||||
|
||||
static void test_BigInteger() {
|
||||
df = new DecimalFormat();
|
||||
dfs = df.getDecimalFormatSymbols();
|
||||
|
||||
/* Test with default pattern */
|
||||
test(new BigInteger("123456789012345678901234567890"),
|
||||
"123,456,789,012,345,678,901,234,567,890");
|
||||
test(new BigInteger("-123456789012345678901234567890"),
|
||||
"-123,456,789,012,345,678,901,234,567,890");
|
||||
|
||||
test(new BigInteger("0"), "0");
|
||||
test(new BigInteger("-0"), "0");
|
||||
|
||||
/* Specify a pattern and the minus sign. */
|
||||
prepareFormatter("<P>#,###<S>;<p>-#,###<s>", 'm');
|
||||
test(new BigInteger("123456789012345678901234567890"),
|
||||
"<P>123,456,789,012,345,678,901,234,567,890<S>");
|
||||
test(new BigInteger("-123456789012345678901234567890"),
|
||||
"<p>m123,456,789,012,345,678,901,234,567,890<s>");
|
||||
|
||||
test(new BigInteger("0"), "<P>0<S>");
|
||||
test(new BigInteger("-0"), "<P>0<S>");
|
||||
// Check that negative exponent number recognized for longs
|
||||
@ParameterizedTest
|
||||
@MethodSource("longs")
|
||||
public void longTest(Number num, String str, DecimalFormat df) {
|
||||
test(num, str, df);
|
||||
}
|
||||
|
||||
static void prepareFormatter(String pattern, char minusSign) {
|
||||
dfs = df.getDecimalFormatSymbols();
|
||||
df.applyPattern(pattern);
|
||||
dfs.setMinusSign(minusSign);
|
||||
df.setDecimalFormatSymbols(dfs);
|
||||
// Same as doubles() data provider, but with long values
|
||||
// Given in the form (long, String, DecimalFormat).
|
||||
private static Stream<Arguments> longs() {
|
||||
DecimalFormat defaultDf = new DecimalFormat();
|
||||
DecimalFormat customDf = getDecimalFormat(
|
||||
"<P>#,###<S>;<p>-#,###<s>", 'm');
|
||||
return Stream.of(
|
||||
// Test with default pattern
|
||||
Arguments.of(123456789L, "123,456,789", defaultDf),
|
||||
Arguments.of(-123456789L, "-123,456,789", defaultDf),
|
||||
Arguments.of(0L, "0", defaultDf),
|
||||
Arguments.of(-0L, "0", defaultDf),
|
||||
// Test with a pattern and the minus sign
|
||||
Arguments.of(123456789L, "<P>123,456,789<S>", customDf),
|
||||
Arguments.of(-123456789L, "<p>m123,456,789<s>", customDf),
|
||||
Arguments.of(0L, "<P>0<S>", customDf),
|
||||
Arguments.of(-0L, "<P>0<S>", customDf)
|
||||
);
|
||||
}
|
||||
|
||||
static void test(Number num, String str) {
|
||||
// Check that negative exponent number recognized for bigDecimals
|
||||
@ParameterizedTest
|
||||
@MethodSource("bigDecimals")
|
||||
public void bigDecimalTest(Number num, String str, DecimalFormat df) {
|
||||
test(num, str, df);
|
||||
}
|
||||
|
||||
// Same as doubles() data provider, but with BigDecimal values
|
||||
// Given in the form (BigDecimal, String, DecimalFormat).
|
||||
private static Stream<Arguments> bigDecimals() {
|
||||
DecimalFormat defaultDf = new DecimalFormat();
|
||||
DecimalFormat customDf = getDecimalFormat(
|
||||
"<P>#.####################E00<S>;<p>-#.####################E00<s>", 'm');
|
||||
return Stream.of(
|
||||
// Test with default pattern
|
||||
Arguments.of(new BigDecimal("123456789012345678901234567890"),
|
||||
"123,456,789,012,345,678,901,234,567,890", defaultDf),
|
||||
Arguments.of(new BigDecimal("0.000000000123456789012345678901234567890"),
|
||||
"0", defaultDf),
|
||||
Arguments.of(new BigDecimal("-123456789012345678901234567890"),
|
||||
"-123,456,789,012,345,678,901,234,567,890", defaultDf),
|
||||
Arguments.of(new BigDecimal("-0.000000000123456789012345678901234567890"),
|
||||
"-0", defaultDf),
|
||||
Arguments.of(new BigDecimal("0"), "0", defaultDf),
|
||||
Arguments.of(new BigDecimal("-0"), "0", defaultDf),
|
||||
// Test with a pattern and the minus sign
|
||||
Arguments.of(new BigDecimal("123456789012345678901234567890"),
|
||||
"<P>1.23456789012345678901E29<S>", customDf),
|
||||
Arguments.of(new BigDecimal("0.000000000123456789012345678901234567890"),
|
||||
"<P>1.23456789012345678901Em10<S>", customDf),
|
||||
Arguments.of(new BigDecimal("-123456789012345678901234567890"),
|
||||
"<p>m1.23456789012345678901E29<s>", customDf),
|
||||
Arguments.of(new BigDecimal("-0.000000000123456789012345678901234567890"),
|
||||
"<p>m1.23456789012345678901Em10<s>", customDf),
|
||||
Arguments.of(new BigDecimal("0"), "<P>0E00<S>", customDf),
|
||||
Arguments.of(new BigDecimal("-0"), "<P>0E00<S>", customDf)
|
||||
);
|
||||
}
|
||||
|
||||
// Check that negative exponent number recognized for bigIntegers
|
||||
@ParameterizedTest
|
||||
@MethodSource("bigIntegers")
|
||||
public void bigIntegerTest(Number num, String str, DecimalFormat df) {
|
||||
test(num, str, df);
|
||||
}
|
||||
|
||||
// Same as doubles() data provider, but with BigInteger values
|
||||
// Given in the form (BigInteger, String, DecimalFormat).
|
||||
private static Stream<Arguments> bigIntegers() {
|
||||
DecimalFormat defaultDf = new DecimalFormat();
|
||||
DecimalFormat customDf = getDecimalFormat(
|
||||
"<P>#,###<S>;<p>-#,###<s>", 'm');
|
||||
return Stream.of(
|
||||
// Test with default pattern
|
||||
Arguments.of(new BigInteger("123456789012345678901234567890"),
|
||||
"123,456,789,012,345,678,901,234,567,890", defaultDf),
|
||||
Arguments.of(new BigInteger("-123456789012345678901234567890"),
|
||||
"-123,456,789,012,345,678,901,234,567,890", defaultDf),
|
||||
Arguments.of(new BigInteger("0"), "0", defaultDf),
|
||||
Arguments.of(new BigInteger("-0"), "0", defaultDf),
|
||||
// Test with a pattern and the minus sign
|
||||
Arguments.of(new BigInteger("123456789012345678901234567890"),
|
||||
"<P>123,456,789,012,345,678,901,234,567,890<S>", customDf),
|
||||
Arguments.of(new BigInteger("-123456789012345678901234567890"),
|
||||
"<p>m123,456,789,012,345,678,901,234,567,890<s>", customDf),
|
||||
Arguments.of(new BigInteger("0"), "<P>0<S>", customDf),
|
||||
Arguments.of(new BigInteger("-0"), "<P>0<S>", customDf)
|
||||
);
|
||||
}
|
||||
|
||||
// Check that the formatted value is correct and also check that
|
||||
// it can be round-tripped via parse() and format()
|
||||
private static void test(Number num, String str, DecimalFormat df) {
|
||||
String formatted = df.format(num);
|
||||
if (!formatted.equals(str)) {
|
||||
err = true;
|
||||
System.err.println(" DecimalFormat format(" +
|
||||
num.getClass().getName() +
|
||||
") error: \n\tnumber: " + num +
|
||||
"\n\tminus sign: " + dfs.getMinusSign() +
|
||||
"\n\tgot: " + formatted +
|
||||
"\n\texpected: " + str);
|
||||
return;
|
||||
}
|
||||
assertEquals(str, formatted, String.format("DecimalFormat format(%s) " +
|
||||
"Error: number: %s, minus sign: %s", num.getClass().getName(), num, df.getDecimalFormatSymbols().getMinusSign()));
|
||||
|
||||
if (num instanceof BigDecimal || num instanceof BigInteger) {
|
||||
df.setParseBigDecimal(true);
|
||||
}
|
||||
testRoundTrip(formatted, str, num, df);
|
||||
}
|
||||
|
||||
// Test that a parsed value can be round-tripped via format() and parse()
|
||||
private static void testRoundTrip(String formatted, String str,
|
||||
Number num, DecimalFormat df) {
|
||||
Number parsed1 = null, parsed2 = null;
|
||||
try {
|
||||
parsed1 = df.parse(formatted);
|
||||
formatted = df.format(parsed1);
|
||||
parsed2 = df.parse(formatted);
|
||||
if (!parsed1.equals(parsed2)) {
|
||||
err = true;
|
||||
System.err.println(" DecimalFormat roundtrip parse(" +
|
||||
num.getClass().getName() +
|
||||
") error: \n\toriginal number: " + str +
|
||||
"\n\tparsed number: " + parsed1 +
|
||||
" (" + parsed1.getClass().getName() + ")" +
|
||||
"\n\tformatted number: " + formatted +
|
||||
"\n\tre-parsed number: " + parsed2 +
|
||||
" (" + parsed2.getClass().getName() + ")" +
|
||||
"\n\tminus sign: " + dfs.getMinusSign());
|
||||
}
|
||||
assertEquals(parsed2, parsed1, """
|
||||
DecimalFormat round trip parse(%s) error:
|
||||
original number: %s
|
||||
parsed number: %s
|
||||
(%s)
|
||||
formatted number: %s
|
||||
re-parsed number: %s
|
||||
(%s)
|
||||
minus sign: %s
|
||||
""".formatted(num.getClass().getName(), str, parsed1, parsed1.getClass().getName(),
|
||||
formatted, parsed2, parsed2.getClass().getName(), df.getDecimalFormatSymbols().getMinusSign()));
|
||||
}
|
||||
catch (Exception e) {
|
||||
err = true;
|
||||
System.err.println(" DecimalFormat parse(" +
|
||||
num.getClass().getName() +
|
||||
") threw an Exception: " + e.getMessage() +
|
||||
"\n\toriginal number: " + str +
|
||||
"\n\tparsed number : " + parsed1 +
|
||||
" (" + parsed1.getClass().getName() + ")" +
|
||||
"\n\tformatted number: " + formatted +
|
||||
"\n\tre-parsed number: " + parsed2 +
|
||||
" (" + parsed2.getClass().getName() + ")" +
|
||||
"\n\tminus sign: " + dfs.getMinusSign());
|
||||
fail("""
|
||||
DecimalFormat parse(%s) threw an Exception: %s
|
||||
original number: %s
|
||||
parsed number: %s
|
||||
(%s)
|
||||
formatted number: %s
|
||||
re-parsed number: %s
|
||||
(%s)
|
||||
minus sign: %s
|
||||
""".formatted(num.getClass().getName(), e.getMessage(), str, parsed1, parsed1.getClass().getName(),
|
||||
formatted, parsed2, parsed2.getClass().getName(), df.getDecimalFormatSymbols().getMinusSign()));
|
||||
}
|
||||
}
|
||||
|
||||
// Set up custom DecimalFormat with DecimalFormatSymbols
|
||||
private static DecimalFormat getDecimalFormat(String pattern, char minusSign) {
|
||||
DecimalFormat df = new DecimalFormat();
|
||||
DecimalFormatSymbols dfs = df.getDecimalFormatSymbols();
|
||||
df.applyPattern(pattern);
|
||||
dfs.setMinusSign(minusSign);
|
||||
df.setDecimalFormatSymbols(dfs);
|
||||
return df;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -25,87 +25,97 @@
|
||||
* @test
|
||||
* @bug 4944439
|
||||
* @summary Confirm that numbers where all digits after the decimal separator are 0
|
||||
* and which are between Long.MIN_VALUE and Long.MAX_VALUE are returned as Long(not double).
|
||||
* and which are between Long.MIN_VALUE and Long.MAX_VALUE are returned
|
||||
* as Long(not double).
|
||||
* @run junit Bug4944439
|
||||
*/
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
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.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||
|
||||
public class Bug4944439 {
|
||||
|
||||
static boolean err = false;
|
||||
static DecimalFormat df;
|
||||
// Save JVM default locale
|
||||
private static final Locale savedLocale = Locale.getDefault();
|
||||
private static final DecimalFormat df = new DecimalFormat();
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
Locale defaultLoc = Locale.getDefault();
|
||||
// Set JVM default locale to US for testing
|
||||
@BeforeAll
|
||||
static void initAll() {
|
||||
Locale.setDefault(Locale.US);
|
||||
|
||||
df = new DecimalFormat();
|
||||
String s = "-9223372036854775809"; // Long.MIN_VALUE-1
|
||||
check_Double(s);
|
||||
|
||||
test(Long.MIN_VALUE, Long.MIN_VALUE+10);
|
||||
test(-10, 10);
|
||||
test(Long.MAX_VALUE-10, Long.MAX_VALUE-1);
|
||||
|
||||
s = "9223372036854775807.00"; // Long.MAX_VALUE
|
||||
check_Long(s);
|
||||
s = "9223372036854775808"; // Long.MAX_VALUE+1
|
||||
check_Double(s);
|
||||
|
||||
s = "-0.0";
|
||||
check_Double(s);
|
||||
s = "0.0";
|
||||
check_Long(s);
|
||||
|
||||
Locale.setDefault(defaultLoc);
|
||||
|
||||
if (err) {
|
||||
throw new RuntimeException("Wrong parsing with DecimalFormat");
|
||||
}
|
||||
}
|
||||
|
||||
private static void test(long from, long to) throws Exception {
|
||||
// Restore JVM default locale
|
||||
@AfterAll
|
||||
static void tearDownAll() {
|
||||
Locale.setDefault(savedLocale);
|
||||
}
|
||||
|
||||
// Check return type and value returned by DecimalFormat.parse() for longs
|
||||
@ParameterizedTest
|
||||
@MethodSource("longs")
|
||||
public void parseLongTest(String s) {
|
||||
// This was originally intended to ensure a ParseException is not thrown
|
||||
Number parsedNumber = assertDoesNotThrow(() -> df.parse(s),
|
||||
"DecimalFormat.parse(\"%s\") should not throw an Exception");
|
||||
assertInstanceOf(Long.class, parsedNumber,
|
||||
"DecimalFormat.parse(\"%s\") did not return Long");
|
||||
// Grab integer portion of value
|
||||
Long expectedVal = Long.valueOf(s.substring(0, s.indexOf('.')));
|
||||
assertEquals(parsedNumber, expectedVal,
|
||||
"DecimalFormat.parse(\"%s\") returned numerically incorrect value");
|
||||
}
|
||||
|
||||
// Test some values between Long.MIN_VALUE and Long.MAX_VALUE
|
||||
private static Stream<String> longs() {
|
||||
ArrayList<String> longs = new ArrayList<>();
|
||||
addLongData(Long.MIN_VALUE, Long.MIN_VALUE+10, longs);
|
||||
addLongData(-10, 10, longs);
|
||||
addLongData(Long.MAX_VALUE-10, Long.MAX_VALUE-1, longs);
|
||||
longs.add("9223372036854775807.00");
|
||||
longs.add("0.0");
|
||||
return longs.stream();
|
||||
}
|
||||
|
||||
// Utility to add values between parameters(long, to) to testLongs ArrayList
|
||||
private static void addLongData(long from, long to, ArrayList<String> testLongs){
|
||||
for (long l = from; l <= to; l++) {
|
||||
check_Long(Long.toString(l) + ".00");
|
||||
testLongs.add(l + ".00");
|
||||
}
|
||||
}
|
||||
|
||||
private static void check_Long(String s) throws Exception {
|
||||
Number number = df.parse(s);
|
||||
if (!(number instanceof Long)) {
|
||||
err = true;
|
||||
System.err.println("Failed: DecimalFormat.parse(\"" + s +
|
||||
"\") should return a Long, but returned a " +
|
||||
number.getClass().getName());
|
||||
}
|
||||
|
||||
int index = s.indexOf('.');
|
||||
Long l = Long.valueOf(s.substring(0, index));
|
||||
if (!l.equals(number)) {
|
||||
err = true;
|
||||
System.err.println("Failed: DecimalFormat.parse(" + s +
|
||||
") should return a Long(" + l + "), but returned " + number);
|
||||
}
|
||||
// Check return type and value returned by DecimalFormat.parse() for doubles
|
||||
@ParameterizedTest
|
||||
@MethodSource("doubles")
|
||||
public void parseDoubleTest(String s) {
|
||||
// This was originally intended to ensure a ParseException is not thrown
|
||||
Number parsedNumber = assertDoesNotThrow(() -> df.parse(s),
|
||||
"DecimalFormat.parse(\"%s\") should not throw an Exception");
|
||||
assertInstanceOf(Double.class, parsedNumber,
|
||||
"DecimalFormat.parse(\"%s\") did not return Double");
|
||||
Double expectedVal = Double.valueOf(s);
|
||||
assertEquals(parsedNumber, expectedVal,
|
||||
"DecimalFormat.parse(\"%s\") returned numerically incorrect value");
|
||||
}
|
||||
|
||||
private static void check_Double(String s) throws Exception {
|
||||
Number number = df.parse(s);
|
||||
if (!(number instanceof Double)) {
|
||||
err = true;
|
||||
System.err.println("Failed: DecimalFormat.parse(\"" + s +
|
||||
"\") should return a Double, but returned a " +
|
||||
number.getClass().getName());
|
||||
}
|
||||
|
||||
Double d = Double.valueOf(s);
|
||||
if (!d.equals(number)) {
|
||||
err = true;
|
||||
System.err.println("Failed: DecimalFormat.parse(" + s +
|
||||
") should return a Double(" + d + "), but returned " + number);
|
||||
}
|
||||
// Check values not between Long.MIN_VALUE and Long.MAX_VALUE
|
||||
private static Stream<String> doubles() {
|
||||
return Stream.of(
|
||||
"-9223372036854775809", // Long.MIN_VALUE-1
|
||||
"9223372036854775808", // Long.MAX_VALUE+1
|
||||
"-0.0"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2004, 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
|
||||
@ -21,20 +21,32 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
/*
|
||||
* @test
|
||||
* @bug 4990596
|
||||
* @summary Make sure that any subclass of Number can be formatted using DecimalFormat.format().
|
||||
* @summary Make sure that any subclass of Number can be formatted using
|
||||
* DecimalFormat.format() without throwing an exception.
|
||||
* @run junit Bug4990596
|
||||
*/
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
|
||||
public class Bug4990596 {
|
||||
|
||||
public static void main(String[] args) {
|
||||
new DecimalFormat().format(new MutableInteger(0));
|
||||
// Test that a custom subclass of Number can be formatted by
|
||||
// DecimalFormat without throwing an IllegalArgumentException
|
||||
@Test
|
||||
public void formatSubclassedNumberTest() {
|
||||
assertDoesNotThrow(() -> new DecimalFormat().format(new MutableInteger(0)),
|
||||
"DecimalFormat.format() should support subclasses of Number");
|
||||
}
|
||||
|
||||
// A custom subclass of Number. Prior to this fix, if an instance of this
|
||||
// class was formatted by DecimalFormat, an exception would be thrown.
|
||||
@SuppressWarnings("serial")
|
||||
public static class MutableInteger extends Number {
|
||||
public int value;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 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
|
||||
@ -24,46 +24,55 @@
|
||||
/*
|
||||
* @test
|
||||
* @summary Confirm that AtomicInteger and AtomicLong are formatted correctly.
|
||||
* That is, make sure they are not treated as a double when formatted
|
||||
* anymore (which can result in the loss of precision).
|
||||
* @bug 6278616
|
||||
* @run junit Bug6278616
|
||||
*/
|
||||
|
||||
import java.text.NumberFormat;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import java.util.Locale;
|
||||
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;
|
||||
|
||||
public class Bug6278616 {
|
||||
|
||||
static final int[] ints = {
|
||||
Integer.MIN_VALUE, -1, 0, 1, Integer.MAX_VALUE
|
||||
};
|
||||
private static final NumberFormat nf = NumberFormat.getInstance();
|
||||
|
||||
static final long[] longs = {
|
||||
Long.MIN_VALUE, -1, 0, 1, Long.MAX_VALUE
|
||||
};
|
||||
// Test that NumberFormat formats numerically equivalent int
|
||||
// and AtomicInteger values the same
|
||||
@ParameterizedTest
|
||||
@MethodSource("ints")
|
||||
public void formattedAtomicIntTest(int testInt) {
|
||||
String formattedInt = nf.format(testInt);
|
||||
String formattedAtomicInt = nf.format(new AtomicInteger(testInt));
|
||||
assertEquals(formattedAtomicInt, formattedInt, "Formatting numerically" +
|
||||
" equivalent AtomicInteger and int should produce the same String value");
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
NumberFormat nf = NumberFormat.getInstance();
|
||||
// Various int values
|
||||
private static int[] ints() {
|
||||
return new int[] { Integer.MIN_VALUE, -1, 0, 1, Integer.MAX_VALUE};
|
||||
}
|
||||
|
||||
for (int j = 0; j < ints.length; j++) {
|
||||
String s_i = nf.format(ints[j]);
|
||||
String s_ai = nf.format(new AtomicInteger(ints[j]));
|
||||
if (!s_i.equals(s_ai)) {
|
||||
throw new RuntimeException("format(AtomicInteger " + s_ai +
|
||||
") doesn't equal format(Integer " +
|
||||
s_i + ")");
|
||||
}
|
||||
}
|
||||
// Test that NumberFormat formats numerically equivalent long
|
||||
// and AtomicLong values the same
|
||||
@ParameterizedTest
|
||||
@MethodSource("longs")
|
||||
public void formattedAtomicLongTest(long testLong) {
|
||||
String formattedLong = nf.format(testLong);
|
||||
String formattedAtomicLong = nf.format(new AtomicLong(testLong));
|
||||
assertEquals(formattedAtomicLong, formattedLong, "Formatting numerically" +
|
||||
" equivalent AtomicLong and long should produce the same String value");
|
||||
}
|
||||
|
||||
for (int j = 0; j < longs.length; j++) {
|
||||
String s_l = nf.format(longs[j]);
|
||||
String s_al = nf.format(new AtomicLong(longs[j]));
|
||||
if (!s_l.equals(s_al)) {
|
||||
throw new RuntimeException("format(AtomicLong " + s_al +
|
||||
") doesn't equal format(Long " +
|
||||
s_l + ")");
|
||||
}
|
||||
}
|
||||
// Various long values
|
||||
private static long[] longs() {
|
||||
return new long[] { Long.MIN_VALUE, -1, 0, 1, Long.MAX_VALUE};
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 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
|
||||
@ -26,20 +26,27 @@
|
||||
* @bug 8132125 8202537
|
||||
* @summary Checks Swiss' number elements
|
||||
* @modules jdk.localedata
|
||||
* @run junit Bug8132125
|
||||
*/
|
||||
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class Bug8132125 {
|
||||
public static void main(String[] args) {
|
||||
|
||||
// Ensure the CLDRConverter does not omit the Swiss number elements
|
||||
@Test
|
||||
public void swissNumElementsTest() {
|
||||
Locale deCH = Locale.of("de", "CH");
|
||||
NumberFormat nf = NumberFormat.getInstance(deCH);
|
||||
|
||||
String expected = "54\u2019839\u2019483.142"; // i.e. "\u2019" as decimal separator, "\u2019" as grouping separator
|
||||
// "\u002E" as decimal separator, "\u2019" as grouping separator
|
||||
String expected = "54\u2019839\u2019483.142";
|
||||
String actual = nf.format(54839483.1415);
|
||||
if (!actual.equals(expected)) {
|
||||
throw new RuntimeException("incorrect for de_CH: " + expected + " vs. actual " + actual);
|
||||
}
|
||||
assertEquals(expected, actual, "incorrect number elements for de_CH");
|
||||
}
|
||||
}
|
||||
|
@ -25,15 +25,19 @@
|
||||
* @test
|
||||
* @bug 4290801 4942982 5102005 8008577 8021121 8210153 8227313 8301991
|
||||
* @summary Basic tests for currency formatting.
|
||||
* Tests both COMPAT and CLDR data.
|
||||
* @modules jdk.localedata
|
||||
* @run main/othervm -Djava.locale.providers=COMPAT CurrencyFormat COMPAT
|
||||
* @run main/othervm -Djava.locale.providers=CLDR CurrencyFormat CLDR
|
||||
* @run junit/othervm -Djava.locale.providers=COMPAT CurrencyFormat
|
||||
* @run junit/othervm -Djava.locale.providers=CLDR CurrencyFormat
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Currency;
|
||||
import java.util.Locale;
|
||||
import java.util.Properties;
|
||||
@ -42,127 +46,140 @@ import java.util.TimeZone;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.text.NumberFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
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;
|
||||
|
||||
public class CurrencyFormat {
|
||||
|
||||
private static boolean isCompat;
|
||||
// Expected data is switched depending on COMPAT or CLDR
|
||||
// currencySymbolsTest() is only ran for COMPAT
|
||||
private static final boolean isCompat =
|
||||
"COMPAT".equals(System.getProperty("java.locale.providers"));
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
isCompat = "COMPAT".equals(args[0]);
|
||||
testFormatting();
|
||||
testSymbols();
|
||||
// Tests the formatting of data for COMPAT + CLDR under various currencies
|
||||
// Using a NumberFormat generated by getCurrencyInstance()
|
||||
@ParameterizedTest
|
||||
@MethodSource("currencyFormatDataProvider")
|
||||
public void currencyFormatTest(String expected, Currency currency,
|
||||
NumberFormat format, Locale locale) {
|
||||
if (currency != null) {
|
||||
format.setCurrency(currency);
|
||||
int digits = currency.getDefaultFractionDigits();
|
||||
format.setMinimumFractionDigits(digits);
|
||||
format.setMaximumFractionDigits(digits);
|
||||
}
|
||||
String result = format.format(1234.56);
|
||||
assertEquals(expected, result, String.format("Failed with locale: %s%s",
|
||||
locale, (currency == null ? ", default currency" : (", currency: " + currency))));
|
||||
}
|
||||
|
||||
static void testFormatting() {
|
||||
boolean failed = false;
|
||||
// Generate a combination of expected data for 1234.56 formatted
|
||||
// under various currencies/locale provider/locale
|
||||
private static Stream<Arguments> currencyFormatDataProvider() {
|
||||
ArrayList<Arguments> data = new ArrayList<Arguments>();
|
||||
Locale[] locales = {
|
||||
Locale.US,
|
||||
Locale.JAPAN,
|
||||
Locale.GERMANY,
|
||||
Locale.ITALY,
|
||||
Locale.of("it", "IT", "EURO"),
|
||||
Locale.forLanguageTag("de-AT"),
|
||||
Locale.forLanguageTag("fr-CH"),
|
||||
Locale.US,
|
||||
Locale.JAPAN,
|
||||
Locale.GERMANY,
|
||||
Locale.ITALY,
|
||||
Locale.of("it", "IT", "EURO"),
|
||||
Locale.forLanguageTag("de-AT"),
|
||||
Locale.forLanguageTag("fr-CH"),
|
||||
};
|
||||
Currency[] currencies = {
|
||||
null,
|
||||
Currency.getInstance("USD"),
|
||||
Currency.getInstance("JPY"),
|
||||
Currency.getInstance("DEM"),
|
||||
Currency.getInstance("EUR"),
|
||||
null,
|
||||
Currency.getInstance("USD"),
|
||||
Currency.getInstance("JPY"),
|
||||
Currency.getInstance("DEM"),
|
||||
Currency.getInstance("EUR"),
|
||||
};
|
||||
String[][] expecteds = {
|
||||
{"$1,234.56", "$1,234.56", "JPY1,235", "DEM1,234.56", "EUR1,234.56"},
|
||||
{"\uFFE51,235", "USD1,234.56", "\uFFE51,235", "DEM1,234.56", "EUR1,234.56"},
|
||||
{"1.234,56 \u20AC", "1.234,56 USD", "1.235 JPY", "1.234,56 DM", "1.234,56 \u20AC"},
|
||||
{"\u20AC 1.234,56", "USD 1.234,56", "JPY 1.235", "DEM 1.234,56", "\u20AC 1.234,56"},
|
||||
{"\u20AC 1.234,56", "USD 1.234,56", "JPY 1.235", "DEM 1.234,56", "\u20AC 1.234,56"},
|
||||
{"\u20AC 1.234,56", "USD 1.234,56", "JPY 1.235", "DEM 1.234,56", "\u20AC 1.234,56"},
|
||||
{"SFr. 1'234.56", "USD 1'234.56", "JPY 1'235", "DEM 1'234.56", "EUR 1'234.56"},
|
||||
String[][] expectedCOMPATData = {
|
||||
{"$1,234.56", "$1,234.56", "JPY1,235", "DEM1,234.56", "EUR1,234.56"},
|
||||
{"\uFFE51,235", "USD1,234.56", "\uFFE51,235", "DEM1,234.56", "EUR1,234.56"},
|
||||
{"1.234,56 \u20AC", "1.234,56 USD", "1.235 JPY", "1.234,56 DM", "1.234,56 \u20AC"},
|
||||
{"\u20AC 1.234,56", "USD 1.234,56", "JPY 1.235", "DEM 1.234,56", "\u20AC 1.234,56"},
|
||||
{"\u20AC 1.234,56", "USD 1.234,56", "JPY 1.235", "DEM 1.234,56", "\u20AC 1.234,56"},
|
||||
{"\u20AC 1.234,56", "USD 1.234,56", "JPY 1.235", "DEM 1.234,56", "\u20AC 1.234,56"},
|
||||
{"SFr. 1'234.56", "USD 1'234.56", "JPY 1'235", "DEM 1'234.56", "EUR 1'234.56"},
|
||||
};
|
||||
String[][] expecteds_cldr = {
|
||||
{"$1,234.56", "$1,234.56", "\u00a51,235", "DEM1,234.56", "\u20ac1,234.56"},
|
||||
{"\uFFE51,235", "$1,234.56", "\uFFE51,235", "DEM1,234.56", "\u20ac1,234.56"},
|
||||
{"1.234,56\u00a0\u20ac", "1.234,56\u00a0$", "1.235\u00a0\u00a5", "1.234,56\u00a0DM", "1.234,56\u00a0\u20ac"},
|
||||
{"1.234,56\u00a0\u20ac", "1.234,56\u00a0USD", "1.235\u00a0JPY", "1.234,56\u00a0DEM", "1.234,56\u00a0\u20ac"},
|
||||
{"1.234,56\u00a0\u20ac", "1.234,56\u00a0USD", "1.235\u00a0JPY", "1.234,56\u00a0DEM", "1.234,56\u00a0\u20ac"},
|
||||
{"\u20ac\u00a01.234,56", "$\u00a01.234,56", "\u00a5\u00a01.235", "DM\u00a01.234,56", "\u20ac\u00a01.234,56"},
|
||||
{"1\u202f234.56\u00a0CHF", "1\u202f234.56\u00a0$US", "1\u202f235\u00a0JPY", "1\u202f234.56\u00a0DEM", "1\u202f234.56\u00a0\u20ac"},
|
||||
String[][] expectedCLDRData = {
|
||||
{"$1,234.56", "$1,234.56", "\u00a51,235", "DEM1,234.56", "\u20ac1,234.56"},
|
||||
{"\uFFE51,235", "$1,234.56", "\uFFE51,235", "DEM1,234.56", "\u20ac1,234.56"},
|
||||
{"1.234,56\u00a0\u20ac", "1.234,56\u00a0$", "1.235\u00a0\u00a5", "1.234,56\u00a0DM", "1.234,56\u00a0\u20ac"},
|
||||
{"1.234,56\u00a0\u20ac", "1.234,56\u00a0USD", "1.235\u00a0JPY", "1.234,56\u00a0DEM", "1.234,56\u00a0\u20ac"},
|
||||
{"1.234,56\u00a0\u20ac", "1.234,56\u00a0USD", "1.235\u00a0JPY", "1.234,56\u00a0DEM", "1.234,56\u00a0\u20ac"},
|
||||
{"\u20ac\u00a01.234,56", "$\u00a01.234,56", "\u00a5\u00a01.235", "DM\u00a01.234,56", "\u20ac\u00a01.234,56"},
|
||||
{"1\u202f234.56\u00a0CHF", "1\u202f234.56\u00a0$US", "1\u202f235\u00a0JPY", "1\u202f234.56\u00a0DEM", "1\u202f234.56\u00a0\u20ac"},
|
||||
};
|
||||
|
||||
for (int i = 0; i < locales.length; i++) {
|
||||
Locale locale = locales[i];
|
||||
NumberFormat format = NumberFormat.getCurrencyInstance(locale);
|
||||
for (int j = 0; j < currencies.length; j++) {
|
||||
Currency currency = currencies[j];
|
||||
String expected = isCompat ? expecteds[i][j] : expecteds_cldr[i][j];
|
||||
if (currency != null) {
|
||||
format.setCurrency(currency);
|
||||
int digits = currency.getDefaultFractionDigits();
|
||||
format.setMinimumFractionDigits(digits);
|
||||
format.setMaximumFractionDigits(digits);
|
||||
}
|
||||
String result = format.format(1234.56);
|
||||
if (!result.equals(expected)) {
|
||||
failed = true;
|
||||
System.out.println("FAIL: Locale " + locale
|
||||
+ (currency == null ? ", default currency" : (", currency: " + currency))
|
||||
+ ", expected: " + expected
|
||||
+ ", actual: " + result);
|
||||
}
|
||||
String expected = isCompat ? expectedCOMPATData[i][j] : expectedCLDRData[i][j];
|
||||
data.add(Arguments.of(expected, currency, format, locale));
|
||||
}
|
||||
}
|
||||
return data.stream();
|
||||
}
|
||||
|
||||
if (failed) {
|
||||
throw new RuntimeException();
|
||||
// Compares the expected currency symbol of a locale to the value returned by
|
||||
// DecimalFormatSymbols.getCurrencySymbol().
|
||||
@ParameterizedTest
|
||||
@MethodSource("currencySymbolsDataProvider")
|
||||
public void currencySymbolsTest(String expected, Locale locale) throws ParseException {
|
||||
if (!isCompat) {
|
||||
return; // For COMPAT only.
|
||||
}
|
||||
if (expected == null) {
|
||||
System.out.println("Warning: No expected currency symbol defined for locale " + locale);
|
||||
} else {
|
||||
// Reserved for when a currency will change its symbol at a given time in the future
|
||||
if (expected.contains(";")) {
|
||||
expected = getFutureSymbol(expected);
|
||||
}
|
||||
DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(locale);
|
||||
String result = symbols.getCurrencySymbol();
|
||||
assertEquals(expected, result, "Wrong currency symbol for locale " +
|
||||
locale + ", expected: " + expected + ", got: " + result);
|
||||
}
|
||||
}
|
||||
|
||||
static void testSymbols() throws Exception {
|
||||
if (!isCompat) {
|
||||
// For COMPAT only.
|
||||
return;
|
||||
}
|
||||
|
||||
FileInputStream stream = new FileInputStream(new File(System.getProperty("test.src", "."), "CurrencySymbols.properties"));
|
||||
// Grabs the custom CurrencySymbols.properties and loads the file into a Properties
|
||||
// instance. Building the data set, which consists of the currency symbol for the locale.
|
||||
private static Stream<Arguments> currencySymbolsDataProvider() throws IOException {
|
||||
ArrayList<Arguments> data = new ArrayList<Arguments>();
|
||||
FileInputStream stream = new FileInputStream(new File(
|
||||
System.getProperty("test.src", "."), "CurrencySymbols.properties"));
|
||||
InputStreamReader streamReader = new InputStreamReader(stream, StandardCharsets.UTF_8);
|
||||
Properties props = new Properties();
|
||||
props.load(streamReader);
|
||||
SimpleDateFormat format = null;
|
||||
|
||||
Locale[] locales = NumberFormat.getAvailableLocales();
|
||||
for (int i = 0; i < locales.length; i++) {
|
||||
Locale locale = locales[i];
|
||||
DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(locale);
|
||||
String result = symbols.getCurrencySymbol();
|
||||
for (Locale locale : locales) {
|
||||
String expected = (String) props.get(locale.toString());
|
||||
data.add(Arguments.of(expected, locale));
|
||||
}
|
||||
return data.stream();
|
||||
}
|
||||
|
||||
if (expected == null) {
|
||||
System.out.println("Warning: No expected currency symbol defined for locale " + locale);
|
||||
} else {
|
||||
if (expected.contains(";")) {
|
||||
StringTokenizer tokens = new StringTokenizer(expected, ";");
|
||||
int tokensCount = tokens.countTokens();
|
||||
|
||||
if (tokensCount == 3) {
|
||||
expected = tokens.nextToken();
|
||||
if (format == null) {
|
||||
format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.US);
|
||||
format.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||
format.setLenient(false);
|
||||
}
|
||||
|
||||
if (format.parse(tokens.nextToken()).getTime() < System.currentTimeMillis()) {
|
||||
expected = tokens.nextToken();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!expected.equals(result)) {
|
||||
throw new RuntimeException("Wrong currency symbol for locale " +
|
||||
locale + ", expected: " + expected + ", got: " + result);
|
||||
}
|
||||
// Utility to grab the future symbol if in the right format and date cut-over allows
|
||||
private static String getFutureSymbol(String expected) throws ParseException {
|
||||
StringTokenizer tokens = new StringTokenizer(expected, ";");
|
||||
int tokensCount = tokens.countTokens();
|
||||
if (tokensCount == 3) {
|
||||
expected = tokens.nextToken();
|
||||
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.US);
|
||||
format.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||
format.setLenient(false);
|
||||
if (format.parse(tokens.nextToken()).getTime() < System.currentTimeMillis()) {
|
||||
expected = tokens.nextToken();
|
||||
}
|
||||
}
|
||||
return expected;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 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
|
||||
@ -21,27 +21,31 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
/*
|
||||
* @test
|
||||
* @bug 8206879
|
||||
* @summary Currency decimal marker incorrect for Peru.
|
||||
* @modules jdk.localedata
|
||||
* @run main/othervm -Djava.locale.providers=JRE TestPeruCurrencyFormat
|
||||
* @summary Currency decimal marker incorrect for Peru (COMPAT).
|
||||
* @run junit/othervm -Djava.locale.providers=COMPAT TestPeruCurrencyFormat
|
||||
*/
|
||||
|
||||
import java.text.NumberFormat;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class TestPeruCurrencyFormat {
|
||||
|
||||
public static void main(String[] args) {
|
||||
// Confirm correct decimal marker for Peru locale on COMPAT
|
||||
@Test
|
||||
public void peruDecimalMarketCOMPAT() {
|
||||
final String expected = "S/.1,234.56";
|
||||
NumberFormat currencyFmt =
|
||||
NumberFormat.getCurrencyInstance(Locale.of("es", "PE"));
|
||||
String s = currencyFmt.format(1234.56);
|
||||
|
||||
if (!s.equals(expected)) {
|
||||
throw new RuntimeException("Currency format for Peru failed, expected " + expected + ", got " + s);
|
||||
}
|
||||
assertEquals(expected, s,
|
||||
"Currency format for Peru failed, expected " + expected + ", got " + s);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user