/* * Copyright (c) 2003, 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 4018937 8008577 * @summary Confirm that methods which are newly added to support BigDecimal and BigInteger work as expected. * @library /java/text/testlib * @run main/othervm -Djava.locale.providers=COMPAT,SPI BigDecimalParse */ import java.math.BigDecimal; import java.text.*; import java.util.*; public class BigDecimalParse extends IntlTest { public static void main(String[] args) throws Exception { Locale loc = Locale.getDefault(); try { Locale.setDefault(Locale.US); new BigDecimalParse().run(args); } finally { // restore the reserved locale Locale.setDefault(loc); } } static final String nonsep_int = "123456789012345678901234567890123456789012345678901234567890" + "123456789012345678901234567890123456789012345678901234567890" + "123456789012345678901234567890123456789012345678901234567890" + "123456789012345678901234567890123456789012345678901234567890" + "123456789012345678901234567890123456789012345678901234567890" + "123456789012345678901234567890123456789012345678901234567890"; static final String sep_int = "123,456,789,012,345,678,901,234,567,890," + "123,456,789,012,345,678,901,234,567,890," + "123,456,789,012,345,678,901,234,567,890," + "123,456,789,012,345,678,901,234,567,890," + "123,456,789,012,345,678,901,234,567,890," + "123,456,789,012,345,678,901,234,567,890," + "123,456,789,012,345,678,901,234,567,890," + "123,456,789,012,345,678,901,234,567,890," + "123,456,789,012,345,678,901,234,567,890," + "123,456,789,012,345,678,901,234,567,890," + "123,456,789,012,345,678,901,234,567,890," + "123,456,789,012,345,678,901,234,567,890"; static final String nonsep_zero = "000000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000000000"; static final String sep_zero = "000,000,000,000,000,000,000,000,000,000," + "000,000,000,000,000,000,000,000,000,000," + "000,000,000,000,000,000,000,000,000,000," + "000,000,000,000,000,000,000,000,000,000," + "000,000,000,000,000,000,000,000,000,000," + "000,000,000,000,000,000,000,000,000,000," + "000,000,000,000,000,000,000,000,000,000," + "000,000,000,000,000,000,000,000,000,000," + "000,000,000,000,000,000,000,000,000,000," + "000,000,000,000,000,000,000,000,000,000," + "000,000,000,000,000,000,000,000,000,000," + "000,000,000,000,000,000,000,000,000,000"; static final String fra = "012345678901234567890123456789012345678901234567890123456789" + "012345678901234567890123456789012345678901234567890123456789" + "012345678901234567890123456789012345678901234567890123456789" + "012345678901234567890123456789012345678901234567890123456789" + "012345678901234567890123456789012345678901234567890123456789" + "012345678901234567890123456789012345678901234567890123456789"; Number parsed = null; ParsePosition pp; boolean exceptionOccurred; String msg; DecimalFormat df; /** * Test for normal big numbers which have the fraction part */ void test_Parse_in_DecimalFormat_BigDecimal() { df = new DecimalFormat(); df.setParseBigDecimal(true); // From: 1234...7890.012...789 // To: BigDecimal 1234...7890.012...789 check(nonsep_int + "." + fra, new BigDecimal(nonsep_int + "." + fra)); // From: -1,234...7,890.012...789 // To: BigDecimal -1234...7890.012...789 check("-" + sep_int + "." + fra, new BigDecimal("-" + nonsep_int + "." + fra)); // From: 000...0000.0...0 // To: BigDecimal 0E-360 check(nonsep_zero + "." + nonsep_zero, new BigDecimal(nonsep_zero + "." + nonsep_zero)); // From: 0.000...0000123...789E370 // To: BigDecimal 0.0123...789 check("0.0000000000" + nonsep_zero + fra + "E370", new BigDecimal("0.0000000000" + nonsep_zero + fra + "E370")); // From: 0.1123...890E-360 // To: BigDecimal 1.123...890E-361 check("0.1" + nonsep_int + "E-360", new BigDecimal("0.1" + nonsep_int + "E-360")); // From: 000...0000.0...0123...7890 // To: BigDecimal 1.234...890E-361 check(nonsep_zero + "." + nonsep_zero + nonsep_int, new BigDecimal(nonsep_zero + "." + nonsep_zero + nonsep_int)); // From: 0.123...890E360 // To: BigDecimal 123...890 check("0." + nonsep_int + "E360", new BigDecimal("0." + nonsep_int + "E360")); } /** * Test for normal big numbers which have the fraction part with multiplier */ void test_Parse_in_DecimalFormat_BigDecimal_usingMultiplier() { df = new DecimalFormat(); df.setParseBigDecimal(true); // From: 250,0...0,000.000...000 // To: 1000...0000.000...000 df.setMultiplier(250000000); check("250,000,000," + sep_zero + "." + nonsep_zero, new BigDecimal("1" + nonsep_zero + "." + nonsep_zero)); // From: -250,0...0,000.000...000 // To: -1000...0000.000...000 check("-250,000,000," + sep_zero + "." + nonsep_zero, new BigDecimal("-1" + nonsep_zero + "." + nonsep_zero)); // From: 250,0...0,000.000...000 // To: -1000...0000.000...000 df.setMultiplier(-250000000); check("250,000,000," + sep_zero + "." + nonsep_zero, new BigDecimal("-1" + nonsep_zero + "." + nonsep_zero)); // From: -250,0...0,000.000...000 // To: 1000...0000.000...000 check("-250,000,000," + sep_zero + "." + nonsep_zero, new BigDecimal("1" + nonsep_zero + "." + nonsep_zero)); // Confirm that ArithmeticException is handled properly // From: 1000.000 // To: 333.333 df.setMultiplier(3); check("1000.000", new BigDecimal("333.333")); // Confirm that ArithmeticException is handled properly // From: 10000.0000 // To: 303.0303 df.setMultiplier(33); check("10000.0000", new BigDecimal("303.0303")); } /** * Test for division by zero (BigDecimal) */ void test_Parse_in_DecimalFormat_BigDecimal_DivisionByZero() { df = new DecimalFormat(); df.setParseBigDecimal(true); df.setMultiplier(0); // From: 1000.000 // To: Double.POSITIVE_INFINITY check("1000.000", new Double(Double.POSITIVE_INFINITY)); // From: -1000 // To: Double.NEGATIVE_INFINITY check("-1000", new Double(Double.NEGATIVE_INFINITY)); // From: -0.00 // To: Double.NaN check("-0.00", new Double(Double.NaN)); } /** * Test for division by zero (Double) */ void test_Parse_in_DecimalFormat_Double_DivisionByZero() { df = new DecimalFormat(); df.setParseBigDecimal(false); df.setMultiplier(0); // From: 1000.000 // To: Double.POSITIVE_INFINITY check("1000.000", new Double(Double.POSITIVE_INFINITY)); // From: -1000.000 // To: Double.NEGATIVE_INFINITY check("-1000.000", new Double(Double.NEGATIVE_INFINITY)); // From: 0.0 // To: Double.NaN check("0.0", new Double(Double.NaN)); // From: -0.0 (Double) // To: Double.NaN check("-0.0", new Double(Double.NaN)); // From: Double.NaN // To: Double.NaN check("\ufffd", new Double(Double.NaN)); // From: Double.POSITIVE_INFINITY // To: Double.NaN check("\u221e", new Double(Double.POSITIVE_INFINITY)); // From: Double.NEGATIVE_INFINITY // To: Double.NaN check("-\u221e", new Double(Double.NEGATIVE_INFINITY)); } /** * Test for division by zero (Long) */ void test_Parse_in_DecimalFormat_Long_DivisionByZero() { df = new DecimalFormat(); df.setParseBigDecimal(false); df.setMultiplier(0); // From: 1000 // To: Double.POSITIVE_INFINITY check("1000", new Double(Double.POSITIVE_INFINITY)); // From: -1000 // To: Double.NEGATIVE_INFINITY check("-1000", new Double(Double.NEGATIVE_INFINITY)); // From: -000 (Long) // To: Double.NaN check("-000", new Double(Double.NaN)); } /** * Test for normal big numbers which don't have the fraction part */ void test_Parse_in_DecimalFormat_BigInteger() { df = new DecimalFormat(); df.setParseBigDecimal(true); // From: 123...890 // To: BigDecimal 123...890 check(nonsep_int + nonsep_int, new BigDecimal(nonsep_int + nonsep_int)); // From: 123,4...7,890 // To: BigDecimal 1234...7890 check(sep_int + "," + sep_int, new BigDecimal(nonsep_int + nonsep_int)); // From: -000...000123...890 // To: BigDecimal -123...890 check("-" + nonsep_zero + nonsep_int, new BigDecimal("-" + nonsep_int)); // From: -000,0...0,000,123,4...7,890 // To: BigDecimal -123...890 check("-" + sep_zero + "," + sep_int, new BigDecimal("-" + nonsep_int)); } /** * Test for normal big numbers which don't have the fraction part with * multiplier */ void test_Parse_in_DecimalFormat_BigInteger_usingMultiplier() { df = new DecimalFormat(); df.setParseBigDecimal(true); // From: 250,0...0,000 // To: 1000...0000 df.setMultiplier(250000000); check("250,000,000," + sep_zero, new BigDecimal("1" + nonsep_zero)); // From: -250,0...0,000 // To: -1000...0000 check("-250,000,000," + sep_zero, new BigDecimal("-1" + nonsep_zero)); // From: 250,0...0,000 // To: -1000...0000 df.setMultiplier(-250000000); check("250,000,000," + sep_zero, new BigDecimal("-1" + nonsep_zero)); // From: -250,0...0,000 // To: 1000...0000 check("-250,000,000," + sep_zero, new BigDecimal("1" + nonsep_zero)); // From: 250,0...0,000E-360 // To: -1000...0000.000...000 check("250,000,000," + sep_zero + "," + sep_zero + "E-360", new BigDecimal("-1" + nonsep_zero + "." + nonsep_zero)); // Confirm that a division which results in a irrational number is done // properly // From: 1000 // To: 333 df.setMultiplier(3); check("1000", new BigDecimal("333")); } /** * Test for special numbers * Double.NaN * Double.POSITIVE_INFINITY * Double.NEGATIVE_INFINITY */ void test_Parse_in_DecimalFormat_SpecialNumber() { df = new DecimalFormat(); df.setParseBigDecimal(true); String[] numbers = { "0", "0.0", "25", "25.0", "25.5", "\u221e", "\ufffd", "-0", "-0.0", "-25", "-25.0", "-25.5", "-\u221e", }; int multipliers[] = {5, -5}; Number[][] expected = { { new BigDecimal("0"), new BigDecimal("0.0"), new BigDecimal("5"), new BigDecimal("5.0"), new BigDecimal("5.1"), new Double(Double.POSITIVE_INFINITY), new Double(Double.NaN), new BigDecimal("0"), new BigDecimal("0.0"), new BigDecimal("-5"), new BigDecimal("-5.0"), new BigDecimal("-5.1"), new Double(Double.NEGATIVE_INFINITY), new Double(Double.NaN), }, { new BigDecimal("0"), new BigDecimal("0.0"), new BigDecimal("-5"), new BigDecimal("-5.0"), new BigDecimal("-5.1"), new Double(Double.NEGATIVE_INFINITY), new Double(Double.NaN), new BigDecimal("0"), new BigDecimal("0.0"), new BigDecimal("5"), new BigDecimal("5.0"), new BigDecimal("5.1"), new Double(Double.POSITIVE_INFINITY), }, }; for (int i = 0; i < multipliers.length; i++) { df.setMultiplier(multipliers[i]); for (int j = 0; j < numbers.length; j++) { check(String.valueOf(numbers[j]), expected[i][j]); } } } /** * Test for special numbers */ void test_Parse_in_DecimalFormat_Other() { df = new DecimalFormat(); df.setParseBigDecimal(true); String[] numbers = { "-9223372036854775808", // Long.MIN_VALUE }; int multipliers[] = {1, -1}; String[][] expected = { {"-9223372036854775808"}, // Long.MIN_VALUE {"9223372036854775808"}, // Long.MAX_VALUE+1 = abs(MIN_VALUE) }; for (int i = 0; i < multipliers.length; i++) { df.setMultiplier(multipliers[i]); for (int j = 0; j < numbers.length; j++) { check(String.valueOf(numbers[j]), new BigDecimal(expected[i][j])); } } } static final String[] patterns = { " {0, number} ", " {0, number} ", " {0, number, currency} ", " {0, number, currency} ", " {0, number, percent} ", " {0, number, percent} ", " {0, number,#,##0.###E0} ", " {0, number,#,##0.###E0} ", " {0, number} ", " {0, number} ", " {0, number, integer} ", " {0, number, integer} ", " {0, number, currency} ", " {0, number, currency} ", " {0, number, percent} ", " {0, number, percent} ", " {0, number,#,##0.###E0} ", " {0, number,#,##0.###E0} ", }; static final String[] from = { " 12,345,678,901,234,567,890.98765432109876543210987654321 ", " -12,345,678,901,234,567,890.98765432109876543210987654321 ", " $12,345,678,901,234,567,890.98765432109876543210987654321 ", " ($12,345,678,901,234,567,890.98765432109876543210987654321) ", " 1,234,567,890,123,456,789,098.76543210987654321098765432100% ", " -1,234,567,890,123,456,789,098.76543210987654321098765432100% ", " 12,345,678,901,234,567,890.98765432109876543210987654321E-20 ", " -12,345,678,901,234,567,890.98765432109876543210987654321E-20 ", " 9,876,543,210,987,654,321,098,765,432,109,876,543,210 ", " -9,876,543,210,987,654,321,098,765,432,109,876,543,210 ", " 9,876,543,210,987,654,321,098,765,432,109,876,543,210E5 ", " -9,876,543,210,987,654,321,098,765,432,109,876,543,210E-5 ", " $9,876,543,210,987,654,321,098,765,432,109,876,543,210.00 ", " ($9,876,543,210,987,654,321,098,765,432,109,876,543,210.00) ", " 987,654,321,098,765,432,109,876,543,210,987,654,321,012% ", " -987,654,321,098,765,432,109,876,543,210,987,654,321,012% ", " 98,765,432,109,876,543,210.98765432109876543210E20 ", " -987,654,321,098,765,432,109,876,543,210,987,654,321,000,000,000,000,000,000,000E-20 ", }; static final String[] expected1 = { // isParseIntegerOnly() == false "12345678901234567890.98765432109876543210987654321", "-12345678901234567890.98765432109876543210987654321", "12345678901234567890.98765432109876543210987654321", "-12345678901234567890.98765432109876543210987654321", "12345678901234567890.98765432109876543210987654321", "-12345678901234567890.98765432109876543210987654321", "0.1234567890123456789098765432109876543210987654321", "-0.1234567890123456789098765432109876543210987654321", "9876543210987654321098765432109876543210", "-9876543210987654321098765432109876543210", "9.876543210987654321098765432109876543210E44", "-98765432109876543210987654321098765.43210", "9876543210987654321098765432109876543210.00", "-9876543210987654321098765432109876543210.00", "9876543210987654321098765432109876543210.12", "-9876543210987654321098765432109876543210.12", "9876543210987654321098765432109876543210", "-9876543210987654321098765432109876543210.00000000000000000000", }; static final int[] parsePosition1 = { 60, 61, 61, 63, 64, 65, 64, 65, 57, 58, 59, 61, 61, 63, 60, 61, 54, 88, }; /** * Test for MessageFormat: setParseIntegerOnly(false) */ void test_Parse_in_MessageFormat_NotParseIntegerOnly() { for (int i=0; i < patterns.length; i++) { pp = new ParsePosition(0); Object[] parsed = null; try { MessageFormat mf = new MessageFormat(patterns[i]); Format[] formats = mf.getFormats(); for (int j=0; j < formats.length; j++) { ((DecimalFormat)formats[j]).setParseBigDecimal(true); } parsed = mf.parse(from[i], pp); if (pp.getErrorIndex() != -1) { errln("Case" + (i+1) + ": getErrorIndex() returns wrong value. expected:-1, got:"+ pp.getErrorIndex() + " for " + from[i]); } if (pp.getIndex() != parsePosition1[i]) { errln("Case" + (i+1) + ": getIndex() returns wrong value. expected:" + parsePosition1[i] + ", got:"+ pp.getIndex() + " for " + from[i]); } } catch(Exception e) { errln("Unexpected exception: " + e.getMessage()); } checkType(from[i], getType(new BigDecimal(expected1[i])), getType((Number)parsed[0])); checkParse(from[i], new BigDecimal(expected1[i]), (Number)parsed[0]); } } static final String[] expected2 = { // isParseIntegerOnly() == true "12345678901234567890", "-12345678901234567890", "12345678901234567890", "-12345678901234567890", "12345678901234567890", "-12345678901234567890", "0", "0", "9876543210987654321098765432109876543210", "-9876543210987654321098765432109876543210", "9.876543210987654321098765432109876543210E44", "-98765432109876543210987654321098765.43210", "9876543210987654321098765432109876543210", "-9876543210987654321098765432109876543210", "9876543210987654321098765432109876543210.12", "-9876543210987654321098765432109876543210.12", "9876543210987654321098765432109876543210", "-9876543210987654321098765432109876543210.00000000000000000000", }; static final int[][] parsePosition2 = { // {errorIndex, index} /* * Should keep in mind that the expected result is different from * DecimalFormat.parse() for some cases. */ {28, 0}, // parsing stopped at '.' {29, 0}, // parsing stopped at '.' {29, 0}, // parsing stopped at '.' {2, 0}, // parsing stopped at '(' because cannot find ')' {2, 0}, // parsing stopped at the first numeric // because cannot find '%' {2, 0}, // parsing stopped at the first numeric // because cannot find '%' {28, 0}, // parsing stopped at '.' {29, 0}, // parsing stopped at '.' {-1, 57}, {-1, 58}, {-1, 59}, {-1, 61}, {56, 0}, // parsing stopped at '.' // because cannot find '%' {2, 0}, // parsing stopped at '(' because cannot find ')' {-1, 60}, {-1, 61}, {28, 0}, // parsing stopped at '.' {-1, 88}, }; /** * Test for MessageFormat: setParseIntegerOnly(true) */ void test_Parse_in_MessageFormat_ParseIntegerOnly() { for (int i=0; i < patterns.length; i++) { pp = new ParsePosition(0); Object[] parsed = null; try { MessageFormat mf = new MessageFormat(patterns[i]); Format[] formats = mf.getFormats(); for (int j=0; j < formats.length; j++) { ((DecimalFormat)formats[j]).setParseBigDecimal(true); ((DecimalFormat)formats[j]).setParseIntegerOnly(true); } parsed = mf.parse(from[i], pp); if (pp.getErrorIndex() != parsePosition2[i][0]) { errln("Case" + (i+1) + ": getErrorIndex() returns wrong value. expected:" + parsePosition2[i][0] + ", got:"+ pp.getErrorIndex() + " for " + from[i]); } if (pp.getIndex() != parsePosition2[i][1]) { errln("Case" + (i+1) + ": getIndex() returns wrong value. expected:" + parsePosition2[i][1] + ", got:"+ pp.getIndex() + " for " + from[i]); } } catch(Exception e) { errln("Unexpected exception: " + e.getMessage()); } if (parsePosition2[i][0] == -1) { checkType(from[i], getType(new BigDecimal(expected2[i])), getType((Number)parsed[0])); checkParse(from[i], new BigDecimal(expected2[i]), (Number)parsed[0]); } } } static final String[] from3 = { "12,345,678,901,234,567,890.98765432109876543210987654321", "-12,345,678,901,234,567,890.98765432109876543210987654321", "9,876,543,210,987,654,321,098,765,432,109,876,543,210", "-9,876,543,210,987,654,321,098,765,432,109,876,543,210", "1234556790000E-8", }; static final String[] expected3 = { "12345678901234567890", "-12345678901234567890", "9876543210987654321098765432109876543210", "-9876543210987654321098765432109876543210", "12345.56790000", }; static final int[][] parsePosition3 = { // {errorIndex, index} {-1, 26}, {-1, 27}, {-1, 53}, {-1, 54}, {-1, 16}, }; /** * Test for DecimalFormat: setParseIntegerOnly(true) */ void test_Parse_in_DecimalFormat_ParseIntegerOnly() { DecimalFormat df = (DecimalFormat)NumberFormat.getIntegerInstance(); df.setParseBigDecimal(true); for (int i=0; i < from3.length; i++) { pp = new ParsePosition(0); Number parsed = null; try { parsed = df.parse(from3[i], pp); if (pp.getErrorIndex() != parsePosition3[i][0]) { errln("Case" + (i+1) + ": getErrorIndex() returns wrong value. expected:" + parsePosition3[i][0] + ", got:"+ pp.getErrorIndex() + " for " + from3[i]); } if (pp.getIndex() != parsePosition3[i][1]) { errln("Case" + (i+1) + ": getIndex() returns wrong value. expected:" + parsePosition3[i][1] + ", got:"+ pp.getIndex() + " for " + from3[i]); } } catch(Exception e) { errln("Unexpected exception: " + e.getMessage()); } if (parsePosition3[i][0] == -1) { checkType(from3[i], getType(new BigDecimal(expected3[i])), getType(parsed)); checkParse(from3[i], new BigDecimal(expected3[i]), parsed); } } } protected void check(String from, Number to) { pp = new ParsePosition(0); try { parsed = df.parse(from, pp); } catch(Exception e) { exceptionOccurred = true; errln(e.getMessage()); } if (!exceptionOccurred) { checkParse(from, to, parsed); checkType(from, getType(to), getType(parsed)); checkParsePosition(from, from.length(), pp.getIndex()); } } private void checkParse(String orig, Number expected, Number got) { if (!expected.equals(got)) { errln("Parsing... failed." + "\n original: " + orig + "\n parsed: " + got + "\n expected: " + expected + "\n"); } } private void checkType(String orig, String expected, String got) { if (!expected.equals(got)) { errln("Parsing... unexpected Class returned." + "\n original: " + orig + "\n got: " + got + "\n expected: " + expected + "\n"); } } private void checkParsePosition(String orig, int expected, int got) { if (expected != got) { errln("Parsing... wrong ParsePosition returned." + "\n original: " + orig + "\n got: " + got + "\n expected: " + expected + "\n"); } } private String getType(Number number) { return number.getClass().getName(); } }