undefect. CWE-407 — 63 sites patched across 27 ecosystems

Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com

Patches, unit tests, benchmarks, whitepaper, and outreach briefs.
Public domain — no copyright claimed. Use freely.
This commit is contained in:
russell@unturf.com 2026-03-26 17:11:57 -04:00
commit 0a580b313d
70422 changed files with 17213626 additions and 0 deletions

View file

@ -0,0 +1,50 @@
/*
* Copyright (c) 2025, 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 8351074
* @summary Test input value check for DecimalFormat affix setter methods
* @run junit AffixTest
*/
import org.junit.jupiter.api.Test;
import java.text.DecimalFormat;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class AffixTest {
@Test
public void nullPrefixTest() {
assertThrows(NullPointerException.class, () -> new DecimalFormat().setPositivePrefix(null));
assertThrows(NullPointerException.class, () -> new DecimalFormat().setNegativePrefix(null));
}
@Test
public void nullSuffixTest() {
assertThrows(NullPointerException.class, () -> new DecimalFormat().setPositiveSuffix(null));
assertThrows(NullPointerException.class, () -> new DecimalFormat().setNegativeSuffix(null));
}
}

View file

@ -0,0 +1,129 @@
/*
* Copyright (c) 2017, 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 6609740
* @summary Checks the formatting and parsing of a number based
* on the positive and negative sub-patterns, also
* checks few invalid number patterns
*/
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Locale;
public class Bug6609740 {
public static void main(String[] args) {
double dNumber = -3456.349347;
String fOutput = "(3,456.35)";
String[] validCases = {"#,##0.0#;(#,##0.0#)", "#,##0.0#;(#)",
"#,##0.0#;(#,##0)"};
// formatting with the valid cases
NumberFormat nf = NumberFormat.getInstance(Locale.US);
for (String pattern : validCases) {
formatOnPattern(nf, pattern, dNumber, fOutput);
}
// parsing with the valid cases
String parseString = "(3,456.35)";
Number pOutput = -3456.35;
for (String pattern : validCases) {
parseOnPattern(nf, pattern, parseString, pOutput);
}
// should throw parse exception
String[] invalidParseCases = {"#,##0.0#;0", "#,##0.0#;()"};
for (String pattern : invalidParseCases) {
if (nf instanceof DecimalFormat) {
((DecimalFormat) nf).applyPattern(pattern);
}
try {
nf.parse(parseString);
} catch (ParseException ex) {
continue;
}
throw new RuntimeException("[FAILED: Should throw"
+ " ParseException for pattern: "
+ pattern + " and input: " + parseString + "]");
}
// should throw exception on invalid patterns
// invalid patterns: no positive subpattern, zero after non-zero in
// the decimal part i.e. 0#0, multiple decimal separators,
// multiple percent, malformed pattern
String[] invalidPatterns = {";(#,##0.0#)", "#,##0.0#0;(#)",
"#,##0.0.#", "#,##0%%", ".#,##0"};
for (String pattern : invalidPatterns) {
if (nf instanceof DecimalFormat) {
try {
((DecimalFormat) nf).applyPattern(pattern);
} catch (IllegalArgumentException ex) {
continue;
}
throw new RuntimeException("[FAILED: Should throw"
+ " IllegalArgumentException for invalid pattern: "
+ pattern + "]");
}
}
}
private static void formatOnPattern(NumberFormat nf, String pattern,
double number, String expected) {
if (nf instanceof DecimalFormat) {
((DecimalFormat) nf).applyPattern(pattern);
}
String formatted = nf.format(number);
if (!formatted.equals(expected)) {
throw new RuntimeException("[FAILED: Unable to format the number"
+ " based on the pattern: '" + pattern + "', Expected : '"
+ expected + "', Found: '" + formatted + "']");
}
}
private static void parseOnPattern(NumberFormat nf, String pattern,
String parseString, Number expected) {
if (nf instanceof DecimalFormat) {
((DecimalFormat) nf).applyPattern(pattern);
}
try {
Number output = nf.parse(parseString);
if (expected.doubleValue() != output.doubleValue()) {
throw new RuntimeException("[FAILED: Unable to parse the number"
+ " based on the pattern: '" + pattern + "', Expected : '"
+ expected + "', Found: '" + output + "']");
}
} catch (ParseException ex) {
throw new RuntimeException("[FAILED: Unable to parse the pattern:"
+ " '" + pattern + "']", ex);
}
}
}

View file

@ -0,0 +1,73 @@
/*
* Copyright (c) 2012, 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 7196316
* @summary Confirm that a non-default rounding mode is used even after deserialization.
*/
import java.io.*;
import java.math.*;
import java.text.*;
public class Bug7196316 {
private static final String filename = "bug7196316.ser";
public static void main(String[] args) throws Exception {
DecimalFormat df;
RoundingMode mode = RoundingMode.DOWN;
double given = 6.6;
String expected;
String actual;
try (ObjectOutputStream os
= new ObjectOutputStream(new FileOutputStream(filename))) {
df = new DecimalFormat("#");
df.setRoundingMode(mode);
expected = df.format(given);
os.writeObject(df);
}
try (ObjectInputStream is
= new ObjectInputStream(new FileInputStream(filename))) {
df = (DecimalFormat)is.readObject();
}
RoundingMode newMode = df.getRoundingMode();
if (mode != newMode) {
throw new RuntimeException("Unexpected roundig mode: " + newMode);
} else {
actual = df.format(given);
if (!expected.equals(actual)) {
throw new RuntimeException("Unexpected formatted result: \""
+ actual + "\"");
} else {
System.out.println("Passed: Expected rounding mode (" + newMode
+ ") & formatted result: \"" + actual + "\"");
}
}
}
}

View file

@ -0,0 +1,95 @@
/*
* Copyright (c) 2016, 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 8165466
* @summary Checks the subsequent function calls of the DecimalFormat.format()
* method in which the minimumFractionDigit is set to 0 and one of
* the format() call include formatting of the number with zero
* fraction value e.g. 0.00, 9.00
*/
import java.text.DecimalFormat;
import java.util.Locale;
public class Bug8165466 {
public static void main(String[] args) {
DecimalFormat nf = (DecimalFormat) DecimalFormat
.getPercentInstance(Locale.US);
nf.setMaximumFractionDigits(3);
nf.setMinimumFractionDigits(0);
nf.setMultiplier(1);
double d = 0.005678;
String result = nf.format(d);
if (!result.equals("0.006%")) {
throw new RuntimeException("[Failed while formatting the double"
+ " value: " + d + " Expected: 0.006%, Found: " + result
+ "]");
}
d = 0.00;
result = nf.format(d);
if (!result.equals("0%")) {
throw new RuntimeException("[Failed while formatting the double"
+ " value: " + d + " Expected: 0%, Found: " + result
+ "]");
}
d = 0.005678;
result = nf.format(d);
if (!result.equals("0.006%")) {
throw new RuntimeException("[Failed while formatting the double"
+ " value: " + d + " Expected: 0.006%, Found: " + result
+ "]");
}
//checking with the non zero value
d = 0.005678;
result = nf.format(d);
if (!result.equals("0.006%")) {
throw new RuntimeException("[Failed while formatting the double"
+ " value: " + d + " Expected: 0.006%, Found: " + result
+ "]");
}
d = 9.00;
result = nf.format(d);
if (!result.equals("9%")) {
throw new RuntimeException("[Failed while formatting the double"
+ " value: " + d + " Expected: 9%, Found: " + result
+ "]");
}
d = 0.005678;
result = nf.format(d);
if (!result.equals("0.006%")) {
throw new RuntimeException("[Failed while formatting the double"
+ " value: " + d + " Expected: 0.006%, Found: " + result
+ "]");
}
}
}

View file

@ -0,0 +1,156 @@
/*
* Copyright (c) 2025, 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 8354522 8358880 8367324
* @summary Check for cloning interference
* @library /test/lib
* @run junit/othervm --add-opens=java.base/java.text=ALL-UNNAMED CloneTest
*/
import jtreg.SkippedException;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import static org.junit.jupiter.api.Assertions.*;
public class CloneTest {
// Note: this is a white-box test that may fail if the implementation is changed
@Test
public void testClone() {
DecimalFormat df = new DecimalFormat("#");
new CloneTester(df).testClone();
}
// Note: this is a white-box test that may fail if the implementation is changed
@Test
public void testCloneAfterInit() {
DecimalFormat df = new DecimalFormat("#");
// This initial use of the formatter initialises its internal state, which could
// subsequently be shared across clones. This is key to reproducing this specific
// issue.
String _ = df.format(Math.PI);
new CloneTester(df).testClone();
}
private static class CloneTester {
private final Field digitListField;
private final Class<?> digitListClass;
private final DecimalFormat original;
public CloneTester(DecimalFormat original) {
this.original = original;
try {
digitListField = DecimalFormat.class.getDeclaredField("digitList");
digitListField.setAccessible(true);
DecimalFormat df = new DecimalFormat();
Object digitList = digitListField.get(df);
digitListClass = digitList.getClass();
} catch (ReflectiveOperationException e) {
throw new SkippedException("reflective access in white-box test failed", e);
}
}
public void testClone() {
try {
DecimalFormat dfClone = (DecimalFormat) original.clone();
Object digits = valFromDigitList(original, "digits");
assertNotSame(digits, valFromDigitList(dfClone, "digits"));
assertEquals(digitListField.get(original), digitListField.get(dfClone));
} catch (ReflectiveOperationException e) {
throw new SkippedException("reflective access in white-box test failed", e);
}
}
private Object valFromDigitList(DecimalFormat df, String fieldName) throws ReflectiveOperationException {
Object digitList = digitListField.get(df);
Field field = digitListClass.getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(digitList);
}
}
// Tests that when DecimalFormat is cloned after use with
// a long double/BigDecimal, clones will be independent. This is not an
// exhaustive test. This tests for the issue of the same DigitList.data
// array being reused across clones of DecimalFormat.
@Test
public void testCloneIndependence() {
AtomicInteger mismatchCount = new AtomicInteger(0);
DecimalFormat df = new DecimalFormat("#");
CountDownLatch startSignal = new CountDownLatch(1);
// This initial use of the formatter initialises its internal state, which could
// subsequently be shared across clones. This is key to reproducing this specific
// issue.
String _ = df.format(Math.PI);
try (var ex = Executors.newThreadPerTaskExecutor(Thread.ofPlatform().factory())) {
for (int i = 0; i < 5; i++) {
final int finalI = i;
// Each thread gets its own clone of df
DecimalFormat threadDf = (DecimalFormat) df.clone();
Runnable task = () -> {
try {
startSignal.await();
for (int j = 0; j < 1_000; j++) {
if (mismatchCount.get() > 0) {
// Exit early if mismatch has already occurred
break;
}
int value = finalI * j;
String dfString = threadDf.format(BigDecimal.valueOf(value));
String str = String.valueOf(value);
if (!str.equals(dfString)) {
mismatchCount.getAndIncrement();
System.err.println("mismatch: str = " + str + " dfString = " + dfString);
break;
}
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
};
ex.execute(task);
}
startSignal.countDown(); // let all tasks start working at the same time
}
assertEquals(0, mismatchCount.get());
}
}

View file

@ -0,0 +1,328 @@
/*
* Copyright (c) 2025, 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 4068067 4101150 8366401
* @library /java/text/testlib
* @build HexDumpReader
* @summary Check serialization of DecimalFormatSymbols. That is, ensure the
* behavior for each stream version is correct during de-serialization.
* @run junit/othervm --add-opens java.base/java.text=ALL-UNNAMED DFSSerializationTest
*/
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.text.DecimalFormatSymbols;
import java.util.Currency;
import java.util.Locale;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class DFSSerializationTest {
// Test that rely on hex dump files that were written from older JDK versions
@Nested
class HexDumpTests {
@Test // See 4068067 and CDFS which is the class in the serialized hex dump
void JDK1_1_4Test() {
// Reconstruct a class serialized during 1.1.4 which has a DFS holder
var cdfs = (CheckDecimalFormatSymbols) assertDoesNotThrow(
() -> deSer("DecimalFormatSymbols.114.txt"));
assertDoesNotThrow(cdfs::Update); // Checks getDigit call succeeds
}
@Test // See 4068067
void JDK1_4_2Test() {
// Reconstruct a 1.4.2 DFS
var dfs = (DecimalFormatSymbols) assertDoesNotThrow(
() -> deSer("DecimalFormatSymbols.142.txt"));
// Checks curr symbol is saved, and exponent separator default set
assertEquals("E", dfs.getExponentSeparator());
assertEquals("*SpecialCurrencySymbol*", dfs.getCurrencySymbol());
}
}
@Nested
class StreamVersionTests {
// Ensure correct monetarySeparator and exponential field defaults
// Reads monetary from decimal, and sets exponential to 'E'
@Test
void version0Test() {
var crafted = new DFSBuilder()
.setVer(0)
.set("monetarySeparator", '~')
.set("exponential", 'Z')
.build();
var bytes = ser(crafted);
var dfs = assertDoesNotThrow(() -> deSer(bytes));
// Check exponential is set to proper default 'E', not 'Z'
assertEquals('E', readField(dfs, "exponential"));
// Ensure that mSep is based on dSep, and is not '~'
assertNotEquals('~', dfs.getMonetaryDecimalSeparator());
assertEquals(dfs.getDecimalSeparator(), dfs.getMonetaryDecimalSeparator());
}
// Version 1 did not have a locale field, and it defaulted to Locale.ROOT.
// Note that other versions did allow a locale field, which was nullable.
// E.g. see nullableLocaleTest which does not set locale when it is `null`
@Test
void version1Test() {
var crafted = new DFSBuilder()
.setVer(1)
.set("locale", null)
.build();
var bytes = ser(crafted);
var dfs = assertDoesNotThrow(() -> deSer(bytes));
assertEquals(Locale.ROOT, dfs.getLocale());
}
// Version 2 did not have an exponential separator, and created it via exponent
// char field.
@Test
void version2Test() {
var crafted = new DFSBuilder()
.setVer(2)
.set("exponentialSeparator", null)
.set("exponential", '~')
.build();
var bytes = ser(crafted);
var dfs = assertDoesNotThrow(() -> deSer(bytes));
assertEquals("~", dfs.getExponentSeparator());
}
// Version 3 didn't have perMillText, percentText, and minusSignText.
// These were created from the corresponding char equivalents.
@Test
void version3Test() {
var crafted = new DFSBuilder()
.setVer(3)
.set("perMillText", null)
.set("percentText", null)
.set("minusSignText", null)
.set("perMill", '~')
.set("percent", '~')
.set("minusSign", '~')
.build();
var bytes = ser(crafted);
var dfs = assertDoesNotThrow(() -> deSer(bytes));
// Need to check these String fields using reflection, since they
// are not exposed via the public API
assertEquals("~", readField(dfs, "perMillText"));
assertEquals("~", readField(dfs, "percentText"));
assertEquals("~", readField(dfs, "minusSignText"));
}
// Version 4 did not have monetaryGroupingSeparator. It should be based
// off of groupingSeparator.
@Test
void version4Test() {
var crafted = new DFSBuilder()
.setVer(4)
.set("monetaryGroupingSeparator", 'Z')
.set("groupingSeparator", '~')
.build();
var bytes = ser(crafted);
var dfs = assertDoesNotThrow(() -> deSer(bytes));
assertEquals(dfs.getGroupingSeparator(), dfs.getMonetaryGroupingSeparator());
}
}
// Up-to-date DFS stream versions do not expect a null locale since the
// standard DecimalFormatSymbols API forbids it. However, this was not always
// the case and previous stream versions can contain a null locale. Thus,
// ensure that a null locale does not cause number data loading to fail.
@Test
void nullableLocaleTest() {
var bytes = ser(new DFSBuilder()
.set("locale", null)
.set("minusSignText", "zFoo")
.set("minusSign", 'z') // Set so that char/String forms agree
.build());
var dfs = assertDoesNotThrow(() -> deSer(bytes));
assertNull(dfs.getLocale());
// LMS should be based off of minusSignText when locale is null
assertEquals("zFoo", readField(dfs, "lenientMinusSigns"));
}
// readObject fails when the {@code char} and {@code String} representations
// of percent, per mille, and/or minus sign disagree.
@Test
void disagreeingTextTest() {
var expected = "'char' and 'String' representations of either percent, " +
"per mille, and/or minus sign disagree.";
assertEquals(expected, assertThrows(InvalidObjectException.class, () ->
deSer(ser(new DFSBuilder()
.set("minusSignText", "Z")
.set("minusSign", 'X')
.build()))).getMessage());
assertEquals(expected, assertThrows(InvalidObjectException.class, () ->
deSer(ser(new DFSBuilder()
.set("perMillText", "Z")
.set("perMill", 'X')
.build()))).getMessage());
assertEquals(expected, assertThrows(InvalidObjectException.class, () ->
deSer(ser(new DFSBuilder()
.set("percentText", "Z")
.set("percent", 'X')
.build()))).getMessage());
}
// Ensure the serial version is updated to the current after de-serialization.
@Test
void updatedVersionTest() {
var bytes = ser(new DFSBuilder().setVer(-25).build());
var dfs = assertDoesNotThrow(() -> deSer(bytes));
assertEquals(5, readField(dfs, "serialVersionOnStream"));
}
// Should set currency from 4217 code when it is valid.
@Test
void validIntlCurrencyTest() {
var bytes = ser(new DFSBuilder().set("intlCurrencySymbol", "JPY").build());
var dfs = assertDoesNotThrow(() -> deSer(bytes));
assertEquals(Currency.getInstance("JPY"), dfs.getCurrency());
}
// Should not set currency when 4217 code is invalid, it remains null.
@Test
void invalidIntlCurrencyTest() {
var bytes = ser(new DFSBuilder()
.set("intlCurrencySymbol", ">.,")
.set("locale", Locale.JAPAN)
.build());
var dfs = assertDoesNotThrow(() -> deSer(bytes));
// Can not init off invalid 4217 code, remains null
assertNull(dfs.getCurrency());
}
// Ensure the currency symbol is read properly
@Test
void currencySymbolTest() {
var crafted = new DecimalFormatSymbols();
crafted.setCurrencySymbol("*SpecialCurrencySymbol*");
var bytes = ser(crafted);
var dfs = assertDoesNotThrow(() -> deSer(bytes));
assertEquals("*SpecialCurrencySymbol*", dfs.getCurrencySymbol());
}
// Ensure the exponent separator is read properly
@Test
void exponentSeparatorTest() {
var crafted = new DecimalFormatSymbols();
crafted.setExponentSeparator("*SpecialExponentSeparator*");
var bytes = ser(crafted);
var dfs = assertDoesNotThrow(() -> deSer(bytes));
assertEquals("*SpecialExponentSeparator*", dfs.getExponentSeparator());
}
// Utilities ----
// Utility to serialize
private static byte[] ser(Object obj) {
return assertDoesNotThrow(() -> {
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(byteArrayOutputStream)) {
oos.writeObject(obj);
return byteArrayOutputStream.toByteArray();
}
}, "Unexpected error during serialization");
}
// Utility to deserialize from byte array
private static DecimalFormatSymbols deSer(byte[] bytes) throws IOException, ClassNotFoundException {
try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(byteArrayInputStream)) {
return (DecimalFormatSymbols) ois.readObject();
}
}
// Utility to deserialize from file in hex format
private static Object deSer(String file) throws IOException, ClassNotFoundException {
try (InputStream stream = HexDumpReader.getStreamFromHexDump(file);
ObjectInputStream ois = new ObjectInputStream(stream)) {
return ois.readObject();
}
}
// Utility to read a private field
private static Object readField(DecimalFormatSymbols dfs, String name) {
return assertDoesNotThrow(() -> {
var field = DecimalFormatSymbols.class.getDeclaredField(name);
field.setAccessible(true);
return field.get(dfs);
}, "Unexpected error during field reading");
}
// Utility class to build instances of DFS via reflection
private static class DFSBuilder {
private final DecimalFormatSymbols dfs;
private DFSBuilder() {
dfs = new DecimalFormatSymbols();
}
private DFSBuilder setVer(Object value) {
return set("serialVersionOnStream", value);
}
private DFSBuilder set(String field, Object value) {
return assertDoesNotThrow(() -> {
Field f = dfs.getClass().getDeclaredField(field);
f.setAccessible(true);
f.set(dfs, value);
return this;
}, "Unexpected error during reflection setting");
}
private DecimalFormatSymbols build() {
return dfs;
}
}
}
// Not nested, so that it can be cast correctly for the 1.1.4 test
class CheckDecimalFormatSymbols implements Serializable {
DecimalFormatSymbols _decFormatSymbols = new DecimalFormatSymbols();
public char Update()
{
return _decFormatSymbols.getDigit();
}
}

View file

@ -0,0 +1,54 @@
#
# Copyright (c) 1998, 2016, 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.
#
# Hex dump of a serialized DecimalFormat for SerializationLoadTest.
aced000573720012436865636b446563696d616c466f726d6174aa9218d3b530
540a0200014c000a5f646563466f726d61747400194c6a6176612f746578742f
446563696d616c466f726d61743b7870737200176a6176612e746578742e4465
63696d616c466f726d61740bff0362d872303a0200085a001b646563696d616c
536570617261746f72416c7761797353686f776e42000c67726f7570696e6753
697a6549000a6d756c7469706c6965724c000e6e656761746976655072656669
787400124c6a6176612f6c616e672f537472696e673b4c000e6e656761746976
655375666669787400124c6a6176612f6c616e672f537472696e673b4c000e70
6f7369746976655072656669787400124c6a6176612f6c616e672f537472696e
673b4c000e706f7369746976655375666669787400124c6a6176612f6c616e67
2f537472696e673b4c000773796d626f6c737400204c6a6176612f746578742f
446563696d616c466f726d617453796d626f6c733b787200166a6176612e7465
78742e4e756d626572466f726d6174dff6b3bf137d07e80200065a000c67726f
7570696e67557365644200116d61784672616374696f6e446967697473420010
6d6178496e74656765724469676974734200116d696e4672616374696f6e4469
676974734200106d696e496e74656765724469676974735a0010706172736549
6e74656765724f6e6c79787200106a6176612e746578742e466f726d6174fbd8
bc12e90f1843020000787001037f0001000003000000017400012d7400007400
007400007372001e6a6176612e746578742e446563696d616c466f726d617453
796d626f6c73501d17990868939c02000c430010646563696d616c5365706172
61746f72430005646967697443001167726f7570696e67536570617261746f72
4300096d696e75735369676e4300107061747465726e536570617261746f7243
00077065724d696c6c43000770657263656e744300097a65726f44696769744c
00034e614e7400124c6a6176612f6c616e672f537472696e673b4c000e637572
72656e637953796d626f6c7400124c6a6176612f6c616e672f537472696e673b
4c0008696e66696e6974797400124c6a6176612f6c616e672f537472696e673b
4c0012696e746c43757272656e637953796d626f6c7400124c6a6176612f6c61
6e672f537472696e673b7870002e0023002c002d003b203000250030740003ef
bfbd74000124740003e2889e740003555344

View file

@ -0,0 +1,39 @@
#
# Copyright (c) 1998, 2016, 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.
#
# Hex dump of a serialized DecimalFormatSymbols for SerializationLoadTest.
aced000573720019436865636b446563696d616c466f726d617453796d626f6c
737763237e1aa359bb0200014c00115f646563466f726d617453796d626f6c73
7400204c6a6176612f746578742f446563696d616c466f726d617453796d626f
6c733b78707372001e6a6176612e746578742e446563696d616c466f726d6174
53796d626f6c73501d17990868939c02000c430010646563696d616c53657061
7261746f72430005646967697443001167726f7570696e67536570617261746f
724300096d696e75735369676e4300107061747465726e536570617261746f72
4300077065724d696c6c43000770657263656e744300097a65726f4469676974
4c00034e614e7400124c6a6176612f6c616e672f537472696e673b4c000e6375
7272656e637953796d626f6c7400124c6a6176612f6c616e672f537472696e67
3b4c0008696e66696e6974797400124c6a6176612f6c616e672f537472696e67
3b4c0012696e746c43757272656e637953796d626f6c7400124c6a6176612f6c
616e672f537472696e673b7870002e0023002c002d003b203000250030740003
efbfbd74000124740003e2889e740003555344

View file

@ -0,0 +1,42 @@
#
# Copyright (c) 1998, 2016, 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.
#
# Hex dump of a serialized DecimalFormatSymbols for SerializationLoadTest.
aced00057372001e6a6176612e746578742e446563696d616c466f726d617453
796d626f6c73501d17990868939c020010430010646563696d616c5365706172
61746f72430005646967697443000b6578706f6e656e7469616c43001167726f
7570696e67536570617261746f724300096d696e75735369676e4300116d6f6e
6574617279536570617261746f724300107061747465726e536570617261746f
724300077065724d696c6c43000770657263656e7449001573657269616c5665
7273696f6e4f6e53747265616d4300097a65726f44696769744c00034e614e74
00124c6a6176612f6c616e672f537472696e673b4c000e63757272656e637953
796d626f6c71007e00014c0008696e66696e69747971007e00014c0012696e74
6c43757272656e637953796d626f6c71007e00014c00066c6f63616c65740012
4c6a6176612f7574696c2f4c6f63616c653b7870002e00230045002c002d002e
003b20300025000000020030740003efbfbd7400172a5370656369616c437572
72656e637953796d626f6c2a740003e2889e740003434e59737200106a617661
2e7574696c2e4c6f63616c657ef811609c30f9ec03000449000868617368636f
64654c0007636f756e74727971007e00014c00086c616e677561676571007e00
014c000776617269616e7471007e00017870ffffffff740002434e7400027a68
74000078

View file

@ -0,0 +1,74 @@
/*
* Copyright (c) 2025, 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 8362448
* @summary Verify DecimalFormat::format on doubles.
* @run junit DoubleFormattingTest
* @run junit/othervm -Djdk.compat.DecimalFormat=true DoubleFormattingTest
*/
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Formatter;
import java.util.Locale;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.*;
public class DoubleFormattingTest {
private static final boolean COMPAT = Boolean.getBoolean("jdk.compat.DecimalFormat");
static Stream<Arguments> testFormat() {
return Stream.of(
Arguments.of(4.8726570057E288, 0),
Arguments.of(7.3879E20, 0),
Arguments.of(1.9400994884341945E25, 0),
Arguments.of(6.3E-322, 324)
);
}
@ParameterizedTest
@MethodSource
void testFormat(double v, int minFractionDigits) {
DecimalFormat df = (DecimalFormat) NumberFormat.getNumberInstance(Locale.ROOT);
df.setGroupingUsed(false);
df.setMinimumFractionDigits(minFractionDigits);
String actual = df.format(v);
Formatter fmt = new Formatter(Locale.ROOT);
fmt.format("%." + minFractionDigits + "f", v);
String expected = fmt.toString();
if (COMPAT) {
assertNotEquals(expected, actual);
} else {
assertEquals(expected, actual);
}
}
}

View file

@ -0,0 +1,53 @@
/*
* Copyright (c) 2024, 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 8327640
* @summary Check parseStrict correctness for DecimalFormat.equals()
* @run junit EqualityTest
*/
import org.junit.jupiter.api.Test;
import java.text.DecimalFormat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
public class EqualityTest {
private static final DecimalFormat fmt1 = new DecimalFormat();
private static final DecimalFormat fmt2 = new DecimalFormat();
// Ensure that parseStrict is reflected correctly for DecimalFormat.equals()
@Test
public void checkStrictTest() {
// parseStrict is false by default
assertEquals(fmt1, fmt2);
fmt1.setStrict(true);
assertNotEquals(fmt1, fmt2);
fmt2.setStrict(true);
assertEquals(fmt1, fmt2);
}
}

View file

