1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html#License
3/*****************************************************************************************
4 *
5 *   Copyright (C) 1996-2012, International Business Machines
6 *   Corporation and others.  All Rights Reserved.
7 **/
8
9/**
10 * Port From:   JDK 1.4b1 : java.text.Format.IntlTestDecimalFormatAPI
11 * Source File: java/text/format/IntlTestDecimalFormatAPI.java
12 **/
13
14/*
15    @test 1.4 98/03/06
16    @summary test International Decimal Format API
17*/
18
19package com.ibm.icu.dev.test.format;
20
21import java.text.FieldPosition;
22import java.text.Format;
23import java.text.ParseException;
24import java.text.ParsePosition;
25import java.util.Locale;
26
27import org.junit.Test;
28import org.junit.runner.RunWith;
29import org.junit.runners.JUnit4;
30
31import com.ibm.icu.dev.test.TestFmwk;
32import com.ibm.icu.math.BigDecimal;
33import com.ibm.icu.math.MathContext;
34import com.ibm.icu.text.DecimalFormat;
35import com.ibm.icu.text.DecimalFormatSymbols;
36import com.ibm.icu.text.NumberFormat;
37
38@RunWith(JUnit4.class)
39public class IntlTestDecimalFormatAPI extends TestFmwk
40{
41    /**
42     * Problem 1: simply running
43     * decF4.setRoundingMode(java.math.BigDecimal.ROUND_HALF_UP) does not work
44     * as decF4.setRoundingIncrement(.0001) must also be run.
45     * Problem 2: decF4.format(8.88885) does not return 8.8889 as expected.
46     * You must run decF4.format(new BigDecimal(Double.valueOf(8.88885))) in
47     * order for this to work as expected.
48     * Problem 3: There seems to be no way to set half up to be the default
49     * rounding mode.
50     * We solved the problem with the code at the bottom of this page however
51     * this is not quite general purpose enough to include in icu4j. A static
52     * setDefaultRoundingMode function would solve the problem nicely. Also
53     * decimal places past 20 are not handled properly. A small ammount of work
54     * would make bring this up to snuff.
55     */
56    @Test
57    public void testJB1871()
58    {
59        // problem 2
60        double number = 8.88885;
61        String expected = "8.8889";
62
63        String pat = ",##0.0000";
64        DecimalFormat dec = new DecimalFormat(pat);
65        dec.setRoundingMode(BigDecimal.ROUND_HALF_UP);
66        dec.setRoundingIncrement(new java.math.BigDecimal("0.0001"));
67        String str = dec.format(number);
68        if (!str.equals(expected)) {
69            errln("Fail: " + number + " x \"" + pat + "\" = \"" +
70                  str + "\", expected \"" + expected + "\"");
71        }
72
73        pat = ",##0.0001";
74        dec = new DecimalFormat(pat);
75        dec.setRoundingMode(BigDecimal.ROUND_HALF_UP);
76        str = dec.format(number);
77        if (!str.equals(expected)) {
78            errln("Fail: " + number + " x \"" + pat + "\" = \"" +
79                  str + "\", expected \"" + expected + "\"");
80        }
81
82        // testing 20 decimal places
83        pat = ",##0.00000000000000000001";
84        dec = new DecimalFormat(pat);
85        BigDecimal bignumber = new BigDecimal("8.888888888888888888885");
86        expected = "8.88888888888888888889";
87
88        dec.setRoundingMode(BigDecimal.ROUND_HALF_UP);
89        str = dec.format(bignumber);
90        if (!str.equals(expected)) {
91            errln("Fail: " + bignumber + " x \"" + pat + "\" = \"" +
92                  str + "\", expected \"" + expected + "\"");
93        }
94
95    }
96
97    /**
98     * This test checks various generic API methods in DecimalFormat to achieve
99     * 100% API coverage.
100     */
101    @Test
102    public void TestAPI()
103    {
104        logln("DecimalFormat API test---"); logln("");
105        Locale.setDefault(Locale.ENGLISH);
106
107        // ======= Test constructors
108
109        logln("Testing DecimalFormat constructors");
110
111        DecimalFormat def = new DecimalFormat();
112
113        final String pattern = new String("#,##0.# FF");
114        DecimalFormat pat = null;
115        try {
116            pat = new DecimalFormat(pattern);
117        }
118        catch (IllegalArgumentException e) {
119            errln("ERROR: Could not create DecimalFormat (pattern)");
120        }
121
122        DecimalFormatSymbols symbols = new DecimalFormatSymbols(Locale.FRENCH);
123
124        DecimalFormat cust1 = new DecimalFormat(pattern, symbols);
125
126        // ======= Test clone(), assignment, and equality
127
128        logln("Testing clone() and equality operators");
129
130        Format clone = (Format) def.clone();
131        if( ! def.equals(clone)) {
132            errln("ERROR: Clone() failed");
133        }
134
135        // ======= Test various format() methods
136
137        logln("Testing various format() methods");
138
139//        final double d = -10456.0037; // this appears as -10456.003700000001 on NT
140//        final double d = -1.04560037e-4; // this appears as -1.0456003700000002E-4 on NT
141        final double d = -10456.00370000000000; // this works!
142        final long l = 100000000;
143        logln("" + d + " is the double value");
144
145        StringBuffer res1 = new StringBuffer();
146        StringBuffer res2 = new StringBuffer();
147        StringBuffer res3 = new StringBuffer();
148        StringBuffer res4 = new StringBuffer();
149        FieldPosition pos1 = new FieldPosition(0);
150        FieldPosition pos2 = new FieldPosition(0);
151        FieldPosition pos3 = new FieldPosition(0);
152        FieldPosition pos4 = new FieldPosition(0);
153
154        res1 = def.format(d, res1, pos1);
155        logln("" + d + " formatted to " + res1);
156
157        res2 = pat.format(l, res2, pos2);
158        logln("" + l + " formatted to " + res2);
159
160        res3 = cust1.format(d, res3, pos3);
161        logln("" + d + " formatted to " + res3);
162
163        res4 = cust1.format(l, res4, pos4);
164        logln("" + l + " formatted to " + res4);
165
166        // ======= Test parse()
167
168        logln("Testing parse()");
169
170        String text = new String("-10,456.0037");
171        ParsePosition pos = new ParsePosition(0);
172        String patt = new String("#,##0.#");
173        pat.applyPattern(patt);
174        double d2 = pat.parse(text, pos).doubleValue();
175        if(d2 != d) {
176            errln("ERROR: Roundtrip failed (via parse(" + d2 + " != " + d + ")) for " + text);
177        }
178        logln(text + " parsed into " + (long) d2);
179
180        // ======= Test getters and setters
181
182        logln("Testing getters and setters");
183
184        final DecimalFormatSymbols syms = pat.getDecimalFormatSymbols();
185        def.setDecimalFormatSymbols(syms);
186        if( ! pat.getDecimalFormatSymbols().equals(def.getDecimalFormatSymbols())) {
187            errln("ERROR: set DecimalFormatSymbols() failed");
188        }
189
190        String posPrefix;
191        pat.setPositivePrefix("+");
192        posPrefix = pat.getPositivePrefix();
193        logln("Positive prefix (should be +): " + posPrefix);
194        assertEquals("ERROR: setPositivePrefix() failed", "+", posPrefix);
195
196        String negPrefix;
197        pat.setNegativePrefix("-");
198        negPrefix = pat.getNegativePrefix();
199        logln("Negative prefix (should be -): " + negPrefix);
200        assertEquals("ERROR: setNegativePrefix() failed", "-", negPrefix);
201
202        String posSuffix;
203        pat.setPositiveSuffix("_");
204        posSuffix = pat.getPositiveSuffix();
205        logln("Positive suffix (should be _): " + posSuffix);
206        assertEquals("ERROR: setPositiveSuffix() failed", "_", posSuffix);
207
208        String negSuffix;
209        pat.setNegativeSuffix("~");
210        negSuffix = pat.getNegativeSuffix();
211        logln("Negative suffix (should be ~): " + negSuffix);
212        assertEquals("ERROR: setNegativeSuffix() failed", "~", negSuffix);
213
214        long multiplier = 0;
215        pat.setMultiplier(8);
216        multiplier = pat.getMultiplier();
217        logln("Multiplier (should be 8): " + multiplier);
218        if(multiplier != 8) {
219            errln("ERROR: setMultiplier() failed");
220        }
221
222        int groupingSize = 0;
223        pat.setGroupingSize(2);
224        groupingSize = pat.getGroupingSize();
225        logln("Grouping size (should be 2): " + (long) groupingSize);
226        if(groupingSize != 2) {
227            errln("ERROR: setGroupingSize() failed");
228        }
229
230        pat.setDecimalSeparatorAlwaysShown(true);
231        boolean tf = pat.isDecimalSeparatorAlwaysShown();
232        logln("DecimalSeparatorIsAlwaysShown (should be true) is " +  (tf ? "true" : "false"));
233        if(tf != true) {
234            errln("ERROR: setDecimalSeparatorAlwaysShown() failed");
235        }
236
237        String funkyPat;
238        funkyPat = pat.toPattern();
239        logln("Pattern is " + funkyPat);
240
241        String locPat;
242        locPat = pat.toLocalizedPattern();
243        logln("Localized pattern is " + locPat);
244
245        // ======= Test applyPattern()
246
247        logln("Testing applyPattern()");
248
249        String p1 = new String("#,##0.0#;(#,##0.0#)");
250        logln("Applying pattern " + p1);
251        pat.applyPattern(p1);
252        String s2;
253        s2 = pat.toPattern();
254        logln("Extracted pattern is " + s2);
255        if( ! s2.equals(p1) ) {
256            errln("ERROR: toPattern() result did not match pattern applied");
257        }
258
259        String p2 = new String("#,##0.0# FF;(#,##0.0# FF)");
260        logln("Applying pattern " + p2);
261        pat.applyLocalizedPattern(p2);
262        String s3;
263        s3 = pat.toLocalizedPattern();
264        logln("Extracted pattern is " + s3);
265        if( ! s3.equals(p2) ) {
266            errln("ERROR: toLocalizedPattern() result did not match pattern applied");
267        }
268    }
269
270    @Test
271    public void testJB6134()
272    {
273        DecimalFormat decfmt = new DecimalFormat();
274        StringBuffer buf = new StringBuffer();
275
276        FieldPosition fposByInt = new FieldPosition(NumberFormat.INTEGER_FIELD);
277        decfmt.format(123, buf, fposByInt);
278
279        buf.setLength(0);
280        FieldPosition fposByField = new FieldPosition(NumberFormat.Field.INTEGER);
281        decfmt.format(123, buf, fposByField);
282
283        if (fposByInt.getEndIndex() != fposByField.getEndIndex())
284        {
285            errln("ERROR: End index for integer field - fposByInt:" + fposByInt.getEndIndex() +
286                " / fposByField: " + fposByField.getEndIndex());
287        }
288    }
289
290    @Test
291    public void testJB4971()
292    {
293        DecimalFormat decfmt = new DecimalFormat();
294        MathContext resultICU;
295
296        MathContext comp1 = new MathContext(0, MathContext.PLAIN, false, MathContext.ROUND_HALF_EVEN);
297        resultICU = decfmt.getMathContextICU();
298        if ((comp1.getDigits() != resultICU.getDigits()) ||
299            (comp1.getForm() != resultICU.getForm()) ||
300            (comp1.getLostDigits() != resultICU.getLostDigits()) ||
301            (comp1.getRoundingMode() != resultICU.getRoundingMode()))
302        {
303            errln("ERROR: Math context 1 not equal - result: " + resultICU.toString() +
304                " / expected: " + comp1.toString());
305        }
306
307        MathContext comp2 = new MathContext(5, MathContext.ENGINEERING, false, MathContext.ROUND_HALF_EVEN);
308        decfmt.setMathContextICU(comp2);
309        resultICU = decfmt.getMathContextICU();
310        if ((comp2.getDigits() != resultICU.getDigits()) ||
311            (comp2.getForm() != resultICU.getForm()) ||
312            (comp2.getLostDigits() != resultICU.getLostDigits()) ||
313            (comp2.getRoundingMode() != resultICU.getRoundingMode()))
314        {
315            errln("ERROR: Math context 2 not equal - result: " + resultICU.toString() +
316                " / expected: " + comp2.toString());
317        }
318
319        java.math.MathContext result;
320
321        java.math.MathContext comp3 = new java.math.MathContext(3, java.math.RoundingMode.DOWN);
322        decfmt.setMathContext(comp3);
323        result = decfmt.getMathContext();
324        if ((comp3.getPrecision() != result.getPrecision()) ||
325            (comp3.getRoundingMode() != result.getRoundingMode()))
326        {
327            errln("ERROR: Math context 3 not equal - result: " + result.toString() +
328                " / expected: " + comp3.toString());
329        }
330
331    }
332
333    @Test
334    public void testJB6354()
335    {
336        DecimalFormat pat = new DecimalFormat("#,##0.00");
337        java.math.BigDecimal r1, r2;
338
339        // get default rounding increment
340        r1 = pat.getRoundingIncrement();
341
342        // set rounding mode with zero increment.  Rounding
343        // increment should be set by this operation
344        pat.setRoundingMode(BigDecimal.ROUND_UP);
345        r2 = pat.getRoundingIncrement();
346
347        // check for different values
348        if ((r1 != null) && (r2 != null))
349        {
350            if (r1.compareTo(r2) == 0)
351            {
352                errln("ERROR: Rounding increment did not change");
353            }
354        }
355    }
356
357    @Test
358    public void testJB6648()
359    {
360        DecimalFormat df = new DecimalFormat();
361        df.setParseStrict(true);
362
363        String numstr = new String();
364
365        String[] patterns = {
366            "0",
367            "00",
368            "000",
369            "0,000",
370            "0.0",
371            "#000.0"
372        };
373
374        for(int i=0; i < patterns.length; i++) {
375            df.applyPattern(patterns[i]);
376            numstr = df.format(5);
377            try {
378                Number n = df.parse(numstr);
379                logln("INFO: Parsed " + numstr + " -> " + n);
380            } catch (ParseException pe) {
381                errln("ERROR: Failed round trip with strict parsing.");
382            }
383        }
384
385        df.applyPattern(patterns[1]);
386        numstr = "005";
387        try {
388            Number n = df.parse(numstr);
389            logln("INFO: Successful parse for " + numstr + " with strict parse enabled. Number is " + n);
390        } catch (ParseException pe) {
391            errln("ERROR: Parse Exception encountered in strict mode: numstr -> " + numstr);
392        }
393
394    }
395}
396