+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
/********************************************************************
* COPYRIGHT:
- * Copyright (c) 1997-2010, International Business Machines Corporation and
+ * Copyright (c) 1997-2016, International Business Machines Corporation and
* others. All Rights Reserved.
********************************************************************/
#include "unicode/decimfmt.h"
#include "unicode/ucurr.h"
#include "unicode/smpdtfmt.h"
+#include "unicode/strenum.h"
#include "unicode/dtfmtsym.h"
#include "unicode/brkiter.h"
#include "unicode/coll.h"
+#include "unicode/ustring.h"
+#include "charstr.h"
+#include "cmemory.h"
#include "cstring.h"
#include <stdio.h>
+#include <string.h>
#include "putilimp.h"
-#include "unicode/ustring.h"
+#include "hash.h"
+#include "locmap.h"
static const char* const rawData[33][8] = {
// display name (English)
// Updated no_NO_NY English display name for new pattern-based algorithm
// (part of Euro support).
- { "English (United States)", "French (France)", "Catalan (Spain)", "Greek (Greece)", "Norwegian (Norway, NY)", "Italian", "xx (YY)", "Chinese (Simplified Han, China)" },
+ { "English (United States)", "French (France)", "Catalan (Spain)", "Greek (Greece)", "Norwegian (Norway, NY)", "Italian", "xx (YY)", "Chinese (Simplified, China)" },
// display langage (French)
{ "anglais", "fran\\u00E7ais", "catalan", "grec", "norv\\u00E9gien", "italien", "xx", "chinois" },
// display script (French)
- { "", "", "", "", "", "", "", "id\\u00E9ogrammes han simplifi\\u00E9s" },
+ { "", "", "", "", "", "", "", "sinogrammes simplifi\\u00E9s" },
// display country (French)
{ "\\u00C9tats-Unis", "France", "Espagne", "Gr\\u00E8ce", "Norv\\u00E8ge", "", "YY", "Chine" },
// display variant (French)
{ "", "", "", "", "NY", "", "", "" },
// display name (French)
//{ "anglais (Etats-Unis)", "francais (France)", "catalan (Espagne)", "grec (Grece)", "norvegien (Norvege,Nynorsk)", "italien", "xx (YY)" },
- { "anglais (\\u00C9tats-Unis)", "fran\\u00E7ais (France)", "catalan (Espagne)", "grec (Gr\\u00E8ce)", "norv\\u00E9gien (Norv\\u00E8ge, NY)", "italien", "xx (YY)", "chinois (id\\u00E9ogrammes han simplifi\\u00E9s, Chine)" }, // STILL not right
+ { "anglais (\\u00C9tats-Unis)", "fran\\u00E7ais (France)", "catalan (Espagne)", "grec (Gr\\u00E8ce)", "norv\\u00E9gien (Norv\\u00E8ge, NY)", "italien", "xx (YY)", "chinois (simplifi\\u00E9, Chine)" },
/* display language (Catalan) */
{ "angl\\u00E8s", "franc\\u00E8s", "catal\\u00E0", "grec", "noruec", "itali\\u00E0", "", "xin\\u00E8s" },
/* display script (Catalan) */
- { "", "", "", "", "", "", "", "xin\\u00E8s simplificat" },
+ { "", "", "", "", "", "", "", "han simplificat" },
/* 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)", "itali\\u00E0", "", "xin\\u00E8s (xin\\u00E8s simplificat, Xina)" },
+ { "angl\\u00E8s (Estats Units)", "franc\\u00E8s (Fran\\u00E7a)", "catal\\u00E0 (Espanya)", "grec (Gr\\u00E8cia)", "noruec (Noruega, NY)", "itali\\u00E0", "", "xin\\u00E8s (simplificat, Xina)" },
// display langage (Greek)[actual values listed below]
{ "\\u0391\\u03b3\\u03b3\\u03bb\\u03b9\\u03ba\\u03ac",
"\\u039A\\u03B9\\u03BD\\u03B5\\u03B6\\u03B9\\u03BA\\u03AC"
},
// display script (Greek)
- { "", "", "", "", "", "", "", "\\u0391\\u03c0\\u03bb\\u03bf\\u03c0\\u03bf\\u03b9\\u03b7\\u03bc\\u03ad\\u03bd\\u03bf \\u039a\\u03b9\\u03bd\\u03b5\\u03b6\\u03b9\\u03ba\\u03cc" },
+ { "", "", "", "", "", "", "", "\\u0391\\u03c0\\u03bb\\u03bf\\u03c0\\u03bf\\u03b9\\u03b7\\u03bc\\u03ad\\u03bd\\u03bf \\u03a7\\u03b1\\u03bd" },
// display country (Greek)[actual values listed below]
- { "\\u0397\\u03BD\\u03C9\\u03BC\\u03AD\\u03BD\\u03B5\\u03C2 \\u03A0\\u03BF\\u03BB\\u03B9\\u03C4\\u03B5\\u03AF\\u03B5\\u03C2 \\u03C4\\u03B7\\u03C2 \\u0391\\u03BC\\u03B5\\u03C1\\u03B9\\u03BA\\u03AE\\u03C2",
+ { "\\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",
// display variant (Greek)
{ "", "", "", "", "NY", "", "" },
// display name (Greek)[actual values listed below]
- { "\\u0391\\u03b3\\u03b3\\u03bb\\u03b9\\u03ba\\u03ac (\\u0397\\u03BD\\u03C9\\u03BC\\u03AD\\u03BD\\u03B5\\u03C2 \\u03A0\\u03BF\\u03BB\\u03B9\\u03C4\\u03B5\\u03AF\\u03B5\\u03C2 \\u03C4\\u03B7\\u03C2 \\u0391\\u03BC\\u03B5\\u03C1\\u03B9\\u03BA\\u03AE\\u03C2)",
+ { "\\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)",
"\\u0399\\u03c4\\u03b1\\u03bb\\u03b9\\u03ba\\u03ac",
"",
- "\\u039A\\u03B9\\u03BD\\u03B5\\u03B6\\u03B9\\u03BA\\u03AC (\\u0391\\u03c0\\u03bb\\u03bf\\u03c0\\u03bf\\u03b9\\u03b7\\u03bc\\u03ad\\u03bd\\u03bf \\u039a\\u03b9\\u03bd\\u03b5\\u03b6\\u03b9\\u03ba\\u03cc, \\u039A\\u03AF\\u03BD\\u03B1)"
+ "\\u039A\\u03B9\\u03BD\\u03B5\\u03B6\\u03B9\\u03BA\\u03AC (\\u0391\\u03c0\\u03bb\\u03bf\\u03c0\\u03bf\\u03b9\\u03b7\\u03bc\\u03ad\\u03bd\\u03b1, \\u039A\\u03AF\\u03BD\\u03B1)"
},
// display langage (<root>)
void LocaleTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
{
- switch (index) {
- TESTCASE(0, TestBasicGetters);
- TESTCASE(1, TestSimpleResourceInfo);
- TESTCASE(2, TestDisplayNames);
- TESTCASE(3, TestSimpleObjectStuff);
- TESTCASE(4, TestPOSIXParsing);
- TESTCASE(5, TestGetAvailableLocales);
- TESTCASE(6, TestDataDirectory);
- TESTCASE(7, TestISO3Fallback);
- TESTCASE(8, TestGetLangsAndCountries);
- TESTCASE(9, TestSimpleDisplayNames);
- TESTCASE(10, TestUninstalledISO3Names);
- TESTCASE(11, TestAtypicalLocales);
+ TESTCASE_AUTO_BEGIN;
+ TESTCASE_AUTO(TestBug11421); // Must run early in list to trigger failure.
+ TESTCASE_AUTO(TestBasicGetters);
+ TESTCASE_AUTO(TestSimpleResourceInfo);
+ TESTCASE_AUTO(TestDisplayNames);
+ TESTCASE_AUTO(TestSimpleObjectStuff);
+ TESTCASE_AUTO(TestPOSIXParsing);
+ TESTCASE_AUTO(TestGetAvailableLocales);
+ TESTCASE_AUTO(TestDataDirectory);
+ TESTCASE_AUTO(TestISO3Fallback);
+ TESTCASE_AUTO(TestGetLangsAndCountries);
+ TESTCASE_AUTO(TestSimpleDisplayNames);
+ TESTCASE_AUTO(TestUninstalledISO3Names);
+ TESTCASE_AUTO(TestAtypicalLocales);
#if !UCONFIG_NO_FORMATTING
- TESTCASE(12, TestThaiCurrencyFormat);
- TESTCASE(13, TestEuroSupport);
+ TESTCASE_AUTO(TestThaiCurrencyFormat);
+ TESTCASE_AUTO(TestEuroSupport);
#endif
- TESTCASE(14, TestToString);
+ TESTCASE_AUTO(TestToString);
#if !UCONFIG_NO_FORMATTING
- TESTCASE(15, Test4139940);
- TESTCASE(16, Test4143951);
+ TESTCASE_AUTO(Test4139940);
+ TESTCASE_AUTO(Test4143951);
#endif
- TESTCASE(17, Test4147315);
- TESTCASE(18, Test4147317);
- TESTCASE(19, Test4147552);
- TESTCASE(20, TestVariantParsing);
+ TESTCASE_AUTO(Test4147315);
+ TESTCASE_AUTO(Test4147317);
+ TESTCASE_AUTO(Test4147552);
+ TESTCASE_AUTO(TestVariantParsing);
#if !UCONFIG_NO_FORMATTING
- TESTCASE(21, Test4105828);
+ TESTCASE_AUTO(Test4105828);
#endif
- TESTCASE(22, TestSetIsBogus);
- TESTCASE(23, TestParallelAPIValues);
- TESTCASE(24, TestKeywordVariants);
- TESTCASE(25, TestKeywordVariantParsing);
- TESTCASE(26, TestSetKeywordValue);
- TESTCASE(27, TestGetBaseName);
+ TESTCASE_AUTO(TestSetIsBogus);
+ TESTCASE_AUTO(TestParallelAPIValues);
+ TESTCASE_AUTO(TestKeywordVariants);
+ TESTCASE_AUTO(TestKeywordVariantParsing);
+ TESTCASE_AUTO(TestSetKeywordValue);
+ TESTCASE_AUTO(TestGetBaseName);
#if !UCONFIG_NO_FILE_IO
- TESTCASE(28, TestGetLocale);
+ TESTCASE_AUTO(TestGetLocale);
#endif
- TESTCASE(29, TestVariantWithOutCountry);
- TESTCASE(30, TestCanonicalization);
- TESTCASE(31, TestCurrencyByDate);
- TESTCASE(32, TestGetVariantWithKeywords);
-
- // keep the last index in sync with the condition in default:
-
- default:
- if (index <= 28) { // keep this in sync with the last index!
- name = "(test omitted by !UCONFIG_NO_FORMATTING)";
- } else {
- name = "";
- }
- break; //needed to end loop
- }
+ TESTCASE_AUTO(TestVariantWithOutCountry);
+ TESTCASE_AUTO(TestCanonicalization);
+ TESTCASE_AUTO(TestCurrencyByDate);
+ TESTCASE_AUTO(TestGetVariantWithKeywords);
+ TESTCASE_AUTO(TestIsRightToLeft);
+ TESTCASE_AUTO(TestBug13277);
+ TESTCASE_AUTO(TestBug13554);
+ TESTCASE_AUTO_END;
}
void LocaleTest::TestBasicGetters() {
;
/* TODO: Change this test to be more like the cloctst version? */
- if (testCount != 491)
- errln("Expected getISOLanguages() to return 491 languages; it returned %d", testCount);
+ if (testCount != 595)
+ errln("Expected getISOLanguages() to return 595 languages; it returned %d", testCount);
else {
for (i = 0; i < 15; i++) {
int32_t j;
for(testCount=0;test[testCount];testCount++)
;
- if (testCount != 246){
- errln("Expected getISOCountries to return 240 countries; it returned %d", testCount);
+ if (testCount != 256){
+ errln("Expected getISOCountries to return 256 countries; it returned %d", testCount);
}else {
for (i = 0; i < spot2Len; i++) {
int32_t j;
errln("Couldn't find " + spotCheck2[i] + " in country list.");
}
}
- for (i = 0; i < testCount; i++) {
- UnicodeString testee(test[i],"");
+ for (i = 0; i < testCount; i++) {
+ UnicodeString testee(test[i],"");
UnicodeString uc(test[i],"");
if (testee != uc.toUpper())
errln(testee + " is not all upper case.");
if (i > 0 && testee.compare(test[i - 1]) <= 0)
errln(testee + " appears in an out-of-order position in the list.");
}
+
+ // This getAvailableLocales and getISO3Language
+ {
+ int32_t numOfLocales;
+ Locale enLoc ("en");
+ const Locale *pLocales = Locale::getAvailableLocales(numOfLocales);
+
+ for (int i = 0; i < numOfLocales; i++) {
+ const Locale &loc(pLocales[i]);
+ UnicodeString name;
+ char szName[200];
+
+ loc.getDisplayName (enLoc, name);
+ name.extract (0, 200, szName, sizeof(szName));
+
+ if (strlen(loc.getISO3Language()) == 0) {
+ errln("getISO3Language() returned an empty string for: " + name);
+ }
+ }
+ }
}
/**
// names, and other stuff like that. This test just checks specific language
// and country codes to make sure we have the correct names for them.
char languageCodes[] [4] = { "he", "id", "iu", "ug", "yi", "za" };
- UnicodeString languageNames [] = { "Hebrew", "Indonesian", "Inuktitut", "Uighur", "Yiddish",
+ UnicodeString languageNames [] = { "Hebrew", "Indonesian", "Inuktitut", "Uyghur", "Yiddish",
"Zhuang" };
for (int32_t i = 0; i < 6; i++) {
UErrorCode status = U_ZERO_ERROR;
DecimalFormat *thaiCurrency = (DecimalFormat*)NumberFormat::createCurrencyInstance(
Locale("th", "TH"), status);
- UChar posPrefix = 0x0e3f;
+ UnicodeString posPrefix("THB", 3, US_INV); // per cldrbug 7618
UnicodeString temp;
if(U_FAILURE(status) || !thaiCurrency)
dataerrln("Couldn't get th_TH currency -> " + UnicodeString(u_errorName(status)));
return;
}
- if (thaiCurrency->getPositivePrefix(temp) != UnicodeString(&posPrefix, 1, 1))
- errln("Thai currency prefix wrong: expected 0x0e3f, got \"" +
+ if (thaiCurrency->getPositivePrefix(temp) != posPrefix)
+ errln("Thai currency prefix wrong: expected THB, got \"" +
thaiCurrency->getPositivePrefix(temp) + "\"");
if (thaiCurrency->getPositiveSuffix(temp) != "")
errln("Thai currency suffix wrong: expected \"\", got \"" +
if (invalidLen || U_SUCCESS(status)) {
errln("Fail: en_QQ didn't return NULL");
}
+
+ // The currency keyword value is as long as the destination buffer.
+ // It should detect the overflow internally, and default to the locale's currency.
+ tmp[0] = u'¤';
+ status = U_ZERO_ERROR;
+ int32_t length = ucurr_forLocale("en_US@currency=euro", tmp, 4, &status);
+ if (U_FAILURE(status) || dollarStr != UnicodeString(tmp, length)) {
+ if (U_SUCCESS(status) && tmp[0] == u'¤') {
+ errln("Fail: ucurr_forLocale(en_US@currency=euro) succeeded without writing output");
+ } else {
+ errln("Fail: ucurr_forLocale(en_US@currency=euro) != USD - %s", u_errorName(status));
+ }
+ }
}
#endif
UnicodeString temp;
// Try with codes that are the wrong length but happen to match text
// at a valid offset in the mapping table
- Locale locale("aaa", "CCC");
+ Locale locale("xxx", "CCC");
const char *result = locale.getISO3Country();
UnicodeString temp;
// Try with codes that are the wrong length but happen to match text
// at a valid offset in the mapping table
- Locale locale("aaa", "CCC");
+ Locale locale("xxx", "CCC");
const char *result = locale.getISO3Language();
return;
}
UnicodeString result;
- FieldPosition pos(0);
+ FieldPosition pos(FieldPosition::DONT_CARE);
fmt->format((int32_t)1, result, pos);
UnicodeString temp;
if(result != "100%") {
const UnicodeString *keywordString;
int32_t keywordLen = 0;
- for(i = 0; i < (int32_t)(sizeof(testCases)/sizeof(testCases[0])); i++) {
+ for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
status = U_ZERO_ERROR;
Locale l(testCases[i].localeID);
keywords = l.createKeywords(status);
int32_t resultLen = 0;
char buffer[256];
- for(i = 0; i < (int32_t)(sizeof(testCases)/sizeof(testCases[0])); i++) {
+ for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
*buffer = 0;
Locale l(testCases[i].localeID);
resultLen = l.getKeywordValue(testCases[i].keyword, buffer, 256, status);
+ (void)resultLen; // Suppress unused variable warning.
if(uprv_strcmp(testCases[i].expectedValue, buffer) != 0) {
err("Expected to extract \"%s\" from \"%s\" for keyword \"%s\". Got \"%s\" instead\n",
testCases[i].expectedValue, testCases[i].localeID, testCases[i].keyword, buffer);
Locale l(Locale::getGerman());
- for(i = 0; i < (int32_t)(sizeof(testCases)/sizeof(testCases[0])); i++) {
+ for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
l.setKeywordValue(testCases[i].keyword, testCases[i].value, status);
if(U_FAILURE(status)) {
err("FAIL: Locale::setKeywordValue failed - %s\n", u_errorName(status));
*buffer = 0;
resultLen = l.getKeywordValue(testCases[i].keyword, buffer, 256, status);
+ (void)resultLen; // Suppress unused variable warning.
if(uprv_strcmp(testCases[i].value, buffer) != 0) {
err("Expected to extract \"%s\" for keyword \"%s\". Got \"%s\" instead\n",
testCases[i].value, testCases[i].keyword, buffer);
} testCases[] = {
{ "de_DE@ C o ll A t i o n = Phonebook ", "de_DE" },
{ "de@currency = euro; CoLLaTion = PHONEBOOk", "de" },
- { "ja@calendar = buddhist", "ja" }
+ { "ja@calendar = buddhist", "ja" },
+ { "de-u-co-phonebk", "de"}
};
int32_t i = 0;
- for(i = 0; i < (int32_t)(sizeof(testCases)/sizeof(testCases[0])); i++) {
+ for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
Locale loc(testCases[i].localeID);
if(strcmp(testCases[i].baseName, loc.getBaseName())) {
errln("For locale \"%s\" expected baseName \"%s\", but got \"%s\"",
return;
}
}
+
+ // Verify that adding a keyword to an existing Locale doesn't change the base name.
+ UErrorCode status = U_ZERO_ERROR;
+ Locale loc2("en-US");
+ if (strcmp("en_US", loc2.getBaseName())) {
+ errln("%s:%d Expected \"en_US\", got \"%s\"", __FILE__, __LINE__, loc2.getBaseName());
+ }
+ loc2.setKeywordValue("key", "value", status);
+ if (strcmp("en_US@key=value", loc2.getName())) {
+ errln("%s:%d Expected \"en_US@key=value\", got \"%s\"", __FILE__, __LINE__, loc2.getName());
+ }
+ if (strcmp("en_US", loc2.getBaseName())) {
+ errln("%s:%d Expected \"en_US\", got \"%s\"", __FILE__, __LINE__, loc2.getBaseName());
+ }
}
/**
void LocaleTest::TestGetLocale(void) {
#if !UCONFIG_NO_SERVICE
- UErrorCode ec = U_ZERO_ERROR;
const char *req;
Locale valid, actual, reqLoc;
// Calendar
#if !UCONFIG_NO_FORMATTING
- req = "en_US_BROOKLYN";
- Calendar* cal = Calendar::createInstance(Locale::createFromName(req), ec);
- if (U_FAILURE(ec)) {
- dataerrln("FAIL: Calendar::createInstance failed - %s", u_errorName(ec));
- } else {
- valid = cal->getLocale(ULOC_VALID_LOCALE, ec);
- actual = cal->getLocale(ULOC_ACTUAL_LOCALE, ec);
+ {
+ UErrorCode ec = U_ZERO_ERROR; // give each resource type its own error code
+ req = "en_US_BROOKLYN";
+ Calendar* cal = Calendar::createInstance(Locale::createFromName(req), ec);
if (U_FAILURE(ec)) {
- errln("FAIL: Calendar::getLocale() failed");
+ dataerrln("FAIL: Calendar::createInstance failed - %s", u_errorName(ec));
} else {
- _checklocs("Calendar", req, valid, actual);
- }
- /* Make sure that it fails correctly */
- ec = U_FILE_ACCESS_ERROR;
- if (cal->getLocale(ULOC_VALID_LOCALE, ec).getName()[0] != 0) {
- errln("FAIL: Calendar::getLocale() failed to fail correctly. It should have returned \"\"");
+ valid = cal->getLocale(ULOC_VALID_LOCALE, ec);
+ actual = cal->getLocale(ULOC_ACTUAL_LOCALE, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: Calendar::getLocale() failed");
+ } else {
+ _checklocs("Calendar", req, valid, actual);
+ }
+ /* Make sure that it fails correctly */
+ ec = U_FILE_ACCESS_ERROR;
+ if (cal->getLocale(ULOC_VALID_LOCALE, ec).getName()[0] != 0) {
+ errln("FAIL: Calendar::getLocale() failed to fail correctly. It should have returned \"\"");
+ }
+ ec = U_ZERO_ERROR;
}
- ec = U_ZERO_ERROR;
+ delete cal;
}
- delete cal;
#endif
// DecimalFormat, DecimalFormatSymbols
#if !UCONFIG_NO_FORMATTING
- req = "fr_FR_NICE";
- NumberFormat* nf = NumberFormat::createInstance(Locale::createFromName(req), ec);
- if (U_FAILURE(ec)) {
- dataerrln("FAIL: NumberFormat::createInstance failed - %s", u_errorName(ec));
- } else {
- DecimalFormat* dec = dynamic_cast<DecimalFormat*>(nf);
- if (dec == NULL) {
- errln("FAIL: NumberFormat::createInstance does not return a DecimalFormat");
- return;
- }
- valid = dec->getLocale(ULOC_VALID_LOCALE, ec);
- actual = dec->getLocale(ULOC_ACTUAL_LOCALE, ec);
+ {
+ UErrorCode ec = U_ZERO_ERROR; // give each resource type its own error code
+ req = "fr_FR_NICE";
+ NumberFormat* nf = NumberFormat::createInstance(Locale::createFromName(req), ec);
if (U_FAILURE(ec)) {
- errln("FAIL: DecimalFormat::getLocale() failed");
+ dataerrln("FAIL: NumberFormat::createInstance failed - %s", u_errorName(ec));
} else {
- _checklocs("DecimalFormat", req, valid, actual);
- }
+ DecimalFormat* dec = dynamic_cast<DecimalFormat*>(nf);
+ if (dec == NULL) {
+ errln("FAIL: NumberFormat::createInstance does not return a DecimalFormat");
+ return;
+ }
+ valid = dec->getLocale(ULOC_VALID_LOCALE, ec);
+ actual = dec->getLocale(ULOC_ACTUAL_LOCALE, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: DecimalFormat::getLocale() failed");
+ } else {
+ _checklocs("DecimalFormat", req, valid, actual);
+ }
- const DecimalFormatSymbols* sym = dec->getDecimalFormatSymbols();
- if (sym == NULL) {
- errln("FAIL: getDecimalFormatSymbols returned NULL");
- return;
+ const DecimalFormatSymbols* sym = dec->getDecimalFormatSymbols();
+ if (sym == NULL) {
+ errln("FAIL: getDecimalFormatSymbols returned NULL");
+ return;
+ }
+ valid = sym->getLocale(ULOC_VALID_LOCALE, ec);
+ actual = sym->getLocale(ULOC_ACTUAL_LOCALE, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: DecimalFormatSymbols::getLocale() failed");
+ } else {
+ _checklocs("DecimalFormatSymbols", req, valid, actual);
+ }
}
- valid = sym->getLocale(ULOC_VALID_LOCALE, ec);
- actual = sym->getLocale(ULOC_ACTUAL_LOCALE, ec);
- if (U_FAILURE(ec)) {
- errln("FAIL: DecimalFormatSymbols::getLocale() failed");
- } else {
- _checklocs("DecimalFormatSymbols", req, valid, actual);
- }
+ delete nf;
}
- delete nf;
#endif
// DateFormat, DateFormatSymbols
#if !UCONFIG_NO_FORMATTING
- req = "de_CH_LUCERNE";
- DateFormat* df =
- DateFormat::createDateInstance(DateFormat::kDefault,
- Locale::createFromName(req));
- if (df == 0){
- dataerrln("Error calling DateFormat::createDateInstance()");
- } else {
- SimpleDateFormat* dat = dynamic_cast<SimpleDateFormat*>(df);
- if (dat == NULL) {
- errln("FAIL: DateFormat::createInstance does not return a SimpleDateFormat");
- return;
- }
- valid = dat->getLocale(ULOC_VALID_LOCALE, ec);
- actual = dat->getLocale(ULOC_ACTUAL_LOCALE, ec);
- if (U_FAILURE(ec)) {
- errln("FAIL: SimpleDateFormat::getLocale() failed");
+ {
+ UErrorCode ec = U_ZERO_ERROR; // give each resource type its own error code
+ req = "de_CH_LUCERNE";
+ DateFormat* df =
+ DateFormat::createDateInstance(DateFormat::kDefault,
+ Locale::createFromName(req));
+ if (df == 0){
+ dataerrln("Error calling DateFormat::createDateInstance()");
} else {
- _checklocs("SimpleDateFormat", req, valid, actual);
- }
+ SimpleDateFormat* dat = dynamic_cast<SimpleDateFormat*>(df);
+ if (dat == NULL) {
+ errln("FAIL: DateFormat::createInstance does not return a SimpleDateFormat");
+ return;
+ }
+ valid = dat->getLocale(ULOC_VALID_LOCALE, ec);
+ actual = dat->getLocale(ULOC_ACTUAL_LOCALE, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: SimpleDateFormat::getLocale() failed");
+ } else {
+ _checklocs("SimpleDateFormat", req, valid, actual);
+ }
- const DateFormatSymbols* sym = dat->getDateFormatSymbols();
- if (sym == NULL) {
- errln("FAIL: getDateFormatSymbols returned NULL");
- return;
+ const DateFormatSymbols* sym = dat->getDateFormatSymbols();
+ if (sym == NULL) {
+ errln("FAIL: getDateFormatSymbols returned NULL");
+ return;
+ }
+ valid = sym->getLocale(ULOC_VALID_LOCALE, ec);
+ actual = sym->getLocale(ULOC_ACTUAL_LOCALE, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: DateFormatSymbols::getLocale() failed");
+ } else {
+ _checklocs("DateFormatSymbols", req, valid, actual);
+ }
}
- valid = sym->getLocale(ULOC_VALID_LOCALE, ec);
- actual = sym->getLocale(ULOC_ACTUAL_LOCALE, ec);
- if (U_FAILURE(ec)) {
- errln("FAIL: DateFormatSymbols::getLocale() failed");
- } else {
- _checklocs("DateFormatSymbols", req, valid, actual);
- }
+ delete df;
}
- delete df;
#endif
// BreakIterator
#if !UCONFIG_NO_BREAK_ITERATION
- req = "es_ES_BARCELONA";
- reqLoc = Locale::createFromName(req);
- BreakIterator* brk = BreakIterator::createWordInstance(reqLoc, ec);
- if (U_FAILURE(ec)) {
- dataerrln("FAIL: BreakIterator::createWordInstance failed - %s", u_errorName(ec));
- } else {
- valid = brk->getLocale(ULOC_VALID_LOCALE, ec);
- actual = brk->getLocale(ULOC_ACTUAL_LOCALE, ec);
+ {
+ UErrorCode ec = U_ZERO_ERROR; // give each resource type its own error code
+ req = "es_ES_BARCELONA";
+ reqLoc = Locale::createFromName(req);
+ BreakIterator* brk = BreakIterator::createWordInstance(reqLoc, ec);
if (U_FAILURE(ec)) {
- errln("FAIL: BreakIterator::getLocale() failed");
+ dataerrln("FAIL: BreakIterator::createWordInstance failed - %s", u_errorName(ec));
} else {
- _checklocs("BreakIterator", req, valid, actual);
- }
+ valid = brk->getLocale(ULOC_VALID_LOCALE, ec);
+ actual = brk->getLocale(ULOC_ACTUAL_LOCALE, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: BreakIterator::getLocale() failed");
+ } else {
+ _checklocs("BreakIterator", req, valid, actual);
+ }
- // After registering something, the behavior should be different
- URegistryKey key = BreakIterator::registerInstance(brk, reqLoc, UBRK_WORD, ec);
- brk = 0; // registerInstance adopts
- if (U_FAILURE(ec)) {
- errln("FAIL: BreakIterator::registerInstance() failed");
- } else {
+ // After registering something, the behavior should be different
+ URegistryKey key = BreakIterator::registerInstance(brk, reqLoc, UBRK_WORD, ec);
+ brk = 0; // registerInstance adopts
+ if (U_FAILURE(ec)) {
+ errln("FAIL: BreakIterator::registerInstance() failed");
+ } else {
+ brk = BreakIterator::createWordInstance(reqLoc, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: BreakIterator::createWordInstance failed");
+ } else {
+ valid = brk->getLocale(ULOC_VALID_LOCALE, ec);
+ actual = brk->getLocale(ULOC_ACTUAL_LOCALE, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: BreakIterator::getLocale() failed");
+ } else {
+ // N.B.: now expect valid==actual==req
+ _checklocs("BreakIterator(registered)",
+ req, valid, actual, "eq", "eq");
+ }
+ }
+ // No matter what, unregister
+ BreakIterator::unregister(key, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: BreakIterator::unregister() failed");
+ }
+ delete brk;
+ brk = 0;
+ }
+
+ // After unregistering, should behave normally again
brk = BreakIterator::createWordInstance(reqLoc, ec);
if (U_FAILURE(ec)) {
errln("FAIL: BreakIterator::createWordInstance failed");
if (U_FAILURE(ec)) {
errln("FAIL: BreakIterator::getLocale() failed");
} else {
- // N.B.: now expect valid==actual==req
- _checklocs("BreakIterator(registered)",
- req, valid, actual, "eq", "eq");
+ _checklocs("BreakIterator(unregistered)", req, valid, actual);
}
}
- // No matter what, unregister
- BreakIterator::unregister(key, ec);
- if (U_FAILURE(ec)) {
- errln("FAIL: BreakIterator::unregister() failed");
- }
- delete brk;
- brk = 0;
- }
-
- // After unregistering, should behave normally again
- brk = BreakIterator::createWordInstance(reqLoc, ec);
- if (U_FAILURE(ec)) {
- errln("FAIL: BreakIterator::createWordInstance failed");
- } else {
- valid = brk->getLocale(ULOC_VALID_LOCALE, ec);
- actual = brk->getLocale(ULOC_ACTUAL_LOCALE, ec);
- if (U_FAILURE(ec)) {
- errln("FAIL: BreakIterator::getLocale() failed");
- } else {
- _checklocs("BreakIterator(unregistered)", req, valid, actual);
- }
}
+ delete brk;
}
- delete brk;
#endif
// Collator
#if !UCONFIG_NO_COLLATION
- req = "hi_IN_BHOPAL";
- reqLoc = Locale::createFromName(req);
- Collator* coll = Collator::createInstance(reqLoc, ec);
- if (U_FAILURE(ec)) {
- dataerrln("FAIL: Collator::createInstance failed - %s", u_errorName(ec));
- } else {
- valid = coll->getLocale(ULOC_VALID_LOCALE, ec);
- actual = coll->getLocale(ULOC_ACTUAL_LOCALE, ec);
- if (U_FAILURE(ec)) {
- errln("FAIL: Collator::getLocale() failed");
- } else {
- _checklocs("Collator", req, valid, actual);
- }
+ {
+ UErrorCode ec = U_ZERO_ERROR; // give each resource type its own error code
- // After registering something, the behavior should be different
- URegistryKey key = Collator::registerInstance(coll, reqLoc, ec);
- coll = 0; // registerInstance adopts
+ checkRegisteredCollators(NULL); // Don't expect any extras
+
+ req = "hi_IN_BHOPAL";
+ reqLoc = Locale::createFromName(req);
+ Collator* coll = Collator::createInstance(reqLoc, ec);
if (U_FAILURE(ec)) {
- errln("FAIL: Collator::registerInstance() failed");
+ dataerrln("FAIL: Collator::createInstance failed - %s", u_errorName(ec));
} else {
+ valid = coll->getLocale(ULOC_VALID_LOCALE, ec);
+ actual = coll->getLocale(ULOC_ACTUAL_LOCALE, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: Collator::getLocale() failed");
+ } else {
+ _checklocs("Collator", req, valid, actual);
+ }
+
+ // After registering something, the behavior should be different
+ URegistryKey key = Collator::registerInstance(coll, reqLoc, ec);
+ coll = 0; // registerInstance adopts
+ if (U_FAILURE(ec)) {
+ errln("FAIL: Collator::registerInstance() failed");
+ } else {
+ coll = Collator::createInstance(reqLoc, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: Collator::createWordInstance failed");
+ } else {
+ valid = coll->getLocale(ULOC_VALID_LOCALE, ec);
+ actual = coll->getLocale(ULOC_ACTUAL_LOCALE, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: Collator::getLocale() failed");
+ } else {
+ // N.B.: now expect valid==actual==req
+ _checklocs("Collator(registered)",
+ req, valid, actual, "eq", "eq");
+ }
+ }
+ checkRegisteredCollators(req); // include hi_IN_BHOPAL
+
+ // No matter what, unregister
+ Collator::unregister(key, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: Collator::unregister() failed");
+ }
+ delete coll;
+ coll = 0;
+ }
+
+ // After unregistering, should behave normally again
coll = Collator::createInstance(reqLoc, ec);
if (U_FAILURE(ec)) {
- errln("FAIL: Collator::createWordInstance failed");
+ errln("FAIL: Collator::createInstance failed");
} else {
valid = coll->getLocale(ULOC_VALID_LOCALE, ec);
actual = coll->getLocale(ULOC_ACTUAL_LOCALE, ec);
if (U_FAILURE(ec)) {
errln("FAIL: Collator::getLocale() failed");
} else {
- // N.B.: now expect valid==actual==req
- _checklocs("Collator(registered)",
- req, valid, actual, "eq", "eq");
+ _checklocs("Collator(unregistered)", req, valid, actual);
}
}
- // No matter what, unregister
- Collator::unregister(key, ec);
- if (U_FAILURE(ec)) {
- errln("FAIL: Collator::unregister() failed");
- }
- delete coll;
- coll = 0;
}
+ delete coll;
- // After unregistering, should behave normally again
- coll = Collator::createInstance(reqLoc, ec);
- if (U_FAILURE(ec)) {
- errln("FAIL: Collator::createInstance failed");
- } else {
- valid = coll->getLocale(ULOC_VALID_LOCALE, ec);
- actual = coll->getLocale(ULOC_ACTUAL_LOCALE, ec);
- if (U_FAILURE(ec)) {
- errln("FAIL: Collator::getLocale() failed");
+ checkRegisteredCollators(NULL); // extra should be gone again
+ }
+#endif
+#endif
+}
+
+#if !UCONFIG_NO_COLLATION
+/**
+ * Compare Collator::getAvailableLocales(int) [ "old", returning an array ]
+ * with Collator::getAvailableLocales() [ "new", returning a StringEnumeration ]
+ * These should be identical (check their API docs) EXCEPT that
+ * if expectExtra is non-NULL, it will be in the "new" array but not "old".
+ * Does not return any status but calls errln on error.
+ * @param expectExtra an extra locale, will be in "new" but not "old". Or NULL.
+ */
+void LocaleTest::checkRegisteredCollators(const char *expectExtra) {
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t count1=0,count2=0;
+ Hashtable oldHash(status);
+ Hashtable newHash(status);
+ TEST_ASSERT_STATUS(status);
+
+ UnicodeString expectStr(expectExtra?expectExtra:"n/a", "");
+
+ // the 'old' list (non enumeration)
+ const Locale* oldList = Collator::getAvailableLocales(count1);
+ if(oldList == NULL) {
+ dataerrln("Error: Collator::getAvailableLocales(count) returned NULL");
+ return;
+ }
+
+ // the 'new' list (enumeration)
+ LocalPointer<StringEnumeration> newEnum(Collator::getAvailableLocales());
+ if(newEnum.isNull()) {
+ errln("Error: collator::getAvailableLocales() returned NULL");
+ return;
+ }
+
+ // OK. Let's add all of the OLD
+ // then check for any in the NEW not in OLD
+ // then check for any in OLD not in NEW.
+
+ // 1. add all of OLD
+ for(int32_t i=0;i<count1;i++) {
+ const UnicodeString key(oldList[i].getName(), "");
+ int32_t oldI = oldHash.puti(key, 1, status);
+ if( oldI == 1 ){
+ errln("Error: duplicate key %s in Collator::getAvailableLocales(count) list.\n",
+ oldList[i].getName());
+ return;
+ }
+ if(expectExtra != NULL && !strcmp(expectExtra, oldList[i].getName())) {
+ errln("Inexplicably, Collator::getAvailableCollators(count) had registered collator %s. This shouldn't happen, so I am going to consider it an error.\n", expectExtra);
+ }
+ }
+
+ // 2. add all of NEW
+ const UnicodeString *locStr;
+ UBool foundExpected = FALSE;
+ while((locStr = newEnum->snext(status)) && U_SUCCESS(status)) {
+ count2++;
+
+ if(expectExtra != NULL && expectStr == *locStr) {
+ foundExpected = TRUE;
+ logln(UnicodeString("Found expected registered collator: ","") + expectStr);
+ }
+ (void)foundExpected; // Hush unused variable compiler warning.
+
+ if( oldHash.geti(*locStr) == 0 ) {
+ if(expectExtra != NULL && expectStr==*locStr) {
+ logln(UnicodeString("As expected, Collator::getAvailableLocales(count) is missing registered collator ") + expectStr);
} else {
- _checklocs("Collator(unregistered)", req, valid, actual);
+ errln(UnicodeString("Error: Collator::getAvailableLocales(count) is missing: ","")
+ + *locStr);
}
}
+ newHash.puti(*locStr, 1, status);
}
- delete coll;
-#endif
-#endif
+
+ // 3. check all of OLD again
+ for(int32_t i=0;i<count1;i++) {
+ const UnicodeString key(oldList[i].getName(), "");
+ int32_t newI = newHash.geti(key);
+ if(newI == 0) {
+ errln(UnicodeString("Error: Collator::getAvailableLocales() is missing: ","")
+ + key);
+ }
+ }
+
+ int32_t expectCount2 = count1;
+ if(expectExtra != NULL) {
+ expectCount2 ++; // if an extra item registered, bump the expect count
+ }
+
+ assertEquals("Collator::getAvail() count", expectCount2, count2);
}
+#endif
+
+
void LocaleTest::TestVariantWithOutCountry(void) {
Locale loc("en","","POSIX");
if (0 != strcmp(loc.getVariant(), "POSIX")) {
- errln("FAIL: en__POSIX didn't get parsed correctly");
+ errln("FAIL: en__POSIX didn't get parsed correctly - name is %s - expected %s got %s", loc.getName(), "POSIX", loc.getVariant());
}
Locale loc2("en","","FOUR");
if (0 != strcmp(loc2.getVariant(), "FOUR")) {
- errln("FAIL: en__FOUR didn't get parsed correctly");
+ errln("FAIL: en__FOUR didn't get parsed correctly - name is %s - expected %s got %s", loc2.getName(), "FOUR", loc2.getVariant());
}
Locale loc3("en","Latn","","FOUR");
if (0 != strcmp(loc3.getVariant(), "FOUR")) {
- errln("FAIL: en_Latn__FOUR didn't get parsed correctly");
+ errln("FAIL: en_Latn__FOUR didn't get parsed correctly - name is %s - expected %s got %s", loc3.getName(), "FOUR", loc3.getVariant());
}
Locale loc4("","Latn","","FOUR");
if (0 != strcmp(loc4.getVariant(), "FOUR")) {
- errln("FAIL: _Latn__FOUR didn't get parsed correctly");
+ errln("FAIL: _Latn__FOUR didn't get parsed correctly - name is %s - expected %s got %s", loc4.getName(), "FOUR", loc4.getVariant());
}
Locale loc5("","Latn","US","FOUR");
if (0 != strcmp(loc5.getVariant(), "FOUR")) {
- errln("FAIL: _Latn_US_FOUR didn't get parsed correctly");
+ errln("FAIL: _Latn_US_FOUR didn't get parsed correctly - name is %s - expected %s got %s", loc5.getName(), "FOUR", loc5.getVariant());
+ }
+ Locale loc6("de-1901");
+ if (0 != strcmp(loc6.getVariant(), "1901")) {
+ errln("FAIL: de-1901 didn't get parsed correctly - name is %s - expected %s got %s", loc6.getName(), "1901", loc6.getVariant());
}
}
{ "qz-qz@Euro", "qz_QZ@Euro", "qz_QZ@currency=EUR" }, /* qz-qz uses private use iso codes */
// NOTE: uloc_getName() works on en-BOONT, but Locale() parser considers it BOGUS
// TODO: unify this behavior
- { "en-BOONT", "BOGUS", "en__BOONT" }, /* registered name */
- { "de-1901", "de_1901", "de__1901" }, /* registered name */
- { "de-1906", "de_1906", "de__1906" }, /* registered name */
+ { "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_RS" }, /* .NET name */
{ "sr-SP-Latn", "sr_SP_LATN", "sr_Latn_RS" }, /* .NET name */
{ "sr_YU_CYRILLIC", "sr_YU_CYRILLIC", "sr_Cyrl_RS" }, /* Linux name */
int32_t i, j;
- for (i=0; i < (int)(sizeof(testCases)/sizeof(testCases[0])); i++) {
+ for (i=0; i < UPRV_LENGTHOF(testCases); i++) {
for (j=0; j<3; ++j) {
const char* expected = (j==1) ? testCases[i].canonicalID : testCases[i].getNameID;
Locale loc = _canonicalize(j, testCases[i].localeID);
buffer[len] = '\0';
test_assert(strcmp("value", buffer) == 0);
}
+
+void LocaleTest::TestIsRightToLeft() {
+ assertFalse("root LTR", Locale::getRoot().isRightToLeft());
+ assertFalse("zh LTR", Locale::getChinese().isRightToLeft());
+ assertTrue("ar RTL", Locale("ar").isRightToLeft());
+ assertTrue("und-EG RTL", Locale("und-EG").isRightToLeft(), FALSE, TRUE);
+ assertFalse("fa-Cyrl LTR", Locale("fa-Cyrl").isRightToLeft());
+ assertTrue("en-Hebr RTL", Locale("en-Hebr").isRightToLeft());
+ assertTrue("ckb RTL", Locale("ckb").isRightToLeft(), FALSE, TRUE); // Sorani Kurdish
+ assertFalse("fil LTR", Locale("fil").isRightToLeft());
+ assertFalse("he-Zyxw LTR", Locale("he-Zyxw").isRightToLeft());
+}
+
+void LocaleTest::TestBug11421() {
+ Locale::getDefault().getBaseName();
+ int32_t numLocales;
+ const Locale *localeList = Locale::getAvailableLocales(numLocales);
+ for (int localeIndex = 0; localeIndex < numLocales; localeIndex++) {
+ const Locale &loc = localeList[localeIndex];
+ if (strncmp(loc.getName(), loc.getBaseName(), strlen(loc.getBaseName()))) {
+ errln("%s:%d loc.getName=\"%s\"; loc.getBaseName=\"%s\"",
+ __FILE__, __LINE__, loc.getName(), loc.getBaseName());
+ break;
+ }
+ }
+}
+
+// TestBug13277. The failure manifests as valgrind errors.
+// See the trac ticket for details.
+//
+
+void LocaleTest::TestBug13277() {
+ UErrorCode status = U_ZERO_ERROR;
+ CharString name("en-us-x-foo", -1, status);
+ while (name.length() < 152) {
+ name.append("-x-foo", -1, status);
+ }
+
+ while (name.length() < 160) {
+ name.append('z', status);
+ Locale loc(name.data(), nullptr, nullptr, nullptr);
+ }
+}
+
+// TestBug13554 Check for read past end of array in getPosixID().
+// The bug shows as an Address Sanitizer failure.
+
+void LocaleTest::TestBug13554() {
+ UErrorCode status = U_ZERO_ERROR;
+ const int BUFFER_SIZE = 100;
+ char posixID[BUFFER_SIZE];
+
+ for (uint32_t hostid = 0; hostid < 0x500; ++hostid) {
+ status = U_ZERO_ERROR;
+ uprv_convertToPosix(hostid, posixID, BUFFER_SIZE, &status);
+ }
+}
+
+