@ -0,0 +1,926 @@
/*
* Copyright (c) 2012, 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 7050528
* @summary Set of micro-benchmarks testing throughput of java.text.DecimalFormat.format()
* @author Olivier Lagneau
* @run main FormatMicroBenchmark
*/
/* This is a set of micro-benchmarks testing throughput of java.text.DecimalFormat.format().
* It never fails.
*
* Usage and arguments:
* - Run with no argument skips the whole benchmark and exits.
* - Run with "-help" as first argument calls the usage() method and exits.
* - Run with "-doit" runs the benchmark with summary details.
* - Run with "-verbose" provides additional details on the run.
*
* Example run :
* java -Xms500m -Xmx500m -XX:NewSize=400m FormatMicroBenchmark -doit -verbose
*
* Running with jtreg:
* The jtreg header "run" tag options+args must be changed to avoid skipping
* the execution. here is an example of run options:
* "main/othervm -Xms500m -Xmx500m -XX:NewSize=400m FormatMicroBenchmark -doit"
*
* Note:
* - Vm options -Xms, -Xmx, -XX:NewSize must be set correctly for
* getting reliable numbers. Otherwise GC activity may corrupt results.
* As of jdk80b48 using "-Xms500m -Xmx500m -XX:NewSize=400m" covers
* all cases.
* - Optionally using "-Xlog:gc" option provides information that
* helps checking any GC activity while benches are run.
*
* Vm Options:
* - Vm options to use (as of jdk80b48):
* fast-path case : -Xms128m -Xmx128m -XX:NewSize=100m
* non fast-path case: -Xms500m -Xmx500m -XX:NewSize=400m
* or use worst case (non fast-path above) with both types of algorithm.
*
* - use -Xlog:gc to verify memory consumption of the benchmarks.
* (See "Checking Memory Consumption" below).
*
* Description:
*
* Fast-path algorithm for format(double...) call stack is very different of
* the standard call stack. Where the standard algorithm for formating double
* uses internal class sun.misc.FloatingDecimal and its dtoa(double) method to
* provide digits, fast-path embeds its own algorithm for binary to decimal
* string conversion.
*
* FloatingDecimal always converts completely the passed double to a string.
* Fast-path converts only to the needed digits since it follows constraints
* on both the pattern rule, the DecimalFormat instance properties, and the
* passed double.
*
* Micro benchmarks below measure the throughput for formating double values
* using NumberFormat.format(double) call stack. The standard DecimalFormat
* call stack as well as the fast-path algorithm implementation are sensitive
* to the nature of the passed double values regarding throughput performance.
*
* These benchmarks are useful both for measuring the global performance gain
* of fast-path and to check that any modification done on fast-path algorithm
* does not bring any regression in the performance boost of fast-path.
*
* Note that these benchmarks will provide numbers without any knowledge of
* the implementation of DecimalFormat class. So to check regression any run
* should be compared to another reference run with a previous JDK, whether or
* not this previous reference JDK contains fast-path implementation.
*
* The eight benchmarks below are dedicated to measure throughput on different
* kinds of double that all fall in the fast-path case (all in Integer range):
*
* - Integer case : used double values are all "integer-like" (ex: -12345.0).
* This is the benchFormatInteger micro-benchmark.
*
* - Fractional case : double values are "fractional" (ex: -0.12345).
* This is the benchFormatFractional micro-benchmark.
*
* - Small integral case : like Integer case but double values are all limited
* in their magnitude, from -500.0 to 500.0 if the number of iterations N is
* set to 500000.
* This is the benchFormatSmallIntegral micro-benchmark.
*
* - Fractional All Nines : doubles values have fractional part that is very
* close to "999" (decimal pattern), or "99" (currency pattern),
* or "0000...".
* This is the benchFormatFractionalAllNines micro-benchmark.
*
* - All Nines : double values are such that both integral and fractional
* part consist only of '9' digits. None of these values are rounded up.
* This is the benchFormatAllNines micro-benchmark.
*
* - Fair simple case : calling J the loop variable and iterating over
* the N number of iterations, used double values are computed as
* d = (double) J + J*seed
* where seed is a very small value that adds a fractional part and adds a
* small number to integral part. Provides fairly distributed double values.
* This is the benchFormatFairSimple micro-benchmark.
*
* - Fair case : this is a combination of small integral case and fair simple
* case. Double values are limited in their magnitude but follow a parabolic
* curve y = x**2 / K, keeping large magnitude only for large values of J.
* The intent is trying to reproduce a distribution of double values as could
* be found in a business application, with most values in either the low
* range or the high range.
* This is the benchFormatFair micro-benchmark.
*
* - Tie cases: values are very close to a tie case (iii...ii.fff5)
* That is the worst situation that can happen for Fast-path algorithm when
* considering throughput.
* This is the benchFormatTie micro-benchmark.
*
* For all of the micro-benchmarks, the throughput load of the eventual
* additional computations inside the loop is calculated prior to running the
* benchmark, and provided in the output. That may be useful since this load
* may vary for each architecture or machine configuration.
*
* The "-verbose" flag, when set, provides the throughput load numbers, the
* time spent for each run of a benchmark, as well as an estimation of the
* memory consumed by the runs. Beware of incremental GCs, see "Checking
* Memory Consumption" section below. Every run should be done with correct
* ms, mx, and NewSize vm options to get fully reliable numbers.
*
* The output provides the mean time needed for a benchmark after the server
* jit compiler has done its optimization work if any. Thus only the last but
* first three runs are taken into account in the time measurement (server jit
* compiler shows to have done full optimization in most cases after the
* second run, given a base number of iterations set to 500000).
*
* The program cleans up memory (stabilizeMemory() method) between each run of
* the benchmarks to make sure that no garbage collection activity happens in
* measurements. However that does not preclude incremental GCs activity that
* may happen during the micro-benchmark if -Xms, -Xmx, and NewSize options
* have not been tuned and set correctly.
*
* Checking Memory Consumption:
*
* For getting confidence in the throughput numbers, there must not give any
* GC activity during the benchmark runs. That means that specific VM options
* related to memory must be tuned for any given implementation of the JDK.
*
* Running with "-verbose" arguments will provide clues of the memory consumed
* but is not enough, since any unexpected incremental GC may lower
* artificially the estimation of the memory consumption.
*
* Options to set are -Xms, -Xmx, -XX:NewSize, plus -Xlog:gc to evaluate
* correctly the values of these options. When running "-verbose", varying
* numbers reported for memory consumption may indicate bad choices for these
* options.
*
* For jdk80b25, fast-path shows a consuption of ~60Mbs for 500000 iterations
* while a jdk without fast-path will consume ~260Mbs for each benchmark run.
* Indeed these values will vary depending on the jdk used.
*
* Correct option settings found jdk80b48 were :
* fast-path : -Xms128m -Xmx128m -XX:NewSize=100m
* non fast-path : -Xms500m -Xmx500m -XX:NewSize=400m
* Greater values can be provided safely but not smaller ones.
* ----------------------------------------------------------------------
*/
import java.util.*;
import java.text.NumberFormat;
import java.text.DecimalFormat;
public class FormatMicroBenchmark {
// The number of times the bench method will be run (must be at least 4).
private static final int NB_RUNS = 20;
// The bench* methods below all iterates over [-MAX_RANGE , +MAX_RANGE] integer values.
private static final int MAX_RANGE = 500000;
// Flag for more details on each bench run (default is no).
private static boolean Verbose = false;
// Should we really execute the benches ? (no by default).
private static boolean DoIt = false;
// Prints out a message describing how to run the program.
private static void usage() {
System.out.println(
"This is a set of micro-benchmarks testing throughput of " +
"java.text.DecimalFormat.format(). It never fails.\n\n" +
"Usage and arguments:\n" +
" - Run with no argument skips the whole benchmark and exits.\n" +
" - Run with \"-help\" as first argument prints this message and exits.\n" +
" - Run with \"-doit\" runs the benchmark with summary details.\n" +
" - Run with \"-verbose\" provides additional details on the run.\n\n" +
"Example run :\n" +
" java -Xms500m -Xmx500m -XX:NewSize=400m FormatMicroBenchmark -doit -verbose\n\n" +
"Note: \n" +
" - Vm options -Xms, -Xmx, -XX:NewSize must be set correctly for \n" +
" getting reliable numbers. Otherwise GC activity may corrupt results.\n" +
" As of jdk80b48 using \"-Xms500m -Xmx500m -XX:NewSize=400m\" covers \n" +
" all cases.\n" +
" - Optionally using \"-Xlog:gc\" option provides information that \n" +
" helps checking any GC activity while benches are run.\n\n" +
"Look at the heading comments and description in source code for " +
"detailed information.\n");
}
/* We will call stabilizeMemory before each call of benchFormat***().
* This in turn tries to clean up as much memory as possible.
* As a safe bound we limit number of System.gc() calls to 10,
* but most of the time two calls to System.gc() will be enough.
* If memory reporting is asked for, the method returns the difference
* of free memory between entering an leaving the method.
*/
private static long stabilizeMemory(boolean reportConsumedMemory) {
final long oneMegabyte = 1024L * 1024L;
long refMemory = 0;
long initialMemoryLeft = Runtime.getRuntime().freeMemory();
long currMemoryLeft = initialMemoryLeft;
int nbGCCalls = 0;
do {
nbGCCalls++;
refMemory = currMemoryLeft;
System.gc();
currMemoryLeft = Runtime.getRuntime().freeMemory();
} while ((Math.abs(currMemoryLeft - refMemory) > oneMegabyte) &&
(nbGCCalls < 10));
if (Verbose &&
reportConsumedMemory)
System.out.println("Memory consumed by previous run : " +
(currMemoryLeft - initialMemoryLeft)/oneMegabyte + "Mbs.");
return currMemoryLeft;
}
// ---------- Integer only based bench --------------------
private static final String INTEGER_BENCH = "benchFormatInteger";
private static String benchFormatInteger(NumberFormat nf) {
String str = "";
for (int j = - MAX_RANGE; j <= MAX_RANGE; j++)
str = nf.format((double) j);
return str;
}
// This reproduces the throughput load added in benchFormatInteger
static double integerThroughputLoad() {
double d = 0.0d;
for (int j = - MAX_RANGE; j <= MAX_RANGE; j++) {
d = (double) j;
}
return d;
}
// Runs integerThroughputLoad and calculate its mean load
static void calculateIntegerThroughputLoad() {
int nbRuns = NB_RUNS;
long elapsedTime = 0;
double foo;
for (int i = 1; i <= nbRuns; i++) {
long startTime = System.nanoTime();
foo = integerThroughputLoad();
long estimatedTime = System.nanoTime() - startTime;
if (i > 3) elapsedTime += estimatedTime / 1000;
}
if (Verbose)
System.out.println(
"calculated throughput load for " + INTEGER_BENCH +
" bench is = " + (elapsedTime / (nbRuns - 3)) + " microseconds");
}
// ---------- Fractional only based bench --------------------
private static final String FRACTIONAL_BENCH = "benchFormatFractional";
private static String benchFormatFractional(NumberFormat nf) {
String str = "";
double floatingN = 1.0d / (double) MAX_RANGE;
for (int j = - MAX_RANGE; j <= MAX_RANGE; j++)
str = nf.format(floatingN * (double) j);
return str;
}
// This reproduces the throughput load added in benchFormatFractional
static double fractionalThroughputLoad() {
double d = 0.0d;
double floatingN = 1.0d / (double) MAX_RANGE;
for (int j = - MAX_RANGE; j <= MAX_RANGE; j++) {
d = floatingN * (double) j;
}
return d;
}
// Runs fractionalThroughputLoad and calculate its mean load
static void calculateFractionalThroughputLoad() {
int nbRuns = NB_RUNS;
long elapsedTime = 0;
double foo;
for (int i = 1; i <= nbRuns; i++) {
long startTime = System.nanoTime();
foo = fractionalThroughputLoad();
long estimatedTime = System.nanoTime() - startTime;
if (i > 3) elapsedTime += estimatedTime / 1000;
}
if (Verbose)
System.out.println(
"calculated throughput load for " + FRACTIONAL_BENCH +
" bench is = " + (elapsedTime / (nbRuns - 3)) + " microseconds");
}
// ---------- An Small Integral bench --------------------
// that limits the magnitude of tested double values
private static final String SMALL_INTEGRAL_BENCH = "benchFormatSmallIntegral";
private static String benchFormatSmallIntegral(NumberFormat nf) {
String str = "";
for (int j = - MAX_RANGE; j <= MAX_RANGE; j++)
str = nf.format(((double) j) / 1000.0d);
return str;
}
// This reproduces the throughput load added in benchFormatSmallIntegral
static double smallIntegralThroughputLoad() {
double d = 0.0d;
for (int j = - MAX_RANGE; j <= MAX_RANGE; j++) {
d = (double) j / 1000.0d;
}
return d;
}
// Runs small_integralThroughputLoad and calculate its mean load
static void calculateSmallIntegralThroughputLoad() {
int nbRuns = NB_RUNS;
long elapsedTime = 0;
double foo;
for (int i = 1; i <= nbRuns; i++) {
long startTime = System.nanoTime();
foo = smallIntegralThroughputLoad();
long estimatedTime = System.nanoTime() - startTime;
if (i > 3) elapsedTime += estimatedTime / 1000;
}
if (Verbose)
System.out.println(
"calculated throughput load for " + SMALL_INTEGRAL_BENCH +
" bench is = " + (elapsedTime / (nbRuns - 3)) + " microseconds");
}
// ---------- A fair and simple bench --------------------
private static final String FAIR_SIMPLE_BENCH = "benchFormatFairSimple";
private static String benchFormatFairSimple(NumberFormat nf, boolean isCurrency) {
String str = "";
double seed = isCurrency ? 0.0010203040506070809 : 0.00010203040506070809;
double d = (double) -MAX_RANGE;
for (int j = - MAX_RANGE; j <= MAX_RANGE; j++) {
d = d + 1.0d + seed;
str = nf.format(d);
}
return str;
}
// This reproduces the throughput load added in benchFormatFairSimple
static double fairSimpleThroughputLoad() {
double seed = 0.00010203040506070809;
double delta = 0.0d;
double d = (double) -MAX_RANGE;
for (int j = - MAX_RANGE; j <= MAX_RANGE; j++) {
d = d + 1.0d + seed;
}
return d;
}
// Runs fairThroughputLoad and calculate its mean load
static void calculateFairSimpleThroughputLoad() {
int nbRuns = NB_RUNS;
long elapsedTime = 0;
double foo;
for (int i = 1; i <= nbRuns; i++) {
long startTime = System.nanoTime();
foo = fairSimpleThroughputLoad();
long estimatedTime = System.nanoTime() - startTime;
if (i > 3) elapsedTime += estimatedTime / 1000;
}
if (Verbose)
System.out.println(
"calculated throughput load for " + FAIR_SIMPLE_BENCH +
" bench is = " + (elapsedTime / (nbRuns - 3)) + " microseconds");
}
// ---------- Fractional part is only made of nines bench --------------
private static final String FRACTIONAL_ALL_NINES_BENCH = "benchFormatFractionalAllNines";
private static String benchFormatFractionalAllNines(NumberFormat nf, boolean isCurrency) {
String str = "";
double fractionalEven = isCurrency ? 0.993000001 : 0.99930000001;
double fractionalOdd = isCurrency ? 0.996000001 : 0.99960000001;
double fractional;
double d;
for (int j = - MAX_RANGE; j <= MAX_RANGE; j++) {
if ((j & 1) == 0)
fractional = fractionalEven;
else
fractional = fractionalOdd;
if ( j >= 0)
d = (double ) j + fractional;
else d = (double) j - fractional;
str = nf.format(d);
}
return str;
}
// This reproduces the throughput load added in benchFormatFractionalAllNines
static double fractionalAllNinesThroughputLoad() {
double fractionalEven = 0.99930000001;
double fractionalOdd = 0.99960000001;
double fractional;
double d = 0.0d;
for (int j = - MAX_RANGE; j <= MAX_RANGE; j++) {
if ((j & 1) == 0)
fractional = fractionalEven;
else fractional = fractionalOdd;
if ( j >= 0)
d = (double ) j + fractional;
else d = (double) j - fractional;
}
return d;
}
// Runs fractionalAllNinesThroughputLoad and calculate its mean load
static void calculateFractionalAllNinesThroughputLoad() {
int nbRuns = NB_RUNS;
long elapsedTime = 0;
double foo;
for (int i = 1; i <= nbRuns; i++) {
long startTime = System.nanoTime();
foo = fractionalAllNinesThroughputLoad();
long estimatedTime = System.nanoTime() - startTime;
if (i > 3) elapsedTime += estimatedTime / 1000;
}
if (Verbose)
System.out.println(
"calculated throughput load for " + FRACTIONAL_ALL_NINES_BENCH +
" bench is = " + (elapsedTime / (nbRuns - 3)) + " microseconds");
}
// ---------- Number is only made of nines bench --------------
private static final String ALL_NINES_BENCH = "benchFormatAllNines";
private static String benchFormatAllNines(NumberFormat nf, boolean isCurrency) {
String str = "";
double[] decimaAllNines =
{9.9993, 99.9993, 999.9993, 9999.9993, 99999.9993,
999999.9993, 9999999.9993, 99999999.9993, 999999999.9993};
double[] currencyAllNines =
{9.993, 99.993, 999.993, 9999.993, 99999.993,
999999.993, 9999999.993, 99999999.993, 999999999.993};
double[] valuesArray = (isCurrency) ? currencyAllNines : decimaAllNines;
double seed = 1.0 / (double) MAX_RANGE;
double d;
int id;
for (int j = - MAX_RANGE; j <= MAX_RANGE; j++) {
id = (j >= 0) ? j % 9 : -j % 9;
if ((j & 1) == 0)
d = valuesArray[id] + id * seed;
else
d = valuesArray[id] - id * seed;
str = nf.format(d);
}
return str;
}
// This reproduces the throughput load added in benchFormatAllNines
static double allNinesThroughputLoad() {
double[] decimaAllNines =
{9.9993, 99.9993, 999.9993, 9999.9993, 99999.9993,
999999.9993, 9999999.9993, 99999999.9993, 999999999.9993};
double[] valuesArray = decimaAllNines;
double seed = 1.0 / (double) MAX_RANGE;
double d = 0.0d;
int id;
for (int j = - MAX_RANGE; j <= MAX_RANGE; j++) {
id = (j >= 0) ? j % 9 : -j % 9;
if ((j & 1) == 0)
d = valuesArray[id] + id * seed;
else
d = valuesArray[id] - id * seed;
}
return d;
}
// Runs allNinesThroughputLoad and calculate its mean load
static void calculateAllNinesThroughputLoad() {
int nbRuns = NB_RUNS;
long elapsedTime = 0;
double foo;
for (int i = 1; i <= nbRuns; i++) {
long startTime = System.nanoTime();
foo = allNinesThroughputLoad();
long estimatedTime = System.nanoTime() - startTime;
if (i > 3) elapsedTime += estimatedTime / 1000;
}
if (Verbose)
System.out.println(
"calculated throughput load for " + ALL_NINES_BENCH +
" bench is = " + (elapsedTime / (nbRuns - 3)) + " microseconds");
}
// --- A fair bench trying (hopefully) to reproduce business applicatons ---
/* benchFormatFair uses the following formula :
* y = F(x) = sign(x) * x**2 * ((1000/MAX_RANGE)**2).
*
* which converts in the loop as (if j is the loop index) :
* x = double(j)
* k = 1000.0d * double(MAX_RANGE)
* y = sign(j) * x**2 * k**2
*
* This is a flattened parabolic curve where only the j values
* in [-1000, 1000] will provide y results in [-1, +1] interval,
* and for abs(j) >= 1000 the result y will be greater than 1.
*
* The difference with benchFormatSmallIntegral is that since y results
* follow a parabolic curve the magnitude of y grows much more rapidly
* and closer to j values when abs(j) >= 1000:
* - for |j| < 1000, SmallIntegral(j) < 1.0 and fair(j) < 1.0
* - for j in [1000, 10000[
* SmallIntegral(j) is in [1, 10[
* Fair(j) is in [4, 400[
* - for j in [10000,100000[
* SmallIntegral(j) is in [10, 100[
* Fair(j) is in [400,40000[
* - for j in [100000,1000000[
* SmallIntegral(j) is in [100, 1000[
* Fair(j) is in [40000, 4000000[
*
* Since double values for j less than 100000 provide only 4 digits in the
* integral, values greater than 250000 provide at least 6 digits, and 500000
* computes to 1000000, the distribution is roughly half with less than 5
* digits and half with at least 6 digits in the integral part.
*
* Compared to FairSimple bench, this represents an application where 20% of
* the double values to format are less than 40000.0 absolute value.
*
* Fair(j) is close to the magnitude of j when j > 100000 and is hopefully
* more representative of what may be found in general in business apps.
* (assumption : there will be mainly either small or large values, and
* less values in middle range).
*
* We could get even more precise distribution of values using formula :
* y = sign(x) * abs(x)**n * ((1000 / MAX_RANGE)**n) where n > 2,
* or even well-known statistics function to fine target such distribution,
* but we have considred that the throughput load for calculating y would
* then be too high. We thus restrain the use of a power of 2 formula.
*/
private static final String FAIR_BENCH = "benchFormatFair";
private static String benchFormatFair(NumberFormat nf) {
String str = "";
double k = 1000.0d / (double) MAX_RANGE;
k *= k;
double d;
double absj;
double jPowerOf2;
for (int j = - MAX_RANGE; j <= MAX_RANGE; j++) {
absj = (double) j;
jPowerOf2 = absj * absj;
d = k * jPowerOf2;
if (j < 0) d = -d;
str = nf.format(d);
}
return str;
}
// This is the exact throughput load added in benchFormatFair
static double fairThroughputLoad() {
double k = 1000.0d / (double) MAX_RANGE;
k *= k;
double d = 0.0d;
double absj;
double jPowerOf2;
for (int j = - MAX_RANGE; j <= MAX_RANGE; j++) {
absj = (double) j;
jPowerOf2 = absj * absj;
d = k * jPowerOf2;
if (j < 0) d = -d;
}
return d;
}
// Runs fairThroughputLoad and calculate its mean load
static void calculateFairThroughputLoad() {
int nbRuns = NB_RUNS;
long elapsedTime = 0;
double foo;
for (int i = 1; i <= nbRuns; i++) {
long startTime = System.nanoTime();
foo = fairThroughputLoad();
long estimatedTime = System.nanoTime() - startTime;
if (i > 3) elapsedTime += estimatedTime / 1000;
}
if (Verbose)
System.out.println(
"calculated throughput load for " + FAIR_BENCH +
" bench is = " + (elapsedTime / (nbRuns - 3)) + " microseconds");
}
// ---------- All double values are very close to a tie --------------------
// i.e. like 123.1235 (for decimal case) or 123.125 (for currency case).
private static final String TIE_BENCH = "benchFormatTie";
private static String benchFormatTie(NumberFormat nf, boolean isCurrency) {
double d;
String str = "";
double fractionaScaling = (isCurrency) ? 1000.0d : 10000.0d;
int fixedFractionalPart = (isCurrency) ? 125 : 1235;
for (int j = - MAX_RANGE; j <= MAX_RANGE; j++) {
d = (((double) j * fractionaScaling) +
(double) fixedFractionalPart) / fractionaScaling;
str = nf.format(d);
}
return str;
}
// This is the exact throughput load added in benchFormatTie
static double tieThroughputLoad(boolean isCurrency) {
double d = 0.0d;
double fractionaScaling = (isCurrency) ? 1000.0d : 10000.0d;
int fixedFractionalPart = (isCurrency) ? 125 : 1235;
for (int j = - MAX_RANGE; j <= MAX_RANGE; j++) {
d = (((double) j * fractionaScaling) +
(double) fixedFractionalPart) / fractionaScaling;
}
return d;
}
// Runs tieThroughputLoad and calculate its mean load
static void calculateTieThroughputLoad(boolean isCurrency) {
int nbRuns = NB_RUNS;
long elapsedTime = 0;
double foo;
for (int i = 1; i <= nbRuns; i++) {
long startTime = System.nanoTime();
foo = tieThroughputLoad(isCurrency);
long estimatedTime = System.nanoTime() - startTime;
if (i > 3) elapsedTime += estimatedTime / 1000;
}
if (Verbose)
System.out.println(
"calculated throughput load for " + TIE_BENCH +
" bench is = " + (elapsedTime / (nbRuns - 3)) + " microseconds");
}
// Print statistics for passed times results of benchName.
static void printPerfResults(long[] times, String benchName) {
int nbBenches = times.length;
long totalTimeSpent = 0;
long meanTimeSpent;
double variance = 0;
double standardDeviation = 0;
// Calculates mean spent time
for (int i = 1; i <= nbBenches; i++)
totalTimeSpent += times[i-1];
meanTimeSpent = totalTimeSpent / nbBenches;
// Calculates standard deviation
for (int j = 1; j <= nbBenches; j++)
variance += Math.pow(((double)times[j-1] - (double)meanTimeSpent), 2);
variance = variance / (double) times.length;
standardDeviation = Math.sqrt(variance) / meanTimeSpent;
// Print result and statistics for benchName
System.out.println(
"Statistics (starting at 4th bench) for bench " + benchName +
"\n for last " + nbBenches +
" runs out of " + NB_RUNS +
" , each with 2x" + MAX_RANGE + " format(double) calls : " +
"\n mean exec time = " + meanTimeSpent + " microseconds" +
"\n standard deviation = " + String.format("%.3f", standardDeviation) + "% \n");
}
public static void main(String[] args) {
if (args.length >= 1) {
// Parse args, just checks expected ones. Ignore others or dups.
if (args[0].equals("-help")) {
usage();
return;
}
for (String s : args) {
if (s.equals("-doit"))
DoIt = true;
else if (s.equals("-verbose"))
Verbose = true;
}
} else {
// No arguments, skips the benchmarks and exits.
System.out.println(
"Test skipped with success by default. See -help for details.");
return;
}
if (!DoIt) {
if (Verbose)
usage();
System.out.println(
"Test skipped and considered successful.");
return;
}
System.out.println("Single Threaded micro benchmark evaluating " +
"the throughput of java.text.DecimalFormat.format() call stack.\n");
String fooString = "";
// Run benches for decimal instance
DecimalFormat df = (DecimalFormat) NumberFormat.getInstance(Locale.US);
System.out.println("Running with a decimal instance of DecimalFormat.");
calculateIntegerThroughputLoad();
fooString =
BenchType.INTEGER_BENCH.runBenchAndPrintStatistics(NB_RUNS, df, false);
calculateFractionalThroughputLoad();
fooString =
BenchType.FRACTIONAL_BENCH.runBenchAndPrintStatistics(NB_RUNS, df, false);
calculateSmallIntegralThroughputLoad();
fooString =
BenchType.SMALL_INTEGRAL_BENCH.runBenchAndPrintStatistics(NB_RUNS, df, false);
calculateFractionalAllNinesThroughputLoad();
fooString =
BenchType.FRACTIONAL_ALL_NINES_BENCH.runBenchAndPrintStatistics(NB_RUNS, df, false);
calculateAllNinesThroughputLoad();
fooString =
BenchType.ALL_NINES_BENCH.runBenchAndPrintStatistics(NB_RUNS, df, false);
calculateFairSimpleThroughputLoad();
fooString =
BenchType.FAIR_SIMPLE_BENCH.runBenchAndPrintStatistics(NB_RUNS, df, false);
calculateFairThroughputLoad();
fooString =
BenchType.FAIR_BENCH.runBenchAndPrintStatistics(NB_RUNS, df, false);
calculateTieThroughputLoad(false);
fooString =
BenchType.TIE_BENCH.runBenchAndPrintStatistics(NB_RUNS, df, false);
// Run benches for currency instance
DecimalFormat cf = (DecimalFormat) NumberFormat.getCurrencyInstance(Locale.US);
System.out.println("Running with a currency instance of DecimalFormat.");
calculateIntegerThroughputLoad();
fooString =
BenchType.INTEGER_BENCH.runBenchAndPrintStatistics(NB_RUNS, cf, false);
calculateFractionalThroughputLoad();
fooString =
BenchType.FRACTIONAL_BENCH.runBenchAndPrintStatistics(NB_RUNS, cf, false);
calculateSmallIntegralThroughputLoad();
fooString =
BenchType.SMALL_INTEGRAL_BENCH.runBenchAndPrintStatistics(NB_RUNS, cf, false);
calculateFractionalAllNinesThroughputLoad();
fooString =
BenchType.FRACTIONAL_ALL_NINES_BENCH.runBenchAndPrintStatistics(NB_RUNS, cf, false);
calculateAllNinesThroughputLoad();
fooString =
BenchType.ALL_NINES_BENCH.runBenchAndPrintStatistics(NB_RUNS, cf, false);
calculateFairSimpleThroughputLoad();
fooString =
BenchType.FAIR_SIMPLE_BENCH.runBenchAndPrintStatistics(NB_RUNS, cf, false);
calculateFairThroughputLoad();
fooString =
BenchType.FAIR_BENCH.runBenchAndPrintStatistics(NB_RUNS, cf, false);
calculateTieThroughputLoad(false);
fooString =
BenchType.TIE_BENCH.runBenchAndPrintStatistics(NB_RUNS, cf, false);
}
// This class to factorise what would be duplicated otherwise.
static enum BenchType {
INTEGER_BENCH("benchFormatInteger"),
FRACTIONAL_BENCH("benchFormatFractional"),
SMALL_INTEGRAL_BENCH("benchFormatSmallIntegral"),
FAIR_SIMPLE_BENCH("benchFormatFairSimple"),
FRACTIONAL_ALL_NINES_BENCH("benchFormatFractionalAllNines"),
ALL_NINES_BENCH("benchFormatAllNines"),
FAIR_BENCH("benchFormatFair"),
TIE_BENCH("benchFormatTie");
private final String name;
BenchType(String name) {
this.name = name;
}
String runBenchAndPrintStatistics(int nbRuns,
NumberFormat nf,
boolean isCurrency) {
// We eliminate the first 3 runs in the time measurements
// to let C2 do complete compilation and optimization work.
long[] elapsedTimes = new long[nbRuns - 3];
System.out.println("Now running " + nbRuns + " times bench " + name);
String str = "";
for (int i = 1; i <= nbRuns; i++) {
stabilizeMemory(false);
long startTime = System.nanoTime();
switch(this) {
case INTEGER_BENCH :
str = benchFormatInteger(nf);
break;
case FRACTIONAL_BENCH :
str = benchFormatFractional(nf);
break;
case SMALL_INTEGRAL_BENCH :
str = benchFormatSmallIntegral(nf);
break;
case FRACTIONAL_ALL_NINES_BENCH :
str = benchFormatFractionalAllNines(nf, isCurrency);
break;
case ALL_NINES_BENCH :
str = benchFormatAllNines(nf, isCurrency);
break;
case FAIR_SIMPLE_BENCH :
str = benchFormatFairSimple(nf, isCurrency);
break;
case FAIR_BENCH :
str = benchFormatFair(nf);
break;
case TIE_BENCH :
str = benchFormatTie(nf, isCurrency);
break;
default:
}
long estimatedTime = System.nanoTime() - startTime;
if (i > 3)
elapsedTimes[i-4] = estimatedTime / 1000;
if (Verbose)
System.out.println(
"calculated time for " + name +
" bench " + i + " is = " +
(estimatedTime / 1000) + " microseconds");
else System.out.print(".");
stabilizeMemory(true);
}
System.out.println(name + " Done.");
printPerfResults(elapsedTimes, name);
return str;
}
}
}

