1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
3/*
4*******************************************************************************
5* Copyright (C) 2014-2015, International Business Machines Corporation and         *
6* others. All Rights Reserved.                                                *
7*******************************************************************************
8*
9* File numfmtspectest.cpp
10*
11*******************************************************************************
12*/
13#include <stdio.h>
14#include <stdlib.h>
15
16#include "intltest.h"
17
18#if !UCONFIG_NO_FORMATTING
19
20#include "unicode/localpointer.h"
21#include "unicode/decimfmt.h"
22#include "unicode/dtfmtsym.h"
23#include "uassert.h"
24
25static const UChar kJPY[] = {0x4A, 0x50, 0x59};
26
27static void fixNonBreakingSpace(UnicodeString &str) {
28    for (int32_t i = 0; i < str.length(); ++i) {
29        if (str[i] == 0xa0) {
30            str.setCharAt(i, 0x20);
31        }
32    }
33}
34
35static NumberFormat *nfWithPattern(const char *pattern) {
36    UnicodeString upattern(pattern, -1, US_INV);
37    upattern = upattern.unescape();
38    UErrorCode status = U_ZERO_ERROR;
39    DecimalFormat *result = new DecimalFormat(
40            upattern, new DecimalFormatSymbols("fr", status), status);
41    if (U_FAILURE(status)) {
42        return NULL;
43    }
44
45    return result;
46}
47
48static UnicodeString format(double d, const NumberFormat &fmt) {
49    UnicodeString result;
50    fmt.format(d, result);
51    fixNonBreakingSpace(result);
52    return result;
53}
54
55class NumberFormatSpecificationTest : public IntlTest {
56public:
57    NumberFormatSpecificationTest() {
58    }
59    void TestBasicPatterns();
60    void TestNfSetters();
61    void TestRounding();
62    void TestSignificantDigits();
63    void TestScientificNotation();
64    void TestPercent();
65    void TestPerMilli();
66    void TestPadding();
67    void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par=0);
68private:
69    void assertPatternFr(
70            const char *expected, double x, const char *pattern, UBool possibleDataError=FALSE);
71
72};
73
74void NumberFormatSpecificationTest::runIndexedTest(
75        int32_t index, UBool exec, const char *&name, char *) {
76    if (exec) {
77        logln("TestSuite NumberFormatSpecificationTest: ");
78    }
79    TESTCASE_AUTO_BEGIN;
80    TESTCASE_AUTO(TestBasicPatterns);
81    TESTCASE_AUTO(TestNfSetters);
82    TESTCASE_AUTO(TestRounding);
83    TESTCASE_AUTO(TestSignificantDigits);
84    TESTCASE_AUTO(TestScientificNotation);
85    TESTCASE_AUTO(TestPercent);
86    TESTCASE_AUTO(TestPerMilli);
87    TESTCASE_AUTO(TestPadding);
88    TESTCASE_AUTO_END;
89}
90
91void NumberFormatSpecificationTest::TestBasicPatterns() {
92    assertPatternFr("1 234,57", 1234.567, "#,##0.##", TRUE);
93    assertPatternFr("1234,57", 1234.567, "0.##", TRUE);
94    assertPatternFr("1235", 1234.567, "0", TRUE);
95    assertPatternFr("1 234,567", 1234.567, "#,##0.###", TRUE);
96    assertPatternFr("1234,567", 1234.567, "###0.#####", TRUE);
97    assertPatternFr("1234,5670", 1234.567, "###0.0000#", TRUE);
98    assertPatternFr("01234,5670", 1234.567, "00000.0000", TRUE);
99    assertPatternFr("1 234,57 \\u20ac", 1234.567, "#,##0.00 \\u00a4", TRUE);
100}
101
102void NumberFormatSpecificationTest::TestNfSetters() {
103    LocalPointer<NumberFormat> nf(nfWithPattern("#,##0.##"));
104    if (nf == NULL) {
105        dataerrln("Error creating NumberFormat");
106        return;
107    }
108    nf->setMaximumIntegerDigits(5);
109    nf->setMinimumIntegerDigits(4);
110    assertEquals("", "34 567,89", format(1234567.89, *nf), TRUE);
111    assertEquals("", "0 034,56", format(34.56, *nf), TRUE);
112}
113
114void NumberFormatSpecificationTest::TestRounding() {
115    assertPatternFr("1,0", 1.25, "0.5", TRUE);
116    assertPatternFr("2,0", 1.75, "0.5", TRUE);
117    assertPatternFr("-1,0", -1.25, "0.5", TRUE);
118    assertPatternFr("-02,0", -1.75, "00.5", TRUE);
119    assertPatternFr("0", 2.0, "4", TRUE);
120    assertPatternFr("8", 6.0, "4", TRUE);
121    assertPatternFr("8", 10.0, "4", TRUE);
122    assertPatternFr("99,90", 99.0, "2.70", TRUE);
123    assertPatternFr("273,00", 272.0, "2.73", TRUE);
124    assertPatternFr("1 03,60", 104.0, "#,#3.70", TRUE);
125}
126
127void NumberFormatSpecificationTest::TestSignificantDigits() {
128    assertPatternFr("1230", 1234.0, "@@@", TRUE);
129    assertPatternFr("1 234", 1234.0, "@,@@@", TRUE);
130    assertPatternFr("1 235 000", 1234567.0, "@,@@@", TRUE);
131    assertPatternFr("1 234 567", 1234567.0, "@@@@,@@@", TRUE);
132    assertPatternFr("12 34 567,00", 1234567.0, "@@@@,@@,@@@", TRUE);
133    assertPatternFr("12 34 567,0", 1234567.0, "@@@@,@@,@@#", TRUE);
134    assertPatternFr("12 34 567", 1234567.0, "@@@@,@@,@##", TRUE);
135    assertPatternFr("12 34 567", 1234567.001, "@@@@,@@,@##", TRUE);
136    assertPatternFr("12 34 567", 1234567.001, "@@@@,@@,###", TRUE);
137    assertPatternFr("1 200", 1234.0, "#,#@@", TRUE);
138}
139
140void NumberFormatSpecificationTest::TestScientificNotation() {
141    assertPatternFr("1,23E4", 12345.0, "0.00E0", TRUE);
142    assertPatternFr("123,00E2", 12300.0, "000.00E0", TRUE);
143    assertPatternFr("123,0E2", 12300.0, "000.0#E0", TRUE);
144    assertPatternFr("123,0E2", 12300.1, "000.0#E0", TRUE);
145    assertPatternFr("123,01E2", 12301.0, "000.0#E0", TRUE);
146    assertPatternFr("123,01E+02", 12301.0, "000.0#E+00", TRUE);
147    assertPatternFr("12,3E3", 12345.0, "##0.00E0", TRUE);
148    assertPatternFr("12,300E3", 12300.1, "##0.0000E0", TRUE);
149    assertPatternFr("12,30E3", 12300.1, "##0.000#E0", TRUE);
150    assertPatternFr("12,301E3", 12301.0, "##0.000#E0", TRUE);
151    if (!logKnownIssue("11020")) {
152        assertPatternFr("1,25E4", 12301.2, "0.05E0");
153    }
154    assertPatternFr("170,0E-3", 0.17, "##0.000#E0", TRUE);
155
156}
157
158void NumberFormatSpecificationTest::TestPercent() {
159    assertPatternFr("57,3%", 0.573, "0.0%", TRUE);
160    assertPatternFr("%57,3", 0.573, "%0.0", TRUE);
161    assertPatternFr("p%p57,3", 0.573, "p%p0.0", TRUE);
162    assertPatternFr("p%p0,6", 0.573, "p'%'p0.0", TRUE);
163    assertPatternFr("%3,260", 0.0326, "%@@@@", TRUE);
164    assertPatternFr("%1 540", 15.43, "%#,@@@", TRUE);
165    assertPatternFr("%1 656,4", 16.55, "%#,##4.1", TRUE);
166    assertPatternFr("%16,3E3", 162.55, "%##0.00E0", TRUE);
167}
168
169void NumberFormatSpecificationTest::TestPerMilli() {
170    assertPatternFr("573,0\\u2030", 0.573, "0.0\\u2030", TRUE);
171    assertPatternFr("\\u2030573,0", 0.573, "\\u20300.0", TRUE);
172    assertPatternFr("p\\u2030p573,0", 0.573, "p\\u2030p0.0", TRUE);
173    assertPatternFr("p\\u2030p0,6", 0.573, "p'\\u2030'p0.0", TRUE);
174    assertPatternFr("\\u203032,60", 0.0326, "\\u2030@@@@", TRUE);
175    assertPatternFr("\\u203015 400", 15.43, "\\u2030#,@@@", TRUE);
176    assertPatternFr("\\u203016 551,7", 16.55, "\\u2030#,##4.1", TRUE);
177    assertPatternFr("\\u2030163E3", 162.55, "\\u2030##0.00E0", TRUE);
178}
179
180void NumberFormatSpecificationTest::TestPadding() {
181    assertPatternFr("$***1 234", 1234, "$**####,##0", TRUE);
182    assertPatternFr("xxx$1 234", 1234, "*x$####,##0", TRUE);
183    assertPatternFr("1 234xxx$", 1234, "####,##0*x$", TRUE);
184    assertPatternFr("1 234$xxx", 1234, "####,##0$*x", TRUE);
185    assertPatternFr("ne1 234nx", -1234, "####,##0$*x;ne#n", TRUE);
186    assertPatternFr("n1 234*xx", -1234, "####,##0$*x;n#'*'", TRUE);
187    assertPatternFr("yyyy%432,6", 4.33, "*y%4.2######",  TRUE);
188    if (!logKnownIssue("11025")) {
189        assertPatternFr("EUR *433,00", 433.0, "\\u00a4\\u00a4 **####0.00");
190        assertPatternFr("EUR *433,00", 433.0, "\\u00a4\\u00a4 **#######0");
191    }
192    {
193        UnicodeString upattern("\\u00a4\\u00a4 **#######0", -1, US_INV);
194        upattern = upattern.unescape();
195        UErrorCode status = U_ZERO_ERROR;
196        UnicodeString result;
197        DecimalFormat fmt(
198                upattern, new DecimalFormatSymbols("fr", status), status);
199        if (U_FAILURE(status)) {
200            dataerrln("Error creating DecimalFormat - %s", u_errorName(status));
201        } else {
202            fmt.setCurrency(kJPY);
203            fmt.format(433.22, result);
204            assertSuccess("", status);
205            assertEquals("", "JPY ****433", result, TRUE);
206        }
207    }
208    {
209        UnicodeString upattern(
210            "\\u00a4\\u00a4 **#######0;\\u00a4\\u00a4 (#)", -1, US_INV);
211        upattern = upattern.unescape();
212        UErrorCode status = U_ZERO_ERROR;
213        UnicodeString result;
214        DecimalFormat fmt(
215                upattern,
216                new DecimalFormatSymbols("en_US", status),
217                status);
218        if (U_FAILURE(status)) {
219            dataerrln("Error creating DecimalFormat - %s", u_errorName(status));
220        } else {
221            fmt.format(-433.22, result);
222            assertSuccess("", status);
223            assertEquals("", "USD (433.22)", result, TRUE);
224        }
225    }
226    const char *paddedSciPattern = "QU**00.#####E0";
227    assertPatternFr("QU***43,3E-1", 4.33, paddedSciPattern, TRUE);
228    {
229        UErrorCode status = U_ZERO_ERROR;
230        DecimalFormatSymbols *sym = new DecimalFormatSymbols("fr", status);
231        sym->setSymbol(DecimalFormatSymbols::kExponentialSymbol, "EE");
232        DecimalFormat fmt(
233                paddedSciPattern,
234                sym,
235                status);
236        if (U_FAILURE(status)) {
237            dataerrln("Error creating DecimalFormat - %s", u_errorName(status));
238        } else {
239            UnicodeString result;
240            fmt.format(4.33, result);
241            assertSuccess("", status);
242            assertEquals("", "QU**43,3EE-1", result, TRUE);
243        }
244    }
245    // padding cannot work as intended with scientific notation.
246    assertPatternFr("QU**43,32E-1", 4.332, paddedSciPattern, TRUE);
247}
248
249void NumberFormatSpecificationTest::assertPatternFr(
250        const char *expected,
251        double x,
252        const char *pattern,
253        UBool possibleDataError) {
254    UnicodeString upattern(pattern, -1, US_INV);
255    UnicodeString uexpected(expected, -1, US_INV);
256    upattern = upattern.unescape();
257    uexpected = uexpected.unescape();
258    UErrorCode status = U_ZERO_ERROR;
259    UnicodeString result;
260    DecimalFormat fmt(
261            upattern, new DecimalFormatSymbols("fr_FR", status), status);
262    if (U_FAILURE(status)) {
263        dataerrln("Error creating DecimalFormatSymbols - %s", u_errorName(status));
264        return;
265    }
266    fmt.format(x, result);
267    fixNonBreakingSpace(result);
268    assertSuccess("", status);
269    assertEquals("", uexpected, result, possibleDataError);
270}
271
272extern IntlTest *createNumberFormatSpecificationTest() {
273    return new NumberFormatSpecificationTest();
274}
275
276#endif
277