| Index: source/test/intltest/numberformattesttuple.cpp
 | 
| diff --git a/source/test/intltest/numberformattesttuple.cpp b/source/test/intltest/numberformattesttuple.cpp
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..366b893c67ac7a228ae68c40203501f047dbfa77
 | 
| --- /dev/null
 | 
| +++ b/source/test/intltest/numberformattesttuple.cpp
 | 
| @@ -0,0 +1,447 @@
 | 
| +/*
 | 
| +*******************************************************************************
 | 
| +* Copyright (C) 2015, International Business Machines Corporation and         *
 | 
| +* others. All Rights Reserved.                                                *
 | 
| +*******************************************************************************
 | 
| +*/
 | 
| +
 | 
| +#include "numberformattesttuple.h"
 | 
| +
 | 
| +#if !UCONFIG_NO_FORMATTING
 | 
| +
 | 
| +#include "ustrfmt.h"
 | 
| +#include "charstr.h"
 | 
| +#include "cstring.h"
 | 
| +#include "cmemory.h"
 | 
| +#include "digitlst.h"
 | 
| +
 | 
| +static NumberFormatTestTuple *gNullPtr = NULL;
 | 
| +
 | 
| +#define FIELD_OFFSET(fieldName) ((int32_t) (((char *) &gNullPtr->fieldName) - ((char *) gNullPtr)))
 | 
| +#define FIELD_FLAG_OFFSET(fieldName) ((int32_t) (((char *) &gNullPtr->fieldName##Flag) - ((char *) gNullPtr)))
 | 
| +
 | 
| +#define FIELD_INIT(fieldName, fieldType) {#fieldName, FIELD_OFFSET(fieldName), FIELD_FLAG_OFFSET(fieldName), fieldType}
 | 
| +
 | 
| +struct Numberformattesttuple_EnumConversion {
 | 
| +    const char *str;
 | 
| +    int32_t value;
 | 
| +};
 | 
| +
 | 
| +static Numberformattesttuple_EnumConversion gRoundingEnum[] = {
 | 
| +    {"ceiling", DecimalFormat::kRoundCeiling},
 | 
| +    {"floor", DecimalFormat::kRoundFloor},
 | 
| +    {"down", DecimalFormat::kRoundDown},
 | 
| +    {"up", DecimalFormat::kRoundUp},
 | 
| +    {"halfEven", DecimalFormat::kRoundHalfEven},
 | 
| +    {"halfDown", DecimalFormat::kRoundHalfDown},
 | 
| +    {"halfUp", DecimalFormat::kRoundHalfUp},
 | 
| +    {"unnecessary", DecimalFormat::kRoundUnnecessary}};
 | 
| +
 | 
| +static Numberformattesttuple_EnumConversion gCurrencyUsageEnum[] = {
 | 
| +    {"standard", UCURR_USAGE_STANDARD},
 | 
| +    {"cash", UCURR_USAGE_CASH}};
 | 
| +
 | 
| +static Numberformattesttuple_EnumConversion gPadPositionEnum[] = {
 | 
| +    {"beforePrefix", DecimalFormat::kPadBeforePrefix},
 | 
| +    {"afterPrefix", DecimalFormat::kPadAfterPrefix},
 | 
| +    {"beforeSuffix", DecimalFormat::kPadBeforeSuffix},
 | 
| +    {"afterSuffix", DecimalFormat::kPadAfterSuffix}};
 | 
| +
 | 
| +static Numberformattesttuple_EnumConversion gFormatStyleEnum[] = {
 | 
| +    {"patternDecimal", UNUM_PATTERN_DECIMAL},
 | 
| +    {"decimal", UNUM_DECIMAL},
 | 
| +    {"currency", UNUM_CURRENCY},
 | 
| +    {"percent", UNUM_PERCENT},
 | 
| +    {"scientific", UNUM_SCIENTIFIC},
 | 
| +    {"spellout", UNUM_SPELLOUT},
 | 
| +    {"ordinal", UNUM_ORDINAL},
 | 
| +    {"duration", UNUM_DURATION},
 | 
| +    {"numberingSystem", UNUM_NUMBERING_SYSTEM},
 | 
| +    {"patternRuleBased", UNUM_PATTERN_RULEBASED},
 | 
| +    {"currencyIso", UNUM_CURRENCY_ISO},
 | 
| +    {"currencyPlural", UNUM_CURRENCY_PLURAL},
 | 
| +    {"currencyAccounting", UNUM_CURRENCY_ACCOUNTING},
 | 
| +    {"cashCurrency", UNUM_CASH_CURRENCY},
 | 
| +    {"default", UNUM_DEFAULT},
 | 
| +    {"ignore", UNUM_IGNORE}};
 | 
