1/*
2 * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23/**
24 * @test
25 * @bug 4052404 4052440 4084688 4092475 4101316 4105828 4107014 4107953 4110613
26 * 4118587 4118595 4122371 4126371 4126880 4135316 4135752 4139504 4139940 4143951
27 * 4147315 4147317 4147552 4335196 4778440 4940539 5010672 6475525 6544471 6627549
28 * 6786276 7066203 7085757 8008577 8030696 8170840
29 * @summary test Locales
30 * @library /java/text/testlib
31 * @modules jdk.localedata
32 * @run main/othervm -Djava.locale.providers=JRE,SPI LocaleTest
33 */
34/*
35 *
36 *
37 * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
38 * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
39 *
40 * Portions copyright (c) 2007 Sun Microsystems, Inc.
41 * All Rights Reserved.
42 *
43 * The original version of this source code and documentation
44 * is copyrighted and owned by Taligent, Inc., a wholly-owned
45 * subsidiary of IBM. These materials are provided under terms
46 * of a License Agreement between Taligent and Sun. This technology
47 * is protected by multiple US and International patents.
48 *
49 * This notice and attribution to Taligent may not be removed.
50 * Taligent is a registered trademark of Taligent, Inc.
51 *
52 * Permission to use, copy, modify, and distribute this software
53 * and its documentation for NON-COMMERCIAL purposes and without
54 * fee is hereby granted provided that this copyright notice
55 * appears in all copies. Please refer to the file "copyright.html"
56 * for further important copyright and licensing information.
57 *
58 * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
59 * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
60 * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
61 * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
62 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
63 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
64 *
65 */
66
67import java.io.ByteArrayInputStream;
68import java.io.ByteArrayOutputStream;
69import java.io.IOException;
70import java.io.ObjectInputStream;
71import java.io.ObjectOutputStream;
72import java.io.OptionalDataException;
73import java.io.StreamCorruptedException;
74import java.text.DateFormat;
75import java.text.DecimalFormat;
76import java.text.NumberFormat;
77import java.text.SimpleDateFormat;
78import java.util.Arrays;
79import java.util.Calendar;
80import java.util.Date;
81import java.util.List;
82import java.util.Locale;
83import java.util.MissingResourceException;
84
85public class LocaleTest extends IntlTest {
86    public LocaleTest() {
87    }
88
89    private int ENGLISH = 0;
90    private int FRENCH = 1;
91    private int CROATIAN = 2;
92    private int GREEK = 3;
93    private int NORWEGIAN = 4;
94    private int ITALIAN = 5;
95    private int DUMMY = 6;
96    private int MAX_LOCALES = 6;
97
98    private int LANG = 0;
99    private int CTRY = 1;
100    private int VAR = 2;
101    private int NAME = 3;
102    private int LANG3 = 4;
103    private int CTRY3 = 5;
104    private int LCID = 6;
105    private int DLANG_EN = 7;
106    private int DCTRY_EN = 8;
107    private int DVAR_EN = 9;
108    private int DNAME_EN = 10;
109    private int DLANG_FR = 11;
110    private int DCTRY_FR = 12;
111    private int DVAR_FR = 13;
112    private int DNAME_FR = 14;
113    private int DLANG_HR = 15;
114    private int DCTRY_HR = 16;
115    private int DVAR_HR = 17;
116    private int DNAME_HR = 18;
117    private int DLANG_EL = 19;
118    private int DCTRY_EL = 20;
119    private int DVAR_EL = 21;
120    private int DNAME_EL = 22;
121    private int DLANG_ROOT = 23;
122    private int DCTRY_ROOT = 24;
123    private int DVAR_ROOT = 25;
124    private int DNAME_ROOT = 26;
125
126    private String[][] dataTable = {
127        // language code
128        {   "en",   "fr",   "hr",   "el",   "no",   "it",   "xx"    },
129        // country code
130        {   "US",   "FR",   "HR",   "GR",   "NO",   "",   "YY"    },
131        // variant code
132        {   "",     "",     "",     "",     "NY",   "",   ""    },
133        // full name
134        {   "en_US",    "fr_FR",    "hr_HR",    "el_GR",    "no_NO_NY", "it",   "xx_YY"  },
135        // ISO-3 language
136        {   "eng",  "fra",  "hrv",  "ell",  "nor",  "ita",  ""   },
137        // ISO-3 country
138        {   "USA",  "FRA",  "HRV",  "GRC",  "NOR",  "",     ""   },
139        // LCID (not currently public)
140        {   "0409", "040c", "041a", "0408", "0814", "",     ""  },
141
142        // display language (English)
143        {   "English",  "French",   "Croatian", "Greek",    "Norwegian",    "Italian",  "xx" },
144        // display country (English)
145        {   "United States",    "France",   "Croatia",  "Greece",   "Norway",   "",     "YY" },
146        // display variant (English)
147        {   "",     "",     "",     "",     "Nynorsk",   "",     ""},
148        // display name (English)
149        // Updated no_NO_NY English display name for new pattern-based algorithm
150        // (part of Euro support).
151        {   "English (United States)", "French (France)", "Croatian (Croatia)", "Greek (Greece)", "Norwegian (Norway,Nynorsk)", "Italian", "xx (YY)" },
152
153        // display langage (French)
154        {   "anglais",  "fran\u00e7ais",   "croate", "grec",    "norv\u00e9gien",    "italien", "xx" },
155        // display country (French)
156        {   "Etats-Unis",    "France",   "Croatie",  "Gr\u00e8ce",   "Norv\u00e8ge", "",     "YY" },
157        // display variant (French)
158        {   "",     "",     "",     "",     "",     "",    "" },
159        // display name (French)
160        {   "anglais (Etats-Unis)", "fran\u00e7ais (France)", "croate (Croatie)", "grec (Gr\u00e8ce)", "norv\u00e9gien (Norv\u00e8ge,Nynorsk)", "italien", "xx (YY)" },
161
162        // display langage (Croatian)
163        {   "",  "", "hrvatski", "",    "", "", "xx" },
164        // display country (Croatian)
165        {   "",    "",   "Hrvatska",  "",   "", "", "YY" },
166        // display variant (Croatian)
167        {   "",     "",     "",     "",     "", "", ""},
168        // display name (Croatian)
169        {   "", "", "hrvatski (Hrvatska)", "", "", "", "xx (YY)" },
170
171        // display langage (Greek)
172        {   "\u0391\u03b3\u03b3\u03bb\u03b9\u03ba\u03ac",  "\u0393\u03b1\u03bb\u03bb\u03b9\u03ba\u03ac", "\u039a\u03c1\u03bf\u03b1\u03c4\u03b9\u03ba\u03ac", "\u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac",    "\u039d\u03bf\u03c1\u03b2\u03b7\u03b3\u03b9\u03ba\u03ac", "\u0399\u03c4\u03b1\u03bb\u03b9\u03ba\u03ac", "xx" },
173        // display country (Greek)
174        {   "\u0397\u03bd\u03c9\u03bc\u03ad\u03bd\u03b5\u03c2 \u03a0\u03bf\u03bb\u03b9\u03c4\u03b5\u03af\u03b5\u03c2",    "\u0393\u03b1\u03bb\u03bb\u03af\u03b1",   "\u039a\u03c1\u03bf\u03b1\u03c4\u03af\u03b1",  "\u0395\u03bb\u03bb\u03ac\u03b4\u03b1",   "\u039d\u03bf\u03c1\u03b2\u03b7\u03b3\u03af\u03b1", "", "YY" },
175        // display variant (Greek)
176        {   "",     "",     "",     "",     "", "", "" },
177        // display name (Greek)
178        {   "\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\u03c1\u03bf\u03b1\u03c4\u03b9\u03ba\u03ac (\u039a\u03c1\u03bf\u03b1\u03c4\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,Nynorsk)", "\u0399\u03c4\u03b1\u03bb\u03b9\u03ba\u03ac", "xx (YY)" },
179
180        // display langage (<root>)
181        {   "English",  "French",   "Croatian", "Greek",    "Norwegian",  "Italian",  "xx" },
182        // display country (<root>)
183        {   "United States",    "France",   "Croatia",  "Greece",   "Norway",  "",     "YY" },
184        // display variant (<root>)
185        {   "",     "",     "",     "",     "Nynorsk",   "",     ""},
186        // display name (<root>)
187        {   "English (United States)", "French (France)", "Croatian (Croatia)", "Greek (Greece)", "Norwegian (Norway,Nynorsk)", "Italian", "xx (YY)" },
188    };
189
190    public static void main(String[] args) throws Exception {
191        new LocaleTest().run(args);
192    }
193
194    public void TestBasicGetters() {
195        for (int i = 0; i <= MAX_LOCALES; i++) {
196            Locale testLocale = new Locale(dataTable[LANG][i], dataTable[CTRY][i], dataTable[VAR][i]);
197            logln("Testing " + testLocale + "...");
198
199            if (!testLocale.getLanguage().equals(dataTable[LANG][i])) {
200                errln("  Language code mismatch: " + testLocale.getLanguage() + " versus "
201                        + dataTable[LANG][i]);
202            }
203            if (!testLocale.getCountry().equals(dataTable[CTRY][i])) {
204                errln("  Country code mismatch: " + testLocale.getCountry() + " versus "
205                        + dataTable[CTRY][i]);
206            }
207            if (!testLocale.getVariant().equals(dataTable[VAR][i])) {
208                errln("  Variant code mismatch: " + testLocale.getVariant() + " versus "
209                        + dataTable[VAR][i]);
210            }
211            if (!testLocale.toString().equals(dataTable[NAME][i])) {
212                errln("  Locale name mismatch: " + testLocale.toString() + " versus "
213                        + dataTable[NAME][i]);
214            }
215        }
216
217        logln("Same thing without variant codes...");
218        for (int i = 0; i <= MAX_LOCALES; i++) {
219            Locale testLocale = new Locale(dataTable[LANG][i], dataTable[CTRY][i]);
220            logln("Testing " + testLocale + "...");
221
222            if (!testLocale.getLanguage().equals(dataTable[LANG][i])) {
223                errln("  Language code mismatch: " + testLocale.getLanguage() + " versus "
224                        + dataTable[LANG][i]);
225            }
226            if (!testLocale.getCountry().equals(dataTable[CTRY][i])) {
227                errln("  Country code mismatch: " + testLocale.getCountry() + " versus "
228                        + dataTable[CTRY][i]);
229            }
230            if (!testLocale.getVariant().equals("")) {
231                errln("  Variant code mismatch: " + testLocale.getVariant() + " versus \"\"");
232            }
233        }
234    }
235
236    public void TestSimpleResourceInfo() {
237        for (int i = 0; i <= MAX_LOCALES; i++) {
238            if (dataTable[LANG][i].equals("xx")) {
239                continue;
240            }
241
242            Locale testLocale = new Locale(dataTable[LANG][i], dataTable[CTRY][i], dataTable[VAR][i]);
243            logln("Testing " + testLocale + "...");
244
245            if (!testLocale.getISO3Language().equals(dataTable[LANG3][i])) {
246                errln("  ISO-3 language code mismatch: " + testLocale.getISO3Language()
247                        + " versus " + dataTable[LANG3][i]);
248            }
249            if (!testLocale.getISO3Country().equals(dataTable[CTRY3][i])) {
250                errln("  ISO-3 country code mismatch: " + testLocale.getISO3Country()
251                        + " versus " + dataTable[CTRY3][i]);
252            }
253/*
254            // getLCID() is currently private
255            if (!String.valueOf(testLocale.getLCID()).equals(dataTable[LCID][i]))
256                errln("  LCID mismatch: " + testLocale.getLCID() + " versus "
257                            + dataTable[LCID][i]);
258*/
259        }
260    }
261
262    /*
263     * @bug 4101316
264     * @bug 4084688 (This bug appears to be a duplicate of something, because it was fixed
265     *              between 1.1.5 and 1.1.6, but I included a new test for it anyway)
266     * @bug 4052440 Stop falling back to the default locale.
267     */
268    public void TestDisplayNames() {
269        Locale saveDefault = Locale.getDefault();
270        Locale english = new Locale("en", "US");
271        Locale french = new Locale("fr", "FR");
272        Locale croatian = new Locale("hr", "HR");
273        Locale greek = new Locale("el", "GR");
274
275        Locale.setDefault(english);
276        logln("With default = en_US...");
277        logln("  In default locale...");
278        doTestDisplayNames(null, DLANG_EN, false);
279        logln("  In locale = en_US...");
280        doTestDisplayNames(english, DLANG_EN, false);
281        logln("  In locale = fr_FR...");
282        doTestDisplayNames(french, DLANG_FR, false);
283        logln("  In locale = hr_HR...");
284        doTestDisplayNames(croatian, DLANG_HR, false);
285        logln("  In locale = el_GR...");
286        doTestDisplayNames(greek, DLANG_EL, false);
287
288        Locale.setDefault(french);
289        logln("With default = fr_FR...");
290        logln("  In default locale...");
291        doTestDisplayNames(null, DLANG_FR, true);
292        logln("  In locale = en_US...");
293        doTestDisplayNames(english, DLANG_EN, true);
294        logln("  In locale = fr_FR...");
295        doTestDisplayNames(french, DLANG_FR, true);
296        logln("  In locale = hr_HR...");
297        doTestDisplayNames(croatian, DLANG_HR, true);
298        logln("  In locale = el_GR...");
299        doTestDisplayNames(greek, DLANG_EL, true);
300
301        Locale.setDefault(saveDefault);
302    }
303
304    private void doTestDisplayNames(Locale inLocale, int compareIndex, boolean defaultIsFrench) {
305        String language = Locale.getDefault().getLanguage();
306
307        if (defaultIsFrench && !language.equals("fr")) {
308            errln("Default locale should be French, but it's really " + language);
309        } else if (!defaultIsFrench && !language.equals("en")) {
310            errln("Default locale should be English, but it's really " + language);
311        }
312
313        for (int i = 0; i <= MAX_LOCALES; i++) {
314            Locale testLocale = new Locale(dataTable[LANG][i], dataTable[CTRY][i], dataTable[VAR][i]);
315            logln("  Testing " + testLocale + "...");
316
317            String testLang;
318            String testCtry;
319            String testVar;
320            String testName;
321
322            if (inLocale == null) {
323                testLang = testLocale.getDisplayLanguage();
324                testCtry = testLocale.getDisplayCountry();
325                testVar = testLocale.getDisplayVariant();
326                testName = testLocale.getDisplayName();
327            } else {
328                testLang = testLocale.getDisplayLanguage(inLocale);
329                testCtry = testLocale.getDisplayCountry(inLocale);
330                testVar = testLocale.getDisplayVariant(inLocale);
331                testName = testLocale.getDisplayName(inLocale);
332            }
333
334            String expectedLang;
335            String expectedCtry;
336            String expectedVar;
337            String expectedName;
338
339            expectedLang = dataTable[compareIndex][i];
340            if (expectedLang.equals("") && defaultIsFrench) {
341                expectedLang = dataTable[DLANG_EN][i];
342            }
343            if (expectedLang.equals("")) {
344                expectedLang = dataTable[DLANG_ROOT][i];
345            }
346
347            expectedCtry = dataTable[compareIndex + 1][i];
348            if (expectedCtry.equals("") && defaultIsFrench) {
349                expectedCtry = dataTable[DCTRY_EN][i];
350            }
351            if (expectedCtry.equals("")) {
352                expectedCtry = dataTable[DCTRY_ROOT][i];
353            }
354
355            expectedVar = dataTable[compareIndex + 2][i];
356            if (expectedVar.equals("") && defaultIsFrench) {
357                expectedVar = dataTable[DVAR_EN][i];
358            }
359            if (expectedVar.equals("")) {
360                expectedVar = dataTable[DVAR_ROOT][i];
361            }
362
363            expectedName = dataTable[compareIndex + 3][i];
364            if (expectedName.equals("") && defaultIsFrench) {
365                expectedName = dataTable[DNAME_EN][i];
366            }
367            if (expectedName.equals("")) {
368                expectedName = dataTable[DNAME_ROOT][i];
369            }
370
371            if (!testLang.equals(expectedLang)) {
372                errln("Display language mismatch: " + testLang + " versus " + expectedLang);
373            }
374            if (!testCtry.equals(expectedCtry)) {
375                errln("Display country mismatch: " + testCtry + " versus " + expectedCtry);
376            }
377            if (!testVar.equals(expectedVar)) {
378                errln("Display variant mismatch: " + testVar + " versus " + expectedVar);
379            }
380            if (!testName.equals(expectedName)) {
381                errln("Display name mismatch: " + testName + " versus " + expectedName);
382            }
383        }
384    }
385
386    public void TestSimpleObjectStuff() {
387        Locale test1 = new Locale("aa", "AA");
388        Locale test2 = new Locale("aa", "AA");
389        Locale test3 = (Locale) test1.clone();
390        Locale test4 = new Locale("zz", "ZZ");
391
392        if (test1 == test2 || test1 == test3 || test1 == test4 || test2 == test3) {
393            errln("Some of the test variables point to the same locale!");
394        }
395
396        if (test3 == null) {
397            errln("clone() failed to produce a valid object!");
398        }
399
400        if (!test1.equals(test2) || !test1.equals(test3) || !test2.equals(test3)) {
401            errln("clone() or equals() failed: objects that should compare equal don't");
402        }
403
404        if (test1.equals(test4) || test2.equals(test4) || test3.equals(test4)) {
405            errln("equals() failed: objects that shouldn't compare equal do");
406        }
407
408        int hash1 = test1.hashCode();
409        int hash2 = test2.hashCode();
410        int hash3 = test3.hashCode();
411
412        if (hash1 != hash2 || hash1 != hash3 || hash2 != hash3) {
413            errln("hashCode() failed: objects that should have the same hash code don't");
414        }
415    }
416
417    /**
418     * @bug 4011756 4011380
419     */
420    public void TestISO3Fallback() {
421        Locale test = new Locale("xx", "YY", "");
422        boolean gotException = false;
423        String result = "";
424
425        try {
426            result = test.getISO3Language();
427        } catch (MissingResourceException e) {
428            gotException = true;
429        }
430        if (!gotException) {
431            errln("getISO3Language() on xx_YY returned " + result + " instead of throwing an exception");
432        }
433
434        gotException = false;
435        try {
436            result = test.getISO3Country();
437        } catch (MissingResourceException e) {
438            gotException = true;
439        }
440        if (!gotException) {
441            errln("getISO3Country() on xx_YY returned " + result + " instead of throwing an exception");
442        }
443    }
444
445    /**
446     * @bug 4106155 4118587 7066203 7085757
447     */
448    public void TestGetLangsAndCountries() {
449        // It didn't seem right to just do an exhaustive test of everything here, so I check
450        // for the following things:
451        // 1) Does each list have the right total number of entries?
452        // 2) Does each list contain certain language and country codes we think are important
453        //     (the G7 countries, plus a couple others)?
454        // 3) Does each list have every entry formatted correctly? (i.e., two characters,
455        //     all lower case for the language codes, all upper case for the country codes)
456        // 4) Is each list in sorted order?
457        String[] test = Locale.getISOLanguages();
458        String[] spotCheck1 = {"en", "es", "fr", "de", "it", "ja", "ko", "zh", "th",
459            "he", "id", "iu", "ug", "yi", "za"};
460
461        if (test.length != 188) {
462            errln("Expected getISOLanguages() to return 188 languages; it returned " + test.length);
463        } else {
464            for (int i = 0; i < spotCheck1.length; i++) {
465                int j;
466                for (j = 0; j < test.length; j++) {
467                    if (test[j].equals(spotCheck1[i])) {
468                        break;
469                    }
470                }
471                if (j == test.length || !test[j].equals(spotCheck1[i])) {
472                    errln("Couldn't find " + spotCheck1[i] + " in language list.");
473                }
474            }
475        }
476        for (int i = 0; i < test.length; i++) {
477            if (!test[i].equals(test[i].toLowerCase())) {
478                errln(test[i] + " is not all lower case.");
479            }
480            if (test[i].length() != 2) {
481                errln(test[i] + " is not two characters long.");
482            }
483            if (i > 0 && test[i].compareTo(test[i - 1]) <= 0) {
484                errln(test[i] + " appears in an out-of-order position in the list.");
485            }
486        }
487
488        test = Locale.getISOCountries();
489        String[] spotCheck2 = {"US", "CA", "GB", "FR", "DE", "IT", "JP", "KR", "CN", "TW", "TH"};
490
491
492        if (test.length != 249) {
493            errln("Expected getISOCountries to return 249 countries; it returned " + test.length);
494        } else {
495            for (int i = 0; i < spotCheck2.length; i++) {
496                int j;
497                for (j = 0; j < test.length; j++) {
498                    if (test[j].equals(spotCheck2[i])) {
499                        break;
500                    }
501                }
502                if (j == test.length || !test[j].equals(spotCheck2[i])) {
503                    errln("Couldn't find " + spotCheck2[i] + " in country list.");
504                }
505            }
506        }
507        for (int i = 0; i < test.length; i++) {
508            if (!test[i].equals(test[i].toUpperCase())) {
509                errln(test[i] + " is not all upper case.");
510            }
511            if (test[i].length() != 2) {
512                errln(test[i] + " is not two characters long.");
513            }
514            if (i > 0 && test[i].compareTo(test[i - 1]) <= 0) {
515                errln(test[i] + " appears in an out-of-order position in the list.");
516            }
517        }
518    }
519
520    /**
521     * @bug 4126880
522     */
523    void Test4126880() {
524        String[] test;
525
526        test = Locale.getISOCountries();
527        test[0] = "SUCKER!!!";
528        test = Locale.getISOCountries();
529        if (test[0].equals("SUCKER!!!")) {
530            errln("Changed internal country code list!");
531        }
532
533        test = Locale.getISOLanguages();
534        test[0] = "HAHAHAHA!!!";
535        test = Locale.getISOLanguages();
536        if (test[0].equals("HAHAHAHA!!!")) { // Fixed typo
537            errln("Changes internal language code list!");
538        }
539    }
540
541    /**
542     * @bug 4107014
543     */
544    public void TestGetAvailableLocales() {
545        Locale[] locales = Locale.getAvailableLocales();
546        if (locales == null || locales.length == 0) {
547            errln("Locale.getAvailableLocales() returned no installed locales!");
548        } else {
549            logln("Locale.getAvailableLocales() returned a list of " + locales.length + " locales.");
550            for (int i = 0; i < locales.length; i++) {
551                logln(locales[i].toString());
552            }
553        }
554    }
555
556    /**
557     * @bug 4135316
558     */
559    public void TestBug4135316() {
560        Locale[] locales1 = Locale.getAvailableLocales();
561        Locale[] locales2 = Locale.getAvailableLocales();
562        if (locales1 == locales2) {
563            errln("Locale.getAvailableLocales() doesn't clone its internal storage!");
564        }
565    }
566
567    /**
568     * @bug 4107953
569     */
570/*
571test commented out pending API-change approval
572    public void TestGetLanguagesForCountry() {
573        String[] languages = Locale.getLanguagesForCountry("US");
574
575        if (!searchStringArrayFor("en", languages))
576            errln("Didn't get en as a language for US");
577
578        languages = Locale.getLanguagesForCountry("FR");
579        if (!searchStringArrayFor("fr", languages))
580            errln("Didn't get fr as a language for FR");
581
582        languages = Locale.getLanguagesForCountry("CH");
583        if (!searchStringArrayFor("fr", languages))
584            errln("Didn't get fr as a language for CH");
585        if (!searchStringArrayFor("it", languages))
586            errln("Didn't get it as a language for CH");
587        if (!searchStringArrayFor("de", languages))
588            errln("Didn't get de as a language for CH");
589
590        languages = Locale.getLanguagesForCountry("JP");
591        if (!searchStringArrayFor("ja", languages))
592            errln("Didn't get ja as a language for JP");
593    }
594*/
595
596    private boolean searchStringArrayFor(String s, String[] array) {
597        for (int i = 0; i < array.length; i++)
598            if (s.equals(array[i]))
599                return true;
600        return false;
601    }
602    /**
603     * @bug 4110613
604     */
605    public void TestSerialization() throws ClassNotFoundException, OptionalDataException,
606            IOException, StreamCorruptedException {
607        ObjectOutputStream ostream;
608        ByteArrayOutputStream obstream;
609        byte[] bytes = null;
610
611        obstream = new ByteArrayOutputStream();
612        ostream = new ObjectOutputStream(obstream);
613
614        Locale test1 = new Locale("zh", "TW", "");
615        int dummy = test1.hashCode();   // fill in the cached hash-code value
616        ostream.writeObject(test1);
617
618        bytes = obstream.toByteArray();
619
620        ObjectInputStream istream = new ObjectInputStream(new ByteArrayInputStream(bytes));
621
622        Locale test2 = (Locale) (istream.readObject());
623
624        if (!test1.equals(test2) || test1.hashCode() != test2.hashCode()) {
625            errln("Locale failed to deserialize correctly.");
626        }
627    }
628
629    /**
630     * @bug 4118587
631     */
632    public void TestSimpleDisplayNames() {
633        // This test is different from TestDisplayNames because TestDisplayNames checks
634        // fallback behavior, combination of language and country names to form locale
635        // names, and other stuff like that.  This test just checks specific language
636        // and country codes to make sure we have the correct names for them.
637        String[] languageCodes = {"he", "id", "iu", "ug", "yi", "za"};
638        String[] languageNames = {"Hebrew", "Indonesian", "Inuktitut", "Uighur", "Yiddish",
639            "Zhuang"};
640
641        for (int i = 0; i < languageCodes.length; i++) {
642            String test = (new Locale(languageCodes[i], "", "")).getDisplayLanguage(Locale.US);
643            if (!test.equals(languageNames[i])) {
644                errln("Got wrong display name for " + languageCodes[i] + ": Expected \""
645                        + languageNames[i] + "\", got \"" + test + "\".");
646            }
647        }
648    }
649
650    /**
651     * @bug 4118595
652     */
653    public void TestUninstalledISO3Names() {
654        // This test checks to make sure getISO3Language and getISO3Country work right
655        // even for locales that are not installed.
656        String[] iso2Languages = {"am", "ba", "fy", "mr", "rn", "ss", "tw", "zu"};
657        String[] iso3Languages = {"amh", "bak", "fry", "mar", "run", "ssw", "twi", "zul"};
658
659        for (int i = 0; i < iso2Languages.length; i++) {
660            String test = (new Locale(iso2Languages[i], "", "")).getISO3Language();
661            if (!test.equals(iso3Languages[i])) {
662                errln("Got wrong ISO3 code for " + iso2Languages[i] + ": Expected \""
663                        + iso3Languages[i] + "\", got \"" + test + "\".");
664            }
665        }
666
667        String[] iso2Countries = {"AF", "BW", "KZ", "MO", "MN", "SB", "TC", "ZW"};
668        String[] iso3Countries = {"AFG", "BWA", "KAZ", "MAC", "MNG", "SLB", "TCA", "ZWE"};
669
670        for (int i = 0; i < iso2Countries.length; i++) {
671            String test = (new Locale("", iso2Countries[i], "")).getISO3Country();
672            if (!test.equals(iso3Countries[i])) {
673                errln("Got wrong ISO3 code for " + iso2Countries[i] + ": Expected \""
674                        + iso3Countries[i] + "\", got \"" + test + "\".");
675            }
676        }
677    }
678
679    /**
680     * @bug 4052404 4778440
681     */
682    public void TestChangedISO639Codes() {
683        Locale hebrewOld = new Locale("iw", "IL", "");
684        Locale hebrewNew = new Locale("he", "IL", "");
685        Locale yiddishOld = new Locale("ji", "IL", "");
686        Locale yiddishNew = new Locale("yi", "IL", "");
687        Locale indonesianOld = new Locale("in", "", "");
688        Locale indonesianNew = new Locale("id", "", "");
689
690        if (!hebrewNew.getLanguage().equals("iw")) {
691            errln("Got back wrong language code for Hebrew: expected \"iw\", got \""
692                    + hebrewNew.getLanguage() + "\"");
693        }
694        if (!yiddishNew.getLanguage().equals("ji")) {
695            errln("Got back wrong language code for Yiddish: expected \"ji\", got \""
696                    + yiddishNew.getLanguage() + "\"");
697        }
698        if (!indonesianNew.getLanguage().equals("in")) {
699            errln("Got back wrong language code for Indonesian: expected \"in\", got \""
700                    + indonesianNew.getLanguage() + "\"");
701        }
702    }
703
704    /**
705     * @bug 4092475
706     * I could not reproduce this bug.  I'm pretty convinced it was fixed with the
707     * big locale-data reorg of 10/28/97.  The lookup logic for language and country
708     * display names was also changed at that time in that check-in.    --rtg 3/20/98
709
710     * This test is not designed to work in any other locale but en_US.
711     * Most of the LocaleElements do not contain display names for other languages,
712     * so this test fails (bug 4289223) when run under different locales. For example,
713     * LocaleElements_es as of kestrel does not have a localized name for Japanese, so
714     * the getDisplayName method asks the default locale for a display name. The Japanese
715     * localized name for "Japanese" does not equal "Japanese" so this test fails for es
716     * display names if run under a ja locale. Eventually, he LocaleElements should probably
717     * be updated to contain more localized language and region display names.
718     * 1999-11-19 joconner
719     *
720     */
721    public void TestAtypicalLocales() {
722        Locale[] localesToTest = { new Locale("de", "CA"),
723                                   new Locale("ja", "ZA"),
724                                   new Locale("ru", "MX"),
725                                   new Locale("en", "FR"),
726                                   new Locale("es", "DE"),
727                                   new Locale("", "HR"),
728                                   new Locale("", "SE"),
729                                   new Locale("", "DO"),
730                                   new Locale("", "BE") };
731        String[] englishDisplayNames = { "German (Canada)",
732                                         "Japanese (South Africa)",
733                                         "Russian (Mexico)",
734                                         "English (France)",
735                                         "Spanish (Germany)",
736                                         "Croatia",
737                                         "Sweden",
738                                         "Dominican Republic",
739                                         "Belgium" };
740        String[] frenchDisplayNames = { "allemand (Canada)",
741                                        "japonais (Afrique du Sud)",
742                                        "russe (Mexique)",
743                                         "anglais (France)",
744                                         "espagnol (Allemagne)",
745                                        "Croatie",
746                                        "Su\u00e8de",
747                                        "R\u00e9publique Dominicaine",
748                                        "Belgique" };
749        String[] spanishDisplayNames = { "alem\u00E1n (Canad\u00E1)",
750                                         "japon\u00E9s (Sud\u00E1frica)",
751                                         "ruso (M\u00e9xico)",
752                                         "ingl\u00E9s (Francia)",
753                                         "espa\u00f1ol (Alemania)",
754                                         "Croacia",
755                                         "Suecia",
756                                         "Rep\u00fablica Dominicana",
757                                         "B\u00E9lgica" };
758
759
760        // save the default locale and set to the new default to en_US
761        Locale defaultLocale = Locale.getDefault();
762        Locale.setDefault(Locale.US);
763
764        for (int i = 0; i < localesToTest.length; i++) {
765            String name = localesToTest[i].getDisplayName(Locale.US);
766            logln(name);
767            if (!name.equals(englishDisplayNames[i])) {
768                errln("Lookup in English failed: expected \"" + englishDisplayNames[i]
769                        + "\", got \"" + name + "\"");
770            }
771        }
772
773        for (int i = 0; i < localesToTest.length; i++) {
774            String name = localesToTest[i].getDisplayName(new Locale("es", "ES"));
775            logln(name);
776            if (!name.equals(spanishDisplayNames[i])) {
777                errln("Lookup in Spanish failed: expected \"" + spanishDisplayNames[i]
778                        + "\", got \"" + name + "\"");
779            }
780        }
781
782        for (int i = 0; i < localesToTest.length; i++) {
783            String name = localesToTest[i].getDisplayName(Locale.FRANCE);
784            logln(name);
785            if (!name.equals(frenchDisplayNames[i])) {
786                errln("Lookup in French failed: expected \"" + frenchDisplayNames[i]
787                        + "\", got \"" + name + "\"");
788            }
789        }
790
791        // restore the default locale for other tests
792        Locale.setDefault(defaultLocale);
793    }
794
795    /**
796     * @bug 4126371
797     */
798    public void TestNullDefault() {
799        // why on earth anyone would ever try to do this is beyond me, but we should
800        // definitely make sure we don't let them
801        boolean gotException = false;
802        try {
803            Locale.setDefault(null);
804        } catch (NullPointerException e) {
805            // all other exception types propagate through here back to the test harness
806            gotException = true;
807        }
808        if (Locale.getDefault() == null) {
809            errln("Locale.getDefault() allowed us to set default to NULL!");
810        }
811        if (!gotException) {
812            errln("Trying to set default locale to NULL didn't throw exception!");
813        }
814    }
815
816    /**
817     * @bug 4135752
818     * This would be better tested by the LocaleDataTest.  Will move it when I
819     * get the LocaleDataTest working again.
820     */
821    public void TestThaiCurrencyFormat() {
822        DecimalFormat thaiCurrency = (DecimalFormat) NumberFormat.getCurrencyInstance(
823                new Locale("th", "TH"));
824        if (!thaiCurrency.getPositivePrefix().equals("\u0e3f")) {
825            errln("Thai currency prefix wrong: expected \"\u0e3f\", got \""
826                    + thaiCurrency.getPositivePrefix() + "\"");
827        }
828        if (!thaiCurrency.getPositiveSuffix().equals("")) {
829            errln("Thai currency suffix wrong: expected \"\", got \""
830                    + thaiCurrency.getPositiveSuffix() + "\"");
831        }
832    }
833
834    /**
835     * @bug 4122371
836     * Confirm that Euro support works.  This test is pretty rudimentary; all it does
837     * is check that any locales with the EURO variant format a number using the
838     * Euro currency symbol.
839     *
840     * ASSUME: All locales encode the Euro character "\u20AC".
841     * If this is changed to use the single-character Euro symbol, this
842     * test must be updated.
843     *
844     * DON'T ASSUME: Any specific countries support the Euro.  Instead,
845     * iterate through all locales.
846     */
847    public void TestEuroSupport() {
848        final String EURO_VARIANT = "EURO";
849        final String EURO_CURRENCY = "\u20AC"; // Look for this string in formatted Euro currency
850
851        Locale[] locales = NumberFormat.getAvailableLocales();
852        for (int i = 0; i < locales.length; ++i) {
853            Locale loc = locales[i];
854            if (loc.getVariant().indexOf(EURO_VARIANT) >= 0) {
855                NumberFormat nf = NumberFormat.getCurrencyInstance(loc);
856                String pos = nf.format(271828.182845);
857                String neg = nf.format(-271828.182845);
858                if (pos.indexOf(EURO_CURRENCY) >= 0
859                        && neg.indexOf(EURO_CURRENCY) >= 0) {
860                    logln("Ok: " + loc.toString()
861                            + ": " + pos + " / " + neg);
862                } else {
863                    errln("Fail: " + loc.toString()
864                            + " formats without " + EURO_CURRENCY
865                            + ": " + pos + " / " + neg
866                            + "\n*** THIS FAILURE MAY ONLY MEAN THAT LOCALE DATA HAS CHANGED ***");
867                }
868            }
869        }
870    }
871
872    /**
873     * @bug 4139504
874     * toString() doesn't work with language_VARIANT.
875     */
876    public void TestToString() {
877        Object[] DATA = {
878            new Locale("xx", "", ""), "xx",
879            new Locale("", "YY", ""), "_YY",
880            new Locale("", "", "ZZ"), "",
881            new Locale("xx", "YY", ""), "xx_YY",
882            new Locale("xx", "", "ZZ"), "xx__ZZ",
883            new Locale("", "YY", "ZZ"), "_YY_ZZ",
884            new Locale("xx", "YY", "ZZ"), "xx_YY_ZZ",
885        };
886        for (int i = 0; i < DATA.length; i += 2) {
887            Locale loc = (Locale) DATA[i];
888            String fmt = (String) DATA[i + 1];
889            if (!loc.toString().equals(fmt)) {
890                errln("Fail: Locale.toString(" + fmt + ")=>" + loc);
891            }
892        }
893    }
894
895    /**
896     * @bug 4105828
897     * Currency symbol in zh is wrong.  We will test this at the NumberFormat
898     * end to test the whole pipe.
899     */
900    public void Test4105828() {
901        Locale[] LOC = {Locale.CHINESE, new Locale("zh", "CN", ""),
902            new Locale("zh", "TW", ""), new Locale("zh", "HK", "")};
903        for (int i = 0; i < LOC.length; ++i) {
904            NumberFormat fmt = NumberFormat.getPercentInstance(LOC[i]);
905            String result = fmt.format(1);
906            if (!result.equals("100%")) {
907                errln("Percent for " + LOC[i] + " should be 100%, got " + result);
908            }
909        }
910    }
911
912    /**
913     * @bug 4139940
914     * Couldn't reproduce this bug -- probably was fixed earlier.
915     *
916     * ORIGINAL BUG REPORT:
917     * -- basically, hungarian for monday shouldn't have an \u00f4
918     * (o circumflex)in it instead it should be an o with 2 inclined
919     * (right) lines over it..
920     *
921     * You may wonder -- why do all this -- why not just add a line to
922     * LocaleData?  Well, I could see by inspection that the locale file had the
923     * right character in it, so I wanted to check the rest of the pipeline -- a
924     * very remote possibility, but I wanted to be sure.  The other possibility
925     * is that something is wrong with the font mapping subsystem, but we can't
926     * test that here.
927     */
928    public void Test4139940() {
929        Locale mylocale = new Locale("hu", "", "");
930        @SuppressWarnings("deprecation")
931        Date mydate = new Date(98, 3, 13); // A Monday
932        DateFormat df_full = new SimpleDateFormat("EEEE", mylocale);
933        String str = df_full.format(mydate);
934        // Make sure that o circumflex (\u00F4) is NOT there, and
935        // o double acute (\u0151) IS.
936        if (str.indexOf('\u0151') < 0 || str.indexOf('\u00F4') >= 0) {
937            errln("Fail: Monday in Hungarian is wrong");
938        }
939    }
940
941    /**
942     * @bug 4143951
943     * Russian first day of week should be Monday. Confirmed.
944     */
945    public void Test4143951() {
946        Calendar cal = Calendar.getInstance(new Locale("ru", "", ""));
947        if (cal.getFirstDayOfWeek() != Calendar.MONDAY) {
948            errln("Fail: First day of week in Russia should be Monday");
949        }
950    }
951
952    /**
953     * @bug 4147315
954     * java.util.Locale.getISO3Country() works wrong for non ISO-3166 codes.
955     * Should throw an exception for unknown locales
956     */
957    public void Test4147315() {
958        // Try with codes that are the wrong length but happen to match text
959        // at a valid offset in the mapping table
960        Locale locale = new Locale("aaa", "CCC");
961
962        try {
963            String result = locale.getISO3Country();
964
965            errln("ERROR: getISO3Country() returns: " + result
966                    + " for locale '" + locale + "' rather than exception");
967        } catch (MissingResourceException e) {
968        }
969    }
970
971    /**
972     * @bug 4147317 4940539
973     * java.util.Locale.getISO3Language() works wrong for non ISO-639 codes.
974     * Should throw an exception for unknown locales, except they have three
975     * letter language codes.
976     */
977    public void Test4147317() {
978        // Try a three letter language code, and check whether it is
979        // returned as is.
980        Locale locale = new Locale("aaa", "CCC");
981
982        String result = locale.getISO3Language();
983        if (!result.equals("aaa")) {
984            errln("ERROR: getISO3Language() returns: " + result
985                    + " for locale '" + locale + "' rather than returning it as is");
986        }
987
988        // Try an invalid two letter language code, and check whether it
989        // throws a MissingResourceException.
990        locale = new Locale("zz", "CCC");
991
992        try {
993            result = locale.getISO3Language();
994
995            errln("ERROR: getISO3Language() returns: " + result
996                    + " for locale '" + locale + "' rather than exception");
997        } catch (MissingResourceException e) {
998        }
999    }
1000
1001    /*
1002     * @bug 4147552 4778440 8030696
1003     */
1004    public void Test4147552() {
1005        Locale[] locales = {new Locale("no", "NO"), new Locale("no", "NO", "B"),
1006            new Locale("no", "NO", "NY"), new Locale("nb", "NO"),
1007            new Locale("nn", "NO")};
1008        String[] englishDisplayNames = {"Norwegian (Norway)",
1009            "Norwegian (Norway,Bokm\u00e5l)",
1010            "Norwegian (Norway,Nynorsk)",
1011            "Norwegian Bokm\u00e5l (Norway)",
1012            "Norwegian Nynorsk (Norway)"};
1013        String[] norwegianDisplayNames = {"norsk (Norge)",
1014            "norsk (Norge,bokm\u00e5l)", "norsk (Noreg,nynorsk)",
1015            "bokm\u00e5l (Norge)", "nynorsk (Noreg)"};
1016
1017        for (int i = 0; i < locales.length; i++) {
1018            Locale loc = locales[i];
1019            if (!loc.getDisplayName(Locale.US).equals(englishDisplayNames[i])) {
1020                errln("English display-name mismatch: expected "
1021                        + englishDisplayNames[i] + ", got " + loc.getDisplayName());
1022            }
1023            if (!loc.getDisplayName(loc).equals(norwegianDisplayNames[i])) {
1024                errln("Norwegian display-name mismatch: expected "
1025                        + norwegianDisplayNames[i] + ", got "
1026                        + loc.getDisplayName(loc));
1027            }
1028        }
1029    }
1030
1031    /*
1032     * @bug 8030696
1033     */
1034    public void Test8030696() {
1035        List<Locale> av = Arrays.asList(Locale.getAvailableLocales());
1036        if (!av.contains(new Locale("nb", "NO"))
1037                || !av.contains(new Locale("nn", "NO"))) {
1038            errln("\"nb-NO\" and/or \"nn-NO\" locale(s) not returned from getAvailableLocales().");
1039        }
1040    }
1041
1042    static String escapeUnicode(String s) {
1043        StringBuffer buf = new StringBuffer();
1044        for (int i = 0; i < s.length(); ++i) {
1045            char c = s.charAt(i);
1046            if (c >= 0x20 && c <= 0x7F) {
1047                buf.append(c);
1048            } else {
1049                buf.append("\\u");
1050                String h = "000" + Integer.toHexString(c);
1051                if (h.length() > 4) {
1052                    h = h.substring(h.length() - 4);
1053                }
1054                buf.append(h);
1055            }
1056        }
1057        return buf.toString();
1058    }
1059}
1060