Ejemplo n.º 1
0
StandardPlural::Form QuantityFormatter::selectPlural(
            const Formattable &number,
            const NumberFormat &fmt,
            const PluralRules &rules,
            UnicodeString &formattedNumber,
            FieldPosition &pos,
            UErrorCode &status) {
    if (U_FAILURE(status)) {
        return StandardPlural::OTHER;
    }
    UnicodeString pluralKeyword;
    const DecimalFormat *decFmt = dynamic_cast<const DecimalFormat *>(&fmt);
    if (decFmt != NULL) {
        number::impl::DecimalQuantity dq;
        decFmt->formatToDecimalQuantity(number, dq, status);
        if (U_FAILURE(status)) {
            return StandardPlural::OTHER;
        }
        pluralKeyword = rules.select(dq);
        decFmt->format(number, formattedNumber, pos, status);
    } else {
        if (number.getType() == Formattable::kDouble) {
            pluralKeyword = rules.select(number.getDouble());
        } else if (number.getType() == Formattable::kLong) {
            pluralKeyword = rules.select(number.getLong());
        } else if (number.getType() == Formattable::kInt64) {
            pluralKeyword = rules.select((double) number.getInt64());
        } else {
            status = U_ILLEGAL_ARGUMENT_ERROR;
            return StandardPlural::OTHER;
        }
        fmt.format(number, formattedNumber, pos, status);
    }
    return StandardPlural::orOtherFromString(pluralKeyword);
}
void PluralRulesTest::testGetSamples() {
  // TODO: fix samples, re-enable this test.

  // no get functional equivalent API in ICU4C, so just
  // test every locale...
  UErrorCode status = U_ZERO_ERROR;
  int32_t numLocales;
  const Locale* locales = Locale::getAvailableLocales(numLocales);

  double values[1000];
  for (int32_t i = 0; U_SUCCESS(status) && i < numLocales; ++i) {
    PluralRules *rules = PluralRules::forLocale(locales[i], status);
    if (U_FAILURE(status)) {
      break;
    }
    StringEnumeration *keywords = rules->getKeywords(status);
    if (U_FAILURE(status)) {
      delete rules;
      break;
    }
    const UnicodeString* keyword;
    while (NULL != (keyword = keywords->snext(status))) {
      int32_t count = rules->getSamples(*keyword, values, LENGTHOF(values), status);
      if (U_FAILURE(status)) {
        errln(UNICODE_STRING_SIMPLE("getSamples() failed for locale ") +
              locales[i].getName() +
              UNICODE_STRING_SIMPLE(", keyword ") + *keyword);
        continue;
      }
      if (count == 0) {
        // TODO: Lots of these. 
        //   errln(UNICODE_STRING_SIMPLE("no samples for keyword ") + *keyword + UNICODE_STRING_SIMPLE(" in locale ") + locales[i].getName() );
      }
      if (count > LENGTHOF(values)) {
        errln(UNICODE_STRING_SIMPLE("getSamples()=") + count +
              UNICODE_STRING_SIMPLE(", too many values, for locale ") +
              locales[i].getName() +
              UNICODE_STRING_SIMPLE(", keyword ") + *keyword);
        count = LENGTHOF(values);
      }
      for (int32_t j = 0; j < count; ++j) {
        if (values[j] == UPLRULES_NO_UNIQUE_VALUE) {
          errln("got 'no unique value' among values");
        } else {
          UnicodeString resultKeyword = rules->select(values[j]);
          // if (strcmp(locales[i].getName(), "uk") == 0) {    // Debug only.
          //     std::cout << "  uk " << US(resultKeyword).cstr() << " " << values[j] << std::endl;
          // }
          if (*keyword != resultKeyword) {
            errln("file %s, line %d, Locale %s, sample for keyword \"%s\":  %g, select(%g) returns keyword \"%s\"",
                __FILE__, __LINE__, locales[i].getName(), US(*keyword).cstr(), values[j], values[j], US(resultKeyword).cstr());
          }
        }
      }
    }
    delete keywords;
    delete rules;
  }
}
void
PluralRulesTest::assertRuleKeyValue(const UnicodeString& rule,
                                    const UnicodeString& key, double expected) {
  UErrorCode status = U_ZERO_ERROR;
  PluralRules *pr = PluralRules::createRules(rule, status);
  double result = pr->getUniqueKeywordValue(key);
  delete pr;
  if (expected != result) {
    errln("expected %g but got %g", expected, result);
  }
}
Ejemplo n.º 4
0
UBool
PluralRules::operator==(const PluralRules& other) const  {
    int32_t limit;
    const UnicodeString *ptrKeyword;
    UErrorCode status= U_ZERO_ERROR;

    if ( this == &other ) {
        return TRUE;
    }
    LocalPointer<StringEnumeration> myKeywordList(getKeywords(status));
    LocalPointer<StringEnumeration> otherKeywordList(other.getKeywords(status));
    if (U_FAILURE(status)) {
        return FALSE;
    }

    if (myKeywordList->count(status)!=otherKeywordList->count(status)) {
        return FALSE;
    }
    myKeywordList->reset(status);
    while ((ptrKeyword=myKeywordList->snext(status))!=NULL) {
        if (!other.isKeyword(*ptrKeyword)) {
            return FALSE;
        }
    }
    otherKeywordList->reset(status);
    while ((ptrKeyword=otherKeywordList->snext(status))!=NULL) {
        if (!this->isKeyword(*ptrKeyword)) {
            return FALSE;
        }
    }
    if (U_FAILURE(status)) {
        return FALSE;
    }

    if ((limit=this->getRepeatLimit()) != other.getRepeatLimit()) {
        return FALSE;
    }
    UnicodeString myKeyword, otherKeyword;
    for (int32_t i=0; i<limit; ++i) {
        myKeyword = this->select(i);
        otherKeyword = other.select(i);
        if (myKeyword!=otherKeyword) {
            return FALSE;
        }
    }
    return TRUE;
}
UBool checkEqual(const PluralRules &test, char *result, int32_t max) {
    UnicodeString key;
    UBool isEqual = TRUE;
    for (int32_t i=0; i<max; ++i) {
        key= test.select(i);
        if ( key.charAt(0)!=result[i] ) {
            isEqual = FALSE;
        }
    }
    return isEqual;
}
Ejemplo n.º 6
0
PluralRules* U_EXPORT2
PluralRules::forLocale(const Locale& locale, UPluralType type, UErrorCode& status) {
    RuleChain   rChain;
    if (U_FAILURE(status)) {
        return NULL;
    }
    if (type >= UPLURAL_TYPE_COUNT) {
        status = U_ILLEGAL_ARGUMENT_ERROR;
        return NULL;
    }
    PluralRules *newObj = new PluralRules(status);
    if (newObj==NULL || U_FAILURE(status)) {
        delete newObj;
        return NULL;
    }
    UnicodeString locRule = newObj->getRuleFromResource(locale, type, status);
    if ((locRule.length() != 0) && U_SUCCESS(status)) {
        newObj->parseDescription(locRule, rChain, status);
        if (U_SUCCESS(status)) {
            newObj->addRules(rChain);
        }
    }
    if (U_FAILURE(status)||(locRule.length() == 0)) {
        // use default plural rule
        status = U_ZERO_ERROR;
        UnicodeString defRule = UnicodeString(PLURAL_DEFAULT_RULE);
        newObj->parseDescription(defRule, rChain, status);
        newObj->addRules(rChain);
    }

    return newObj;
}
Ejemplo n.º 7
0
PluralRules* U_EXPORT2
PluralRules::createRules(const UnicodeString& description, UErrorCode& status) {
    RuleChain   rules;

    if (U_FAILURE(status)) {
        return NULL;
    }
    PluralRules *newRules = new PluralRules(status);
    if ( (newRules != NULL)&& U_SUCCESS(status) ) {
        newRules->parseDescription((UnicodeString &)description, rules, status);
        if (U_SUCCESS(status)) {
            newRules->addRules(rules);
        }
    }
    if (U_FAILURE(status)) {
        delete newRules;
        return NULL;
    }
    else {
        return newRules;
    }
}
void PluralRulesTest::testWithin() {
  // goes to show you what lack of testing will do.
  // of course, this has been broken for two years and no one has noticed...
  UErrorCode status = U_ZERO_ERROR;
  PluralRules *rules = PluralRules::createRules("a: n mod 10 in 5..8", status);
  if (!rules) {
    errln("couldn't instantiate rules");
    return;
  }

  UnicodeString keyword = rules->select((int32_t)26);
  if (keyword != "a") {
    errln("expected 'a' for 26 but didn't get it.");
  }

  keyword = rules->select(26.5);
  if (keyword != "other") {
    errln("expected 'other' for 26.5 but didn't get it.");
  }

  delete rules;
}
Ejemplo n.º 9
0
ECode CResources::GetQuantityText(
    /* [in] */ Int32 id,
    /* [in] */ Int32 quantity,
    /* [out] */ ICharSequence** csq)
{
    if (!csq) {
        return E_INVALID_ARGUMENT;
    }

    PluralRules* rule = GetPluralRule();
    mAssets->GetResourceBagText(id, rule->AttrForNumber(quantity), csq);
    if (*csq != NULL) {
        return NOERROR;
    }
    mAssets->GetResourceBagText(id, PluralRules::ID_OTHER, csq);
    if (*csq != NULL) {
        return NOERROR;
    }

    Logger::E(TAG, StringBuffer("Plural resource ID #0x") + id
        + " quantity=" + quantity
        + " item=" + PluralRules::StringForQuantity(rule->QuantityForNumber(quantity)));
    return E_NOT_FOUND_EXCEPTION;
}
UBool testEquality(const PluralRules &test) {
    UnicodeString testEquRules[MAX_EQ_ROW][MAX_EQ_COL] = {
        {   UNICODE_STRING_SIMPLE("a: n in 2..3"),
            UNICODE_STRING_SIMPLE("a: n is 2 or n is 3"),
            UNICODE_STRING_SIMPLE( "a:n is 3 and n in 2..5 or n is 2"),
            "",
        },
        {   UNICODE_STRING_SIMPLE("a: n is 12; b:n mod 10 in 2..3"),
            UNICODE_STRING_SIMPLE("b: n mod 10 in 2..3 and n is not 12; a: n in 12..12"),
            UNICODE_STRING_SIMPLE("b: n is 13; a: n in 12..13; b: n mod 10 is 2 or n mod 10 is 3"),
            "",
        }
    };
    UErrorCode status = U_ZERO_ERROR;
    UnicodeString key[MAX_EQ_COL];
    UBool ret=TRUE;
    for (int32_t i=0; i<MAX_EQ_ROW; ++i) {
        PluralRules* rules[MAX_EQ_COL];

        for (int32_t j=0; j<MAX_EQ_COL; ++j) {
            rules[j]=NULL;
        }
        int32_t totalRules=0;
        while((totalRules<MAX_EQ_COL) && (testEquRules[i][totalRules].length()>0) ) {
            rules[totalRules]=test.createRules(testEquRules[i][totalRules], status);
            totalRules++;
        }
        for (int32_t n=0; n<300 && ret ; ++n) {
            for(int32_t j=0; j<totalRules;++j) {
                key[j] = rules[j]->select(n);
            }
            for(int32_t j=0; j<totalRules-1;++j) {
                if (key[j]!=key[j+1]) {
                    ret= FALSE;
                    break;
                }
            }

        }
        for (int32_t j=0; j<MAX_EQ_COL; ++j) {
            if (rules[j]!=NULL) {
                delete rules[j];
            }
        }
    }

    return ret;
}
void PluralRulesTest::testAvailbleLocales() {
    
    // Hash set of (char *) strings.
    UErrorCode status = U_ZERO_ERROR;
    UHashtable *localeSet = uhash_open(uhash_hashUnicodeString, uhash_compareUnicodeString, uhash_compareLong, &status);
    uhash_setKeyDeleter(localeSet, uprv_deleteUObject);
    if (U_FAILURE(status)) {
        errln("file %s,  line %d: Error status = %s", __FILE__, __LINE__, u_errorName(status));
        return;
    }

    // Check that each locale returned by the iterator is unique.
    StringEnumeration *localesEnum = PluralRules::getAvailableLocales(status);
    int localeCount = 0;
    for (;;) {
        const char *locale = localesEnum->next(NULL, status);
        if (U_FAILURE(status)) {
            dataerrln("file %s,  line %d: Error status = %s", __FILE__, __LINE__, u_errorName(status));
            return;
        }
        if (locale == NULL) {
            break;
        }
        localeCount++;
        int32_t oldVal = uhash_puti(localeSet, new UnicodeString(locale), 1, &status);
        if (oldVal != 0) {
            errln("file %s,  line %d: locale %s was seen before.", __FILE__, __LINE__, locale);
        }
    }

    // Reset the iterator, verify that we get the same count.
    localesEnum->reset(status);
    int32_t localeCount2 = 0;
    while (localesEnum->next(NULL, status) != NULL) {
        if (U_FAILURE(status)) {
            errln("file %s,  line %d: Error status = %s", __FILE__, __LINE__, u_errorName(status));
            break;
        }
        localeCount2++;
    }
    if (localeCount != localeCount2) {
        errln("file %s,  line %d: locale counts differ. They are (%d, %d)", 
            __FILE__, __LINE__, localeCount, localeCount2);
    }

    // Instantiate plural rules for each available locale.
    localesEnum->reset(status);
    for (;;) {
        status = U_ZERO_ERROR;
        const char *localeName = localesEnum->next(NULL, status);
        if (U_FAILURE(status)) {
            errln("file %s,  line %d: Error status = %s, locale = %s",
                __FILE__, __LINE__, u_errorName(status), localeName);
            return;
        }
        if (localeName == NULL) {
            break;
        }
        Locale locale = Locale::createFromName(localeName);
        PluralRules *pr = PluralRules::forLocale(locale, status);
        if (U_FAILURE(status)) {
            errln("file %s,  line %d: Error %s creating plural rules for locale %s", 
                __FILE__, __LINE__, u_errorName(status), localeName);
            continue;
        }
        if (pr == NULL) {
            errln("file %s, line %d: Null plural rules for locale %s", __FILE__, __LINE__, localeName);
            continue;
        }

        // Pump some numbers through the plural rules.  Can't check for correct results, 
        // mostly this to tickle any asserts or crashes that may be lurking.
        for (double n=0; n<120.0; n+=0.5) {
            UnicodeString keyword = pr->select(n);
            if (keyword.length() == 0) {
                errln("file %s, line %d, empty keyword for n = %g, locale %s",
                    __FILE__, __LINE__, n, localeName);
            }
        }
        delete pr;
    }

    uhash_close(localeSet);
    delete localesEnum;

}
void
PluralRulesTest::testGetAllKeywordValues() {
    const char* data[] = {
        "a: n in 2..5", "a: 2,3,4,5; other: null; b:",
        "a: n not in 2..5", "a: null; other: null",
        "a: n within 2..5", "a: null; other: null",
        "a: n not within 2..5", "a: null; other: null",
        "a: n in 2..5 or n within 6..8", "a: null", // ignore 'other' here on out, always null
        "a: n in 2..5 and n within 6..8", "a:",
        "a: n in 2..5 and n within 5..8", "a: 5",
        "a: n within 2..5 and n within 6..8", "a:", // our sampling catches these
        "a: n within 2..5 and n within 5..8", "a: 5", // ''
        "a: n within 1..2 and n within 2..3 or n within 3..4 and n within 4..5", "a: 2,4",
        "a: n within 1..2 and n within 2..3 or n within 3..4 and n within 4..5 "
          "or n within 5..6 and n within 6..7", "a: null", // but not this...
        "a: n mod 3 is 0", "a: null",
        "a: n mod 3 is 0 and n within 1..2", "a:",
        "a: n mod 3 is 0 and n within 0..5", "a: 0,3",
        "a: n mod 3 is 0 and n within 0..6", "a: null", // similarly with mod, we don't catch...
        "a: n mod 3 is 0 and n in 3..12", "a: 3,6,9,12",
        NULL
    };

    for (int i = 0; data[i] != NULL; i += 2) {
        UErrorCode status = U_ZERO_ERROR;
        UnicodeString ruleDescription(data[i], -1, US_INV);
        const char* result = data[i+1];

        logln("[%d] %s", i >> 1, data[i]);

        PluralRules *p = PluralRules::createRules(ruleDescription, status);
        if (p == NULL || U_FAILURE(status)) {
            errln("file %s, line %d: could not create rules from '%s'\n"
                  "  ErrorCode: %s\n", 
                  __FILE__, __LINE__, data[i], u_errorName(status));
            continue;
        }

        // TODO: fix samples implementation, re-enable test.
        (void)result;
        #if 0

        const char* rp = result;
        while (*rp) {
            while (*rp == ' ') ++rp;
            if (!rp) {
                break;
            }

            const char* ep = rp;
            while (*ep && *ep != ':') ++ep;

            status = U_ZERO_ERROR;
            UnicodeString keyword(rp, ep - rp, US_INV);
            double samples[4]; // no test above should have more samples than 4
            int32_t count = p->getAllKeywordValues(keyword, &samples[0], 4, status);
            if (U_FAILURE(status)) {
                errln("error getting samples for %s", rp);
                break;
            }

            if (count > 4) {
              errln("count > 4 for keyword %s", rp);
              count = 4;
            }

            if (*ep) {
                ++ep; // skip colon
                while (*ep && *ep == ' ') ++ep; // and spaces
            }

            UBool ok = TRUE;
            if (count == -1) {
                if (*ep != 'n') {
                    errln("expected values for keyword %s but got -1 (%s)", rp, ep);
                    ok = FALSE;
                }
            } else if (*ep == 'n') {
                errln("expected count of -1, got %d, for keyword %s (%s)", count, rp, ep);
                ok = FALSE;
            }

            // We'll cheat a bit here.  The samples happend to be in order and so are our
            // expected values, so we'll just test in order until a failure.  If the
            // implementation changes to return samples in an arbitrary order, this test
            // must change.  There's no actual restriction on the order of the samples.

            for (int j = 0; ok && j < count; ++j ) { // we've verified count < 4
                double val = samples[j];
                if (*ep == 0 || *ep == ';') {
                    errln("got unexpected value[%d]: %g", j, val);
                    ok = FALSE;
                    break;
                }
                char* xp;
                double expectedVal = strtod(ep, &xp);
                if (xp == ep) {
                    // internal error
                    errln("yikes!");
                    ok = FALSE;
                    break;
                }
                ep = xp;
                if (expectedVal != val) {
                    errln("expected %g but got %g", expectedVal, val);
                    ok = FALSE;
                    break;
                }
                if (*ep == ',') ++ep;
            }

            if (ok && count != -1) {
                if (!(*ep == 0 || *ep == ';')) {
                    errln("file: %s, line %d, didn't get expected value: %s", __FILE__, __LINE__, ep);
                    ok = FALSE;
                }
            }

            while (*ep && *ep != ';') ++ep;
            if (*ep == ';') ++ep;
            rp = ep;
        }
    #endif
    delete p;
    }
}