View file

@ -0,0 +1,965 @@
/*
* Copyright (c) 2012, 2022, 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.
*/
/* Set of constants and values used in RoundingAndPropertyTest.java.
*
* There are 5 different information in this class:
* - TestLocale is the locale used by RoundingAndPropertyTest regression test
* when calling DecimalFormat.format() on either the set of DecimalGoldenValues
* or CurrencyGoldenValues.
* See main method of RoundingAndPropertyTest.
*
* - FullLocalizationTestLocale is the locale used by RoundingAndPropertyTest
* regression test when calling DecimalFormat.format() on the set of values
* (DecimalLocalizationValues) used to test that localization of digits
* happens correctly when needed.
* See main method of RoundingAndPropertyTest.
*
* - DecimalLocalizationValues is an array containing all the double values used
* to check that localization of digits happens correctly when needed.
* See RoundingAndPropertyTest.testLocalizationValues() method.
*
* - DecimalGoldenValues and CurrencyGoldenValues are arrays containing all the
* double values that will be used as input when checking correctness of
* results returned by DecimalFormat.format().
* 2 arrays are needed since decimal and currency formatting patterns require
* a different number of digits after decimal point.
* See RoundingAndPropertyTest.testGoldenValues() method.
*
* - PROPERTY_CHECK_POSITIVE_VALUE and PROPERTY_CHECK_NEGATIVE_VALUE are the
* double values used for testing the validity of the property changes call
* in the fast-path case. The locale used in that case is TestLocale.
* See RoundingAndPropertyTest.testSettersAndFastPath() method.
*/
import java.util.*;
class GoldenDoubleValues {
// TestLocale is the testing locale used by RoundingAndPropertyTest test,
// when testing the golden double values
static final Locale TestLocale = Locale.US;
// FullTestLocale is the testing locale used by RoundingAndPropertyTest test,
// when testing full localization of double values.
static final Locale FullLocalizationTestLocale = Locale.of("hi", "IN");
/* Below are the two double values used for exercising the changes of
* of DecimalFormat properties and symbols. These values are also used
* as golden values (see golden arrays below).
*/
/* PROPERTY_CHECK_NEGATIVE_VALUE is the negative double value used for
* testing the validity of the property changes for fast-path.
* See testSettersAndFastPath() in RoundingAndPropertyTest test.
*/
static final double PROPERTY_CHECK_NEGATIVE_VALUE = -2147483646.2334997d;
/* PROPERTY_CHECK_POSITIVE_VALUE is the positive double value used for
* testing the validity of the property changes for fast-path.
* See testSettersAndFastPath() in RoundingAndPropertyTest test.
*/
static final double PROPERTY_CHECK_POSITIVE_VALUE = 2147483646.2335003d;
/* --- Array of double values to test localization ------------------------
*
* For most locales, effective localization does not happen on digits, i.e.
* the digits are not changed due to localization. In order to check that
* fast-path localize correctly digits in such a case, the array of double
* values below deals with all the case of localization that may happen on
* digits
*/
static final double[] DecimalLocalizationValues = {
1.123,
12.123,
123.123,
1234.123,
12345.123,
123456.123,
1234567.123,
12345678.123,
123456789.123,
1234567890.123,
1234.0,
1234.9,
1234.99,
1234.999
};
/* --- Arrays of golden double values ----------------------------------
*
* The GoldenValues arrays are used as input values for checking the
* correctness of the DecimalFormat.format() call results done in
* RoundingAndPropertyTest regression test. The results are compared to the
* expected ones found in GoldenFormattedValues. For each value in the
* arrays there is a corresponding expected string result found,
* represented as an array of unicode values, at the same index in the
* related GoldenFormattedValues array. The string returned by the format
* call and the found in GoldenFormattedValues array must be equal for the
* result to be considered valid.
* See RoundingAndPropertyTest.testGoldenValues() method.
*
* We need 2 such GoldenValues arrays since the decimal and currency
* formatting rules require different number of digits after decimal point.
*
* Thus we have two different arrays of golden values:
* - DecimalGoldenValues for the decimal case.
* - CurrencyGoldenValues for the currency case.
*
* They are associated to related GoldenFormattedValues arrays, generated by
* running RoundingAndPropertyTest with a "gengold" argument:
* - DecimalGoldenFormattedValues for the decimal case.
* - CurrencyGoldenFormattedValues for the currency case.
* These two generated arrays are found in GoldenFormattedValues.java file.
*
* The impact of the formatting rules is as follows, because the pattern
* rule for the fractional part is different for decimal and currency
* patterns:
* - in decimal case one must output the first non-zero 3 digits of
* fractional part 1.1232 => "1.123" and 1.12016789 => "1.12"
* - in currency case the first 2 fractional digits are always output
* 1.1232 => "1.12" and 1.0016789 => "1.00"
*
* Thus we need a different number of fractional digits when we specify
* below the golden double values to check, and most of the decimal and
* currency golden values differ only in the number of fractional digits.
*
* The list below exercises almost all code pathes of the fast-path
* algorithm except localization of digits.
*/
// --- The set of golden values for the Decimal formatting case --------
static final double[] DecimalGoldenValues = {
// Testing of specific values
+0.0,
-0.0,
Double.MIN_VALUE,
Double.MIN_NORMAL,
PROPERTY_CHECK_NEGATIVE_VALUE,
PROPERTY_CHECK_POSITIVE_VALUE,
-2147483647.9996,
2147483647.9996,
-1999999999.9994997,
1999999999.9995003,
// Testing fast-path range checks (all outside bounds)
Double.NaN,
Double.POSITIVE_INFINITY,
Double.NEGATIVE_INFINITY,
Double.MAX_VALUE,
-9876543210.9876543,
9876543210.9876543,
-1234567890.1234567E128,
1234567890.1234567E128,
// Testing of integral string size
1.123,
12.123,
123.123,
1234.123,
12345.123,
123456.123,
1234567.123,
12345678.123,
123456789.123,
1234567890.123,
-1.123,
-12.123,
-123.123,
-1234.123,
-12345.123,
-123456.123,
-1234567.123,
-12345678.123,
-123456789.123,
-1234567890.123,
// Testing of fractional string size
0.1,
0.12,
0.123,
0.1234,
10.1,
10.12,
10.123,
10.1234,
100.1,
100.12,
100.123,
100.1234,
1000.1,
1000.12,
1000.123,
1000.1234,
10000.1,
10000.12,
10000.123,
10000.1234,
100000.1,
100000.12,
100000.123,
100000.1234,
1000000.1,
1000000.12,
1000000.123,
1000000.1234,
10000000.1,
10000000.12,
10000000.123,
10000000.1234,
100000000.1,
100000000.12,
100000000.123,
100000000.1234,
1000000000.1,
1000000000.12,
1000000000.123,
1000000000.1234,
-0.1,
-0.12,
-0.123,
-0.1234,
-10.1,
-10.12,
-10.123,
-10.1234,
-100.1,
-100.12,
-100.123,
-100.1234,
-1000.1,
-1000.12,
-1000.123,
-1000.1234,
-10000.1,
-10000.12,
-10000.123,
-10000.1234,
-100000.1,
-100000.12,
-100000.123,
-100000.1234,
-1000000.1,
-1000000.12,
-1000000.123,
-1000000.1234,
-10000000.1,
-10000000.12,
-10000000.123,
-10000000.1234,
-100000000.1,
-100000000.12,
-100000000.123,
-100000000.1234,
-1000000000.1,
-1000000000.12,
-1000000000.123,
-1000000000.1234,
// Testing of special rounding cases
1.9993,
12.9993,
123.9993,
1234.9993,
12345.9993,
123456.9993,
1234567.9993,
12345678.9993,
123456789.9993,
1234567890.9993,
1.9996,
12.9996,
123.9996,
1234.9996,
12345.9996,
123456.9996,
1234567.9996,
12345678.9996,
123456789.9996,
1234567890.9996,
-1.9993,
-12.9993,
-123.9993,
-1234.9993,
-12345.9993,
-123456.9993,
-1234567.9993,
-12345678.9993,
-123456789.9993,
-1234567890.9993,
-1.9996,
-12.9996,
-123.9996,
-1234.9996,
-12345.9996,
-123456.9996,
-1234567.9996,
-12345678.9996,
-123456789.9996,
-1234567890.9996,
109.9996,
1099.9996,
10999.9996,
109999.9996,
1099999.9996,
10999999.9996,
109999999.9996,
1099999999.9996,
-109.9996,
-1099.9996,
-10999.9996,
-109999.9996,
-1099999.9996,
-10999999.9996,
-109999999.9996,
-1099999999.9996,
1.9996,
19.9996,
199.9996,
1999.9996,
19999.9996,
199999.9996,
1999999.9996,
19999999.9996,
199999999.9996,
1999999999.9996,
-1.9996,
-19.9996,
-199.9996,
-1999.9996,
-19999.9996,
-199999.9996,
-1999999.9996,
-19999999.9996,
-199999999.9996,
-1999999999.9996,
// Testing for all nines cases
9.9996,
99.9996,
999.9996,
9999.9996,
99999.9996,
999999.9996,
9999999.9996,
99999999.9996,
999999999.9996,
9.999,
99.999,
999.999,
9999.999,
99999.999,
999999.999,
9999999.999,
99999999.999,
999999999.999,
-9.9996,
-99.9996,
-999.9996,
-9999.9996,
-99999.9996,
-999999.9996,
-9999999.9996,
-99999999.9996,
-999999999.9996,
-9.999,
-99.999,
-999.999,
-9999.999,
-99999.999,
-999999.999,
-9999999.999,
-99999999.999,
-999999999.999,
// Testing for no Fractional part cases
1.0,
12.0,
123.0,
1234.0,
12345.0,
123456.0,
1234567.0,
12345678.0,
123456789.0,
1234567890.0,
-1.0,
-12.0,
-123.0,
-1234.0,
-12345.0,
-123456.0,
-1234567.0,
-12345678.0,
-123456789.0,
-1234567890.0,
// Testing of tricky cases
-2599.399999990123,
-2599.339999990123,
-2599.333999990123,
1.000099999999818,
1.000199999999818,
1.000299999999818,
1.000399999999818,
1.000499999999818,
1.000599999999818,
1.000699999999818,
1.000799999999818,
1.000899999999818,
1.000999999999818,
1.2224999999999980,
1.2224999999999981,
1.2224999999999982,
1.2224999999999983,
1.2224999999999984,
1.2224999999999985,
1.2224999999999986,
1.2224999999999987,
1.2224999999999988,
1.2224999999999989,
1.2224999999999990,
1.2224999999999991,
1.2224999999999992,
1.2224999999999993,
1.2224999999999994,
1.2224999999999995,
1.2224999999999996,
1.2224999999999997,
1.2224999999999998,
// 1.2225 and 1.2224999999999999 have the same double approximation
1.2225,
1.2225000000000001,
1.2225000000000002,
1.2225000000000003,
1.2225000000000004,
1.2225000000000005,
1.2225000000000006,
1.2225000000000007,
1.2225000000000008,
1.2225000000000009,
1.2225000000000010,
1.2225000000000011,
1.2225000000000012,
1.2225000000000013,
1.2225000000000014,
1.2225000000000015,
1.2225000000000016,
1.2225000000000017,
1.2225000000000018,
1.2225000000000019,
// Tricky rounding cases around tie values
100913.67050000005,
199999.99895901306,
251846.3465,
253243.8825000001,
365045.85349999997,
314734.9615,
541133.9755,
858372.1225,
1000999.9995000001,
1347505.7825,
3358844.1975,
9997979.4085,
9993743.1585,
9938671.9085,
3385302.5465,
3404642.6605,
3431280.0865,
3438756.4754999997,
3446053.7874999996,
3457917.5125,
3465393.9014999997,
3484734.0154999997,
3492031.3274999997,
3503895.0525,
3511371.4414999997,
3518668.7534999996,
3530532.4785,
3538008.8674999997,
3545306.1794999996,
3557169.9045,
3557348.9814999998,
3564646.2934999997,
3583986.4074999997,
3591283.7194999997,
3603147.4445,
3610623.8334999997,
3617921.1454999996,
3629784.8705,
3637261.2594999997,
3656422.2965,
3656601.3734999998,
3663898.6854999997,
3675762.4105,
3683238.7994999997,
3690536.1114999996,
3702399.8365,
3709876.2254999997,
3717173.5374999996,
3729037.2625,
3736513.6514999997,
3755853.7654999997,
3763151.0774999997,
3775014.8025,
3782491.1914999997,
3789788.5034999996,
3801652.2285,
3809128.6174999997,
3816425.9294999996,
3828289.6545,
3828468.7314999998,
3835766.0434999997,
3855106.1574999997,
3862403.4694999997,
3874267.1945,
3881743.5834999997,
3889040.8954999996,
3900904.6205,
3908381.0094999997,
3927542.0465,
3927721.1234999998,
3935018.4354999997,
3946882.1605,
3954358.5494999997,
3961655.8614999996,
3973519.5865,
3980995.9754999997,
3988293.2874999996,
4000157.0125,
4007633.4014999997,
4026973.5154999997,
4034270.8274999997,
4046134.5525,
4053610.9414999997,
4060908.2534999996,
4072771.9785,
4080248.3674999997,
4087545.6794999996,
4099409.4045,
4099588.4814999998,
4106885.7934999997,
4126225.9074999997,
4133523.2194999997,
4145386.9445,
4152863.3334999997,
4160160.6454999996,
4172024.3705,
4179500.7594999997,
4198661.7965,
4203407.2865,
4210704.5985,
4213435.4975
};
// --- The set of golden values for the currency formatting case --------
static final double[] CurrencyGoldenValues = {
// Testing of specific values
+0.0,
-0.0,
Double.MIN_VALUE,
Double.MIN_NORMAL,
PROPERTY_CHECK_NEGATIVE_VALUE,
PROPERTY_CHECK_POSITIVE_VALUE,
-2147483647.996,
2147483647.996,
-1999999999.9949997,
1999999999.9950003,
// Testing fast-path range checks (all outside bounds)
Double.NaN,
Double.POSITIVE_INFINITY,
Double.NEGATIVE_INFINITY,
Double.MAX_VALUE,
-9876543210.9876543,
9876543210.9876543,
-1234567890.1234567E128,
1234567890.1234567E128,
// Testing of integral string size
1.12,
12.12,
123.12,
1234.12,
12345.12,
123456.12,
1234567.12,
12345678.12,
123456789.12,
1234567890.12,
-1.12,
-12.12,
-123.12,
-1234.12,
-12345.12,
-123456.12,
-1234567.12,
-12345678.12,
-123456789.12,
-1234567890.12,
// Testing of fractional string size
0.1,
0.12,
0.123,
10.1,
10.12,
10.123,
100.1,
100.12,
100.123,
1000.1,
1000.12,
1000.123,
10000.1,
10000.12,
10000.123,
100000.1,
100000.12,
100000.123,
1000000.1,
1000000.12,
1000000.123,
10000000.1,
10000000.12,
10000000.123,
100000000.1,
100000000.12,
100000000.123,
1000000000.1,
1000000000.12,
1000000000.123,
-0.1,
-0.12,
-0.123,
-10.1,
-10.12,
-10.123,
-100.1,
-100.12,
-100.123,
-1000.1,
-1000.12,
-1000.123,
-10000.1,
-10000.12,
-10000.123,
-100000.1,
-100000.12,
-100000.123,
-1000000.1,
-1000000.12,
-1000000.123,
-10000000.1,
-10000000.12,
-10000000.123,
-100000000.1,
-100000000.12,
-100000000.123,
-1000000000.1,
-1000000000.12,
-1000000000.123,
// Testing of special rounding cases
1.993,
12.993,
123.993,
1234.993,
12345.993,
123456.993,
1234567.993,
12345678.993,
123456789.993,
1234567890.993,
1.996,
12.996,
123.996,
1234.996,
12345.996,
123456.996,
1234567.996,
12345678.996,
123456789.996,
1234567890.996,
-1.993,
-12.993,
-123.993,
-1234.993,
-12345.993,
-123456.993,
-1234567.993,
-12345678.993,
-123456789.993,
-1234567890.993,
-1.996,
-12.996,
-123.996,
-1234.996,
-12345.996,
-123456.996,
-1234567.996,
-12345678.996,
-123456789.996,
-1234567890.996,
109.996,
1099.996,
10999.996,
109999.996,
1099999.996,
10999999.996,
109999999.996,
1099999999.996,
-109.996,
-1099.996,
-10999.996,
-109999.996,
-1099999.996,
-10999999.996,
-109999999.996,
-1099999999.996,
1.996,
19.996,
199.996,
1999.996,
19999.996,
199999.996,
1999999.996,
19999999.996,
199999999.996,
1999999999.996,
-1.996,
-19.996,
-199.996,
-1999.996,
-19999.996,
-199999.996,
-1999999.996,
-19999999.996,
-199999999.996,
-1999999999.996,
// Testing of all nines cases
9.996,
99.996,
999.996,
9999.996,
99999.996,
999999.996,
9999999.996,
99999999.996,
999999999.996,
9.99,
99.99,
999.99,
9999.99,
99999.99,
999999.99,
9999999.99,
99999999.99,
999999999.99,
-9.996,
-99.996,
-999.996,
-9999.996,
-99999.996,
-999999.996,
-9999999.996,
-99999999.996,
-999999999.996,
-9.99,
-99.99,
-999.99,
-9999.99,
-99999.99,
-999999.99,
-9999999.99,
-99999999.99,
-999999999.99,
// Testing of no Fractional part cases
1.0,
12.0,
123.0,
1234.0,
12345.0,
123456.0,
1234567.0,
12345678.0,
123456789.0,
1234567890.0,
-1.0,
-12.0,
-123.0,
-1234.0,
-12345.0,
-123456.0,
-1234567.0,
-12345678.0,
-123456789.0,
-1234567890.0,
// Testing of tricky cases
-2599.399999990123,
-2599.339999990123,
-2599.333999990123,
1.000999999999818,
1.001999999999818,
1.002999999999818,
1.003999999999818,
1.004999999999818,
1.005999999999818,
1.006999999999818,
1.007999999999818,
1.008999999999818,
1.009999999999818,
1.224999999999980,
1.224999999999981,
1.224999999999982,
1.224999999999983,
1.224999999999984,
1.224999999999985,
1.224999999999986,
1.224999999999987,
1.224999999999988,
1.224999999999989,
1.224999999999990,
1.224999999999991,
1.224999999999992,
1.224999999999993,
1.224999999999994,
1.224999999999995,
1.224999999999996,
1.224999999999997,
1.224999999999998,
1.224999999999999,
1.225,
1.225000000000001,
1.225000000000002,
1.225000000000003,
1.225000000000004,
1.225000000000005,
1.225000000000006,
1.225000000000007,
1.225000000000008,
1.225000000000009,
1.225000000000010,
1.225000000000011,
1.225000000000012,
1.225000000000013,
1.225000000000014,
1.225000000000015,
1.225000000000016,
1.225000000000017,
1.225000000000018,
1.225000000000019,
// Tricky rounding cases around tie values
1009136.7050000005,
2518463.465,
2532438.825000001,
3650458.5349999997,
3147349.615,
5411339.755,
8583721.225,
13475057.825,
33588441.975,
99979794.085,
99937431.585,
99386719.085,
33853025.465,
34046426.605,
34312800.865,
34387564.754999997,
34460537.874999996,
34579175.125,
34653939.014999997,
34847340.154999997,
34920313.274999997,
35038950.525,
35113714.414999997,
35186687.534999996,
35305324.785,
35380088.674999997,
35453061.794999996,
35571699.045,
35573489.814999998,
35646462.934999997,
35839864.074999997,
35912837.194999997,
36031474.445,
36106238.334999997,
36179211.454999996,
36297848.705,
36372612.594999997,
36564222.965,
36566013.734999998,
36638986.854999997,
36757624.105,
36832387.994999997,
36905361.114999996,
37023998.365,
37098762.254999997,
37171735.374999996,
37290372.625,
37365136.514999997,
37558537.654999997,
37631510.774999997,
37750148.025,
37824911.914999997,
37897885.034999996,
38016522.285,
38091286.174999997,
38164259.294999996,
38282896.545,
38284687.314999998,
38357660.434999997,
38551061.574999997,
38624034.694999997,
38742671.945,
38817435.834999997,
38890408.954999996,
39009046.205,
39083810.094999997,
39275420.465,
39277211.234999998,
39350184.354999997,
39468821.605,
39543585.494999997,
39616558.614999996,
39735195.865,
39809959.754999997,
39882932.874999996,
40001570.125,
40076334.014999997,
40269735.154999997,
40342708.274999997,
40461345.525,
40536109.414999997,
40609082.534999996,
40727719.785,
40802483.674999997,
40875456.794999996,
40994094.045,
40995884.814999998,
41068857.934999997,
41262259.074999997,
41335232.194999997,
41453869.445,
41528633.334999997,
41601606.454999996,
41720243.705,
41795007.594999997,
41986617.965,
42034072.865,
42107045.985,
42134354.975
};
}

View file

