You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
354 lines
12 KiB
354 lines
12 KiB
// © 2016 and later: Unicode, Inc. and others.
|
|
// License & terms of use: http://www.unicode.org/copyright.html
|
|
/********************************************************************
|
|
* Copyright (c) 2011-2014, International Business Machines Corporation
|
|
* and others. All Rights Reserved.
|
|
********************************************************************/
|
|
/* C API TEST FOR PLURAL RULES */
|
|
|
|
#include "unicode/utypes.h"
|
|
|
|
#if !UCONFIG_NO_FORMATTING
|
|
|
|
#include "unicode/upluralrules.h"
|
|
#include "unicode/ustring.h"
|
|
#include "unicode/uenum.h"
|
|
#include "unicode/unumberformatter.h"
|
|
#include "unicode/unumberrangeformatter.h"
|
|
#include "cintltst.h"
|
|
#include "cmemory.h"
|
|
#include "cstring.h"
|
|
|
|
static void TestPluralRules(void);
|
|
static void TestOrdinalRules(void);
|
|
static void TestGetKeywords(void);
|
|
static void TestFormatted(void);
|
|
static void TestSelectRange(void);
|
|
|
|
void addPluralRulesTest(TestNode** root);
|
|
|
|
#define TESTCASE(x) addTest(root, &x, "tsformat/cpluralrulestest/" #x)
|
|
|
|
void addPluralRulesTest(TestNode** root)
|
|
{
|
|
TESTCASE(TestPluralRules);
|
|
TESTCASE(TestOrdinalRules);
|
|
TESTCASE(TestGetKeywords);
|
|
TESTCASE(TestFormatted);
|
|
TESTCASE(TestSelectRange);
|
|
}
|
|
|
|
typedef struct {
|
|
const char * locale;
|
|
double number;
|
|
const char * keywordExpected;
|
|
const char * keywordExpectedForDecimals;
|
|
} PluralRulesTestItem;
|
|
|
|
/* Just a small set of tests for now, other functionality is tested in the C++ tests */
|
|
static const PluralRulesTestItem testItems[] = {
|
|
{ "en", 0, "other", "other" },
|
|
{ "en", 0.5, "other", "other" },
|
|
{ "en", 1, "one", "other" },
|
|
{ "en", 1.5, "other", "other" },
|
|
{ "en", 2, "other", "other" },
|
|
{ "fr", 0, "one", "one" },
|
|
{ "fr", 0.5, "one", "one" },
|
|
{ "fr", 1, "one", "one" },
|
|
{ "fr", 1.5, "one", "one" },
|
|
{ "fr", 2, "other", "other" },
|
|
{ "ru", 0, "many", "other" },
|
|
{ "ru", 0.5, "other", "other" },
|
|
{ "ru", 1, "one", "other" },
|
|
{ "ru", 1.5, "other", "other" },
|
|
{ "ru", 2, "few", "other" },
|
|
{ "ru", 5, "many", "other" },
|
|
{ "ru", 10, "many", "other" },
|
|
{ "ru", 11, "many", "other" },
|
|
{ NULL, 0, NULL, NULL }
|
|
};
|
|
|
|
static const UChar twoDecimalPat[] = { 0x23,0x30,0x2E,0x30,0x30,0 }; /* "#0.00" */
|
|
|
|
enum {
|
|
kKeywordBufLen = 32
|
|
};
|
|
|
|
static void TestPluralRules()
|
|
{
|
|
const PluralRulesTestItem * testItemPtr;
|
|
log_verbose("\nTesting uplrules_open() and uplrules_select() with various parameters\n");
|
|
for ( testItemPtr = testItems; testItemPtr->locale != NULL; ++testItemPtr ) {
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
UPluralRules* uplrules = uplrules_open(testItemPtr->locale, &status);
|
|
if ( U_SUCCESS(status) ) {
|
|
UNumberFormat* unumfmt;
|
|
UChar keyword[kKeywordBufLen];
|
|
UChar keywordExpected[kKeywordBufLen];
|
|
int32_t keywdLen = uplrules_select(uplrules, testItemPtr->number, keyword, kKeywordBufLen, &status);
|
|
if (keywdLen >= kKeywordBufLen) {
|
|
keyword[kKeywordBufLen-1] = 0;
|
|
}
|
|
if ( U_SUCCESS(status) ) {
|
|
u_unescape(testItemPtr->keywordExpected, keywordExpected, kKeywordBufLen);
|
|
if ( u_strcmp(keyword, keywordExpected) != 0 ) {
|
|
char bcharBuf[kKeywordBufLen];
|
|
log_data_err("ERROR: uplrules_select for locale %s, number %.1f: expect %s, get %s\n",
|
|
testItemPtr->locale, testItemPtr->number, testItemPtr->keywordExpected, u_austrcpy(bcharBuf,keyword) );
|
|
}
|
|
} else {
|
|
log_err("FAIL: uplrules_select for locale %s, number %.1f: %s\n",
|
|
testItemPtr->locale, testItemPtr->number, myErrorName(status) );
|
|
}
|
|
|
|
status = U_ZERO_ERROR;
|
|
unumfmt = unum_open(UNUM_PATTERN_DECIMAL, twoDecimalPat, -1, testItemPtr->locale, NULL, &status);
|
|
if ( U_SUCCESS(status) ) {
|
|
keywdLen = uplrules_selectWithFormat(uplrules, testItemPtr->number, unumfmt, keyword, kKeywordBufLen, &status);
|
|
if (keywdLen >= kKeywordBufLen) {
|
|
keyword[kKeywordBufLen-1] = 0;
|
|
}
|
|
if ( U_SUCCESS(status) ) {
|
|
u_unescape(testItemPtr->keywordExpectedForDecimals, keywordExpected, kKeywordBufLen);
|
|
if ( u_strcmp(keyword, keywordExpected) != 0 ) {
|
|
char bcharBuf[kKeywordBufLen];
|
|
log_data_err("ERROR: uplrules_selectWithFormat for locale %s, number %.1f: expect %s, get %s\n",
|
|
testItemPtr->locale, testItemPtr->number, testItemPtr->keywordExpectedForDecimals, u_austrcpy(bcharBuf,keyword) );
|
|
}
|
|
} else {
|
|
log_err("FAIL: uplrules_selectWithFormat for locale %s, number %.1f: %s\n",
|
|
testItemPtr->locale, testItemPtr->number, myErrorName(status) );
|
|
}
|
|
unum_close(unumfmt);
|
|
} else {
|
|
log_err("FAIL: unum_open for locale %s: %s\n", testItemPtr->locale, myErrorName(status) );
|
|
}
|
|
|
|
uplrules_close(uplrules);
|
|
} else {
|
|
log_err("FAIL: uplrules_open for locale %s: %s\n", testItemPtr->locale, myErrorName(status) );
|
|
}
|
|
}
|
|
}
|
|
|
|
static void TestOrdinalRules() {
|
|
U_STRING_DECL(two, "two", 3);
|
|
UChar keyword[8];
|
|
int32_t length;
|
|
UErrorCode errorCode = U_ZERO_ERROR;
|
|
UPluralRules* upr = uplrules_openForType("en", UPLURAL_TYPE_ORDINAL, &errorCode);
|
|
if (U_FAILURE(errorCode)) {
|
|
log_err("uplrules_openForType(en, ordinal) failed - %s\n", u_errorName(errorCode));
|
|
return;
|
|
}
|
|
U_STRING_INIT(two, "two", 3);
|
|
length = uplrules_select(upr, 2., keyword, 8, &errorCode);
|
|
if (U_FAILURE(errorCode) || u_strCompare(keyword, length, two, 3, FALSE) != 0) {
|
|
log_data_err("uplrules_select(en-ordinal, 2) failed - %s\n", u_errorName(errorCode));
|
|
}
|
|
uplrules_close(upr);
|
|
}
|
|
|
|
/* items for TestGetKeywords */
|
|
|
|
/* all possible plural keywords, in alphabetical order */
|
|
static const char* knownKeywords[] = {
|
|
"few",
|
|
"many",
|
|
"one",
|
|
"other",
|
|
"two",
|
|
"zero"
|
|
};
|
|
enum {
|
|
kNumKeywords = UPRV_LENGTHOF(knownKeywords)
|
|
};
|
|
|
|
/* Return the index of keyword in knownKeywords[], or -1 if not found */
|
|
static int32_t getKeywordIndex(const char* keyword) {
|
|
int32_t i, compare;
|
|
for (i = 0; i < kNumKeywords && (compare = uprv_strcmp(keyword,knownKeywords[i])) >= 0; i++) {
|
|
if (compare == 0) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
typedef struct {
|
|
const char* locale;
|
|
const char* keywords[kNumKeywords + 1];
|
|
} KeywordsForLang;
|
|
|
|
static const KeywordsForLang getKeywordsItems[] = {
|
|
{ "zh", { "other" } },
|
|
{ "en", { "one", "other" } },
|
|
{ "fr", { "one", "many", "other" } },
|
|
{ "lv", { "zero", "one", "other" } },
|
|
{ "hr", { "one", "few", "other" } },
|
|
{ "sl", { "one", "two", "few", "other" } },
|
|
{ "he", { "one", "two", "many", "other" } },
|
|
{ "cs", { "one", "few", "many", "other" } },
|
|
{ "ar", { "zero", "one", "two", "few", "many" , "other" } },
|
|
{ NULL, { NULL } }
|
|
};
|
|
|
|
static void TestGetKeywords() {
|
|
/*
|
|
* We don't know the order in which the enumeration will return keywords,
|
|
* so we have an array with known keywords in a fixed order and then
|
|
* parallel arrays of flags for expected and actual results that indicate
|
|
* which keywords are expected to be or actually are found.
|
|
*/
|
|
const KeywordsForLang* itemPtr = getKeywordsItems;
|
|
for (; itemPtr->locale != NULL; itemPtr++) {
|
|
UPluralRules* uplrules;
|
|
UEnumeration* uenum;
|
|
UBool expectKeywords[kNumKeywords];
|
|
UBool getKeywords[kNumKeywords];
|
|
int32_t i, iKnown;
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
|
|
/* initialize arrays for expected and get results */
|
|
for (i = 0; i < kNumKeywords; i++) {
|
|
expectKeywords[i] = FALSE;
|
|
getKeywords[i] = FALSE;
|
|
}
|
|
for (i = 0; i < kNumKeywords && itemPtr->keywords[i] != NULL; i++) {
|
|
iKnown = getKeywordIndex(itemPtr->keywords[i]);
|
|
if (iKnown >= 0) {
|
|
expectKeywords[iKnown] = TRUE;
|
|
}
|
|
}
|
|
|
|
uplrules = uplrules_openForType(itemPtr->locale, UPLURAL_TYPE_CARDINAL, &status);
|
|
if (U_FAILURE(status)) {
|
|
log_err("FAIL: uplrules_openForType for locale %s, UPLURAL_TYPE_CARDINAL: %s\n", itemPtr->locale, myErrorName(status) );
|
|
continue;
|
|
}
|
|
uenum = uplrules_getKeywords(uplrules, &status);
|
|
if (U_FAILURE(status)) {
|
|
log_err("FAIL: uplrules_getKeywords for locale %s: %s\n", itemPtr->locale, myErrorName(status) );
|
|
} else {
|
|
const char* keyword;
|
|
int32_t keywordLen, keywordCount = 0;
|
|
while ((keyword = uenum_next(uenum, &keywordLen, &status)) != NULL && U_SUCCESS(status)) {
|
|
iKnown = getKeywordIndex(keyword);
|
|
if (iKnown < 0) {
|
|
log_err("FAIL: uplrules_getKeywords for locale %s, unknown keyword %s\n", itemPtr->locale, keyword );
|
|
} else {
|
|
getKeywords[iKnown] = TRUE;
|
|
}
|
|
keywordCount++;
|
|
}
|
|
if (keywordCount > kNumKeywords) {
|
|
log_err("FAIL: uplrules_getKeywords for locale %s, got too many keywords %d\n", itemPtr->locale, keywordCount );
|
|
}
|
|
if (uprv_memcmp(expectKeywords, getKeywords, kNumKeywords) != 0) {
|
|
log_err("FAIL: uplrules_getKeywords for locale %s, got wrong keyword set; with reference to knownKeywords:\n"
|
|
" expected { %d %d %d %d %d %d },\n"
|
|
" got { %d %d %d %d %d %d }\n", itemPtr->locale,
|
|
expectKeywords[0], expectKeywords[1], expectKeywords[2], expectKeywords[3], expectKeywords[4], expectKeywords[5],
|
|
getKeywords[0], getKeywords[1], getKeywords[2], getKeywords[3], getKeywords[4], getKeywords[5] );
|
|
}
|
|
uenum_close(uenum);
|
|
}
|
|
|
|
uplrules_close(uplrules);
|
|
}
|
|
}
|
|
|
|
static void TestFormatted() {
|
|
UErrorCode ec = U_ZERO_ERROR;
|
|
UNumberFormatter* unumf = NULL;
|
|
UFormattedNumber* uresult = NULL;
|
|
UPluralRules* uplrules = NULL;
|
|
|
|
uplrules = uplrules_open("hr", &ec);
|
|
if (!assertSuccess("open plural rules", &ec)) {
|
|
goto cleanup;
|
|
}
|
|
|
|
unumf = unumf_openForSkeletonAndLocale(u".00", -1, "hr", &ec);
|
|
if (!assertSuccess("open unumf", &ec)) {
|
|
goto cleanup;
|
|
}
|
|
|
|
uresult = unumf_openResult(&ec);
|
|
if (!assertSuccess("open result", &ec)) {
|
|
goto cleanup;
|
|
}
|
|
|
|
unumf_formatDouble(unumf, 100.2, uresult, &ec);
|
|
if (!assertSuccess("format", &ec)) {
|
|
goto cleanup;
|
|
}
|
|
|
|
UChar buffer[40];
|
|
uplrules_selectFormatted(uplrules, uresult, buffer, 40, &ec);
|
|
if (!assertSuccess("select", &ec)) {
|
|
goto cleanup;
|
|
}
|
|
|
|
assertUEquals("0.20 is plural category 'other' in hr", u"other", buffer);
|
|
|
|
cleanup:
|
|
uplrules_close(uplrules);
|
|
unumf_close(unumf);
|
|
unumf_closeResult(uresult);
|
|
}
|
|
|
|
static void TestSelectRange() {
|
|
UErrorCode ec = U_ZERO_ERROR;
|
|
UNumberRangeFormatter* unumrf = NULL;
|
|
UFormattedNumberRange* uresult = NULL;
|
|
UPluralRules* uplrules = NULL;
|
|
|
|
int32_t d1 = 102;
|
|
int32_t d2 = 201;
|
|
|
|
// Locale sl has interesting data: one + two => few
|
|
uplrules = uplrules_open("sl", &ec);
|
|
if (!assertSuccess("open plural rules", &ec)) {
|
|
goto cleanup;
|
|
}
|
|
|
|
unumrf = unumrf_openForSkeletonWithCollapseAndIdentityFallback(
|
|
u"",
|
|
0,
|
|
UNUM_RANGE_COLLAPSE_AUTO,
|
|
UNUM_IDENTITY_FALLBACK_APPROXIMATELY,
|
|
"sl",
|
|
NULL,
|
|
&ec);
|
|
if (!assertSuccess("open unumrf", &ec)) {
|
|
goto cleanup;
|
|
}
|
|
|
|
uresult = unumrf_openResult(&ec);
|
|
if (!assertSuccess("open result", &ec)) {
|
|
goto cleanup;
|
|
}
|
|
|
|
unumrf_formatDoubleRange(unumrf, d1, d2, uresult, &ec);
|
|
if (!assertSuccess("format", &ec)) {
|
|
goto cleanup;
|
|
}
|
|
|
|
UChar buffer[40];
|
|
int32_t len = uplrules_selectForRange(uplrules, uresult, buffer, 40, &ec);
|
|
if (!assertSuccess("select", &ec)) {
|
|
goto cleanup;
|
|
}
|
|
|
|
assertUEquals("102-201 is plural category 'few' in sl", u"few", buffer);
|
|
assertIntEquals("Length should be as expected", u_strlen(buffer), len);
|
|
|
|
cleanup:
|
|
uplrules_close(uplrules);
|
|
unumrf_close(unumrf);
|
|
unumrf_closeResult(uresult);
|
|
}
|
|
|
|
#endif /* #if !UCONFIG_NO_FORMATTING */
|