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(new Double(1234),    "1,234");
  75         test(new Double(0.1234),  "0.123");     // rounded
  76         test(new Double(-1234),   "-1,234");
  77         test(new Double(-0.1234), "-0.123");    // rounded
  78 
  79         test(new Double(Double.POSITIVE_INFINITY), "\u221e");
  80         test(new Double(Double.NEGATIVE_INFINITY), "-\u221e");
  81         test(new Double(Double.NaN), "\ufffd"); // without prefix and suffix
  82         test(new Double(0.0),  "0");
  83         test(new Double(-0.0), "-0");   // with the minus sign
  84 
  85         /* Specify a pattern and the minus sign. */
  86         prepareFormatter("<P>#.###E00<S>", 'm');
  87         test(new Double(1234),    "<P>1.234E03<S>");
  88         test(new Double(0.1234),  "<P>1.234Em01<S>");
  89         test(new Double(-1234),   "m<P>1.234E03<S>");
  90         test(new Double(-0.1234), "m<P>1.234Em01<S>");
  91 
  92         prepareFormatter("<P>#.###E00<S>;#.###E00", 'm');
  93         test(new Double(1234),    "<P>1.234E03<S>");
  94         test(new Double(0.1234),  "<P>1.234Em01<S>");
  95         test(new Double(-1234),   "1.234E03");
  96         test(new Double(-0.1234), "1.234Em01");
  97 
  98         prepareFormatter("#.###E00;<P>#.###E00<S>", 'm');
  99         test(new Double(1234),    "1.234E03");
 100         test(new Double(0.1234),  "1.234Em01");
 101         test(new Double(-1234),   "<P>1.234E03<S>");
 102         test(new Double(-0.1234), "<P>1.234Em01<S>");
 103 
 104         prepareFormatter("<P>#.###E00<S>;<p>-#.###E00<s>", 'm');
 105         test(new Double(1234),    "<P>1.234E03<S>");
 106         test(new Double(0.1234),  "<P>1.234Em01<S>");
 107         test(new Double(-1234),   "<p>m1.234E03<s>");
 108         test(new Double(-0.1234), "<p>m1.234Em01<s>");
 109 
 110         test(new Double(Double.POSITIVE_INFINITY), "<P>\u221e<S>");
 111         test(new Double(Double.NEGATIVE_INFINITY), "<p>m\u221e<s>");
 112         test(new Double(Double.NaN), "\ufffd"); // without prefix and suffix
 113         test(new Double(0.0),  "<P>0E00<S>");
 114         test(new Double(-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(new Long(123456789),  "123,456,789");
 155         test(new Long(-123456789), "-123,456,789");
 156 
 157         test(new Long(0), "0");
 158         test(new Long(-0), "0");
 159 
 160         /* Specify a pattern and the minus sign. */
 161         prepareFormatter("<P>#,###<S>;<p>-#,###<s>", 'm');
 162         test(new Long(123456789),  "<P>123,456,789<S>");
 163         test(new Long(-123456789), "<p>m123,456,789<s>");
 164 
 165         test(new Long(0), "<P>0<S>");
 166         test(new Long(-0), "<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 }