@ -0,0 +1,868 @@
/*
* Copyright (c) 2012, 2015, 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.
*/
/* This is a machine generated file - Please DO NOT EDIT !
* Change RoundingAndPropertyTest instead,
* and run with "-gengold" argument to regenerate (without copyright header).
*/
/* This file contains the set of result Strings expected from calling inside
* RoundingAndPropertyTest the method NumberFormat.format() upon the set of
* double values provided in GoldenDoubleValues.java. It contains three arrays,
* each containing arrays of unicode values representing the expected string
* result when calling format() on the corresponding (i.e. same index) double
* value found in GoldenDoubleValues arrays :
* - DecimalDigitsLocalizedFormattedValues corresponds to DecimalLocalizationValues,
* when using FullLocalizationTestLocale to format.
* - DecimalGoldenFormattedValues corresponds to DecimalGoldenValues, when used
* in the decimal pattern case together with TestLocale.
* - CurrencyGoldenFormattedValues corresponds to CurrencyGoldenValues. when used
* in the currency pattern case together with TestLocale.
* Please see documentation in RoundingAndPropertyTest.java for more details.
*
* This file generated by running RoundingAndPropertyTest with "-gengold" argument.
*/
class GoldenFormattedValues {
// The formatted values below were generated from golden values
// listed in GoldenDoubleValues.java, using the following jvm version :
// Oracle Corporation Java HotSpot(TM) 64-Bit Server VM 1.9.0-internal-fastdebug
// locale for golden double values : en_US
// locale for testing digit localization : hi_IN
// The array of int[] unicode values storing the expected results
// when experiencing full localization of digits on DecimalLocalizationValues.
static int[][] DecimalDigitsLocalizedFormattedValues = {
{ 49, 46, 49, 50, 51 },
{ 49, 50, 46, 49, 50, 51 },
{ 49, 50, 51, 46, 49, 50, 51 },
{ 49, 44, 50, 51, 52, 46, 49, 50, 51 },
{ 49, 50, 44, 51, 52, 53, 46, 49, 50, 51 },
{ 49, 50, 51, 44, 52, 53, 54, 46, 49, 50, 51 },
{ 49, 44, 50, 51, 52, 44, 53, 54, 55, 46, 49, 50, 51 },
{ 49, 50, 44, 51, 52, 53, 44, 54, 55, 56, 46, 49, 50, 51 },
{ 49, 50, 51, 44, 52, 53, 54, 44, 55, 56, 57, 46, 49, 50, 51 },
{ 49, 44, 50, 51, 52, 44, 53, 54, 55, 44, 56, 57, 48, 46, 49, 50, 51 },
{ 49, 44, 50, 51, 52 },
{ 49, 44, 50, 51, 52, 46, 57 },
{ 49, 44, 50, 51, 52, 46, 57, 57 },
{ 49, 44, 50, 51, 52, 46, 57, 57, 57 },
};
// The array of int[] unicode values storing the expected results
// when calling Decimal.format(double) on the decimal GoldenDoubleValues.
static int[][] DecimalGoldenFormattedValues = {
{ 48 },
{ 45, 48 },
{ 48 },
{ 48 },
{ 45, 50, 44, 49, 52, 55, 44, 52, 56, 51, 44, 54, 52, 54, 46, 50, 51, 51 },
{ 50, 44, 49, 52, 55, 44, 52, 56, 51, 44, 54, 52, 54, 46, 50, 51, 52 },
{ 45, 50, 44, 49, 52, 55, 44, 52, 56, 51, 44, 54, 52, 56 },
{ 50, 44, 49, 52, 55, 44, 52, 56, 51, 44, 54, 52, 56 },
{ 45, 49, 44, 57, 57, 57, 44, 57, 57, 57, 44, 57, 57, 57, 46, 57, 57, 57 },
{ 50, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48 },
{ 78, 97, 78 },
{ 8734 },
{ 45, 8734 },
{ 49, 55, 57, 44, 55, 54, 57, 44, 51, 49, 51, 44, 52, 56, 54, 44, 50, 51, 49, 44, 53, 55, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48 },
{ 45, 57, 44, 56, 55, 54, 44, 53, 52, 51, 44, 50, 49, 48, 46, 57, 56, 56 },
{ 57, 44, 56, 55, 54, 44, 53, 52, 51, 44, 50, 49, 48, 46, 57, 56, 56 },
{ 45, 49, 50, 51, 44, 52, 53, 54, 44, 55, 56, 57, 44, 48, 49, 50, 44, 51, 52, 53, 44, 54, 55, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48 },
{ 49, 50, 51, 44, 52, 53, 54, 44, 55, 56, 57, 44, 48, 49, 50, 44, 51, 52, 53, 44, 54, 55, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48 },
{ 49, 46, 49, 50, 51 },
{ 49, 50, 46, 49, 50, 51 },
{ 49, 50, 51, 46, 49, 50, 51 },
{ 49, 44, 50, 51, 52, 46, 49, 50, 51 },
{ 49, 50, 44, 51, 52, 53, 46, 49, 50, 51 },
{ 49, 50, 51, 44, 52, 53, 54, 46, 49, 50, 51 },
{ 49, 44, 50, 51, 52, 44, 53, 54, 55, 46, 49, 50, 51 },
{ 49, 50, 44, 51, 52, 53, 44, 54, 55, 56, 46, 49, 50, 51 },
{ 49, 50, 51, 44, 52, 53, 54, 44, 55, 56, 57, 46, 49, 50, 51 },
{ 49, 44, 50, 51, 52, 44, 53, 54, 55, 44, 56, 57, 48, 46, 49, 50, 51 },
{ 45, 49, 46, 49, 50, 51 },
{ 45, 49, 50, 46, 49, 50, 51 },
{ 45, 49, 50, 51, 46, 49, 50, 51 },
{ 45, 49, 44, 50, 51, 52, 46, 49, 50, 51 },
{ 45, 49, 50, 44, 51, 52, 53, 46, 49, 50, 51 },
{ 45, 49, 50, 51, 44, 52, 53, 54, 46, 49, 50, 51 },
{ 45, 49, 44, 50, 51, 52, 44, 53, 54, 55, 46, 49, 50, 51 },
{ 45, 49, 50, 44, 51, 52, 53, 44, 54, 55, 56, 46, 49, 50, 51 },
{ 45, 49, 50, 51, 44, 52, 53, 54, 44, 55, 56, 57, 46, 49, 50, 51 },
{ 45, 49, 44, 50, 51, 52, 44, 53, 54, 55, 44, 56, 57, 48, 46, 49, 50, 51 },
{ 48, 46, 49 },
{ 48, 46, 49, 50 },
{ 48, 46, 49, 50, 51 },
{ 48, 46, 49, 50, 51 },
{ 49, 48, 46, 49 },
{ 49, 48, 46, 49, 50 },
{ 49, 48, 46, 49, 50, 51 },
{ 49, 48, 46, 49, 50, 51 },
{ 49, 48, 48, 46, 49 },
{ 49, 48, 48, 46, 49, 50 },
{ 49, 48, 48, 46, 49, 50, 51 },
{ 49, 48, 48, 46, 49, 50, 51 },
{ 49, 44, 48, 48, 48, 46, 49 },
{ 49, 44, 48, 48, 48, 46, 49, 50 },
{ 49, 44, 48, 48, 48, 46, 49, 50, 51 },
{ 49, 44, 48, 48, 48, 46, 49, 50, 51 },
{ 49, 48, 44, 48, 48, 48, 46, 49 },
{ 49, 48, 44, 48, 48, 48, 46, 49, 50 },
{ 49, 48, 44, 48, 48, 48, 46, 49, 50, 51 },
{ 49, 48, 44, 48, 48, 48, 46, 49, 50, 51 },
{ 49, 48, 48, 44, 48, 48, 48, 46, 49 },
{ 49, 48, 48, 44, 48, 48, 48, 46, 49, 50 },
{ 49, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 },
{ 49, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 },
{ 49, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49 },
{ 49, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 },
{ 49, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 },
{ 49, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 },
{ 49, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49 },
{ 49, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 },
{ 49, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 },
{ 49, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 },
{ 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49 },
{ 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 },
{ 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 },
{ 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 },
{ 49, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49 },
{ 49, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 },
{ 49, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 },
{ 49, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 },
{ 45, 48, 46, 49 },
{ 45, 48, 46, 49, 50 },
{ 45, 48, 46, 49, 50, 51 },
{ 45, 48, 46, 49, 50, 51 },
{ 45, 49, 48, 46, 49 },
{ 45, 49, 48, 46, 49, 50 },
{ 45, 49, 48, 46, 49, 50, 51 },
{ 45, 49, 48, 46, 49, 50, 51 },
{ 45, 49, 48, 48, 46, 49 },
{ 45, 49, 48, 48, 46, 49, 50 },
{ 45, 49, 48, 48, 46, 49, 50, 51 },
{ 45, 49, 48, 48, 46, 49, 50, 51 },
{ 45, 49, 44, 48, 48, 48, 46, 49 },
{ 45, 49, 44, 48, 48, 48, 46, 49, 50 },
{ 45, 49, 44, 48, 48, 48, 46, 49, 50, 51 },
{ 45, 49, 44, 48, 48, 48, 46, 49, 50, 51 },
{ 45, 49, 48, 44, 48, 48, 48, 46, 49 },
{ 45, 49, 48, 44, 48, 48, 48, 46, 49, 50 },
{ 45, 49, 48, 44, 48, 48, 48, 46, 49, 50, 51 },
{ 45, 49, 48, 44, 48, 48, 48, 46, 49, 50, 51 },
{ 45, 49, 48, 48, 44, 48, 48, 48, 46, 49 },
{ 45, 49, 48, 48, 44, 48, 48, 48, 46, 49, 50 },
{ 45, 49, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 },
{ 45, 49, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 },
{ 45, 49, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49 },
{ 45, 49, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 },
{ 45, 49, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 },
{ 45, 49, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 },
{ 45, 49, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49 },
{ 45, 49, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 },
{ 45, 49, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 },
{ 45, 49, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 },
{ 45, 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49 },
{ 45, 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 },
{ 45, 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 },
{ 45, 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 },
{ 45, 49, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49 },
{ 45, 49, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 },
{ 45, 49, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 },
{ 45, 49, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50, 51 },
{ 49, 46, 57, 57, 57 },
{ 49, 50, 46, 57, 57, 57 },
{ 49, 50, 51, 46, 57, 57, 57 },
{ 49, 44, 50, 51, 52, 46, 57, 57, 57 },
{ 49, 50, 44, 51, 52, 53, 46, 57, 57, 57 },
{ 49, 50, 51, 44, 52, 53, 54, 46, 57, 57, 57 },
{ 49, 44, 50, 51, 52, 44, 53, 54, 55, 46, 57, 57, 57 },
{ 49, 50, 44, 51, 52, 53, 44, 54, 55, 56, 46, 57, 57, 57 },
{ 49, 50, 51, 44, 52, 53, 54, 44, 55, 56, 57, 46, 57, 57, 57 },
{ 49, 44, 50, 51, 52, 44, 53, 54, 55, 44, 56, 57, 48, 46, 57, 57, 57 },
{ 50 },
{ 49, 51 },
{ 49, 50, 52 },
{ 49, 44, 50, 51, 53 },
{ 49, 50, 44, 51, 52, 54 },
{ 49, 50, 51, 44, 52, 53, 55 },
{ 49, 44, 50, 51, 52, 44, 53, 54, 56 },
{ 49, 50, 44, 51, 52, 53, 44, 54, 55, 57 },
{ 49, 50, 51, 44, 52, 53, 54, 44, 55, 57, 48 },
{ 49, 44, 50, 51, 52, 44, 53, 54, 55, 44, 56, 57, 49 },
{ 45, 49, 46, 57, 57, 57 },
{ 45, 49, 50, 46, 57, 57, 57 },
{ 45, 49, 50, 51, 46, 57, 57, 57 },
{ 45, 49, 44, 50, 51, 52, 46, 57, 57, 57 },
{ 45, 49, 50, 44, 51, 52, 53, 46, 57, 57, 57 },
{ 45, 49, 50, 51, 44, 52, 53, 54, 46, 57, 57, 57 },
{ 45, 49, 44, 50, 51, 52, 44, 53, 54, 55, 46, 57, 57, 57 },
{ 45, 49, 50, 44, 51, 52, 53, 44, 54, 55, 56, 46, 57, 57, 57 },
{ 45, 49, 50, 51, 44, 52, 53, 54, 44, 55, 56, 57, 46, 57, 57, 57 },
{ 45, 49, 44, 50, 51, 52, 44, 53, 54, 55, 44, 56, 57, 48, 46, 57, 57, 57 },
{ 45, 50 },
{ 45, 49, 51 },
{ 45, 49, 50, 52 },
{ 45, 49, 44, 50, 51, 53 },
{ 45, 49, 50, 44, 51, 52, 54 },
{ 45, 49, 50, 51, 44, 52, 53, 55 },
{ 45, 49, 44, 50, 51, 52, 44, 53, 54, 56 },
{ 45, 49, 50, 44, 51, 52, 53, 44, 54, 55, 57 },
{ 45, 49, 50, 51, 44, 52, 53, 54, 44, 55, 57, 48 },
{ 45, 49, 44, 50, 51, 52, 44, 53, 54, 55, 44, 56, 57, 49 },
{ 49, 49, 48 },
{ 49, 44, 49, 48, 48 },
{ 49, 49, 44, 48, 48, 48 },
{ 49, 49, 48, 44, 48, 48, 48 },
{ 49, 44, 49, 48, 48, 44, 48, 48, 48 },
{ 49, 49, 44, 48, 48, 48, 44, 48, 48, 48 },
{ 49, 49, 48, 44, 48, 48, 48, 44, 48, 48, 48 },
{ 49, 44, 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48 },
{ 45, 49, 49, 48 },
{ 45, 49, 44, 49, 48, 48 },
{ 45, 49, 49, 44, 48, 48, 48 },
{ 45, 49, 49, 48, 44, 48, 48, 48 },
{ 45, 49, 44, 49, 48, 48, 44, 48, 48, 48 },
{ 45, 49, 49, 44, 48, 48, 48, 44, 48, 48, 48 },
{ 45, 49, 49, 48, 44, 48, 48, 48, 44, 48, 48, 48 },
{ 45, 49, 44, 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48 },
{ 50 },
{ 50, 48 },
{ 50, 48, 48 },
{ 50, 44, 48, 48, 48 },
{ 50, 48, 44, 48, 48, 48 },
{ 50, 48, 48, 44, 48, 48, 48 },
{ 50, 44, 48, 48, 48, 44, 48, 48, 48 },
{ 50, 48, 44, 48, 48, 48, 44, 48, 48, 48 },
{ 50, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48 },
{ 50, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48 },
{ 45, 50 },
{ 45, 50, 48 },
{ 45, 50, 48, 48 },
{ 45, 50, 44, 48, 48, 48 },
{ 45, 50, 48, 44, 48, 48, 48 },
{ 45, 50, 48, 48, 44, 48, 48, 48 },
{ 45, 50, 44, 48, 48, 48, 44, 48, 48, 48 },
{ 45, 50, 48, 44, 48, 48, 48, 44, 48, 48, 48 },
{ 45, 50, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48 },
{ 45, 50, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48 },
{ 49, 48 },
{ 49, 48, 48 },
{ 49, 44, 48, 48, 48 },
{ 49, 48, 44, 48, 48, 48 },
{ 49, 48, 48, 44, 48, 48, 48 },
{ 49, 44, 48, 48, 48, 44, 48, 48, 48 },
{ 49, 48, 44, 48, 48, 48, 44, 48, 48, 48 },
{ 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48 },
{ 49, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48 },
{ 57, 46, 57, 57, 57 },
{ 57, 57, 46, 57, 57, 57 },
{ 57, 57, 57, 46, 57, 57, 57 },
{ 57, 44, 57, 57, 57, 46, 57, 57, 57 },
{ 57, 57, 44, 57, 57, 57, 46, 57, 57, 57 },
{ 57, 57, 57, 44, 57, 57, 57, 46, 57, 57, 57 },
{ 57, 44, 57, 57, 57, 44, 57, 57, 57, 46, 57, 57, 57 },
{ 57, 57, 44, 57, 57, 57, 44, 57, 57, 57, 46, 57, 57, 57 },
{ 57, 57, 57, 44, 57, 57, 57, 44, 57, 57, 57, 46, 57, 57, 57 },
{ 45, 49, 48 },
{ 45, 49, 48, 48 },
{ 45, 49, 44, 48, 48, 48 },
{ 45, 49, 48, 44, 48, 48, 48 },
{ 45, 49, 48, 48, 44, 48, 48, 48 },
{ 45, 49, 44, 48, 48, 48, 44, 48, 48, 48 },
{ 45, 49, 48, 44, 48, 48, 48, 44, 48, 48, 48 },
{ 45, 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48 },
{ 45, 49, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48 },
{ 45, 57, 46, 57, 57, 57 },
{ 45, 57, 57, 46, 57, 57, 57 },
{ 45, 57, 57, 57, 46, 57, 57, 57 },
{ 45, 57, 44, 57, 57, 57, 46, 57, 57, 57 },
{ 45, 57, 57, 44, 57, 57, 57, 46, 57, 57, 57 },
{ 45, 57, 57, 57, 44, 57, 57, 57, 46, 57, 57, 57 },
{ 45, 57, 44, 57, 57, 57, 44, 57, 57, 57, 46, 57, 57, 57 },
{ 45, 57, 57, 44, 57, 57, 57, 44, 57, 57, 57, 46, 57, 57, 57 },
{ 45, 57, 57, 57, 44, 57, 57, 57, 44, 57, 57, 57, 46, 57, 57, 57 },
{ 49 },
{ 49, 50 },
{ 49, 50, 51 },
{ 49, 44, 50, 51, 52 },
{ 49, 50, 44, 51, 52, 53 },
{ 49, 50, 51, 44, 52, 53, 54 },
{ 49, 44, 50, 51, 52, 44, 53, 54, 55 },
{ 49, 50, 44, 51, 52, 53, 44, 54, 55, 56 },
{ 49, 50, 51, 44, 52, 53, 54, 44, 55, 56, 57 },
{ 49, 44, 50, 51, 52, 44, 53, 54, 55, 44, 56, 57, 48 },
{ 45, 49 },
{ 45, 49, 50 },
{ 45, 49, 50, 51 },
{ 45, 49, 44, 50, 51, 52 },
{ 45, 49, 50, 44, 51, 52, 53 },
{ 45, 49, 50, 51, 44, 52, 53, 54 },
{ 45, 49, 44, 50, 51, 52, 44, 53, 54, 55 },
{ 45, 49, 50, 44, 51, 52, 53, 44, 54, 55, 56 },
{ 45, 49, 50, 51, 44, 52, 53, 54, 44, 55, 56, 57 },
{ 45, 49, 44, 50, 51, 52, 44, 53, 54, 55, 44, 56, 57, 48 },
{ 45, 50, 44, 53, 57, 57, 46, 52 },
{ 45, 50, 44, 53, 57, 57, 46, 51, 52 },
{ 45, 50, 44, 53, 57, 57, 46, 51, 51, 52 },
{ 49 },
{ 49 },
{ 49 },
{ 49 },
{ 49 },
{ 49, 46, 48, 48, 49 },
{ 49, 46, 48, 48, 49 },
{ 49, 46, 48, 48, 49 },
{ 49, 46, 48, 48, 49 },
{ 49, 46, 48, 48, 49 },
{ 49, 46, 50, 50, 50 },
{ 49, 46, 50, 50, 50 },
{ 49, 46, 50, 50, 50 },
{ 49, 46, 50, 50, 50 },
{ 49, 46, 50, 50, 50 },
{ 49, 46, 50, 50, 50 },
{ 49, 46, 50, 50, 50 },
{ 49, 46, 50, 50, 50 },
{ 49, 46, 50, 50, 50 },
{ 49, 46, 50, 50, 50 },
{ 49, 46, 50, 50, 50 },
{ 49, 46, 50, 50, 50 },
{ 49, 46, 50, 50, 50 },
{ 49, 46, 50, 50, 50 },
{ 49, 46, 50, 50, 50 },
{ 49, 46, 50, 50, 50 },
{ 49, 46, 50, 50, 50 },
{ 49, 46, 50, 50, 50 },
{ 49, 46, 50, 50, 50 },
{ 49, 46, 50, 50, 50 },
{ 49, 46, 50, 50, 51 },
{ 49, 46, 50, 50, 51 },
{ 49, 46, 50, 50, 51 },
{ 49, 46, 50, 50, 51 },
{ 49, 46, 50, 50, 51 },
{ 49, 46, 50, 50, 51 },
{ 49, 46, 50, 50, 51 },
{ 49, 46, 50, 50, 51 },
{ 49, 46, 50, 50, 51 },
{ 49, 46, 50, 50, 51 },
{ 49, 46, 50, 50, 51 },
{ 49, 46, 50, 50, 51 },
{ 49, 46, 50, 50, 51 },
{ 49, 46, 50, 50, 51 },
{ 49, 46, 50, 50, 51 },
{ 49, 46, 50, 50, 51 },
{ 49, 46, 50, 50, 51 },
{ 49, 46, 50, 50, 51 },
{ 49, 46, 50, 50, 51 },
{ 49, 48, 48, 44, 57, 49, 51, 46, 54, 55, 49 },
{ 49, 57, 57, 44, 57, 57, 57, 46, 57, 57, 57 },
{ 50, 53, 49, 44, 56, 52, 54, 46, 51, 52, 55 },
{ 50, 53, 51, 44, 50, 52, 51, 46, 56, 56, 51 },
{ 51, 54, 53, 44, 48, 52, 53, 46, 56, 53, 51 },
{ 51, 49, 52, 44, 55, 51, 52, 46, 57, 54, 49 },
{ 53, 52, 49, 44, 49, 51, 51, 46, 57, 55, 53 },
{ 56, 53, 56, 44, 51, 55, 50, 46, 49, 50, 51 },
{ 49, 44, 48, 48, 49, 44, 48, 48, 48 },
{ 49, 44, 51, 52, 55, 44, 53, 48, 53, 46, 55, 56, 50 },
{ 51, 44, 51, 53, 56, 44, 56, 52, 52, 46, 49, 57, 55 },
{ 57, 44, 57, 57, 55, 44, 57, 55, 57, 46, 52, 48, 57 },
{ 57, 44, 57, 57, 51, 44, 55, 52, 51, 46, 49, 53, 57 },
{ 57, 44, 57, 51, 56, 44, 54, 55, 49, 46, 57, 48, 57 },
{ 51, 44, 51, 56, 53, 44, 51, 48, 50, 46, 53, 52, 55 },
{ 51, 44, 52, 48, 52, 44, 54, 52, 50, 46, 54, 54, 49 },
{ 51, 44, 52, 51, 49, 44, 50, 56, 48, 46, 48, 56, 55 },
{ 51, 44, 52, 51, 56, 44, 55, 53, 54, 46, 52, 55, 53 },
{ 51, 44, 52, 52, 54, 44, 48, 53, 51, 46, 55, 56, 55 },
{ 51, 44, 52, 53, 55, 44, 57, 49, 55, 46, 53, 49, 51 },
{ 51, 44, 52, 54, 53, 44, 51, 57, 51, 46, 57, 48, 49 },
{ 51, 44, 52, 56, 52, 44, 55, 51, 52, 46, 48, 49, 53 },
{ 51, 44, 52, 57, 50, 44, 48, 51, 49, 46, 51, 50, 55 },
{ 51, 44, 53, 48, 51, 44, 56, 57, 53, 46, 48, 53, 51 },
{ 51, 44, 53, 49, 49, 44, 51, 55, 49, 46, 52, 52, 49 },
{ 51, 44, 53, 49, 56, 44, 54, 54, 56, 46, 55, 53, 51 },
{ 51, 44, 53, 51, 48, 44, 53, 51, 50, 46, 52, 55, 57 },
{ 51, 44, 53, 51, 56, 44, 48, 48, 56, 46, 56, 54, 55 },
{ 51, 44, 53, 52, 53, 44, 51, 48, 54, 46, 49, 55, 57 },
{ 51, 44, 53, 53, 55, 44, 49, 54, 57, 46, 57, 48, 53 },
{ 51, 44, 53, 53, 55, 44, 51, 52, 56, 46, 57, 56, 49 },
{ 51, 44, 53, 54, 52, 44, 54, 52, 54, 46, 50, 57, 51 },
{ 51, 44, 53, 56, 51, 44, 57, 56, 54, 46, 52, 48, 55 },
{ 51, 44, 53, 57, 49, 44, 50, 56, 51, 46, 55, 49, 57 },
{ 51, 44, 54, 48, 51, 44, 49, 52, 55, 46, 52, 52, 53 },
{ 51, 44, 54, 49, 48, 44, 54, 50, 51, 46, 56, 51, 51 },
{ 51, 44, 54, 49, 55, 44, 57, 50, 49, 46, 49, 52, 53 },
{ 51, 44, 54, 50, 57, 44, 55, 56, 52, 46, 56, 55, 49 },
{ 51, 44, 54, 51, 55, 44, 50, 54, 49, 46, 50, 53, 57 },
{ 51, 44, 54, 53, 54, 44, 52, 50, 50, 46, 50, 57, 55 },
{ 51, 44, 54, 53, 54, 44, 54, 48, 49, 46, 51, 55, 51 },
{ 51, 44, 54, 54, 51, 44, 56, 57, 56, 46, 54, 56, 53 },
{ 51, 44, 54, 55, 53, 44, 55, 54, 50, 46, 52, 49, 49 },
{ 51, 44, 54, 56, 51, 44, 50, 51, 56, 46, 55, 57, 57 },
{ 51, 44, 54, 57, 48, 44, 53, 51, 54, 46, 49, 49, 49 },
{ 51, 44, 55, 48, 50, 44, 51, 57, 57, 46, 56, 51, 55 },
{ 51, 44, 55, 48, 57, 44, 56, 55, 54, 46, 50, 50, 53 },
{ 51, 44, 55, 49, 55, 44, 49, 55, 51, 46, 53, 51, 55 },
{ 51, 44, 55, 50, 57, 44, 48, 51, 55, 46, 50, 54, 51 },
{ 51, 44, 55, 51, 54, 44, 53, 49, 51, 46, 54, 53, 49 },
{ 51, 44, 55, 53, 53, 44, 56, 53, 51, 46, 55, 54, 53 },
{ 51, 44, 55, 54, 51, 44, 49, 53, 49, 46, 48, 55, 55 },
{ 51, 44, 55, 55, 53, 44, 48, 49, 52, 46, 56, 48, 51 },
{ 51, 44, 55, 56, 50, 44, 52, 57, 49, 46, 49, 57, 49 },
{ 51, 44, 55, 56, 57, 44, 55, 56, 56, 46, 53, 48, 51 },
{ 51, 44, 56, 48, 49, 44, 54, 53, 50, 46, 50, 50, 57 },
{ 51, 44, 56, 48, 57, 44, 49, 50, 56, 46, 54, 49, 55 },
{ 51, 44, 56, 49, 54, 44, 52, 50, 53, 46, 57, 50, 57 },
{ 51, 44, 56, 50, 56, 44, 50, 56, 57, 46, 54, 53, 53 },
{ 51, 44, 56, 50, 56, 44, 52, 54, 56, 46, 55, 51, 49 },
{ 51, 44, 56, 51, 53, 44, 55, 54, 54, 46, 48, 52, 51 },
{ 51, 44, 56, 53, 53, 44, 49, 48, 54, 46, 49, 53, 55 },
{ 51, 44, 56, 54, 50, 44, 52, 48, 51, 46, 52, 54, 57 },
{ 51, 44, 56, 55, 52, 44, 50, 54, 55, 46, 49, 57, 53 },
{ 51, 44, 56, 56, 49, 44, 55, 52, 51, 46, 53, 56, 51 },
{ 51, 44, 56, 56, 57, 44, 48, 52, 48, 46, 56, 57, 53 },
{ 51, 44, 57, 48, 48, 44, 57, 48, 52, 46, 54, 50, 49 },
{ 51, 44, 57, 48, 56, 44, 51, 56, 49, 46, 48, 48, 57 },
{ 51, 44, 57, 50, 55, 44, 53, 52, 50, 46, 48, 52, 55 },
{ 51, 44, 57, 50, 55, 44, 55, 50, 49, 46, 49, 50, 51 },
{ 51, 44, 57, 51, 53, 44, 48, 49, 56, 46, 52, 51, 53 },
{ 51, 44, 57, 52, 54, 44, 56, 56, 50, 46, 49, 54, 49 },
{ 51, 44, 57, 53, 52, 44, 51, 53, 56, 46, 53, 52, 57 },
{ 51, 44, 57, 54, 49, 44, 54, 53, 53, 46, 56, 54, 49 },
{ 51, 44, 57, 55, 51, 44, 53, 49, 57, 46, 53, 56, 55 },
{ 51, 44, 57, 56, 48, 44, 57, 57, 53, 46, 57, 55, 53 },
{ 51, 44, 57, 56, 56, 44, 50, 57, 51, 46, 50, 56, 55 },
{ 52, 44, 48, 48, 48, 44, 49, 53, 55, 46, 48, 49, 51 },
{ 52, 44, 48, 48, 55, 44, 54, 51, 51, 46, 52, 48, 49 },
{ 52, 44, 48, 50, 54, 44, 57, 55, 51, 46, 53, 49, 53 },
{ 52, 44, 48, 51, 52, 44, 50, 55, 48, 46, 56, 50, 55 },
{ 52, 44, 48, 52, 54, 44, 49, 51, 52, 46, 53, 53, 51 },
{ 52, 44, 48, 53, 51, 44, 54, 49, 48, 46, 57, 52, 49 },
{ 52, 44, 48, 54, 48, 44, 57, 48, 56, 46, 50, 53, 51 },
{ 52, 44, 48, 55, 50, 44, 55, 55, 49, 46, 57, 55, 57 },
{ 52, 44, 48, 56, 48, 44, 50, 52, 56, 46, 51, 54, 55 },
{ 52, 44, 48, 56, 55, 44, 53, 52, 53, 46, 54, 55, 57 },
{ 52, 44, 48, 57, 57, 44, 52, 48, 57, 46, 52, 48, 53 },
{ 52, 44, 48, 57, 57, 44, 53, 56, 56, 46, 52, 56, 49 },
{ 52, 44, 49, 48, 54, 44, 56, 56, 53, 46, 55, 57, 51 },
{ 52, 44, 49, 50, 54, 44, 50, 50, 53, 46, 57, 48, 55 },
{ 52, 44, 49, 51, 51, 44, 53, 50, 51, 46, 50, 49, 57 },
{ 52, 44, 49, 52, 53, 44, 51, 56, 54, 46, 57, 52, 53 },
{ 52, 44, 49, 53, 50, 44, 56, 54, 51, 46, 51, 51, 51 },
{ 52, 44, 49, 54, 48, 44, 49, 54, 48, 46, 54, 52, 53 },
{ 52, 44, 49, 55, 50, 44, 48, 50, 52, 46, 51, 55, 49 },
{ 52, 44, 49, 55, 57, 44, 53, 48, 48, 46, 55, 53, 57 },
{ 52, 44, 49, 57, 56, 44, 54, 54, 49, 46, 55, 57, 55 },
{ 52, 44, 50, 48, 51, 44, 52, 48, 55, 46, 50, 56, 55 },
{ 52, 44, 50, 49, 48, 44, 55, 48, 52, 46, 53, 57, 57 },
{ 52, 44, 50, 49, 51, 44, 52, 51, 53, 46, 52, 57, 55 },
};
// The array of int[] unicode values storing the expected results
// when calling Decimal.format(double) on the currency GoldenDoubleValues.
static int[][] CurrencyGoldenFormattedValues = {
{ 36, 48, 46, 48, 48 },
{ 45, 36, 48, 46, 48, 48 },
{ 36, 48, 46, 48, 48 },
{ 36, 48, 46, 48, 48 },
{ 45, 36, 50, 44, 49, 52, 55, 44, 52, 56, 51, 44, 54, 52, 54, 46, 50, 51 },
{ 36, 50, 44, 49, 52, 55, 44, 52, 56, 51, 44, 54, 52, 54, 46, 50, 51 },
{ 45, 36, 50, 44, 49, 52, 55, 44, 52, 56, 51, 44, 54, 52, 56, 46, 48, 48 },
{ 36, 50, 44, 49, 52, 55, 44, 52, 56, 51, 44, 54, 52, 56, 46, 48, 48 },
{ 45, 36, 49, 44, 57, 57, 57, 44, 57, 57, 57, 44, 57, 57, 57, 46, 57, 57 },
{ 36, 50, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 78, 97, 78 },
{ 36, 8734 },
{ 45, 36, 8734 },
{ 36, 49, 55, 57, 44, 55, 54, 57, 44, 51, 49, 51, 44, 52, 56, 54, 44, 50, 51, 49, 44, 53, 55, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 45, 36, 57, 44, 56, 55, 54, 44, 53, 52, 51, 44, 50, 49, 48, 46, 57, 57 },
{ 36, 57, 44, 56, 55, 54, 44, 53, 52, 51, 44, 50, 49, 48, 46, 57, 57 },
{ 45, 36, 49, 50, 51, 44, 52, 53, 54, 44, 55, 56, 57, 44, 48, 49, 50, 44, 51, 52, 53, 44, 54, 55, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 36, 49, 50, 51, 44, 52, 53, 54, 44, 55, 56, 57, 44, 48, 49, 50, 44, 51, 52, 53, 44, 54, 55, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 36, 49, 46, 49, 50 },
{ 36, 49, 50, 46, 49, 50 },
{ 36, 49, 50, 51, 46, 49, 50 },
{ 36, 49, 44, 50, 51, 52, 46, 49, 50 },
{ 36, 49, 50, 44, 51, 52, 53, 46, 49, 50 },
{ 36, 49, 50, 51, 44, 52, 53, 54, 46, 49, 50 },
{ 36, 49, 44, 50, 51, 52, 44, 53, 54, 55, 46, 49, 50 },
{ 36, 49, 50, 44, 51, 52, 53, 44, 54, 55, 56, 46, 49, 50 },
{ 36, 49, 50, 51, 44, 52, 53, 54, 44, 55, 56, 57, 46, 49, 50 },
{ 36, 49, 44, 50, 51, 52, 44, 53, 54, 55, 44, 56, 57, 48, 46, 49, 50 },
{ 45, 36, 49, 46, 49, 50 },
{ 45, 36, 49, 50, 46, 49, 50 },
{ 45, 36, 49, 50, 51, 46, 49, 50 },
{ 45, 36, 49, 44, 50, 51, 52, 46, 49, 50 },
{ 45, 36, 49, 50, 44, 51, 52, 53, 46, 49, 50 },
{ 45, 36, 49, 50, 51, 44, 52, 53, 54, 46, 49, 50 },
{ 45, 36, 49, 44, 50, 51, 52, 44, 53, 54, 55, 46, 49, 50 },
{ 45, 36, 49, 50, 44, 51, 52, 53, 44, 54, 55, 56, 46, 49, 50 },
{ 45, 36, 49, 50, 51, 44, 52, 53, 54, 44, 55, 56, 57, 46, 49, 50 },
{ 45, 36, 49, 44, 50, 51, 52, 44, 53, 54, 55, 44, 56, 57, 48, 46, 49, 50 },
{ 36, 48, 46, 49, 48 },
{ 36, 48, 46, 49, 50 },
{ 36, 48, 46, 49, 50 },
{ 36, 49, 48, 46, 49, 48 },
{ 36, 49, 48, 46, 49, 50 },
{ 36, 49, 48, 46, 49, 50 },
{ 36, 49, 48, 48, 46, 49, 48 },
{ 36, 49, 48, 48, 46, 49, 50 },
{ 36, 49, 48, 48, 46, 49, 50 },
{ 36, 49, 44, 48, 48, 48, 46, 49, 48 },
{ 36, 49, 44, 48, 48, 48, 46, 49, 50 },
{ 36, 49, 44, 48, 48, 48, 46, 49, 50 },
{ 36, 49, 48, 44, 48, 48, 48, 46, 49, 48 },
{ 36, 49, 48, 44, 48, 48, 48, 46, 49, 50 },
{ 36, 49, 48, 44, 48, 48, 48, 46, 49, 50 },
{ 36, 49, 48, 48, 44, 48, 48, 48, 46, 49, 48 },
{ 36, 49, 48, 48, 44, 48, 48, 48, 46, 49, 50 },
{ 36, 49, 48, 48, 44, 48, 48, 48, 46, 49, 50 },
{ 36, 49, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 48 },
{ 36, 49, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 },
{ 36, 49, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 },
{ 36, 49, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 48 },
{ 36, 49, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 },
{ 36, 49, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 },
{ 36, 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 48 },
{ 36, 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 },
{ 36, 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 },
{ 36, 49, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 48 },
{ 36, 49, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 },
{ 36, 49, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 },
{ 45, 36, 48, 46, 49, 48 },
{ 45, 36, 48, 46, 49, 50 },
{ 45, 36, 48, 46, 49, 50 },
{ 45, 36, 49, 48, 46, 49, 48 },
{ 45, 36, 49, 48, 46, 49, 50 },
{ 45, 36, 49, 48, 46, 49, 50 },
{ 45, 36, 49, 48, 48, 46, 49, 48 },
{ 45, 36, 49, 48, 48, 46, 49, 50 },
{ 45, 36, 49, 48, 48, 46, 49, 50 },
{ 45, 36, 49, 44, 48, 48, 48, 46, 49, 48 },
{ 45, 36, 49, 44, 48, 48, 48, 46, 49, 50 },
{ 45, 36, 49, 44, 48, 48, 48, 46, 49, 50 },
{ 45, 36, 49, 48, 44, 48, 48, 48, 46, 49, 48 },
{ 45, 36, 49, 48, 44, 48, 48, 48, 46, 49, 50 },
{ 45, 36, 49, 48, 44, 48, 48, 48, 46, 49, 50 },
{ 45, 36, 49, 48, 48, 44, 48, 48, 48, 46, 49, 48 },
{ 45, 36, 49, 48, 48, 44, 48, 48, 48, 46, 49, 50 },
{ 45, 36, 49, 48, 48, 44, 48, 48, 48, 46, 49, 50 },
{ 45, 36, 49, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 48 },
{ 45, 36, 49, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 },
{ 45, 36, 49, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 },
{ 45, 36, 49, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 48 },
{ 45, 36, 49, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 },
{ 45, 36, 49, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 },
{ 45, 36, 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 48 },
{ 45, 36, 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 },
{ 45, 36, 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 },
{ 45, 36, 49, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 48 },
{ 45, 36, 49, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 },
{ 45, 36, 49, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 49, 50 },
{ 36, 49, 46, 57, 57 },
{ 36, 49, 50, 46, 57, 57 },
{ 36, 49, 50, 51, 46, 57, 57 },
{ 36, 49, 44, 50, 51, 52, 46, 57, 57 },
{ 36, 49, 50, 44, 51, 52, 53, 46, 57, 57 },
{ 36, 49, 50, 51, 44, 52, 53, 54, 46, 57, 57 },
{ 36, 49, 44, 50, 51, 52, 44, 53, 54, 55, 46, 57, 57 },
{ 36, 49, 50, 44, 51, 52, 53, 44, 54, 55, 56, 46, 57, 57 },
{ 36, 49, 50, 51, 44, 52, 53, 54, 44, 55, 56, 57, 46, 57, 57 },
{ 36, 49, 44, 50, 51, 52, 44, 53, 54, 55, 44, 56, 57, 48, 46, 57, 57 },
{ 36, 50, 46, 48, 48 },
{ 36, 49, 51, 46, 48, 48 },
{ 36, 49, 50, 52, 46, 48, 48 },
{ 36, 49, 44, 50, 51, 53, 46, 48, 48 },
{ 36, 49, 50, 44, 51, 52, 54, 46, 48, 48 },
{ 36, 49, 50, 51, 44, 52, 53, 55, 46, 48, 48 },
{ 36, 49, 44, 50, 51, 52, 44, 53, 54, 56, 46, 48, 48 },
{ 36, 49, 50, 44, 51, 52, 53, 44, 54, 55, 57, 46, 48, 48 },
{ 36, 49, 50, 51, 44, 52, 53, 54, 44, 55, 57, 48, 46, 48, 48 },
{ 36, 49, 44, 50, 51, 52, 44, 53, 54, 55, 44, 56, 57, 49, 46, 48, 48 },
{ 45, 36, 49, 46, 57, 57 },
{ 45, 36, 49, 50, 46, 57, 57 },
{ 45, 36, 49, 50, 51, 46, 57, 57 },
{ 45, 36, 49, 44, 50, 51, 52, 46, 57, 57 },
{ 45, 36, 49, 50, 44, 51, 52, 53, 46, 57, 57 },
{ 45, 36, 49, 50, 51, 44, 52, 53, 54, 46, 57, 57 },
{ 45, 36, 49, 44, 50, 51, 52, 44, 53, 54, 55, 46, 57, 57 },
{ 45, 36, 49, 50, 44, 51, 52, 53, 44, 54, 55, 56, 46, 57, 57 },
{ 45, 36, 49, 50, 51, 44, 52, 53, 54, 44, 55, 56, 57, 46, 57, 57 },
{ 45, 36, 49, 44, 50, 51, 52, 44, 53, 54, 55, 44, 56, 57, 48, 46, 57, 57 },
{ 45, 36, 50, 46, 48, 48 },
{ 45, 36, 49, 51, 46, 48, 48 },
{ 45, 36, 49, 50, 52, 46, 48, 48 },
{ 45, 36, 49, 44, 50, 51, 53, 46, 48, 48 },
{ 45, 36, 49, 50, 44, 51, 52, 54, 46, 48, 48 },
{ 45, 36, 49, 50, 51, 44, 52, 53, 55, 46, 48, 48 },
{ 45, 36, 49, 44, 50, 51, 52, 44, 53, 54, 56, 46, 48, 48 },
{ 45, 36, 49, 50, 44, 51, 52, 53, 44, 54, 55, 57, 46, 48, 48 },
{ 45, 36, 49, 50, 51, 44, 52, 53, 54, 44, 55, 57, 48, 46, 48, 48 },
{ 45, 36, 49, 44, 50, 51, 52, 44, 53, 54, 55, 44, 56, 57, 49, 46, 48, 48 },
{ 36, 49, 49, 48, 46, 48, 48 },
{ 36, 49, 44, 49, 48, 48, 46, 48, 48 },
{ 36, 49, 49, 44, 48, 48, 48, 46, 48, 48 },
{ 36, 49, 49, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 36, 49, 44, 49, 48, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 36, 49, 49, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 36, 49, 49, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 36, 49, 44, 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 45, 36, 49, 49, 48, 46, 48, 48 },
{ 45, 36, 49, 44, 49, 48, 48, 46, 48, 48 },
{ 45, 36, 49, 49, 44, 48, 48, 48, 46, 48, 48 },
{ 45, 36, 49, 49, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 45, 36, 49, 44, 49, 48, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 45, 36, 49, 49, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 45, 36, 49, 49, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 45, 36, 49, 44, 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 36, 50, 46, 48, 48 },
{ 36, 50, 48, 46, 48, 48 },
{ 36, 50, 48, 48, 46, 48, 48 },
{ 36, 50, 44, 48, 48, 48, 46, 48, 48 },
{ 36, 50, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 36, 50, 48, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 36, 50, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 36, 50, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 36, 50, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 36, 50, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 45, 36, 50, 46, 48, 48 },
{ 45, 36, 50, 48, 46, 48, 48 },
{ 45, 36, 50, 48, 48, 46, 48, 48 },
{ 45, 36, 50, 44, 48, 48, 48, 46, 48, 48 },
{ 45, 36, 50, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 45, 36, 50, 48, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 45, 36, 50, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 45, 36, 50, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 45, 36, 50, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 45, 36, 50, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 36, 49, 48, 46, 48, 48 },
{ 36, 49, 48, 48, 46, 48, 48 },
{ 36, 49, 44, 48, 48, 48, 46, 48, 48 },
{ 36, 49, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 36, 49, 48, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 36, 49, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 36, 49, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 36, 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 36, 49, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 36, 57, 46, 57, 57 },
{ 36, 57, 57, 46, 57, 57 },
{ 36, 57, 57, 57, 46, 57, 57 },
{ 36, 57, 44, 57, 57, 57, 46, 57, 57 },
{ 36, 57, 57, 44, 57, 57, 57, 46, 57, 57 },
{ 36, 57, 57, 57, 44, 57, 57, 57, 46, 57, 57 },
{ 36, 57, 44, 57, 57, 57, 44, 57, 57, 57, 46, 57, 57 },
{ 36, 57, 57, 44, 57, 57, 57, 44, 57, 57, 57, 46, 57, 57 },
{ 36, 57, 57, 57, 44, 57, 57, 57, 44, 57, 57, 57, 46, 57, 57 },
{ 45, 36, 49, 48, 46, 48, 48 },
{ 45, 36, 49, 48, 48, 46, 48, 48 },
{ 45, 36, 49, 44, 48, 48, 48, 46, 48, 48 },
{ 45, 36, 49, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 45, 36, 49, 48, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 45, 36, 49, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 45, 36, 49, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 45, 36, 49, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 45, 36, 49, 44, 48, 48, 48, 44, 48, 48, 48, 44, 48, 48, 48, 46, 48, 48 },
{ 45, 36, 57, 46, 57, 57 },
{ 45, 36, 57, 57, 46, 57, 57 },
{ 45, 36, 57, 57, 57, 46, 57, 57 },
{ 45, 36, 57, 44, 57, 57, 57, 46, 57, 57 },
{ 45, 36, 57, 57, 44, 57, 57, 57, 46, 57, 57 },
{ 45, 36, 57, 57, 57, 44, 57, 57, 57, 46, 57, 57 },
{ 45, 36, 57, 44, 57, 57, 57, 44, 57, 57, 57, 46, 57, 57 },
{ 45, 36, 57, 57, 44, 57, 57, 57, 44, 57, 57, 57, 46, 57, 57 },
{ 45, 36, 57, 57, 57, 44, 57, 57, 57, 44, 57, 57, 57, 46, 57, 57 },
{ 36, 49, 46, 48, 48 },
{ 36, 49, 50, 46, 48, 48 },
{ 36, 49, 50, 51, 46, 48, 48 },
{ 36, 49, 44, 50, 51, 52, 46, 48, 48 },
{ 36, 49, 50, 44, 51, 52, 53, 46, 48, 48 },
{ 36, 49, 50, 51, 44, 52, 53, 54, 46, 48, 48 },
{ 36, 49, 44, 50, 51, 52, 44, 53, 54, 55, 46, 48, 48 },
{ 36, 49, 50, 44, 51, 52, 53, 44, 54, 55, 56, 46, 48, 48 },
{ 36, 49, 50, 51, 44, 52, 53, 54, 44, 55, 56, 57, 46, 48, 48 },
{ 36, 49, 44, 50, 51, 52, 44, 53, 54, 55, 44, 56, 57, 48, 46, 48, 48 },
{ 45, 36, 49, 46, 48, 48 },
{ 45, 36, 49, 50, 46, 48, 48 },
{ 45, 36, 49, 50, 51, 46, 48, 48 },
{ 45, 36, 49, 44, 50, 51, 52, 46, 48, 48 },
{ 45, 36, 49, 50, 44, 51, 52, 53, 46, 48, 48 },
{ 45, 36, 49, 50, 51, 44, 52, 53, 54, 46, 48, 48 },
{ 45, 36, 49, 44, 50, 51, 52, 44, 53, 54, 55, 46, 48, 48 },
{ 45, 36, 49, 50, 44, 51, 52, 53, 44, 54, 55, 56, 46, 48, 48 },
{ 45, 36, 49, 50, 51, 44, 52, 53, 54, 44, 55, 56, 57, 46, 48, 48 },
{ 45, 36, 49, 44, 50, 51, 52, 44, 53, 54, 55, 44, 56, 57, 48, 46, 48, 48 },
{ 45, 36, 50, 44, 53, 57, 57, 46, 52, 48 },
{ 45, 36, 50, 44, 53, 57, 57, 46, 51, 52 },
{ 45, 36, 50, 44, 53, 57, 57, 46, 51, 51 },
{ 36, 49, 46, 48, 48 },
{ 36, 49, 46, 48, 48 },
{ 36, 49, 46, 48, 48 },
{ 36, 49, 46, 48, 48 },
{ 36, 49, 46, 48, 48 },
{ 36, 49, 46, 48, 49 },
{ 36, 49, 46, 48, 49 },
{ 36, 49, 46, 48, 49 },
{ 36, 49, 46, 48, 49 },
{ 36, 49, 46, 48, 49 },
{ 36, 49, 46, 50, 50 },
{ 36, 49, 46, 50, 50 },
{ 36, 49, 46, 50, 50 },
{ 36, 49, 46, 50, 50 },
{ 36, 49, 46, 50, 50 },
{ 36, 49, 46, 50, 50 },
{ 36, 49, 46, 50, 50 },
{ 36, 49, 46, 50, 50 },
{ 36, 49, 46, 50, 50 },
{ 36, 49, 46, 50, 50 },
{ 36, 49, 46, 50, 50 },
{ 36, 49, 46, 50, 50 },
{ 36, 49, 46, 50, 50 },
{ 36, 49, 46, 50, 50 },
{ 36, 49, 46, 50, 50 },
{ 36, 49, 46, 50, 50 },
{ 36, 49, 46, 50, 50 },
{ 36, 49, 46, 50, 50 },
{ 36, 49, 46, 50, 50 },
{ 36, 49, 46, 50, 50 },
{ 36, 49, 46, 50, 51 },
{ 36, 49, 46, 50, 51 },
{ 36, 49, 46, 50, 51 },
{ 36, 49, 46, 50, 51 },
{ 36, 49, 46, 50, 51 },
{ 36, 49, 46, 50, 51 },
{ 36, 49, 46, 50, 51 },
{ 36, 49, 46, 50, 51 },
{ 36, 49, 46, 50, 51 },
{ 36, 49, 46, 50, 51 },
{ 36, 49, 46, 50, 51 },
{ 36, 49, 46, 50, 51 },
{ 36, 49, 46, 50, 51 },
{ 36, 49, 46, 50, 51 },
{ 36, 49, 46, 50, 51 },
{ 36, 49, 46, 50, 51 },
{ 36, 49, 46, 50, 51 },
{ 36, 49, 46, 50, 51 },
{ 36, 49, 46, 50, 51 },
{ 36, 49, 46, 50, 51 },
{ 36, 49, 44, 48, 48, 57, 44, 49, 51, 54, 46, 55, 49 },
{ 36, 50, 44, 53, 49, 56, 44, 52, 54, 51, 46, 52, 54 },
{ 36, 50, 44, 53, 51, 50, 44, 52, 51, 56, 46, 56, 51 },
{ 36, 51, 44, 54, 53, 48, 44, 52, 53, 56, 46, 53, 51 },
{ 36, 51, 44, 49, 52, 55, 44, 51, 52, 57, 46, 54, 50 },
{ 36, 53, 44, 52, 49, 49, 44, 51, 51, 57, 46, 55, 53 },
{ 36, 56, 44, 53, 56, 51, 44, 55, 50, 49, 46, 50, 50 },
{ 36, 49, 51, 44, 52, 55, 53, 44, 48, 53, 55, 46, 56, 50 },
{ 36, 51, 51, 44, 53, 56, 56, 44, 52, 52, 49, 46, 57, 56 },
{ 36, 57, 57, 44, 57, 55, 57, 44, 55, 57, 52, 46, 48, 56 },
{ 36, 57, 57, 44, 57, 51, 55, 44, 52, 51, 49, 46, 53, 56 },
{ 36, 57, 57, 44, 51, 56, 54, 44, 55, 49, 57, 46, 48, 56 },
{ 36, 51, 51, 44, 56, 53, 51, 44, 48, 50, 53, 46, 52, 55 },
{ 36, 51, 52, 44, 48, 52, 54, 44, 52, 50, 54, 46, 54, 48 },
{ 36, 51, 52, 44, 51, 49, 50, 44, 56, 48, 48, 46, 56, 55 },
{ 36, 51, 52, 44, 51, 56, 55, 44, 53, 54, 52, 46, 55, 53 },
{ 36, 51, 52, 44, 52, 54, 48, 44, 53, 51, 55, 46, 56, 55 },
{ 36, 51, 52, 44, 53, 55, 57, 44, 49, 55, 53, 46, 49, 50 },
{ 36, 51, 52, 44, 54, 53, 51, 44, 57, 51, 57, 46, 48, 50 },
{ 36, 51, 52, 44, 56, 52, 55, 44, 51, 52, 48, 46, 49, 53 },
{ 36, 51, 52, 44, 57, 50, 48, 44, 51, 49, 51, 46, 50, 55 },
{ 36, 51, 53, 44, 48, 51, 56, 44, 57, 53, 48, 46, 53, 50 },
{ 36, 51, 53, 44, 49, 49, 51, 44, 55, 49, 52, 46, 52, 49 },
{ 36, 51, 53, 44, 49, 56, 54, 44, 54, 56, 55, 46, 53, 51 },
{ 36, 51, 53, 44, 51, 48, 53, 44, 51, 50, 52, 46, 55, 56 },
{ 36, 51, 53, 44, 51, 56, 48, 44, 48, 56, 56, 46, 54, 55 },
{ 36, 51, 53, 44, 52, 53, 51, 44, 48, 54, 49, 46, 55, 57 },
{ 36, 51, 53, 44, 53, 55, 49, 44, 54, 57, 57, 46, 48, 53 },
{ 36, 51, 53, 44, 53, 55, 51, 44, 52, 56, 57, 46, 56, 49 },
{ 36, 51, 53, 44, 54, 52, 54, 44, 52, 54, 50, 46, 57, 51 },
{ 36, 51, 53, 44, 56, 51, 57, 44, 56, 54, 52, 46, 48, 55 },
{ 36, 51, 53, 44, 57, 49, 50, 44, 56, 51, 55, 46, 50, 48 },
{ 36, 51, 54, 44, 48, 51, 49, 44, 52, 55, 52, 46, 52, 53 },
{ 36, 51, 54, 44, 49, 48, 54, 44, 50, 51, 56, 46, 51, 51 },
{ 36, 51, 54, 44, 49, 55, 57, 44, 50, 49, 49, 46, 52, 53 },
{ 36, 51, 54, 44, 50, 57, 55, 44, 56, 52, 56, 46, 55, 48 },
{ 36, 51, 54, 44, 51, 55, 50, 44, 54, 49, 50, 46, 53, 57 },
{ 36, 51, 54, 44, 53, 54, 52, 44, 50, 50, 50, 46, 57, 55 },
{ 36, 51, 54, 44, 53, 54, 54, 44, 48, 49, 51, 46, 55, 51 },
{ 36, 51, 54, 44, 54, 51, 56, 44, 57, 56, 54, 46, 56, 53 },
{ 36, 51, 54, 44, 55, 53, 55, 44, 54, 50, 52, 46, 49, 48 },
{ 36, 51, 54, 44, 56, 51, 50, 44, 51, 56, 55, 46, 57, 57 },
{ 36, 51, 54, 44, 57, 48, 53, 44, 51, 54, 49, 46, 49, 49 },
{ 36, 51, 55, 44, 48, 50, 51, 44, 57, 57, 56, 46, 51, 55 },
{ 36, 51, 55, 44, 48, 57, 56, 44, 55, 54, 50, 46, 50, 53 },
{ 36, 51, 55, 44, 49, 55, 49, 44, 55, 51, 53, 46, 51, 55 },
{ 36, 51, 55, 44, 50, 57, 48, 44, 51, 55, 50, 46, 54, 50 },
{ 36, 51, 55, 44, 51, 54, 53, 44, 49, 51, 54, 46, 53, 50 },
{ 36, 51, 55, 44, 53, 53, 56, 44, 53, 51, 55, 46, 54, 53 },
{ 36, 51, 55, 44, 54, 51, 49, 44, 53, 49, 48, 46, 55, 55 },
{ 36, 51, 55, 44, 55, 53, 48, 44, 49, 52, 56, 46, 48, 50 },
{ 36, 51, 55, 44, 56, 50, 52, 44, 57, 49, 49, 46, 57, 49 },
{ 36, 51, 55, 44, 56, 57, 55, 44, 56, 56, 53, 46, 48, 51 },
{ 36, 51, 56, 44, 48, 49, 54, 44, 53, 50, 50, 46, 50, 56 },
{ 36, 51, 56, 44, 48, 57, 49, 44, 50, 56, 54, 46, 49, 55 },
{ 36, 51, 56, 44, 49, 54, 52, 44, 50, 53, 57, 46, 50, 57 },
{ 36, 51, 56, 44, 50, 56, 50, 44, 56, 57, 54, 46, 53, 53 },
{ 36, 51, 56, 44, 50, 56, 52, 44, 54, 56, 55, 46, 51, 49 },
{ 36, 51, 56, 44, 51, 53, 55, 44, 54, 54, 48, 46, 52, 51 },
{ 36, 51, 56, 44, 53, 53, 49, 44, 48, 54, 49, 46, 53, 55 },
{ 36, 51, 56, 44, 54, 50, 52, 44, 48, 51, 52, 46, 55, 48 },
{ 36, 51, 56, 44, 55, 52, 50, 44, 54, 55, 49, 46, 57, 53 },
{ 36, 51, 56, 44, 56, 49, 55, 44, 52, 51, 53, 46, 56, 51 },
{ 36, 51, 56, 44, 56, 57, 48, 44, 52, 48, 56, 46, 57, 53 },
{ 36, 51, 57, 44, 48, 48, 57, 44, 48, 52, 54, 46, 50, 48 },
{ 36, 51, 57, 44, 48, 56, 51, 44, 56, 49, 48, 46, 48, 57 },
{ 36, 51, 57, 44, 50, 55, 53, 44, 52, 50, 48, 46, 52, 55 },
{ 36, 51, 57, 44, 50, 55, 55, 44, 50, 49, 49, 46, 50, 51 },
{ 36, 51, 57, 44, 51, 53, 48, 44, 49, 56, 52, 46, 51, 53 },
{ 36, 51, 57, 44, 52, 54, 56, 44, 56, 50, 49, 46, 54, 48 },
{ 36, 51, 57, 44, 53, 52, 51, 44, 53, 56, 53, 46, 52, 57 },
{ 36, 51, 57, 44, 54, 49, 54, 44, 53, 53, 56, 46, 54, 49 },
{ 36, 51, 57, 44, 55, 51, 53, 44, 49, 57, 53, 46, 56, 55 },
{ 36, 51, 57, 44, 56, 48, 57, 44, 57, 53, 57, 46, 55, 53 },
{ 36, 51, 57, 44, 56, 56, 50, 44, 57, 51, 50, 46, 56, 55 },
{ 36, 52, 48, 44, 48, 48, 49, 44, 53, 55, 48, 46, 49, 50 },
{ 36, 52, 48, 44, 48, 55, 54, 44, 51, 51, 52, 46, 48, 50 },
{ 36, 52, 48, 44, 50, 54, 57, 44, 55, 51, 53, 46, 49, 53 },
{ 36, 52, 48, 44, 51, 52, 50, 44, 55, 48, 56, 46, 50, 55 },
{ 36, 52, 48, 44, 52, 54, 49, 44, 51, 52, 53, 46, 53, 50 },
{ 36, 52, 48, 44, 53, 51, 54, 44, 49, 48, 57, 46, 52, 49 },
{ 36, 52, 48, 44, 54, 48, 57, 44, 48, 56, 50, 46, 53, 51 },
{ 36, 52, 48, 44, 55, 50, 55, 44, 55, 49, 57, 46, 55, 56 },
{ 36, 52, 48, 44, 56, 48, 50, 44, 52, 56, 51, 46, 54, 55 },
{ 36, 52, 48, 44, 56, 55, 53, 44, 52, 53, 54, 46, 55, 57 },
{ 36, 52, 48, 44, 57, 57, 52, 44, 48, 57, 52, 46, 48, 53 },
{ 36, 52, 48, 44, 57, 57, 53, 44, 56, 56, 52, 46, 56, 49 },
{ 36, 52, 49, 44, 48, 54, 56, 44, 56, 53, 55, 46, 57, 51 },
{ 36, 52, 49, 44, 50, 54, 50, 44, 50, 53, 57, 46, 48, 55 },
{ 36, 52, 49, 44, 51, 51, 53, 44, 50, 51, 50, 46, 50, 48 },
{ 36, 52, 49, 44, 52, 53, 51, 44, 56, 54, 57, 46, 52, 53 },
{ 36, 52, 49, 44, 53, 50, 56, 44, 54, 51, 51, 46, 51, 51 },
{ 36, 52, 49, 44, 54, 48, 49, 44, 54, 48, 54, 46, 52, 53 },
{ 36, 52, 49, 44, 55, 50, 48, 44, 50, 52, 51, 46, 55, 48 },
{ 36, 52, 49, 44, 55, 57, 53, 44, 48, 48, 55, 46, 53, 57 },
{ 36, 52, 49, 44, 57, 56, 54, 44, 54, 49, 55, 46, 57, 55 },
{ 36, 52, 50, 44, 48, 51, 52, 44, 48, 55, 50, 46, 56, 55 },
{ 36, 52, 50, 44, 49, 48, 55, 44, 48, 52, 53, 46, 57, 56 },
{ 36, 52, 50, 44, 49, 51, 52, 44, 51, 53, 52, 46, 57, 56 },
};
}

