void PluralRulesTest::checkSelect(const LocalPointer<PluralRules> &rules, UErrorCode &status, 
                                  int32_t line, const char *keyword, ...) {
    // The varargs parameters are a const char* strings, each being a decimal number.
    //   The formatting of the numbers as strings is significant, e.g.
    //     the difference between "2" and "2.0" can affect which rule matches (which keyword is selected).
    // Note: rules parameter is a LocalPointer reference rather than a PluralRules * to avoid having
    //       to write getAlias() at every (numerous) call site.

    if (U_FAILURE(status)) {
        errln("file %s, line %d, ICU error status: %s.", __FILE__, line, u_errorName(status));
        status = U_ZERO_ERROR;
        return;
    }

    if (rules == NULL) {
        errln("file %s, line %d: rules pointer is NULL", __FILE__, line);
        return;
    }
        
    va_list ap;
    va_start(ap, keyword);
    for (;;) {
        const char *num = va_arg(ap, const char *);
        if (strcmp(num, END_MARK) == 0) {
            break;
        }

        // DigitList is a convenient way to parse the decimal number string and get a double.
        DigitList  dl;
        dl.set(StringPiece(num), status);
        if (U_FAILURE(status)) {
            errln("file %s, line %d, ICU error status: %s.", __FILE__, line, u_errorName(status));
            status = U_ZERO_ERROR;
            continue;
        }
        double numDbl = dl.getDouble();
        const char *decimalPoint = strchr(num, '.');
        int fractionDigitCount = decimalPoint == NULL ? 0 : (num + strlen(num) - 1) - decimalPoint;
        int fractionDigits = fractionDigitCount == 0 ? 0 : atoi(decimalPoint + 1);
        FixedDecimal ni(numDbl, fractionDigitCount, fractionDigits);
        
        UnicodeString actualKeyword = rules->select(ni);
        if (actualKeyword != UnicodeString(keyword)) {
            errln("file %s, line %d, select(%s) returned incorrect keyword. Expected %s, got %s",
                   __FILE__, line, num, keyword, US(actualKeyword).cstr());
        }
    }
    va_end(ap);
}
UBool
FractionalPartSubstitution::doParse(const UnicodeString& text,
                ParsePosition& parsePosition,
                double baseValue,
                double /*upperBound*/,
                UBool lenientParse,
                Formattable& resVal) const
{
    // if we're not in byDigits mode, we can just use the inherited
    // doParse()
    if (!byDigits) {
        return NFSubstitution::doParse(text, parsePosition, baseValue, 0, lenientParse, resVal);

        // if we ARE in byDigits mode, parse the text one digit at a time
        // using this substitution's owning rule set (we do this by setting
        // upperBound to 10 when calling doParse() ) until we reach
        // nonmatching text
    } else {
        UnicodeString workText(text);
        ParsePosition workPos(1);
        double result = 0;
        int32_t digit;
//          double p10 = 0.1;

        DigitList dl;
        NumberFormat* fmt = NULL;
        while (workText.length() > 0 && workPos.getIndex() != 0) {
            workPos.setIndex(0);
            Formattable temp;
            getRuleSet()->parse(workText, workPos, 10, temp);
            UErrorCode status = U_ZERO_ERROR;
            digit = temp.getLong(status);
//            digit = temp.getType() == Formattable::kLong ?
//               temp.getLong() :
//            (int32_t)temp.getDouble();

            if (lenientParse && workPos.getIndex() == 0) {
                if (!fmt) {
                    status = U_ZERO_ERROR;
                    fmt = NumberFormat::createInstance(status);
                    if (U_FAILURE(status)) {
                        delete fmt;
                        fmt = NULL;
                    }
                }
                if (fmt) {
                    fmt->parse(workText, temp, workPos);
                    digit = temp.getLong(status);
                }
            }

            if (workPos.getIndex() != 0) {
                dl.append((char)('0' + digit));
//                  result += digit * p10;
//                  p10 /= 10;
                parsePosition.setIndex(parsePosition.getIndex() + workPos.getIndex());
                workText.removeBetween(0, workPos.getIndex());
                while (workText.length() > 0 && workText.charAt(0) == gSpace) {
                    workText.removeBetween(0, 1);
                    parsePosition.setIndex(parsePosition.getIndex() + 1);
                }
            }
        }
        delete fmt;

        result = dl.fCount == 0 ? 0 : dl.getDouble();
        result = composeRuleValue(result, baseValue);
        resVal.setDouble(result);
        return TRUE;
    }
}