1 /*
  2  * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 
 24 /*
 25  * @test
 26  * @bug 4838107 8008577
 27  * @summary Confirm that DecimalFormat can format a number with negative exponent number correctly.
 28  * @library /java/text/testlib
 29  * @run main/othervm -Djava.locale.providers=COMPAT,SPI Bug4838107
 30  */
 31 
 32 import java.math.*;
 33 import java.util.*;
 34 import java.text.*;
 35 
 36 public class Bug4838107 extends IntlTest {
 37 
 38     static DecimalFormat df;
 39     static DecimalFormatSymbols dfs;
 40     static boolean err = false;
 41 
 42     static public void main(String[] args) {
 43         Locale defaultLoc = Locale.getDefault();
 44         Locale.setDefault(Locale.US);
 45 
 46         /**
 47          * This bug is about exponential formatting. But I added test cases for:
 48          *   - Double and BigDecimal numbers which don't have exponent parts.
 49          *   - Long and BigInteger numbers which don't support exponential
 50          *     notation.
 51          * because there are few test cases for suffix and prefix.
 52          * And also, I added test cases to guarantee further formatting and
 53          * parsing using the same DecimalFormat instance will not change the
 54          * Number's value anymore.
 55          */
 56 
 57         test_double();
 58         test_long();
 59         test_BigDecimal();
 60         test_BigInteger();
 61 
 62         Locale.setDefault(defaultLoc);
 63 
 64         if (err) {
 65             throw new RuntimeException("Wrong format with DecimalFormat");
 66         }
 67     }
 68 
 69     static void test_double() {
 70         df = new DecimalFormat();
 71         dfs = df.getDecimalFormatSymbols();
 72 
 73         /* Test with default pattern */
 74         test(1234D,    "1,234");
 75         test(0.1234,  "0.123");     // rounded
 76         test(-1234D,   "-1,234");
 77         test(-0.1234, "-0.123");    // rounded
 78 
 79         test(Double.POSITIVE_INFINITY, "\u221e");
 80         test(Double.NEGATIVE_INFINITY, "-\u221e");
 81         test(Double.NaN, "\ufffd"); // without prefix and suffix
 82         test(0.0,  "0");
 83         test(-0.0, "-0");   // with the minus sign
 84 
 85         /* Specify a pattern and the minus sign. */
 86         prepareFormatter("<P>#.###E00<S>", 'm');
 87         test(1234D,    "<P>1.234E03<S>");
 88         test(0.1234,  "<P>1.234Em01<S>");
 89         test(-1234D,   "m<P>1.234E03<S>");
 90         test(-0.1234, "m<P>1.234Em01<S>");
 91 
 92         prepareFormatter("<P>#.###E00<S>;#.###E00", 'm');
 93         test(1234D,    "<P>1.234E03<S>");
 94         test(0.1234,  "<P>1.234Em01<S>");
 95         test(-1234D,   "1.234E03");
 96         test(-0.1234, "1.234Em01");
 97 
 98         prepareFormatter("#.###E00;<P>#.###E00<S>", 'm');
 99         test(1234D,    "1.234E03");
100         test(0.1234,  "1.234Em01");
101         test(-1234D,   "<P>1.234E03<S>");
102         test(-0.1234, "<P>1.234Em01<S>");
103 
104         prepareFormatter("<P>#.###E00<S>;<p>-#.###E00<s>", 'm');
105         test(1234D,    "<P>1.234E03<S>");
106         test(0.1234,  "<P>1.234Em01<S>");
107         test(-1234D,   "<p>m1.234E03<s>");
108         test(-0.1234, "<p>m1.234Em01<s>");
109 
110         test(Double.POSITIVE_INFINITY, "<P>\u221e<S>");
111         test(Double.NEGATIVE_INFINITY, "<p>m\u221e<s>");
112         test(Double.NaN, "\ufffd"); // without prefix and suffix
113         test(0.0,  "<P>0E00<S>");
114         test(-0.0, "<p>m0E00<s>");  // with the minus sign
115     }
116 
117     static void test_BigDecimal() {
118         df = new DecimalFormat();
119         dfs = df.getDecimalFormatSymbols();
120 
121         /* Test with default pattern */
122         test(new BigDecimal("123456789012345678901234567890"),
123              "123,456,789,012,345,678,901,234,567,890");
124         test(new BigDecimal("0.000000000123456789012345678901234567890"),
125              "0");
126         test(new BigDecimal("-123456789012345678901234567890"),
127              "-123,456,789,012,345,678,901,234,567,890");
128         test(new BigDecimal("-0.000000000123456789012345678901234567890"),
129               "-0");
130 
131         test(new BigDecimal("0"), "0");
132         test(new BigDecimal("-0"), "0");
133 
134         /* Specify a pattern and the minus sign. */
135         prepareFormatter("<P>#.####################E00<S>;<p>-#.####################E00<s>", 'm');
136         test(new BigDecimal("123456789012345678901234567890"),
137              "<P>1.23456789012345678901E29<S>");
138         test(new BigDecimal("0.000000000123456789012345678901234567890"),
139              "<P>1.23456789012345678901Em10<S>");
140         test(new BigDecimal("-123456789012345678901234567890"),
141              "<p>m1.23456789012345678901E29<s>");
142         test(new BigDecimal("-0.000000000123456789012345678901234567890"),
143               "<p>m1.23456789012345678901Em10<s>");
144 
145         test(new BigDecimal("0"), "<P>0E00<S>");
146         test(new BigDecimal("-0"), "<P>0E00<S>");
147     }
148 
149     static void test_long() {
150         df = new DecimalFormat();
151         dfs = df.getDecimalFormatSymbols();
152 
153         /* Test with default pattern */
154         test(123456789L,  "123,456,789");
155         test(-123456789L, "-123,456,789");
156 
157         test(0L, "0");
158         test(-0L, "0");
159 
160         /* Specify a pattern and the minus sign. */
161         prepareFormatter("<P>#,###<S>;<p>-#,###<s>", 'm');
162         test(123456789L,  "<P>123,456,789<S>");
163         test(-123456789L, "<p>m123,456,789<s>");
164 
165         test(0L, "<P>0<S>");
166         test(-0L, "<P>0<S>");
167     }
168 
169     static void test_BigInteger() {
170         df = new DecimalFormat();
171         dfs = df.getDecimalFormatSymbols();
172 
173         /* Test with default pattern */
174         test(new BigInteger("123456789012345678901234567890"),
175              "123,456,789,012,345,678,901,234,567,890");
176         test(new BigInteger("-123456789012345678901234567890"),
177              "-123,456,789,012,345,678,901,234,567,890");
178 
179         test(new BigInteger("0"), "0");
180         test(new BigInteger("-0"), "0");
181 
182         /* Specify a pattern and the minus sign. */
183         prepareFormatter("<P>#,###<S>;<p>-#,###<s>", 'm');
184         test(new BigInteger("123456789012345678901234567890"),
185              "<P>123,456,789,012,345,678,901,234,567,890<S>");
186         test(new BigInteger("-123456789012345678901234567890"),
187              "<p>m123,456,789,012,345,678,901,234,567,890<s>");
188 
189         test(new BigInteger("0"), "<P>0<S>");
190         test(new BigInteger("-0"), "<P>0<S>");
191     }
192 
193     static void prepareFormatter(String pattern, char minusSign) {
194         dfs = df.getDecimalFormatSymbols();
195         df.applyPattern(pattern);
196         dfs.setMinusSign(minusSign);
197         df.setDecimalFormatSymbols(dfs);
198     }
199 
200     static void test(Number num, String str) {
201         String formatted = df.format(num);
202         if (!formatted.equals(str)) {
203             err = true;
204             System.err.println("    DecimalFormat format(" +
205                                num.getClass().getName() +
206                                ") error: \n\tnumber: " + num +
207                                "\n\tminus sign: " + dfs.getMinusSign() +
208                                "\n\tgot:        " + formatted +
209                                "\n\texpected:   " + str);
210             return;
211         }
212 
213         if (num instanceof BigDecimal || num instanceof BigInteger) {
214             df.setParseBigDecimal(true);
215         }
216         Number parsed1 = null, parsed2 = null;
217         try {
218             parsed1 = df.parse(formatted);
219             formatted = df.format(parsed1);
220             parsed2 = df.parse(formatted);
221             if (!parsed1.equals(parsed2)) {
222                 err = true;
223                 System.err.println("    DecimalFormat roundtrip parse(" +
224                                    num.getClass().getName() +
225                                    ") error: \n\toriginal number:  " + str +
226                                    "\n\tparsed number:    " + parsed1 +
227                                    "  (" + parsed1.getClass().getName() + ")" +
228                                    "\n\tformatted number: " + formatted +
229                                    "\n\tre-parsed number: " + parsed2 +
230                                    "  (" + parsed2.getClass().getName() + ")" +
231                                    "\n\tminus sign: " + dfs.getMinusSign());
232             }
233         }
234         catch (Exception e) {
235             err = true;
236             System.err.println("    DecimalFormat parse(" +
237                                num.getClass().getName() +
238                                ") threw an Exception:  " + e.getMessage() +
239                                "\n\toriginal number:  " + str +
240                                "\n\tparsed number   : " + parsed1 +
241                                "  (" + parsed1.getClass().getName() + ")" +
242                                "\n\tformatted number: " + formatted +
243                                "\n\tre-parsed number: " + parsed2 +
244                                "  (" + parsed2.getClass().getName() + ")" +
245                                "\n\tminus sign: " + dfs.getMinusSign());
246         }
247     }
248 }