View file

@ -0,0 +1,193 @@
/*
* Copyright (c) 2024, 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 8331485
* @summary Ensure correctness when parsing large (+/-) exponent values that
* exceed Integer.MAX_VALUE and Long.MAX_VALUE.
* @run junit/othervm --add-opens java.base/java.text=ALL-UNNAMED LargeExponentsTest
*/
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.ParsePosition;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.assertEquals;
// We prevent odd results when parsing large exponent values by ensuring
// that we properly handle overflow in the implementation of DigitList
public class LargeExponentsTest {
// Exponent symbol is 'E'
private static final NumberFormat FMT = NumberFormat.getInstance(Locale.US);
// Check that the parsed value and parse position index are both equal to the expected values.
// We are mainly checking that an exponent > Integer.MAX_VALUE no longer
// parses to 0 and that an exponent > Long.MAX_VALUE no longer parses to the mantissa.
@ParameterizedTest
@MethodSource({"largeExponentValues", "smallExponentValues", "bugReportValues", "edgeCases"})
public void overflowTest(String parseString, Double expectedValue) throws ParseException {
checkParse(parseString, expectedValue);
checkParseWithPP(parseString, expectedValue);
}
// A separate white-box test to avoid the memory consumption of testing cases
// when the String is near Integer.MAX_LENGTH
@ParameterizedTest
@MethodSource
public void largeDecimalAtExponentTest(int expected, int decimalAt, long expVal)
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
DecimalFormat df = new DecimalFormat();
Method m = df.getClass().getDeclaredMethod(
"shiftDecimalAt", int.class, long.class);
m.setAccessible(true);
assertEquals(expected, m.invoke(df, decimalAt, expVal));
}
// Cases where we can test behavior when the String is near Integer.MAX_LENGTH
private static Stream<Arguments> largeDecimalAtExponentTest() {
return Stream.of(
// Equivalent to testing Arguments.of("0."+"0".repeat(Integer.MAX_VALUE-20)+"1"+"E2147483650", 1.0E22)
// This is an absurdly long decimal string with length close to Integer.MAX_VALUE
// where the decimal position correctly negates the exponent value, even if it exceeds Integer.MAX_VALUE
Arguments.of(23, -(Integer.MAX_VALUE-20), 3L+Integer.MAX_VALUE),
Arguments.of(-23, Integer.MAX_VALUE-20, -(3L+Integer.MAX_VALUE)),
Arguments.of(Integer.MIN_VALUE, -(Integer.MAX_VALUE-20), -(3L+Integer.MAX_VALUE)),
Arguments.of(Integer.MAX_VALUE, Integer.MAX_VALUE-20, 3L+Integer.MAX_VALUE),
Arguments.of(Integer.MAX_VALUE, -(Integer.MAX_VALUE-20), Long.MAX_VALUE),
Arguments.of(Integer.MIN_VALUE, Integer.MAX_VALUE-20, Long.MIN_VALUE)
);
}
// Checks the parse(String, ParsePosition) method
public void checkParse(String parseString, Double expectedValue) {
ParsePosition pp = new ParsePosition(0);
Number actualValue = FMT.parse(parseString, pp);
assertEquals(expectedValue, (double)actualValue);
assertEquals(parseString.length(), pp.getIndex());
}
// Checks the parse(String) method
public void checkParseWithPP(String parseString, Double expectedValue)
throws ParseException {
Number actualValue = FMT.parse(parseString);
assertEquals(expectedValue, (double)actualValue);
}
// Generate large enough exponents that should all be parsed as infinity
// when positive. This includes exponents that exceed Long.MAX_VALUE
private static List<Arguments> largeExponentValues() {
return createExponentValues(false);
}
// Same as previous provider but for negative exponent values, so expecting
// a parsed value of 0.
private static List<Arguments> smallExponentValues() {
return createExponentValues(true);
}
// Programmatically generate some large parse values that are expected
// to be parsed as infinity or 0
private static List<Arguments> createExponentValues(boolean negative) {
List<Arguments> args = new ArrayList<>();
// Start with a base value that should be parsed as infinity
String baseValue = "12234.123E1100";
// Continuously add to the String until we trigger the overflow condition
for (int i = 0; i < 100; i++) {
StringBuilder bldr = new StringBuilder();
// Add to exponent
bldr.append(baseValue).append("1".repeat(i));
// Add to mantissa
bldr.insert(0, "1".repeat(i));
args.add(Arguments.of(
// Prepend "-" to exponent if negative
negative ? bldr.insert(bldr.indexOf("E")+1, "-").toString() : bldr.toString(),
// Expect 0 if negative, else infinity
negative ? 0.0 : Double.POSITIVE_INFINITY));
}
return args;
}
// The provided values are all from the JBS issue
// These contain exponents that exceed Integer.MAX_VALUE, but not Long.MAX_VALUE
private static Stream<Arguments> bugReportValues() {
return Stream.of(
Arguments.of("0.123E1", 1.23),
Arguments.of("0.123E309", 1.23E308),
Arguments.of("0.123E310", Double.POSITIVE_INFINITY),
Arguments.of("0.123E2147483647", Double.POSITIVE_INFINITY),
Arguments.of("0.123E2147483648", Double.POSITIVE_INFINITY),
Arguments.of("0.0123E2147483648", Double.POSITIVE_INFINITY),
Arguments.of("0.0123E2147483649", Double.POSITIVE_INFINITY),
Arguments.of("1.23E2147483646", Double.POSITIVE_INFINITY),
Arguments.of("1.23E2147483647", Double.POSITIVE_INFINITY),
Arguments.of("0.123E4294967296", Double.POSITIVE_INFINITY),
Arguments.of("0.123E-322", 9.9E-324),
Arguments.of("0.123E-323", 0.0),
Arguments.of("0.123E-2147483647", 0.0),
Arguments.of("0.123E-2147483648", 0.0),
Arguments.of("0.123E-2147483649", 0.0)
);
}
// Some other edge case values to ensure parse correctness
private static Stream<Arguments> edgeCases() {
return Stream.of(
// Exponent itself does not cause underflow, but decimalAt adjustment
// based off mantissa should. decimalAt(-1) + exponent(Integer.MIN_VALUE) = underflow
Arguments.of("0.0123E-2147483648", 0.0),
// 0 exponent
Arguments.of("1.23E0", 1.23),
// Leading zeroes
Arguments.of("1.23E0000123", 1.23E123),
// Leading zeroes - Past Long.MAX_VALUE length
Arguments.of("1.23E00000000000000000000000000000000000000000123", 1.23E123),
// Trailing zeroes
Arguments.of("1.23E100", 1.23E100),
// Long.MAX_VALUE length
Arguments.of("1.23E1234567891234567800", Double.POSITIVE_INFINITY),
// Long.MAX_VALUE with trailing zeroes
Arguments.of("1.23E9223372036854775807000", Double.POSITIVE_INFINITY),
// Long.MIN_VALUE
Arguments.of("1.23E-9223372036854775808", 0.0),
// Exponent value smaller than Long.MIN_VALUE
Arguments.of("1.23E-9223372036854775809", 0.0),
// Exponent value equal to Long.MAX_VALUE
Arguments.of("1.23E9223372036854775807", Double.POSITIVE_INFINITY),
// Exponent value larger than Long.MAX_VALUE
Arguments.of("1.23E9223372036854775808", Double.POSITIVE_INFINITY)
);
}
}