| +
 | 
| +static int32_t toEnum(
 | 
| +        const Numberformattesttuple_EnumConversion *table,
 | 
| +        int32_t tableLength,
 | 
| +        const UnicodeString &str,
 | 
| +        UErrorCode &status) {
 | 
| +    if (U_FAILURE(status)) {
 | 
| +        return 0;
 | 
| +    }
 | 
| +    CharString cstr;
 | 
| +    cstr.appendInvariantChars(str, status);
 | 
| +    if (U_FAILURE(status)) {
 | 
| +        return 0;
 | 
| +    }
 | 
| +    for (int32_t i = 0; i < tableLength; ++i) {
 | 
| +        if (uprv_strcmp(cstr.data(), table[i].str) == 0) {
 | 
| +            return table[i].value;
 | 
| +        }
 | 
| +    }
 | 
| +    status = U_ILLEGAL_ARGUMENT_ERROR;
 | 
| +    return 0;
 | 
| +}
 | 
| +
 | 
| +static void fromEnum(
 | 
| +        const Numberformattesttuple_EnumConversion *table,
 | 
| +        int32_t tableLength,
 | 
| +        int32_t val,
 | 
| +        UnicodeString &appendTo) {
 | 
| +    for (int32_t i = 0; i < tableLength; ++i) {
 | 
| +        if (table[i].value == val) {
 | 
| +            appendTo.append(table[i].str);
 | 
| +        }
 | 
| +    }
 | 
| +}
 | 
| +
 | 
| +static void identVal(
 | 
| +        const UnicodeString &str, void *strPtr, UErrorCode & /*status*/) {
 | 
| +    *static_cast<UnicodeString *>(strPtr) = str;
 | 
| +}
 | 
| + 
 | 
| +static void identStr(
 | 
| +        const void *strPtr, UnicodeString &appendTo) {
 | 
| +    appendTo.append(*static_cast<const UnicodeString *>(strPtr));
 | 
| +}
 | 
| +
 | 
| +static void strToLocale(
 | 
| +        const UnicodeString &str, void *localePtr, UErrorCode &status) {
 | 
| +    if (U_FAILURE(status)) {
 | 
| +        return;
 | 
| +    }
 | 
| +    CharString localeStr;
 | 
| +    localeStr.appendInvariantChars(str, status);
 | 
| +    *static_cast<Locale *>(localePtr) = Locale(localeStr.data());
 | 
| +}
 | 
| +
 | 
| +static void localeToStr(
 | 
| +        const void *localePtr, UnicodeString &appendTo) {
 | 
| +    appendTo.append(
 | 
| +            UnicodeString(
 | 
| +                    static_cast<const Locale *>(localePtr)->getName()));
 | 
| +}
 | 
| +
 | 
| +static void strToInt(
 | 
| +        const UnicodeString &str, void *intPtr, UErrorCode &status) {
 | 
| +    if (U_FAILURE(status)) {
 | 
| +        return;
 | 
| +    }
 | 
| +    int32_t len = str.length();
 | 
| +    int32_t start = 0;
 | 
| +    UBool neg = FALSE;
 | 
| +    if (len > 0 && str[0] == 0x2D) { // negative
 | 
| +        neg = TRUE;
 | 
| +        start = 1;
 | 
| +    }
 | 
| +    if (start == len) {
 | 
| +        status = U_ILLEGAL_ARGUMENT_ERROR;
 | 
| +        return;
 | 
| +    }
 | 
| +    int32_t value = 0;
 | 
| +    for (int32_t i = start; i < len; ++i) {
 | 
| +        UChar ch = str[i];
 | 
| +        if (ch < 0x30 || ch > 0x39) {
 | 
| +            status = U_ILLEGAL_ARGUMENT_ERROR;
 | 
| +            return;
 | 
| +        }
 | 
| +        value = value * 10 - 0x30 + (int32_t) ch;
 | 
| +    }
 | 
| +    if (neg) {
 | 
| +        value = -value;
 | 
| +    }
 | 
| +    *static_cast<int32_t *>(intPtr) = value;
 | 
| +}
 | 
