1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.lang3;
18
19 import static org.apache.commons.lang3.JavaVersion.JAVA_1_4;
20 import static org.apache.commons.lang3.LangAssertions.assertIllegalArgumentException;
21 import static org.junit.jupiter.api.Assertions.assertEquals;
22 import static org.junit.jupiter.api.Assertions.assertFalse;
23 import static org.junit.jupiter.api.Assertions.assertNotEquals;
24 import static org.junit.jupiter.api.Assertions.assertNotNull;
25 import static org.junit.jupiter.api.Assertions.assertNull;
26 import static org.junit.jupiter.api.Assertions.assertSame;
27 import static org.junit.jupiter.api.Assertions.assertThrows;
28 import static org.junit.jupiter.api.Assertions.assertTrue;
29
30 import java.lang.reflect.Constructor;
31 import java.lang.reflect.Modifier;
32 import java.util.Arrays;
33 import java.util.Collection;
34 import java.util.Comparator;
35 import java.util.HashSet;
36 import java.util.List;
37 import java.util.Locale;
38 import java.util.Set;
39 import java.util.concurrent.ConcurrentMap;
40
41 import org.junit.jupiter.api.BeforeEach;
42 import org.junit.jupiter.api.Test;
43 import org.junit.jupiter.params.ParameterizedTest;
44 import org.junit.jupiter.params.provider.MethodSource;
45 import org.junit.jupiter.params.provider.ValueSource;
46 import org.junitpioneer.jupiter.DefaultLocale;
47 import org.junitpioneer.jupiter.ReadsDefaultLocale;
48
49
50
51
52 class LocaleUtilsTest extends AbstractLangTest {
53
54 private static final Locale LOCALE_EN = new Locale("en", "");
55 private static final Locale LOCALE_EN_US = new Locale("en", "US");
56 private static final Locale LOCALE_EN_US_ZZZZ = new Locale("en", "US", "ZZZZ");
57 private static final Locale LOCALE_FR = new Locale("fr", "");
58 private static final Locale LOCALE_FR_CA = new Locale("fr", "CA");
59 private static final Locale LOCALE_QQ = new Locale("qq", "");
60 private static final Locale LOCALE_QQ_ZZ = new Locale("qq", "ZZ");
61
62
63
64
65
66
67
68
69
70
71
72 private static void assertCountriesByLanguage(final String language, final String[] countries) {
73 final List<Locale> list = LocaleUtils.countriesByLanguage(language);
74 final List<Locale> list2 = LocaleUtils.countriesByLanguage(language);
75 assertNotNull(list);
76 assertSame(list, list2);
77
78 for (final String country : countries) {
79 boolean found = false;
80
81 for (final Locale locale : list) {
82
83 assertTrue(StringUtils.isEmpty(locale.getVariant()));
84 assertEquals(language, locale.getLanguage());
85 if (country.equals(locale.getCountry())) {
86 found = true;
87 break;
88 }
89 }
90 assertTrue(found, "Could not find language: " + country + " for country: " + language);
91 }
92 assertUnmodifiableCollection(list);
93 }
94
95
96
97
98
99
100
101
102
103
104 private static void assertLanguageByCountry(final String country, final String[] languages) {
105 final List<Locale> list = LocaleUtils.languagesByCountry(country);
106 final List<Locale> list2 = LocaleUtils.languagesByCountry(country);
107 assertNotNull(list);
108 assertSame(list, list2);
109
110 for (final String language : languages) {
111 boolean found = false;
112
113 for (final Locale locale : list) {
114
115 assertTrue(StringUtils.isEmpty(locale.getVariant()));
116 assertEquals(country, locale.getCountry());
117 if (language.equals(locale.getLanguage())) {
118 found = true;
119 break;
120 }
121 }
122 assertTrue(found, "Could not find language: " + language + " for country: " + country);
123 }
124 assertUnmodifiableCollection(list);
125 }
126
127
128
129
130
131
132
133
134 private static void assertLocaleLookupList(final Locale locale, final Locale defaultLocale, final Locale[] expected) {
135 final List<Locale> localeList = defaultLocale == null ?
136 LocaleUtils.localeLookupList(locale) :
137 LocaleUtils.localeLookupList(locale, defaultLocale);
138
139 assertEquals(expected.length, localeList.size());
140 assertEquals(Arrays.asList(expected), localeList);
141 assertUnmodifiableCollection(localeList);
142 }
143
144
145
146
147 private static void assertUnmodifiableCollection(final Collection<?> coll) {
148 assertThrows(UnsupportedOperationException.class, () -> coll.add(null));
149 }
150
151
152
153
154
155
156 private static void assertValidToLocale(final String language) {
157 final Locale locale = LocaleUtils.toLocale(language);
158 assertNotNull(locale, "valid locale");
159 assertEquals(language, locale.getLanguage());
160
161 assertTrue(StringUtils.isEmpty(locale.getCountry()));
162 assertTrue(StringUtils.isEmpty(locale.getVariant()));
163 }
164
165
166
167
168
169
170
171
172 private static void assertValidToLocale(final String localeString, final String language, final String country) {
173 final Locale locale = LocaleUtils.toLocale(localeString);
174 assertNotNull(locale, "valid locale");
175 assertEquals(language, locale.getLanguage());
176 assertEquals(country, locale.getCountry());
177
178 assertTrue(StringUtils.isEmpty(locale.getVariant()));
179 }
180
181
182
183
184
185
186
187
188
189 private static void assertValidToLocale(
190 final String localeString, final String language,
191 final String country, final String variant) {
192 final Locale locale = LocaleUtils.toLocale(localeString);
193 assertNotNull(locale, "valid locale");
194 assertEquals(language, locale.getLanguage());
195 assertEquals(country, locale.getCountry());
196 assertEquals(variant, locale.getVariant());
197 }
198
199 @BeforeEach
200 @ReadsDefaultLocale
201 public void setUp() {
202
203 LocaleUtils.isAvailableLocale(Locale.getDefault());
204 }
205
206
207
208
209 @Test
210 void testAvailableLocaleList() {
211 final List<Locale> list = LocaleUtils.availableLocaleList();
212 final List<Locale> list2 = LocaleUtils.availableLocaleList();
213 assertNotNull(list);
214 assertSame(list, list2);
215 assertUnmodifiableCollection(list);
216
217 final Locale[] jdkLocaleArray = Locale.getAvailableLocales();
218 final List<Locale> jdkLocaleList = Arrays.asList(ArraySorter.sort(jdkLocaleArray, Comparator.comparing(Locale::toString)));
219 assertEquals(jdkLocaleList, list);
220 }
221
222
223
224
225 @Test
226 void testAvailableLocaleSet() {
227 final Set<Locale> set = LocaleUtils.availableLocaleSet();
228 final Set<Locale> set2 = LocaleUtils.availableLocaleSet();
229 assertNotNull(set);
230 assertSame(set, set2);
231 assertUnmodifiableCollection(set);
232
233 final Locale[] jdkLocaleArray = Locale.getAvailableLocales();
234 final List<Locale> jdkLocaleList = Arrays.asList(jdkLocaleArray);
235 final Set<Locale> jdkLocaleSet = new HashSet<>(jdkLocaleList);
236 assertEquals(jdkLocaleSet, set);
237 }
238
239
240
241
242 @Test
243 void testConstructor() {
244 assertNotNull(new LocaleUtils());
245 final Constructor<?>[] cons = LocaleUtils.class.getDeclaredConstructors();
246 assertEquals(1, cons.length);
247 assertTrue(Modifier.isPublic(cons[0].getModifiers()));
248 assertTrue(Modifier.isPublic(LocaleUtils.class.getModifiers()));
249 assertFalse(Modifier.isFinal(LocaleUtils.class.getModifiers()));
250 }
251
252
253
254
255 @Test
256 void testCountriesByLanguage() {
257 assertCountriesByLanguage(null, new String[0]);
258 assertCountriesByLanguage("de", new String[]{"DE", "CH", "AT", "LU"});
259 assertCountriesByLanguage("zz", new String[0]);
260 assertCountriesByLanguage("it", new String[]{"IT", "CH"});
261 }
262
263 @ParameterizedTest
264 @ValueSource(strings = {"x", "abcd", "EN", "e1", "en-US", " "})
265 void testCountriesByLanguageDoesNotCacheInvalidLanguageCode(final String languageCode) {
266 final ConcurrentMap<String, List<Locale>> map = LocaleUtils.getLcToLocalesMap();
267 assertFalse(map.containsKey(languageCode));
268 final int cacheSize = map.size();
269 assertTrue(LocaleUtils.countriesByLanguage(languageCode).isEmpty());
270 assertEquals(cacheSize, map.size());
271 assertFalse(map.containsKey(languageCode));
272 }
273
274 @Test
275 void testIllegalLanguageWithNumericCountry() {
276 assertIllegalArgumentException(() -> LocaleUtils.toLocale("../../unexpected_001"));
277 }
278
279 @Test
280 void testIllegalSingleCharLanguageWithNumericCountry() {
281 assertIllegalArgumentException(() -> LocaleUtils.toLocale("x_001"));
282 }
283
284
285
286
287 @SuppressWarnings("boxing")
288 @Test
289 void testIsAvailableLocale() {
290 final Set<Locale> set = LocaleUtils.availableLocaleSet();
291 assertEquals(set.contains(LOCALE_EN), LocaleUtils.isAvailableLocale(LOCALE_EN));
292 assertEquals(set.contains(LOCALE_EN_US), LocaleUtils.isAvailableLocale(LOCALE_EN_US));
293 assertEquals(set.contains(LOCALE_EN_US_ZZZZ), LocaleUtils.isAvailableLocale(LOCALE_EN_US_ZZZZ));
294 assertEquals(set.contains(LOCALE_FR), LocaleUtils.isAvailableLocale(LOCALE_FR));
295 assertEquals(set.contains(LOCALE_FR_CA), LocaleUtils.isAvailableLocale(LOCALE_FR_CA));
296 assertEquals(set.contains(LOCALE_QQ), LocaleUtils.isAvailableLocale(LOCALE_QQ));
297 assertEquals(set.contains(LOCALE_QQ_ZZ), LocaleUtils.isAvailableLocale(LOCALE_QQ_ZZ));
298 }
299
300 @Test
301 void testIsLanguageUndetermined() {
302 final Set<Locale> set = LocaleUtils.availableLocaleSet();
303
304 assertNotEquals(set.contains(LOCALE_EN), LocaleUtils.isLanguageUndetermined(LOCALE_EN));
305 assertNotEquals(set.contains(LOCALE_EN_US), LocaleUtils.isLanguageUndetermined(LOCALE_EN_US));
306 assertNotEquals(set.contains(LOCALE_FR), LocaleUtils.isLanguageUndetermined(LOCALE_FR));
307 assertNotEquals(set.contains(LOCALE_FR_CA), LocaleUtils.isLanguageUndetermined(LOCALE_FR_CA));
308
309 assertEquals(set.contains(LOCALE_EN_US_ZZZZ), LocaleUtils.isLanguageUndetermined(LOCALE_EN_US_ZZZZ));
310 assertEquals(set.contains(LOCALE_QQ), LocaleUtils.isLanguageUndetermined(LOCALE_QQ));
311 assertEquals(set.contains(LOCALE_QQ_ZZ), LocaleUtils.isLanguageUndetermined(LOCALE_QQ_ZZ));
312
313 assertTrue(LocaleUtils.isLanguageUndetermined(null));
314 }
315
316
317
318
319 @Test
320 void testLang1823() {
321 assertValidToLocale("th_TH_#Thai", "th", "TH", "#Thai");
322 }
323
324
325
326
327 @Test
328 void testLang328() {
329 assertValidToLocale("fr__P", "fr", "", "P");
330 assertValidToLocale("fr__POSIX", "fr", "", "POSIX");
331 }
332
333
334
335
336 @Test
337 void testLang865() {
338 assertValidToLocale("_GB", "", "GB", "");
339 assertValidToLocale("_GB_P", "", "GB", "P");
340 assertValidToLocale("_GB_POSIX", "", "GB", "POSIX");
341 assertIllegalArgumentException(() -> LocaleUtils.toLocale("_G"), "Must be at least 3 chars if starts with underscore");
342 assertIllegalArgumentException(() -> LocaleUtils.toLocale("_Gb"), "Must be uppercase if starts with underscore");
343 assertIllegalArgumentException(() -> LocaleUtils.toLocale("_gB"), "Must be uppercase if starts with underscore");
344 assertIllegalArgumentException(() -> LocaleUtils.toLocale("_1B"), "Must be letter if starts with underscore");
345 assertIllegalArgumentException(() -> LocaleUtils.toLocale("_G1"), "Must be letter if starts with underscore");
346 assertIllegalArgumentException(() -> LocaleUtils.toLocale("_GB_"), "Must be at least 5 chars if starts with underscore");
347 assertIllegalArgumentException(() -> LocaleUtils.toLocale("_GBAP"),
348 "Must have underscore after the country if starts with underscore and is at least 5 chars");
349 }
350
351 @Test
352 void testLanguageAndUNM49Numeric3AreaCodeLang1312() {
353 assertValidToLocale("en_001", "en", "001");
354 assertValidToLocale("en_150", "en", "150");
355 assertValidToLocale("ar_001", "ar", "001");
356
357
358 assertValidToLocale("en_001_GB", "en", "001", "GB");
359 assertValidToLocale("en_150_US", "en", "150", "US");
360 }
361
362
363
364
365 @Test
366 void testLanguagesByCountry() {
367 assertLanguageByCountry(null, new String[0]);
368 assertLanguageByCountry("GB", new String[]{"en"});
369 assertLanguageByCountry("ZZ", new String[0]);
370 assertLanguageByCountry("CH", new String[]{"fr", "de", "it"});
371 }
372
373 @ParameterizedTest
374 @ValueSource(strings = {"x", "abcd", "English", "e1", "en-US", " "})
375 void testLanguagesByCountryDoesNotCacheInvalidLanguageCode(final String languageCode) {
376 final ConcurrentMap<String, List<Locale>> map = LocaleUtils.getCcToLocalesMap();
377 assertFalse(map.containsKey(languageCode));
378 final int cacheSize = map.size();
379 assertTrue(LocaleUtils.languagesByCountry(languageCode).isEmpty());
380 assertEquals(cacheSize, map.size());
381 assertFalse(map.containsKey(languageCode));
382 }
383
384
385
386
387 @Test
388 void testLocaleLookupList_Locale() {
389 assertLocaleLookupList(null, null, new Locale[0]);
390 assertLocaleLookupList(LOCALE_QQ, null, new Locale[]{LOCALE_QQ});
391 assertLocaleLookupList(LOCALE_EN, null, new Locale[]{LOCALE_EN});
392 assertLocaleLookupList(LOCALE_EN, null, new Locale[]{LOCALE_EN});
393 assertLocaleLookupList(LOCALE_EN_US, null,
394 new Locale[] {
395 LOCALE_EN_US,
396 LOCALE_EN});
397 assertLocaleLookupList(LOCALE_EN_US_ZZZZ, null,
398 new Locale[] {
399 LOCALE_EN_US_ZZZZ,
400 LOCALE_EN_US,
401 LOCALE_EN});
402 }
403
404
405
406
407 @Test
408 void testLocaleLookupList_LocaleLocale() {
409 assertLocaleLookupList(LOCALE_QQ, LOCALE_QQ,
410 new Locale[]{LOCALE_QQ});
411 assertLocaleLookupList(LOCALE_EN, LOCALE_EN,
412 new Locale[]{LOCALE_EN});
413
414 assertLocaleLookupList(LOCALE_EN_US, LOCALE_EN_US,
415 new Locale[]{
416 LOCALE_EN_US,
417 LOCALE_EN});
418 assertLocaleLookupList(LOCALE_EN_US, LOCALE_QQ,
419 new Locale[] {
420 LOCALE_EN_US,
421 LOCALE_EN,
422 LOCALE_QQ});
423 assertLocaleLookupList(LOCALE_EN_US, LOCALE_QQ_ZZ,
424 new Locale[] {
425 LOCALE_EN_US,
426 LOCALE_EN,
427 LOCALE_QQ_ZZ});
428
429 assertLocaleLookupList(LOCALE_EN_US_ZZZZ, null,
430 new Locale[] {
431 LOCALE_EN_US_ZZZZ,
432 LOCALE_EN_US,
433 LOCALE_EN});
434 assertLocaleLookupList(LOCALE_EN_US_ZZZZ, LOCALE_EN_US_ZZZZ,
435 new Locale[] {
436 LOCALE_EN_US_ZZZZ,
437 LOCALE_EN_US,
438 LOCALE_EN});
439 assertLocaleLookupList(LOCALE_EN_US_ZZZZ, LOCALE_QQ,
440 new Locale[] {
441 LOCALE_EN_US_ZZZZ,
442 LOCALE_EN_US,
443 LOCALE_EN,
444 LOCALE_QQ});
445 assertLocaleLookupList(LOCALE_EN_US_ZZZZ, LOCALE_QQ_ZZ,
446 new Locale[] {
447 LOCALE_EN_US_ZZZZ,
448 LOCALE_EN_US,
449 LOCALE_EN,
450 LOCALE_QQ_ZZ});
451 assertLocaleLookupList(LOCALE_FR_CA, LOCALE_EN,
452 new Locale[] {
453 LOCALE_FR_CA,
454 LOCALE_FR,
455 LOCALE_EN});
456 }
457
458 @ParameterizedTest
459 @MethodSource("java.util.Locale#getAvailableLocales")
460 void testParseAllLocales(final Locale actualLocale) {
461
462 final Locale locale = new Locale(actualLocale.getLanguage(), actualLocale.getCountry(), actualLocale.getVariant());
463 if (actualLocale.equals(locale)) {
464 assertEquals(actualLocale, LocaleUtils.toLocale(actualLocale.toString()));
465 final String str = actualLocale.toString();
466
467 int suff = str.indexOf("_#");
468 if (suff == -1) {
469 suff = str.indexOf("#");
470 }
471 String localeStr = str;
472 if (suff >= 0) {
473 localeStr = str.substring(0, suff);
474 }
475 assertEquals(actualLocale, LocaleUtils.toLocale(localeStr));
476 }
477 }
478
479
480
481
482 @Test
483 void testSpecialCases() {
484 assertValidToLocale("th_TH_TH", "th", "TH", "TH");
485 assertValidToLocale("ja_JP_JP", "ja", "JP", "JP");
486
487 LocaleUtils.localeLookupList(new Locale("th", "TH", "TH")).forEach(locale -> assertEquals(locale, LocaleUtils.toLocale(locale.toString())));
488
489 LocaleUtils.localeLookupList(new Locale("ja", "JP", "JP")).forEach(locale -> assertEquals(locale, LocaleUtils.toLocale(locale.toString())));
490 }
491
492
493
494
495 @Test
496 void testThreeCharsLocale() {
497 for (final String str : Arrays.asList("udm", "tet")) {
498 final Locale locale = LocaleUtils.toLocale(str);
499 assertNotNull(locale);
500 assertEquals(str, locale.getLanguage());
501 assertTrue(StringUtils.isBlank(locale.getCountry()));
502 assertEquals(new Locale(str), locale);
503 }
504 }
505
506
507
508
509 @Test
510 void testToLocale_1Part() {
511 assertNull(LocaleUtils.toLocale((String) null));
512 assertValidToLocale("us");
513 assertValidToLocale("fr");
514 assertValidToLocale("de");
515 assertValidToLocale("zh");
516
517 assertValidToLocale("qq");
518
519 assertValidToLocale("");
520 assertIllegalArgumentException(() -> LocaleUtils.toLocale("Us"), "Should fail if not lowercase");
521 assertIllegalArgumentException(() -> LocaleUtils.toLocale("uS"), "Should fail if not lowercase");
522 assertIllegalArgumentException(() -> LocaleUtils.toLocale("u#"), "Should fail if not lowercase");
523 assertIllegalArgumentException(() -> LocaleUtils.toLocale("u"), "Must be 2 chars if less than 5");
524 assertIllegalArgumentException(() -> LocaleUtils.toLocale("uu_U"), "Must be 2 chars if less than 5");
525 }
526
527
528
529
530 @Test
531 void testToLocale_2Part() {
532 assertValidToLocale("us_EN", "us", "EN");
533 assertValidToLocale("us-EN", "us", "EN");
534
535 assertValidToLocale("us_ZH", "us", "ZH");
536 assertIllegalArgumentException(() -> LocaleUtils.toLocale("us_En"), "Should fail second part not uppercase");
537 assertIllegalArgumentException(() -> LocaleUtils.toLocale("us_en"), "Should fail second part not uppercase");
538 assertIllegalArgumentException(() -> LocaleUtils.toLocale("us_eN"), "Should fail second part not uppercase");
539 assertIllegalArgumentException(() -> LocaleUtils.toLocale("uS_EN"), "Should fail first part not lowercase");
540 assertIllegalArgumentException(() -> LocaleUtils.toLocale("us_E3"), "Should fail second part not uppercase");
541 }
542
543
544
545
546 @Test
547 void testToLocale_3Part() {
548 assertValidToLocale("us_EN_A", "us", "EN", "A");
549 assertValidToLocale("us-EN-A", "us", "EN", "A");
550
551
552 if (SystemUtils.isJavaVersionAtLeast(JAVA_1_4)) {
553 assertValidToLocale("us_EN_a", "us", "EN", "a");
554 assertValidToLocale("us_EN_SFsafdFDsdfF", "us", "EN", "SFsafdFDsdfF");
555 } else {
556 assertValidToLocale("us_EN_a", "us", "EN", "A");
557 assertValidToLocale("us_EN_SFsafdFDsdfF", "us", "EN", "SFSAFDFDSDFF");
558 }
559 assertIllegalArgumentException(() -> LocaleUtils.toLocale("us_EN-a"), "Should fail as no consistent delimiter");
560 assertIllegalArgumentException(() -> LocaleUtils.toLocale("uu_UU_"), "Must be 3, 5 or 7+ in length");
561
562 assertEquals(new Locale("en", "001", "US_POSIX"), LocaleUtils.toLocale("en_001_US_POSIX"));
563 }
564
565
566
567
568 @Test
569 @ReadsDefaultLocale
570 void testToLocale_Locale_defaults() {
571 assertNull(LocaleUtils.toLocale((String) null));
572 assertEquals(Locale.getDefault(), LocaleUtils.toLocale((Locale) null));
573 assertEquals(Locale.getDefault(), LocaleUtils.toLocale(Locale.getDefault()));
574 }
575
576 @ParameterizedTest
577 @MethodSource("java.util.Locale#getISOCountries")
578 void testToLocaleGetIso3Country(final String country) {
579 assertEquals(LocaleUtils.ofCountry(country).getISO3Country(), LocaleUtils.toLocale(country).getISO3Country());
580 }
581
582 @Test
583 void testToLocaleGetIso3CountryKnown() {
584 assertEquals("USA", LocaleUtils.toLocale("US").getISO3Country());
585 assertEquals("GBR", LocaleUtils.toLocale("GB").getISO3Country());
586 assertEquals("PAK", LocaleUtils.toLocale("PK").getISO3Country());
587 assertEquals("IND", LocaleUtils.toLocale("IN").getISO3Country());
588 assertEquals("FRA", LocaleUtils.toLocale("FR").getISO3Country());
589 }
590
591 @Test
592 @DefaultLocale(country = "US", language = "en")
593 void testToLocaleGetIso3LanguageKown() {
594 assertEquals("United States", LocaleUtils.toLocale("US").getDisplayCountry());
595 assertEquals("United Kingdom", LocaleUtils.toLocale("GB").getDisplayCountry());
596 assertEquals("Pakistan", LocaleUtils.toLocale("PK").getDisplayCountry());
597 assertEquals("India", LocaleUtils.toLocale("IN").getDisplayCountry());
598 assertEquals("France", LocaleUtils.toLocale("FR").getDisplayCountry());
599 }
600
601 @ParameterizedTest
602 @MethodSource("java.util.Locale#getISOCountries")
603 void testToLocaleGetIso3LanguageKown(final String country) {
604 assertEquals(LocaleUtils.ofCountry(country).getDisplayCountry(), LocaleUtils.toLocale(country).getDisplayCountry());
605 }
606
607
608
609
610 @ParameterizedTest
611 @MethodSource("java.util.Locale#getAvailableLocales")
612 void testToLocales(final Locale actualLocale) {
613 assertEquals(actualLocale, LocaleUtils.toLocale(actualLocale));
614 }
615 }