Home | History | Annotate | Download | only in cintltst
      1 //  2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html
      3 /********************************************************************
      4  * Copyright (c) 2011-2014, International Business Machines Corporation
      5  * and others. All Rights Reserved.
      6  ********************************************************************/
      7 /* C API TEST FOR PLURAL RULES */
      8 
      9 #include "unicode/utypes.h"
     10 
     11 #if !UCONFIG_NO_FORMATTING
     12 
     13 #include "unicode/upluralrules.h"
     14 #include "unicode/ustring.h"
     15 #include "unicode/uenum.h"
     16 #include "cintltst.h"
     17 #include "cmemory.h"
     18 #include "cstring.h"
     19 
     20 static void TestPluralRules(void);
     21 static void TestOrdinalRules(void);
     22 static void TestGetKeywords(void);
     23 
     24 void addPluralRulesTest(TestNode** root);
     25 
     26 #define TESTCASE(x) addTest(root, &x, "tsformat/cpluralrulestest/" #x)
     27 
     28 void addPluralRulesTest(TestNode** root)
     29 {
     30     TESTCASE(TestPluralRules);
     31     TESTCASE(TestOrdinalRules);
     32     TESTCASE(TestGetKeywords);
     33 }
     34 
     35 typedef struct {
     36     const char * locale;
     37     double       number;
     38     const char * keywordExpected;
     39     const char * keywordExpectedForDecimals;
     40 } PluralRulesTestItem;
     41 
     42 /* Just a small set of tests for now, other functionality is tested in the C++ tests */
     43 static const PluralRulesTestItem testItems[] = {
     44     { "en",   0, "other", "other" },
     45     { "en", 0.5, "other", "other" },
     46     { "en",   1, "one",   "other" },
     47     { "en", 1.5, "other", "other" },
     48     { "en",   2, "other", "other" },
     49     { "fr",   0, "one",   "one" },
     50     { "fr", 0.5, "one",   "one" },
     51     { "fr",   1, "one",   "one" },
     52     { "fr", 1.5, "one",   "one" },
     53     { "fr",   2, "other", "other" },
     54     { "ru",   0, "many",  "other" },
     55     { "ru", 0.5, "other", "other" },
     56     { "ru",   1, "one",   "other" },
     57     { "ru", 1.5, "other", "other" },
     58     { "ru",   2, "few",   "other" },
     59     { "ru",   5, "many",  "other" },
     60     { "ru",  10, "many",  "other" },
     61     { "ru",  11, "many",  "other" },
     62     { NULL,   0, NULL,    NULL }
     63 };
     64 
     65 static const UChar twoDecimalPat[] = { 0x23,0x30,0x2E,0x30,0x30,0 }; /* "#0.00" */
     66 
     67 enum {
     68     kKeywordBufLen = 32
     69 };
     70 
     71 static void TestPluralRules()
     72 {
     73     const PluralRulesTestItem * testItemPtr;
     74     log_verbose("\nTesting uplrules_open() and uplrules_select() with various parameters\n");
     75     for ( testItemPtr = testItems; testItemPtr->locale != NULL; ++testItemPtr ) {
     76         UErrorCode status = U_ZERO_ERROR;
     77         UPluralRules* uplrules = uplrules_open(testItemPtr->locale, &status);
     78         if ( U_SUCCESS(status) ) {
     79             UNumberFormat* unumfmt;
     80             UChar keyword[kKeywordBufLen];
     81             UChar keywordExpected[kKeywordBufLen];
     82             int32_t keywdLen = uplrules_select(uplrules, testItemPtr->number, keyword, kKeywordBufLen, &status);
     83             if (keywdLen >= kKeywordBufLen) {
     84                 keyword[kKeywordBufLen-1] = 0;
     85             }
     86             if ( U_SUCCESS(status) ) {
     87                 u_unescape(testItemPtr->keywordExpected, keywordExpected, kKeywordBufLen);
     88                 if ( u_strcmp(keyword, keywordExpected) != 0 ) {
     89                     char bcharBuf[kKeywordBufLen];
     90                     log_data_err("ERROR: uplrules_select for locale %s, number %.1f: expect %s, get %s\n",
     91                              testItemPtr->locale, testItemPtr->number, testItemPtr->keywordExpected, u_austrcpy(bcharBuf,keyword) );
     92                 }
     93             } else {
     94                 log_err("FAIL: uplrules_select for locale %s, number %.1f: %s\n",
     95                         testItemPtr->locale, testItemPtr->number, myErrorName(status) );
     96             }
     97 
     98             status = U_ZERO_ERROR;
     99             unumfmt = unum_open(UNUM_PATTERN_DECIMAL, twoDecimalPat, -1, testItemPtr->locale, NULL, &status);
    100             if ( U_SUCCESS(status) ) {
    101                 keywdLen = uplrules_selectWithFormat(uplrules, testItemPtr->number, unumfmt, keyword, kKeywordBufLen, &status);
    102                 if (keywdLen >= kKeywordBufLen) {
    103                     keyword[kKeywordBufLen-1] = 0;
    104                 }
    105                 if ( U_SUCCESS(status) ) {
    106                     u_unescape(testItemPtr->keywordExpectedForDecimals, keywordExpected, kKeywordBufLen);
    107                     if ( u_strcmp(keyword, keywordExpected) != 0 ) {
    108                         char bcharBuf[kKeywordBufLen];
    109                         log_data_err("ERROR: uplrules_selectWithFormat for locale %s, number %.1f: expect %s, get %s\n",
    110                                  testItemPtr->locale, testItemPtr->number, testItemPtr->keywordExpectedForDecimals, u_austrcpy(bcharBuf,keyword) );
    111                     }
    112                 } else {
    113                     log_err("FAIL: uplrules_selectWithFormat for locale %s, number %.1f: %s\n",
    114                             testItemPtr->locale, testItemPtr->number, myErrorName(status) );
    115                 }
    116                 unum_close(unumfmt);
    117             } else {
    118                 log_err("FAIL: unum_open for locale %s: %s\n", testItemPtr->locale, myErrorName(status) );
    119             }
    120 
    121             uplrules_close(uplrules);
    122         } else {
    123             log_err("FAIL: uplrules_open for locale %s: %s\n", testItemPtr->locale, myErrorName(status) );
    124         }
    125     }
    126 }
    127 
    128 static void TestOrdinalRules() {
    129     U_STRING_DECL(two, "two", 3);
    130     UChar keyword[8];
    131     int32_t length;
    132     UErrorCode errorCode = U_ZERO_ERROR;
    133     UPluralRules* upr = uplrules_openForType("en", UPLURAL_TYPE_ORDINAL, &errorCode);
    134     if (U_FAILURE(errorCode)) {
    135         log_err("uplrules_openForType(en, ordinal) failed - %s\n", u_errorName(errorCode));
    136         return;
    137     }
    138     U_STRING_INIT(two, "two", 3);
    139     length = uplrules_select(upr, 2., keyword, 8, &errorCode);
    140     if (U_FAILURE(errorCode) || u_strCompare(keyword, length, two, 3, FALSE) != 0) {
    141         log_data_err("uplrules_select(en-ordinal, 2) failed - %s\n", u_errorName(errorCode));
    142     }
    143     uplrules_close(upr);
    144 }
    145 
    146 /* items for TestGetKeywords */
    147 
    148 /* all possible plural keywords, in alphabetical order */
    149 static const char* knownKeywords[] = {
    150     "few",
    151     "many",
    152     "one",
    153     "other",
    154     "two",
    155     "zero"
    156 };
    157 enum {
    158     kNumKeywords = UPRV_LENGTHOF(knownKeywords)
    159 };
    160 
    161 /* Return the index of keyword in knownKeywords[], or -1 if not found */
    162 static int32_t getKeywordIndex(const char* keyword) {
    163     int32_t i, compare;
    164     for (i = 0; i < kNumKeywords && (compare = uprv_strcmp(keyword,knownKeywords[i])) >= 0; i++) {
    165         if (compare == 0) {
    166         	return i;
    167         }
    168     }
    169     return -1;
    170 }
    171 
    172 typedef struct {
    173     const char* locale;
    174     const char* keywords[kNumKeywords + 1];
    175 } KeywordsForLang;
    176 
    177 static const KeywordsForLang getKeywordsItems[] = {
    178     { "zh", { "other" } },
    179     { "en", { "one", "other" } },
    180     { "fr", { "one", "other" } },
    181     { "lv", { "zero", "one", "other" } },
    182     { "hr", { "one", "few", "other" } },
    183     { "sl", { "one", "two", "few", "other" } },
    184     { "he", { "one", "two", "many", "other" } },
    185     { "cs", { "one", "few", "many", "other" } },
    186     { "ar", { "zero", "one", "two", "few", "many" , "other" } },
    187     { NULL, { NULL } }
    188 };
    189 
    190 static void TestGetKeywords() {
    191     /*
    192      * We don't know the order in which the enumeration will return keywords,
    193      * so we have an array with known keywords in a fixed order and then
    194      * parallel arrays of flags for expected and actual results that indicate
    195      * which keywords are expected to be or actually are found.
    196      */
    197     const KeywordsForLang* itemPtr = getKeywordsItems;
    198     for (; itemPtr->locale != NULL; itemPtr++) {
    199         UPluralRules* uplrules;
    200         UEnumeration* uenum;
    201         UBool expectKeywords[kNumKeywords];
    202         UBool getKeywords[kNumKeywords];
    203         int32_t i, iKnown;
    204         UErrorCode status = U_ZERO_ERROR;
    205 
    206         /* initialize arrays for expected and get results */
    207         for (i = 0; i < kNumKeywords; i++) {
    208             expectKeywords[i] = FALSE;
    209             getKeywords[i] = FALSE;
    210         }
    211         for (i = 0; i < kNumKeywords && itemPtr->keywords[i] != NULL; i++) {
    212             iKnown = getKeywordIndex(itemPtr->keywords[i]);
    213             if (iKnown >= 0) {
    214                 expectKeywords[iKnown] = TRUE;
    215             }
    216         }
    217 
    218         uplrules = uplrules_openForType(itemPtr->locale, UPLURAL_TYPE_CARDINAL, &status);
    219         if (U_FAILURE(status)) {
    220             log_err("FAIL: uplrules_openForType for locale %s, UPLURAL_TYPE_CARDINAL: %s\n", itemPtr->locale, myErrorName(status) );
    221             continue;
    222         }
    223         uenum = uplrules_getKeywords(uplrules, &status);
    224         if (U_FAILURE(status)) {
    225             log_err("FAIL: uplrules_getKeywords for locale %s: %s\n", itemPtr->locale, myErrorName(status) );
    226         } else {
    227             const char* keyword;
    228             int32_t keywordLen, keywordCount = 0;
    229             while ((keyword = uenum_next(uenum, &keywordLen, &status)) != NULL && U_SUCCESS(status)) {
    230                 iKnown = getKeywordIndex(keyword);
    231                 if (iKnown < 0) {
    232                     log_err("FAIL: uplrules_getKeywords for locale %s, unknown keyword %s\n", itemPtr->locale, keyword );
    233                 } else {
    234                     getKeywords[iKnown] = TRUE;
    235                 }
    236                 keywordCount++;
    237             }
    238             if (keywordCount > kNumKeywords) {
    239                 log_err("FAIL: uplrules_getKeywords for locale %s, got too many keywords %d\n", itemPtr->locale, keywordCount );
    240             }
    241             if (uprv_memcmp(expectKeywords, getKeywords, kNumKeywords) != 0) {
    242                 log_err("FAIL: uplrules_getKeywords for locale %s, got wrong keyword set; with reference to knownKeywords:\n"
    243                         "        expected { %d %d %d %d %d %d },\n"
    244                         "        got      { %d %d %d %d %d %d }\n", itemPtr->locale,
    245                         expectKeywords[0], expectKeywords[1], expectKeywords[2], expectKeywords[3], expectKeywords[4], expectKeywords[5],
    246                         getKeywords[0], getKeywords[1], getKeywords[2], getKeywords[3], getKeywords[4], getKeywords[5] );
    247             }
    248             uenum_close(uenum);
    249         }
    250 
    251         uplrules_close(uplrules);
    252     }
    253 }
    254 
    255 #endif /* #if !UCONFIG_NO_FORMATTING */
    256