Home | History | Annotate | Download | only in intltest
      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 */
    450