1 // © 2023 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3
4 #include "unicode/ctest.h"
5 #include "unicode/uloc.h"
6 #include "unicode/ulocale.h"
7 #include "cintltst.h"
8 #include "cmemory.h"
9 #include "cstring.h"
10
11 #define WHERE __FILE__ ":" XLINE(__LINE__) " "
12 #define XLINE(s) LINE(s)
13 #define LINE(s) #s
14
15 #define TESTCASE(name) addTest(root, &name, "tsutil/ulocaletst/" #name)
16
17 enum {
18 LANGUAGE = 0,
19 SCRIPT,
20 REGION,
21 VAR,
22 NAME,
23 BASENAME,
24 };
25 static const char* const rawData[][6] = {
26 { "en", "", "US", "", "en_US", "en_US"},
27 { "fr", "", "FR", "", "fr_FR", "fr_FR"},
28 { "ca", "", "ES", "", "ca_ES", "ca_ES"},
29 { "el", "", "GR", "", "el_GR", "el_GR"},
30 { "no", "", "NO", "NY", "no_NO_NY", "no_NO_NY"},
31 { "it", "", "", "", "it", "it"},
32 { "xx", "", "YY", "", "xx_YY", "xx_YY"},
33 { "zh", "Hans", "CN", "", "zh_Hans_CN", "zh_Hans_CN"},
34 { "zh", "Hans", "CN", "", "zh_Hans_CN", "zh_Hans_CN"},
35 { "x-klingon", "Latn", "ZX", "", "x-klingon_Latn_ZX.utf32be@special", "x-klingon_Latn_ZX.utf32be@special"},
36 };
37
TestBasicGetters(void)38 static void TestBasicGetters(void) {
39 for (int32_t i = 0; i < UPRV_LENGTHOF(rawData); i++) {
40 UErrorCode status = U_ZERO_ERROR;
41 ULocale* l = ulocale_openForLocaleID(rawData[i][NAME], -1, &status);
42 if (assertSuccess(WHERE "ulocale_openForLocaleID()", &status)) {
43 assertEquals(WHERE "ulocale_getLanguage()", rawData[i][LANGUAGE], ulocale_getLanguage(l));
44 assertEquals(WHERE "ulocale_getScript()", rawData[i][SCRIPT], ulocale_getScript(l));
45 assertEquals(WHERE "ulocale_getRegion()", rawData[i][REGION], ulocale_getRegion(l));
46 assertEquals(WHERE "ulocale_getVariant()", rawData[i][VAR], ulocale_getVariant(l));
47 assertEquals(WHERE "ulocale_getLocaleID()", rawData[i][NAME], ulocale_getLocaleID(l));
48 assertEquals(WHERE "ulocale_getBaseName()", rawData[i][BASENAME], ulocale_getBaseName(l));
49 ulocale_close(l);
50 }
51 }
52 }
53
VerifyMatch(const char * localeID,const char * tag)54 static void VerifyMatch(const char* localeID, const char* tag) {
55 UErrorCode status = U_ZERO_ERROR;
56 ULocale* fromID = ulocale_openForLocaleID(localeID, -1, &status);
57 if (assertSuccess(WHERE "ulocale_openForLocaleID()", &status)) {
58 ULocale* fromTag = ulocale_openForLanguageTag(tag, -1, &status);
59 if (assertSuccess(WHERE "ulocale_openForLanguageTag()", &status)) {
60 assertEquals(tag, ulocale_getLocaleID(fromID), ulocale_getLocaleID(fromTag));
61 ulocale_close(fromTag);
62 }
63 ulocale_close(fromID);
64 }
65 }
66
TestForLanguageTag(void)67 static void TestForLanguageTag(void) {
68 VerifyMatch("en_US", "en-US");
69 VerifyMatch("en_GB_OXENDICT", "en-GB-oed");
70 VerifyMatch("af@calendar=coptic;t=ar-i0-handwrit;x=foo", "af-t-ar-i0-handwrit-u-ca-coptic-x-foo");
71 VerifyMatch("en_GB", "en-GB");
72 VerifyMatch("en_GB@1=abc-efg;a=xyz", "en-GB-1-abc-efg-a-xyz"); // ext
73 VerifyMatch("sl__1994_BISKE_ROZAJ", "sl-rozaj-biske-1994"); // var
74
75 UErrorCode status = U_ZERO_ERROR;
76 ULocale* result_ill = ulocale_openForLanguageTag("!", -1, &status);
77 assertIntEquals("!", U_ILLEGAL_ARGUMENT_ERROR, status);
78 assertPtrEquals("!", NULL, result_ill);
79 ulocale_close(result_ill);
80
81 VerifyMatch("", NULL);
82
83 // ICU-21433
84 VerifyMatch("__1994_BISKE_ROZAJ", "und-1994-biske-rozaj");
85 VerifyMatch("de__1994_BISKE_ROZAJ", "de-1994-biske-rozaj");
86 VerifyMatch("@x=private", "und-x-private");
87 VerifyMatch("de__1994_BISKE_ROZAJ@x=private", "de-1994-biske-rozaj-x-private");
88 VerifyMatch("__1994_BISKE_ROZAJ@x=private", "und-1994-biske-rozaj-x-private");
89 }
90
TestGetKeywords(void)91 static void TestGetKeywords(void) {
92 UErrorCode status = U_ZERO_ERROR;
93 ULocale* l = ulocale_openForLocaleID("de@calendar=buddhist;collation=phonebook", -1, &status);
94 if (assertSuccess(WHERE "ulocale_openForLocaleID()", &status)) {
95 UEnumeration* en = ulocale_getKeywords(l, &status);
96 if (assertSuccess(WHERE "ulocale_getKeywords()", &status)) {
97 assertIntEquals("uenum_count()", 2, uenum_count(en, &status));
98 bool hasCalendar = false;
99 bool hasCollation = false;
100 const char* key = NULL;
101 while ((key = uenum_next(en, NULL, &status)) != NULL) {
102 if (uprv_strcmp(key, "calendar") == 0) {
103 hasCalendar = true;
104 } else if (uprv_strcmp(key, "collation") == 0) {
105 hasCollation = true;
106 }
107 }
108 assertTrue(
109 WHERE "ulocale_getKeywords() should return UEnumeration that has \"calendar\"",
110 hasCalendar);
111 assertTrue(
112 WHERE "ulocale_getKeywords() should return UEnumeration that has \"collation\"",
113 hasCollation);
114 uenum_close(en);
115 }
116 ulocale_close(l);
117 }
118 }
119
TestGetKeywordsEmpty(void)120 static void TestGetKeywordsEmpty(void) {
121 UErrorCode status = U_ZERO_ERROR;
122 ULocale* l = ulocale_openForLocaleID("de", -1, &status);
123 if (assertSuccess(WHERE "ulocale_openForLocaleID()", &status)) {
124 UEnumeration* en = ulocale_getKeywords(l, &status);
125 if (assertSuccess(WHERE "ulocale_getKeywords()", &status)) {
126 assertPtrEquals(WHERE "ulocale_getKeyword()", NULL, en);
127 uenum_close(en);
128 }
129 ulocale_close(l);
130 }
131 }
132
TestGetKeywordsWithPrivateUse(void)133 static void TestGetKeywordsWithPrivateUse(void) {
134 UErrorCode status = U_ZERO_ERROR;
135 ULocale* l = ulocale_openForLanguageTag("en-US-u-ca-gregory-x-foo", -1, &status);
136 if (assertSuccess(WHERE "ulocale_openForLanguageTag()", &status)) {
137 UEnumeration* en = ulocale_getKeywords(l, &status);
138 if (assertSuccess(WHERE "ulocale_getKeywords()", &status)) {
139 assertIntEquals("uenum_count()", 2, uenum_count(en, &status));
140 bool hasCalendar = false;
141 bool hasX = false;
142 const char* key = NULL;
143 while ((key = uenum_next(en, NULL, &status)) != NULL) {
144 if (uprv_strcmp(key, "calendar") == 0) {
145 hasCalendar = true;
146 } else if (uprv_strcmp(key, "x") == 0) {
147 hasX = true;
148 }
149 }
150 assertTrue(WHERE "ulocale_getKeywords() should return UEnumeration that has \"calendar\"",
151 hasCalendar);
152 assertTrue(WHERE "ulocale_getKeywords() should return UEnumeration that has \"x\"",
153 hasX);
154 uenum_close(en);
155 }
156 ulocale_close(l);
157 }
158 }
159
TestGetUnicodeKeywords(void)160 static void TestGetUnicodeKeywords(void) {
161 UErrorCode status = U_ZERO_ERROR;
162 ULocale* l = ulocale_openForLocaleID("de@calendar=buddhist;collation=phonebook", -1, &status);
163 if (assertSuccess(WHERE "ulocale_openForLocaleID()", &status)) {
164 UEnumeration* en = ulocale_getUnicodeKeywords(l, &status);
165 if (assertSuccess(WHERE "ulocale_getUnicodeKeywords()", &status)) {
166 assertIntEquals("uenum_count()", 2, uenum_count(en, &status));
167 bool hasCa = false;
168 bool hasCo = false;
169 const char* key = NULL;
170 while ((key = uenum_next(en, NULL, &status)) != NULL) {
171 if (uprv_strcmp(key, "ca") == 0) {
172 hasCa = true;
173 } else if (uprv_strcmp(key, "co") == 0) {
174 hasCo = true;
175 }
176 }
177 assertTrue(
178 WHERE "ulocale_getUnicodeKeywords() should return UEnumeration that has \"ca\"",
179 hasCa);
180 assertTrue(
181 WHERE "ulocale_getUnicodeKeywords() should return UEnumeration that has \"co\"",
182 hasCo);
183 uenum_close(en);
184 }
185 ulocale_close(l);
186 }
187 }
188
TestGetUnicodeKeywordsEmpty(void)189 static void TestGetUnicodeKeywordsEmpty(void) {
190 UErrorCode status = U_ZERO_ERROR;
191 ULocale* l = ulocale_openForLocaleID("de", -1, &status);
192 if (assertSuccess(WHERE "ulocale_openForLocaleID()", &status)) {
193 UEnumeration* en = ulocale_getUnicodeKeywords(l, &status);
194 if (assertSuccess(WHERE "ulocale_getUnicodeKeywords()", &status)) {
195 assertPtrEquals("ulocale_getUnicodeKeyword()", NULL, en);
196 uenum_close(en);
197 }
198 ulocale_close(l);
199 }
200 }
201
TestGetUnicodeKeywordsWithPrivateUse(void)202 static void TestGetUnicodeKeywordsWithPrivateUse(void) {
203 UErrorCode status = U_ZERO_ERROR;
204 ULocale* l = ulocale_openForLanguageTag("en-US-u-ca-gregory-x-foo", -1, &status);
205 if (assertSuccess(WHERE "ulocale_openForLanguageTag()", &status)) {
206 UEnumeration* en = ulocale_getUnicodeKeywords(l, &status);
207 if (assertSuccess(WHERE "ulocale_getUnicodeKeywords()", &status)) {
208 int32_t count = uenum_count(en, &status);
209 if (count != 1) {
210 log_knownIssue("ICU-22457", "uenum_count() should be 1 but get %d\n", count);
211 }
212 const char* key = uenum_next(en, NULL, &status);
213 if (assertSuccess(WHERE "uenum_next()", &status)) {
214 assertEquals(WHERE "ulocale_getUnicodeKeywords() should return UEnumeration that has \"ca\"",
215 "ca", key);
216 }
217 uenum_close(en);
218 }
219 ulocale_close(l);
220 }
221 }
222
TestGetKeywordValue(void)223 static void TestGetKeywordValue(void) {
224 UErrorCode status = U_ZERO_ERROR;
225 ULocale* l = ulocale_openForLanguageTag("fa-u-nu-thai", -1, &status);
226 if (assertSuccess(WHERE "ulocale_openForLanguageTag()", &status)) {
227 char buffer[ULOC_FULLNAME_CAPACITY];
228 ulocale_getKeywordValue(l, "numbers", -1, buffer, ULOC_FULLNAME_CAPACITY, &status);
229 if (assertSuccess(WHERE "ulocale_getKeywordValue()", &status)) {
230 assertEquals(WHERE "ulocale_getKeywordValue(\"numbers\")", "thai", buffer);
231 }
232
233 ulocale_getKeywordValue(l, "calendar", -1, buffer, ULOC_FULLNAME_CAPACITY, &status);
234 if (assertSuccess(WHERE "ulocale_getKeywordValue()", &status)) {
235 assertEquals(WHERE "ulocale_getKeywordValue(\"calendar\")", "", buffer);
236 }
237 ulocale_getKeywordValue(l, "collation", -1, buffer, ULOC_FULLNAME_CAPACITY, &status);
238 if (assertSuccess(WHERE "ulocale_getKeywordValue()", &status)) {
239 assertEquals(WHERE "ulocale_getKeywordValue(\"collation\")", "", buffer);
240 }
241 ulocale_close(l);
242 }
243 }
244
TestGetUnicodeKeywordValue(void)245 static void TestGetUnicodeKeywordValue(void) {
246 UErrorCode status = U_ZERO_ERROR;
247 ULocale* l = ulocale_openForLanguageTag("fa-u-nu-thai", -1, &status);
248 if (assertSuccess(WHERE "ulocale_openForLanguageTag()", &status)) {
249 char buffer[ULOC_FULLNAME_CAPACITY];
250 ulocale_getUnicodeKeywordValue(l, "nu", -1, buffer, ULOC_FULLNAME_CAPACITY, &status);
251 if (assertSuccess(WHERE "ulocale_getUnicodeKeywordValue()", &status)) {
252 assertEquals(WHERE "ulocale_getUnicodeKeywordValue(\"nu\")", "thai", buffer);
253 }
254
255 ulocale_getUnicodeKeywordValue(l, "ca", -1, buffer, ULOC_FULLNAME_CAPACITY, &status);
256 if (U_FAILURE(status) || buffer[0] != '\0') {
257 log_knownIssue(
258 "ICU-22459",
259 WHERE "ulocale_getUnicodeKeywordValue(\"fa-u-nu-thai\", \"ca\") should not return error and should return empty string.");
260 }
261 ulocale_getUnicodeKeywordValue(l, "co", -1, buffer, ULOC_FULLNAME_CAPACITY, &status);
262 if (U_FAILURE(status) || buffer[0] != '\0') {
263 log_knownIssue(
264 "ICU-22459",
265 WHERE "ulocale_getUnicodeKeywordValue(\"fa-u-nu-thai\", \"co\") should not return error and should return empty string.");
266 }
267 ulocale_close(l);
268 }
269 }
270
271 void addULocaleTest(TestNode** root);
addULocaleTest(TestNode ** root)272 void addULocaleTest(TestNode** root)
273 {
274 TESTCASE(TestBasicGetters);
275 TESTCASE(TestForLanguageTag);
276 TESTCASE(TestGetKeywords);
277 TESTCASE(TestGetKeywordsEmpty);
278 TESTCASE(TestGetKeywordsWithPrivateUse);
279 TESTCASE(TestGetUnicodeKeywords);
280 TESTCASE(TestGetUnicodeKeywordsEmpty);
281 TESTCASE(TestGetUnicodeKeywordsWithPrivateUse);
282 TESTCASE(TestGetKeywordValue);
283 TESTCASE(TestGetUnicodeKeywordValue);
284 }
285
286