| +
 | 
| +static void intToStr(
 | 
| +        const void *intPtr, UnicodeString &appendTo) {
 | 
| +    UChar buffer[20];
 | 
| +    int32_t x = *static_cast<const int32_t *>(intPtr);
 | 
| +    UBool neg = FALSE;
 | 
| +    if (x < 0) {
 | 
| +        neg = TRUE;
 | 
| +        x = -x;
 | 
| +    }
 | 
| +    if (neg) {
 | 
| +        appendTo.append(0x2D);
 | 
| +    }
 | 
| +    int32_t len = uprv_itou(buffer, UPRV_LENGTHOF(buffer), (uint32_t) x, 10, 1);
 | 
| +    appendTo.append(buffer, 0, len);
 | 
| +}
 | 
| +
 | 
| +static void strToDouble(
 | 
| +        const UnicodeString &str, void *doublePtr, UErrorCode &status) {
 | 
| +    if (U_FAILURE(status)) {
 | 
| +        return;
 | 
| +    }
 | 
| +    CharString buffer;
 | 
| +    buffer.appendInvariantChars(str, status);
 | 
| +    if (U_FAILURE(status)) {
 | 
| +        return;
 | 
| +    }
 | 
| +    *static_cast<double *>(doublePtr) = atof(buffer.data());
 | 
| +}
 | 
| +
 | 
| +static void doubleToStr(
 | 
| +        const void *doublePtr, UnicodeString &appendTo) {
 | 
| +    char buffer[256];
 | 
| +    double x = *static_cast<const double *>(doublePtr);
 | 
| +    sprintf(buffer, "%f", x);
 | 
| +    appendTo.append(buffer);
 | 
| +}
 | 
| +
 | 
| +static void strToERounding(
 | 
| +        const UnicodeString &str, void *roundPtr, UErrorCode &status) {
 | 
| +    int32_t val = toEnum(
 | 
| +            gRoundingEnum, UPRV_LENGTHOF(gRoundingEnum), str, status);
 | 
| +    *static_cast<DecimalFormat::ERoundingMode *>(roundPtr) = (DecimalFormat::ERoundingMode) val;
 | 
| +}
 | 
| +
 | 
| +static void eRoundingToStr(
 | 
| +        const void *roundPtr, UnicodeString &appendTo) {
 | 
| +    DecimalFormat::ERoundingMode rounding = 
 | 
| +            *static_cast<const DecimalFormat::ERoundingMode *>(roundPtr);
 | 
| +    fromEnum(
 | 
| +            gRoundingEnum,
 | 
| +            UPRV_LENGTHOF(gRoundingEnum),
 | 
| +            rounding,
 | 
| +            appendTo);
 | 
| +}
 | 
| +
 | 
| +static void strToCurrencyUsage(
 | 
| +        const UnicodeString &str, void *currencyUsagePtr, UErrorCode &status) {
 | 
| +    int32_t val = toEnum(
 | 
| +            gCurrencyUsageEnum, UPRV_LENGTHOF(gCurrencyUsageEnum), str, status);
 | 
| +    *static_cast<UCurrencyUsage *>(currencyUsagePtr) = (UCurrencyUsage) val;
 | 
| +}
 | 
| +
 | 
| +static void currencyUsageToStr(
 | 
| +        const void *currencyUsagePtr, UnicodeString &appendTo) {
 | 
| +    UCurrencyUsage currencyUsage = 
 | 
| +            *static_cast<const UCurrencyUsage *>(currencyUsagePtr);
 | 
| +    fromEnum(
 | 
| +            gCurrencyUsageEnum,
 | 
| +            UPRV_LENGTHOF(gCurrencyUsageEnum),
 | 
| +            currencyUsage,
 | 
| +            appendTo);
 | 
| +}
 | 
