/******************************************************************** * COPYRIGHT: * Copyright (c) 1997-2003, International Business Machines Corporation and * others. All Rights Reserved. ********************************************************************/ /******************************************************************************** * * File CLOCTST.C * * Modification History: * Name Description * Madhu Katragadda Ported for C API ********************************************************************************* */ #include #include #include #include "unicode/utypes.h" #include "unicode/putil.h" #include "cloctst.h" #include "unicode/uloc.h" #include "unicode/uscript.h" #include "unicode/uchar.h" #include "unicode/ustring.h" #include "unicode/uset.h" #include "cintltst.h" #include "cstring.h" #include "unicode/ures.h" #include "locmap.h" #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0])) static void TestNullDefault(void); static void TestLocaleNameConversion(void); static void VerifyTranslation(void); void PrintDataTable(); /*--------------------------------------------------- table of valid data --------------------------------------------------- */ #define LOCALE_SIZE 6 #define LOCALE_INFO_SIZE 28 static const char* rawData2[LOCALE_INFO_SIZE][LOCALE_SIZE] = { /* language code */ { "en", "fr", "ca", "el", "no", "zh" }, /* script code */ { "", "", "", "", "", "Hans" }, /* country code */ { "US", "FR", "ES", "GR", "NO", "CN" }, /* variant code */ { "", "", "", "", "NY", "" }, /* full name */ { "en_US", "fr_FR", "ca_ES", "el_GR", "no_NO_NY", "zh_Hans_CN" }, /* ISO-3 language */ { "eng", "fra", "cat", "ell", "nor", "zho" }, /* ISO-3 country */ { "USA", "FRA", "ESP", "GRC", "NOR", "CHN" }, /* LCID */ { "409", "40c", "403", "408", "814", "804" }, /* display language (English) */ { "English", "French", "Catalan", "Greek", "Norwegian", "Chinese" }, /* display script code (English) */ { "", "", "", "", "", "Simplified Han" }, /* display country (English) */ { "United States", "France", "Spain", "Greece", "Norway", "China" }, /* display variant (English) */ { "", "", "", "", "Nynorsk", "" }, /* display name (English) */ { "English (United States)", "French (France)", "Catalan (Spain)", "Greek (Greece)", "Norwegian (Norway, Nynorsk)", "Chinese (Simplified Han, China)" }, /* display language (French) */ { "anglais", "fran\\u00E7ais", "catalan", "grec", "norv\\u00E9gien", "chinois" }, /* display script code (French) */ { "", "", "", "", "", "Hans" }, /* display country (French) */ { "\\u00C9tats-Unis", "France", "Espagne", "Gr\\u00E8ce", "Norv\\u00E8ge", "Chine" }, /* display variant (French) */ { "", "", "", "", "NY", "" }, /* display name (French) */ { "anglais (\\u00C9tats-Unis)", "fran\\u00E7ais (France)", "catalan (Espagne)", "grec (Gr\\u00E8ce)", "norv\\u00E9gien (Norv\\u00E8ge, NY)", "chinois (Hans, Chine)" }, /* display language (Catalan) */ { "angl\\u00E8s", "franc\\u00E8s", "catal\\u00E0", "grec", "noruec", "xin\\u00E9s" }, /* display script code (Catalan) */ { "", "", "", "", "", "Hans" }, /* display country (Catalan) */ { "Estats Units", "Fran\\u00E7a", "Espanya", "Gr\\u00E8cia", "Noruega", "Xina" }, /* display variant (Catalan) */ { "", "", "", "", "NY", "" }, /* display name (Catalan) */ { "angl\\u00E8s (Estats Units)", "franc\\u00E8s (Fran\\u00E7a)", "catal\\u00E0 (Espanya)", "grec (Gr\\u00E8cia)", "noruec (Noruega, NY)", "xin\\u00E9s (Hans, Xina)" }, /* display language (Greek) */ { "\\u0391\\u03b3\\u03b3\\u03bb\\u03b9\\u03ba\\u03ac", "\\u0393\\u03b1\\u03bb\\u03bb\\u03b9\\u03ba\\u03ac", "\\u039a\\u03b1\\u03c4\\u03b1\\u03bb\\u03b1\\u03bd\\u03b9\\u03ba\\u03ac", "\\u0395\\u03bb\\u03bb\\u03b7\\u03bd\\u03b9\\u03ba\\u03ac", "\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03b9\\u03ba\\u03ac", "\\u039A\\u03B9\\u03BD\\u03B5\\u03B6\\u03B9\\u03BA\\u03AC" }, /* display script code (Greek) */ { "", "", "", "", "", "Hans" }, /* display country (Greek) */ { "\\u0397\\u03bd\\u03c9\\u03bc\\u03ad\\u03bd\\u03b5\\u03c2 \\u03a0\\u03bf\\u03bb\\u03b9\\u03c4\\u03b5\\u03af\\u03b5\\u03c2", "\\u0393\\u03b1\\u03bb\\u03bb\\u03af\\u03b1", "\\u0399\\u03c3\\u03c0\\u03b1\\u03bd\\u03af\\u03b1", "\\u0395\\u03bb\\u03bb\\u03ac\\u03b4\\u03b1", "\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03af\\u03b1", "\\u039A\\u03AF\\u03BD\\u03B1" }, /* display variant (Greek) */ { "", "", "", "", "NY", "" }, /* TODO: currently there is no translation for NY in Greek fix this test when we have it */ /* display name (Greek) */ { "\\u0391\\u03b3\\u03b3\\u03bb\\u03b9\\u03ba\\u03ac (\\u0397\\u03bd\\u03c9\\u03bc\\u03ad\\u03bd\\u03b5\\u03c2 \\u03a0\\u03bf\\u03bb\\u03b9\\u03c4\\u03b5\\u03af\\u03b5\\u03c2)", "\\u0393\\u03b1\\u03bb\\u03bb\\u03b9\\u03ba\\u03ac (\\u0393\\u03b1\\u03bb\\u03bb\\u03af\\u03b1)", "\\u039a\\u03b1\\u03c4\\u03b1\\u03bb\\u03b1\\u03bd\\u03b9\\u03ba\\u03ac (\\u0399\\u03c3\\u03c0\\u03b1\\u03bd\\u03af\\u03b1)", "\\u0395\\u03bb\\u03bb\\u03b7\\u03bd\\u03b9\\u03ba\\u03ac (\\u0395\\u03bb\\u03bb\\u03ac\\u03b4\\u03b1)", "\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03b9\\u03ba\\u03ac (\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03af\\u03b1, NY)", "\\u039A\\u03B9\\u03BD\\u03B5\\u03B6\\u03B9\\u03BA\\u03AC (Hans, \\u039A\\u03AF\\u03BD\\u03B1)" } }; static UChar*** dataTable=0; enum { ENGLISH = 0, FRENCH = 1, CATALAN = 2, GREEK = 3, NORWEGIAN = 4 }; enum { LANG = 0, SCRIPT = 1, CTRY = 2, VAR = 3, NAME = 4, LANG3 = 5, CTRY3 = 6, LCID = 7, DLANG_EN = 8, DSCRIPT_EN = 9, DCTRY_EN = 10, DVAR_EN = 11, DNAME_EN = 12, DLANG_FR = 13, DSCRIPT_FR = 14, DCTRY_FR = 15, DVAR_FR = 16, DNAME_FR = 17, DLANG_CA = 18, DSCRIPT_CA = 19, DCTRY_CA = 20, DVAR_CA = 21, DNAME_CA = 22, DLANG_EL = 23, DSCRIPT_EL = 24, DCTRY_EL = 25, DVAR_EL = 26, DNAME_EL = 27 }; void addLocaleTest(TestNode** root); void addLocaleTest(TestNode** root) { addTest(root, &TestObsoleteNames, "tsutil/cloctst/TestObsoleteNames"); /* srl- move */ addTest(root, &TestBasicGetters, "tsutil/cloctst/TestBasicGetters"); addTest(root, &TestNullDefault, "tsutil/cloctst/TestNullDefault"); addTest(root, &TestPrefixes, "tsutil/cloctst/TestPrefixes"); addTest(root, &TestSimpleResourceInfo, "tsutil/cloctst/TestSimpleResourceInfo"); addTest(root, &TestDisplayNames, "tsutil/cloctst/TestDisplayNames"); addTest(root, &TestGetAvailableLocales, "tsutil/cloctst/TestGetAvailableLocales"); addTest(root, &TestDataDirectory, "tsutil/cloctst/TestDataDirectory"); addTest(root, &TestISOFunctions, "tsutil/cloctst/TestISOFunctions"); addTest(root, &TestISO3Fallback, "tsutil/cloctst/TestISO3Fallback"); addTest(root, &TestUninstalledISO3Names, "tsutil/cloctst/TestUninstalledISO3Names"); addTest(root, &TestSimpleDisplayNames, "tsutil/cloctst/TestSimpleDisplayNames"); addTest(root, &TestVariantParsing, "tsutil/cloctst/TestVariantParsing"); addTest(root, &TestLocaleStructure, "tsutil/cloctst/TestLocaleStructure"); addTest(root, &TestConsistentCountryInfo,"tsutil/cloctst/TestConsistentCountryInfo"); addTest(root, &VerifyTranslation, "tsutil/cloctst/VerifyTranslation"); /*addTest(root, &MoreVariants, "tsutil/cloctst/MoreVariants");*/ addTest(root, &TestKeywordVariants, "tsutil/cloctst/TestKeywordVariants"); addTest(root, &TestKeywordVariantParsing,"tsutil/cloctst/TestKeywordVariantParsing"); addTest(root, &TestCanonicalization, "tsutil/cloctst/TestCanonicalization"); } /* testing uloc(), uloc_getName(), uloc_getLanguage(), uloc_getVariant(), uloc_getCountry() */ static void TestBasicGetters() { int32_t i; int32_t cap; UErrorCode status = U_ZERO_ERROR; char *testLocale = 0; char *temp = 0, *name = 0; log_verbose("Testing Basic Getters\n"); for (i = 0; i < LOCALE_SIZE; i++) { testLocale=(char*)malloc(sizeof(char) * (strlen(rawData2[NAME][i])+1)); strcpy(testLocale,rawData2[NAME][i]); log_verbose("Testing %s .....\n", testLocale); cap=uloc_getLanguage(testLocale, NULL, 0, &status); if(status==U_BUFFER_OVERFLOW_ERROR){ status=U_ZERO_ERROR; temp=(char*)malloc(sizeof(char) * (cap+1)); uloc_getLanguage(testLocale, temp, cap+1, &status); } if(U_FAILURE(status)){ log_err("ERROR: in uloc_getLanguage %s\n", myErrorName(status)); } if (0 !=strcmp(temp,rawData2[LANG][i])) { log_err(" Language code mismatch: %s versus %s\n", temp, rawData2[LANG][i]); } cap=uloc_getCountry(testLocale, temp, cap, &status); if(status==U_BUFFER_OVERFLOW_ERROR){ status=U_ZERO_ERROR; temp=(char*)realloc(temp, sizeof(char) * (cap+1)); uloc_getCountry(testLocale, temp, cap+1, &status); } if(U_FAILURE(status)){ log_err("ERROR: in uloc_getCountry %s\n", myErrorName(status)); } if (0 != strcmp(temp, rawData2[CTRY][i])) { log_err(" Country code mismatch: %s versus %s\n", temp, rawData2[CTRY][i]); } cap=uloc_getVariant(testLocale, temp, cap, &status); if(status==U_BUFFER_OVERFLOW_ERROR){ status=U_ZERO_ERROR; temp=(char*)realloc(temp, sizeof(char) * (cap+1)); uloc_getVariant(testLocale, temp, cap+1, &status); } if(U_FAILURE(status)){ log_err("ERROR: in uloc_getVariant %s\n", myErrorName(status)); } if (0 != strcmp(temp, rawData2[VAR][i])) { log_err("Variant code mismatch: %s versus %s\n", temp, rawData2[VAR][i]); } cap=uloc_getName(testLocale, NULL, 0, &status); if(status==U_BUFFER_OVERFLOW_ERROR){ status=U_ZERO_ERROR; name=(char*)malloc(sizeof(char) * (cap+1)); uloc_getName(testLocale, name, cap+1, &status); } else if(status==U_ZERO_ERROR) { log_err("ERROR: in uloc_getName(%s,NULL,0,..), expected U_BUFFER_OVERFLOW_ERROR!\n", testLocale); } if(U_FAILURE(status)){ log_err("ERROR: in uloc_getName %s\n", myErrorName(status)); } if (0 != strcmp(name, rawData2[NAME][i])){ log_err(" Mismatch in getName: %s versus %s\n", name, rawData2[NAME][i]); } free(temp); free(name); free(testLocale); } } static void TestNullDefault() { UErrorCode status = U_ZERO_ERROR; char original[ULOC_FULLNAME_CAPACITY]; uprv_strcpy(original, uloc_getDefault()); uloc_setDefault("qq_BLA", &status); if (uprv_strcmp(uloc_getDefault(), "qq_BLA") != 0) { log_err(" Mismatch in uloc_setDefault: qq_BLA versus %s\n", uloc_getDefault()); } uloc_setDefault(NULL, &status); if (uprv_strcmp(uloc_getDefault(), original) != 0) { log_err(" uloc_setDefault(NULL, &status) didn't get the default locale back!\n"); } { /* Test that set & get of default locale work, and that * default locales are cached and reused, and not overwritten. */ const char *n_en_US; const char *n_fr_FR; const char *n2_en_US; status = U_ZERO_ERROR; uloc_setDefault("en_US", &status); n_en_US = uloc_getDefault(); if (strcmp(n_en_US, "en_US") != 0) { log_err("Wrong result from uloc_getDefault(). Expected \"en_US\", got \"%s\"\n", n_en_US); } uloc_setDefault("fr_FR", &status); n_fr_FR = uloc_getDefault(); if (strcmp(n_en_US, "en_US") != 0) { log_err("uloc_setDefault altered previously default string." "Expected \"en_US\", got \"%s\"\n", n_en_US); } if (strcmp(n_fr_FR, "fr_FR") != 0) { log_err("Wrong result from uloc_getDefault(). Expected \"fr_FR\", got %s\n", n_fr_FR); } uloc_setDefault("en_US", &status); n2_en_US = uloc_getDefault(); if (strcmp(n2_en_US, "en_US") != 0) { log_err("Wrong result from uloc_getDefault(). Expected \"en_US\", got \"%s\"\n", n_en_US); } if (n2_en_US != n_en_US) { log_err("Default locale cache failed to reuse en_US locale.\n"); } if (U_FAILURE(status)) { log_err("Failure returned from uloc_setDefault - \"%s\"\n", u_errorName(status)); } } } /* Test the i- and x- and @ and . functionality */ #define PREFIXBUFSIZ 128 static void TestPrefixes() { int row = 0; int n; const char *loc; const char *testData[][6] = { {"sv", "", "FI", "AL", "sv-fi-al", "sv_FI_AL" }, {"en", "", "GB", "", "en-gb", "en_GB" }, {"i-hakka", "", "MT", "XEMXIJA", "i-hakka_MT_XEMXIJA", "i-hakka_MT_XEMXIJA"}, {"i-hakka", "", "CN", "", "i-hakka_CN", "i-hakka_CN"}, {"i-hakka", "", "MX", "", "I-hakka_MX", "i-hakka_MX"}, {"x-klingon", "", "US", "SANJOSE", "X-KLINGON_us_SANJOSE", "x-klingon_US_SANJOSE"}, {"mr", "", "", "", "mr.utf8", "mr"}, {"de", "", "TV", "", "de-tv.koi8r", "de_TV"}, {"x-piglatin", "", "ML", "", "x-piglatin_ML.MBE", "x-piglatin_ML"}, /* Multibyte English */ {"i-cherokee", "","US", "", "i-Cherokee_US.utf7", "i-cherokee_US"}, {"x-filfli", "", "MT", "FILFLA", "x-filfli_MT_FILFLA.gb-18030", "x-filfli_MT_FILFLA"}, {"no", "", "NO", "NY", "no-no-ny.utf32@B", "no_NO_NY"}, /* @ ignored unless variant is empty */ {"no", "", "NO", "B", "no-no.utf32@B", "no_NO_B" }, {"no", "", "", "NY", "no__ny", "no__NY" }, {"no", "", "", "NY", "no@ny", "no__NY" }, {"el", "Latn", "", "", "el-latn", "el_Latn" }, {"en", "Cyrl", "RU", "", "en-cyrl-ru", "en_Cyrl_RU" }, {"zh", "Hant", "TW", "STROKE", "zh-hant_TW_STROKE", "zh_Hant_TW_STROKE" }, {"qq", "Qqqq", "QQ", "QQ", "qq_Qqqq_QQ_QQ", "qq_Qqqq_QQ_QQ" }, {"qq", "Qqqq", "", "QQ", "qq_Qqqq__QQ", "qq_Qqqq__QQ" }, {"12", "3456", "78", "90", "12_3456_78_90", "12_3456_78_90" }, /* total garbage */ { "","","","",""} }; const char *testTitles[] = { "uloc_getLanguage()", "uloc_getScript()", "uloc_getCountry()", "uloc_getVariant()", "name", "uloc_getName()", "country3" }; char buf[PREFIXBUFSIZ]; int32_t len; UErrorCode err; for(row=0;testData[row][0][0] != 0;row++) { loc = testData[row][NAME]; log_verbose("Test #%d: %s\n", row, loc); err = U_ZERO_ERROR; len=0; buf[0]=0; for(n=0;n<=(NAME+1);n++) { if(n==NAME) continue; for(len=0;len [%s] (length %d)\n", row, testTitles[n], loc, buf, len); if(len != (int32_t)strlen(buf)) { log_err("#%d: %s on %s: -> [%s] (length returned %d, actual %d!)\n", row, testTitles[n], loc, buf, len, strlen(buf)+1); } /* see if they smashed something */ if(buf[len+1] != '%') { log_err("#%d: %s on %s: -> [%s] - wrote [%X] out ofbounds!\n", row, testTitles[n], loc, buf, buf[len+1]); } if(strcmp(buf, testData[row][n])) { log_err("#%d: %s on %s: -> [%s] (expected '%s'!)\n", row, testTitles[n], loc, buf, testData[row][n]); } } } } } /* testing uloc_getISO3Language(), uloc_getISO3Country(), */ static void TestSimpleResourceInfo() { int32_t i; char* testLocale = 0; UChar* expected = 0; const char* temp; char temp2[20]; testLocale=(char*)malloc(sizeof(char) * 1); expected=(UChar*)malloc(sizeof(UChar) * 1); setUpDataTable(); log_verbose("Testing getISO3Language and getISO3Country\n"); for (i = 0; i < LOCALE_SIZE; i++) { testLocale=(char*)realloc(testLocale, sizeof(char) * (u_strlen(dataTable[NAME][i])+1)); u_austrcpy(testLocale, dataTable[NAME][i]); log_verbose("Testing %s ......\n", testLocale); temp=uloc_getISO3Language(testLocale); expected=(UChar*)realloc(expected, sizeof(UChar) * (strlen(temp) + 1)); u_uastrcpy(expected,temp); if (0 != u_strcmp(expected, dataTable[LANG3][i])) { log_err(" ISO-3 language code mismatch: %s versus %s\n", austrdup(expected), austrdup(dataTable[LANG3][i])); } temp=uloc_getISO3Country(testLocale); expected=(UChar*)realloc(expected, sizeof(UChar) * (strlen(temp) + 1)); u_uastrcpy(expected,temp); if (0 != u_strcmp(expected, dataTable[CTRY3][i])) { log_err(" ISO-3 Country code mismatch: %s versus %s\n", austrdup(expected), austrdup(dataTable[CTRY3][i])); } sprintf(temp2, "%x", uloc_getLCID(testLocale)); if (strcmp(temp2, rawData2[LCID][i]) != 0) { log_err("LCID mismatch: %s versus %s\n", temp2 , rawData2[LCID][i]); } } free(expected); free(testLocale); cleanUpDataTable(); } /* * Jitterbug 2439 -- markus 20030425 * * The lookup of display names must not fall back through the default * locale because that yields useless results. */ static void TestDisplayNames() { UChar buffer[100]; UErrorCode errorCode=U_ZERO_ERROR; int32_t length; UChar temp[500]; int32_t maxresultsize=uloc_getDisplayVariant("no_NO_NY", "en_US", temp, 500, &errorCode); log_verbose("Testing getDisplayName for different locales\n"); log_verbose(" In locale = en_US...\n"); doTestDisplayNames("en_US", DLANG_EN); log_verbose(" In locale = fr_FR....\n"); doTestDisplayNames("fr_FR", DLANG_FR); log_verbose(" In locale = ca_ES...\n"); doTestDisplayNames("ca_ES", DLANG_CA); log_verbose(" In locale = gr_EL..\n"); doTestDisplayNames("el_GR", DLANG_EL); /* test that the default locale has a display name for its own language */ errorCode=U_ZERO_ERROR; length=uloc_getDisplayLanguage(NULL, NULL, buffer, LENGTHOF(buffer), &errorCode); if(U_FAILURE(errorCode) || (length<=3 && buffer[0]<=0x7f)) { /* check <=3 to reject getting the language code as a display name */ log_err("unable to get a display string for the language of the default locale - %s\n", u_errorName(errorCode)); } /* test that we get the language code itself for an unknown language, and a default warning */ errorCode=U_ZERO_ERROR; length=uloc_getDisplayLanguage("qq", "rr", buffer, LENGTHOF(buffer), &errorCode); if(errorCode!=U_USING_DEFAULT_WARNING || length!=2 || buffer[0]!=0x71 || buffer[1]!=0x71) { log_err("error getting the display string for an unknown language - %s\n", u_errorName(errorCode)); } } /* test for uloc_getAvialable() and uloc_countAvilable()*/ static void TestGetAvailableLocales() { const char *locList; int32_t locCount,i; log_verbose("Testing the no of avialable locales\n"); locCount=uloc_countAvailable(); if (locCount == 0) log_data_err("countAvailable() returned an empty list!\n"); /* use something sensible w/o hardcoding the count */ else if(locCount < 0){ log_data_err("countAvailable() returned a wrong value!= %d\n", locCount); } else{ log_info("Number of locales returned = %d\n", locCount); } for(i=0;i subBundleSize) { minSize = subBundleSize; log_err("Arrays are different size with key \"%s\" in \"%s\" from root for locale \"%s\"\n", subBundleKey, ures_getKey(currentBundle), locale); } for (idx = 0; idx < minSize && sameArray; idx++) { if (subRootBundleArr[idx] != subBundleArr[idx]) { sameArray = FALSE; } if (strcmp(subBundleKey, "DateTimeElements") == 0 && (subBundleArr[idx] < 1 || 7 < subBundleArr[idx])) { log_err("Value out of range with key \"%s\" at index %d in \"%s\" for locale \"%s\"\n", subBundleKey, idx, ures_getKey(currentBundle), locale); } } /* Special exception es_US and DateTimeElements */ if (sameArray && !(strcmp(locale, "es_US") == 0 && strcmp(subBundleKey, "DateTimeElements") == 0)) { log_err("Integer vectors are the same with key \"%s\" in \"%s\" from root for locale \"%s\"\n", subBundleKey, ures_getKey(currentBundle), locale); } } else if (ures_getType(subBundle) == URES_ARRAY) { UResourceBundle *subSubBundle = ures_getByIndex(subBundle, 0, NULL, &errorCode); UResourceBundle *subSubRootBundle = ures_getByIndex(subRootBundle, 0, NULL, &errorCode); if (U_SUCCESS(errorCode) && (ures_getType(subSubBundle) == URES_ARRAY || ures_getType(subSubRootBundle) == URES_ARRAY)) { /* TODO: Properly check for 2D arrays and zoneStrings */ if (subBundleKey != NULL && strcmp(subBundleKey, "zoneStrings") == 0) { /* int32_t minSize = ures_getSize(subBundle); int32_t idx; for (idx = 0; idx < minSize; idx++) { UResourceBundle *subSubBundleAtIndex = ures_getByIndex(subBundle, idx, NULL, &errorCode); if (ures_getSize(subSubBundleAtIndex) != 6) { log_err("zoneStrings at index %d has wrong size for locale \"%s\". array size=%d\n", idx, locale, ures_getSize(subSubBundleAtIndex)); } ures_close(subSubBundleAtIndex); }*/ } else { /* Here is one of the recursive parts */ TestKeyInRootRecursive(subRootBundle, rootName, subBundle, locale); } } else { int32_t minSize = ures_getSize(subRootBundle); int32_t idx; UBool sameArray = TRUE; if (minSize > ures_getSize(subBundle)) { minSize = ures_getSize(subBundle); } if ((subBundleKey == NULL || (subBundleKey != NULL && strcmp(subBundleKey, "LocaleScript") != 0)) && ures_getSize(subRootBundle) != ures_getSize(subBundle)) { log_err("Different size array with key \"%s\" in \"%s\" from root for locale \"%s\"\n" "\troot array size=%d, locale array size=%d\n", subBundleKey, ures_getKey(currentBundle), locale, ures_getSize(subRootBundle), ures_getSize(subBundle)); } for (idx = 0; idx < minSize; idx++) { int32_t rootStrLen, localeStrLen; const UChar *rootStr = ures_getStringByIndex(subRootBundle,idx,&rootStrLen,&errorCode); const UChar *localeStr = ures_getStringByIndex(subBundle,idx,&localeStrLen,&errorCode); if (rootStr && localeStr && U_SUCCESS(errorCode)) { if (u_strcmp(rootStr, localeStr) != 0) { sameArray = FALSE; } } else { log_err("Got a NULL string with key \"%s\" in \"%s\" at index %d for root or locale \"%s\"\n", subBundleKey, ures_getKey(currentBundle), idx, locale); continue; } if (localeStr[0] == (UChar)0x20) { log_err("key \"%s\" at index %d in \"%s\" starts with a space in locale \"%s\"\n", subBundleKey, idx, ures_getKey(currentBundle), locale); } else if (localeStr[localeStrLen - 1] == (UChar)0x20) { log_err("key \"%s\" at index %d in \"%s\" ends with a space in locale \"%s\"\n", subBundleKey, idx, ures_getKey(currentBundle), locale); } else if (subBundleKey != NULL && strcmp(subBundleKey, "DateTimePatterns") == 0) { int32_t quoted = 0; const UChar *localeStrItr = localeStr; while (*localeStrItr) { if (*localeStrItr == (UChar)0x27 /* ' */) { quoted++; } else if ((quoted % 2) == 0) { /* Search for unquoted characters */ if (4 <= idx && idx <= 7 && (*localeStrItr == (UChar)0x6B /* k */ || *localeStrItr == (UChar)0x48 /* H */ || *localeStrItr == (UChar)0x6D /* m */ || *localeStrItr == (UChar)0x73 /* s */ || *localeStrItr == (UChar)0x53 /* S */ || *localeStrItr == (UChar)0x61 /* a */ || *localeStrItr == (UChar)0x68 /* h */ || *localeStrItr == (UChar)0x7A /* z */)) { log_err("key \"%s\" at index %d has time pattern chars in date for locale \"%s\"\n", subBundleKey, idx, locale); } else if (0 <= idx && idx <= 3 && (*localeStrItr == (UChar)0x47 /* G */ || *localeStrItr == (UChar)0x79 /* y */ || *localeStrItr == (UChar)0x4D /* M */ || *localeStrItr == (UChar)0x64 /* d */ || *localeStrItr == (UChar)0x45 /* E */ || *localeStrItr == (UChar)0x44 /* D */ || *localeStrItr == (UChar)0x46 /* F */ || *localeStrItr == (UChar)0x77 /* w */ || *localeStrItr == (UChar)0x57 /* W */)) { log_err("key \"%s\" at index %d has date pattern chars in time for locale \"%s\"\n", subBundleKey, idx, locale); } } localeStrItr++; } } else if (idx == 4 && subBundleKey != NULL && strcmp(subBundleKey, "NumberElements") == 0 && u_charDigitValue(localeStr[0]) != 0) { log_err("key \"%s\" at index %d has a non-zero based number for locale \"%s\"\n", subBundleKey, idx, locale); } } if (sameArray && strcmp(rootName, "root") == 0) { log_err("Arrays are the same with key \"%s\" in \"%s\" from root for locale \"%s\"\n", subBundleKey, ures_getKey(currentBundle), locale); } } ures_close(subSubBundle); ures_close(subSubRootBundle); } else if (ures_getType(subBundle) == URES_STRING) { int32_t len = 0; const UChar *string = ures_getString(subBundle, &len, &errorCode); if (U_FAILURE(errorCode) || string == NULL) { log_err("Can't open a string with key \"%s\" in \"%s\" for locale \"%s\"\n", subBundleKey, ures_getKey(currentBundle), locale); } else if (string[0] == (UChar)0x20) { log_err("key \"%s\" in \"%s\" starts with a space in locale \"%s\"\n", subBundleKey, ures_getKey(currentBundle), locale); } else if (string[len - 1] == (UChar)0x20) { log_err("key \"%s\" in \"%s\" ends with a space in locale \"%s\"\n", subBundleKey, ures_getKey(currentBundle), locale); } else if (strcmp(subBundleKey, "localPatternChars") == 0 && len != 20) { log_err("key \"%s\" has the wrong number of characters in locale \"%s\"\n", subBundleKey, locale); } /* No fallback was done. Check for duplicate data */ /* The ures_* API does not do fallback of sub-resource bundles, So we can't do this now. */ else if (strcmp(locale, "root") != 0 && errorCode == U_ZERO_ERROR) { const UChar *rootString = ures_getString(subRootBundle, &len, &errorCode); if (U_FAILURE(errorCode) || rootString == NULL) { log_err("Can't open a string with key \"%s\" in \"%s\" in root\n", ures_getKey(subRootBundle), ures_getKey(currentBundle)); continue; } else if (u_strcmp(string, rootString) == 0) { if (strcmp(locale, "de_CH") != 0 && strcmp(subBundleKey, "Countries") != 0) { log_err("Found duplicate data with key \"%s\" in \"%s\" in locale \"%s\"\n", ures_getKey(subRootBundle), ures_getKey(currentBundle), locale); } else { /* Ignore for now. */ /* Can be fixed if fallback through de locale was done. */ log_verbose("Skipping key %s in %s\n", subBundleKey, locale); } } } } else if (ures_getType(subBundle) == URES_TABLE) { /* Here is one of the recursive parts */ TestKeyInRootRecursive(subRootBundle, rootName, subBundle, locale); } else if (ures_getType(subBundle) == URES_BINARY || ures_getType(subBundle) == URES_INT) { /* Can't do anything to check it */ /* We'll assume it's all correct */ if (strcmp(subBundleKey, "LocaleID") != 0) { log_verbose("Skipping key \"%s\" in \"%s\" for locale \"%s\"\n", subBundleKey, ures_getKey(currentBundle), locale); } /* Testing for LocaleID is done in testLCID */ } else { log_err("Type %d for key \"%s\" in \"%s\" is unknown for locale \"%s\"\n", ures_getType(subBundle), subBundleKey, ures_getKey(currentBundle), locale); } ures_close(subRootBundle); ures_close(subBundle); } } static void testLCID(UResourceBundle *currentBundle, const char *localeName) { UErrorCode status = U_ZERO_ERROR; uint32_t lcid; uint32_t expectedLCID; char lcidStringC[64] = {0}; int32_t lcidStringLen = 0; const UChar *lcidString = NULL; expectedLCID = uloc_getLCID(localeName); lcid = uprv_convertToLCID(localeName, &status); if (U_FAILURE(status)) { if (expectedLCID == 0) { log_verbose("INFO: %-5s does not have any LCID mapping\n", localeName); } else { log_err("ERROR: %-5s does not have an LCID mapping to 0x%.4X\n", localeName, expectedLCID); } return; } status = U_ZERO_ERROR; uprv_strcpy(lcidStringC, uprv_convertToPosix(expectedLCID, &status)); if (U_FAILURE(status)) { log_err("ERROR: %.4x does not have a POSIX mapping due to %s\n", expectedLCID, u_errorName(status)); } if(lcid != expectedLCID) { log_err("ERROR: %-5s wrongfully has 0x%.4x instead of 0x%.4x for LCID\n", localeName, expectedLCID, lcid); } if(strcmp(localeName, lcidStringC) != 0) { char langName[1024]; char langLCID[1024]; uloc_getLanguage(localeName, langName, sizeof(langName), &status); uloc_getLanguage(lcidStringC, langLCID, sizeof(langLCID), &status); if (expectedLCID == lcid && strcmp(langName, langLCID) == 0) { log_verbose("WARNING: %-5s resolves to %s (0x%.4x)\n", localeName, lcidStringC, lcid); } else if (expectedLCID == lcid) { log_err("ERROR: %-5s has 0x%.4x and the number resolves wrongfully to %s\n", localeName, expectedLCID, lcidStringC); } else { log_err("ERROR: %-5s has 0x%.4x and the number resolves wrongfully to %s. It should be 0x%x.\n", localeName, expectedLCID, lcidStringC, lcid); } } } static void TestLocaleStructure(void) { UResourceBundle *root, *completeLoc, *currentLocale, *subtable, *completeSubtable; int32_t locCount = uloc_countAvailable(); int32_t locIndex; UErrorCode errorCode = U_ZERO_ERROR; const char *currLoc; /* TODO: Compare against parent's data too. This code can't handle fallbacks that some tools do already. */ /* char locName[ULOC_FULLNAME_CAPACITY]; char *locNamePtr; for (locIndex = 0; locIndex < locCount; locIndex++) { errorCode=U_ZERO_ERROR; strcpy(locName, uloc_getAvailable(locIndex)); locNamePtr = strrchr(locName, '_'); if (locNamePtr) { *locNamePtr = 0; } else { strcpy(locName, "root"); } root = ures_openDirect(NULL, locName, &errorCode); if(U_FAILURE(errorCode)) { log_err("Can't open %s\n", locName); continue; } */ if (locCount <= 1) { log_data_err("At least root needs to be installed\n"); } root = ures_openDirect(NULL, "root", &errorCode); if(U_FAILURE(errorCode)) { log_data_err("Can't open root\n"); return; } completeLoc = ures_openDirect(NULL, "en", &errorCode); if(U_FAILURE(errorCode)) { log_data_err("Can't open en\n"); return; } for (locIndex = 0; locIndex < locCount; locIndex++) { errorCode=U_ZERO_ERROR; currLoc = uloc_getAvailable(locIndex); currentLocale = ures_open(NULL, currLoc, &errorCode); if(errorCode != U_ZERO_ERROR) { if(U_SUCCESS(errorCode)) { /* It's installed, but there is no data. It's installed for the g18n white paper [grhoten] */ log_err("ERROR: Locale %-5s not installed, and it should be!\n", uloc_getAvailable(locIndex)); } else { log_err("%%%%%%% Unexpected error %d in %s %%%%%%%", u_errorName(errorCode), uloc_getAvailable(locIndex)); } ures_close(currentLocale); continue; } ures_getStringByKey(currentLocale, "Version", NULL, &errorCode); if(errorCode != U_ZERO_ERROR) { log_err("No version information is available for locale %s, and it should be!\n", currLoc); } else if (ures_getStringByKey(currentLocale, "Version", NULL, &errorCode)[0] == (UChar)(0x78)) { log_verbose("WARNING: The locale %s is experimental! It shouldn't be listed as an installed locale.\n", currLoc); } TestKeyInRootRecursive(root, "root", currentLocale, currLoc); completeSubtable = ures_getByKey(completeLoc, "Currencies", NULL, &errorCode); subtable = ures_getByKey(currentLocale, "Currencies", NULL, &errorCode); TestKeyInRootRecursive(completeSubtable, "en", subtable, currLoc); testLCID(currentLocale, currLoc); ures_close(completeSubtable); ures_close(subtable); ures_close(currentLocale); } ures_close(root); ures_close(completeLoc); } static void compareArrays(const char *keyName, UResourceBundle *fromArray, const char *fromLocale, UResourceBundle *toArray, const char *toLocale, int32_t start, int32_t end) { int32_t fromSize = ures_getSize(fromArray); int32_t toSize = ures_getSize(fromArray); int32_t idx; UErrorCode errorCode = U_ZERO_ERROR; if (fromSize > toSize) { fromSize = toSize; log_err("Arrays are different size from \"%s\" to \"%s\"\n", fromLocale, toLocale); } for (idx = start; idx <= end; idx++) { const UChar *fromBundleStr = ures_getStringByIndex(fromArray, idx, NULL, &errorCode); const UChar *toBundleStr = ures_getStringByIndex(toArray, idx, NULL, &errorCode); if (fromBundleStr && toBundleStr && u_strcmp(fromBundleStr, toBundleStr) != 0) { log_err("Difference for %s at index %d from %s= \"%s\" to %s= \"%s\"\n", keyName, idx, fromLocale, austrdup(fromBundleStr), toLocale, austrdup(toBundleStr)); } } } static void compareConsistentCountryInfo(const char *fromLocale, const char *toLocale) { UErrorCode errorCode = U_ZERO_ERROR; UResourceBundle *fromDateTimeElements, *toDateTimeElements; UResourceBundle *fromArray, *toArray; UResourceBundle *fromLocaleBund = ures_open(NULL, fromLocale, &errorCode); UResourceBundle *toLocaleBund = ures_open(NULL, toLocale, &errorCode); if(U_FAILURE(errorCode)) { log_err("Can't open resource bundle %s or %s - %s\n", fromLocale, toLocale, u_errorName(errorCode)); return; } fromDateTimeElements = ures_getByKey(fromLocaleBund, "DateTimeElements", NULL, &errorCode); toDateTimeElements = ures_getByKey(toLocaleBund, "DateTimeElements", NULL, &errorCode); if (strcmp(fromLocale, "ar_IN") != 0) { int32_t fromSize; int32_t toSize; int32_t idx; const int32_t *fromBundleArr = ures_getIntVector(fromDateTimeElements, &fromSize, &errorCode); const int32_t *toBundleArr = ures_getIntVector(toDateTimeElements, &toSize, &errorCode); if (fromSize > toSize) { fromSize = toSize; log_err("Arrays are different size with key \"DateTimeElements\" from \"%s\" to \"%s\"\n", fromLocale, toLocale); } for (idx = 0; idx < fromSize; idx++) { if (fromBundleArr[idx] != toBundleArr[idx]) { log_err("Difference with key \"DateTimeElements\" at index %d from \"%s\" to \"%s\"\n", idx, fromLocale, toLocale); } } } ures_close(fromDateTimeElements); ures_close(toDateTimeElements); fromArray = ures_getByKey(fromLocaleBund, "CurrencyElements", NULL, &errorCode); toArray = ures_getByKey(toLocaleBund, "CurrencyElements", NULL, &errorCode); if (strcmp(fromLocale, "en_CA") != 0) { /* The first one is probably localized. */ compareArrays("CurrencyElements", fromArray, fromLocale, toArray, toLocale, 1, 2); } ures_close(fromArray); ures_close(toArray); fromArray = ures_getByKey(fromLocaleBund, "NumberPatterns", NULL, &errorCode); toArray = ures_getByKey(toLocaleBund, "NumberPatterns", NULL, &errorCode); if (strcmp(fromLocale, "en_CA") != 0) { compareArrays("NumberPatterns", fromArray, fromLocale, toArray, toLocale, 0, 3); } ures_close(fromArray); ures_close(toArray); /* Difficult to test properly */ /* fromArray = ures_getByKey(fromLocaleBund, "DateTimePatterns", NULL, &errorCode); toArray = ures_getByKey(toLocaleBund, "DateTimePatterns", NULL, &errorCode); { compareArrays("DateTimePatterns", fromArray, fromLocale, toArray, toLocale); } ures_close(fromArray); ures_close(toArray);*/ fromArray = ures_getByKey(fromLocaleBund, "NumberElements", NULL, &errorCode); toArray = ures_getByKey(toLocaleBund, "NumberElements", NULL, &errorCode); if (strcmp(fromLocale, "en_CA") != 0) { compareArrays("NumberElements", fromArray, fromLocale, toArray, toLocale, 0, 3); /* Index 4 is a script based 0 */ compareArrays("NumberElements", fromArray, fromLocale, toArray, toLocale, 5, 10); } ures_close(fromArray); ures_close(toArray); ures_close(fromLocaleBund); ures_close(toLocaleBund); } static void TestConsistentCountryInfo(void) { /* UResourceBundle *fromLocale, *toLocale;*/ int32_t locCount = uloc_countAvailable(); int32_t fromLocIndex, toLocIndex; int32_t fromCountryLen, toCountryLen; char fromCountry[ULOC_FULLNAME_CAPACITY], toCountry[ULOC_FULLNAME_CAPACITY]; int32_t fromVariantLen, toVariantLen; char fromVariant[ULOC_FULLNAME_CAPACITY], toVariant[ULOC_FULLNAME_CAPACITY]; UErrorCode errorCode = U_ZERO_ERROR; for (fromLocIndex = 0; fromLocIndex < locCount; fromLocIndex++) { const char *fromLocale = uloc_getAvailable(fromLocIndex); errorCode=U_ZERO_ERROR; fromCountryLen = uloc_getCountry(fromLocale, fromCountry, ULOC_FULLNAME_CAPACITY, &errorCode); if (fromCountryLen <= 0) { /* Ignore countryless locales */ continue; } fromVariantLen = uloc_getVariant(fromLocale, fromVariant, ULOC_FULLNAME_CAPACITY, &errorCode); if (fromVariantLen > 0) { /* Most variants are ignorable like PREEURO, or collation variants. */ continue; } /* Start comparing only after the current index. Previous loop should have already compared fromLocIndex. */ for (toLocIndex = fromLocIndex + 1; toLocIndex < locCount; toLocIndex++) { const char *toLocale = uloc_getAvailable(toLocIndex); toCountryLen = uloc_getCountry(toLocale, toCountry, ULOC_FULLNAME_CAPACITY, &errorCode); if(U_FAILURE(errorCode)) { log_err("Unknown failure fromLocale=%s toLocale=%s errorCode=%s\n", fromLocale, toLocale, u_errorName(errorCode)); continue; } if (toCountryLen <= 0) { /* Ignore countryless locales */ continue; } toVariantLen = uloc_getVariant(toLocale, toVariant, ULOC_FULLNAME_CAPACITY, &errorCode); if (toVariantLen > 0) { /* Most variants are ignorable like PREEURO, or collation variants. */ /* They're a variant for a reason. */ continue; } if (strcmp(fromCountry, toCountry) == 0) { log_verbose("comparing fromLocale=%s toLocale=%s\n", fromLocale, toLocale); compareConsistentCountryInfo(fromLocale, toLocale); } } } } static int32_t findStringSetMismatch(const UChar *string, int32_t langSize, const UChar *exemplarCharacters, int32_t exemplarLen, UBool ignoreNumbers) { UErrorCode errorCode = U_ZERO_ERROR; USet *exemplarSet = uset_openPatternOptions(exemplarCharacters, exemplarLen, USET_CASE_INSENSITIVE, &errorCode); int32_t strIdx; if (U_FAILURE(errorCode)) { log_err("error uset_openPattern returned %s\n", u_errorName(errorCode)); return -1; } for (strIdx = 0; strIdx < langSize; strIdx++) { if (!uset_contains(exemplarSet, string[strIdx]) && string[strIdx] != 0x0020 && string[strIdx] != 0x00A0 && string[strIdx] != 0x002e && string[strIdx] != 0x002c && string[strIdx] != 0x002d && string[strIdx] != 0x0027) { if (!ignoreNumbers || (ignoreNumbers && (string[strIdx] < 0x30 || string[strIdx] > 0x39))) { return strIdx; } } } uset_close(exemplarSet); return -1; } static void findSetMatch( UScriptCode *scriptCodes, int32_t scriptsLen, const UChar *exemplarCharacters, int32_t exemplarLen, const char *locale){ USet *scripts[10]= {0}; char pattern[256] = { '[', ':', 0x000 }; UChar uPattern[256] = {0}; UErrorCode status = U_ZERO_ERROR; int32_t i; UBool testFailed = FALSE; /* create the sets with script codes */ for(i = 0; i 2048) { log_verbose("skipping test for %s\n", currLoc); } else { UChar langBuffer[128]; int32_t langSize; int32_t strIdx; langSize = uloc_getDisplayLanguage(currLoc, currLoc, langBuffer, sizeof(langBuffer)/sizeof(langBuffer[0]), &errorCode); if (U_FAILURE(errorCode)) { log_err("error uloc_getDisplayLanguage returned %s\n", u_errorName(errorCode)); } else { strIdx = findStringSetMismatch(langBuffer, langSize, exemplarCharacters, exemplarLen, FALSE); if (strIdx >= 0) { log_err("getDisplayLanguage(%s) at index %d returned characters not in the exemplar characters.\n", currLoc, strIdx); } } langSize = uloc_getDisplayCountry(currLoc, currLoc, langBuffer, sizeof(langBuffer)/sizeof(langBuffer[0]), &errorCode); if (U_FAILURE(errorCode)) { log_err("error uloc_getDisplayCountry returned %s\n", u_errorName(errorCode)); } else { strIdx = findStringSetMismatch(langBuffer, langSize, exemplarCharacters, exemplarLen, FALSE); if (strIdx >= 0) { log_err("getDisplayCountry(%s) at index %d returned characters not in the exemplar characters.\n", currLoc, strIdx); } } resArray = ures_getByKey(currentLocale, "DayNames", NULL, &errorCode); if (U_FAILURE(errorCode)) { log_err("error ures_getByKey returned %s\n", u_errorName(errorCode)); } if (QUICK) { end = 1; } else { end = ures_getSize(resArray); } for (idx = 0; idx < end; idx++) { const UChar *fromBundleStr = ures_getStringByIndex(resArray, idx, &langSize, &errorCode); if (U_FAILURE(errorCode)) { log_err("error ures_getStringByIndex(%d) returned %s\n", idx, u_errorName(errorCode)); continue; } strIdx = findStringSetMismatch(fromBundleStr, langSize, exemplarCharacters, exemplarLen, TRUE); if (strIdx >= 0) { log_err("getDayNames(%s, %d) at index %d returned characters not in the exemplar characters.\n", currLoc, idx, strIdx); } } ures_close(resArray); resArray = ures_getByKey(currentLocale, "MonthNames", NULL, &errorCode); if (U_FAILURE(errorCode)) { log_err("error ures_getByKey returned %s\n", u_errorName(errorCode)); } if (QUICK) { end = 1; } else { end = ures_getSize(resArray); } for (idx = 0; idx < end; idx++) { const UChar *fromBundleStr = ures_getStringByIndex(resArray, idx, &langSize, &errorCode); if (U_FAILURE(errorCode)) { log_err("error ures_getStringByIndex(%d) returned %s\n", idx, u_errorName(errorCode)); continue; } strIdx = findStringSetMismatch(fromBundleStr, langSize, exemplarCharacters, exemplarLen, TRUE); if (strIdx >= 0) { log_err("getMonthNames(%s, %d) at index %d returned characters not in the exemplar characters.\n", currLoc, idx, strIdx); } } ures_close(resArray); errorCode = U_ZERO_ERROR; numScripts = uscript_getCode(currLoc, scripts, sizeof(scripts)/sizeof(scripts[0]), &errorCode); if (numScripts == 0) { log_err("uscript_getCode(%s) doesn't work.\n", currLoc); }else if(scripts[0] == USCRIPT_COMMON){ log_err("uscript_getCode(%s) returned USCRIPT_COMMON.\n", currLoc); } /* test if exemplar characters are part of script code */ findSetMatch(scripts, numScripts, exemplarCharacters, exemplarLen, currLoc); /* TODO: test that the scripts are a superset of exemplar characters. */ } ures_close(currentLocale); } ures_close(root); } static void MoreVariants(void) { struct { const char *localeID; const char *keyword; const char *expectedValue; } testCases[] = { { "de_DE_EURO@collation=PHONEBOOK", "collation", "PHONEBOOK" }, { "es_ES.utf8@euro", "collation", ""}, { "es_ES.hello.utf8@euro", "", "" }, { " s pa c e d _ more spaces _ spaced variant ", "", ""} }; UErrorCode status = U_ZERO_ERROR; int32_t i = 0; int32_t resultLen = 0; char buffer[256]; for(i = 0; i < sizeof(testCases)/sizeof(testCases[0]); i++) { *buffer = 0; resultLen = uloc_getName(testCases[i].localeID, buffer, 256, &status); if(uprv_strcmp(testCases[i].expectedValue, buffer) != 0) { log_err("Expected to extract \"%s\" from \"%s\" for keyword \"%s\". Got \"%s\" instead\n", testCases[i].expectedValue, testCases[i].localeID, testCases[i].keyword, buffer); } } } static void TestKeywordVariants(void) { struct { const char *localeID; const char *expectedLocaleID; const char *expectedLocaleIDNoKeywords; const char *expectedKeywords[10]; int32_t numKeywords; UErrorCode expectedStatus; } testCases[] = { { "de_DE@ currency = euro; C o ll A t i o n = Phonebook ; C alen dar = budhist ", "de_DE@c alen dar=budhist;c o ll a t i o n=Phonebook;currency=euro", "de_DE", { "c alen dar", "c o ll a t i o n", "currency"}, 3, U_ZERO_ERROR }, { "de_DE@euro", "de_DE_EURO", "de_DE", {""}, 0, U_INVALID_FORMAT_ERROR}, /*{ "de_DE@euro;collation=phonebook", "", "", U_INVALID_FORMAT_ERROR}*/ }; UErrorCode status = U_ZERO_ERROR; int32_t i = 0, j = 0; int32_t resultLen = 0; char buffer[256]; UEnumeration *keywords; int32_t keyCount = 0; const char *keyword = NULL; int32_t keywordLen = 0; for(i = 0; i < sizeof(testCases)/sizeof(testCases[0]); i++) { status = U_ZERO_ERROR; *buffer = 0; keywords = uloc_getKeywords(testCases[i].localeID, &status); if(status != testCases[i].expectedStatus) { log_err("Expected to get status %s. Got %s instead\n", u_errorName(testCases[i].expectedStatus), u_errorName(status)); } status = U_ZERO_ERROR; if(keywords) { if((keyCount = uenum_count(keywords, &status)) != testCases[i].numKeywords) { log_err("Expected to get %i keywords, got %i\n", testCases[i].numKeywords, keyCount); } if(keyCount) { j = 0; while(keyword = uenum_next(keywords, &keywordLen, &status)) { if(strcmp(keyword, testCases[i].expectedKeywords[j]) != 0) { log_err("Expected to get keyword value %s, got %s\n", testCases[i].expectedKeywords[j], keyword); } j++; } } uenum_close(keywords); } resultLen = uloc_getName(testCases[i].localeID, buffer, 256, &status); if(uprv_strcmp(testCases[i].expectedLocaleID, buffer) != 0) { log_err("Expected to get \"%s\" from \"%s\". Got \"%s\" instead\n", testCases[i].expectedLocaleID, testCases[i].localeID, buffer); } } } static void TestKeywordVariantParsing(void) { struct { const char *localeID; const char *keyword; const char *expectedValue; } testCases[] = { { "de_DE@ C o ll A t i o n = Phonebook ", "c o ll a t i o n", "Phonebook" }, { "de_DE", "collation", ""}, { "de_DE@collation=PHONEBOOK", "collation", "PHONEBOOK" }, { "de_DE@currency = euro; CoLLaTion = PHONEBOOk", "collatiON", "PHONEBOOk" }, }; UErrorCode status = U_ZERO_ERROR; int32_t i = 0; int32_t resultLen = 0; char buffer[256]; for(i = 0; i < sizeof(testCases)/sizeof(testCases[0]); i++) { *buffer = 0; resultLen = uloc_getKeywordValue(testCases[i].localeID, testCases[i].keyword, buffer, 256, &status); if(uprv_strcmp(testCases[i].expectedValue, buffer) != 0) { log_err("Expected to extract \"%s\" from \"%s\" for keyword \"%s\". Got \"%s\" instead\n", testCases[i].expectedValue, testCases[i].localeID, testCases[i].keyword, buffer); } } } static void TestCanonicalization(void) { struct { const char *localeID; const char *expectedValue; const char *expectedValueNoKeywords; } testCases[] = { { "ca_ES_PREEURO-with-extra-stuff-that really doesn't make any sense-unless-you're trying to increase code coverage", "ca_ES_PREEURO_WITH_EXTRA_STUFF_THAT REALLY DOESN'T MAKE ANY SENSE_UNLESS_YOU'RE TRYING TO INCREASE CODE COVERAGE", "ca_ES_PREEURO_WITH_EXTRA_STUFF_THAT REALLY DOESN'T MAKE ANY SENSE_UNLESS_YOU'RE TRYING TO INCREASE CODE COVERAGE"}, { "ca_ES_PREEURO", "ca_ES@currency=ESP", "ca_ES"}, { "de_AT_PREEURO", "de_AT@currency=ATS", "de_AT" }, { "de_DE_PREEURO", "de_DE@currency=DEM", "de_DE" }, { "de_LU_PREEURO", "de_LU@currency=EUR", "de_LU" }, { "el_GR_PREEURO", "el_GR@currency=GRD", "el_GR" }, { "en_BE_PREEURO", "en_BE@currency=BEF", "en_BE" }, { "en_IE_PREEURO", "en_IE@currency=IEP", "en_IE" }, { "es_ES_PREEURO", "es_ES@currency=ESP", "es_ES" }, { "eu_ES_PREEURO", "eu_ES@currency=ESP", "eu_ES" }, { "fi_FI_PREEURO", "fi_FI@currency=FIM", "fi_FI" }, { "fr_BE_PREEURO", "fr_BE@currency=BEF", "fr_BE" }, { "fr_FR_PREEURO", "fr_FR@currency=FRF", "fr_FR" }, { "fr_LU_PREEURO", "fr_LU@currency=LUF", "fr_LU" }, { "ga_IE_PREEURO", "ga_IE@currency=IEP", "ga_IE" }, { "gl_ES_PREEURO", "gl_ES@currency=ESP", "gl_ES" }, { "it_IT_PREEURO", "it_IT@currency=ITL", "it_IT" }, { "nl_BE_PREEURO", "nl_BE@currency=BEF", "nl_BE" }, { "nl_NL_PREEURO", "nl_NL@currency=NLG", "nl_NL" }, { "pt_PT_PREEURO", "pt_PT@currency=PTE", "pt_PT" }, { "de__PHONEBOOK", "de@collation=phonebook", "de" }, { "en_GB_EURO", "en_GB@currency=EUR", "en_GB" }, { "es__TRADITIONAL", "es@collation=traditional", "es" }, { "hi__DIRECT", "hi@collation=direct", "hi" }, { "ja_JP_TRADITIONAL", "ja_JP@calendar=japanese", "ja_JP" }, { "th_TH_TRADITIONAL", "th_TH@calendar=buddhist", "th_TH" }, { "zh_TW_STROKE", "zh_TW@collation=stroke", "zh_TW" }, { "zh__PINYIN", "zh@collation=pinyin", "zh" }, { "en_US_POSIX", "en_US_POSIX", "en_US_POSIX" }, { "hy_AM_REVISED", "hy_AM_REVISED", "hy_AM_REVISED" }, { "no_NO_NY", "no_NO_NY", "no_NO_NY" }, { "qz-qz@Euro", "qz_QZ@currency=EUR", "qz_QZ@currency=EUR" }, /* qz-qz uses private use iso codes */ { "en-BOONT", "en__BOONT", "en__BOONT" }, /* registered name */ { "de-1901", "de__1901", "de__1901" }, /* registered name */ { "de-1906", "de__1906", "de__1906" }, /* registered name */ { "sr-SP-Cyrl", "sr_Cyrl_SP", "sr_Cyrl_SP" }, /* .NET name */ { "sr-SP-Latn", "sr_Latn_SP", "sr_Latn_SP" }, /* .NET name */ { "uz-UZ-Cyrl", "uz_Cyrl_UZ", "uz_Cyrl_UZ" }, /* .NET name */ { "uz-UZ-Latn", "uz_Latn_UZ", "uz_Latn_UZ" }, /* .NET name */ { "zh-CHS", "zh_Hans", "zh_Hans" }, /* .NET name */ { "zh-CHT", "zh_Hant", "zh_Hant" }, /* .NET name */ }; UErrorCode status = U_ZERO_ERROR; int32_t i = 0; int32_t resultLen = 0; int32_t origResultLen; char buffer[256]; for(i = 0; i < sizeof(testCases)/sizeof(testCases[0]); i++) { *buffer = 0; status = U_ZERO_ERROR; origResultLen = uloc_canonicalize(testCases[i].localeID, NULL, 0, &status); if (status != U_BUFFER_OVERFLOW_ERROR) { log_err("%s status == %s instead of U_BUFFER_OVERFLOW_ERROR\n", testCases[i].localeID, u_errorName(status)); } status = U_ZERO_ERROR; resultLen = uloc_canonicalize(testCases[i].localeID, buffer, sizeof(buffer), &status); if (U_FAILURE(status)) { log_err("status = %s\n", u_errorName(status)); } if(uprv_strcmp(testCases[i].expectedValue, buffer) != 0) { log_err("Expected to get \"%s\" from \"%s\". Got \"%s\" instead\n", testCases[i].expectedValue, testCases[i].localeID, buffer); } if (resultLen != (int32_t)strlen(buffer)) { log_err("\"%s\" returned len=%d instead of len=%d\n", testCases[i].localeID, resultLen, strlen(buffer)); } if (origResultLen != resultLen) { log_err("\"%s\" returned origResultLen=%d differs from resultLen=%d\n", testCases[i].localeID, origResultLen, resultLen); } /* resultLen = uloc_getNameNoKeywords(testCases[i].localeID, buffer, 256, &status); if(uprv_strcmp(testCases[i].expectedValueNoKeywords, buffer) != 0) { log_err("Expected to get \"%s\" from \"%s\". Got \"%s\" instead\n", testCases[i].expectedValueNoKeywords, testCases[i].localeID, buffer); }*/ } }