1/*
2*******************************************************************************
3* Copyright (C) 1997-2015, International Business Machines Corporation and    *
4* others. All Rights Reserved.                                                *
5*******************************************************************************
6*
7* File COMPACTDECIMALFORMATTEST.CPP
8*
9********************************************************************************
10*/
11#include <stdio.h>
12#include <stdlib.h>
13
14#include "intltest.h"
15
16#if !UCONFIG_NO_FORMATTING
17
18#include "unicode/compactdecimalformat.h"
19#include "unicode/unum.h"
20#include "cmemory.h"
21
22typedef struct ExpectedResult {
23  double value;
24  const char *expected;
25} ExpectedResult;
26
27static const char *kShortStr = "Short";
28static const char *kLongStr = "Long";
29
30static ExpectedResult kEnglishShort[] = {
31  {0.0, "0"},
32  {0.17, "0.17"},
33  {1.0, "1"},
34  {1234.0, "1.2K"},
35  {12345.0, "12K"},
36  {123456.0, "120K"},
37  {1234567.0, "1.2M"},
38  {12345678.0, "12M"},
39  {123456789.0, "120M"},
40  {1.23456789E9, "1.2B"},
41  {1.23456789E10, "12B"},
42  {1.23456789E11, "120B"},
43  {1.23456789E12, "1.2T"},
44  {1.23456789E13, "12T"},
45  {1.23456789E14, "120T"},
46  {1.23456789E15, "1200T"}};
47
48static ExpectedResult kSerbianShort[] = {
49  {1234.0, "1,2\\u00a0\\u0445\\u0438\\u0459."},
50  {12345.0, "12\\u00a0\\u0445\\u0438\\u0459."},
51  {20789.0, "21\\u00a0\\u0445\\u0438\\u0459."},
52  {123456.0, "120\\u00a0\\u0445\\u0438\\u0459."},
53  {1234567.0, "1,2\\u00A0\\u043C\\u0438\\u043B."},
54  {12345678.0, "12\\u00A0\\u043C\\u0438\\u043B."},
55  {123456789.0, "120\\u00A0\\u043C\\u0438\\u043B."},
56  {1.23456789E9, "1,2\\u00A0\\u043C\\u043B\\u0440\\u0434."},
57  {1.23456789E10, "12\\u00A0\\u043C\\u043B\\u0440\\u0434."},
58  {1.23456789E11, "120\\u00A0\\u043C\\u043B\\u0440\\u0434."},
59  {1.23456789E12, "1,2\\u00A0\\u0431\\u0438\\u043B."},
60  {1.23456789E13, "12\\u00A0\\u0431\\u0438\\u043B."},
61  {1.23456789E14, "120\\u00A0\\u0431\\u0438\\u043B."},
62  {1.23456789E15, "1200\\u00A0\\u0431\\u0438\\u043B."}};
63
64static ExpectedResult kSerbianLong[] = {
65  {1234.0, "1,2 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0435"}, // 10^3 few
66  {12345.0, "12 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0430"}, // 10^3 other
67  {21789.0, "22 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0435"}, // 10^3 few
68  {123456.0, "120 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0430"}, // 10^3 other
69  {999999.0, "1 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D"}, // 10^6 one
70  {1234567.0, "1,2 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"}, // 10^6 few
71  {12345678.0, "12 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"}, // 10^6 other
72  {123456789.0, "120 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"}, // 10^6 other
73  {1.23456789E9, "1,2 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0435"}, // 10^9 few
74  {1.23456789E10, "12 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0438"}, // 10^9 other
75  {2.08901234E10, "21 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0430"}, // 10^9 one
76  {2.18901234E10, "22 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0435"}, // 10^9 few
77  {1.23456789E11, "120 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0438"}, // 10^9 other
78  {1.23456789E12, "1,2 \\u0442\\u0440\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"}, // 10^12 few
79  {1.23456789E13, "12 \\u0442\\u0440\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"}, // 10^12 other
80  {1.23456789E14, "120 \\u0442\\u0440\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"}, // 10^12 other
81  {1.23456789E15, "1200 \\u0442\\u0440\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"}}; // 10^12 other
82
83static ExpectedResult kSerbianLongNegative[] = {
84  {-1234.0, "-1,2 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0435"},
85  {-12345.0, "-12 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0430"},
86  {-21789.0, "-22 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0435"},
87  {-123456.0, "-120 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0430"},
88  {-999999.0, "-1 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D"},
89  {-1234567.0, "-1,2 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"},
90  {-12345678.0, "-12 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"},
91  {-123456789.0, "-120 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"},
92  {-1.23456789E9, "-1,2 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0435"},
93  {-1.23456789E10, "-12 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0438"},
94  {-2.08901234E10, "-21 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0430"},
95  {-2.18901234E10, "-22 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0435"},
96  {-1.23456789E11, "-120 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0438"},
97  {-1.23456789E12, "-1,2 \\u0442\\u0440\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"},
98  {-1.23456789E13, "-12 \\u0442\\u0440\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"},
99  {-1.23456789E14, "-120 \\u0442\\u0440\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"},
100  {-1.23456789E15, "-1200 \\u0442\\u0440\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"}};
101
102static ExpectedResult kJapaneseShort[] = {
103  {1234.0, "1200"},
104  {12345.0, "1.2\\u4E07"},
105  {123456.0, "12\\u4E07"},
106  {1234567.0, "120\\u4E07"},
107  {12345678.0, "1200\\u4E07"},
108  {123456789.0, "1.2\\u5104"},
109  {1.23456789E9, "12\\u5104"},
110  {1.23456789E10, "120\\u5104"},
111  {1.23456789E11, "1200\\u5104"},
112  {1.23456789E12, "1.2\\u5146"},
113  {1.23456789E13, "12\\u5146"},
114  {1.23456789E14, "120\\u5146"}};
115
116static ExpectedResult kSwahiliShort[] = {
117  {1234.0, "elfu\\u00a01.2"},
118  {12345.0, "elfu\\u00a012"},
119  {123456.0, "elfu\\u00a0120"},
120  {1234567.0, "M1.2"},
121  {12345678.0, "M12"},
122  {123456789.0, "M120"},
123  {1.23456789E9, "B1.2"},
124  {1.23456789E10, "B12"},
125  {1.23456789E11, "B120"},
126  {1.23456789E12, "T1.2"},
127  {1.23456789E13, "T12"},
128  {1.23456789E15, "T1200"}};
129
130static ExpectedResult kCsShort[] = {
131  {1000.0, "1\\u00a0tis."},
132  {1500.0, "1,5\\u00a0tis."},
133  {5000.0, "5\\u00a0tis."},
134  {23000.0, "23\\u00a0tis."},
135  {127123.0, "130\\u00a0tis."},
136  {1271234.0, "1,3\\u00a0mil."},
137  {12712345.0, "13\\u00a0mil."},
138  {127123456.0, "130\\u00a0mil."},
139  {1.27123456E9, "1,3\\u00a0mld."},
140  {1.27123456E10, "13\\u00a0mld."},
141  {1.27123456E11, "130\\u00a0mld."},
142  {1.27123456E12, "1,3\\u00a0bil."},
143  {1.27123456E13, "13\\u00a0bil."},
144  {1.27123456E14, "130\\u00a0bil."}};
145
146static ExpectedResult kSkLong[] = {
147  {1000.0, "1 tis\\u00edc"},
148  {1572.0, "1,6 tis\\u00edca"},
149  {5184.0, "5,2 tis\\u00edca"}};
150
151static ExpectedResult kSwahiliShortNegative[] = {
152  {-1234.0, "elfu\\u00a0-1.2"},
153  {-12345.0, "elfu\\u00a0-12"},
154  {-123456.0, "elfu\\u00a0-120"},
155  {-1234567.0, "M-1.2"},
156  {-12345678.0, "M-12"},
157  {-123456789.0, "M-120"},
158  {-1.23456789E9, "B-1.2"},
159  {-1.23456789E10, "B-12"},
160  {-1.23456789E11, "B-120"},
161  {-1.23456789E12, "T-1.2"},
162  {-1.23456789E13, "T-12"},
163  {-1.23456789E15, "T-1200"}};
164
165static ExpectedResult kArabicLong[] = {
166  {-5300.0, "\\u200F-\\u0665\\u066B\\u0663 \\u0623\\u0644\\u0641"}};
167
168
169class CompactDecimalFormatTest : public IntlTest {
170public:
171    CompactDecimalFormatTest() {
172    }
173
174    void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par=0);
175private:
176    void TestEnglishShort();
177    void TestSerbianShort();
178    void TestSerbianLong();
179    void TestSerbianLongNegative();
180    void TestJapaneseShort();
181    void TestSwahiliShort();
182    void TestCsShort();
183    void TestSkLong();
184    void TestSwahiliShortNegative();
185    void TestArabicLong();
186    void TestFieldPosition();
187    void TestSignificantDigits();
188    void TestAPIVariants();
189    void CheckLocale(
190        const Locale& locale, UNumberCompactStyle style,
191        const ExpectedResult* expectedResult, int32_t expectedResultLength);
192    void CheckExpectedResult(
193        const CompactDecimalFormat* cdf, const ExpectedResult* expectedResult,
194        const char* description);
195    CompactDecimalFormat* createCDFInstance(const Locale& locale, UNumberCompactStyle style, UErrorCode& status);
196    static const char *StyleStr(UNumberCompactStyle style);
197};
198
199void CompactDecimalFormatTest::runIndexedTest(
200    int32_t index, UBool exec, const char *&name, char *) {
201  if (exec) {
202    logln("TestSuite CompactDecimalFormatTest: ");
203  }
204  TESTCASE_AUTO_BEGIN;
205  TESTCASE_AUTO(TestEnglishShort);
206  TESTCASE_AUTO(TestSerbianShort);
207  TESTCASE_AUTO(TestSerbianLong);
208  TESTCASE_AUTO(TestSerbianLongNegative);
209  TESTCASE_AUTO(TestJapaneseShort);
210  TESTCASE_AUTO(TestSwahiliShort);
211  TESTCASE_AUTO(TestCsShort);
212  TESTCASE_AUTO(TestSkLong);
213  TESTCASE_AUTO(TestSwahiliShortNegative);
214  TESTCASE_AUTO(TestArabicLong);
215  TESTCASE_AUTO(TestFieldPosition);
216  TESTCASE_AUTO(TestSignificantDigits);
217  TESTCASE_AUTO(TestAPIVariants);
218  TESTCASE_AUTO_END;
219}
220
221void CompactDecimalFormatTest::TestEnglishShort() {
222  CheckLocale("en", UNUM_SHORT, kEnglishShort, UPRV_LENGTHOF(kEnglishShort));
223}
224
225void CompactDecimalFormatTest::TestSerbianShort() {
226  CheckLocale("sr", UNUM_SHORT, kSerbianShort, UPRV_LENGTHOF(kSerbianShort));
227}
228
229void CompactDecimalFormatTest::TestSerbianLong() {
230  CheckLocale("sr", UNUM_LONG, kSerbianLong, UPRV_LENGTHOF(kSerbianLong));
231}
232
233void CompactDecimalFormatTest::TestSerbianLongNegative() {
234  CheckLocale("sr", UNUM_LONG, kSerbianLongNegative, UPRV_LENGTHOF(kSerbianLongNegative));
235}
236
237void CompactDecimalFormatTest::TestJapaneseShort() {
238  CheckLocale(Locale::getJapan(), UNUM_SHORT, kJapaneseShort, UPRV_LENGTHOF(kJapaneseShort));
239}
240
241void CompactDecimalFormatTest::TestSwahiliShort() {
242  CheckLocale("sw", UNUM_SHORT, kSwahiliShort, UPRV_LENGTHOF(kSwahiliShort));
243}
244
245void CompactDecimalFormatTest::TestFieldPosition() {
246  // Swahili uses prefixes which forces offsets in field position to change
247  UErrorCode status = U_ZERO_ERROR;
248  LocalPointer<CompactDecimalFormat> cdf(createCDFInstance("sw", UNUM_SHORT, status));
249  if (U_FAILURE(status)) {
250    dataerrln("Unable to create format object - %s", u_errorName(status));
251    return;
252  }
253  FieldPosition fp(UNUM_INTEGER_FIELD);
254  UnicodeString result;
255  cdf->format(1234567.0, result, fp);
256  UnicodeString subString = result.tempSubString(fp.getBeginIndex(), fp.getEndIndex() - fp.getBeginIndex());
257  if (subString != UnicodeString("1", -1, US_INV)) {
258    errln(UnicodeString("Expected 1, got ") + subString);
259  }
260}
261
262void CompactDecimalFormatTest::TestCsShort() {
263  CheckLocale("cs", UNUM_SHORT, kCsShort, UPRV_LENGTHOF(kCsShort));
264}
265
266void CompactDecimalFormatTest::TestSkLong() {
267  // In CLDR we have:
268  // 1000 {
269  //   few{"0"}
270  //   one{"0"}
271  //   other{"0"}
272  CheckLocale("sk", UNUM_LONG, kSkLong, UPRV_LENGTHOF(kSkLong));
273}
274
275void CompactDecimalFormatTest::TestSwahiliShortNegative() {
276  CheckLocale("sw", UNUM_SHORT, kSwahiliShortNegative, UPRV_LENGTHOF(kSwahiliShortNegative));
277}
278
279void CompactDecimalFormatTest::TestArabicLong() {
280  CheckLocale("ar", UNUM_LONG, kArabicLong, UPRV_LENGTHOF(kArabicLong));
281}
282
283void CompactDecimalFormatTest::TestSignificantDigits() {
284  UErrorCode status = U_ZERO_ERROR;
285  LocalPointer<CompactDecimalFormat> cdf(CompactDecimalFormat::createInstance("en", UNUM_SHORT, status));
286  if (U_FAILURE(status)) {
287    dataerrln("Unable to create format object - %s", u_errorName(status));
288    return;
289  }
290  UnicodeString actual;
291  cdf->format(123456.0, actual);
292  // We expect 3 significant digits by default
293  UnicodeString expected("123K", -1, US_INV);
294  if (actual != expected) {
295    errln(UnicodeString("Fail: Expected: ") + expected + UnicodeString(" Got: ") + actual);
296  }
297}
298
299void CompactDecimalFormatTest::TestAPIVariants() {
300  UErrorCode status = U_ZERO_ERROR;
301  LocalPointer<CompactDecimalFormat> cdf(CompactDecimalFormat::createInstance("en", UNUM_SHORT, status));
302  if (U_FAILURE(status)) {
303    dataerrln("Unable to create format object - %s", u_errorName(status));
304    return;
305  }
306  UnicodeString actual;
307  FieldPosition pos;
308  FieldPositionIterator posIter;
309  UnicodeString expected("123K", -1, US_INV);
310  pos.setField(UNUM_INTEGER_FIELD);
311
312  actual.remove();
313  pos.setBeginIndex(0);
314  pos.setEndIndex(0);
315  cdf->format((double)123456.0, actual, pos);
316  if (actual != expected || pos.getEndIndex() != 3) {
317    errln(UnicodeString("Fail format(double,UnicodeString&,FieldPosition&): Expected: \"") + expected + "\", pos 3; " +
318                                                                           "Got: \"" + actual + "\", pos " + pos.getEndIndex());
319  }
320
321  actual.remove();
322  pos.setBeginIndex(0);
323  pos.setEndIndex(0);
324  status = U_ZERO_ERROR;
325  cdf->format((double)123456.0, actual, pos, status);
326  if (actual != expected || pos.getEndIndex() != 3 || status != U_ZERO_ERROR) {
327    errln(UnicodeString("Fail format(double,UnicodeString&,FieldPosition&,UErrorCode&): Expected: \"") + expected + "\", pos 3, status U_ZERO_ERROR; " +
328                                                              "Got: \"" + actual + "\", pos " + pos.getEndIndex() + ", status " + u_errorName(status));
329  }
330
331  actual.remove();
332  status = U_ZERO_ERROR;
333  cdf->format((double)123456.0, actual, &posIter, status);
334  if (status != U_UNSUPPORTED_ERROR) {
335    errln(UnicodeString("Fail format(double,UnicodeString&,FieldPositionIterator*,UErrorCode&): Expected status U_UNSUPPORTED_ERROR;") +
336                                                              "Got status " + u_errorName(status));
337  }
338
339  actual.remove();
340  pos.setBeginIndex(0);
341  pos.setEndIndex(0);
342  cdf->format((int32_t)123456, actual, pos);
343  if (actual != expected || pos.getEndIndex() != 3) {
344    errln(UnicodeString("Fail format(int32_t,UnicodeString&,FieldPosition&): Expected: \"") + expected + "\", pos 3; " +
345                                                                           "Got: \"" + actual + "\", pos " + pos.getEndIndex());
346  }
347
348  actual.remove();
349  pos.setBeginIndex(0);
350  pos.setEndIndex(0);
351  status = U_ZERO_ERROR;
352  cdf->format((int32_t)123456, actual, pos, status);
353  if (actual != expected || pos.getEndIndex() != 3 || status != U_ZERO_ERROR) {
354    errln(UnicodeString("Fail format(int32_t,UnicodeString&,FieldPosition&,UErrorCode&): Expected: \"") + expected + "\", pos 3, status U_ZERO_ERROR; " +
355                                                              "Got: \"" + actual + "\", pos " + pos.getEndIndex() + ", status " + u_errorName(status));
356  }
357
358  actual.remove();
359  status = U_ZERO_ERROR;
360  cdf->format((int32_t)123456, actual, &posIter, status);
361  if (status != U_UNSUPPORTED_ERROR) {
362    errln(UnicodeString("Fail format(int32_t,UnicodeString&,FieldPositionIterator*,UErrorCode&): Expected status U_UNSUPPORTED_ERROR;") +
363                                                              "Got status " + u_errorName(status));
364  }
365
366  actual.remove();
367  pos.setBeginIndex(0);
368  pos.setEndIndex(0);
369  cdf->format((int64_t)123456, actual, pos);
370  if (actual != expected || pos.getEndIndex() != 3) {
371    errln(UnicodeString("Fail format(int64_t,UnicodeString&,FieldPosition&): Expected: \"") + expected + "\", pos 3; " +
372                                                                           "Got: \"" + actual + "\", pos " + pos.getEndIndex());
373  }
374
375  actual.remove();
376  pos.setBeginIndex(0);
377  pos.setEndIndex(0);
378  status = U_ZERO_ERROR;
379  cdf->format((int64_t)123456, actual, pos, status);
380  if (actual != expected || pos.getEndIndex() != 3 || status != U_ZERO_ERROR) {
381    errln(UnicodeString("Fail format(int64_t,UnicodeString&,FieldPosition&,UErrorCode&): Expected: \"") + expected + "\", pos 3, status U_ZERO_ERROR; " +
382                                                              "Got: \"" + actual + "\", pos " + pos.getEndIndex() + ", status " + u_errorName(status));
383  }
384
385  actual.remove();
386  status = U_ZERO_ERROR;
387  cdf->format((int64_t)123456, actual, &posIter, status);
388  if (status != U_UNSUPPORTED_ERROR) {
389    errln(UnicodeString("Fail format(int64_t,UnicodeString&,FieldPositionIterator*,UErrorCode&): Expected status U_UNSUPPORTED_ERROR;") +
390                                                              "Got status " + u_errorName(status));
391  }
392
393}
394
395void CompactDecimalFormatTest::CheckLocale(const Locale& locale, UNumberCompactStyle style, const ExpectedResult* expectedResults, int32_t expectedResultLength) {
396  UErrorCode status = U_ZERO_ERROR;
397  LocalPointer<CompactDecimalFormat> cdf(createCDFInstance(locale, style, status));
398  if (U_FAILURE(status)) {
399    dataerrln("Unable to create format object - %s", u_errorName(status));
400    return;
401  }
402  char description[256];
403  sprintf(description,"%s - %s", locale.getName(), StyleStr(style));
404  for (int32_t i = 0; i < expectedResultLength; i++) {
405    CheckExpectedResult(cdf.getAlias(), &expectedResults[i], description);
406  }
407}
408
409void CompactDecimalFormatTest::CheckExpectedResult(
410    const CompactDecimalFormat* cdf, const ExpectedResult* expectedResult, const char* description) {
411  UnicodeString actual;
412  cdf->format(expectedResult->value, actual);
413  UnicodeString expected(expectedResult->expected, -1, US_INV);
414  expected = expected.unescape();
415  if (actual != expected) {
416    errln(UnicodeString("Fail: Expected: ") + expected
417          + UnicodeString(" Got: ") + actual
418          + UnicodeString(" for: ") + UnicodeString(description));
419  }
420}
421
422CompactDecimalFormat*
423CompactDecimalFormatTest::createCDFInstance(const Locale& locale, UNumberCompactStyle style, UErrorCode& status) {
424  CompactDecimalFormat* result = CompactDecimalFormat::createInstance(locale, style, status);
425  if (U_FAILURE(status)) {
426    return NULL;
427  }
428  // All tests are written for two significant digits, so we explicitly set here
429  // in case default significant digits change.
430  result->setMaximumSignificantDigits(2);
431  return result;
432}
433
434const char *CompactDecimalFormatTest::StyleStr(UNumberCompactStyle style) {
435  if (style == UNUM_SHORT) {
436    return kShortStr;
437  }
438  return kLongStr;
439}
440
441extern IntlTest *createCompactDecimalFormatTest() {
442  return new CompactDecimalFormatTest();
443}
444
445#endif
446