| +
 | 
| +static void strToEPadPosition(
 | 
| +        const UnicodeString &str, void *padPositionPtr, UErrorCode &status) {
 | 
| +    int32_t val = toEnum(
 | 
| +            gPadPositionEnum, UPRV_LENGTHOF(gPadPositionEnum), str, status);
 | 
| +    *static_cast<DecimalFormat::EPadPosition *>(padPositionPtr) =
 | 
| +            (DecimalFormat::EPadPosition) val;
 | 
| +}
 | 
| +
 | 
| +static void ePadPositionToStr(
 | 
| +        const void *padPositionPtr, UnicodeString &appendTo) {
 | 
| +    DecimalFormat::EPadPosition padPosition = 
 | 
| +            *static_cast<const DecimalFormat::EPadPosition *>(padPositionPtr);
 | 
| +    fromEnum(
 | 
| +            gPadPositionEnum,
 | 
| +            UPRV_LENGTHOF(gPadPositionEnum),
 | 
| +            padPosition,
 | 
| +            appendTo);
 | 
| +}
 | 
| +
 | 
| +static void strToFormatStyle(
 | 
| +        const UnicodeString &str, void *formatStylePtr, UErrorCode &status) {
 | 
| +    int32_t val = toEnum(
 | 
| +            gFormatStyleEnum, UPRV_LENGTHOF(gFormatStyleEnum), str, status);
 | 
| +    *static_cast<UNumberFormatStyle *>(formatStylePtr) = (UNumberFormatStyle) val;
 | 
| +}
 | 
| +
 | 
| +static void formatStyleToStr(
 | 
| +        const void *formatStylePtr, UnicodeString &appendTo) {
 | 
| +    UNumberFormatStyle formatStyle = 
 | 
| +            *static_cast<const UNumberFormatStyle *>(formatStylePtr);
 | 
| +    fromEnum(
 | 
| +            gFormatStyleEnum,
 | 
| +            UPRV_LENGTHOF(gFormatStyleEnum),
 | 
| +            formatStyle,
 | 
| +            appendTo);
 | 
| +}
 | 
| +
 | 
| +struct NumberFormatTestTupleFieldOps {
 | 
| +    void (*toValue)(const UnicodeString &str, void *valPtr, UErrorCode &);
 | 
| +    void (*toString)(const void *valPtr, UnicodeString &appendTo);
 | 
| +};
 | 
| +
 | 
| +const NumberFormatTestTupleFieldOps gStrOps = {identVal, identStr};
 | 
| +const NumberFormatTestTupleFieldOps gIntOps = {strToInt, intToStr};
 | 
| +const NumberFormatTestTupleFieldOps gLocaleOps = {strToLocale, localeToStr};
 | 
| +const NumberFormatTestTupleFieldOps gDoubleOps = {strToDouble, doubleToStr};
 | 
| +const NumberFormatTestTupleFieldOps gERoundingOps = {strToERounding, eRoundingToStr};
 | 
| +const NumberFormatTestTupleFieldOps gCurrencyUsageOps = {strToCurrencyUsage, currencyUsageToStr};
 | 
| +const NumberFormatTestTupleFieldOps gEPadPositionOps = {strToEPadPosition, ePadPositionToStr};
 | 
| +const NumberFormatTestTupleFieldOps gFormatStyleOps = {strToFormatStyle, formatStyleToStr};
 | 
| +
 | 
| +struct NumberFormatTestTupleFieldData {
 | 
| +    const char *name;
 | 
| +    int32_t offset;
 | 
| +    int32_t flagOffset;
 | 
| +    const NumberFormatTestTupleFieldOps *ops;
 | 
| +};
 | 
| +
 | 
| +// Order must correspond to ENumberFormatTestTupleField
 | 