View file

@ -0,0 +1,103 @@
/*
* Copyright (c) 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 8159023
* @summary Confirm behavior of mantissa for scientific notation in Decimal Format
* @run junit MantissaDigits
*/
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.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 MantissaDigits {
private static final double[] NUMBERS = {
1.1, 12.1, 123.1, 1234.1, 12345.1, 123456.1,
-1.1, -12.1, -123.1, -1234.1, -12345.1, -123456.1,
1, 12, 123, 1234, 12345, 123456, 1234567,
-1, -12, -123, -1234, -12345, -123456, -1234567,
1.1234, 1.1111, 1.412, 222.333, -771.2222
};
private static final DecimalFormatSymbols DFS = new DecimalFormatSymbols(Locale.US);
private static final String ERRMSG = "%s formatted with %s gives %s, and " +
"significant digit count was %s, but the formula provided %s%n";
// Hard coded as 1, since all test patterns only have 1 exponent digit
private static final int EXPONENTDIGITS = 1;
@ParameterizedTest
@MethodSource("patterns")
public void testMantissaDefinition(String pattern, int minDigits, int maxDigits) {
DecimalFormat df = new DecimalFormat(pattern, DFS);
for (double number : NUMBERS) {
// Count the significant digits in the pre-formatted number
int originalNumDigits = (int) String.valueOf(number).chars()
.filter(Character::isDigit).count();
if (wholeNumber(number)) {
// Trailing 0 should not be counted
originalNumDigits--;
}
// Format the number, then grab the significant
// digits inside the mantissa
String formattedNum = df.format(number);
int mantissaDigits = (int) formattedNum.chars()
.filter(Character::isDigit).count() - EXPONENTDIGITS;
// Test the new definition of the Mantissa
Integer calculatedDigits = Math
.min(Math.max(minDigits, originalNumDigits), maxDigits);
assertEquals(mantissaDigits, calculatedDigits, String.format(ERRMSG,
number, pattern, formattedNum, mantissaDigits, calculatedDigits));
}
}
private static Boolean wholeNumber(double number) {
return (int) number == number;
}
private static Stream<Arguments> patterns() {
return Stream.of(
Arguments.of("#0.0##E0", 2, 5),
Arguments.of("#00.00##E0", 4, 7),
Arguments.of("#0.000##E0", 4, 7),
Arguments.of("#00.000##E0", 5, 8),
Arguments.of("#000.0##E0", 4, 7),
Arguments.of("#000.00##E0", 5, 8),
Arguments.of("#000.000##E0", 6, 9),
Arguments.of("000.000E0", 6, 6),
Arguments.of("#.##E0", 0, 3),
Arguments.of("######.######E0", 0, 12),
Arguments.of("####00.00######E0", 4, 14)
);
}
}

View file

@ -0,0 +1,57 @@
#
# Copyright (c) 1999, 2016, 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.
#
# Hex dump of a serialized NumberFormat for NumberRegression.
aced0005737200176a6176612e746578742e446563696d616c466f726d61740b
ff0362d872303a02000b5a001b646563696d616c536570617261746f72416c77
61797353686f776e42000c67726f7570696e6753697a654200116d696e457870
6f6e656e7444696769747349000a6d756c7469706c6965724900157365726961
6c56657273696f6e4f6e53747265616d5a00167573654578706f6e656e746961
6c4e6f746174696f6e4c000e6e656761746976655072656669787400124c6a61
76612f6c616e672f537472696e673b4c000e6e65676174697665537566666978
71007e00014c000e706f73697469766550726566697871007e00014c000e706f
73697469766553756666697871007e00014c000773796d626f6c737400204c6a
6176612f746578742f446563696d616c466f726d617453796d626f6c733b7872
00166a6176612e746578742e4e756d626572466f726d6174dff6b3bf137d07e8
03000b5a000c67726f7570696e67557365644200116d61784672616374696f6e
4469676974734200106d6178496e74656765724469676974734900156d617869
6d756d4672616374696f6e4469676974734900146d6178696d756d496e746567
65724469676974734200116d696e4672616374696f6e4469676974734200106d
696e496e74656765724469676974734900156d696e696d756d4672616374696f
6e4469676974734900146d696e696d756d496e74656765724469676974735a00
107061727365496e74656765724f6e6c7949001573657269616c56657273696f
6e4f6e53747265616d787200106a6176612e746578742e466f726d6174fbd8bc
12e90f18430200007870017f7f00000123000001217f7f000001240000012200
00000001780003000000000100000001007400012d7400007400007400007372
001e6a6176612e746578742e446563696d616c466f726d617453796d626f6c73
501d17990868939c02000f430010646563696d616c536570617261746f724300
05646967697443000b6578706f6e656e7469616c43001167726f7570696e6753
6570617261746f724300096d696e75735369676e4300116d6f6e657461727953
6570617261746f724300107061747465726e536570617261746f724300077065
724d696c6c43000770657263656e7449001573657269616c56657273696f6e4f
6e53747265616d4300097a65726f44696769744c00034e614e71007e00014c00
0e63757272656e637953796d626f6c71007e00014c0008696e66696e69747971
007e00014c0012696e746c43757272656e637953796d626f6c71007e00017870
002e00230045002c002d002e003b20300025000000010030740003efbfbd7400
0124740003e2889e740003555344

View file

@ -0,0 +1,57 @@
#
# Copyright (c) 1999, 2016, 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.
#
# Hex dump of a serialized NumberFormat for NumberRegression.
aced0005737200176a6176612e746578742e446563696d616c466f726d61740b
ff0362d872303a02000b5a001b646563696d616c536570617261746f72416c77
61797353686f776e42000c67726f7570696e6753697a654200116d696e457870
6f6e656e7444696769747349000a6d756c7469706c6965724900157365726961
6c56657273696f6e4f6e53747265616d5a00167573654578706f6e656e746961
6c4e6f746174696f6e4c000e6e656761746976655072656669787400124c6a61
76612f6c616e672f537472696e673b4c000e6e65676174697665537566666978
71007e00014c000e706f73697469766550726566697871007e00014c000e706f
73697469766553756666697871007e00014c000773796d626f6c737400204c6a
6176612f746578742f446563696d616c466f726d617453796d626f6c733b7872
00166a6176612e746578742e4e756d626572466f726d6174dff6b3bf137d07e8
03000b5a000c67726f7570696e67557365644200116d61784672616374696f6e
4469676974734200106d6178496e74656765724469676974734900156d617869
6d756d4672616374696f6e4469676974734900146d6178696d756d496e746567
65724469676974734200116d696e4672616374696f6e4469676974734200106d
696e496e74656765724469676974734900156d696e696d756d4672616374696f
6e4469676974734900146d696e696d756d496e74656765724469676974735a00
107061727365496e74656765724f6e6c7949001573657269616c56657273696f
6e4f6e53747265616d787200106a6176612e746578742e466f726d6174fbd8bc
12e90f18430200007870017f7f00000314000003127f7f000003130000031100
00000001780003000000000100000001007400012d7400007400007400007372
001e6a6176612e746578742e446563696d616c466f726d617453796d626f6c73
501d17990868939c02000f430010646563696d616c536570617261746f724300
05646967697443000b6578706f6e656e7469616c43001167726f7570696e6753
6570617261746f724300096d696e75735369676e4300116d6f6e657461727953
6570617261746f724300107061747465726e536570617261746f724300077065
724d696c6c43000770657263656e7449001573657269616c56657273696f6e4f
6e53747265616d4300097a65726f44696769744c00034e614e71007e00014c00
0e63757272656e637953796d626f6c71007e00014c0008696e66696e69747971
007e00014c0012696e746c43757272656e637953796d626f6c71007e00017870
002e00230045002c002d002e003b20300025000000010030740003efbfbd7400
0124740003e2889e740003555344

View file

