1/*
2 *******************************************************************************
3 * Copyright (C) 1996-2009, International Business Machines Corporation and    *
4 * others. All Rights Reserved.                                                *
5 *******************************************************************************
6 */
7package com.ibm.icu.dev.test.format;
8
9import java.text.ParseException;
10import java.util.Locale;
11
12import com.ibm.icu.dev.test.TestFmwk;
13import com.ibm.icu.impl.Utility;
14import com.ibm.icu.text.DecimalFormat;
15import com.ibm.icu.text.DecimalFormatSymbols;
16import com.ibm.icu.text.NumberFormat;
17
18/**
19 * @test
20 * General test of Big NumberFormat
21 */
22public class BigNumberFormatTest extends TestFmwk {
23
24    static final int ILLEGAL = -1;
25
26    public static void main(String[] args) throws Exception {
27        new BigNumberFormatTest().run(args);
28    }
29
30    public void TestExponent() {
31        DecimalFormatSymbols US = new DecimalFormatSymbols(Locale.US);
32        DecimalFormat fmt1 = new DecimalFormat("0.###E0", US);
33        DecimalFormat fmt2 = new DecimalFormat("0.###E+0", US);
34        Number n = new Long(1234);
35        expect(fmt1, n, "1.234E3");
36        expect(fmt2, n, "1.234E+3");
37        expect(fmt1, "1.234E3", n);
38        expect(fmt1, "1.234E+3", n); // Either format should parse "E+3"
39        expect(fmt2, "1.234E+3", n);
40    }
41
42    /**
43     * Test the functioning of the secondary grouping value.
44     */
45    public void TestSecondaryGrouping() {
46        DecimalFormatSymbols US = new DecimalFormatSymbols(Locale.US);
47        DecimalFormat f = new DecimalFormat("#,##,###", US);
48        expect(f, new Long(123456789), "12,34,56,789");
49        expectPat(f, "#,##,###");
50        f.applyPattern("#,###");
51        f.setSecondaryGroupingSize(4);
52        expect(f, new Long(123456789), "12,3456,789");
53        expectPat(f, "#,####,###");
54
55        // On Sun JDK 1.2-1.3, the hi_IN locale uses '0' for a zero digit,
56        // but on IBM JDK 1.2-1.3, the locale uses U+0966.
57        f = (DecimalFormat) NumberFormat.getInstance(new Locale("hi", "IN"));
58        String str = transmute("1,87,65,43,210",
59                               f.getDecimalFormatSymbols().getZeroDigit());
60        expect(f, new Long(1876543210), str);
61    }
62
63    private void expectPad(DecimalFormat fmt, String pat, int pos) {
64        expectPad(fmt, pat, pos, 0, (char)0);
65    }
66
67    private void expectPad(DecimalFormat fmt, String pat,
68                           int pos, int width, char pad) {
69        int apos = 0, awidth = 0;
70        char apad = 0;
71        try {
72            fmt.applyPattern(pat);
73            apos = fmt.getPadPosition();
74            awidth = fmt.getFormatWidth();
75            apad = fmt.getPadCharacter();
76        } catch (IllegalArgumentException e) {
77            apos = -1;
78            awidth = width;
79            apad = pad;
80        }
81        if (apos == pos && awidth == width && apad == pad) {
82            logln("Ok   \"" + pat + "\" pos=" + apos +
83                  ((pos == -1) ? "" : " width=" + awidth + " pad=" + apad));
84        } else {
85            logln("FAIL \"" + pat + "\" pos=" + apos +
86                  " width=" + awidth + " pad=" + apad +
87                  ", expected " + pos + " " + width + " " + pad);
88        }
89    }
90
91    /**
92     */
93    public void TestPatterns() {
94        DecimalFormatSymbols US = new DecimalFormatSymbols(Locale.US);
95        DecimalFormat fmt = new DecimalFormat("#", US);
96
97        expectPad(fmt, "*^#", DecimalFormat.PAD_BEFORE_PREFIX, 1, '^');
98        expectPad(fmt, "$*^#", DecimalFormat.PAD_AFTER_PREFIX, 2, '^');
99        expectPad(fmt, "#*^", DecimalFormat.PAD_BEFORE_SUFFIX, 1, '^');
100        expectPad(fmt, "#$*^", DecimalFormat.PAD_AFTER_SUFFIX, 2, '^');
101        expectPad(fmt, "$*^$#", ILLEGAL);
102        expectPad(fmt, "#$*^$", ILLEGAL);
103        expectPad(fmt, "'pre'#,##0*x'post'", DecimalFormat.PAD_BEFORE_SUFFIX,
104                  12, 'x');
105        expectPad(fmt, "''#0*x", DecimalFormat.PAD_BEFORE_SUFFIX,
106                  3, 'x');
107        expectPad(fmt, "'I''ll'*a###.##", DecimalFormat.PAD_AFTER_PREFIX,
108                  10, 'a');
109
110        fmt.applyPattern("AA#,##0.00ZZ");
111        fmt.setPadCharacter('^');
112
113        fmt.setFormatWidth(10);
114
115        fmt.setPadPosition(DecimalFormat.PAD_BEFORE_PREFIX);
116        expectPat(fmt, "*^AA#,##0.00ZZ");
117
118        fmt.setPadPosition(DecimalFormat.PAD_BEFORE_SUFFIX);
119        expectPat(fmt, "AA#,##0.00*^ZZ");
120
121        fmt.setPadPosition(DecimalFormat.PAD_AFTER_SUFFIX);
122        expectPat(fmt, "AA#,##0.00ZZ*^");
123
124        //            12  3456789012
125        String exp = "AA*^#,##0.00ZZ";
126        fmt.setFormatWidth(12);
127        fmt.setPadPosition(DecimalFormat.PAD_AFTER_PREFIX);
128        expectPat(fmt, exp);
129
130        fmt.setFormatWidth(13);
131        //              12  34567890123
132        expectPat(fmt, "AA*^##,##0.00ZZ");
133
134        fmt.setFormatWidth(14);
135        //              12  345678901234
136        expectPat(fmt, "AA*^###,##0.00ZZ");
137
138        fmt.setFormatWidth(15);
139        //              12  3456789012345
140        expectPat(fmt, "AA*^####,##0.00ZZ"); // This is the interesting case
141
142        fmt.setFormatWidth(16);
143        //              12  34567890123456
144        expectPat(fmt, "AA*^#,###,##0.00ZZ");
145    }
146
147    private void expectPat(DecimalFormat fmt, String exp) {
148        String pat = fmt.toPattern();
149        if (pat.equals(exp)) {
150            logln("Ok   \"" + pat + '"');
151        } else {
152            errln("FAIL \"" + pat + "\", expected \"" + exp + '"');
153        }
154    }
155
156    /**
157     * Test the handling of the AlphaWorks BigDecimal
158     */
159    public void TestAlphaBigDecimal() {
160        DecimalFormatSymbols US = new DecimalFormatSymbols(Locale.US);
161        /*For ICU compatibility [Richard/GCL]*/
162        expect(NumberFormat.getScientificInstance(Locale.US),
163               new Number[] { new com.ibm.icu.math.BigDecimal("12345.678901"),
164                           },
165               "1.2345678901E4");
166        expect(new DecimalFormat("##0.####E0", US),
167               new Number[] { new com.ibm.icu.math.BigDecimal("12345.4999"),
168                              new com.ibm.icu.math.BigDecimal("12344.5001"),
169                            },
170               "12.345E3");
171        expect(new DecimalFormat("##0.####E0", US),
172               new Number[] { new com.ibm.icu.math.BigDecimal("12345.5000"),
173                              new com.ibm.icu.math.BigDecimal("12346.5000"),
174                            },
175               "12.346E3");
176    }
177
178    /**
179     */
180    public void TestScientific() {
181        DecimalFormatSymbols US = new DecimalFormatSymbols(Locale.US);
182        /*For ICU compatibility [Richard/GCL]*/
183        expect(NumberFormat.getScientificInstance(Locale.US),
184               new Number[] { new Double(12345.678901),
185                              new java.math.BigDecimal("12345.678901"),
186                            },
187               "1.2345678901E4");
188        expect(new DecimalFormat("##0.###E0", US),
189               new Double(12345),
190               "12.34E3");
191        expect(new DecimalFormat("##0.###E0", US),
192               new Double(12345.00001),
193               "12.35E3");
194        expect(new DecimalFormat("##0.####E0", US),
195               new Number[] { new Integer(12345),
196                              new Long(12345),
197                              new java.math.BigDecimal("12345.4999"),
198                              new java.math.BigDecimal("12344.5001"),
199                            },
200               "12.345E3");
201        expect(new DecimalFormat("##0.####E0", US),
202               new Number[] { new java.math.BigDecimal("12345.5000"),
203                              new java.math.BigDecimal("12346.5000"),
204                            },
205               "12.346E3");
206        /*For ICU compatibility [Richard/GCL]*/
207        expect(NumberFormat.getScientificInstance(Locale.FRANCE),
208               new Double(12345.678901),
209               "1,2345678901E4");
210        expect(new DecimalFormat("##0.####E0", US),
211               new Double(789.12345e-9),
212               "789.12E-9");
213        expect(new DecimalFormat("##0.####E0", US),
214               new Double(780.e-9),
215               "780E-9");
216        expect(new DecimalFormat(".###E0", US),
217               new Double(45678),
218               ".457E5");
219        expect(new DecimalFormat(".###E0", US),
220               new Long(0),
221               ".0E0");
222        expect(new DecimalFormat[] { new DecimalFormat("#E0", US),
223                                     new DecimalFormat("##E0", US),
224                                     new DecimalFormat("####E0", US),
225                                     new DecimalFormat("0E0", US),
226                                     new DecimalFormat("00E0", US),
227                                     new DecimalFormat("000E0", US),
228                                   },
229               new Long(45678000),
230               new String[] { "4.5678E7",
231                              "45.678E6",
232                              "4567.8E4",
233                              "5E7",
234                              "46E6",
235                              "457E5",
236                            }
237               );
238        expect(new DecimalFormat("###E0", US),
239               new Object[] { new Double(0.0000123), "12.3E-6",
240                              new Double(0.000123), "123E-6",
241                              new java.math.BigDecimal("0.00123"), "1.23E-3", // Cafe VM messes up Double(0.00123)
242                              new Double(0.0123), "12.3E-3",
243                              new Double(0.123), "123E-3",
244                              new Double(1.23), "1.23E0",
245                              new Double(12.3), "12.3E0",
246                              new Double(123), "123E0",
247                              new Double(1230), "1.23E3",
248                             });
249        expect(new DecimalFormat("0.#E+00", US),
250               new Object[] { new Double(0.00012), "1.2E-04",
251                              new Long(12000),     "1.2E+04",
252                             });
253    }
254
255    /**
256     */
257    public void TestPad() {
258        DecimalFormatSymbols US = new DecimalFormatSymbols(Locale.US);
259        expect(new DecimalFormat("*^##.##", US),
260               new Object[] { new Long(0),      "^^^^0",
261                              new Double(-1.3), "^-1.3",
262                            }
263               );
264        expect(new DecimalFormat("##0.0####E0*_ 'g-m/s^2'", US),
265               new Object[] { new Long(0),       "0.0E0______ g-m/s^2",
266                              new Double(1.0/3), "333.333E-3_ g-m/s^2",
267                            }
268               );
269        expect(new DecimalFormat("##0.0####*_ 'g-m/s^2'", US),
270               new Object[] { new Long(0),       "0.0______ g-m/s^2",
271                              new Double(1.0/3), "0.33333__ g-m/s^2",
272                            }
273               );
274        expect(new DecimalFormat("*x#,###,###,##0.00;*x(#,###,###,##0.00)", US),
275               new Object[] {
276                   new Long(-100),        "xxxxxxxx(100.00)",
277                   new Long(-1000),       "xxxxxx(1,000.00)",
278                   new Long(-1000000),    "xx(1,000,000.00)",
279                   new Long(-1000000000), "(1,000,000,000.00)",
280               });
281    }
282
283    private void expect(NumberFormat fmt, Object[] data) {
284        for (int i=0; i<data.length; i+=2) {
285            expect(fmt, (Number) data[i], (String) data[i+1]);
286        }
287    }
288
289    private void expect(Object fmto, Object numo, Object expo) {
290        NumberFormat fmt = null, fmts[] = null;
291        Number num = null, nums[] = null;
292        String exp = null, exps[] = null;
293        if (fmto instanceof NumberFormat[]) {
294            fmts = (NumberFormat[]) fmto;
295        } else {
296            fmt = (NumberFormat) fmto;
297        }
298        if (numo instanceof Number[]) {
299            nums = (Number[]) numo;
300        } else {
301            num = (Number) numo;
302        }
303        if (expo instanceof String[]) {
304            exps = (String[]) expo;
305        } else {
306            exp = (String) expo;
307        }
308        int n = 1;
309        if (fmts != null) {
310            n = Math.max(n, fmts.length);
311        }
312        if (nums != null) {
313            n = Math.max(n, nums.length);
314        }
315        if (exps != null) {
316            n = Math.max(n, exps.length);
317        }
318        for (int i=0; i<n; ++i) {
319            expect(fmts == null ? fmt : fmts[i],
320                   nums == null ? num : nums[i],
321                   exps == null ? exp : exps[i]);
322        }
323    }
324
325    private static String showNumber(Number n) {
326        String cls = n.getClass().getName();
327        if (!(n instanceof com.ibm.icu.math.BigDecimal
328              || n instanceof java.math.BigDecimal)) {
329            int i = cls.lastIndexOf('.');
330            cls = cls.substring(i+1);
331        }
332        return n.toString() + " (" + cls + ')';
333    }
334
335    private void expect(NumberFormat fmt, Number n, String exp) {
336        String saw = fmt.format(n);
337        String pat = ((DecimalFormat) fmt).toPattern();
338        if (saw.equals(exp)) {
339            logln("Ok   " + showNumber(n) + " x " +
340                  pat + " = " +
341                  Utility.escape(saw));
342        } else {
343            errln("FAIL " + showNumber(n) + " x " +
344                  pat + " = \"" +
345                  Utility.escape(saw) + ", expected " + Utility.escape(exp));
346        }
347    }
348
349    private void expect(NumberFormat fmt, String str, Number exp) {
350        Number saw = null;
351        try {
352            saw = fmt.parse(str);
353        } catch (ParseException e) {
354            saw = null;
355        }
356        String pat = ((DecimalFormat) fmt).toPattern();
357        if (saw.equals(exp)) {
358            logln("Ok   \"" + str + "\" x " +
359                  pat + " = " +
360                  showNumber(saw));
361        } else {
362            errln("FAIL \"" + str + "\" x " +
363                  pat + " = " +
364                  showNumber(saw) + ", expected " + showNumber(exp));
365        }
366    }
367
368    /**
369     * Given a string composed of [0-9] and other chars, convert the
370     * [0-9] chars to be offsets 0..9 from 'zero'.
371     */
372    private static String transmute(String str, char zero) {
373        StringBuffer buf = new StringBuffer();
374        for (int i=0; i<str.length(); ++i) {
375            char c = str.charAt(i);
376            if (c >= '0' && c <= '9') {
377                c = (char) (c - '0' + zero);
378            }
379            buf.append(c);
380        }
381        return buf.toString();
382    }
383
384    public void Test4161100() {
385        NumberFormat f = NumberFormat.getInstance();
386        f.setMinimumFractionDigits(1);
387        f.setMaximumFractionDigits(1);
388        double a = -0.09;
389        String s = f.format(a);
390        logln(a + " x " +
391              ((DecimalFormat) f).toPattern() + " = " +
392              s);
393        if (!s.equals("-0.1")) {
394            errln("FAIL");
395        }
396    }
397
398    public void TestBigDecimalJ28() {
399        String[] DATA = {
400            "1", "1E0",
401            "-1", "-1E0",
402            "0", "0E0",
403            "12e34", "1.2E35",
404            "-12.3e-45", "-1.23E-44",
405            "0.73e-7", "7.3E-8",
406        };
407        NumberFormat fmt = NumberFormat.getScientificInstance(Locale.US);
408        logln("Pattern: " + ((DecimalFormat)fmt).toPattern());
409        for (int i=0; i<DATA.length; i+=2) {
410            String input = DATA[i];
411            String exp = DATA[i+1];
412            com.ibm.icu.math.BigDecimal bd = new com.ibm.icu.math.BigDecimal(input);
413            String output = fmt.format(bd);
414            if (output.equals(exp)) {
415                logln("input=" + input + " num=" + bd + " output=" + output);
416            } else {
417                errln("FAIL: input=" + input + " num=" + bd + " output=" + output +
418                      " expected=" + exp);
419            }
420        }
421    }
422    public void TestBigDecimalRounding() {
423        // jb 3657
424        java.text.DecimalFormat jdkFormat=new java.text.DecimalFormat("###,###,###,##0");
425        com.ibm.icu.text.DecimalFormat icuFormat=new com.ibm.icu.text.DecimalFormat("###,###,###,##0");
426        String[] values = {
427            "-1.74", "-1.24", "-0.74", "-0.24", "0.24", "0.74", "1.24", "1.74"
428        };
429        for (int i = 0; i < values.length; ++i) {
430            String val = values[i];
431            java.math.BigDecimal bd = new java.math.BigDecimal(val);
432            String jdk = jdkFormat.format(bd);
433            String icu = icuFormat.format(bd);
434            logln("Format of BigDecimal " + val + " by JDK is " + jdk);
435            logln("Format of BigDecimal " + val + " by ICU is " + icu);
436            if (!jdk.equals(icu)) {
437                errln("BigDecimal jdk: " + jdk + " != icu: " + icu);
438            }
439
440            double d = bd.doubleValue();
441            jdk = jdkFormat.format(d);
442            icu = icuFormat.format(d);
443            logln("Format of double " + val + " by JDK is " + jdk);
444            logln("Format of double " + val + " by ICU is " + icu);
445            if (!jdk.equals(icu)) {
446                errln("double jdk: " + jdk + " != icu: " + icu);
447            }
448        }
449    }
450}
451