| +const NumberFormatTestTupleFieldData gFieldData[] = {
 | 
| +    FIELD_INIT(locale, &gLocaleOps),
 | 
| +    FIELD_INIT(currency, &gStrOps),
 | 
| +    FIELD_INIT(pattern, &gStrOps),
 | 
| +    FIELD_INIT(format, &gStrOps),
 | 
| +    FIELD_INIT(output, &gStrOps),
 | 
| +    FIELD_INIT(comment, &gStrOps),
 | 
| +    FIELD_INIT(minIntegerDigits, &gIntOps),
 | 
| +    FIELD_INIT(maxIntegerDigits, &gIntOps),
 | 
| +    FIELD_INIT(minFractionDigits, &gIntOps),
 | 
| +    FIELD_INIT(maxFractionDigits, &gIntOps),
 | 
| +    FIELD_INIT(minGroupingDigits, &gIntOps),
 | 
| +    FIELD_INIT(breaks, &gStrOps),
 | 
| +    FIELD_INIT(useSigDigits, &gIntOps),
 | 
| +    FIELD_INIT(minSigDigits, &gIntOps),
 | 
| +    FIELD_INIT(maxSigDigits, &gIntOps),
 | 
| +    FIELD_INIT(useGrouping, &gIntOps),
 | 
| +    FIELD_INIT(multiplier, &gIntOps),
 | 
| +    FIELD_INIT(roundingIncrement, &gDoubleOps),
 | 
| +    FIELD_INIT(formatWidth, &gIntOps),
 | 
| +    FIELD_INIT(padCharacter, &gStrOps),
 | 
| +    FIELD_INIT(useScientific, &gIntOps),
 | 
| +    FIELD_INIT(grouping, &gIntOps),
 | 
| +    FIELD_INIT(grouping2, &gIntOps),
 | 
| +    FIELD_INIT(roundingMode, &gERoundingOps),
 | 
| +    FIELD_INIT(currencyUsage, &gCurrencyUsageOps),
 | 
| +    FIELD_INIT(minimumExponentDigits, &gIntOps),
 | 
| +    FIELD_INIT(exponentSignAlwaysShown, &gIntOps),
 | 
| +    FIELD_INIT(decimalSeparatorAlwaysShown, &gIntOps),
 | 
| +    FIELD_INIT(padPosition, &gEPadPositionOps),
 | 
| +    FIELD_INIT(positivePrefix, &gStrOps),
 | 
| +    FIELD_INIT(positiveSuffix, &gStrOps),
 | 
| +    FIELD_INIT(negativePrefix, &gStrOps),
 | 
| +    FIELD_INIT(negativeSuffix, &gStrOps),
 | 
| +    FIELD_INIT(localizedPattern, &gStrOps),
 | 
| +    FIELD_INIT(toPattern, &gStrOps),
 | 
| +    FIELD_INIT(toLocalizedPattern, &gStrOps),
 | 
| +    FIELD_INIT(style, &gFormatStyleOps),
 | 
| +    FIELD_INIT(parse, &gStrOps),
 | 
| +    FIELD_INIT(lenient, &gIntOps),
 | 
| +    FIELD_INIT(plural, &gStrOps),
 | 
| +    FIELD_INIT(parseIntegerOnly, &gIntOps),
 | 
| +    FIELD_INIT(decimalPatternMatchRequired, &gIntOps),
 | 
| +    FIELD_INIT(parseNoExponent, &gIntOps),
 | 
| +    FIELD_INIT(outputCurrency, &gStrOps)
 | 
| +};
 | 
| +
 | 
| +UBool
 | 
| +NumberFormatTestTuple::setField(
 | 
| +        ENumberFormatTestTupleField fieldId, 
 | 
| +        const UnicodeString &fieldValue,
 | 
| +        UErrorCode &status) {
 | 
| +    if (U_FAILURE(status)) {
 | 
| +        return FALSE;
 | 
| +    }
 | 
| +    if (fieldId == kNumberFormatTestTupleFieldCount) {
 | 
| +        status = U_ILLEGAL_ARGUMENT_ERROR;
 | 
| +        return FALSE;
 | 
| +    }
 | 
| +    gFieldData[fieldId].ops->toValue(
 | 
| +            fieldValue, getMutableFieldAddress(fieldId), status);
 | 
| +    if (U_FAILURE(status)) {
 | 
| +        return FALSE;
 | 
| +    }
 | 
| +    setFlag(fieldId, TRUE);
 | 
| +    return TRUE;
 | 
| +}
 | 
| +
 | 
| +UBool
 | 