@ -0,0 +1,796 @@
/*
* Copyright (c) 2012, 2022, 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 7050528
* @summary Test java.text.DecimalFormat fast-path for format(double...)
* @author Olivier Lagneau
* @build GoldenDoubleValues GoldenFormattedValues
* @run main RoundingAndPropertyTest
*
*/
/* -----------------------------------------------------------------------------
* Note :
* Since fast-path algorithm does not modify any feature of DecimalFormat,
* some tests or values in this program may have to be adapted/added/removed
* when any change has been done in the fast-path source code, because the
* conditions for exercising fast-path may change.
*
* This is specially true if the set of constraints to fall in the fast-path
* case is relaxed in any manner.
*
* Usage :
* - Run main without any argument to test against a set of golden values and
* associated results hard-coded in the source code. That will do the tests
* described below
* See below comment section named "Description".
*
* or
*
* - Run main with string argument "-gengold" to output source code of
* GoldenFormattedValues.java class file with the jdk version used while
* generating the code.
* See below comment section named : "Modifying Golden Values".
*
* In case of error while running the test, a Runtime exception is generated
* providing the numbers of errors detected (format of golden values checks and
* property changes checks), and the program exit.
*
* Description :
*
* This test first checks that localization of digits is done correctly when
* calling DecimalFormat.format() on the array of values DecimalLocalizationValues
* found in GoldenDoubleValues, using the locale FullLocalizationTestLocale
* (from GoldenDoubleValues) that implies localization of digits. it checks the
* the results against expected returned string. In case of formatting error,
* it provides a message informing which value was wrongly formatted.
*
* Then it checks the results of calling NumberFormat.format(double) on a set
* of predefined golden values and checks results against expected returned
* string. It does this both for the decimal case, with an instance returned
* NumberFormat.getInstance() call and for the currency case, with an instance
* returned by NumberFormat.getCurrencyInstance(). Almost all the tested double
* values satisfy the constraints assumed by the fast-path algorithm for
* format(double ...). Some are voluntarily outside the scope of fast-path to
* check that the algorithm correctly eliminate them. In case of formatting
* error a message provides information on the golden value raising the error
* (value, exact decimal value (using BidDecimal), expected result, formatted result).
*
* Last the test checks the status and behavior of a DecimalFormat instance
* when changing properties that make this instance satisfy/invalidate its
* fast-path status, depending on the predefined set of fast-path constraints.
*
* The golden results are predefined arrays of int[] containing the unicode
* ints of the chars in the expected formatted string, when using locale
* provided in GoldenDoubleValues class. The results are those obtained by
* using a reference jdk version (for example one that does not contains the
* DecimalFormat fast-path algorithm, like jdk80-b25).
*
* The double values from which we get golden results are stored inside two
* arrays of double values:
* - DecimalGoldenValues for testing NumberFormat.getInstance().
* - CurrencyGoldenValues for testing NumberFormat.getCurrencyInstance().
* These arrays are located in GoldenDoubleValues.java source file.
*
* For each double value in the arrays above, there is an associated golden
* result. These results are stored in arrays of int[]:
* - DecimalGoldenFormattedValues for expected decimal golden results.
* - CurrencyGoldenFormattedValues for expected currency golden results.
* - DecimalDigitsLocalizedFormattedValues for expected localized digit results.
*
* We store the results in int[] arrays containing the expected unicode values
* because the compiler that will compile the containing java file may use a
* different locale than the one registered in GoldenDoubleValues.java. These
* arrays are located in a separate GoldenFormattedValues.java source file
* that is generated by RoundingAndPropertyTest using "-gengold" parameter.
* See below "Modifying Golden Values".
*
* The golden value arrays can be expanded, modified ... to test additional
* or different double values. In that case, the source file of class
* GoldenFormattedValues must be regenerated to replace the existing one..
*
* Modifying Golden Values :
*
* In order to ease further modification of the list of double values checked
* and associated golden results, the test includes the method
* generatesGoldenFormattedValuesClass() that writes on standard output stream
* the source code for GoldenFormattedValues class that includes the expected
* results arrays.
*
* Here are the steps to follow for updating/modifying golden values and results:
* 1- Edit GoldenDoubleValues.java to add/remove/modify golden or localization
* values.
* 2- Run main with "-gengold" string argument with a target jdk.
* (at the creation of this test file, the target jdk used was jdk1.8.0-ea).
* 2- Copy this java code that has been writen on standard output and replace
* GoldenFormattedValues.java contents by the generated output.
* 3- Check that this updated code compiles.
* [4]- If needed replaces existing GoldenDoubleValues and GoldenFormattedValues
* files in jdk/test section, respectively by the one modified at step 1 and
* generated at step 2.
* -----------------------------------------------------------------------------
*/
import java.util.*;
import java.text.NumberFormat;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.math.RoundingMode;
import java.math.BigDecimal;
public class RoundingAndPropertyTest {
// Prints on standard output stream the unicode values of chars as a
// comma-separated list of int values
private static void printUnicodeValuesArray(char[] chars) {
for (int i = 0; i < chars.length; i++) {
System.out.print((int) chars[i]);
if (i != (chars.length - 1))
System.out.print(", ");
}
}
// Converts given array of unicode values as an array of chars.
// Returns this converted array.
private static char[] getCharsFromUnicodeArray(int[] unicodeValues) {
char[] chars = new char[unicodeValues.length];
for (int i = 0; i < unicodeValues.length; i++) {
chars[i] = (char) unicodeValues[i];
}
return chars;
}
/* Prints on standard output stream the java code of resulting
* GoldenFormattedValues class for the golden values found in
* class GoldenDoubleValues.
*/
private static void generatesGoldenFormattedValuesClass() {
String fourWhiteSpaces = " ";
String eightWhiteSpaces = " ";
// Prints header without Copyright header.
System.out.println("/* This is a machine generated file - Please DO NOT EDIT !");
System.out.println(" * Change RoundingAndPropertyTest instead,");
System.out.println(" * and run with \"-gengold\" argument to regenerate (without copyright header).");
System.out.println(" */");
System.out.println();
System.out.println("/* This file contains the set of result Strings expected from calling inside");
System.out.println(" * RoundingAndPropertyTest the method NumberFormat.format() upon the set of");
System.out.println(" * double values provided in GoldenDoubleValues.java. It contains three arrays,");
System.out.println(" * each containing arrays of unicode values representing the expected string");
System.out.println(" * result when calling format() on the corresponding (i.e. same index) double");
System.out.println(" * value found in GoldenDoubleValues arrays :");
System.out.println(" * - DecimalDigitsLocalizedFormattedValues corresponds to DecimalLocalizationValues,");
System.out.println(" * when using FullLocalizationTestLocale to format.");
System.out.println(" * - DecimalGoldenFormattedValues corresponds to DecimalGoldenValues, when used");
System.out.println(" * in the decimal pattern case together with TestLocale.");
System.out.println(" * - CurrencyGoldenFormattedValues corresponds to CurrencyGoldenValues. when used");
System.out.println(" * in the currency pattern case together with TestLocale.");
System.out.println(" * Please see documentation in RoundingAndPropertyTest.java for more details.");
System.out.println(" *");
System.out.println(" * This file generated by running RoundingAndPropertyTest with \"-gengold\" argument.");
System.out.println(" */");
System.out.println();
// Prints beginning of class GoldenFormattedValues.
System.out.println("class GoldenFormattedValues {");
System.out.println();
System.out.println(
fourWhiteSpaces +
"// The formatted values below were generated from golden values");
System.out.print(
fourWhiteSpaces +
"// listed in GoldenDoubleValues.java,");
System.out.println(" using the following jvm version :");
System.out.println(
fourWhiteSpaces + "// " +
System.getProperty("java.vendor") +
" " +
System.getProperty("java.vm.name") +
" " +
System.getProperty("java.version"));
System.out.println(
fourWhiteSpaces +
"// locale for golden double values : " + GoldenDoubleValues.TestLocale);
System.out.println(
fourWhiteSpaces +
"// locale for testing digit localization : " + GoldenDoubleValues.FullLocalizationTestLocale);
System.out.println();
// Prints the expected results when digit localization happens
System.out.println(
fourWhiteSpaces +
"// The array of int[] unicode values storing the expected results");
System.out.print(
fourWhiteSpaces +
"// when experiencing full localization of digits");
System.out.println(" on DecimalLocalizationValues.");
System.out.println(
fourWhiteSpaces +
"static int[][] DecimalDigitsLocalizedFormattedValues = {");
NumberFormat df =
NumberFormat.getInstance(GoldenDoubleValues.FullLocalizationTestLocale);
for (int i = 0;
i < GoldenDoubleValues.DecimalLocalizationValues.length;
i++) {
double d = GoldenDoubleValues.DecimalLocalizationValues[i];
String formatted = df.format(d);
char[] decFmtChars = formatted.toCharArray();
System.out.print(eightWhiteSpaces + "{ ");
printUnicodeValuesArray(decFmtChars);
System.out.println(" },");
}
System.out.println(fourWhiteSpaces + "};");
System.out.println();
// Prints the golden expected results for the decimal pattern case
System.out.println(
fourWhiteSpaces +
"// The array of int[] unicode values storing the expected results");
System.out.print(
fourWhiteSpaces +
"// when calling Decimal.format(double)");
System.out.println(" on the decimal GoldenDoubleValues.");
System.out.println(
fourWhiteSpaces +
"static int[][] DecimalGoldenFormattedValues = {");
df = NumberFormat.getInstance(GoldenDoubleValues.TestLocale);
for (int i = 0;
i < GoldenDoubleValues.DecimalGoldenValues.length;
i++) {
double d = GoldenDoubleValues.DecimalGoldenValues[i];
String formatted = df.format(d);
char[] decFmtChars = formatted.toCharArray();
System.out.print(eightWhiteSpaces + "{ ");
printUnicodeValuesArray(decFmtChars);
System.out.println(" },");
}
System.out.println(fourWhiteSpaces + "};");
System.out.println();
// Prints the golden expected results for the currency pattern case
System.out.println(
fourWhiteSpaces +
"// The array of int[] unicode values storing the expected results");
System.out.print(
fourWhiteSpaces +
"// when calling Decimal.format(double)");
System.out.println(" on the currency GoldenDoubleValues.");
System.out.println(
fourWhiteSpaces +
"static int[][] CurrencyGoldenFormattedValues = {");
NumberFormat cf =
NumberFormat.getCurrencyInstance(GoldenDoubleValues.TestLocale);
for (int i = 0;
i < GoldenDoubleValues.CurrencyGoldenValues.length;
i++) {
double d = GoldenDoubleValues.CurrencyGoldenValues[i];
String formatted = cf.format(d);
char[] decFmtChars = formatted.toCharArray();
System.out.print(eightWhiteSpaces + "{ ");
printUnicodeValuesArray(decFmtChars);
System.out.println(" },");
}
System.out.println(fourWhiteSpaces + "};");
System.out.println();
// Prints end of GoldenFormattedValues class.
System.out.println("}");
}
private static int testLocalizationValues() {
DecimalFormat df = (DecimalFormat)
NumberFormat.getInstance(GoldenDoubleValues.FullLocalizationTestLocale);
double[] localizationValues = GoldenDoubleValues.DecimalLocalizationValues;
int size = localizationValues.length;
int successCounter = 0;
int failureCounter = 0;
for (int i = 0; i < size; i++) {
double d = localizationValues[i];
String formatted = df.format(d);
char[] expectedUnicodeArray =
getCharsFromUnicodeArray(
GoldenFormattedValues.DecimalDigitsLocalizedFormattedValues[i]);
String expected = new String(expectedUnicodeArray);
if (!formatted.equals(expected)) {
failureCounter++;
System.out.println(
"--- Localization error for value d = " + d +
". Exact value = " + new BigDecimal(d).toString() +
". Expected result = " + expected +
". Output result = " + formatted);
} else successCounter++;
}
System.out.println("Checked positively " + successCounter +
" golden decimal values out of " + size +
" tests. There were " + failureCounter +
" format failure");
return failureCounter;
}
private static int testGoldenValues(java.text.DecimalFormat df,
java.text.DecimalFormat cf) {
double[] goldenDecimalValues = GoldenDoubleValues.DecimalGoldenValues;
int decimalSize = goldenDecimalValues.length;
int decimalSuccessCounter = 0;
int decimalFailureCounter = 0;
for (int i = 0; i < decimalSize; i++) {
double d = goldenDecimalValues[i];
String formatted = df.format(d);
char[] expectedUnicodeArray =
getCharsFromUnicodeArray(
GoldenFormattedValues.DecimalGoldenFormattedValues[i]);
String expected = new String(expectedUnicodeArray);
if (!formatted.equals(expected)) {
decimalFailureCounter++;
System.out.println(
"--- Error for golden value d = " + d +
". Exact value = " + new BigDecimal(d).toString() +
". Expected result = " + expected +
". Output result = " + formatted);
} else decimalSuccessCounter++;
}
System.out.println("Checked positively " + decimalSuccessCounter +
" golden decimal values out of " + decimalSize +
" tests. There were " + decimalFailureCounter +
" format failure");
double[] goldenCurrencyValues = GoldenDoubleValues.CurrencyGoldenValues;
int currencySize = goldenCurrencyValues.length;
int currencySuccessCounter = 0;
int currencyFailureCounter = 0;
for (int i = 0; i < currencySize; i++) {
double d = goldenCurrencyValues[i];
String formatted = cf.format(d);
char[] expectedUnicodeArray =
getCharsFromUnicodeArray(
GoldenFormattedValues.CurrencyGoldenFormattedValues[i]);
String expected = new String(expectedUnicodeArray);
if (!formatted.equals(expected)) {
currencyFailureCounter++;
System.out.println(
"--- Error for golden value d = " + d +
". Exact value = " + new BigDecimal(d).toString() +
". Expected result = " + expected +
". Output result = " + formatted);
} else currencySuccessCounter++;
}
System.out.println("Checked positively " + currencySuccessCounter +
" golden currency values out of " + currencySize +
" tests. There were " + currencyFailureCounter +
" format failure");
return (decimalFailureCounter + currencyFailureCounter);
}
// Checks that the two passed s1 and s2 string are equal, and prints
// out message in case of error.
private static boolean resultsEqual(String propertyName,
String s1,
String s2) {
boolean equality = s1.equals(s2);
if (!equality)
System.out.println(
"\n*** Error while reverting to default " +
propertyName + " property.\n" +
" initial output = " + s1 +
". reverted output = " + s2 + ".");
else System.out.println(" Test passed.");
return equality;
}
/* This methods checks the behaviour of the management of properties
* of a DecimalFormat instance that satisfies fast-path constraints.
*
* It does this by comparing the results of the format(double) output
* obtained from initial fast-path state with the output provided by
* the same instance that has been pushed and exercised outside
* fast-path rules and finally "reverted" to its initial fast-path state.
*
* The schema of actions is this :
* - Call format(double) on a known DecimalFormat fast-path instance,
* and store this result.
* - Record the current state of a given property.
* - Change the property to invalidate the fast-path state.
* - Call again format(double) on the instance.
* - Revert state of property to validate again fast-path context.
* - Call format(double) again.
* - Check that first and last call to format(double) provide same result
* - Record failure if any.
* - Do the same for another property with the same instance.
* So all the property changes are chained one after the other on only the
* same instance.
*
* Some properties that currently do not influence the fast-path state
* are also tested. This is not useful with current fast-path source
* but is here for testing the whole set of properties. This is the case
* for prefixes and suffixes, and parseBigDecimal properties.
*/
private static int testSettersAndFastPath(DecimalFormat df,
boolean isCurrency) {
final double d1 = GoldenDoubleValues.PROPERTY_CHECK_POSITIVE_VALUE;
final double d2 = GoldenDoubleValues.PROPERTY_CHECK_NEGATIVE_VALUE;
int errors = 0;
boolean testSucceeded = false;
String firstFormatResult;
String secondFormatResult;
String propertyName;
// ---- positivePrefix property test ----
testSucceeded = false;
propertyName = "positivePrefix";
System.out.print("Checking " + propertyName + " property.");
String initialPrefix = df.getPositivePrefix();
firstFormatResult = df.format(d1);
df.setPositivePrefix("positivePrefix:");
df.format(d1);
df.setPositivePrefix(initialPrefix);
secondFormatResult = df.format(d1);
testSucceeded =
resultsEqual(propertyName, firstFormatResult, secondFormatResult);
if (!testSucceeded)
errors++;
// ---- positiveSuffix property test ----
testSucceeded = false;
propertyName = "positiveSuffix";
System.out.print("Checking " + propertyName + " property.");
String initialSuffix = df.getPositiveSuffix();
firstFormatResult = df.format(d1);
df.setPositiveSuffix("positiveSuffix:");
df.format(d1);
df.setPositiveSuffix(initialSuffix);
secondFormatResult = df.format(d1);
testSucceeded =
resultsEqual(propertyName,firstFormatResult, secondFormatResult);
if (!testSucceeded)
errors++;
// ---- negativePrefix property test ----
testSucceeded = false;
propertyName = "negativePrefix";
System.out.print("Checking " + propertyName + " property.");
initialPrefix = df.getNegativePrefix();
firstFormatResult = df.format(d1);
df.setNegativePrefix("negativePrefix:");
df.format(d1);
df.setNegativePrefix(initialPrefix);
secondFormatResult = df.format(d1);
testSucceeded =
resultsEqual(propertyName, firstFormatResult, secondFormatResult);
if (!testSucceeded)
errors++;
// ---- negativeSuffix property test ----
testSucceeded = false;
propertyName = "negativeSuffix";
System.out.print("Checking " + propertyName + " property.");
initialSuffix = df.getNegativeSuffix();
firstFormatResult = df.format(d1);
df.setNegativeSuffix("negativeSuffix:");
df.format(d1);
df.setNegativeSuffix(initialSuffix);
secondFormatResult = df.format(d1);
testSucceeded =
resultsEqual(propertyName, firstFormatResult, secondFormatResult);
if (!testSucceeded)
errors++;
// ---- multiplier property test ----
testSucceeded = false;
propertyName = "multiplier";
System.out.print("Checking " + propertyName + " property.");
int initialMultiplier = df.getMultiplier();
firstFormatResult = df.format(d1);
df.setMultiplier(10);
df.format(d1);
df.setMultiplier(initialMultiplier);
secondFormatResult = df.format(d1);
testSucceeded =
resultsEqual(propertyName, firstFormatResult, secondFormatResult);
if (!testSucceeded)
errors++;
// ---- groupingUsed property test ----
testSucceeded = false;
propertyName = "groupingUsed";
System.out.print("Checking " + propertyName + " property.");
boolean initialGroupingUsed = df.isGroupingUsed();
firstFormatResult = df.format(d1);
df.setGroupingUsed(!initialGroupingUsed);
df.format(d1);
df.setGroupingUsed(initialGroupingUsed);
secondFormatResult = df.format(d1);
testSucceeded =
resultsEqual(propertyName, firstFormatResult, secondFormatResult);
if (!testSucceeded)
errors++;
// ---- groupingSize property test ----
testSucceeded = false;
propertyName = "groupingSize";
System.out.print("Checking " + propertyName + " property.");
int initialGroupingSize = df.getGroupingSize();
firstFormatResult = df.format(d1);
df.setGroupingSize(initialGroupingSize + 1);
df.format(d1);
df.setGroupingSize(initialGroupingSize);
secondFormatResult = df.format(d1);
testSucceeded =
resultsEqual(propertyName, firstFormatResult, secondFormatResult);
if (!testSucceeded)
errors++;
// ---- decimalSeparatorAlwaysShown property test ----
testSucceeded = false;
propertyName = "decimalSeparatorAlwaysShown";
System.out.print("Checking " + propertyName + " property.");
boolean initialDSShown = df.isDecimalSeparatorAlwaysShown();
firstFormatResult = df.format(d1);
df.setDecimalSeparatorAlwaysShown(!initialDSShown);
df.format(d1);
df.setDecimalSeparatorAlwaysShown(initialDSShown);
secondFormatResult = df.format(d1);
testSucceeded =
resultsEqual(propertyName, firstFormatResult, secondFormatResult);
if (!testSucceeded)
errors++;
// ---- parseBigDecimal property test ----
testSucceeded = false;
propertyName = "parseBigDecimal";
System.out.print("Checking " + propertyName + " property.");
boolean initialParseBigdecimal = df.isParseBigDecimal();
firstFormatResult = df.format(d1);
df.setParseBigDecimal(!initialParseBigdecimal);
df.format(d1);
df.setParseBigDecimal(initialParseBigdecimal);
secondFormatResult = df.format(d1);
testSucceeded =
resultsEqual(propertyName, firstFormatResult, secondFormatResult);
if (!testSucceeded)
errors++;
// ---- maximumIntegerDigits property test ----
testSucceeded = false;
propertyName = "maximumIntegerDigits";
System.out.print("Checking " + propertyName + " property.");
int initialMaxIDs = df.getMaximumIntegerDigits();
firstFormatResult = df.format(d1);
df.setMaximumIntegerDigits(8);
df.format(d1);
df.setMaximumIntegerDigits(initialMaxIDs);
secondFormatResult = df.format(d1);
testSucceeded =
resultsEqual(propertyName, firstFormatResult, secondFormatResult);
if (!testSucceeded)
errors++;
// ---- minimumIntegerDigits property test ----
testSucceeded = false;
propertyName = "minimumIntegerDigits";
System.out.print("Checking " + propertyName + " property.");
int initialMinIDs = df.getMinimumIntegerDigits();
firstFormatResult = df.format(d1);
df.setMinimumIntegerDigits(2);
df.format(d1);
df.setMinimumIntegerDigits(initialMinIDs);
secondFormatResult = df.format(d1);
testSucceeded =
resultsEqual(propertyName, firstFormatResult, secondFormatResult);
if (!testSucceeded)
errors++;
// ---- maximumFractionDigits property test ----
testSucceeded = false;
propertyName = "maximumFractionDigits";
System.out.print("Checking " + propertyName + " property.");
firstFormatResult = df.format(d1);
df.setMaximumFractionDigits(8);
df.format(d1);
if (isCurrency) {
df.setMinimumFractionDigits(2);
df.setMaximumFractionDigits(2);
} else {
df.setMinimumFractionDigits(0);
df.setMaximumFractionDigits(3);
}
secondFormatResult = df.format(d1);
testSucceeded =
resultsEqual(propertyName, firstFormatResult, secondFormatResult);
if (!testSucceeded)
errors++;
// ---- minimumFractionDigits property test ----
testSucceeded = false;
propertyName = "minimumFractionDigits";
System.out.print("Checking " + propertyName + " property.");
firstFormatResult = df.format(d1);
df.setMinimumFractionDigits(1);
df.format(d1);
if (isCurrency) {
df.setMinimumFractionDigits(2);
df.setMaximumFractionDigits(2);
} else {
df.setMinimumFractionDigits(0);
df.setMaximumFractionDigits(3);
}
secondFormatResult = df.format(d1);
testSucceeded =
resultsEqual(propertyName, firstFormatResult, secondFormatResult);
if (!testSucceeded)
errors++;
// ---- currency property test ----
testSucceeded = false;
propertyName = "currency";
System.out.print("Checking " + propertyName + " property.");
Currency initialCurrency = df.getCurrency();
Currency japanCur = java.util.Currency.getInstance(Locale.JAPAN);
firstFormatResult = df.format(d1);
df.setCurrency(japanCur);
df.format(d1);
df.setCurrency(initialCurrency);
secondFormatResult = df.format(d1);
testSucceeded =
resultsEqual(propertyName, firstFormatResult, secondFormatResult);
if (!testSucceeded)
errors++;
// ---- roundingMode property test ----
testSucceeded = false;
propertyName = "roundingMode";
System.out.print("Checking " + propertyName + " property.");
RoundingMode initialRMode = df.getRoundingMode();
firstFormatResult = df.format(d1);
df.setRoundingMode(RoundingMode.HALF_UP);
df.format(d1);
df.setRoundingMode(RoundingMode.HALF_EVEN);
secondFormatResult = df.format(d1);
testSucceeded =
resultsEqual(propertyName, firstFormatResult, secondFormatResult);
if (!testSucceeded)
errors++;
// ---- decimalFormatSymbols property test ----
testSucceeded = false;
propertyName = "decimalFormatSymbols";
System.out.print("Checking " + propertyName + " property.");
DecimalFormatSymbols initialDecimalFormatSymbols = df.getDecimalFormatSymbols();
firstFormatResult = df.format(d1);
Locale bizarreLocale = Locale.FRANCE;
DecimalFormatSymbols unusualSymbols = new DecimalFormatSymbols(bizarreLocale);
unusualSymbols.setDecimalSeparator('@');
unusualSymbols.setGroupingSeparator('|');
df.setDecimalFormatSymbols(unusualSymbols);
df.format(d1);
df.setDecimalFormatSymbols(initialDecimalFormatSymbols);
secondFormatResult = df.format(d1);
testSucceeded =
resultsEqual(propertyName, firstFormatResult, secondFormatResult);
if (!testSucceeded)
errors++;
testSucceeded = false;
System.out.print("Checking " + propertyName + " property.");
initialDecimalFormatSymbols = df.getDecimalFormatSymbols();
firstFormatResult = df.format(d1);
Locale japanLocale = Locale.JAPAN;
unusualSymbols = new DecimalFormatSymbols(japanLocale);
unusualSymbols.setDecimalSeparator('9');
unusualSymbols.setGroupingSeparator('0');
df.setDecimalFormatSymbols(unusualSymbols);
df.format(d1);
df.setDecimalFormatSymbols(initialDecimalFormatSymbols);
secondFormatResult = df.format(d1);
testSucceeded =
resultsEqual(propertyName, firstFormatResult, secondFormatResult);
if (!testSucceeded)
errors++;
return errors;
}
// Main for RoundingAndPropertyTest. We test first the golden values,
// and then the property setters and getters.
public static void main(String[] args) {
if ((args.length >= 1) &&
(args[0].equals("-gengold")))
generatesGoldenFormattedValuesClass();
else {
System.out.println("\nChecking correctness of formatting with digit localization.");
System.out.println("=============================================================");
int localizationErrors = testLocalizationValues();
if (localizationErrors != 0)
System.out.println("*** Failure in localization tests : " +
localizationErrors + " errors detected ");
else System.out.println(" Tests for full localization of digits all passed.");
DecimalFormat df = (DecimalFormat)
NumberFormat.getInstance(GoldenDoubleValues.TestLocale);
DecimalFormat cf = (DecimalFormat)
NumberFormat.getCurrencyInstance(GoldenDoubleValues.TestLocale);
System.out.println("\nChecking correctness of formating for golden values.");
System.out.println("=============================================================");
int goldenValuesErrors = testGoldenValues(df,cf);
if (goldenValuesErrors != 0)
System.out.println("*** Failure in goldenValues tests : " +
goldenValuesErrors + " errors detected ");
else System.out.println(" Tests for golden values all passed.");
System.out.println("\nChecking behavior of property changes for decimal case.");
System.out.println("=============================================================");
int decimalTestsErrors = testSettersAndFastPath(df, false);
if (decimalTestsErrors != 0)
System.out.println("*** Failure in decimal property changes tests : " +
decimalTestsErrors + " errors detected ");
else System.out.println(" Tests for decimal property changes all passed.");
System.out.println("\nChecking behavior of property changes for currency case.");
System.out.println("=============================================================");
int currencyTestsErrors = testSettersAndFastPath(cf, true);
if (currencyTestsErrors != 0)
System.out.println("*** Failure in currency property changes tests : " +
currencyTestsErrors + " errors detected ");
else System.out.println(" Tests for currency property chamges all passed.");
if ((localizationErrors > 0) ||
(goldenValuesErrors > 0) ||
(decimalTestsErrors > 0) ||
(currencyTestsErrors > 0))
throw new RuntimeException(
"Failed with " +
(localizationErrors + goldenValuesErrors +
decimalTestsErrors + currencyTestsErrors) +
" error(s).");
}
}
}

View file

@ -0,0 +1,83 @@
/*
* Copyright (c) 2025, 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 8369050
* @summary Check rounding of DecimalFormat on tie cases when the maximum
* fraction digits allowed is one less than the position of the first
* significant digit in the double.
* @run junit RoundingTiesNearZeroTest
*/
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.math.RoundingMode;
import java.text.NumberFormat;
import java.util.Locale;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class RoundingTiesNearZeroTest {
// Safe to re-use since we are not testing any fast-path cases
// so state is irrelevant
private static final NumberFormat format = NumberFormat.getInstance(Locale.US);
@ParameterizedTest
@MethodSource("ties")
void roundingTieTest(RoundingMode rm, int maxDigits, double db, String expected) {
format.setRoundingMode(rm);
format.setMaximumFractionDigits(maxDigits);
assertEquals(expected, format.format(db), "Rounding failed under " + rm);
}
static Stream<Arguments> ties() {
return Stream.of(
// 1) String is exact as binary
// 0.5 -> 0.5
Arguments.of(RoundingMode.HALF_EVEN, 0, 0.5, "0"),
Arguments.of(RoundingMode.HALF_UP, 0, 0.5, "1"),
Arguments.of(RoundingMode.HALF_DOWN, 0, 0.5, "0"),
// 2) String is rounded up from binary
// 0.0000005 -> 4.999999999999999773740559129431293428069693618454039096832275390625E-7
Arguments.of(RoundingMode.HALF_EVEN, 6, 0.0000005, "0"),
Arguments.of(RoundingMode.HALF_UP, 6, 0.0000005, "0"),
Arguments.of(RoundingMode.HALF_DOWN, 6, 0.0000005, "0"),
// 3) String is not rounded up from binary
// Non-exponential notation
// 0.05 -> 0.05000000000000000277555756156289135105907917022705078125
Arguments.of(RoundingMode.HALF_EVEN, 1, 0.05, "0.1"),
Arguments.of(RoundingMode.HALF_UP, 1, 0.05, "0.1"),
Arguments.of(RoundingMode.HALF_DOWN, 1, 0.05, "0.1"),
// Exponential notation
// 0.00005 -> 0.0000500000000000000023960868011929647991564706899225711822509765625
Arguments.of(RoundingMode.HALF_EVEN, 4, 0.00005, "0.0001"),
Arguments.of(RoundingMode.HALF_UP, 4, 0.00005, "0.0001"),
Arguments.of(RoundingMode.HALF_DOWN, 4, 0.00005, "0.0001")
);
}
}

View file

@ -0,0 +1,365 @@
/*
* Copyright (c) 2024, 2025, 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 4069754 4067878 4101150 4185761 8327640
* @library /java/text/testlib
* @build HexDumpReader
* @summary Check de-serialization correctness for DecimalFormat. That is, ensure the
* behavior for each stream version is correct during de-serialization.
* @run junit/othervm --add-opens java.base/java.text=ALL-UNNAMED SerializationTest
*/
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.math.RoundingMode;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Random;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class SerializationTest {
@Nested // Test that rely on hex dump files that were written from older JDK versions
class HexDumpTests {
@Test // See 4101150 and CDF which is the serialized hex dump
void JDK1_1_4Test() {
// Reconstruct a 1.1.4 serializable class which has a DF holder
var cdf = (CheckDecimalFormat) assertDoesNotThrow(
() -> deSer("DecimalFormat.114.txt"));
assertDoesNotThrow(cdf::Update); // Checks format call succeeds
}
@Test // See 4185761
void minMaxDigitsTest() {
// Reconstructing a DFS stream from an older JDK version
// The min digits are smaller than the max digits and should fail
// minint maxint minfrac maxfrac
// 0x122 0x121 0x124 0x123
assertEquals("Digit count range invalid",
assertThrows(InvalidObjectException.class,
() -> deSer("NumberFormat4185761a.ser.txt")).getMessage());
}
@Test // See 4185761
void digitLimitTest() {
// Reconstructing a DFS stream from an older JDK version
// The digit values exceed the class invariant limits
// minint maxint minfrac maxfrac
// 0x311 0x312 0x313 0x314
assertEquals("Digit count out of range",
assertThrows(InvalidObjectException.class,
() -> deSer("NumberFormat4185761b.ser.txt")).getMessage());
}
}
@Nested
class VersionTests {
// Version 0 did not have exponential fields and defaulted the value to false
@Test
void version0Test() {
var crafted = new DFBuilder()
.setVer(0)
.set("useExponentialNotation", true)
.build();
var bytes = ser(crafted);
var df = assertDoesNotThrow(() -> deSer(bytes));
// Ensure we do not observe exponential notation form
assertFalse(df.format(0).contains("E"));
}
// Version 1 did not support the affix pattern Strings. Ensure when they
// are read in from the stream they are not defaulted and remain null.
@Test
void version1Test() {
var crafted = new DFBuilder()
.setVer(1)
.set("posPrefixPattern", null)
.set("posSuffixPattern", null)
.set("negPrefixPattern", null)
.set("negSuffixPattern", null)
.build();
var bytes = ser(crafted);
var df = assertDoesNotThrow(() -> deSer(bytes));
assertNull(readField(df, "posPrefixPattern"));
assertNull(readField(df, "posSuffixPattern"));
assertNull(readField(df, "negPrefixPattern"));
assertNull(readField(df, "negSuffixPattern"));
}
// Version 2 did not support the min/max int and frac digits.
// Ensure the proper defaults are set.
@Test
void version2Test() {
var crafted = new DFBuilder()
.setVer(2)
.set("maximumIntegerDigits", -1)
.set("maximumFractionDigits", -1)
.set("minimumIntegerDigits", -1)
.set("minimumFractionDigits", -1)
.build();
var bytes = ser(crafted);
var df = assertDoesNotThrow(() -> deSer(bytes));
assertEquals(1, df.getMinimumIntegerDigits());
assertEquals(3, df.getMaximumFractionDigits());
assertEquals(309, df.getMaximumIntegerDigits());
assertEquals(0, df.getMinimumFractionDigits());
}
// Version 3 did not support rounding mode. Should default to HALF_EVEN
@Test
void version3Test() {
var crafted = new DFBuilder()
.setVer(3)
.set("roundingMode", RoundingMode.UNNECESSARY)
.build();
var bytes = ser(crafted);
var df = assertDoesNotThrow(() -> deSer(bytes));
assertEquals(RoundingMode.HALF_EVEN, df.getRoundingMode());
}
}
// Some invariant checking in DF relies on checking NF fields.
// Either via NF.readObject() or through super calls in DF.readObject
@Nested // For all these nested tests, see 4185761
class NumberFormatTests {
// Ensure the max integer value invariant is not exceeded
@Test
void integerTest() {
var crafted = new DFBuilder()
.setSuper("maximumIntegerDigits", 786)
.setSuper("minimumIntegerDigits", 785)
.build();
var bytes = ser(crafted);
assertEquals("Digit count out of range",
assertThrows(InvalidObjectException.class, () -> deSer(bytes)).getMessage());
}
// Ensure the max fraction value invariant is not exceeded
@Test
void fractionTest() {
var crafted = new DFBuilder()
.setSuper("maximumFractionDigits", 788)
.setSuper("minimumFractionDigits", 787)
.build();
var bytes = ser(crafted);
assertEquals("Digit count out of range",
assertThrows(InvalidObjectException.class, () -> deSer(bytes)).getMessage());
}
// Ensure the minimum integer digits cannot be greater than the max
@Test
void maxMinIntegerTest() {
var crafted = new DFBuilder()
.setSuper("maximumIntegerDigits", 5)
.setSuper("minimumIntegerDigits", 6)
.build();
var bytes = ser(crafted);
assertEquals("Digit count range invalid",
assertThrows(InvalidObjectException.class, () -> deSer(bytes)).getMessage());
}
// Ensure the minimum fraction digits cannot be greater than the max
@Test
void maxMinFractionTest() {
var crafted = new DFBuilder()
.setSuper("maximumFractionDigits", 5)
.setSuper("minimumFractionDigits", 6)
.build();
var bytes = ser(crafted);
assertEquals("Digit count range invalid",
assertThrows(InvalidObjectException.class, () -> deSer(bytes)).getMessage());
}
}
// Ensure the serial version is updated to the current after de-serialization.
@Test
void versionTest() {
var bytes = ser(new DFBuilder().setVer(-25).build());
var df = assertDoesNotThrow(() -> deSer(bytes));
assertEquals(4, readField(df, "serialVersionOnStream"));
}
// Ensure strictness value is read properly when it is set.
@Test
void strictnessTest() {
var crafted = new DecimalFormat();
crafted.setStrict(true);
var bytes = ser(crafted);
var df = assertDoesNotThrow(() -> deSer(bytes));
assertTrue(df.isStrict());
}
// Ensure invalid grouping sizes are corrected to the default invariant.
@Test
void groupingSizeTest() {
var crafted = new DFBuilder()
.set("groupingSize", (byte) -5)
.build();
var bytes = ser(crafted);
var df = assertDoesNotThrow(() -> deSer(bytes));
assertEquals(3, df.getGroupingSize());
}
// Ensure a de-serialized dFmt does not throw NPE from missing digitList
// later when formatting. i.e. re-construct the transient digitList field
@Test // See 4069754, 4067878
void digitListTest() {
var crafted = new DecimalFormat();
var bytes = ser(crafted);
var df = assertDoesNotThrow(() -> deSer(bytes));
assertDoesNotThrow(() -> df.format(1));
assertNotNull(readField(df, "digitList"));
}
// Similar to the previous test, but the original regression test
// which was a failure in DateFormat due to DecimalFormat NPE
@Test // See 4069754 and 4067878
void digitListDateFormatTest() {
var fmt = new FooFormat();
fmt.now();
var bytes = ser(fmt);
var ff = (FooFormat) assertDoesNotThrow(() -> deSer0(bytes));
assertDoesNotThrow(ff::now);
}
static class FooFormat implements Serializable {
DateFormat dateFormat = DateFormat.getDateInstance();
public String now() {
GregorianCalendar calendar = new GregorianCalendar();
Date t = calendar.getTime();
return dateFormat.format(t);
}
}
// Utilities ----
// Utility to serialize
private static byte[] ser(Object obj) {
return assertDoesNotThrow(() -> {
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(byteArrayOutputStream)) {
oos.writeObject(obj);
return byteArrayOutputStream.toByteArray();
}
}, "Unexpected error during serialization");
}
// Utility to deserialize
private static Object deSer0(byte[] bytes) throws IOException, ClassNotFoundException {
try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(byteArrayInputStream)) {
return ois.readObject();
}
}
// Convenience cast to DF
private static DecimalFormat deSer(byte[] bytes) throws IOException, ClassNotFoundException {
return (DecimalFormat) deSer0(bytes);
}
// Utility to deserialize from file in hex format
private static Object deSer(String file) throws IOException, ClassNotFoundException {
try (InputStream stream = HexDumpReader.getStreamFromHexDump(file);
ObjectInputStream ois = new ObjectInputStream(stream)) {
return ois.readObject();
}
}
// Utility to read a private field
private static Object readField(DecimalFormat df, String name) {
return assertDoesNotThrow(() -> {
var field = DecimalFormat.class.getDeclaredField(name);
field.setAccessible(true);
return field.get(df);
}, "Unexpected error during field reading");
}
// Utility class to build instances of DF via reflection
private static class DFBuilder {
private final DecimalFormat df;
private DFBuilder() {
df = new DecimalFormat();
}
private DFBuilder setVer(Object value) {
return set("serialVersionOnStream", value);
}
private DFBuilder setSuper(String field, Object value) {
return set(df.getClass().getSuperclass(), field, value);
}
private DFBuilder set(String field, Object value) {
return set(df.getClass(), field, value);
}
private DFBuilder set(Class<?> clzz, String field, Object value) {
return assertDoesNotThrow(() -> {
Field f = clzz.getDeclaredField(field);
f.setAccessible(true);
f.set(df, value);
return this;
}, "Unexpected error during reflection setting");
}
private DecimalFormat build() {
return df;
}
}
}
// Not nested, so that it can be recognized and cast correctly for the 1.1.4 test
class CheckDecimalFormat implements Serializable {
DecimalFormat _decFormat = (DecimalFormat) NumberFormat.getInstance();
public String Update() {
Random r = new Random();
return _decFormat.format(r.nextDouble());
}
}

