/******************************************************************** * COPYRIGHT: * Copyright (c) 1997-2004, International Business Machines Corporation and * others. All Rights Reserved. ********************************************************************/ /******************************************************************************** * * File CLOCTST.C * * Modification History: * Name Description * Madhu Katragadda Ported for C API ********************************************************************************* */ #include "cloctst.h" #include #include #include #include "cintltst.h" #include "cmemory.h" #include "cstring.h" #include "locmap.h" #include "uresimp.h" #include "uassert.h" #include "unicode/putil.h" #include "unicode/ubrk.h" #include "unicode/uchar.h" #include "unicode/ucol.h" #include "unicode/udat.h" #include "unicode/uloc.h" #include "unicode/ulocdata.h" #include "unicode/umsg.h" #include "unicode/ures.h" #include "unicode/uscript.h" #include "unicode/uset.h" #include "unicode/ustring.h" #include "unicode/utypes.h" #include "unicode/ulocdata.h" #include "unicode/parseerr.h" /* may not be included with some uconfig switches */ #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0])) static void TestNullDefault(void); static void VerifyTranslation(void); static void TestExemplarSet(void); void PrintDataTable(); /*--------------------------------------------------- table of valid data --------------------------------------------------- */ #define LOCALE_SIZE 9 #define LOCALE_INFO_SIZE 28 static const char* rawData2[LOCALE_INFO_SIZE][LOCALE_SIZE] = { /* language code */ { "en", "fr", "ca", "el", "no", "zh", "de", "es", "ja" }, /* script code */ { "", "", "", "", "", "Hans", "", "", "" }, /* country code */ { "US", "FR", "ES", "GR", "NO", "CN", "DE", "", "JP" }, /* variant code */ { "", "", "", "", "NY", "", "", "", "" }, /* full name */ { "en_US", "fr_FR", "ca_ES", "el_GR", "no_NO_NY", "zh_Hans_CN", "de_DE@collation=phonebook", "es@collation=traditional", "ja_JP@calendar=japanese" }, /* ISO-3 language */ { "eng", "fra", "cat", "ell", "nor", "zho", "deu", "spa", "jpn" }, /* ISO-3 country */ { "USA", "FRA", "ESP", "GRC", "NOR", "CHN", "DEU", "", "JPN" }, /* LCID */ { "409", "40c", "403", "408", "814", "804", "407", "a", "411" }, /* display language (English) */ { "English", "French", "Catalan", "Greek", "Norwegian", "Chinese", "German", "Spanish", "Japanese" }, /* display script code (English) */ { "", "", "", "", "", "Simplified Han", "", "", "" }, /* display country (English) */ { "United States", "France", "Spain", "Greece", "Norway", "China", "Germany", "", "Japan" }, /* display variant (English) */ { "", "", "", "", "NY", "", "", "", "" }, /* display name (English) */ { "English (United States)", "French (France)", "Catalan (Spain)", "Greek (Greece)", "Norwegian (Norway, NY)", "Chinese (Simplified Han, China)", "German (Germany, Collation=Phonebook Order)", "Spanish (Collation=Traditional)", "Japanese (Japan, Calendar=Japanese Calendar)" }, /* display language (French) */ { "anglais", "fran\\u00E7ais", "catalan", "grec", "norv\\u00E9gien", "chinois", "allemand", "espagnol", "japonais" }, /* display script code (French) */ { "", "", "", "", "", "han simplifi\\u00E9", "", "", "" }, /* display country (French) */ { "\\u00C9tats-Unis", "France", "Espagne", "Gr\\u00E8ce", "Norv\\u00E8ge", "Chine", "Allemagne", "", "Japon" }, /* display variant (French) */ { "", "", "", "", "NY", "", "", "", "" }, /* display name (French) */ { "anglais (\\u00C9tats-Unis)", "fran\\u00E7ais (France)", "catalan (Espagne)", "grec (Gr\\u00E8ce)", "norv\\u00E9gien (Norv\\u00E8ge, NY)", "chinois (han simplifi\\u00E9, Chine)", "allemand (Allemagne, Ordonnancement=Ordre de l\\u2019annuaire)", "espagnol (Ordonnancement=Ordre traditionnel)", "japonais (Japon, Calendrier=Calendrier japonais)" }, /* display language (Catalan) */ { "angl\\u00E8s", "franc\\u00E8s", "catal\\u00E0", "grec", "noruec", "xin\\u00E9s", "alemany", "espanyol", "japon\\u00E8s" }, /* display script code (Catalan) */ { "", "", "", "", "", "Hans", "", "", "" }, /* display country (Catalan) */ { "Estats Units", "Fran\\u00E7a", "Espanya", "Gr\\u00E8cia", "Noruega", "Xina", "Alemanya", "", "Jap\\u00F3" }, /* 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)", "alemany (Alemanya, COLLATION=PHONEBOOK)", "espanyol (COLLATION=TRADITIONAL)", "japon\\u00E8s (Jap\\u00F3, CALENDAR=JAPANESE)" }, /* 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", "\\u0393\\u03B5\\u03C1\\u03BC\\u03B1\\u03BD\\u03B9\\u03BA\\u03AC", "\\u0399\\u03C3\\u03C0\\u03B1\\u03BD\\u03B9\\u03BA\\u03AC", "\\u0399\\u03B1\\u03C0\\u03C9\\u03BD\\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", "\\u0393\\u03B5\\u03C1\\u03BC\\u03B1\\u03BD\\u03AF\\u03B1", "", "\\u0399\\u03B1\\u03C0\\u03C9\\u03BD\\u03AF\\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)", "\\u0393\\u03B5\\u03C1\\u03BC\\u03B1\\u03BD\\u03B9\\u03BA\\u03AC (\\u0393\\u03B5\\u03C1\\u03BC\\u03B1\\u03BD\\u03AF\\u03B1, COLLATION=PHONEBOOK)", "\\u0399\\u03C3\\u03C0\\u03B1\\u03BD\\u03B9\\u03BA\\u03AC (COLLATION=TRADITIONAL)", "\\u0399\\u03B1\\u03C0\\u03C9\\u03BD\\u03B9\\u03BA\\u03AC (\\u0399\\u03B1\\u03C0\\u03C9\\u03BD\\u03AF\\u03B1, CALENDAR=JAPANESE)" } }; 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 }; #define TESTCASE(name) addTest(root, &name, "tsutil/cloctst/" #name) void addLocaleTest(TestNode** root); void addLocaleTest(TestNode** root) { TESTCASE(TestObsoleteNames); /* srl- move */ TESTCASE(TestBasicGetters); TESTCASE(TestNullDefault); TESTCASE(TestPrefixes); TESTCASE(TestSimpleResourceInfo); TESTCASE(TestDisplayNames); TESTCASE(TestGetAvailableLocales); TESTCASE(TestDataDirectory); TESTCASE(TestISOFunctions); TESTCASE(TestISO3Fallback); TESTCASE(TestUninstalledISO3Names); TESTCASE(TestSimpleDisplayNames); TESTCASE(TestVariantParsing); TESTCASE(TestLocaleStructure); TESTCASE(TestConsistentCountryInfo); TESTCASE(VerifyTranslation); /*TESTCASE(MoreVariants);*/ TESTCASE(TestKeywordVariants); TESTCASE(TestKeywordVariantParsing); TESTCASE(TestCanonicalization); TESTCASE(TestDisplayKeywords); TESTCASE(TestDisplayKeywordValues); TESTCASE(TestGetBaseName); TESTCASE(TestGetLocale); TESTCASE(TestExemplarSet); } /* 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, *expected; const char *testData[][7] = { /* NULL canonicalize() column means "expect same as getName()" */ {"sv", "", "FI", "AL", "sv-fi-al", "sv_FI_AL", NULL}, {"en", "", "GB", "", "en-gb", "en_GB", NULL}, {"i-hakka", "", "MT", "XEMXIJA", "i-hakka_MT_XEMXIJA", "i-hakka_MT_XEMXIJA", NULL}, {"i-hakka", "", "CN", "", "i-hakka_CN", "i-hakka_CN", NULL}, {"i-hakka", "", "MX", "", "I-hakka_MX", "i-hakka_MX", NULL}, {"x-klingon", "", "US", "SANJOSE", "X-KLINGON_us_SANJOSE", "x-klingon_US_SANJOSE", NULL}, {"mr", "", "", "", "mr.utf8", "mr.utf8", "mr"}, {"de", "", "TV", "", "de-tv.koi8r", "de_TV.koi8r", "de_TV"}, {"x-piglatin", "", "ML", "", "x-piglatin_ML.MBE", "x-piglatin_ML.MBE", "x-piglatin_ML"}, /* Multibyte English */ {"i-cherokee", "","US", "", "i-Cherokee_US.utf7", "i-cherokee_US.utf7", "i-cherokee_US"}, {"x-filfli", "", "MT", "FILFLA", "x-filfli_MT_FILFLA.gb-18030", "x-filfli_MT_FILFLA.gb-18030", "x-filfli_MT_FILFLA"}, {"no", "", "NO", "NY", "no-no-ny.utf32@B", "no_NO_NY.utf32@B", "no_NO_NY_B"}, {"no", "", "NO", "", "no-no.utf32@B", "no_NO.utf32@B", "no_NO_B"}, {"no", "", "", "NY", "no__ny", "no__NY", NULL}, {"no", "", "", "", "no@ny", "no@ny", "no__NY"}, {"el", "Latn", "", "", "el-latn", "el_Latn", NULL}, {"en", "Cyrl", "RU", "", "en-cyrl-ru", "en_Cyrl_RU", NULL}, {"zh", "Hant", "TW", "STROKE", "zh-hant_TW_STROKE", "zh_Hant_TW_STROKE", NULL}, {"qq", "Qqqq", "QQ", "QQ", "qq_Qqqq_QQ_QQ", "qq_Qqqq_QQ_QQ", NULL}, {"qq", "Qqqq", "", "QQ", "qq_Qqqq__QQ", "qq_Qqqq__QQ", NULL}, {"12", "3456", "78", "90", "12_3456_78_90", "12_3456_78_90", NULL}, /* total garbage */ {NULL,NULL,NULL,NULL,NULL,NULL,NULL} }; const char *testTitles[] = { "uloc_getLanguage()", "uloc_getScript()", "uloc_getCountry()", "uloc_getVariant()", "name", "uloc_getName()", "uloc_canonicalize()" }; char buf[PREFIXBUFSIZ]; int32_t len; UErrorCode err; for(row=0;testData[row][0] != NULL;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+2);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]); } expected = testData[row][n]; if (expected == NULL && n == (NAME+2)) { /* NULL expected canonicalize() means "expect same as getName()" */ expected = testData[row][NAME+1]; } if(strcmp(buf, expected)) { log_err("#%d: %s on %s: -> [%s] (expected '%s'!)\n", row, testTitles[n], loc, buf, expected); } } } } } /* 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", (int)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; 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 && !isCurrencyPreEuro(subBundleKey))) && 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) { /* Check well-formedness of localPatternChars. First, the * length must match the number of fields defined by * DateFormat. Second, each character in the string must * be in the set [A-Za-z]. Finally, each character must be * unique. */ int32_t i,j; #if !UCONFIG_NO_FORMATTING if (len != UDAT_FIELD_COUNT) { log_err("key \"%s\" has the wrong number of characters in locale \"%s\"\n", subBundleKey, locale); } #endif /* Check char validity. */ for (i=0; i= 65/*'A'*/ && string[i] <= 90/*'Z'*/) || (string[i] >= 97/*'a'*/ && string[i] <= 122/*'z'*/))) { log_err("key \"%s\" has illegal character '%c' in locale \"%s\"\n", subBundleKey, (char) string[i], locale); } /* Do O(n^2) check for duplicate chars. */ for (j=0; j 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); UResourceBundle *toCalendar, *fromCalendar, *toGregorian, *fromGregorian; if(U_FAILURE(errorCode)) { log_err("Can't open resource bundle %s or %s - %s\n", fromLocale, toLocale, u_errorName(errorCode)); return; } fromCalendar = ures_getByKey(fromLocaleBund, "calendar", NULL, &errorCode); fromGregorian = ures_getByKeyWithFallback(fromCalendar, "gregorian", NULL, &errorCode); fromDateTimeElements = ures_getByKeyWithFallback(fromGregorian, "DateTimeElements", NULL, &errorCode); toCalendar = ures_getByKey(toLocaleBund, "calendar", NULL, &errorCode); toGregorian = ures_getByKeyWithFallback(toCalendar, "gregorian", NULL, &errorCode); toDateTimeElements = ures_getByKeyWithFallback(toGregorian, "DateTimeElements", NULL, &errorCode); if(U_FAILURE(errorCode)){ log_err("Did not get DateTimeElements from the bundle %s or %s\n", fromLocale, toLocale); return; } ures_close(fromCalendar); ures_close(toCalendar); ures_close(fromGregorian); ures_close(toGregorian); 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, USet *exemplarSet, const char *locale){ USet *scripts[10]= {0}; char pattern[256] = { '[', ':', 0x000 }; UChar uPattern[256] = {0}; UErrorCode status = U_ZERO_ERROR; int32_t i; /* 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); } } { UResourceBundle* cal = ures_getByKey(currentLocale, "calendar", NULL, &errorCode); UResourceBundle* greg = ures_getByKeyWithFallback(cal, "gregorian", NULL, &errorCode); UResourceBundle* names = ures_getByKeyWithFallback(greg, "dayNames", NULL, &errorCode); UResourceBundle* format = ures_getByKeyWithFallback(names, "format", NULL, &errorCode); resArray = ures_getByKeyWithFallback(format, "wide", 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); ures_close(format); ures_close(names); names = ures_getByKeyWithFallback(greg, "monthNames", NULL, &errorCode); format = ures_getByKeyWithFallback(names,"format", NULL, &errorCode); resArray = ures_getByKeyWithFallback(format, "wide", 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); ures_close(format); ures_close(names); ures_close(greg); ures_close(cal); } 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 that the scripts are a superset of exemplar characters. */ { USet *exemplarSet = ulocdata_getExemplarSet(NULL,currLoc, 0, &errorCode); /* test if exemplar characters are part of script code */ findSetMatch(scripts, numScripts, exemplarSet, currLoc); uset_close(exemplarSet); } /* test that the paperSize API works */ { int32_t height=0, width=0; ulocdata_getPaperSize(currLoc, &height, &width, &errorCode); if(U_FAILURE(errorCode)){ log_err("ulocdata_getPaperSize failed for locale %s with error: %s \n", currLoc, u_errorName(errorCode)); } if(strstr(currLoc, "_US")!=NULL && height != 279 && width != 216 ){ log_err("ulocdata_getPaperSize did not return expected data for locale %s \n", currLoc); } } /* test that the MeasurementSystem works API works */ { UMeasurementSystem measurementSystem = ulocdata_getMeasurementSystem(currLoc, &errorCode); if(U_FAILURE(errorCode)){ log_err("ulocdata_getMeasurementSystem failed for locale %s with error: %s \n", currLoc, u_errorName(errorCode)); } if(strstr(currLoc, "_US")!=NULL){ if(measurementSystem != UMS_US){ log_err("ulocdata_getMeasurementSystem did not return expected data for locale %s \n", currLoc); } }else if(measurementSystem != UMS_SI){ log_err("ulocdata_getMeasurementSystem did not return expected data for locale %s \n", currLoc); } } } 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 *expectedCanonicalID; const char *expectedKeywords[10]; int32_t numKeywords; UErrorCode expectedStatus; /* from uloc_openKeywords */ } testCases[] = { { "de_DE@ currency = euro; C o ll A t i o n = Phonebook ; C alen dar = buddhist ", "de_DE@calendar=buddhist;collation=Phonebook;currency=euro", "de_DE", "de_DE@calendar=buddhist;collation=Phonebook;currency=euro", {"calendar", "collation", "currency"}, 3, U_ZERO_ERROR }, { "de_DE@euro", "de_DE@euro", "de_DE", "de_DE@currency=EUR", {"","","","","","",""}, 0, U_INVALID_FORMAT_ERROR /* must have '=' after '@' */ }, { "de_DE@euro;collation=phonebook", "de_DE", /* error result; bad format */ "de_DE", /* error result; bad format */ "de_DE", /* error result; bad format */ {"","","","","","",""}, 0, 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_openKeywords(testCases[i].localeID, &status); if(status != testCases[i].expectedStatus) { log_err("Expected to uloc_openKeywords(\"%s\") => status %s. Got %s instead\n", testCases[i].localeID, 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 uloc_getName(\"%s\") => \"%s\"; got \"%s\"\n", testCases[i].localeID, testCases[i].expectedLocaleID, buffer); } resultLen = uloc_canonicalize(testCases[i].localeID, buffer, 256, &status); if (uprv_strcmp(testCases[i].expectedCanonicalID, buffer) != 0) { log_err("Expected uloc_canonicalize(\"%s\") => \"%s\"; got \"%s\"\n", testCases[i].localeID, testCases[i].expectedCanonicalID, 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 int32_t _canonicalize(int32_t selector, /* 0==getName, 1==canonicalize */ const char* localeID, char* result, int32_t resultCapacity, UErrorCode* ec) { /* YOU can change this to use function pointers if you like */ switch (selector) { case 0: return uloc_getName(localeID, result, resultCapacity, ec); case 1: return uloc_canonicalize(localeID, result, resultCapacity, ec); default: return -1; } } static void TestCanonicalization(void) { static struct { const char *localeID; /* input */ const char *getNameID; /* expected getName() result */ const char *canonicalID; /* expected canonicalize() result */ } 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_PREEURO", "ca_ES@currency=ESP" }, { "de_AT_PREEURO", "de_AT_PREEURO", "de_AT@currency=ATS" }, { "de_DE_PREEURO", "de_DE_PREEURO", "de_DE@currency=DEM" }, { "de_LU_PREEURO", "de_LU_PREEURO", "de_LU@currency=LUF" }, { "el_GR_PREEURO", "el_GR_PREEURO", "el_GR@currency=GRD" }, { "en_BE_PREEURO", "en_BE_PREEURO", "en_BE@currency=BEF" }, { "en_IE_PREEURO", "en_IE_PREEURO", "en_IE@currency=IEP" }, { "es_ES_PREEURO", "es_ES_PREEURO", "es_ES@currency=ESP" }, { "eu_ES_PREEURO", "eu_ES_PREEURO", "eu_ES@currency=ESP" }, { "fi_FI_PREEURO", "fi_FI_PREEURO", "fi_FI@currency=FIM" }, { "fr_BE_PREEURO", "fr_BE_PREEURO", "fr_BE@currency=BEF" }, { "fr_FR_PREEURO", "fr_FR_PREEURO", "fr_FR@currency=FRF" }, { "fr_LU_PREEURO", "fr_LU_PREEURO", "fr_LU@currency=LUF" }, { "ga_IE_PREEURO", "ga_IE_PREEURO", "ga_IE@currency=IEP" }, { "gl_ES_PREEURO", "gl_ES_PREEURO", "gl_ES@currency=ESP" }, { "it_IT_PREEURO", "it_IT_PREEURO", "it_IT@currency=ITL" }, { "nl_BE_PREEURO", "nl_BE_PREEURO", "nl_BE@currency=BEF" }, { "nl_NL_PREEURO", "nl_NL_PREEURO", "nl_NL@currency=NLG" }, { "pt_PT_PREEURO", "pt_PT_PREEURO", "pt_PT@currency=PTE" }, { "de__PHONEBOOK", "de__PHONEBOOK", "de@collation=phonebook" }, { "en_GB_EURO", "en_GB_EURO", "en_GB@currency=EUR" }, { "en_GB@EURO", "en_GB@EURO", "en_GB@currency=EUR" }, /* POSIX ID */ { "es__TRADITIONAL", "es__TRADITIONAL", "es@collation=traditional" }, { "hi__DIRECT", "hi__DIRECT", "hi@collation=direct" }, { "ja_JP_TRADITIONAL", "ja_JP_TRADITIONAL", "ja_JP@calendar=japanese" }, { "th_TH_TRADITIONAL", "th_TH_TRADITIONAL", "th_TH@calendar=buddhist" }, { "zh_TW_STROKE", "zh_TW_STROKE", "zh_TW@collation=stroke" }, { "zh__PINYIN", "zh__PINYIN", "zh@collation=pinyin" }, { "zh@collation=pinyin", "zh@collation=pinyin", "zh@collation=pinyin" }, { "zh_CN@collation=pinyin", "zh_CN@collation=pinyin", "zh_CN@collation=pinyin" }, { "zh_CN_CA@collation=pinyin", "zh_CN_CA@collation=pinyin", "zh_CN_CA@collation=pinyin" }, { "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" /* not: "nn_NO" [alan ICU3.0] */ }, { "no@ny", "no@ny", "no__NY" /* not: "nn" [alan ICU3.0] */ }, /* POSIX ID */ { "no-no.utf32@B", "no_NO.utf32@B", "no_NO_B" /* not: "nb_NO_B" [alan ICU3.0] */ }, /* POSIX ID */ { "qz-qz@Euro", "qz_QZ@Euro", "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_SP_CYRL", "sr_Cyrl_SP" }, /* .NET name */ { "sr-SP-Latn", "sr_SP_LATN", "sr_Latn_SP" }, /* .NET name */ { "uz-UZ-Cyrl", "uz_UZ_CYRL", "uz_Cyrl_UZ" }, /* .NET name */ { "uz-UZ-Latn", "uz_UZ_LATN", "uz_Latn_UZ" }, /* .NET name */ { "zh-CHS", "zh_CHS", "zh_Hans" }, /* .NET name */ { "zh-CHT", "zh_CHT", "zh_TW" }, /* .NET name This may change back to zh_Hant */ /* posix behavior that used to be performed by getName */ { "mr.utf8", "mr.utf8", "mr" }, { "de-tv.koi8r", "de_TV.koi8r", "de_TV" }, { "x-piglatin_ML.MBE", "x-piglatin_ML.MBE", "x-piglatin_ML" }, { "i-cherokee_US.utf7", "i-cherokee_US.utf7", "i-cherokee_US" }, { "x-filfli_MT_FILFLA.gb-18030", "x-filfli_MT_FILFLA.gb-18030", "x-filfli_MT_FILFLA" }, { "no-no-ny.utf8@B", "no_NO_NY.utf8@B", "no_NO_NY_B" /* not: "nn_NO" [alan ICU3.0] */ }, /* @ ignored unless variant is empty */ /* fleshing out canonicalization */ /* trim space and sort keywords, ';' is separator so not present at end in canonical form */ { "en_Hant_IL_VALLEY_GIRL@ currency = EUR; calendar = Japanese ;", "en_Hant_IL_VALLEY_GIRL@calendar=Japanese;currency=EUR", "en_Hant_IL_VALLEY_GIRL@calendar=Japanese;currency=EUR" }, /* already-canonical ids are not changed */ { "en_Hant_IL_VALLEY_GIRL@calendar=Japanese;currency=EUR", "en_Hant_IL_VALLEY_GIRL@calendar=Japanese;currency=EUR", "en_Hant_IL_VALLEY_GIRL@calendar=Japanese;currency=EUR" }, /* PRE_EURO and EURO conversions don't affect other keywords */ { "es_ES_PREEURO@CALendar=Japanese", "es_ES_PREEURO@calendar=Japanese", "es_ES@calendar=Japanese;currency=ESP" }, { "es_ES_EURO@SHOUT=zipeedeedoodah", "es_ES_EURO@shout=zipeedeedoodah", "es_ES@currency=EUR;shout=zipeedeedoodah" }, /* currency keyword overrides PRE_EURO and EURO currency */ { "es_ES_PREEURO@currency=EUR", "es_ES_PREEURO@currency=EUR", "es_ES@currency=EUR" }, { "es_ES_EURO@currency=ESP", "es_ES_EURO@currency=ESP", "es_ES@currency=ESP" }, /* norwegian is just too weird, if we handle things in their full generality */ { "no-Hant-GB_NY@currency=$$$", "no_Hant_GB_NY@currency=$$$", "no_Hant_GB_NY@currency=$$$" /* not: "nn_Hant_GB@currency=$$$" [alan ICU3.0] */ }, /* test cases reflecting internal resource bundle usage */ { "root@kw=foo", "root@kw=foo", "root@kw=foo" }, { "@calendar=gregorian", "@calendar=gregorian", "@calendar=gregorian" }, { "ja_JP@calendar=Japanese", "ja_JP@calendar=Japanese", "ja_JP@calendar=Japanese" }, { "ja_JP", "ja_JP", "ja_JP" } }; static const char* label[] = { "getName", "canonicalize" }; UErrorCode status = U_ZERO_ERROR; int32_t i, j, resultLen = 0, origResultLen; char buffer[256]; for (i=0; i < sizeof(testCases)/sizeof(testCases[0]); i++) { for (j=0; j<2; ++j) { const char* expected = (j==0) ? testCases[i].getNameID : testCases[i].canonicalID; *buffer = 0; status = U_ZERO_ERROR; /* log_verbose("testing %s -> %s\n", testCases[i], testCases[i].canonicalID); */ origResultLen = _canonicalize(j, testCases[i].localeID, NULL, 0, &status); if (status != U_BUFFER_OVERFLOW_ERROR) { log_err("FAIL: uloc_%s(%s) => %s, expected U_BUFFER_OVERFLOW_ERROR\n", label[j], testCases[i].localeID, u_errorName(status)); continue; } status = U_ZERO_ERROR; resultLen = _canonicalize(j, testCases[i].localeID, buffer, sizeof(buffer), &status); if (U_FAILURE(status)) { log_err("FAIL: uloc_%s(%s) => %s, expected U_ZERO_ERROR\n", label[j], testCases[i].localeID, u_errorName(status)); continue; } if(uprv_strcmp(expected, buffer) != 0) { log_err("FAIL: uloc_%s(%s) => \"%s\", expected \"%s\"\n", label[j], testCases[i].localeID, buffer, expected); } else { log_verbose("Ok: uloc_%s(%s) => \"%s\"\n", label[j], testCases[i].localeID, buffer); } if (resultLen != (int32_t)strlen(buffer)) { log_err("FAIL: uloc_%s(%s) => len %d, expected len %d\n", label[j], testCases[i].localeID, resultLen, strlen(buffer)); } if (origResultLen != resultLen) { log_err("FAIL: uloc_%s(%s) => preflight len %d != actual len %d\n", label[j], testCases[i].localeID, origResultLen, resultLen); } } } } static void TestDisplayKeywords(void) { int32_t i; static const struct { const char *localeID; const char *displayLocale; UChar displayKeyword[200]; } testCases[] = { { "ca_ES@currency=ESP", "de_AT", {0x0057, 0x00e4, 0x0068, 0x0072, 0x0075, 0x006e, 0x0067, 0x0000}, }, { "ja_JP@calendar=japanese", "de", { 0x004b, 0x0061, 0x006c, 0x0065, 0x006e, 0x0064, 0x0065, 0x0072, 0x0000} }, { "de_DE@collation=traditional", "de_DE", {0x0053, 0x006f, 0x0072, 0x0074, 0x0069, 0x0065, 0x0072, 0x0075, 0x006e, 0x0067, 0x0000} }, }; for(i = 0; i < sizeof(testCases)/sizeof(testCases[0]); i++) { UErrorCode status = U_ZERO_ERROR; const char* keyword =NULL; int32_t keywordLen = 0; int32_t keywordCount = 0; UChar *displayKeyword=NULL; int32_t displayKeywordLen = 0; UEnumeration* keywordEnum = uloc_openKeywords(testCases[i].localeID, &status); for(keywordCount = uenum_count(keywordEnum, &status); keywordCount > 0 ; keywordCount--){ if(U_FAILURE(status)){ log_err("uloc_getKeywords failed for locale id: %s with error : %s \n", testCases[i].localeID, u_errorName(status)); break; } /* the uenum_next returns NUL terminated string */ keyword = uenum_next(keywordEnum, &keywordLen, &status); /* fetch the displayKeyword */ displayKeywordLen = uloc_getDisplayKeyword(keyword, testCases[i].displayLocale, displayKeyword, displayKeywordLen, &status); if(status==U_BUFFER_OVERFLOW_ERROR){ status = U_ZERO_ERROR; displayKeywordLen++; /* for null termination */ displayKeyword = (UChar*) malloc(displayKeywordLen * U_SIZEOF_UCHAR); displayKeywordLen = uloc_getDisplayKeyword(keyword, testCases[i].displayLocale, displayKeyword, displayKeywordLen, &status); if(U_FAILURE(status)){ log_err("uloc_getDisplayKeyword filed for keyword : %s in locale id: %s for display locale: %s \n", testCases[i].localeID, keyword, testCases[i].displayLocale, u_errorName(status)); break; } if(u_strncmp(displayKeyword, testCases[i].displayKeyword, displayKeywordLen)!=0){ log_err("uloc_getDisplayKeyword did not get the expected value for keyword : %s in locale id: %s for display locale: %s \n", testCases[i].localeID, keyword, testCases[i].displayLocale); break; } }else{ log_err("uloc_getDisplayKeyword did not return the expected error. Error: %s\n", u_errorName(status)); } free(displayKeyword); } uenum_close(keywordEnum); } } static void TestDisplayKeywordValues(void){ int32_t i; struct { const char *localeID; const char *displayLocale; UChar displayKeywordValue[500]; } testCases[] = { { "ca_ES@currency=ESP", "de_AT", {0x0053, 0x0070, 0x0061, 0x006e, 0x0069, 0x0073, 0x0063, 0x0068, 0x0065, 0x0020, 0x0050, 0x0065, 0x0073, 0x0065, 0x0074, 0x0065, 0x0000} }, { "de_AT@currency=ATS", "fr_FR", {0x0073, 0x0063, 0x0068, 0x0069, 0x006c, 0x006c, 0x0069, 0x006e, 0x0067, 0x0020, 0x0061, 0x0075, 0x0074, 0x0072, 0x0069, 0x0063, 0x0068, 0x0069, 0x0065, 0x006e, 0x0000} }, { "de_DE@currency=DEM", "it", {0x004d, 0x0061, 0x0072, 0x0063, 0x006f, 0x0020, 0x0054, 0x0065, 0x0064, 0x0065, 0x0073, 0x0063, 0x006f, 0x0000} }, { "el_GR@currency=GRD", "en", {0x0047, 0x0072, 0x0065, 0x0065, 0x006b, 0x0020, 0x0044, 0x0072, 0x0061, 0x0063, 0x0068, 0x006d, 0x0061, 0x0000} }, { "eu_ES@currency=ESP", "it_IT", {0x0050, 0x0065, 0x0073, 0x0065, 0x0074, 0x0061, 0x0020, 0x0053, 0x0070, 0x0061, 0x0067, 0x006e, 0x006f, 0x006c, 0x0061, 0x0000} }, { "de@collation=phonebook", "es", {0x006F, 0x0072, 0x0064, 0x0065, 0x006E, 0x0020, 0x0064, 0x0065, 0x0020, 0x006C, 0x0069, 0x0073, 0x0074, 0x00ED, 0x006E, 0x0020, 0x0074, 0x0065, 0x006C, 0x0065, 0x0066, 0x00F3, 0x006E, 0x0069, 0x0063, 0x006F, 0x0000} }, { "de_DE@collation=phonebook", "es", {0x006F, 0x0072, 0x0064, 0x0065, 0x006E, 0x0020, 0x0064, 0x0065, 0x0020, 0x006C, 0x0069, 0x0073, 0x0074, 0x00ED, 0x006E, 0x0020, 0x0074, 0x0065, 0x006C, 0x0065, 0x0066, 0x00F3, 0x006E, 0x0069, 0x0063, 0x006F, 0x0000} }, { "es_ES@collation=traditional","de", {0x0054, 0x0072, 0x0061, 0x0064, 0x0069, 0x0074, 0x0069, 0x006f, 0x006e, 0x0065, 0x006c, 0x006c, 0x0065, 0x0020, 0x0053, 0x006f, 0x0072, 0x0074, 0x0069, 0x0065, 0x0072, 0x0072, 0x0065, 0x0067, 0x0065, 0x006c, 0x006e, 0x0000} }, { "ja_JP@calendar=japanese", "de", {0x004a, 0x0061, 0x0070, 0x0061, 0x006e, 0x0069, 0x0073, 0x0063, 0x0068, 0x0065, 0x0072, 0x0020, 0x004b, 0x0061, 0x006c, 0x0065, 0x006e, 0x0064, 0x0065, 0x0072, 0x0000} }, }; for(i = 0; i < sizeof(testCases)/sizeof(testCases[0]); i++) { UErrorCode status = U_ZERO_ERROR; const char* keyword =NULL; int32_t keywordLen = 0; int32_t keywordCount = 0; UChar *displayKeywordValue = NULL; int32_t displayKeywordValueLen = 0; UEnumeration* keywordEnum = uloc_openKeywords(testCases[i].localeID, &status); for(keywordCount = uenum_count(keywordEnum, &status); keywordCount > 0 ; keywordCount--){ if(U_FAILURE(status)){ log_err("uloc_getKeywords failed for locale id: %s in display locale: % with error : %s \n", testCases[i].localeID, testCases[i].displayLocale, u_errorName(status)); break; } /* the uenum_next returns NUL terminated string */ keyword = uenum_next(keywordEnum, &keywordLen, &status); /* fetch the displayKeywordValue */ displayKeywordValueLen = uloc_getDisplayKeywordValue(testCases[i].localeID, keyword, testCases[i].displayLocale, displayKeywordValue, displayKeywordValueLen, &status); if(status==U_BUFFER_OVERFLOW_ERROR){ status = U_ZERO_ERROR; displayKeywordValueLen++; /* for null termination */ displayKeywordValue = (UChar*)malloc(displayKeywordValueLen * U_SIZEOF_UCHAR); displayKeywordValueLen = uloc_getDisplayKeywordValue(testCases[i].localeID, keyword, testCases[i].displayLocale, displayKeywordValue, displayKeywordValueLen, &status); if(U_FAILURE(status)){ log_err("uloc_getDisplayKeywordValue failed for keyword : %s in locale id: %s for display locale: %s with error : %s \n", testCases[i].localeID, keyword, testCases[i].displayLocale, u_errorName(status)); break; } if(u_strncmp(displayKeywordValue, testCases[i].displayKeywordValue, displayKeywordValueLen)!=0){ log_err("uloc_getDisplayKeywordValue did not return the expected value keyword : %s in locale id: %s for display locale: %s with error : %s \n", testCases[i].localeID, keyword, testCases[i].displayLocale, u_errorName(status)); break; } }else{ log_err("uloc_getDisplayKeywordValue did not return the expected error. Error: %s\n", u_errorName(status)); } free(displayKeywordValue); } uenum_close(keywordEnum); } { /* test a multiple keywords */ UErrorCode status = U_ZERO_ERROR; const char* keyword =NULL; int32_t keywordLen = 0; int32_t keywordCount = 0; const char* localeID = "es@collation=phonebook;calendar=buddhist;currency=DEM"; const char* displayLocale = "de"; const UChar expected[][50] = { {0x0042, 0x0075, 0x0064, 0x0064, 0x0068, 0x0069, 0x0073, 0x0074, 0x0069, 0x0073, 0x0063, 0x0068, 0x0065, 0x0072, 0x0020, 0x004b, 0x0061, 0x006c, 0x0065, 0x006e, 0x0064, 0x0065, 0x0072, 0x0000}, {0x0054, 0x0065, 0x006c, 0x0065, 0x0066, 0x006f, 0x006e, 0x0062, 0x0075, 0x0063, 0x0068, 0x002d, 0x0053, 0x006f, 0x0072, 0x0074, 0x0069, 0x0065, 0x0072, 0x0072, 0x0065, 0x0067, 0x0065, 0x006c, 0x006e, 0x0000}, {0x0044, 0x0065, 0x0075, 0x0074, 0x0073, 0x0063, 0x0068, 0x0065, 0x0020, 0x004d, 0x0061, 0x0072, 0x006b, 0x0000}, }; UEnumeration* keywordEnum = uloc_openKeywords(localeID, &status); for(keywordCount = 0; keywordCount < uenum_count(keywordEnum, &status) ; keywordCount++){ UChar *displayKeywordValue = NULL; int32_t displayKeywordValueLen = 0; if(U_FAILURE(status)){ log_err("uloc_getKeywords failed for locale id: %s in display locale: % with error : %s \n", localeID, displayLocale, u_errorName(status)); break; } /* the uenum_next returns NUL terminated string */ keyword = uenum_next(keywordEnum, &keywordLen, &status); /* fetch the displayKeywordValue */ displayKeywordValueLen = uloc_getDisplayKeywordValue(localeID, keyword, displayLocale, displayKeywordValue, displayKeywordValueLen, &status); if(status==U_BUFFER_OVERFLOW_ERROR){ status = U_ZERO_ERROR; displayKeywordValueLen++; /* for null termination */ displayKeywordValue = (UChar*)malloc(displayKeywordValueLen * U_SIZEOF_UCHAR); displayKeywordValueLen = uloc_getDisplayKeywordValue(localeID, keyword, displayLocale, displayKeywordValue, displayKeywordValueLen, &status); if(U_FAILURE(status)){ log_err("uloc_getDisplayKeywordValue failed for keyword : %s in locale id: %s for display locale: %s with error : %s \n", localeID, keyword, displayLocale, u_errorName(status)); break; } if(u_strncmp(displayKeywordValue, expected[keywordCount], displayKeywordValueLen)!=0){ log_err("uloc_getDisplayKeywordValue did not return the expected value keyword : %s in locale id: %s for display locale: %s \n", localeID, keyword, displayLocale); break; } }else{ log_err("uloc_getDisplayKeywordValue did not return the expected error. Error: %s\n", u_errorName(status)); } free(displayKeywordValue); } uenum_close(keywordEnum); } { /* Test non existent keywords */ UErrorCode status = U_ZERO_ERROR; const char* localeID = "es"; const char* displayLocale = "de"; UChar *displayKeywordValue = NULL; int32_t displayKeywordValueLen = 0; /* fetch the displayKeywordValue */ displayKeywordValueLen = uloc_getDisplayKeywordValue(localeID, "calendar", displayLocale, displayKeywordValue, displayKeywordValueLen, &status); if(U_FAILURE(status)) { log_err("uloc_getDisplaykeywordValue returned error status %s\n", u_errorName(status)); } else if(displayKeywordValueLen != 0) { log_err("uloc_getDisplaykeywordValue returned %d should be 0 \n", displayKeywordValueLen); } } } static void TestGetBaseName(void) { struct { const char *localeID; const char *baseName; } testCases[] = { { "de_DE@ C o ll A t i o n = Phonebook ", "de_DE" }, { "de@currency = euro; CoLLaTion = PHONEBOOk", "de" }, { "ja@calendar = buddhist", "ja" } }; int32_t i = 0, baseNameLen = 0; char baseName[256]; UErrorCode status = U_ZERO_ERROR; for(i = 0; i < sizeof(testCases)/sizeof(testCases[0]); i++) { baseNameLen = uloc_getBaseName(testCases[i].localeID, baseName, 256, &status); if(strcmp(testCases[i].baseName, baseName)) { log_err("For locale \"%s\" expected baseName \"%s\", but got \"%s\"\n", testCases[i].localeID, testCases[i].baseName, baseName); return; } } } /** * Compare the ICU version against the given major/minor version. */ static int32_t _cmpversion(const char* version) { UVersionInfo x, icu; u_versionFromString(x, version); u_getVersion(icu); return uprv_memcmp(icu, x, U_MAX_VERSION_LENGTH); } /** * Compare two locale IDs. If they are equal, return 0. If `string' * starts with `prefix' plus an additional element, that is, string == * prefix + '_' + x, then return 1. Otherwise return a value < 0. */ static UBool _loccmp(const char* string, const char* prefix) { int32_t slen = uprv_strlen(string), plen = uprv_strlen(prefix); int32_t c = uprv_strncmp(string, prefix, plen); /* 'root' is less than everything */ if (uprv_strcmp(prefix, "root") == 0) { return (uprv_strcmp(string, "root") == 0) ? 0 : 1; } if (c) return -1; /* mismatch */ if (slen == plen) return 0; if (string[plen] == '_') return 1; return -2; /* false match, e.g. "en_USX" cmp "en_US" */ } static void _checklocs(const char* label, const char* req, const char* valid, const char* actual) { /* We want the valid to be strictly > the bogus requested locale, and the valid to be >= the actual. */ if (_loccmp(req, valid) > 0 && _loccmp(valid, actual) >= 0) { log_verbose("%s; req=%s, valid=%s, actual=%s\n", label, req, valid, actual); } else { log_err("FAIL: %s; req=%s, valid=%s, actual=%s\n", label, req, valid, actual); } } static void TestGetLocale(void) { UErrorCode ec = U_ZERO_ERROR; UParseError pe; UChar EMPTY[1] = {0}; /* === udat === */ #if !UCONFIG_NO_FORMATTING { UDateFormat *obj; const char *req = "en_US_REDWOODSHORES", *valid, *actual; obj = udat_open(UDAT_DEFAULT, UDAT_DEFAULT, req, NULL, 0, NULL, 0, &ec); if (U_FAILURE(ec)) { log_err("udat_open failed\n"); return; } valid = udat_getLocaleByType(obj, ULOC_VALID_LOCALE, &ec); actual = udat_getLocaleByType(obj, ULOC_ACTUAL_LOCALE, &ec); if (U_FAILURE(ec)) { log_err("udat_getLocaleByType() failed\n"); return; } _checklocs("udat", req, valid, actual); udat_close(obj); } #endif /* === ucal === */ #if !UCONFIG_NO_FORMATTING { UCalendar *obj; const char *req = "fr_FR_PROVENCAL", *valid, *actual; obj = ucal_open(NULL, 0, req, UCAL_GREGORIAN, &ec); if (U_FAILURE(ec)) { log_err("ucal_open failed\n"); return; } valid = ucal_getLocaleByType(obj, ULOC_VALID_LOCALE, &ec); actual = ucal_getLocaleByType(obj, ULOC_ACTUAL_LOCALE, &ec); if (U_FAILURE(ec)) { log_err("ucal_getLocaleByType() failed\n"); return; } _checklocs("ucal", req, valid, actual); ucal_close(obj); } #endif /* === unum === */ #if !UCONFIG_NO_FORMATTING { UNumberFormat *obj; const char *req = "zh_TW_TAINAN", *valid, *actual; obj = unum_open(UNUM_DECIMAL, NULL, 0, req, &pe, &ec); if (U_FAILURE(ec)) { log_err("unum_open failed\n"); return; } valid = unum_getLocaleByType(obj, ULOC_VALID_LOCALE, &ec); actual = unum_getLocaleByType(obj, ULOC_ACTUAL_LOCALE, &ec); if (U_FAILURE(ec)) { log_err("unum_getLocaleByType() failed\n"); return; } _checklocs("unum", req, valid, actual); unum_close(obj); } #endif /* === umsg === */ #if !UCONFIG_NO_FORMATTING { UMessageFormat *obj; const char *req = "ja_JP_TAKAYAMA", *valid, *actual; UBool test; obj = umsg_open(EMPTY, 0, req, &pe, &ec); if (U_FAILURE(ec)) { log_err("umsg_open failed\n"); return; } valid = umsg_getLocaleByType(obj, ULOC_VALID_LOCALE, &ec); actual = umsg_getLocaleByType(obj, ULOC_ACTUAL_LOCALE, &ec); if (U_FAILURE(ec)) { log_err("umsg_getLocaleByType() failed\n"); return; } /* We want the valid to be strictly > the bogus requested locale, and the valid to be >= the actual. */ /* TODO MessageFormat is currently just storing the locale it is given. As a result, it will return whatever it was given, even if the locale is invalid. */ test = (_cmpversion("3.1") <= 0) ? /* Here is the weakened test for 3.0: */ (_loccmp(req, valid) >= 0) : /* Here is what the test line SHOULD be: */ (_loccmp(req, valid) > 0); if (test && _loccmp(valid, actual) >= 0) { log_verbose("umsg; req=%s, valid=%s, actual=%s\n", req, valid, actual); } else { log_err("FAIL: umsg; req=%s, valid=%s, actual=%s\n", req, valid, actual); } umsg_close(obj); } #endif /* === ubrk === */ #if !UCONFIG_NO_BREAK_ITERATION { UBreakIterator *obj; const char *req = "ar_KW_ABDALI", *valid, *actual; obj = ubrk_open(UBRK_WORD, req, EMPTY, 0, &ec); if (U_FAILURE(ec)) { log_err("ubrk_open failed\n"); return; } valid = ubrk_getLocaleByType(obj, ULOC_VALID_LOCALE, &ec); actual = ubrk_getLocaleByType(obj, ULOC_ACTUAL_LOCALE, &ec); if (U_FAILURE(ec)) { log_err("ubrk_getLocaleByType() failed\n"); return; } _checklocs("ubrk", req, valid, actual); ubrk_close(obj); } #endif /* === ucol === */ #if !UCONFIG_NO_COLLATION { UCollator *obj; const char *req = "es_AR_BUENOSAIRES", *valid, *actual; obj = ucol_open(req, &ec); if (U_FAILURE(ec)) { log_err("ucol_open failed\n"); return; } valid = ucol_getLocaleByType(obj, ULOC_VALID_LOCALE, &ec); actual = ucol_getLocaleByType(obj, ULOC_ACTUAL_LOCALE, &ec); if (U_FAILURE(ec)) { log_err("ucol_getLocaleByType() failed\n"); return; } _checklocs("ucol", req, valid, actual); ucol_close(obj); } #endif } /* adjust this limit as appropriate */ #define MAX_SCRIPTS_PER_LOCALE 8 static void TestExemplarSet(void){ int32_t i, j, k, m, n; int32_t equalCount = 0; UErrorCode ec = U_ZERO_ERROR; UEnumeration* avail; USet* exemplarSets[2]; UScriptCode code[MAX_SCRIPTS_PER_LOCALE]; USet* codeSets[MAX_SCRIPTS_PER_LOCALE]; int32_t codeLen; char cbuf[32]; /* 9 should be enough */ UChar ubuf[64]; /* adjust as needed */ UBool existsInScript; int32_t itemCount; int32_t strLen; UChar32 start, end; exemplarSets[0] = exemplarSets[1] = NULL; for (i=0; i 0 && equalCount < n); END: uenum_close(avail); uset_close(exemplarSets[0]); uset_close(exemplarSets[1]); for (i=0; i