| +NumberFormatTestTuple::clearField(
 | 
| +        ENumberFormatTestTupleField fieldId, 
 | 
| +        UErrorCode &status) {
 | 
| +    if (U_FAILURE(status)) {
 | 
| +        return FALSE;
 | 
| +    }
 | 
| +    if (fieldId == kNumberFormatTestTupleFieldCount) {
 | 
| +        status = U_ILLEGAL_ARGUMENT_ERROR;
 | 
| +        return FALSE;
 | 
| +    }
 | 
| +    setFlag(fieldId, FALSE);
 | 
| +    return TRUE;
 | 
| +}
 | 
| +
 | 
| +void
 | 
| +NumberFormatTestTuple::clear() {
 | 
| +    for (int32_t i = 0; i < kNumberFormatTestTupleFieldCount; ++i) {
 | 
| +        setFlag(i, FALSE);
 | 
| +    }
 | 
| +}
 | 
| +
 | 
| +UnicodeString &
 | 
| +NumberFormatTestTuple::toString(
 | 
| +        UnicodeString &appendTo) const {
 | 
| +    appendTo.append("{");
 | 
| +    UBool first = TRUE;
 | 
| +    for (int32_t i = 0; i < kNumberFormatTestTupleFieldCount; ++i) {
 | 
| +        if (!isFlag(i)) {
 | 
| +            continue;
 | 
| +        }
 | 
| +        if (!first) {
 | 
| +            appendTo.append(", ");
 | 
| +        }
 | 
| +        first = FALSE;
 | 
| +        appendTo.append(gFieldData[i].name);
 | 
| +        appendTo.append(": ");
 | 
| +        gFieldData[i].ops->toString(getFieldAddress(i), appendTo);
 | 
| +    }
 | 
| +    appendTo.append("}");
 | 
| +    return appendTo;
 | 
| +}
 | 
| +
 | 
| +ENumberFormatTestTupleField
 | 
| +NumberFormatTestTuple::getFieldByName(
 | 
| +        const UnicodeString &name) {
 | 
| +    CharString buffer;
 | 
| +    UErrorCode status = U_ZERO_ERROR;
 | 
| +    buffer.appendInvariantChars(name, status);
 | 
| +    if (U_FAILURE(status)) {
 | 
| +        return kNumberFormatTestTupleFieldCount;
 | 
| +    }
 | 
| +    int32_t result = -1;
 | 
| +    for (int32_t i = 0; i < UPRV_LENGTHOF(gFieldData); ++i) {
 | 
| +        if (uprv_strcmp(gFieldData[i].name, buffer.data()) == 0) {
 | 
| +            result = i;
 | 
| +            break;
 | 
| +        }
 | 
| +    }
 | 
| +    if (result == -1) {
 | 
| +        return kNumberFormatTestTupleFieldCount;
 | 
| +    }
 | 
| +    return (ENumberFormatTestTupleField) result;
 | 
| +}
 | 
| +
 | 
| +const void *
 | 
| +NumberFormatTestTuple::getFieldAddress(int32_t fieldId) const {
 | 
| +    return reinterpret_cast<const char *>(this) + gFieldData[fieldId].offset;
 | 
| +}
 | 
| +
 | 
| +void *
 | 
| +NumberFormatTestTuple::getMutableFieldAddress(int32_t fieldId) {
 | 
| +    return reinterpret_cast<char *>(this) + gFieldData[fieldId].offset;
 | 
| +}
 | 
| +
 | 
| +void 
 | 
| +NumberFormatTestTuple::setFlag(int32_t fieldId, UBool value) {
 | 
| +    void *flagAddr = reinterpret_cast<char *>(this) + gFieldData[fieldId].flagOffset;
 | 
| +    *static_cast<UBool *>(flagAddr) = value;
 | 
| +}
 | 
| +
 | 
| +UBool
 | 
| +NumberFormatTestTuple::isFlag(int32_t fieldId) const {
 | 
| +    const void *flagAddr = reinterpret_cast<const char *>(this) + gFieldData[fieldId].flagOffset;
 | 
| +    return *static_cast<const UBool *>(flagAddr);
 | 
| +}
 | 
| +
 | 
| +#endif /* !UCONFIG_NO_FORMATTING */
 | 
| 
 |