View file

@ -0,0 +1,76 @@
/*
* Copyright (c) 2019, 2025, 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 8212749
* @summary test whether input value check for
* DecimalFormat.setGroupingSize(int) works correctly.
* @run junit/othervm SetGroupingSizeTest
*/
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import java.text.DecimalFormat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class SetGroupingSizeTest {
static Object[][] validGroupingSizes() {
return new Object[][] {
{ 0 },
{ Byte.MAX_VALUE },
};
}
static Object[][] invalidGroupingSizes() {
return new Object[][] {
{ Byte.MIN_VALUE - 1 },
{ Byte.MIN_VALUE },
{ -1 },
{ Byte.MAX_VALUE + 1 },
{ Integer.MIN_VALUE },
{ Integer.MAX_VALUE },
};
}
@ParameterizedTest
@MethodSource("validGroupingSizes")
void test_validGroupingSize(int newVal) {
DecimalFormat df = new DecimalFormat();
df.setGroupingSize(newVal);
assertEquals(newVal, df.getGroupingSize());
}
@ParameterizedTest
@MethodSource("invalidGroupingSizes")
void test_invalidGroupingSize(int newVal) {
assertThrows(IllegalArgumentException.class, () -> {
DecimalFormat df = new DecimalFormat();
df.setGroupingSize(newVal);
});
}
}

View file

@ -0,0 +1,109 @@
/*
* Copyright (c) 2024, 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 8341445
* @summary DFS setters should throw NPE. This ensures that NPE is not thrown
* by equals().
* @run junit SettersShouldThrowNPETest
*/
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.text.DecimalFormatSymbols;
import java.util.Arrays;
import java.util.Currency;
import java.util.List;
import java.util.Locale;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class SettersShouldThrowNPETest {
// The public setter methods that should throw NPE
private static final List<Method> NPE_SETTERS =
Arrays.stream(DecimalFormatSymbols.class.getDeclaredMethods())
.filter(m -> Modifier.isPublic(m.getModifiers())
&& m.getName().startsWith("set")
&& Stream.of(m.getParameterTypes()).noneMatch(Class::isPrimitive))
.toList();
// Non-primitive setters should throw NPE
@ParameterizedTest
@MethodSource("setters")
public void settersThrowNPETest(Method m) {
var dfs = new DecimalFormatSymbols();
InvocationTargetException e =
assertThrows(InvocationTargetException.class, () -> m.invoke(dfs, (Object) null));
if (!(e.getCause() instanceof NullPointerException)) {
throw new RuntimeException(e.getCause() + " was thrown instead of NPE by : " + m);
}
}
// Currency fields are lazy and can be null
// Ensure when exposed to users, they are never null
@ParameterizedTest
@MethodSource("locales")
public void lazyCurrencyFieldsTest(Locale locale) {
var dfs = new DecimalFormatSymbols(locale);
assertDoesNotThrow(() -> dfs.equals(new DecimalFormatSymbols()));
assertNotNull(dfs.getCurrency());
assertNotNull(dfs.getInternationalCurrencySymbol());
assertNotNull(dfs.getCurrencySymbol());
}
// Prior to 8341445, if the international currency symbol was invalid,
// the currency attribute was set to null. However, we should not have null
// currency fields post initializeCurrency() call. Ensure invalid code
// does not update the other fields.
@Test
public void setInternationalCurrencySymbolFallbackTest() {
var code = "fooBarBazQux";
// initialize() should provide null for all currency related fields
var dfs = new DecimalFormatSymbols(Locale.ROOT);
// Load the fallbacks via initCurrency() since the loc is Locale.ROOT
dfs.setInternationalCurrencySymbol(code); // set invalid code
// Ensure our values are the expected fallbacks, minus the updated intl code
assertEquals(Currency.getInstance("XXX"), dfs.getCurrency());
assertEquals("\u00A4", dfs.getCurrencySymbol());
assertEquals("fooBarBazQux", dfs.getInternationalCurrencySymbol());
}
private static List<Method> setters() {
return NPE_SETTERS;
}
private static List<Locale> locales() {
return List.of(Locale.ROOT, Locale.US, Locale.forLanguageTag("XXX"));
}
}

View file

@ -0,0 +1,439 @@
/*
* Copyright (c) 2012, 2014, 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 7131459 8039915
* @summary test various situations of NumberFormat rounding when close to tie
* @author Olivier Lagneau
* @run main TieRoundingTest
*
*/
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.NumberFormat;
import java.text.DecimalFormat;
import java.math.RoundingMode;
import java.util.Locale;
public class TieRoundingTest {
static int testCounter = 0;
static int errorCounter = 0;
static boolean allPassed = true;
static void formatOutputTestDouble(NumberFormat nf,
double doubleToTest,
String tiePosition,
String inputDigits,
String expectedOutput) {
int mfd = nf.getMaximumFractionDigits();
RoundingMode rm = nf.getRoundingMode();
String result = nf.format(doubleToTest);
if (!result.equals(expectedOutput)) {
System.out.println();
System.out.println("========================================");
System.out.println("***Failure : error formatting value from string : " +
inputDigits);
System.out.println("NumberFormat pattern is : " +
((DecimalFormat ) nf).toPattern());
System.out.println("Maximum number of fractional digits : " + mfd);
System.out.println("Fractional rounding digit : " + (mfd + 1));
System.out.println("Position of value relative to tie : " + tiePosition);
System.out.println("Rounding Mode : " + rm);
System.out.println("BigDecimal output : " +
new BigDecimal(doubleToTest).toString());
System.out.println("FloatingDecimal output : " + doubleToTest);
System.out.println(
"Error. Formatted result different from expected." +
"\nExpected output is : \"" + expectedOutput + "\"" +
"\nFormated output is : \"" + result + "\"");
System.out.println("========================================");
System.out.println();
errorCounter++;
allPassed = false;
} else {
testCounter++;
System.out.println("\nSuccess for double value : " + doubleToTest + " :");
System.out.println(" Input digits :" + inputDigits +
", BigDecimal value : " +
new BigDecimal(doubleToTest).toString());
System.out.print(" Rounding mode: " + rm);
System.out.print(", fract digits : " + mfd);
System.out.print(", position : " + tiePosition + " tie");
System.out.print(", result : " + result);
System.out.println(", expected : " + expectedOutput);
}
}
static void formatOutputTestLong(NumberFormat nf,
long longToTest,
String tiePosition,
String inputDigits,
String expectedOutput) {
int mfd = nf.getMaximumFractionDigits();
RoundingMode rm = nf.getRoundingMode();
String result = nf.format(longToTest);
if (!result.equals(expectedOutput)) {
System.out.println();
System.out.println("========================================");
System.out.println("***Failure : error formatting value from string : " +
inputDigits);
System.out.println("NumberFormat pattern is : " +
((DecimalFormat ) nf).toPattern());
System.out.println("Maximum number of fractional digits : " + mfd);
System.out.println("Fractional rounding digit : " + (mfd + 1));
System.out.println("Position of value relative to tie : " + tiePosition);
System.out.println("Rounding Mode : " + rm);
System.out.println(
"Error. Formatted result different from expected." +
"\nExpected output is : \"" + expectedOutput + "\"" +
"\nFormated output is : \"" + result + "\"");
System.out.println("========================================");
System.out.println();
errorCounter++;
allPassed = false;
} else {
testCounter++;
System.out.print("Success. Long input :" + inputDigits);
System.out.print(", rounding : " + rm);
System.out.print(", fract digits : " + mfd);
System.out.print(", tie position : " + tiePosition);
System.out.println(", expected : " + expectedOutput);
}
}
static void formatOutputTestObject(NumberFormat nf,
Object someNumber,
String tiePosition,
String inputDigits,
String expectedOutput) {
int mfd = nf.getMaximumFractionDigits();
RoundingMode rm = nf.getRoundingMode();
String result = nf.format(someNumber);
if (!result.equals(expectedOutput)) {
System.out.println();
System.out.println("========================================");
System.out.println("***Failure : error formatting value from string : " +
inputDigits);
System.out.println("NumberFormat pattern is : " +
((DecimalFormat ) nf).toPattern());
System.out.println("Maximum number of fractional digits : " + mfd);
System.out.println("Fractional rounding digit : " + (mfd + 1));
System.out.println("Position of value relative to tie : " + tiePosition);
System.out.println("Rounding Mode : " + rm);
System.out.println("Number self output representation: " + someNumber);
System.out.println(
"Error. Formatted result different from expected." +
"\nExpected output is : \"" + expectedOutput + "\"" +
"\nFormated output is : \"" + result + "\"");
System.out.println("========================================");
System.out.println();
errorCounter++;
allPassed = false;
} else {
testCounter++;
System.out.print("Success. Number input :" + inputDigits);
System.out.print(", rounding : " + rm);
System.out.print(", fract digits : " + mfd);
System.out.print(", tie position : " + tiePosition);
System.out.println(", expected : " + expectedOutput);
}
}
public static void main(String[] args) {
// The 3 HALF_* rounding modes are impacted by bugs 7131459, 8039915.
// So we do not test the other rounding modes.
RoundingMode[] roundingModes = {
RoundingMode.HALF_DOWN,
RoundingMode.HALF_EVEN,
RoundingMode.HALF_UP
};
// Precise the relative position of input value against its closest tie.
// The double values tested below for 3 and 5 fractional digits must follow
// this scheme (position toward tie).
String[] tieRelativePositions = {
"below", "exact", "above",
"below", "exact", "above",
"below", "exact", "above",
"below", "above", "above",
"below", "below", "above",
"below", "exact", "above"
};
// =============== Testing double (and thus float) value cases =========
System.out.println("\n===== testing 3 digits rounding position =====");
double[] values3FractDigits = {
// unimpacting values close to tie, with less than 3 input fract digits
1.115d, 1.125d, 1.135d,
// HALF_* impacting close to tie values covering all 6 tie cases
0.3115d, 0.3125d, 0.3135d,
0.6865d, 0.6875d, 0.6885d,
// specific HALF_UP close to tie values
0.3124d, 0.3126d, 0.3128d,
// specific HALF_DOWN close to tie values
0.6864d, 0.6865d, 0.6868d,
// unimpacting values close to tie, with more than 3 input fract digits
1.46885d, 2.46875d, 1.46865d
};
String[] inputs3FractDigits = {
"1.115d", "1.125d", "1.135d",
"0.3115d", "0.3125d", "0.3135d",
"0.6865d", "0.6875d", "0.6885d",
"0.3124d", "0.3126d", "0.3128d",
"0.6864d", "0.6865d", "0.6868d",
"1.46885d", "2.46875d", "1.46865d"
};
String[][] expected3FractDigits = {
{"1.115", "1.125", "1.135",
"0.311", "0.312", "0.314",
"0.686", "0.687", "0.689",
"0.312", "0.313", "0.313",
"0.686", "0.686", "0.687",
"1.469", "2.469", "1.469"
},
{"1.115", "1.125", "1.135",
"0.311", "0.312", "0.314",
"0.686", "0.688", "0.689",
"0.312", "0.313", "0.313",
"0.686", "0.686", "0.687",
"1.469", "2.469", "1.469"
},
{"1.115", "1.125", "1.135",
"0.311", "0.313", "0.314",
"0.686", "0.688", "0.689",
"0.312", "0.313", "0.313",
"0.686", "0.686", "0.687",
"1.469", "2.469", "1.469"
},
};
for (int r = 0; r < roundingModes.length; r++) {
NumberFormat dfDefault = NumberFormat.getInstance(Locale.US);
RoundingMode rmode = roundingModes[r];
dfDefault.setRoundingMode(rmode);
System.out.println("\n----- Now checking " + rmode +
" rounding mode -----");
for (int i = 0; i < values3FractDigits.length; i++) {
double d = values3FractDigits[i];
String tiePosition = tieRelativePositions[i];
String input = inputs3FractDigits[i];
String expected = expected3FractDigits[r][i];
formatOutputTestDouble(dfDefault, d, tiePosition, input, expected);
}
}
System.out.println("\n===== testing 5 digits rounding position =====");
double[] values5FractDigits = {
// unimpacting values close to tie, with less than 5 input fract digits
1.3135d, 1.3125d, 1.3115d,
// HALF_* impacting values close to tie, covering all 6 cases
1.328115d, 1.328125d, 1.328135d,
1.796865d, 1.796875d, 1.796885d,
// specific HALF_UP close to tie values
1.328124d, 1.798876d, 1.796889d,
// specific HALF_DOWN close to tie values
1.328114d, 1.796865d, 1.328138d,
// unimpacting values close to tie, with more than 5 input fract digits
1.3281149999999d, 1.75390625d, 1.7968750000001d
};
String[] inputs5FractDigits = {
"1.3135d", "1.3125d", "1.3115d",
"1.328115d", "1.328125d", "1.328135d",
"1.796865d", "1.796875d", "1.796885d",
"1.328124d", "1.798876d", "1.796889d",
"1.328114d", "1.796865d", "1.328138d",
"1.3281149999999d", "1.75390625d", "1.7968750000001d"
};
String[][] expected5FractDigits = {
{"1.3135", "1.3125", "1.3115",
"1.32811", "1.32812", "1.32814",
"1.79686", "1.79687", "1.79689",
"1.32812", "1.79888", "1.79689",
"1.32811", "1.79686", "1.32814",
"1.32811", "1.75391", "1.79688"
},
{"1.3135", "1.3125", "1.3115",
"1.32811", "1.32812", "1.32814",
"1.79686", "1.79688", "1.79689",
"1.32812", "1.79888", "1.79689",
"1.32811", "1.79686", "1.32814",
"1.32811", "1.75391", "1.79688"
},
{"1.3135", "1.3125", "1.3115",
"1.32811", "1.32813", "1.32814",
"1.79686", "1.79688", "1.79689",
"1.32812", "1.79888", "1.79689",
"1.32811", "1.79686", "1.32814",
"1.32811", "1.75391", "1.79688"
}
};
for (int r = 0; r < roundingModes.length; r++) {
DecimalFormat df5 = (DecimalFormat) NumberFormat.getInstance(Locale.US);
RoundingMode rmode = roundingModes[r];
df5.setRoundingMode(rmode);
System.out.println("\n----- Now checking " + rmode +
" rounding mode -----");
df5.applyPattern("#,###.#####");
for (int i = 0; i < values5FractDigits.length; i++) {
double d = values5FractDigits[i];
String tiePosition = tieRelativePositions[i];
String input = inputs5FractDigits[i];
String expected = expected5FractDigits[r][i];
formatOutputTestDouble(df5, d, tiePosition, input, expected);
}
}
// ==================== Testing long value cases ====================
System.out.println("\n===== testing long values =====");
long l = 123456789012345L;
DecimalFormat dfLong = (DecimalFormat) NumberFormat.getInstance(Locale.US);
String tiePosition = "exact";
String input = "123456789012345L";
String expected = "123,456,789,012,345";
String result = dfLong.format(l);
formatOutputTestLong(dfLong, l, tiePosition, input, expected);
dfLong.applyPattern("0.###E0");
expected = "1.235E14";
formatOutputTestLong(dfLong, l, tiePosition, input, expected);
l = 123450000000000L;
input = "123450000000000L";
expected = "1.234E14";
formatOutputTestLong(dfLong, l, tiePosition, input, expected);
l = 987750000000000L;
input = "987750000000000L";
expected = "9.878E14";
formatOutputTestLong(dfLong, l, tiePosition, input, expected);
dfLong.applyPattern("#,###.0E0");
l = 987755000000000L;
input = "987755000000000L";
expected = "987.76E12";
formatOutputTestLong(dfLong, l, tiePosition, input, expected);
// ================= Testing BigInteger value cases =================
System.out.println("\n===== testing BigInteger values =====");
String stringValue = "12345678901234567890123456789012345";
BigInteger bi = new BigInteger(stringValue);
DecimalFormat dfBig = (DecimalFormat) NumberFormat.getInstance(Locale.US);
tiePosition = "exact";
input = stringValue;
expected = "12,345,678,901,234,567,890,123,456,789,012,345";
formatOutputTestObject(dfBig, bi, tiePosition, input, expected);
dfBig.applyPattern("0.###E0");
expected = "1.235E34";
formatOutputTestObject(dfBig, bi, tiePosition, input, expected);
stringValue = "12345000000000000000000000000000000";
input = stringValue;
bi = new BigInteger(stringValue);
expected = "1.234E34";
formatOutputTestObject(dfBig, bi, tiePosition, input, expected);
stringValue = "12345000000000000000000000000000001";
input = stringValue;
bi = new BigInteger(stringValue);
expected = "1.235E34";
formatOutputTestObject(dfBig, bi, tiePosition, input, expected);
stringValue = "98755000000000000000000000000000000";
input = stringValue;
bi = new BigInteger(stringValue);
expected = "9.876E34";
formatOutputTestObject(dfBig, bi, tiePosition, input, expected);
dfLong.applyPattern("#,###.0E0");
stringValue = "98775500000000000000000000000000000";
input = stringValue;
expected = "987.76E34";
// =============== Testing BigDecimal value cases ================
System.out.println("\n===== testing BigDecimal values =====");
dfBig = (DecimalFormat) NumberFormat.getInstance(Locale.US);
stringValue = "0.68850000000000000088817841970012523233890533447265625";
BigDecimal bd = new BigDecimal(stringValue);
tiePosition = "exact";
input = stringValue;
expected = "0.689";
formatOutputTestObject(dfBig, bd, tiePosition, input, expected);
stringValue = "0.31149999999999999911182158029987476766109466552734375";
bd = new BigDecimal(stringValue);
dfBig.applyPattern("#,##0.####");
tiePosition = "exact";
input = stringValue;
expected = "0.3115";
formatOutputTestObject(dfBig, bd, tiePosition, input, expected);
// ==================== Printing results and exiting ===================
System.out.println();
System.out.println("==> " + testCounter + " tests passed successfully");
System.out.println("==> " + errorCounter + " tests failed");
System.out.println();
if (allPassed) {
System.out.println(
"Success in formating all the values with the given parameters");
} else {
String s = "Test failed with " + errorCounter + " formating error(s).";
System.out.println(s);
throw new RuntimeException(s);
}
}
}

View file

@ -0,0 +1,76 @@
/*
* Copyright (c) 2022, 2024, 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 8282929 8326908
* @summary Verify DecimalFormat::toLocalizedPattern correctness.
* @run junit ToLocalizedPatternTest
*/
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Locale;
public class ToLocalizedPatternTest {
private static final char MONETARY_GROUPING = 'g';
private static final char MONETARY_DECIMAL = 'd';
// Verifies that the toLocalizedPattern() method correctly returns
// monetary symbols for a currency formatter.
@Test
public void monetarySymbolsTest() {
var dfs = new DecimalFormatSymbols(Locale.US);
// Customize the decimal format symbols
dfs.setMonetaryGroupingSeparator(MONETARY_GROUPING);
dfs.setMonetaryDecimalSeparator(MONETARY_DECIMAL);
// create a currency formatter
var cf = (DecimalFormat)DecimalFormat.getCurrencyInstance(Locale.US);
cf.setDecimalFormatSymbols(dfs);
// check
assertEquals(cf.toLocalizedPattern(),
cf.toPattern()
.replace(',', MONETARY_GROUPING)
.replace('.', MONETARY_DECIMAL));
}
// Verify some common symbols are enforced with the DFS
@Test
public void useDFSWhenLocalizedTest() {
DecimalFormatSymbols dfs = new DecimalFormatSymbols();
dfs.setGroupingSeparator('a');
dfs.setDecimalSeparator('b');
dfs.setDigit('c');
dfs.setZeroDigit('d');
// Create a DecimalFormat that utilizes the above symbols
DecimalFormat dFmt = new DecimalFormat("###,##0.###", dfs);
assertEquals("caccdbccc", dFmt.toLocalizedPattern());
}
}

View file

@ -0,0 +1,130 @@
/*
* Copyright (c) 2024, 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 8326908
* @summary Verify DecimalFormat::toPattern correctness.
* @run junit ToPatternTest
*/
import org.junit.jupiter.api.Test;
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.assertTrue;
import java.text.DecimalFormat;
import java.util.stream.Stream;
public class ToPatternTest {
// DecimalFormat constant
private static final int DOUBLE_FRACTION_DIGITS = 340;
// Ensure that toPattern() provides the correct amount of minimum
// and maximum digits for integer/fraction.
@ParameterizedTest
@MethodSource("minMaxDigits")
public void basicTest(int maxInt, int minInt, int maxFrac, int minFrac) {
DecimalFormat dFmt = new DecimalFormat();
dFmt.setMaximumIntegerDigits(maxInt);
dFmt.setMinimumIntegerDigits(minInt);
dFmt.setMaximumFractionDigits(maxFrac);
dFmt.setMinimumFractionDigits(minFrac);
// Non-localized separator always uses '.'
String[] patterns = dFmt.toPattern().split("\\.");
assertEquals(2, patterns.length,
dFmt.toPattern() + " should be split into an integer/fraction portion");
String integerPattern = patterns[0];
String fractionPattern = patterns[1];
// Count # and 0 explicitly (since there are grouping symbols)
assertEquals(integerPattern.chars().filter(ch -> ch == '0').count() +
integerPattern.chars().filter(ch -> ch == '#').count(),
Math.max(dFmt.getGroupingSize(), dFmt.getMinimumIntegerDigits()) + 1);
assertEquals(integerPattern.chars().filter(ch -> ch == '0').count(), dFmt.getMinimumIntegerDigits());
assertEquals(fractionPattern.length(), dFmt.getMaximumFractionDigits());
assertEquals(fractionPattern.chars().filter(ch -> ch == '0').count(), dFmt.getMinimumFractionDigits());
}
// General and edge cases for the min and max Integer/Fraction digits
private static Stream<Arguments> minMaxDigits() {
return Stream.of(
Arguments.of(10, 5, 10, 5),
Arguments.of(0, 0, 1, 1),
Arguments.of(1, 1, 1, 1),
Arguments.of(5, 5, 5, 5),
Arguments.of(5, 10, 5, 10),
Arguments.of(333, 27, 409, 3)
);
}
// Ensure that a NegativePattern is explicitly produced when required.
@Test
public void negativeSubPatternTest() {
DecimalFormat dFmt = new DecimalFormat();
dFmt.setPositivePrefix("foo");
dFmt.setPositiveSuffix("bar");
dFmt.setNegativePrefix("baz");
dFmt.setNegativeSuffix("qux");
String[] patterns = dFmt.toPattern().split(";");
assertEquals(2, patterns.length,
"There should be a positivePattern and negativePattern");
String positivePattern = patterns[0];
String negativePattern = patterns[1];
assertTrue(positivePattern.startsWith(dFmt.getPositivePrefix()));
assertTrue(positivePattern.endsWith(dFmt.getPositiveSuffix()));
assertTrue(negativePattern.startsWith(dFmt.getNegativePrefix()));
assertTrue(negativePattern.endsWith(dFmt.getNegativeSuffix()));
}
// 8326908: Verify that an empty pattern DecimalFormat does not throw an
// OutOfMemoryError when toPattern() is invoked. Behavioral change of
// MAXIMUM_INTEGER_DIGITS replaced with DOUBLE_FRACTION_DIGITS for empty
// pattern initialization.
@Test
public void emptyStringPatternTest() {
DecimalFormat empty = new DecimalFormat("");
// Verify new maximum fraction digits value
assertEquals(DOUBLE_FRACTION_DIGITS, empty.getMaximumFractionDigits());
// Verify no OOME for empty pattern
assertDoesNotThrow(empty::toPattern);
// Check toString for coverage, as it invokes toPattern
assertDoesNotThrow(empty::toString);
}
// Verify that only the last grouping interval is used for the grouping size.
@Test
public void groupingSizeTest() {
assertEquals(22,
new DecimalFormat( "###,####,"+"#".repeat(22)).getGroupingSize());
}
}

View file

@ -0,0 +1,56 @@
/*
* Copyright (c) 2024, 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 8321545
* @summary Ensure value returned by overridden toString method is as expected
* @run junit ToStringTest
*/
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.util.Locale;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class ToStringTest {
// Check a normal expected value. There is no null locale test as
// DecimalFormatSymbols will throw an exception when created with a null locale.
@Test
public void expectedValueTest() {
String expectedStr =
"DecimalFormat [locale: \"English (Canada)\", pattern: \"foo#00.00bar\"]\n";
var d = new DecimalFormat("foo#00.00bar", new DecimalFormatSymbols(Locale.CANADA));
assertEquals(expectedStr, d.toString());
String expectedStr2 =
"DecimalFormat [locale: \"English (Canada)\", pattern: \"#,##0.###\"]\n";
var d2 = NumberFormat.getInstance(Locale.CANADA);
assertEquals(expectedStr2, d2.toString());
}
}