Imported Upstream version 58.1
[platform/upstream/icu.git] / source / test / intltest / numberformattesttuple.cpp
1 // Copyright (C) 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 *******************************************************************************
5 * Copyright (C) 2015, International Business Machines Corporation and         *
6 * others. All Rights Reserved.                                                *
7 *******************************************************************************
8 */
9
10 #include "numberformattesttuple.h"
11
12 #if !UCONFIG_NO_FORMATTING
13
14 #include "ustrfmt.h"
15 #include "charstr.h"
16 #include "cstring.h"
17 #include "cmemory.h"
18 #include "digitlst.h"
19
20 static NumberFormatTestTuple *gNullPtr = NULL;
21
22 #define FIELD_OFFSET(fieldName) ((int32_t) (((char *) &gNullPtr->fieldName) - ((char *) gNullPtr)))
23 #define FIELD_FLAG_OFFSET(fieldName) ((int32_t) (((char *) &gNullPtr->fieldName##Flag) - ((char *) gNullPtr)))
24
25 #define FIELD_INIT(fieldName, fieldType) {#fieldName, FIELD_OFFSET(fieldName), FIELD_FLAG_OFFSET(fieldName), fieldType}
26
27 struct Numberformattesttuple_EnumConversion {
28     const char *str;
29     int32_t value;
30 };
31
32 static Numberformattesttuple_EnumConversion gRoundingEnum[] = {
33     {"ceiling", DecimalFormat::kRoundCeiling},
34     {"floor", DecimalFormat::kRoundFloor},
35     {"down", DecimalFormat::kRoundDown},
36     {"up", DecimalFormat::kRoundUp},
37     {"halfEven", DecimalFormat::kRoundHalfEven},
38     {"halfDown", DecimalFormat::kRoundHalfDown},
39     {"halfUp", DecimalFormat::kRoundHalfUp},
40     {"unnecessary", DecimalFormat::kRoundUnnecessary}};
41
42 static Numberformattesttuple_EnumConversion gCurrencyUsageEnum[] = {
43     {"standard", UCURR_USAGE_STANDARD},
44     {"cash", UCURR_USAGE_CASH}};
45
46 static Numberformattesttuple_EnumConversion gPadPositionEnum[] = {
47     {"beforePrefix", DecimalFormat::kPadBeforePrefix},
48     {"afterPrefix", DecimalFormat::kPadAfterPrefix},
49     {"beforeSuffix", DecimalFormat::kPadBeforeSuffix},
50     {"afterSuffix", DecimalFormat::kPadAfterSuffix}};
51
52 static Numberformattesttuple_EnumConversion gFormatStyleEnum[] = {
53     {"patternDecimal", UNUM_PATTERN_DECIMAL},
54     {"decimal", UNUM_DECIMAL},
55     {"currency", UNUM_CURRENCY},
56     {"percent", UNUM_PERCENT},
57     {"scientific", UNUM_SCIENTIFIC},
58     {"spellout", UNUM_SPELLOUT},
59     {"ordinal", UNUM_ORDINAL},
60     {"duration", UNUM_DURATION},
61     {"numberingSystem", UNUM_NUMBERING_SYSTEM},
62     {"patternRuleBased", UNUM_PATTERN_RULEBASED},
63     {"currencyIso", UNUM_CURRENCY_ISO},
64     {"currencyPlural", UNUM_CURRENCY_PLURAL},
65     {"currencyAccounting", UNUM_CURRENCY_ACCOUNTING},
66     {"cashCurrency", UNUM_CASH_CURRENCY},
67     {"default", UNUM_DEFAULT},
68     {"ignore", UNUM_IGNORE}};
69
70 static int32_t toEnum(
71         const Numberformattesttuple_EnumConversion *table,
72         int32_t tableLength,
73         const UnicodeString &str,
74         UErrorCode &status) {
75     if (U_FAILURE(status)) {
76         return 0;
77     }
78     CharString cstr;
79     cstr.appendInvariantChars(str, status);
80     if (U_FAILURE(status)) {
81         return 0;
82     }
83     for (int32_t i = 0; i < tableLength; ++i) {
84         if (uprv_strcmp(cstr.data(), table[i].str) == 0) {
85             return table[i].value;
86         }
87     }
88     status = U_ILLEGAL_ARGUMENT_ERROR;
89     return 0;
90 }
91
92 static void fromEnum(
93         const Numberformattesttuple_EnumConversion *table,
94         int32_t tableLength,
95         int32_t val,
96         UnicodeString &appendTo) {
97     for (int32_t i = 0; i < tableLength; ++i) {
98         if (table[i].value == val) {
99             appendTo.append(table[i].str);
100         }
101     }
102 }
103
104 static void identVal(
105         const UnicodeString &str, void *strPtr, UErrorCode & /*status*/) {
106     *static_cast<UnicodeString *>(strPtr) = str;
107 }
108  
109 static void identStr(
110         const void *strPtr, UnicodeString &appendTo) {
111     appendTo.append(*static_cast<const UnicodeString *>(strPtr));
112 }
113
114 static void strToLocale(
115         const UnicodeString &str, void *localePtr, UErrorCode &status) {
116     if (U_FAILURE(status)) {
117         return;
118     }
119     CharString localeStr;
120     localeStr.appendInvariantChars(str, status);
121     *static_cast<Locale *>(localePtr) = Locale(localeStr.data());
122 }
123
124 static void localeToStr(
125         const void *localePtr, UnicodeString &appendTo) {
126     appendTo.append(
127             UnicodeString(
128                     static_cast<const Locale *>(localePtr)->getName()));
129 }
130
131 static void strToInt(
132         const UnicodeString &str, void *intPtr, UErrorCode &status) {
133     if (U_FAILURE(status)) {
134         return;
135     }
136     int32_t len = str.length();
137     int32_t start = 0;
138     UBool neg = FALSE;
139     if (len > 0 && str[0] == 0x2D) { // negative
140         neg = TRUE;
141         start = 1;
142     }
143     if (start == len) {
144         status = U_ILLEGAL_ARGUMENT_ERROR;
145         return;
146     }
147     int32_t value = 0;
148     for (int32_t i = start; i < len; ++i) {
149         UChar ch = str[i];
150         if (ch < 0x30 || ch > 0x39) {
151             status = U_ILLEGAL_ARGUMENT_ERROR;
152             return;
153         }
154         value = value * 10 - 0x30 + (int32_t) ch;
155     }
156     if (neg) {
157         value = -value;
158     }
159     *static_cast<int32_t *>(intPtr) = value;
160 }
161
162 static void intToStr(
163         const void *intPtr, UnicodeString &appendTo) {
164     UChar buffer[20];
165     int32_t x = *static_cast<const int32_t *>(intPtr);
166     UBool neg = FALSE;
167     if (x < 0) {
168         neg = TRUE;
169         x = -x;
170     }
171     if (neg) {
172         appendTo.append((UChar)0x2D);
173     }
174     int32_t len = uprv_itou(buffer, UPRV_LENGTHOF(buffer), (uint32_t) x, 10, 1);
175     appendTo.append(buffer, 0, len);
176 }
177
178 static void strToDouble(
179         const UnicodeString &str, void *doublePtr, UErrorCode &status) {
180     if (U_FAILURE(status)) {
181         return;
182     }
183     CharString buffer;
184     buffer.appendInvariantChars(str, status);
185     if (U_FAILURE(status)) {
186         return;
187     }
188     *static_cast<double *>(doublePtr) = atof(buffer.data());
189 }
190
191 static void doubleToStr(
192         const void *doublePtr, UnicodeString &appendTo) {
193     char buffer[256];
194     double x = *static_cast<const double *>(doublePtr);
195     sprintf(buffer, "%f", x);
196     appendTo.append(buffer);
197 }
198
199 static void strToERounding(
200         const UnicodeString &str, void *roundPtr, UErrorCode &status) {
201     int32_t val = toEnum(
202             gRoundingEnum, UPRV_LENGTHOF(gRoundingEnum), str, status);
203     *static_cast<DecimalFormat::ERoundingMode *>(roundPtr) = (DecimalFormat::ERoundingMode) val;
204 }
205
206 static void eRoundingToStr(
207         const void *roundPtr, UnicodeString &appendTo) {
208     DecimalFormat::ERoundingMode rounding = 
209             *static_cast<const DecimalFormat::ERoundingMode *>(roundPtr);
210     fromEnum(
211             gRoundingEnum,
212             UPRV_LENGTHOF(gRoundingEnum),
213             rounding,
214             appendTo);
215 }
216
217 static void strToCurrencyUsage(
218         const UnicodeString &str, void *currencyUsagePtr, UErrorCode &status) {
219     int32_t val = toEnum(
220             gCurrencyUsageEnum, UPRV_LENGTHOF(gCurrencyUsageEnum), str, status);
221     *static_cast<UCurrencyUsage *>(currencyUsagePtr) = (UCurrencyUsage) val;
222 }
223
224 static void currencyUsageToStr(
225         const void *currencyUsagePtr, UnicodeString &appendTo) {
226     UCurrencyUsage currencyUsage = 
227             *static_cast<const UCurrencyUsage *>(currencyUsagePtr);
228     fromEnum(
229             gCurrencyUsageEnum,
230             UPRV_LENGTHOF(gCurrencyUsageEnum),
231             currencyUsage,
232             appendTo);
233 }
234
235 static void strToEPadPosition(
236         const UnicodeString &str, void *padPositionPtr, UErrorCode &status) {
237     int32_t val = toEnum(
238             gPadPositionEnum, UPRV_LENGTHOF(gPadPositionEnum), str, status);
239     *static_cast<DecimalFormat::EPadPosition *>(padPositionPtr) =
240             (DecimalFormat::EPadPosition) val;
241 }
242
243 static void ePadPositionToStr(
244         const void *padPositionPtr, UnicodeString &appendTo) {
245     DecimalFormat::EPadPosition padPosition = 
246             *static_cast<const DecimalFormat::EPadPosition *>(padPositionPtr);
247     fromEnum(
248             gPadPositionEnum,
249             UPRV_LENGTHOF(gPadPositionEnum),
250             padPosition,
251             appendTo);
252 }
253
254 static void strToFormatStyle(
255         const UnicodeString &str, void *formatStylePtr, UErrorCode &status) {
256     int32_t val = toEnum(
257             gFormatStyleEnum, UPRV_LENGTHOF(gFormatStyleEnum), str, status);
258     *static_cast<UNumberFormatStyle *>(formatStylePtr) = (UNumberFormatStyle) val;
259 }
260
261 static void formatStyleToStr(
262         const void *formatStylePtr, UnicodeString &appendTo) {
263     UNumberFormatStyle formatStyle = 
264             *static_cast<const UNumberFormatStyle *>(formatStylePtr);
265     fromEnum(
266             gFormatStyleEnum,
267             UPRV_LENGTHOF(gFormatStyleEnum),
268             formatStyle,
269             appendTo);
270 }
271
272 struct NumberFormatTestTupleFieldOps {
273     void (*toValue)(const UnicodeString &str, void *valPtr, UErrorCode &);
274     void (*toString)(const void *valPtr, UnicodeString &appendTo);
275 };
276
277 const NumberFormatTestTupleFieldOps gStrOps = {identVal, identStr};
278 const NumberFormatTestTupleFieldOps gIntOps = {strToInt, intToStr};
279 const NumberFormatTestTupleFieldOps gLocaleOps = {strToLocale, localeToStr};
280 const NumberFormatTestTupleFieldOps gDoubleOps = {strToDouble, doubleToStr};
281 const NumberFormatTestTupleFieldOps gERoundingOps = {strToERounding, eRoundingToStr};
282 const NumberFormatTestTupleFieldOps gCurrencyUsageOps = {strToCurrencyUsage, currencyUsageToStr};
283 const NumberFormatTestTupleFieldOps gEPadPositionOps = {strToEPadPosition, ePadPositionToStr};
284 const NumberFormatTestTupleFieldOps gFormatStyleOps = {strToFormatStyle, formatStyleToStr};
285
286 struct NumberFormatTestTupleFieldData {
287     const char *name;
288     int32_t offset;
289     int32_t flagOffset;
290     const NumberFormatTestTupleFieldOps *ops;
291 };
292
293 // Order must correspond to ENumberFormatTestTupleField
294 const NumberFormatTestTupleFieldData gFieldData[] = {
295     FIELD_INIT(locale, &gLocaleOps),
296     FIELD_INIT(currency, &gStrOps),
297     FIELD_INIT(pattern, &gStrOps),
298     FIELD_INIT(format, &gStrOps),
299     FIELD_INIT(output, &gStrOps),
300     FIELD_INIT(comment, &gStrOps),
301     FIELD_INIT(minIntegerDigits, &gIntOps),
302     FIELD_INIT(maxIntegerDigits, &gIntOps),
303     FIELD_INIT(minFractionDigits, &gIntOps),
304     FIELD_INIT(maxFractionDigits, &gIntOps),
305     FIELD_INIT(minGroupingDigits, &gIntOps),
306     FIELD_INIT(breaks, &gStrOps),
307     FIELD_INIT(useSigDigits, &gIntOps),
308     FIELD_INIT(minSigDigits, &gIntOps),
309     FIELD_INIT(maxSigDigits, &gIntOps),
310     FIELD_INIT(useGrouping, &gIntOps),
311     FIELD_INIT(multiplier, &gIntOps),
312     FIELD_INIT(roundingIncrement, &gDoubleOps),
313     FIELD_INIT(formatWidth, &gIntOps),
314     FIELD_INIT(padCharacter, &gStrOps),
315     FIELD_INIT(useScientific, &gIntOps),
316     FIELD_INIT(grouping, &gIntOps),
317     FIELD_INIT(grouping2, &gIntOps),
318     FIELD_INIT(roundingMode, &gERoundingOps),
319     FIELD_INIT(currencyUsage, &gCurrencyUsageOps),
320     FIELD_INIT(minimumExponentDigits, &gIntOps),
321     FIELD_INIT(exponentSignAlwaysShown, &gIntOps),
322     FIELD_INIT(decimalSeparatorAlwaysShown, &gIntOps),
323     FIELD_INIT(padPosition, &gEPadPositionOps),
324     FIELD_INIT(positivePrefix, &gStrOps),
325     FIELD_INIT(positiveSuffix, &gStrOps),
326     FIELD_INIT(negativePrefix, &gStrOps),
327     FIELD_INIT(negativeSuffix, &gStrOps),
328     FIELD_INIT(localizedPattern, &gStrOps),
329     FIELD_INIT(toPattern, &gStrOps),
330     FIELD_INIT(toLocalizedPattern, &gStrOps),
331     FIELD_INIT(style, &gFormatStyleOps),
332     FIELD_INIT(parse, &gStrOps),
333     FIELD_INIT(lenient, &gIntOps),
334     FIELD_INIT(plural, &gStrOps),
335     FIELD_INIT(parseIntegerOnly, &gIntOps),
336     FIELD_INIT(decimalPatternMatchRequired, &gIntOps),
337     FIELD_INIT(parseNoExponent, &gIntOps),
338     FIELD_INIT(outputCurrency, &gStrOps)
339 };
340
341 UBool
342 NumberFormatTestTuple::setField(
343         ENumberFormatTestTupleField fieldId, 
344         const UnicodeString &fieldValue,
345         UErrorCode &status) {
346     if (U_FAILURE(status)) {
347         return FALSE;
348     }
349     if (fieldId == kNumberFormatTestTupleFieldCount) {
350         status = U_ILLEGAL_ARGUMENT_ERROR;
351         return FALSE;
352     }
353     gFieldData[fieldId].ops->toValue(
354             fieldValue, getMutableFieldAddress(fieldId), status);
355     if (U_FAILURE(status)) {
356         return FALSE;
357     }
358     setFlag(fieldId, TRUE);
359     return TRUE;
360 }
361
362 UBool
363 NumberFormatTestTuple::clearField(
364         ENumberFormatTestTupleField fieldId, 
365         UErrorCode &status) {
366     if (U_FAILURE(status)) {
367         return FALSE;
368     }
369     if (fieldId == kNumberFormatTestTupleFieldCount) {
370         status = U_ILLEGAL_ARGUMENT_ERROR;
371         return FALSE;
372     }
373     setFlag(fieldId, FALSE);
374     return TRUE;
375 }
376
377 void
378 NumberFormatTestTuple::clear() {
379     for (int32_t i = 0; i < kNumberFormatTestTupleFieldCount; ++i) {
380         setFlag(i, FALSE);
381     }
382 }
383
384 UnicodeString &
385 NumberFormatTestTuple::toString(
386         UnicodeString &appendTo) const {
387     appendTo.append("{");
388     UBool first = TRUE;
389     for (int32_t i = 0; i < kNumberFormatTestTupleFieldCount; ++i) {
390         if (!isFlag(i)) {
391             continue;
392         }
393         if (!first) {
394             appendTo.append(", ");
395         }
396         first = FALSE;
397         appendTo.append(gFieldData[i].name);
398         appendTo.append(": ");
399         gFieldData[i].ops->toString(getFieldAddress(i), appendTo);
400     }
401     appendTo.append("}");
402     return appendTo;
403 }
404
405 ENumberFormatTestTupleField
406 NumberFormatTestTuple::getFieldByName(
407         const UnicodeString &name) {
408     CharString buffer;
409     UErrorCode status = U_ZERO_ERROR;
410     buffer.appendInvariantChars(name, status);
411     if (U_FAILURE(status)) {
412         return kNumberFormatTestTupleFieldCount;
413     }
414     int32_t result = -1;
415     for (int32_t i = 0; i < UPRV_LENGTHOF(gFieldData); ++i) {
416         if (uprv_strcmp(gFieldData[i].name, buffer.data()) == 0) {
417             result = i;
418             break;
419         }
420     }
421     if (result == -1) {
422         return kNumberFormatTestTupleFieldCount;
423     }
424     return (ENumberFormatTestTupleField) result;
425 }
426
427 const void *
428 NumberFormatTestTuple::getFieldAddress(int32_t fieldId) const {
429     return reinterpret_cast<const char *>(this) + gFieldData[fieldId].offset;
430 }
431
432 void *
433 NumberFormatTestTuple::getMutableFieldAddress(int32_t fieldId) {
434     return reinterpret_cast<char *>(this) + gFieldData[fieldId].offset;
435 }
436
437 void 
438 NumberFormatTestTuple::setFlag(int32_t fieldId, UBool value) {
439     void *flagAddr = reinterpret_cast<char *>(this) + gFieldData[fieldId].flagOffset;
440     *static_cast<UBool *>(flagAddr) = value;
441 }
442
443 UBool
444 NumberFormatTestTuple::isFlag(int32_t fieldId) const {
445     const void *flagAddr = reinterpret_cast<const char *>(this) + gFieldData[fieldId].flagOffset;
446     return *static_cast<const UBool *>(flagAddr);
447 }
448
449 #endif /* !UCONFIG_NO_FORMATTING */