]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/test/cintltst/cloctst.c
ICU-62107.0.1.tar.gz
[apple/icu.git] / icuSources / test / cintltst / cloctst.c
index baa1da1c6fdf8eecb6401efbaab24dfbc59d3a6a..ea59ec22111398c630888b91fed91830b79b011f 100644 (file)
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
 /********************************************************************
  * COPYRIGHT:
- * Copyright (c) 1997-2003, International Business Machines Corporation and
+ * Copyright (c) 1997-2016, International Business Machines Corporation and
  * others. All Rights Reserved.
  ********************************************************************/
-/********************************************************************************
+/*****************************************************************************
 *
 * File CLOCTST.C
 *
 * Modification History:
 *        Name                     Description 
 *     Madhu Katragadda            Ported for C API
-*********************************************************************************
+******************************************************************************
 */
+#include "cloctst.h"
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
-#include "unicode/utypes.h"
-#include "unicode/putil.h"
-#include "cloctst.h"
-#include "unicode/uloc.h"
-#include "unicode/uscript.h"
-#include "unicode/uchar.h"
-#include "unicode/ustring.h"
-#include "unicode/uset.h"
 #include "cintltst.h"
+#include "cmemory.h"
 #include "cstring.h"
+#include "uparse.h"
+#include "uresimp.h"
+#include "cmemory.h"
+
+#include "unicode/putil.h"
+#include "unicode/ubrk.h"
+#include "unicode/uchar.h"
+#include "unicode/ucol.h"
+#include "unicode/udat.h"
+#include "unicode/uloc.h"
+#include "unicode/umsg.h"
 #include "unicode/ures.h"
+#include "unicode/uset.h"
+#include "unicode/ustring.h"
+#include "unicode/utypes.h"
+#include "unicode/ulocdata.h"
+#include "unicode/uldnames.h"
+#include "unicode/parseerr.h" /* may not be included with some uconfig switches */
+#include "udbgutil.h"
+#include "unicode/ualoc.h" /* Apple-specific */
+
+static void TestNullDefault(void);
+static void TestNonexistentLanguageExemplars(void);
+static void TestLocDataErrorCodeChaining(void);
+static void TestLocDataWithRgTag(void);
+static void TestLanguageExemplarsFallbacks(void);
+static void TestDisplayNameBrackets(void);
 
-#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
+static void TestUnicodeDefines(void);
 
-#ifdef WIN32
-#include "locmap.h"
-#endif
+static void TestIsRightToLeft(void);
+static void TestBadLocaleIDs(void);
+
+static void TestUldnNameVariants(void);
+static void TestGetLanguagesForRegion(void);
+static void TestGetAppleParent(void);
+static void TestAppleLocalizationsToUse(void);
 
-static void TestNullDefault(void);
-static void VerifyTranslation(void);
 void PrintDataTable();
 
 /*---------------------------------------------------
   table of valid data
  --------------------------------------------------- */
-#define LOCALE_SIZE 5
-#define LOCALE_INFO_SIZE 23
+#define LOCALE_SIZE 9
+#define LOCALE_INFO_SIZE 28
 
-static const char* rawData2[LOCALE_INFO_SIZE][LOCALE_SIZE] = {
+static const char* const rawData2[LOCALE_INFO_SIZE][LOCALE_SIZE] = {
     /* language code */
-    {   "en",   "fr",   "hr",   "el",   "no"    },
+    {   "en",   "fr",   "ca",   "el",   "no",   "zh",   "de",   "es",  "ja"    },
+    /* script code */
+    {   "",     "",     "",     "",     "",     "", "", "", ""  },
     /* country code */
-    {   "US",   "FR",   "HR",   "GR",   "NO"    },
+    {   "US",   "FR",   "ES",   "GR",   "NO",   "CN", "DE", "", "JP"    },
     /* variant code */
-    {   "",     "",     "",     "",     "NY"    },
+    {   "",     "",     "",     "",     "NY",   "", "", "", ""      },
     /* full name */
-    {   "en_US",    "fr_FR",    "hr_HR",    "el_GR",    "no_NO_NY"  },
+    {   "en_US",    "fr_FR",    "ca_ES",    
+        "el_GR",    "no_NO_NY", "zh_Hans_CN", 
+        "de_DE@collation=phonebook", "es@collation=traditional",  "ja_JP@calendar=japanese" },
     /* ISO-3 language */
-    {   "eng",  "fra",  "hrv",  "ell",  "nor"   },
+    {   "eng",  "fra",  "cat",  "ell",  "nor",  "zho", "deu", "spa", "jpn"   },
     /* ISO-3 country */
-    {   "USA",  "FRA",  "HRV",  "GRC",  "NOR"   },
-    /* LCID (not currently public) */
-    {   "409", "40c", "41a", "408", "814"  },
+    {   "USA",  "FRA",  "ESP",  "GRC",  "NOR",  "CHN", "DEU", "", "JPN"   },
+    /* LCID */
+    {   "409", "40c", "403", "408", "814",  "804", "10407", "40a", "411"     },
 
     /* display language (English) */
-    {   "English",  "French",   "Croatian", "Greek",    "Norwegian" },
+    {   "English",  "French",   "Catalan", "Greek",    "Norwegian", "Chinese", "German", "Spanish", "Japanese"    },
+    /* display script code (English) */
+    {   "",     "",     "",     "",     "",     "Simplified Han", "", "", ""       },
     /* display country (English) */
-    {   "United States",    "France",   "Croatia",  "Greece",   "Norway"    },
+    {   "United States",    "France",   "Spain",  "Greece",   "Norway", "China", "Germany", "", "Japan"       },
     /* display variant (English) */
-    {   "",     "",     "",     "",     "Nynorsk"    },
+    {   "",     "",     "",     "",     "NY",  "", "", "", ""       },
     /* display name (English) */
-    {   "English (United States)", "French (France)", "Croatian (Croatia)", "Greek (Greece)", "Norwegian (Norway, Nynorsk)" },
+    {   "English (United States)", "French (France)", "Catalan (Spain)", 
+        "Greek (Greece)", "Norwegian (Norway, NY)", "Chinese (Simplified, China)", 
+        "German (Germany, Sort Order=Phonebook Sort Order)", "Spanish (Sort Order=Traditional Sort Order)", "Japanese (Japan, Calendar=Japanese Calendar)" },
 
     /* display language (French) */
-    {   "anglais",  "fran\\u00E7ais",   "croate", "grec",    "norv\\u00E9gien" },
+    {   "anglais",  "fran\\u00E7ais",   "catalan", "grec",    "norv\\u00E9gien",    "chinois", "allemand", "espagnol", "japonais"     },
+    /* display script code (French) */
+    {   "",     "",     "",     "",     "",     "sinogrammes simplifi\\u00e9s", "", "", ""         },
     /* display country (French) */
-    {   "\\u00C9tats-Unis",    "France",   "Croatie",  "Gr\\u00E8ce",   "Norv\\u00E8ge"    },
+    {   "\\u00C9tats-Unis",    "France",   "Espagne",  "Gr\\u00E8ce",   "Norv\\u00E8ge",    "Chine", "Allemagne", "", "Japon"       },
     /* display variant (French) */
-    {   "",     "",     "",     "",     "Nynorsk"    },
+    {   "",     "",     "",     "",     "NY",   "", "", "", ""       },
     /* display name (French) */
-    {   "anglais (\\u00C9tats-Unis)", "fran\\u00E7ais (France)", "croate (Croatie)", "grec (Gr\\u00E8ce)", "norv\\u00E9gien (Norv\\u00E8ge, Nynorsk)" },
-
-    /* display language (Croatian) */
-    {   "", "", "hrvatski",            "",  "" },
-    /* display country (Croatian) */
-    {   "", "", "Hrvatska",            "", "" },
-    /* display variant (Croatian) */
-    {   "", "", "",                    "", "Nynorsk" },
-    /* display name (Croatian) */
-    {   "", "", "hrvatski (Hrvatska)", "", "" },
+    {   "anglais (\\u00C9tats-Unis)", "fran\\u00E7ais (France)", "catalan (Espagne)", 
+        "grec (Gr\\u00E8ce)", "norv\\u00E9gien (Norv\\u00E8ge, NY)",  "chinois (simplifi\\u00e9, Chine)", 
+        "allemand (Allemagne, ordre de tri=ordre de l\\u2019annuaire)", "espagnol (ordre de tri=ordre traditionnel)", "japonais (Japon, calendrier=calendrier japonais)" },
+
+    /* display language (Catalan) */
+    {   "angl\\u00E8s", "franc\\u00E8s", "catal\\u00E0", "grec",  "noruec", "xin\\u00E8s", "alemany", "espanyol", "japon\\u00E8s"    },
+    /* display script code (Catalan) */
+    {   "",     "",     "",     "",     "",     "han simplificat", "", "", ""         },
+    /* display country (Catalan) */
+    {   "Estats Units", "Fran\\u00E7a", "Espanya",  "Gr\\u00E8cia", "Noruega",  "Xina", "Alemanya", "", "Jap\\u00F3"    },
+    /* display variant (Catalan) */
+    {   "", "", "",                    "", "NY",    "", "", "", ""    },
+    /* display name (Catalan) */
+    {   "angl\\u00E8s (Estats Units)", "franc\\u00E8s (Fran\\u00E7a)", "catal\\u00E0 (Espanya)", 
+    "grec (Gr\\u00E8cia)", "noruec (Noruega, NY)", "xin\\u00E8s (simplificat, Xina)", 
+    "alemany (Alemanya, ordenaci\\u00F3=ordre de la guia telef\\u00F2nica)", "espanyol (ordenaci\\u00F3=ordre tradicional)", "japon\\u00E8s (Jap\\u00F3, calendari=calendari japon\\u00e8s)" },
 
     /* display language (Greek) */
     {
         "\\u0391\\u03b3\\u03b3\\u03bb\\u03b9\\u03ba\\u03ac",
         "\\u0393\\u03b1\\u03bb\\u03bb\\u03b9\\u03ba\\u03ac",
-        "\\u039a\\u03c1\\u03bf\\u03b1\\u03c4\\u03b9\\u03ba\\u03ac",
-        "\\u03b5\\u03bb\\u03bb\\u03b7\\u03bd\\u03b9\\u03ba\\u03ac",
-        "\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03b9\\u03ba\\u03ac"
+        "\\u039a\\u03b1\\u03c4\\u03b1\\u03bb\\u03b1\\u03bd\\u03b9\\u03ba\\u03ac",
+        "\\u0395\\u03bb\\u03bb\\u03b7\\u03bd\\u03b9\\u03ba\\u03ac",
+        "\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03b9\\u03ba\\u03ac",
+        "\\u039A\\u03B9\\u03BD\\u03B5\\u03B6\\u03B9\\u03BA\\u03AC", 
+        "\\u0393\\u03B5\\u03C1\\u03BC\\u03B1\\u03BD\\u03B9\\u03BA\\u03AC", 
+        "\\u0399\\u03C3\\u03C0\\u03B1\\u03BD\\u03B9\\u03BA\\u03AC", 
+        "\\u0399\\u03B1\\u03C0\\u03C9\\u03BD\\u03B9\\u03BA\\u03AC"   
     },
+    /* display script code (Greek) */
+
+    {   "",     "",     "",     "",     "", "\\u0391\\u03c0\\u03bb\\u03bf\\u03c0\\u03bf\\u03b9\\u03b7\\u03bc\\u03ad\\u03bd\\u03bf \\u03a7\\u03b1\\u03bd", "", "", "" },
     /* display country (Greek) */
     {
-        "\\u0397\\u03bd\\u03c9\\u03bc\\u03ad\\u03bd\\u03b5\\u03c2 \\u03a0\\u03bf\\u03bb\\u03b9\\u03c4\\u03b5\\u03af\\u03b5\\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",
-        "\\u039a\\u03c1\\u03bf\\u03b1\\u03c4\\u03af\\u03b1",
+        "\\u0399\\u03c3\\u03c0\\u03b1\\u03bd\\u03af\\u03b1",
         "\\u0395\\u03bb\\u03bb\\u03ac\\u03b4\\u03b1",
-        "\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03af\\u03b1"
+        "\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03af\\u03b1",
+        "\\u039A\\u03AF\\u03BD\\u03B1", 
+        "\\u0393\\u03B5\\u03C1\\u03BC\\u03B1\\u03BD\\u03AF\\u03B1", 
+        "", 
+        "\\u0399\\u03B1\\u03C0\\u03C9\\u03BD\\u03AF\\u03B1"   
     },
     /* display variant (Greek) */
-    {   "", "", "", "", "Nynorsk" },
+    {   "", "", "", "", "NY", "", "", "", ""    }, /* TODO: currently there is no translation for NY in Greek fix this test when we have it */
     /* display name (Greek) */
     {
-        "\\u0391\\u03b3\\u03b3\\u03bb\\u03b9\\u03ba\\u03ac (\\u0397\\u03bd\\u03c9\\u03bc\\u03ad\\u03bd\\u03b5\\u03c2 \\u03a0\\u03bf\\u03bb\\u03b9\\u03c4\\u03b5\\u03af\\u03b5\\u03c2 \\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\\u03c1\\u03bf\\u03b1\\u03c4\\u03b9\\u03ba\\u03ac (\\u039a\\u03c1\\u03bf\\u03b1\\u03c4\\u03af\\u03b1)",
-        "\\u03b5\\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)"
+        "\\u039a\\u03b1\\u03c4\\u03b1\\u03bb\\u03b1\\u03bd\\u03b9\\u03ba\\u03ac (\\u0399\\u03c3\\u03c0\\u03b1\\u03bd\\u03af\\u03b1)",
+        "\\u0395\\u03bb\\u03bb\\u03b7\\u03bd\\u03b9\\u03ba\\u03ac (\\u0395\\u03bb\\u03bb\\u03ac\\u03b4\\u03b1)",
+        "\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03b9\\u03ba\\u03ac (\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03af\\u03b1, NY)",
+        "\\u039A\\u03B9\\u03BD\\u03B5\\u03B6\\u03B9\\u03BA\\u03AC (\\u0391\\u03c0\\u03bb\\u03bf\\u03c0\\u03bf\\u03b9\\u03b7\\u03bc\\u03ad\\u03bd\\u03b1, \\u039A\\u03AF\\u03BD\\u03B1)",
+        "\\u0393\\u03b5\\u03c1\\u03bc\\u03b1\\u03bd\\u03b9\\u03ba\\u03ac (\\u0393\\u03b5\\u03c1\\u03bc\\u03b1\\u03bd\\u03af\\u03b1, \\u03a3\\u03b5\\u03b9\\u03c1\\u03ac \\u03c4\\u03b1\\u03be\\u03b9\\u03bd\\u03cc\\u03bc\\u03b7\\u03c3\\u03b7\\u03c2=\\u03a3\\u03b5\\u03b9\\u03c1\\u03ac \\u03c4\\u03b1\\u03be\\u03b9\\u03bd\\u03cc\\u03bc\\u03b7\\u03c3\\u03b7\\u03c2 \\u03c4\\u03b7\\u03bb\\u03b5\\u03c6\\u03c9\\u03bd\\u03b9\\u03ba\\u03bf\\u03cd \\u03ba\\u03b1\\u03c4\\u03b1\\u03bb\\u03cc\\u03b3\\u03bf\\u03c5)",
+        "\\u0399\\u03c3\\u03c0\\u03b1\\u03bd\\u03b9\\u03ba\\u03ac (\\u03a3\\u03b5\\u03b9\\u03c1\\u03ac \\u03c4\\u03b1\\u03be\\u03b9\\u03bd\\u03cc\\u03bc\\u03b7\\u03c3\\u03b7\\u03c2=\\u03a0\\u03b1\\u03c1\\u03b1\\u03b4\\u03bf\\u03c3\\u03b9\\u03b1\\u03ba\\u03ae \\u03c3\\u03b5\\u03b9\\u03c1\\u03ac \\u03c4\\u03b1\\u03be\\u03b9\\u03bd\\u03cc\\u03bc\\u03b7\\u03c3\\u03b7\\u03c2)",
+        "\\u0399\\u03b1\\u03c0\\u03c9\\u03bd\\u03b9\\u03ba\\u03ac (\\u0399\\u03b1\\u03c0\\u03c9\\u03bd\\u03af\\u03b1, \\u0397\\u03bc\\u03b5\\u03c1\\u03bf\\u03bb\\u03cc\\u03b3\\u03b9\\u03bf=\\u0399\\u03b1\\u03c0\\u03c9\\u03bd\\u03b9\\u03ba\\u03cc \\u03b7\\u03bc\\u03b5\\u03c1\\u03bf\\u03bb\\u03cc\\u03b3\\u03b9\\u03bf)"
     }
 };
 
@@ -118,57 +173,105 @@ static UChar*** dataTable=0;
 enum {
     ENGLISH = 0,
     FRENCH = 1,
-    CROATIAN = 2,
+    CATALAN = 2,
     GREEK = 3,
     NORWEGIAN = 4
 };
 
 enum {
     LANG = 0,
-    CTRY = 1,
-    VAR = 2,
-    NAME = 3,
-    LANG3 = 4,
-    CTRY3 = 5,
-    LCID = 6,
-    DLANG_EN = 7,
-    DCTRY_EN = 8,
-    DVAR_EN = 9,
-    DNAME_EN = 10,
-    DLANG_FR = 11,
-    DCTRY_FR = 12,
-    DVAR_FR = 13,
-    DNAME_FR = 14,
-    DLANG_HR = 15,
-    DCTRY_HR = 16,
-    DVAR_HR = 17,
-    DNAME_HR = 18,
-    DLANG_EL = 19,
-    DCTRY_EL = 20,
-    DVAR_EL = 21,
-    DNAME_EL = 22
+    SCRIPT = 1,
+    CTRY = 2,
+    VAR = 3,
+    NAME = 4,
+    LANG3 = 5,
+    CTRY3 = 6,
+    LCID = 7,
+    DLANG_EN = 8,
+    DSCRIPT_EN = 9,
+    DCTRY_EN = 10,
+    DVAR_EN = 11,
+    DNAME_EN = 12,
+    DLANG_FR = 13,
+    DSCRIPT_FR = 14,
+    DCTRY_FR = 15,
+    DVAR_FR = 16,
+    DNAME_FR = 17,
+    DLANG_CA = 18,
+    DSCRIPT_CA = 19,
+    DCTRY_CA = 20,
+    DVAR_CA = 21,
+    DNAME_CA = 22,
+    DLANG_EL = 23,
+    DSCRIPT_EL = 24,
+    DCTRY_EL = 25,
+    DVAR_EL = 26,
+    DNAME_EL = 27
 };
 
+#define TESTCASE(name) addTest(root, &name, "tsutil/cloctst/" #name)
+
 void addLocaleTest(TestNode** root);
 
 void addLocaleTest(TestNode** root)
 {
-    addTest(root, &TestObsoleteNames,        "tsutil/cloctst/TestObsoleteNames"); /* srl- move */
-    addTest(root, &TestBasicGetters,         "tsutil/cloctst/TestBasicGetters");
-    addTest(root, &TestNullDefault,          "tsutil/cloctst/TestNullDefault");
-    addTest(root, &TestPrefixes,             "tsutil/cloctst/TestPrefixes");
-    addTest(root, &TestSimpleResourceInfo,   "tsutil/cloctst/TestSimpleResourceInfo");
-    addTest(root, &TestDisplayNames,         "tsutil/cloctst/TestDisplayNames");
-    addTest(root, &TestGetAvailableLocales,  "tsutil/cloctst/TestGetAvailableLocales");
-    addTest(root, &TestDataDirectory,        "tsutil/cloctst/TestDataDirectory");
-    addTest(root, &TestISOFunctions,         "tsutil/cloctst/TestISOFunctions");
-    addTest(root, &TestISO3Fallback,         "tsutil/cloctst/TestISO3Fallback");
-    addTest(root, &TestUninstalledISO3Names, "tsutil/cloctst/TestUninstalledISO3Names");
-    addTest(root, &TestSimpleDisplayNames,   "tsutil/cloctst/TestSimpleDisplayNames");
-    addTest(root, &TestVariantParsing,       "tsutil/cloctst/TestVariantParsing");
-    addTest(root, &TestLocaleStructure,      "tsutil/cloctst/TestLocaleStructure");
-    addTest(root, &TestConsistentCountryInfo,"tsutil/cloctst/TestConsistentCountryInfo");
-    addTest(root, &VerifyTranslation,        "tsutil/cloctst/VerifyTranslation");
+    TESTCASE(TestObsoleteNames); /* srl- move */
+    TESTCASE(TestBasicGetters);
+    TESTCASE(TestNullDefault);
+    TESTCASE(TestPrefixes);
+    TESTCASE(TestSimpleResourceInfo);
+    TESTCASE(TestDisplayNames);
+    TESTCASE(TestGetAvailableLocales);
+    TESTCASE(TestDataDirectory);
+#if !UCONFIG_NO_FILE_IO && !UCONFIG_NO_LEGACY_CONVERSION
+    TESTCASE(TestISOFunctions);
+#endif
+    TESTCASE(TestISO3Fallback);
+    TESTCASE(TestUninstalledISO3Names);
+    TESTCASE(TestSimpleDisplayNames);
+    TESTCASE(TestVariantParsing);
+    TESTCASE(TestKeywordVariants);
+    TESTCASE(TestKeywordVariantParsing);
+    TESTCASE(TestCanonicalization);
+    TESTCASE(TestKeywordSet);
+    TESTCASE(TestKeywordSetError);
+    TESTCASE(TestDisplayKeywords);
+    TESTCASE(TestDisplayKeywordValues);
+    TESTCASE(TestGetBaseName);
+#if !UCONFIG_NO_FILE_IO
+    TESTCASE(TestGetLocale);
+#endif
+    TESTCASE(TestDisplayNameWarning);
+    TESTCASE(TestNonexistentLanguageExemplars);
+    TESTCASE(TestLocDataErrorCodeChaining);
+    TESTCASE(TestLocDataWithRgTag);
+    TESTCASE(TestLanguageExemplarsFallbacks);
+    TESTCASE(TestCalendar);
+    TESTCASE(TestDateFormat);
+    TESTCASE(TestCollation);
+    TESTCASE(TestULocale);
+    TESTCASE(TestUResourceBundle);
+    TESTCASE(TestDisplayName); 
+    TESTCASE(TestAcceptLanguage); 
+    TESTCASE(TestGetLocaleForLCID);
+    TESTCASE(TestOrientation);
+    TESTCASE(TestLikelySubtags);
+    TESTCASE(TestToLanguageTag);
+    TESTCASE(TestForLanguageTag);
+    TESTCASE(TestTrailingNull);
+    TESTCASE(TestUnicodeDefines);
+    TESTCASE(TestEnglishExemplarCharacters);
+    TESTCASE(TestDisplayNameBrackets);
+    TESTCASE(TestIsRightToLeft);
+    TESTCASE(TestToUnicodeLocaleKey);
+    TESTCASE(TestToLegacyKey);
+    TESTCASE(TestToUnicodeLocaleType);
+    TESTCASE(TestToLegacyType);
+    TESTCASE(TestBadLocaleIDs);
+    TESTCASE(TestUldnNameVariants);
+    TESTCASE(TestGetLanguagesForRegion);
+    TESTCASE(TestGetAppleParent);
+    TESTCASE(TestAppleLocalizationsToUse);
 }
 
 
@@ -241,7 +344,6 @@ static void TestBasicGetters() {
             log_err(" Mismatch in getName:  %s  versus   %s\n", name, rawData2[NAME][i]);
         }
 
-
         free(temp);
         free(name);
 
@@ -262,6 +364,47 @@ static void TestNullDefault() {
     if (uprv_strcmp(uloc_getDefault(), original) != 0) {
         log_err(" uloc_setDefault(NULL, &status) didn't get the default locale back!\n");
     }
+
+    {
+    /* Test that set & get of default locale work, and that
+     * default locales are cached and reused, and not overwritten.
+     */
+        const char *n_en_US;
+        const char *n_fr_FR;
+        const char *n2_en_US;
+        
+        status = U_ZERO_ERROR;
+        uloc_setDefault("en_US", &status);
+        n_en_US = uloc_getDefault();
+        if (strcmp(n_en_US, "en_US") != 0) {
+            log_err("Wrong result from uloc_getDefault().  Expected \"en_US\", got \"%s\"\n", n_en_US);
+        }
+        
+        uloc_setDefault("fr_FR", &status);
+        n_fr_FR = uloc_getDefault();
+        if (strcmp(n_en_US, "en_US") != 0) {
+            log_err("uloc_setDefault altered previously default string."
+                "Expected \"en_US\", got \"%s\"\n",  n_en_US);
+        }
+        if (strcmp(n_fr_FR, "fr_FR") != 0) {
+            log_err("Wrong result from uloc_getDefault().  Expected \"fr_FR\", got %s\n",  n_fr_FR);
+        }
+        
+        uloc_setDefault("en_US", &status);
+        n2_en_US = uloc_getDefault();
+        if (strcmp(n2_en_US, "en_US") != 0) {
+            log_err("Wrong result from uloc_getDefault().  Expected \"en_US\", got \"%s\"\n", n_en_US);
+        }
+        if (n2_en_US != n_en_US) {
+            log_err("Default locale cache failed to reuse en_US locale.\n");
+        }
+        
+        if (U_FAILURE(status)) {
+            log_err("Failure returned from uloc_setDefault - \"%s\"\n", u_errorName(status));
+        }
+        
+    }
+    
 }
 /* Test the i- and x- and @ and . functionality 
 */
@@ -269,103 +412,135 @@ static void TestNullDefault() {
 #define PREFIXBUFSIZ 128
 
 static void TestPrefixes() {
-  int row = 0;
-  int n;
-  const char *loc;
-
-  const char *testData[][5] =
-  {
-    {"sv", "FI", "AL", "sv-fi-al", "sv_FI_AL" },
-    {"en", "GB", "", "en-gb", "en_GB" },
-    {"i-hakka", "MT", "XEMXIJA", "i-hakka_MT_XEMXIJA", "i-hakka_MT_XEMXIJA"},
-    {"i-hakka", "CN", "", "i-hakka_CN", "i-hakka_CN"},
-    {"i-hakka", "MX", "", "I-hakka_MX", "i-hakka_MX"},
-    {"x-klingon", "US", "SANJOSE", "X-KLINGON_us_SANJOSE", "x-klingon_US_SANJOSE"},
-
-    {"mr", "", "", "mr.utf8", "mr"},
-    {"de", "TV", "", "de-tv.koi8r", "de_TV"},
-    {"x-piglatin", "ML", "", "x-piglatin_ML.MBE", "x-piglatin_ML"},  /* Multibyte English */
-    {"i-cherokee","US", "", "i-Cherokee_US.utf7", "i-cherokee_US"},
-    {"x-filfli", "MT", "FILFLA", "x-filfli_MT_FILFLA.gb-18030", "x-filfli_MT_FILFLA"},
-    {"no", "NO", "NY", "no-no-ny.utf32@B", "no_NO_NY"}, /* @ ignored unless variant is empty */
-    {"no", "NO", "B",  "no-no.utf32@B", "no_NO_B" },
-    {"no", "",   "NY", "no__ny", "no__NY" },
-    {"no", "",   "NY", "no@ny", "no__NY" },
-
-    { "","","","",""}
-  };
-
-  const char *testTitles[] = { "uloc_getLanguage()", "uloc_getCountry()", "uloc_getVariant()", "name", "uloc_getName()", "country3", "lcid" };
-
-  char buf[PREFIXBUFSIZ];
-  int32_t len;
-  UErrorCode err;
-
-
-  for(row=0;testData[row][0][0] != 0;row++) {
-    loc = testData[row][NAME];
-    log_verbose("Test #%d: %s\n", row, loc);
-
-    err = U_ZERO_ERROR;
-    len=0;
-    buf[0]=0;
-    for(n=0;n<=(NAME+1);n++) {
-      if(n==NAME) continue;
-
-      for(len=0;len<PREFIXBUFSIZ;len++) {
-        buf[len] = '%'; /* Set a tripwire.. */
-      }
-      len = 0;
-
-      switch(n) {
-      case LANG:
-        len = uloc_getLanguage(loc, buf, PREFIXBUFSIZ, &err);
-        break;
-
-      case CTRY:
-        len = uloc_getCountry(loc, buf, PREFIXBUFSIZ, &err);
-        break;
-
-      case VAR:
-        len = uloc_getVariant(loc, buf, PREFIXBUFSIZ, &err);
-        break;
-
-      case NAME+1:
-        len = uloc_getName(loc, buf, PREFIXBUFSIZ, &err);
-        break;
-
-      default:
-        strcpy(buf, "**??");
-        len=4;
-      }
-
-      if(U_FAILURE(err)) {
-        log_err("#%d: %s on %s: err %s\n",
-                row, testTitles[n], loc, u_errorName(err));
-      } else {
-        log_verbose("#%d: %s on %s: -> [%s] (length %d)\n",
-                row, testTitles[n], loc, buf, len);
-
-        if(len != (int32_t)strlen(buf)) {
-          log_err("#%d: %s on %s: -> [%s] (length returned %d, actual %d!)\n",
-                row, testTitles[n], loc, buf, len, strlen(buf)+1);
-
-        }
-
-        /* see if they smashed something */
-        if(buf[len+1] != '%') {
-          log_err("#%d: %s on %s: -> [%s] - wrote [%X] out ofbounds!\n",
-                row, testTitles[n], loc, buf, buf[len+1]);
-        }
-
-        if(strcmp(buf, testData[row][n])) {
-          log_err("#%d: %s on %s: -> [%s] (expected '%s'!)\n",
-                row, testTitles[n], loc, buf, testData[row][n]);
-
+    int row = 0;
+    int n;
+    const char *loc, *expected;
+    
+    static const char * const testData[][7] =
+    {
+        /* NULL canonicalize() column means "expect same as getName()" */
+        {"sv", "", "FI", "AL", "sv-fi-al", "sv_FI_AL", NULL},
+        {"en", "", "GB", "", "en-gb", "en_GB", NULL},
+        {"i-hakka", "", "MT", "XEMXIJA", "i-hakka_MT_XEMXIJA", "i-hakka_MT_XEMXIJA", NULL},
+        {"i-hakka", "", "CN", "", "i-hakka_CN", "i-hakka_CN", NULL},
+        {"i-hakka", "", "MX", "", "I-hakka_MX", "i-hakka_MX", NULL},
+        {"x-klingon", "", "US", "SANJOSE", "X-KLINGON_us_SANJOSE", "x-klingon_US_SANJOSE", NULL},
+        
+        {"zh", "Hans", "", "PINYIN", "zh-Hans-pinyin", "zh_Hans__PINYIN", "zh_Hans@collation=pinyin"},
+        {"hy", "", "", "AREVMDA", "hy_AREVMDA", "hy__AREVMDA", NULL},
+        
+        {"de", "", "", "1901", "de-1901", "de__1901", NULL},
+        {"mr", "", "", "", "mr.utf8", "mr.utf8", "mr"},
+        {"de", "", "TV", "", "de-tv.koi8r", "de_TV.koi8r", "de_TV"},
+        {"x-piglatin", "", "ML", "", "x-piglatin_ML.MBE", "x-piglatin_ML.MBE", "x-piglatin_ML"},  /* Multibyte English */
+        {"i-cherokee", "","US", "", "i-Cherokee_US.utf7", "i-cherokee_US.utf7", "i-cherokee_US"},
+        {"x-filfli", "", "MT", "FILFLA", "x-filfli_MT_FILFLA.gb-18030", "x-filfli_MT_FILFLA.gb-18030", "x-filfli_MT_FILFLA"},
+        {"no", "", "NO", "NY", "no-no-ny.utf32@B", "no_NO_NY.utf32@B", "no_NO_NY_B"},
+        {"no", "", "NO", "",  "no-no.utf32@B", "no_NO.utf32@B", "no_NO_B"},
+        {"no", "", "",   "NY", "no__ny", "no__NY", NULL},
+        {"no", "", "",   "", "no@ny", "no@ny", "no__NY"},
+        {"el", "Latn", "", "", "el-latn", "el_Latn", NULL},
+        {"en", "Cyrl", "RU", "", "en-cyrl-ru", "en_Cyrl_RU", NULL},
+        {"zh", "Hant", "TW", "STROKE", "zh-hant_TW_STROKE", "zh_Hant_TW_STROKE", "zh_Hant_TW@collation=stroke"},
+        {"qq", "Qqqq", "QQ", "QQ", "qq_Qqqq_QQ_QQ", "qq_Qqqq_QQ_QQ", NULL},
+        {"qq", "Qqqq", "", "QQ", "qq_Qqqq__QQ", "qq_Qqqq__QQ", NULL},
+        {"ab", "Cdef", "GH", "IJ", "ab_cdef_gh_ij", "ab_Cdef_GH_IJ", NULL}, /* total garbage */
+        
+        {NULL,NULL,NULL,NULL,NULL,NULL,NULL}
+    };
+    
+    static const char * const testTitles[] = {
+        "uloc_getLanguage()",
+        "uloc_getScript()",
+        "uloc_getCountry()",
+        "uloc_getVariant()",
+        "name",
+        "uloc_getName()",
+        "uloc_canonicalize()"
+    };
+    
+    char buf[PREFIXBUFSIZ];
+    int32_t len;
+    UErrorCode err;
+    
+    
+    for(row=0;testData[row][0] != NULL;row++) {
+        loc = testData[row][NAME];
+        log_verbose("Test #%d: %s\n", row, loc);
+        
+        err = U_ZERO_ERROR;
+        len=0;
+        buf[0]=0;
+        for(n=0;n<=(NAME+2);n++) {
+            if(n==NAME) continue;
+            
+            for(len=0;len<PREFIXBUFSIZ;len++) {
+                buf[len] = '%'; /* Set a tripwire.. */
+            }
+            len = 0;
+            
+            switch(n) {
+            case LANG:
+                len = uloc_getLanguage(loc, buf, PREFIXBUFSIZ, &err);
+                break;
+                
+            case SCRIPT:
+                len = uloc_getScript(loc, buf, PREFIXBUFSIZ, &err);
+                break;
+                
+            case CTRY:
+                len = uloc_getCountry(loc, buf, PREFIXBUFSIZ, &err);
+                break;
+                
+            case VAR:
+                len = uloc_getVariant(loc, buf, PREFIXBUFSIZ, &err);
+                break;
+                
+            case NAME+1:
+                len = uloc_getName(loc, buf, PREFIXBUFSIZ, &err);
+                break;
+                
+            case NAME+2:
+                len = uloc_canonicalize(loc, buf, PREFIXBUFSIZ, &err);
+                break;
+                
+            default:
+                strcpy(buf, "**??");
+                len=4;
+            }
+            
+            if(U_FAILURE(err)) {
+                log_err("#%d: %s on %s: err %s\n",
+                    row, testTitles[n], loc, u_errorName(err));
+            } else {
+                log_verbose("#%d: %s on %s: -> [%s] (length %d)\n",
+                    row, testTitles[n], loc, buf, len);
+                
+                if(len != (int32_t)strlen(buf)) {
+                    log_err("#%d: %s on %s: -> [%s] (length returned %d, actual %d!)\n",
+                        row, testTitles[n], loc, buf, len, strlen(buf)+1);
+                    
+                }
+                
+                /* see if they smashed something */
+                if(buf[len+1] != '%') {
+                    log_err("#%d: %s on %s: -> [%s] - wrote [%X] out ofbounds!\n",
+                        row, testTitles[n], loc, buf, buf[len+1]);
+                }
+                
+                expected = testData[row][n];
+                if (expected == NULL && n == (NAME+2)) {
+                    /* NULL expected canonicalize() means "expect same as getName()" */
+                    expected = testData[row][NAME+1];
+                }
+                if(strcmp(buf, expected)) {
+                    log_err("#%d: %s on %s: -> [%s] (expected '%s'!)\n",
+                        row, testTitles[n], loc, buf, expected);
+                    
+                }
+            }
         }
-      }
     }
-  }
 }
 
 
@@ -374,46 +549,120 @@ static void TestSimpleResourceInfo() {
     int32_t i;
     char* testLocale = 0;
     UChar* expected = 0;
-
+    
     const char* temp;
     char            temp2[20];
     testLocale=(char*)malloc(sizeof(char) * 1);
     expected=(UChar*)malloc(sizeof(UChar) * 1);
-
-setUpDataTable();
+    
+    setUpDataTable();
     log_verbose("Testing getISO3Language and getISO3Country\n");
     for (i = 0; i < LOCALE_SIZE; i++) {
-
+        
         testLocale=(char*)realloc(testLocale, sizeof(char) * (u_strlen(dataTable[NAME][i])+1));
         u_austrcpy(testLocale, dataTable[NAME][i]);
-
+        
         log_verbose("Testing   %s ......\n", testLocale);
-
+        
         temp=uloc_getISO3Language(testLocale);
         expected=(UChar*)realloc(expected, sizeof(UChar) * (strlen(temp) + 1));
         u_uastrcpy(expected,temp);
         if (0 != u_strcmp(expected, dataTable[LANG3][i])) {
-             log_err("  ISO-3 language code mismatch:  %s versus  %s\n",  austrdup(expected),
-                                                            austrdup(dataTable[LANG3][i]));
+            log_err("  ISO-3 language code mismatch:  %s versus  %s\n",  austrdup(expected),
+                austrdup(dataTable[LANG3][i]));
         }
-
+        
         temp=uloc_getISO3Country(testLocale);
         expected=(UChar*)realloc(expected, sizeof(UChar) * (strlen(temp) + 1));
         u_uastrcpy(expected,temp);
         if (0 != u_strcmp(expected, dataTable[CTRY3][i])) {
             log_err("  ISO-3 Country code mismatch:  %s versus  %s\n",  austrdup(expected),
-                                                            austrdup(dataTable[CTRY3][i]));
+                austrdup(dataTable[CTRY3][i]));
         }
-        sprintf(temp2, "%x", uloc_getLCID(testLocale));
+        sprintf(temp2, "%x", (int)uloc_getLCID(testLocale));
         if (strcmp(temp2, rawData2[LCID][i]) != 0) {
             log_err("LCID mismatch: %s versus %s\n", temp2 , rawData2[LCID][i]);
         }
+    }
+    
+    free(expected);
+    free(testLocale);
+    cleanUpDataTable();
+}
 
+/* if len < 0, we convert until we hit UChar 0x0000, which is not output. will add trailing null
+ * if there's room but won't be included in result.  result < 0 indicates an error.
+ * Returns the number of chars written (not those that would be written if there's enough room.*/
+static int32_t UCharsToEscapedAscii(const UChar* utext, int32_t len, char* resultChars, int32_t buflen) {
+    static const struct {
+        char escapedChar;
+        UChar sourceVal;
+    } ESCAPE_MAP[] = {
+        /*a*/ {'a', 0x07},
+        /*b*/ {'b', 0x08},
+        /*e*/ {'e', 0x1b},
+        /*f*/ {'f', 0x0c},
+        /*n*/ {'n', 0x0a},
+        /*r*/ {'r', 0x0d},
+        /*t*/ {'t', 0x09},
+        /*v*/ {'v', 0x0b}
+    };
+    static const int32_t ESCAPE_MAP_LENGTH = UPRV_LENGTHOF(ESCAPE_MAP);
+    static const char HEX_DIGITS[] = {
+        '0', '1', '2', '3', '4', '5', '6', '7',
+        '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+    };
+    int32_t i, j;
+    int32_t resultLen = 0;
+    const int32_t limit = len<0 ? buflen : len; /* buflen is long enough to hit the buffer limit */
+    const int32_t escapeLimit1 = buflen-2;
+    const int32_t escapeLimit2 = buflen-6;
+    UChar uc;
+
+    if(utext==NULL || resultChars==NULL || buflen<0) {
+        return -1;
     }
 
- free(expected);
- free(testLocale);
-cleanUpDataTable();
+    for(i=0;i<limit && resultLen<buflen;++i) {
+        uc=utext[i];
+        if(len<0 && uc==0) {
+            break;
+        }
+        if(uc<0x20) {
+            for(j=0;j<ESCAPE_MAP_LENGTH && uc!=ESCAPE_MAP[j].sourceVal;j++) {
+            }
+            if(j<ESCAPE_MAP_LENGTH) {
+                if(resultLen>escapeLimit1) {
+                    break;
+                }
+                resultChars[resultLen++]='\\';
+                resultChars[resultLen++]=ESCAPE_MAP[j].escapedChar;
+                continue;
+            }
+        } else if(uc<0x7f) {
+            u_austrncpy(resultChars + resultLen, &uc, 1);
+            resultLen++;
+            continue;
+        }
+
+        if(resultLen>escapeLimit2) {
+            break;
+        }
+
+        /* have to escape the uchar */
+        resultChars[resultLen++]='\\';
+        resultChars[resultLen++]='u';
+        resultChars[resultLen++]=HEX_DIGITS[(uc>>12)&0xff];
+        resultChars[resultLen++]=HEX_DIGITS[(uc>>8)&0xff];
+        resultChars[resultLen++]=HEX_DIGITS[(uc>>4)&0xff];
+        resultChars[resultLen++]=HEX_DIGITS[uc&0xff];
+    }
+
+    if(resultLen<buflen) {
+        resultChars[resultLen] = 0;
+    }
+
+    return resultLen;
 }
 
 /*
@@ -425,34 +674,137 @@ cleanUpDataTable();
 static void TestDisplayNames()
 {
     UChar buffer[100];
-    UErrorCode errorCode;
+    UErrorCode errorCode=U_ZERO_ERROR;
     int32_t length;
-
     log_verbose("Testing getDisplayName for different locales\n");
 
     log_verbose("  In locale = en_US...\n");
     doTestDisplayNames("en_US", DLANG_EN);
     log_verbose("  In locale = fr_FR....\n");
     doTestDisplayNames("fr_FR", DLANG_FR);
-    log_verbose("  In locale = hr_HR...\n");
-    doTestDisplayNames("hr_HR", DLANG_HR);
+    log_verbose("  In locale = ca_ES...\n");
+    doTestDisplayNames("ca_ES", DLANG_CA);
     log_verbose("  In locale = gr_EL..\n");
     doTestDisplayNames("el_GR", DLANG_EL);
 
     /* test that the default locale has a display name for its own language */
     errorCode=U_ZERO_ERROR;
-    length=uloc_getDisplayLanguage(NULL, NULL, buffer, LENGTHOF(buffer), &errorCode);
+    length=uloc_getDisplayLanguage(NULL, NULL, buffer, UPRV_LENGTHOF(buffer), &errorCode);
     if(U_FAILURE(errorCode) || (length<=3 && buffer[0]<=0x7f)) {
         /* check <=3 to reject getting the language code as a display name */
-        log_err("unable to get a display string for the language of the default locale - %s\n", u_errorName(errorCode));
+        log_data_err("unable to get a display string for the language of the default locale - %s (Are you missing data?)\n", u_errorName(errorCode));
     }
 
     /* test that we get the language code itself for an unknown language, and a default warning */
     errorCode=U_ZERO_ERROR;
-    length=uloc_getDisplayLanguage("qq", "rr", buffer, LENGTHOF(buffer), &errorCode);
+    length=uloc_getDisplayLanguage("qq", "rr", buffer, UPRV_LENGTHOF(buffer), &errorCode);
     if(errorCode!=U_USING_DEFAULT_WARNING || length!=2 || buffer[0]!=0x71 || buffer[1]!=0x71) {
         log_err("error getting the display string for an unknown language - %s\n", u_errorName(errorCode));
     }
+    
+    /* test that we get a default warning for a display name where one component is unknown (4255) */
+    errorCode=U_ZERO_ERROR;
+    length=uloc_getDisplayName("qq_US_POSIX", "en_US", buffer, UPRV_LENGTHOF(buffer), &errorCode);
+    if(errorCode!=U_USING_DEFAULT_WARNING) {
+        log_err("error getting the display name for a locale with an unknown language - %s\n", u_errorName(errorCode));
+    }
+
+    {
+        int32_t i;
+        static const char *aLocale = "es@collation=traditional;calendar=japanese";
+        static const char *testL[] = { "en_US", 
+            "fr_FR", 
+            "ca_ES",
+            "el_GR" };
+        static const char *expect[] = { "Spanish (Calendar=Japanese Calendar, Sort Order=Traditional Sort Order)", /* note sorted order of keywords */
+            "espagnol (calendrier=calendrier japonais, ordre de tri=ordre traditionnel)",
+            "espanyol (calendari=calendari japon\\u00e8s, ordenaci\\u00f3=ordre tradicional)",
+            "\\u0399\\u03c3\\u03c0\\u03b1\\u03bd\\u03b9\\u03ba\\u03ac (\\u0397\\u03bc\\u03b5\\u03c1\\u03bf\\u03bb\\u03cc\\u03b3\\u03b9\\u03bf=\\u0399\\u03b1\\u03c0\\u03c9\\u03bd\\u03b9\\u03ba\\u03cc \\u03b7\\u03bc\\u03b5\\u03c1\\u03bf\\u03bb\\u03cc\\u03b3\\u03b9\\u03bf, \\u03a3\\u03b5\\u03b9\\u03c1\\u03ac \\u03c4\\u03b1\\u03be\\u03b9\\u03bd\\u03cc\\u03bc\\u03b7\\u03c3\\u03b7\\u03c2=\\u03a0\\u03b1\\u03c1\\u03b1\\u03b4\\u03bf\\u03c3\\u03b9\\u03b1\\u03ba\\u03ae \\u03c3\\u03b5\\u03b9\\u03c1\\u03ac \\u03c4\\u03b1\\u03be\\u03b9\\u03bd\\u03cc\\u03bc\\u03b7\\u03c3\\u03b7\\u03c2)" };
+        UChar *expectBuffer;
+
+        for(i=0;i<UPRV_LENGTHOF(testL);i++) {
+            errorCode = U_ZERO_ERROR;
+            uloc_getDisplayName(aLocale, testL[i], buffer, UPRV_LENGTHOF(buffer), &errorCode);
+            if(U_FAILURE(errorCode)) {
+                log_err("FAIL in uloc_getDisplayName(%s,%s,..) -> %s\n", aLocale, testL[i], u_errorName(errorCode));
+            } else {
+                expectBuffer = CharsToUChars(expect[i]);
+                if(u_strcmp(buffer,expectBuffer)) {
+                    log_data_err("FAIL in uloc_getDisplayName(%s,%s,..) expected '%s' got '%s' (Are you missing data?)\n", aLocale, testL[i], expect[i], austrdup(buffer));
+                } else {
+                    log_verbose("pass in uloc_getDisplayName(%s,%s,..) got '%s'\n", aLocale, testL[i], expect[i]);
+                }
+                free(expectBuffer);
+            }
+        }
+    }
+
+    /* test that we properly preflight and return data when there's a non-default pattern,
+       see ticket #8262. */
+    {
+        int32_t i;
+        static const char *locale="az_Cyrl";
+        static const char *displayLocale="ja";
+        static const char *expectedChars =
+                "\\u30a2\\u30bc\\u30eb\\u30d0\\u30a4\\u30b8\\u30e3\\u30f3\\u8a9e "
+                "(\\u30ad\\u30ea\\u30eb\\u6587\\u5b57)";
+        UErrorCode ec=U_ZERO_ERROR;
+        UChar result[256];
+        int32_t len;
+        int32_t preflightLen=uloc_getDisplayName(locale, displayLocale, NULL, 0, &ec);
+        /* inconvenient semantics when preflighting, this condition is expected... */
+        if(ec==U_BUFFER_OVERFLOW_ERROR) {
+            ec=U_ZERO_ERROR;
+        }
+        len=uloc_getDisplayName(locale, displayLocale, result, UPRV_LENGTHOF(result), &ec);
+        if(U_FAILURE(ec)) {
+            log_err("uloc_getDisplayName(%s, %s...) returned error: %s",
+                    locale, displayLocale, u_errorName(ec));
+        } else {
+            UChar *expected=CharsToUChars(expectedChars);
+            int32_t expectedLen=u_strlen(expected);
+
+            if(len!=expectedLen) {
+                log_data_err("uloc_getDisplayName(%s, %s...) returned string of length %d, expected length %d",
+                        locale, displayLocale, len, expectedLen);
+            } else if(preflightLen!=expectedLen) {
+                log_err("uloc_getDisplayName(%s, %s...) returned preflight length %d, expected length %d",
+                        locale, displayLocale, preflightLen, expectedLen);
+            } else if(u_strncmp(result, expected, len)) {
+                int32_t cap=len*6+1;  /* worst case + space for trailing null */
+                char* resultChars=(char*)malloc(cap);
+                int32_t resultCharsLen=UCharsToEscapedAscii(result, len, resultChars, cap);
+                if(resultCharsLen<0 || resultCharsLen<cap-1) {
+                    log_err("uloc_getDisplayName(%s, %s...) mismatch", locale, displayLocale);
+                } else {
+                    log_err("uloc_getDisplayName(%s, %s...) returned '%s' but expected '%s'",
+                            locale, displayLocale, resultChars, expectedChars);
+                }
+                free(resultChars);
+                resultChars=NULL;
+            } else {
+                /* test all buffer sizes */
+                for(i=len+1;i>=0;--i) {
+                    len=uloc_getDisplayName(locale, displayLocale, result, i, &ec);
+                    if(ec==U_BUFFER_OVERFLOW_ERROR) {
+                        ec=U_ZERO_ERROR;
+                    }
+                    if(U_FAILURE(ec)) {
+                        log_err("using buffer of length %d returned error %s", i, u_errorName(ec));
+                        break;
+                    }
+                    if(len!=expectedLen) {
+                        log_err("with buffer of length %d, expected length %d but got %d", i, expectedLen, len);
+                        break;
+                    }
+                    /* There's no guarantee about what's in the buffer if we've overflowed, in particular,
+                     * we don't know that it's been filled, so no point in checking. */
+                }
+            }
+
+            free(expected);
+        }
+    }
 }
 
 
@@ -537,12 +889,14 @@ static void doTestDisplayNames(const char* displayLocale, int32_t compareIndex)
 
 
     UChar  *testLang  = 0;
+    UChar  *testScript  = 0;
     UChar  *testCtry = 0;
     UChar  *testVar = 0;
     UChar  *testName = 0;
 
 
     UChar*  expectedLang = 0;
+    UChar*  expectedScript = 0;
     UChar*  expectedCtry = 0;
     UChar*  expectedVar = 0;
     UChar*  expectedName = 0;
@@ -571,6 +925,22 @@ setUpDataTable();
             log_err("Error in getDisplayLanguage()  %s\n", myErrorName(status));
         }
 
+        maxresultsize=0;
+        maxresultsize=uloc_getDisplayScript(testLocale, displayLocale, NULL, maxresultsize, &status);
+        if(status==U_BUFFER_OVERFLOW_ERROR)
+        {
+            status=U_ZERO_ERROR;
+            testScript=(UChar*)malloc(sizeof(UChar) * (maxresultsize+1));
+            uloc_getDisplayScript(testLocale, displayLocale, testScript, maxresultsize + 1, &status);
+        }
+        else
+        {
+            testScript=&_NUL;
+        }
+        if(U_FAILURE(status)){
+            log_err("Error in getDisplayScript()  %s\n", myErrorName(status));
+        }
+
         maxresultsize=0;
         maxresultsize=uloc_getDisplayCountry(testLocale, displayLocale, NULL, maxresultsize, &status);
         if(status==U_BUFFER_OVERFLOW_ERROR)
@@ -623,32 +993,40 @@ setUpDataTable();
         if(u_strlen(expectedLang)== 0)
             expectedLang=dataTable[DLANG_EN][i];
 
-        expectedCtry=dataTable[compareIndex + 1][i];
+        expectedScript=dataTable[compareIndex + 1][i];
+        if(u_strlen(expectedScript)== 0)
+            expectedScript=dataTable[DSCRIPT_EN][i];
+
+        expectedCtry=dataTable[compareIndex + 2][i];
         if(u_strlen(expectedCtry)== 0)
             expectedCtry=dataTable[DCTRY_EN][i];
 
-        expectedVar=dataTable[compareIndex + 2][i];
-        if(u_strlen(expectedCtry)== 0)
+        expectedVar=dataTable[compareIndex + 3][i];
+        if(u_strlen(expectedVar)== 0)
             expectedVar=dataTable[DVAR_EN][i];
 
-        expectedName=dataTable[compareIndex + 3][i];
+        expectedName=dataTable[compareIndex + 4][i];
         if(u_strlen(expectedName) == 0)
             expectedName=dataTable[DNAME_EN][i];
 
         if (0 !=u_strcmp(testLang,expectedLang))  {
-            log_data_err(" Display Language mismatch: got %s expected %s displayLocale=%s\n", austrdup(testLang), austrdup(expectedLang), displayLocale);
+            log_data_err(" Display Language mismatch: got %s expected %s displayLocale=%s (Are you missing data?)\n", austrdup(testLang), austrdup(expectedLang), displayLocale);
+        }
+
+        if (0 != u_strcmp(testScript,expectedScript))   {
+            log_data_err(" Display Script mismatch: got %s expected %s displayLocale=%s (Are you missing data?)\n", austrdup(testScript), austrdup(expectedScript), displayLocale);
         }
 
         if (0 != u_strcmp(testCtry,expectedCtry))   {
-            log_data_err(" Display Country mismatch: got %s expected %s displayLocale=%s\n", austrdup(testCtry), austrdup(expectedCtry), displayLocale);
+            log_data_err(" Display Country mismatch: got %s expected %s displayLocale=%s (Are you missing data?)\n", austrdup(testCtry), austrdup(expectedCtry), displayLocale);
         }
 
         if (0 != u_strcmp(testVar,expectedVar))    {
-            log_data_err(" Display Variant mismatch: got %s expected %s displayLocale=%s\n", austrdup(testVar), austrdup(expectedVar), displayLocale);
+            log_data_err(" Display Variant mismatch: got %s expected %s displayLocale=%s (Are you missing data?)\n", austrdup(testVar), austrdup(expectedVar), displayLocale);
         }
 
         if(0 != u_strcmp(testName, expectedName))    {
-            log_data_err(" Display Name mismatch: got %s expected %s displayLocale=%s\n", austrdup(testName), austrdup(expectedName), displayLocale);
+            log_data_err(" Display Name mismatch: got %s expected %s displayLocale=%s (Are you missing data?)\n", austrdup(testName), austrdup(expectedName), displayLocale);
         }
 
         if(testName!=&_NUL) {
@@ -657,6 +1035,9 @@ setUpDataTable();
         if(testLang!=&_NUL) {
             free(testLang);
         }
+        if(testScript!=&_NUL) {
+            free(testScript);
+        }
         if(testCtry!=&_NUL) {
             free(testCtry);
         }
@@ -667,82 +1048,244 @@ setUpDataTable();
 cleanUpDataTable();
 }
 
+/*------------------------------
+ * TestDisplayNameBrackets
+ */
+
+typedef struct {
+    const char * displayLocale;
+    const char * namedRegion;
+    const char * namedLocale;
+    const char * regionName;
+    const char * ulocLocaleName;
+    const char * uldnLocaleName;
+} DisplayNameBracketsItem;
+
+static const DisplayNameBracketsItem displayNameBracketsItems[] = {
+    { "en", "CC", "en_CC",      "Cocos (Keeling) Islands",  "English (Cocos [Keeling] Islands)",  "English (Cocos [Keeling] Islands)" },
+    { "en", "MM", "my_MM",      "Myanmar (Burma)",          "Burmese (Myanmar [Burma])",          "Burmese (Myanmar)"                 },
+    { "en", "MM", "my_Mymr_MM", "Myanmar (Burma)",          "Burmese (Myanmar, Myanmar [Burma])", "Burmese (Myanmar, Myanmar)"        },
+    { "zh", "CC", "en_CC",      "\\u79D1\\u79D1\\u65AF\\uFF08\\u57FA\\u6797\\uFF09\\u7FA4\\u5C9B",
+                                "\\u82F1\\u6587\\uFF08\\u79D1\\u79D1\\u65AF\\uFF3B\\u57FA\\u6797\\uFF3D\\u7FA4\\u5C9B\\uFF09",
+                                "\\u82F1\\u6587\\uFF08\\u79D1\\u79D1\\u65AF\\uFF3B\\u57FA\\u6797\\uFF3D\\u7FA4\\u5C9B\\uFF09"         },
+    { "zh", "CG", "fr_CG",      "\\u521A\\u679C\\uFF08\\u5E03\\uFF09",
+                                "\\u6CD5\\u6587\\uFF08\\u521A\\u679C\\uFF3B\\u5E03\\uFF3D\\uFF09",
+                                "\\u6CD5\\u6587\\uFF08\\u521A\\u679C\\uFF3B\\u5E03\\uFF3D\\uFF09"                                     },
+    { NULL, NULL, NULL,         NULL,                       NULL,                                  NULL                               }
+};
+
+enum { kDisplayNameBracketsMax = 128 };
+
+static void TestDisplayNameBrackets()
+{
+    const DisplayNameBracketsItem * itemPtr = displayNameBracketsItems;
+    for (; itemPtr->displayLocale != NULL; itemPtr++) {
+        ULocaleDisplayNames * uldn;
+        UErrorCode status;
+        UChar expectRegionName[kDisplayNameBracketsMax];
+        UChar expectUlocLocaleName[kDisplayNameBracketsMax];
+        UChar expectUldnLocaleName[kDisplayNameBracketsMax];
+        UChar getName[kDisplayNameBracketsMax];
+        int32_t ulen;
+        
+        (void) u_unescape(itemPtr->regionName, expectRegionName, kDisplayNameBracketsMax);
+        (void) u_unescape(itemPtr->ulocLocaleName, expectUlocLocaleName, kDisplayNameBracketsMax);
+        (void) u_unescape(itemPtr->uldnLocaleName, expectUldnLocaleName, kDisplayNameBracketsMax);
+
+        status = U_ZERO_ERROR;
+        ulen = uloc_getDisplayCountry(itemPtr->namedLocale, itemPtr->displayLocale, getName, kDisplayNameBracketsMax, &status);
+        if ( U_FAILURE(status) || u_strcmp(getName, expectRegionName) != 0 ) {
+            log_data_err("uloc_getDisplayCountry for displayLocale %s and namedLocale %s returns unexpected name or status %s\n", itemPtr->displayLocale, itemPtr->namedLocale, myErrorName(status));
+        }
+
+        status = U_ZERO_ERROR;
+        ulen = uloc_getDisplayName(itemPtr->namedLocale, itemPtr->displayLocale, getName, kDisplayNameBracketsMax, &status);
+        if ( U_FAILURE(status) || u_strcmp(getName, expectUlocLocaleName) != 0 ) {
+            log_data_err("uloc_getDisplayName for displayLocale %s and namedLocale %s returns unexpected name or status %s\n", itemPtr->displayLocale, itemPtr->namedLocale, myErrorName(status));
+        }
+        if ( U_FAILURE(status) ) {
+            log_data_err("uloc_getDisplayName for displayLocale %s and namedLocale %-10s returns unexpected status %s\n", itemPtr->displayLocale, itemPtr->namedLocale, myErrorName(status));
+        } else if ( u_strcmp(getName, expectUlocLocaleName) != 0 ) {
+            char bbuf[128];
+            u_strToUTF8(bbuf, 128, NULL, getName, ulen, &status);
+            log_data_err("uloc_getDisplayName for displayLocale %s and namedLocale %-10s returns unexpected name (len %d): \"%s\"\n", itemPtr->displayLocale, itemPtr->namedLocale, ulen, bbuf);
+        }
+
+#if !UCONFIG_NO_FORMATTING
+        status = U_ZERO_ERROR;
+        uldn = uldn_open(itemPtr->displayLocale, ULDN_STANDARD_NAMES, &status);
+        if (U_SUCCESS(status)) {
+            status = U_ZERO_ERROR;
+            ulen = uldn_regionDisplayName(uldn, itemPtr->namedRegion, getName, kDisplayNameBracketsMax, &status);
+            if ( U_FAILURE(status) || u_strcmp(getName, expectRegionName) != 0 ) {
+                log_data_err("uldn_regionDisplayName for displayLocale %s and namedRegion %s returns unexpected name or status %s\n", itemPtr->displayLocale, itemPtr->namedRegion, myErrorName(status));
+            }
+
+            status = U_ZERO_ERROR;
+            ulen = uldn_localeDisplayName(uldn, itemPtr->namedLocale, getName, kDisplayNameBracketsMax, &status);
+            if ( U_FAILURE(status) ) {
+                log_data_err("uldn_localeDisplayName for displayLocale %s and namedLocale %-10s returns unexpected status %s\n", itemPtr->displayLocale, itemPtr->namedLocale, myErrorName(status));
+            } else if ( u_strcmp(getName, expectUldnLocaleName) != 0 ) {
+                char bbuf[128];
+                u_strToUTF8(bbuf, 128, NULL, getName, ulen, &status);
+                log_data_err("uldn_localeDisplayName for displayLocale %s and namedLocale %-10s returns unexpected name (len %d): \"%s\"\n", itemPtr->displayLocale, itemPtr->namedLocale, ulen, bbuf);
+            }
+
+            uldn_close(uldn);
+        } else {
+            log_data_err("uldn_open fails for displayLocale %s, status=%s\n", itemPtr->displayLocale, u_errorName(status));
+        }
+#endif
+    (void)ulen;   /* Suppress variable not used warning */
+    }
+}
+
+/*------------------------------
+ * TestISOFunctions
+ */
+
+#if !UCONFIG_NO_FILE_IO && !UCONFIG_NO_LEGACY_CONVERSION
 /* test for uloc_getISOLanguages, uloc_getISOCountries */
 static void TestISOFunctions()
 {
     const char* const* str=uloc_getISOLanguages();
     const char* const* str1=uloc_getISOCountries();
     const char* test;
-    int32_t count  = 0;
-    UBool done = FALSE;
+    const char *key = NULL;
+    int32_t count = 0, skipped = 0;
     int32_t expect;
+    UResourceBundle *res;
+    UResourceBundle *subRes;
+    UErrorCode status = U_ZERO_ERROR;
 
     /*  test getISOLanguages*/
     /*str=uloc_getISOLanguages(); */
     log_verbose("Testing ISO Languages: \n");
 
-    while(!done)
+    /* use structLocale - this data is no longer in root */
+    res = ures_openDirect(loadTestData(&status), "structLocale", &status);
+    subRes = ures_getByKey(res, "Languages", NULL, &status);
+    if (U_FAILURE(status)) {
+        log_data_err("There is an error in structLocale's ures_getByKey(\"Languages\"), status=%s\n", u_errorName(status));
+        return;
+    }
+
+    expect = ures_getSize(subRes);
+    for(count = 0; *(str+count) != 0; count++)
     {
-        if(*(str+count++) == 0)
-        {
-            done = TRUE;
+        key = NULL;
+        test = *(str+count);
+        status = U_ZERO_ERROR;
+
+        do {
+            /* Skip over language tags. This API only returns language codes. */
+            skipped += (key != NULL);
+            ures_getNextString(subRes, NULL, &key, &status);
         }
-        else
-        {
-            test = *(str+count-1);
-            if(!strcmp(test,"in"))
-                log_err("FAIL getISOLanguages() has obsolete language code %s\n", test);
-            if(!strcmp(test,"iw"))
-                log_err("FAIL getISOLanguages() has obsolete language code %s\n", test);
-            if(!strcmp(test,"ji"))
-                log_err("FAIL getISOLanguages() has obsolete language code %s\n", test);
-            if(!strcmp(test,"jw"))
-                log_err("FAIL getISOLanguages() has obsolete language code %s\n", test);
-            if(!strcmp(test,"sh"))
-                log_err("FAIL getISOLanguages() has obsolete language code %s\n", test);
-        }
-    }
-    count--;
-    expect = 450;
+        while (key != NULL && strchr(key, '_'));
+
+        if(key == NULL)
+            break;
+        /* TODO: Consider removing sh, which is deprecated */
+        if(strcmp(key,"root") == 0 || strcmp(key,"Fallback") == 0 || strcmp(key,"sh") == 0) {
+            ures_getNextString(subRes, NULL, &key, &status);
+            skipped++;
+        }
+#if U_CHARSET_FAMILY==U_ASCII_FAMILY
+        /* This code only works on ASCII machines where the keys are stored in ASCII order */
+        if(strcmp(test,key)) {
+            /* The first difference usually implies the place where things get out of sync */
+            log_err("FAIL Language diff at offset %d, \"%s\" != \"%s\"\n", count, test, key);
+        }
+#endif
+
+        if(!strcmp(test,"in"))
+            log_err("FAIL getISOLanguages() has obsolete language code %s\n", test);
+        if(!strcmp(test,"iw"))
+            log_err("FAIL getISOLanguages() has obsolete language code %s\n", test);
+        if(!strcmp(test,"ji"))
+            log_err("FAIL getISOLanguages() has obsolete language code %s\n", test);
+        if(!strcmp(test,"jw"))
+            log_err("FAIL getISOLanguages() has obsolete language code %s\n", test);
+        if(!strcmp(test,"sh"))
+            log_err("FAIL getISOLanguages() has obsolete language code %s\n", test);
+    }
+
+    expect -= skipped; /* Ignore the skipped resources from structLocale */
 
     if(count!=expect) {
-        log_err("There is an error in getISOLanguages, got %d, expected %d\n", count, expect);
+        log_err("There is an error in getISOLanguages, got %d, expected %d (as per structLocale)\n", count, expect);
     }
 
+    subRes = ures_getByKey(res, "Countries", subRes, &status);
     log_verbose("Testing ISO Countries");
-    count=0;
-    done=FALSE;
-    while(!done)
+    skipped = 0;
+    expect = ures_getSize(subRes) - 1; /* Skip ZZ */
+    for(count = 0; *(str1+count) != 0; count++)
     {
-        if(*(str1 + count++)==0)
-        {
-            done=TRUE;
+        key = NULL;
+        test = *(str1+count);
+        do {
+            /* Skip over numeric UN tags. This API only returns ISO-3166 codes. */
+            skipped += (key != NULL);
+            ures_getNextString(subRes, NULL, &key, &status);
         }
-        else
-        {
-            test = *(str1+count-1);
-            if(!strcmp(test,"FX"))
-                log_err("FAIL getISOCountries() has obsolete country code %s\n", test);
-            if(!strcmp(test,"ZR"))
-                log_err("FAIL getISOCountries() has obsolete country code %s\n", test);
+        while (key != NULL && strlen(key) != 2);
+
+        if(key == NULL)
+            break;
+        /* TODO: Consider removing CS, which is deprecated */
+        while(strcmp(key,"QO") == 0 || strcmp(key,"QU") == 0 || strcmp(key,"CS") == 0) {
+            ures_getNextString(subRes, NULL, &key, &status);
+            skipped++;
         }
+#if U_CHARSET_FAMILY==U_ASCII_FAMILY
+        /* This code only works on ASCII machines where the keys are stored in ASCII order */
+        if(strcmp(test,key)) {
+            /* The first difference usually implies the place where things get out of sync */
+            log_err("FAIL Country diff at offset %d, \"%s\" != \"%s\"\n", count, test, key);
+        }
+#endif
+        if(!strcmp(test,"FX"))
+            log_err("FAIL getISOCountries() has obsolete country code %s\n", test);
+        if(!strcmp(test,"YU"))
+            log_err("FAIL getISOCountries() has obsolete country code %s\n", test);
+        if(!strcmp(test,"ZR"))
+            log_err("FAIL getISOCountries() has obsolete country code %s\n", test);
     }
-    count--;
-    expect=239;
+
+    ures_getNextString(subRes, NULL, &key, &status);
+    if (strcmp(key, "ZZ") != 0) {
+        log_err("ZZ was expected to be the last entry in structLocale, but got %s\n", key);
+    }
+#if U_CHARSET_FAMILY==U_EBCDIC_FAMILY
+    /* On EBCDIC machines, the numbers are sorted last. Account for those in the skipped value too. */
+    key = NULL;
+    do {
+        /* Skip over numeric UN tags. uloc_getISOCountries only returns ISO-3166 codes. */
+        skipped += (key != NULL);
+        ures_getNextString(subRes, NULL, &key, &status);
+    }
+    while (U_SUCCESS(status) && key != NULL && strlen(key) != 2);
+#endif
+    expect -= skipped; /* Ignore the skipped resources from structLocale */
     if(count!=expect)
     {
         log_err("There is an error in getISOCountries, got %d, expected %d \n", count, expect);
     }
+    ures_close(subRes);
+    ures_close(res);
 }
+#endif
 
 static void setUpDataTable()
 {
     int32_t i,j;
     dataTable = (UChar***)(calloc(sizeof(UChar**),LOCALE_INFO_SIZE));
 
-    for (i = 0; i < 23; i++) {
+    for (i = 0; i < LOCALE_INFO_SIZE; i++) {
         dataTable[i] = (UChar**)(calloc(sizeof(UChar*),LOCALE_SIZE));
-        for (j = 0; j < 5; j++){
+        for (j = 0; j < LOCALE_SIZE; j++){
             dataTable[i][j] = CharsToUChars(rawData2[i][j]);
         }
     }
@@ -796,21 +1339,28 @@ static void TestSimpleDisplayNames()
      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" };
-    const char* languageNames [] = { "Hebrew", "Indonesian", "Inukitut", "Uighur", "Yiddish",
-                               "Zhuang" };
+    char languageCodes[] [4] = { "he", "id", "iu", "ug", "yi", "za", "419" };
+    const char* languageNames [] = { "Hebrew", "Indonesian", "Inuktitut", "Uyghur", "Yiddish",
+                               "Zhuang", "419" };
+    const char* inLocale [] = { "en_US", "zh_Hant"};
     UErrorCode status=U_ZERO_ERROR;
 
     int32_t i;
-    for (i = 0; i < 6; i++) {
+    int32_t localeIndex = 0;
+    for (i = 0; i < 7; i++) {
         UChar *testLang=0;
         UChar *expectedLang=0;
         int size=0;
-        size=uloc_getDisplayLanguage(languageCodes[i], "en_US", NULL, size, &status);
+        
+        if (i == 6) {
+            localeIndex = 1; /* Use the second locale for the rest of the test. */
+        }
+        
+        size=uloc_getDisplayLanguage(languageCodes[i], inLocale[localeIndex], NULL, size, &status);
         if(status==U_BUFFER_OVERFLOW_ERROR) {
             status=U_ZERO_ERROR;
             testLang=(UChar*)malloc(sizeof(UChar) * (size + 1));
-            uloc_getDisplayLanguage(languageCodes[i], "en_US", testLang, size + 1, &status);
+            uloc_getDisplayLanguage(languageCodes[i], inLocale[localeIndex], testLang, size + 1, &status);
         }
         expectedLang=(UChar*)malloc(sizeof(UChar) * (strlen(languageNames[i])+1));
         u_uastrcpy(expectedLang, languageNames[i]);
@@ -830,13 +1380,13 @@ static void TestUninstalledISO3Names()
 {
   /* This test checks to make sure getISO3Language and getISO3Country work right
      even for locales that are not installed. */
-    const char iso2Languages [][4] = {     "am", "ba", "fy", "mr", "rn",
+    static const char iso2Languages [][4] = {     "am", "ba", "fy", "mr", "rn",
                                         "ss", "tw", "zu" };
-    const char iso3Languages [][5] = {     "amh", "bak", "fry", "mar", "run",
+    static const char iso3Languages [][5] = {     "amh", "bak", "fry", "mar", "run",
                                         "ssw", "twi", "zul" };
-    char iso2Countries [][6] = {     "am_AF", "ba_BW", "fy_KZ", "mr_MO", "rn_MN",
+    static const char iso2Countries [][6] = {     "am_AF", "ba_BW", "fy_KZ", "mr_MO", "rn_MN",
                                         "ss_SB", "tw_TC", "zu_ZW" };
-    char iso3Countries [][4] = {     "AFG", "BWA", "KAZ", "MAC", "MNG",
+    static const char iso3Countries [][4] = {     "AFG", "BWA", "KAZ", "MAC", "MNG",
                                         "SLB", "TCA", "ZWE" };
     int32_t i;
 
@@ -861,13 +1411,13 @@ static void TestUninstalledISO3Names()
 
 static void TestVariantParsing()
 {
-    const char* en_US_custom="en_US_De Anza_Cupertino_California_United States_Earth";
-    const char* dispName="English (United States, DE ANZA_CUPERTINO_CALIFORNIA_UNITED STATES_EARTH)";
-    const char* dispVar="DE ANZA_CUPERTINO_CALIFORNIA_UNITED STATES_EARTH";
-    const char* shortVariant="fr_FR_foo";
-    const char* bogusVariant="fr_FR__foo";
-    const char* bogusVariant2="fr_FR_foo_";
-    const char* bogusVariant3="fr_FR__foo_";
+    static const char* en_US_custom="en_US_De Anza_Cupertino_California_United States_Earth";
+    static const char* dispName="English (United States, DE ANZA_CUPERTINO_CALIFORNIA_UNITED STATES_EARTH)";
+    static const char* dispVar="DE ANZA_CUPERTINO_CALIFORNIA_UNITED STATES_EARTH";
+    static const char* shortVariant="fr_FR_foo";
+    static const char* bogusVariant="fr_FR__foo";
+    static const char* bogusVariant2="fr_FR_foo_";
+    static const char* bogusVariant3="fr_FR__foo_";
 
 
     UChar displayVar[100];
@@ -900,7 +1450,11 @@ static void TestVariantParsing()
     }
     u_uastrcpy(displayName, dispName);
     if(u_strcmp(got,displayName)!=0) {
-        log_err("FAIL: getDisplayName() Wanted %s, got %s\n", dispName, austrdup(got));
+        if (status == U_USING_DEFAULT_WARNING) {
+            log_data_err("FAIL: getDisplayName() got %s. Perhaps you are missing data?\n", u_errorName(status));
+        } else {
+            log_err("FAIL: getDisplayName() Wanted %s, got %s\n", dispName, austrdup(got));
+        }
     }
 
     size=0;
@@ -969,13 +1523,13 @@ static void TestObsoleteNames(void)
     UErrorCode status = U_ZERO_ERROR;
     char buff[256];
 
-    struct
+    static const struct
     {
         char locale[9];
-        char lang3[6];
-        char lang[6];
-        char ctry3[6];
-        char ctry[6];
+        char lang3[4];
+        char lang[4];
+        char ctry3[4];
+        char ctry[4];
     } tests[] =
     {
         { "eng_USA", "eng", "en", "USA", "US" },
@@ -983,6 +1537,7 @@ static void TestObsoleteNames(void)
         { "in",  "ind", "in", "", "" },
         { "id",  "ind", "id", "", "" }, /* NO aliasing */
         { "sh",  "srp", "sh", "", "" },
+        { "zz_CS",  "", "zz", "SCG", "CS" },
         { "zz_FX",  "", "zz", "FXX", "FX" },
         { "zz_RO",  "", "zz", "ROU", "RO" },
         { "zz_TP",  "", "zz", "TMP", "TP" },
@@ -994,6 +1549,7 @@ static void TestObsoleteNames(void)
         { "zz_ZAR",  "", "zz", "ZAR", "ZR" },
         { "zz_TMP",  "", "zz", "TMP", "TP" },
         { "zz_TLS",  "", "zz", "TLS", "TL" },
+        { "zz_YUG",  "", "zz", "YUG", "YU" },
         { "mlt_PSE", "mlt", "mt", "PSE", "PS" },
         { "iw", "heb", "iw", "", "" },
         { "ji", "yid", "ji", "", "" },
@@ -1081,6 +1637,14 @@ static void TestObsoleteNames(void)
         }
     }
 
+    if (uloc_getLCID("iw_IL") != uloc_getLCID("he_IL")) {
+        log_err("he,iw LCID mismatch: %X versus %X\n", uloc_getLCID("iw_IL"), uloc_getLCID("he_IL"));
+    }
+
+    if (uloc_getLCID("iw") != uloc_getLCID("he")) {
+        log_err("he,iw LCID mismatch: %X versus %X\n", uloc_getLCID("iw"), uloc_getLCID("he"));
+    }
+
 #if 0
 
     i = uloc_getLanguage("kok",NULL,0,&icu_err);
@@ -1142,837 +1706,5886 @@ static void TestObsoleteNames(void)
 
 }
 
-static void
-TestKeyInRootRecursive(UResourceBundle *root, const char *rootName,
-                       UResourceBundle *currentBundle, const char *locale) {
-    UErrorCode errorCode = U_ZERO_ERROR;
-    UResourceBundle *subRootBundle = NULL, *subBundle = NULL;
-
-    ures_resetIterator(root);
-    ures_resetIterator(currentBundle);
-    while (ures_hasNext(currentBundle)) {
-        const char *subBundleKey = NULL;
-        const char *currentBundleKey = NULL;
-
-        errorCode = U_ZERO_ERROR;
-        subBundle = ures_getNextResource(currentBundle, NULL, &errorCode);
-        if (U_FAILURE(errorCode)) {
-            log_err("Can't open a resource for locale %s\n", locale);
-            continue;
+static void TestKeywordVariants(void) 
+{
+    static const struct {
+        const char *localeID;
+        const char *expectedLocaleID;           /* uloc_getName */
+        const char *expectedLocaleIDNoKeywords; /* uloc_getBaseName */
+        const char *expectedCanonicalID;        /* uloc_canonicalize */
+        const char *expectedKeywords[10];
+        int32_t numKeywords;
+        UErrorCode expectedStatus; /* from uloc_openKeywords */
+    } testCases[] = {
+        {
+            "de_DE@  currency = euro; C o ll A t i o n   = Phonebook   ; C alen dar = buddhist   ", 
+            "de_DE@calendar=buddhist;collation=Phonebook;currency=euro", 
+            "de_DE",
+            "de_DE@calendar=buddhist;collation=Phonebook;currency=euro", 
+            {"calendar", "collation", "currency"},
+            3,
+            U_ZERO_ERROR
+        },
+        {
+            "de_DE@euro",
+            "de_DE@euro",
+            "de_DE@euro",   /* we probably should strip off the POSIX style variant @euro see #11690 */
+            "de_DE@currency=EUR",
+            {"","","","","","",""},
+            0,
+            U_INVALID_FORMAT_ERROR /* must have '=' after '@' */
+        },
+        {
+            "de_DE@euro;collation=phonebook",   /* The POSIX style variant @euro cannot be combined with key=value? */
+            "de_DE", /* getName returns de_DE - should be INVALID_FORMAT_ERROR? */
+            "de_DE", /* getBaseName returns de_DE - should be INVALID_FORMAT_ERROR? see #11690 */
+            "de_DE", /* canonicalize returns de_DE - should be INVALID_FORMAT_ERROR? */
+            {"","","","","","",""},
+            0,
+            U_INVALID_FORMAT_ERROR
+        },
+        {
+            "de_DE@collation=",
+            0, /* expected getName to fail */
+            "de_DE", /* getBaseName returns de_DE - should be INVALID_FORMAT_ERROR? see #11690 */
+            0, /* expected canonicalize to fail */
+            {"","","","","","",""},
+            0,
+            U_INVALID_FORMAT_ERROR /* must have '=' after '@' */
         }
-        subBundleKey = ures_getKey(subBundle);
-        currentBundleKey = ures_getKey(currentBundle);
-
-        subRootBundle = ures_getByKey(root, subBundleKey, NULL, &errorCode);
-        if (U_FAILURE(errorCode)) {
-/*            if (ures_hasNext(root)) {
-                errorCode = U_ZERO_ERROR;
-                subRootBundle = ures_getNextResource(root, NULL, &errorCode);
-            }
-            if (errorCode!=U_ZERO_ERROR) {
-                if (ures_getKey(currentBundle) != 0 && strcmp(ures_getKey(currentBundle), "zoneStrings") == 0) {
-                    break;
-                }
-                else {*/
-                    if (subBundleKey == NULL
-                        || (strcmp(subBundleKey, "TransliterateLATIN") != 0 /* Ignore these special cases */
-                        && strcmp(subBundleKey, "BreakDictionaryData") != 0))
-                    {
-                        UBool isRoot = strcmp(rootName, "root") == 0;
-                        UBool isSpecial = FALSE;
-                        if (currentBundleKey) {
-                            isSpecial = strcmp(currentBundleKey, "Currencies") == 0
-                                || strcmp(currentBundleKey, "Languages") == 0
-                                || strcmp(currentBundleKey, "Countries") == 0;
-                        }
-
-                        if ((isRoot && !isSpecial)
-                            || (!isRoot && isSpecial))
-                        {
-                            log_err("Can't open a resource with key \"%s\" in \"%s\" from %s for locale \"%s\"\n",
-                                    subBundleKey,
-                                    ures_getKey(currentBundle),
-                                    rootName,
-                                    locale);
-                        }
-                    }
-                    ures_close(subBundle);
-                    continue;
-/*                }
-            }*/
-        }
-        if (ures_getType(subRootBundle) != ures_getType(subBundle)) {
-            log_err("key \"%s\" in \"%s\" has a different type from root for locale \"%s\"\n"
-                    "\troot=%d, locale=%d\n",
-                    subBundleKey,
-                    ures_getKey(currentBundle),
-                    locale,
-                    ures_getType(subRootBundle),
-                    ures_getType(subBundle));
-            continue;
+    };
+    UErrorCode status = U_ZERO_ERROR;
+    
+    int32_t i = 0, j = 0;
+    int32_t resultLen = 0;
+    char buffer[256];
+    UEnumeration *keywords;
+    int32_t keyCount = 0;
+    const char *keyword = NULL;
+    int32_t keywordLen = 0;
+    
+    for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
+        status = U_ZERO_ERROR;
+        *buffer = 0;
+        keywords = uloc_openKeywords(testCases[i].localeID, &status);
+        
+        if(status != testCases[i].expectedStatus) {
+            log_err("Expected to uloc_openKeywords(\"%s\") => status %s. Got %s instead\n", 
+                    testCases[i].localeID,
+                    u_errorName(testCases[i].expectedStatus), u_errorName(status));
         }
-        else if (ures_getType(subBundle) == URES_INT_VECTOR) {
-            int32_t minSize;
-            int32_t subBundleSize;
-            int32_t idx;
-            UBool sameArray = TRUE;
-            const int32_t *subRootBundleArr = ures_getIntVector(subRootBundle, &minSize, &errorCode);
-            const int32_t *subBundleArr = ures_getIntVector(subBundle, &subBundleSize, &errorCode);
-
-            if (minSize > subBundleSize) {
-                minSize = subBundleSize;
-                log_err("Arrays are different size with key \"%s\" in \"%s\" from root for locale \"%s\"\n",
-                        subBundleKey,
-                        ures_getKey(currentBundle),
-                        locale);
+        status = U_ZERO_ERROR;
+        if(keywords) {
+            if((keyCount = uenum_count(keywords, &status)) != testCases[i].numKeywords) {
+                log_err("Expected to get %i keywords, got %i\n", testCases[i].numKeywords, keyCount);
             }
-
-            for (idx = 0; idx < minSize && sameArray; idx++) {
-                if (subRootBundleArr[idx] != subBundleArr[idx]) {
-                    sameArray = FALSE;
+            if(keyCount) {
+                j = 0;
+                while((keyword = uenum_next(keywords, &keywordLen, &status))) {
+                    if(strcmp(keyword, testCases[i].expectedKeywords[j]) != 0) {
+                        log_err("Expected to get keyword value %s, got %s\n", testCases[i].expectedKeywords[j], keyword);
+                    }
+                    j++;
                 }
-                if (strcmp(subBundleKey, "DateTimeElements") == 0
-                    && (subBundleArr[idx] < 1 || 7 < subBundleArr[idx]))
-                {
-                    log_err("Value out of range with key \"%s\" at index %d in \"%s\" for locale \"%s\"\n",
-                            subBundleKey,
-                            idx,
-                            ures_getKey(currentBundle),
-                            locale);
+                j = 0;
+                uenum_reset(keywords, &status);
+                while((keyword = uenum_next(keywords, &keywordLen, &status))) {
+                    if(strcmp(keyword, testCases[i].expectedKeywords[j]) != 0) {
+                        log_err("Expected to get keyword value %s, got %s\n", testCases[i].expectedKeywords[j], keyword);
+                    }
+                    j++;
                 }
             }
-            /* Special exception es_US and DateTimeElements */
-            if (sameArray
-                && !(strcmp(locale, "es_US") == 0 && strcmp(subBundleKey, "DateTimeElements") == 0))
-            {
-                log_err("Integer vectors are the same with key \"%s\" in \"%s\" from root for locale \"%s\"\n",
-                        subBundleKey,
-                        ures_getKey(currentBundle),
-                        locale);
-            }
+            uenum_close(keywords);
         }
-        else if (ures_getType(subBundle) == URES_ARRAY) {
-            UResourceBundle *subSubBundle = ures_getByIndex(subBundle, 0, NULL, &errorCode);
-            UResourceBundle *subSubRootBundle = ures_getByIndex(subRootBundle, 0, NULL, &errorCode);
 
-            if (U_SUCCESS(errorCode)
-                && (ures_getType(subSubBundle) == URES_ARRAY || ures_getType(subSubRootBundle) == URES_ARRAY))
-            {
-                /* TODO: Properly check for 2D arrays and zoneStrings */
-                if (subBundleKey != NULL && strcmp(subBundleKey, "zoneStrings") == 0) {
-/*                    int32_t minSize = ures_getSize(subBundle);
-                    int32_t idx;
-
-                    for (idx = 0; idx < minSize; idx++) {
-                        UResourceBundle *subSubBundleAtIndex = ures_getByIndex(subBundle, idx, NULL, &errorCode);
-                        if (ures_getSize(subSubBundleAtIndex) != 6) {
-                            log_err("zoneStrings at index %d has wrong size for locale \"%s\". array size=%d\n",
-                                    idx,
-                                    locale,
-                                    ures_getSize(subSubBundleAtIndex));
-                        }
-                        ures_close(subSubBundleAtIndex);
-                    }*/
-                }
-                else {
-                    /* Here is one of the recursive parts */
-                    TestKeyInRootRecursive(subRootBundle, rootName, subBundle, locale);
-                }
+        status = U_ZERO_ERROR;
+        resultLen = uloc_getName(testCases[i].localeID, buffer, 256, &status);
+        if (U_SUCCESS(status)) {
+            if (testCases[i].expectedLocaleID == 0) {
+                log_err("Expected uloc_getName(\"%s\") to fail; got \"%s\"\n",
+                        testCases[i].localeID, buffer);
+            } else if (uprv_strcmp(testCases[i].expectedLocaleID, buffer) != 0) {
+                log_err("Expected uloc_getName(\"%s\") => \"%s\"; got \"%s\"\n",
+                        testCases[i].localeID, testCases[i].expectedLocaleID, buffer);
             }
-            else {
-                int32_t minSize = ures_getSize(subRootBundle);
-                int32_t idx;
-                UBool sameArray = TRUE;
-
-                if (minSize > ures_getSize(subBundle)) {
-                    minSize = ures_getSize(subBundle);
-                }
-
-                if ((subBundleKey == NULL
-                    || (subBundleKey != NULL && strcmp(subBundleKey, "LocaleScript") != 0))
-                    && ures_getSize(subRootBundle) != ures_getSize(subBundle))
-                {
-                    log_err("Different size array with key \"%s\" in \"%s\" from root for locale \"%s\"\n"
-                            "\troot array size=%d, locale array size=%d\n",
-                            subBundleKey,
-                            ures_getKey(currentBundle),
-                            locale,
-                            ures_getSize(subRootBundle),
-                            ures_getSize(subBundle));
-                }
-
-                for (idx = 0; idx < minSize; idx++) {
-                    int32_t rootStrLen, localeStrLen;
-                    const UChar *rootStr = ures_getStringByIndex(subRootBundle,idx,&rootStrLen,&errorCode);
-                    const UChar *localeStr = ures_getStringByIndex(subBundle,idx,&localeStrLen,&errorCode);
-                    if (rootStr && localeStr && U_SUCCESS(errorCode)) {
-                        if (u_strcmp(rootStr, localeStr) != 0) {
-                            sameArray = FALSE;
-                        }
-                    }
-                    else {
-                        log_err("Got a NULL string with key \"%s\" in \"%s\" at index %d for root or locale \"%s\"\n",
-                                subBundleKey,
-                                ures_getKey(currentBundle),
-                                idx,
-                                locale);
-                        continue;
-                    }
-                    if (localeStr[0] == (UChar)0x20) {
-                        log_err("key \"%s\" at index %d in \"%s\" starts with a space in locale \"%s\"\n",
-                                subBundleKey,
-                                idx,
-                                ures_getKey(currentBundle),
-                                locale);
-                    }
-                    else if (localeStr[localeStrLen - 1] == (UChar)0x20) {
-                        log_err("key \"%s\" at index %d in \"%s\" ends with a space in locale \"%s\"\n",
-                                subBundleKey,
-                                idx,
-                                ures_getKey(currentBundle),
-                                locale);
-                    }
-                    else if (subBundleKey != NULL
-                        && strcmp(subBundleKey, "DateTimePatterns") == 0)
-                    {
-                        int32_t quoted = 0;
-                        const UChar *localeStrItr = localeStr;
-                        while (*localeStrItr) {
-                            if (*localeStrItr == (UChar)0x27 /* ' */) {
-                                quoted++;
-                            }
-                            else if ((quoted % 2) == 0) {
-                                /* Search for unquoted characters */
-                                if (4 <= idx && idx <= 7
-                                    && (*localeStrItr == (UChar)0x6B /* k */
-                                    || *localeStrItr == (UChar)0x48 /* H */
-                                    || *localeStrItr == (UChar)0x6D /* m */
-                                    || *localeStrItr == (UChar)0x73 /* s */
-                                    || *localeStrItr == (UChar)0x53 /* S */
-                                    || *localeStrItr == (UChar)0x61 /* a */
-                                    || *localeStrItr == (UChar)0x68 /* h */
-                                    || *localeStrItr == (UChar)0x7A /* z */))
-                                {
-                                    log_err("key \"%s\" at index %d has time pattern chars in date for locale \"%s\"\n",
-                                            subBundleKey,
-                                            idx,
-                                            locale);
-                                }
-                                else if (0 <= idx && idx <= 3
-                                    && (*localeStrItr == (UChar)0x47 /* G */
-                                    || *localeStrItr == (UChar)0x79 /* y */
-                                    || *localeStrItr == (UChar)0x4D /* M */
-                                    || *localeStrItr == (UChar)0x64 /* d */
-                                    || *localeStrItr == (UChar)0x45 /* E */
-                                    || *localeStrItr == (UChar)0x44 /* D */
-                                    || *localeStrItr == (UChar)0x46 /* F */
-                                    || *localeStrItr == (UChar)0x77 /* w */
-                                    || *localeStrItr == (UChar)0x57 /* W */))
-                                {
-                                    log_err("key \"%s\" at index %d has date pattern chars in time for locale \"%s\"\n",
-                                            subBundleKey,
-                                            idx,
-                                            locale);
-                                }
-                            }
-                            localeStrItr++;
-                        }
-                    }
-                    else if (idx == 4 && subBundleKey != NULL
-                        && strcmp(subBundleKey, "NumberElements") == 0
-                        && u_charDigitValue(localeStr[0]) != 0)
-                    {
-                        log_err("key \"%s\" at index %d has a non-zero based number for locale \"%s\"\n",
-                                subBundleKey,
-                                idx,
-                                locale);
-                    }
-                }
-                if (sameArray && strcmp(rootName, "root") == 0) {
-                    log_err("Arrays are the same with key \"%s\" in \"%s\" from root for locale \"%s\"\n",
-                            subBundleKey,
-                            ures_getKey(currentBundle),
-                            locale);
-                }
+        } else {
+            if (testCases[i].expectedLocaleID != 0) {
+                log_err("Expected uloc_getName(\"%s\") => \"%s\"; but returned error: %s\n",
+                        testCases[i].localeID, testCases[i].expectedLocaleID, buffer, u_errorName(status));
             }
-            ures_close(subSubBundle);
-            ures_close(subSubRootBundle);
-        }
-        else if (ures_getType(subBundle) == URES_STRING) {
-            int32_t len = 0;
-            const UChar *string = ures_getString(subBundle, &len, &errorCode);
-            if (U_FAILURE(errorCode) || string == NULL) {
-                log_err("Can't open a string with key \"%s\" in \"%s\" for locale \"%s\"\n",
-                        subBundleKey,
-                        ures_getKey(currentBundle),
-                        locale);
-            } else if (string[0] == (UChar)0x20) {
-                log_err("key \"%s\" in \"%s\" starts with a space in locale \"%s\"\n",
-                        subBundleKey,
-                        ures_getKey(currentBundle),
-                        locale);
-            } else if (string[len - 1] == (UChar)0x20) {
-                log_err("key \"%s\" in \"%s\" ends with a space in locale \"%s\"\n",
-                        subBundleKey,
-                        ures_getKey(currentBundle),
-                        locale);
-            } else if (strcmp(subBundleKey, "localPatternChars") == 0 && len != 20) {
-                log_err("key \"%s\" has the wrong number of characters in locale \"%s\"\n",
-                        subBundleKey,
-                        locale);
+        }
+
+        status = U_ZERO_ERROR;
+        resultLen = uloc_getBaseName(testCases[i].localeID, buffer, 256, &status);
+        if (U_SUCCESS(status)) {
+            if (testCases[i].expectedLocaleIDNoKeywords == 0) {
+                log_err("Expected uloc_getBaseName(\"%s\") to fail; got \"%s\"\n",
+                        testCases[i].localeID, buffer);
+            } else if (uprv_strcmp(testCases[i].expectedLocaleIDNoKeywords, buffer) != 0) {
+                log_err("Expected uloc_getBaseName(\"%s\") => \"%s\"; got \"%s\"\n",
+                        testCases[i].localeID, testCases[i].expectedLocaleIDNoKeywords, buffer);
             }
-            /* No fallback was done. Check for duplicate data */
-            /* The ures_* API does not do fallback of sub-resource bundles,
-               So we can't do this now. */
-            else if (strcmp(locale, "root") != 0 && errorCode == U_ZERO_ERROR) {
-
-                const UChar *rootString = ures_getString(subRootBundle, &len, &errorCode);
-                if (U_FAILURE(errorCode) || rootString == NULL) {
-                    log_err("Can't open a string with key \"%s\" in \"%s\" in root\n",
-                            ures_getKey(subRootBundle),
-                            ures_getKey(currentBundle));
-                    continue;
-                } else if (u_strcmp(string, rootString) == 0) {
-                    if (strcmp(locale, "de_CH") != 0 && strcmp(subBundleKey, "Countries") != 0) {
-                        log_err("Found duplicate data with key \"%s\" in \"%s\" in locale \"%s\"\n",
-                                ures_getKey(subRootBundle),
-                                ures_getKey(currentBundle),
-                                locale);
-                    }
-                    else {
-                        /* Ignore for now. */
-                        /* Can be fixed if fallback through de locale was done. */
-                        log_verbose("Skipping key %s in %s\n", subBundleKey, locale);
-                    }
-                }
+        } else {
+            if (testCases[i].expectedLocaleIDNoKeywords != 0) {
+                log_err("Expected uloc_getBaseName(\"%s\") => \"%s\"; but returned error: %s\n",
+                        testCases[i].localeID, testCases[i].expectedLocaleIDNoKeywords, buffer, u_errorName(status));
             }
         }
-        else if (ures_getType(subBundle) == URES_TABLE) {
-            /* Here is one of the recursive parts */
-            TestKeyInRootRecursive(subRootBundle, rootName, subBundle, locale);
-        }
-        else if (ures_getType(subBundle) == URES_BINARY || ures_getType(subBundle) == URES_INT) {
-            /* Can't do anything to check it */
-            /* We'll assume it's all correct */
-            if (strcmp(subBundleKey, "LocaleID") != 0) {
-                log_verbose("Skipping key \"%s\" in \"%s\" for locale \"%s\"\n",
-                        subBundleKey,
-                        ures_getKey(currentBundle),
-                        locale);
+
+        status = U_ZERO_ERROR;
+        resultLen = uloc_canonicalize(testCases[i].localeID, buffer, 256, &status);
+        if (U_SUCCESS(status)) {
+            if (testCases[i].expectedCanonicalID == 0) {
+                log_err("Expected uloc_canonicalize(\"%s\") to fail; got \"%s\"\n",
+                        testCases[i].localeID, buffer);
+            } else if (uprv_strcmp(testCases[i].expectedCanonicalID, buffer) != 0) {
+                log_err("Expected uloc_canonicalize(\"%s\") => \"%s\"; got \"%s\"\n",
+                        testCases[i].localeID, testCases[i].expectedCanonicalID, buffer);
+            }
+        } else {
+            if (testCases[i].expectedCanonicalID != 0) {
+                log_err("Expected uloc_canonicalize(\"%s\") => \"%s\"; but returned error: %s\n",
+                        testCases[i].localeID, testCases[i].expectedCanonicalID, buffer, u_errorName(status));
             }
-            /* Testing for LocaleID is done in testLCID */
-        }
-        else {
-            log_err("Type %d for key \"%s\" in \"%s\" is unknown for locale \"%s\"\n",
-                    ures_getType(subBundle),
-                    subBundleKey,
-                    ures_getKey(currentBundle),
-                    locale);
         }
-        ures_close(subRootBundle);
-        ures_close(subBundle);
     }
 }
 
+static void TestKeywordVariantParsing(void) 
+{
+    static const struct {
+        const char *localeID;
+        const char *keyword;
+        const char *expectedValue; /* NULL if failure is expected */
+    } testCases[] = {
+        { "de_DE@  C o ll A t i o n   = Phonebook   ", "c o ll a t i o n", NULL }, /* malformed key name */
+        { "de_DE", "collation", ""},
+        { "de_DE@collation=PHONEBOOK", "collation", "PHONEBOOK" },
+        { "de_DE@currency = euro; CoLLaTion   = PHONEBOOk", "collatiON", "PHONEBOOk" },
+    };
+    
+    UErrorCode status;
+    int32_t i = 0;
+    int32_t resultLen = 0;
+    char buffer[256];
+    
+    for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
+        *buffer = 0;
+        status = U_ZERO_ERROR;
+        resultLen = uloc_getKeywordValue(testCases[i].localeID, testCases[i].keyword, buffer, 256, &status);
+        (void)resultLen;    /* Suppress set but not used warning. */
+        if (testCases[i].expectedValue) {
+            /* expect success */
+            if (U_FAILURE(status)) {
+                log_err("Expected to extract \"%s\" from \"%s\" for keyword \"%s\". Instead got status %s\n",
+                    testCases[i].expectedValue, testCases[i].localeID, testCases[i].keyword, u_errorName(status));
+            } else if (uprv_strcmp(testCases[i].expectedValue, buffer) != 0) {
+                log_err("Expected to extract \"%s\" from \"%s\" for keyword \"%s\". Instead got \"%s\"\n",
+                    testCases[i].expectedValue, testCases[i].localeID, testCases[i].keyword, buffer);
+            }
+        } else if (U_SUCCESS(status)) {
+            /* expect failure */
+            log_err("Expected failure but got success from \"%s\" for keyword \"%s\". Got \"%s\"\n",
+                testCases[i].localeID, testCases[i].keyword, buffer);
+            
+        }
+    }
+}
+
+static const struct {
+  const char *l; /* locale */
+  const char *k; /* kw */
+  const char *v; /* value */
+  const char *x; /* expected */
+} kwSetTestCases[] = {
+#if 1
+  { "en_US", "calendar", "japanese", "en_US@calendar=japanese" },
+  { "en_US@", "calendar", "japanese", "en_US@calendar=japanese" },
+  { "en_US@calendar=islamic", "calendar", "japanese", "en_US@calendar=japanese" },
+  { "en_US@calendar=slovakian", "calendar", "gregorian", "en_US@calendar=gregorian" }, /* don't know what this means, but it has the same # of chars as gregorian */
+  { "en_US@calendar=gregorian", "calendar", "japanese", "en_US@calendar=japanese" },
+  { "de", "Currency", "CHF", "de@currency=CHF" },
+  { "de", "Currency", "CHF", "de@currency=CHF" },
+
+  { "en_US@collation=phonebook", "calendar", "japanese", "en_US@calendar=japanese;collation=phonebook" },
+  { "en_US@calendar=japanese", "collation", "phonebook", "en_US@calendar=japanese;collation=phonebook" },
+  { "de@collation=phonebook", "Currency", "CHF", "de@collation=phonebook;currency=CHF" },
+  { "en_US@calendar=gregorian;collation=phonebook", "calendar", "japanese", "en_US@calendar=japanese;collation=phonebook" },
+  { "en_US@calendar=slovakian;collation=phonebook", "calendar", "gregorian", "en_US@calendar=gregorian;collation=phonebook" }, /* don't know what this means, but it has the same # of chars as gregorian */
+  { "en_US@calendar=slovakian;collation=videobook", "collation", "phonebook", "en_US@calendar=slovakian;collation=phonebook" }, /* don't know what this means, but it has the same # of chars as gregorian */
+  { "en_US@calendar=islamic;collation=phonebook", "calendar", "japanese", "en_US@calendar=japanese;collation=phonebook" },
+  { "de@collation=phonebook", "Currency", "CHF", "de@collation=phonebook;currency=CHF" },
+#endif
+#if 1
+  { "mt@a=0;b=1;c=2;d=3", "c","j", "mt@a=0;b=1;c=j;d=3" },
+  { "mt@a=0;b=1;c=2;d=3", "x","j", "mt@a=0;b=1;c=2;d=3;x=j" },
+  { "mt@a=0;b=1;c=2;d=3", "a","f", "mt@a=f;b=1;c=2;d=3" },
+  { "mt@a=0;aa=1;aaa=3", "a","x", "mt@a=x;aa=1;aaa=3" },
+  { "mt@a=0;aa=1;aaa=3", "aa","x", "mt@a=0;aa=x;aaa=3" },
+  { "mt@a=0;aa=1;aaa=3", "aaa","x", "mt@a=0;aa=1;aaa=x" },
+  { "mt@a=0;aa=1;aaa=3", "a","yy", "mt@a=yy;aa=1;aaa=3" },
+  { "mt@a=0;aa=1;aaa=3", "aa","yy", "mt@a=0;aa=yy;aaa=3" },
+  { "mt@a=0;aa=1;aaa=3", "aaa","yy", "mt@a=0;aa=1;aaa=yy" },
+#endif
+#if 1
+  /* removal tests */
+  /* 1. removal of item at end */
+  { "de@collation=phonebook;currency=CHF", "currency",   "", "de@collation=phonebook" },
+  { "de@collation=phonebook;currency=CHF", "currency", NULL, "de@collation=phonebook" },
+  /* 2. removal of item at beginning */
+  { "de@collation=phonebook;currency=CHF", "collation", "", "de@currency=CHF" },
+  { "de@collation=phonebook;currency=CHF", "collation", NULL, "de@currency=CHF" },
+  /* 3. removal of an item not there */
+  { "de@collation=phonebook;currency=CHF", "calendar", NULL, "de@collation=phonebook;currency=CHF" },
+  /* 4. removal of only item */
+  { "de@collation=phonebook", "collation", NULL, "de" },
+#endif
+  { "de@collation=phonebook", "Currency", "CHF", "de@collation=phonebook;currency=CHF" },
+  /* cases with legal extra spacing */
+  /*31*/{ "en_US@ calendar = islamic", "calendar", "japanese", "en_US@calendar=japanese" },
+  /*32*/{ "en_US@ calendar = gregorian ; collation = phonebook", "calendar", "japanese", "en_US@calendar=japanese;collation=phonebook" },
+  /*33*/{ "en_US@ calendar = islamic", "currency", "CHF", "en_US@calendar=islamic;currency=CHF" },
+  /*34*/{ "en_US@ currency = CHF", "calendar", "japanese", "en_US@calendar=japanese;currency=CHF" },
+  /* cases in which setKeywordValue expected to fail (implied by NULL for expected); locale need not be canonical */
+  /*35*/{ "en_US@calendar=gregorian;", "calendar", "japanese", NULL },
+  /*36*/{ "en_US@calendar=gregorian;=", "calendar", "japanese", NULL },
+  /*37*/{ "en_US@calendar=gregorian;currency=", "calendar", "japanese", NULL },
+  /*38*/{ "en_US@=", "calendar", "japanese", NULL },
+  /*39*/{ "en_US@=;", "calendar", "japanese", NULL },
+  /*40*/{ "en_US@= ", "calendar", "japanese", NULL },
+  /*41*/{ "en_US@ =", "calendar", "japanese", NULL },
+  /*42*/{ "en_US@ = ", "calendar", "japanese", NULL },
+  /*43*/{ "en_US@=;calendar=gregorian", "calendar", "japanese", NULL },
+  /*44*/{ "en_US@= calen dar = gregorian", "calendar", "japanese", NULL },
+  /*45*/{ "en_US@= calendar = greg orian", "calendar", "japanese", NULL },
+  /*46*/{ "en_US@=;cal...endar=gregorian", "calendar", "japanese", NULL },
+  /*47*/{ "en_US@=;calendar=greg...orian", "calendar", "japanese", NULL },
+  /*48*/{ "en_US@calendar=gregorian", "cale ndar", "japanese", NULL },
+  /*49*/{ "en_US@calendar=gregorian", "calendar", "japa..nese", NULL },
+  /* cases in which getKeywordValue and setKeyword expected to fail (implied by NULL for value and expected) */
+  /*50*/{ "en_US@=", "calendar", NULL, NULL },
+  /*51*/{ "en_US@=;", "calendar", NULL, NULL },
+  /*52*/{ "en_US@= ", "calendar", NULL, NULL },
+  /*53*/{ "en_US@ =", "calendar", NULL, NULL },
+  /*54*/{ "en_US@ = ", "calendar", NULL, NULL },
+  /*55*/{ "en_US@=;calendar=gregorian", "calendar", NULL, NULL },
+  /*56*/{ "en_US@= calen dar = gregorian", "calendar", NULL, NULL },
+  /*57*/{ "en_US@= calendar = greg orian", "calendar", NULL, NULL },
+  /*58*/{ "en_US@=;cal...endar=gregorian", "calendar", NULL, NULL },
+  /*59*/{ "en_US@=;calendar=greg...orian", "calendar", NULL, NULL },
+  /*60*/{ "en_US@calendar=gregorian", "cale ndar", NULL, NULL },
+};
 
-#ifdef WIN32
-
-static void
-testLCID(UResourceBundle *currentBundle,
-         const char *localeName)
+
+static void TestKeywordSet(void)
 {
-    UErrorCode status = U_ZERO_ERROR;
-    uint32_t lcid;
-    uint32_t expectedLCID;
-    char lcidStringC[64] = {0};
-    int32_t lcidStringLen = 0;
-    const UChar *lcidString = NULL;
-    UResourceBundle *localeID = ures_getByKey(currentBundle, "LocaleID", NULL, &status);
+    int32_t i = 0;
+    int32_t resultLen = 0;
+    char buffer[1024];
 
-    expectedLCID = ures_getInt(localeID, &status);
-    ures_close(localeID);
+    char cbuffer[1024];
 
-    if (U_FAILURE(status)) {
-        log_err("ERROR:   %s does not have a LocaleID (%s)\n",
-            localeName, u_errorName(status));
-        return;
-    }
+    for(i = 0; i < UPRV_LENGTHOF(kwSetTestCases); i++) {
+      UErrorCode status = U_ZERO_ERROR;
+      memset(buffer,'%',1023);
+      strcpy(buffer, kwSetTestCases[i].l);
 
-    lcid = uprv_convertToLCID(localeName, &status);
-    if (U_FAILURE(status)) {
-        if (expectedLCID == 0) {
-            log_verbose("INFO:    %-5s does not have any LCID mapping\n",
-                localeName);
+      if (kwSetTestCases[i].x != NULL) {
+        uloc_canonicalize(kwSetTestCases[i].l, cbuffer, 1023, &status);
+        if(strcmp(buffer,cbuffer)) {
+          log_verbose("note: [%d] wasn't canonical, should be: '%s' not '%s'. Won't check for canonicity in output.\n", i, cbuffer, buffer);
         }
-        else {
-            log_err("ERROR:   %-5s does not have an LCID mapping to 0x%.4X\n",
-                localeName, expectedLCID);
+        /* sanity check test case results for canonicity */
+        uloc_canonicalize(kwSetTestCases[i].x, cbuffer, 1023, &status);
+        if(strcmp(kwSetTestCases[i].x,cbuffer)) {
+          log_err("%s:%d: ERROR: kwSetTestCases[%d].x = '%s', should be %s (must be canonical)\n", __FILE__, __LINE__, i, kwSetTestCases[i].x, cbuffer);
         }
-        return;
+
+        status = U_ZERO_ERROR;
+        resultLen = uloc_setKeywordValue(kwSetTestCases[i].k, kwSetTestCases[i].v, buffer, 1023, &status);
+        if(U_FAILURE(status)) {
+          log_err("Err on test case %d for setKeywordValue: got error %s\n", i, u_errorName(status));
+        } else if(strcmp(buffer,kwSetTestCases[i].x) || ((int32_t)strlen(buffer)!=resultLen)) {
+          log_err("FAIL: #%d setKeywordValue: %s + [%s=%s] -> %s (%d) expected %s (%d)\n", i, kwSetTestCases[i].l, kwSetTestCases[i].k,
+                  kwSetTestCases[i].v, buffer, resultLen, kwSetTestCases[i].x, strlen(buffer));
+        } else {
+          log_verbose("pass: #%d: %s + [%s=%s] -> %s\n", i, kwSetTestCases[i].l, kwSetTestCases[i].k, kwSetTestCases[i].v,buffer);
+        }
+
+        if (kwSetTestCases[i].v != NULL && kwSetTestCases[i].v[0] != 0) {
+          status = U_ZERO_ERROR;
+          resultLen = uloc_getKeywordValue(kwSetTestCases[i].x, kwSetTestCases[i].k, buffer, 1023, &status);
+          if(U_FAILURE(status)) {
+            log_err("Err on test case %d for getKeywordValue: got error %s\n", i, u_errorName(status));
+          } else if (resultLen != uprv_strlen(kwSetTestCases[i].v) || uprv_strcmp(buffer, kwSetTestCases[i].v) != 0) {
+            log_err("FAIL: #%d getKeywordValue: got %s (%d) expected %s (%d)\n", i, buffer, resultLen,
+                    kwSetTestCases[i].v, uprv_strlen(kwSetTestCases[i].v));
+          }
+        }
+      } else {
+        /* test cases expected to result in error */
+        status = U_ZERO_ERROR;
+        resultLen = uloc_setKeywordValue(kwSetTestCases[i].k, kwSetTestCases[i].v, buffer, 1023, &status);
+        if(U_SUCCESS(status)) {
+          log_err("Err on test case %d for setKeywordValue: expected to fail but succeeded, got %s (%d)\n", i, buffer, resultLen);
+        }
+
+        if (kwSetTestCases[i].v == NULL) {
+          status = U_ZERO_ERROR;
+          strcpy(cbuffer, kwSetTestCases[i].l);
+          resultLen = uloc_getKeywordValue(cbuffer, kwSetTestCases[i].k, buffer, 1023, &status);
+          if(U_SUCCESS(status)) {
+            log_err("Err on test case %d for getKeywordValue: expected to fail but succeeded\n", i);
+          }
+        }
+      }
     }
+}
+
+static void TestKeywordSetError(void)
+{
+    char buffer[1024];
+    UErrorCode status;
+    int32_t res;
+    int32_t i;
+    int32_t blen;
 
+    /* 0-test whether an error condition modifies the buffer at all */
+    blen=0;
+    i=0;
+    memset(buffer,'%',1023);
     status = U_ZERO_ERROR;
-    uprv_strcpy(lcidStringC, uprv_convertToPosix(expectedLCID, &status));
-    if (U_FAILURE(status)) {
-        log_err("ERROR:   %.4x does not have a POSIX mapping due to %s\n",
-            expectedLCID, u_errorName(status));
+    res = uloc_setKeywordValue(kwSetTestCases[i].k, kwSetTestCases[i].v, buffer, blen, &status);
+    if(status != U_ILLEGAL_ARGUMENT_ERROR) {
+        log_err("expected illegal err got %s\n", u_errorName(status));
+        return;
+    }
+    /*  if(res!=strlen(kwSetTestCases[i].x)) {
+    log_err("expected result %d got %d\n", strlen(kwSetTestCases[i].x), res);
+    return;
+    } */
+    if(buffer[blen]!='%') {
+        log_err("Buffer byte %d was modified: now %c\n", blen, buffer[blen]);
+        return;
     }
+    log_verbose("0-buffer modify OK\n");
 
-    if(lcid != expectedLCID) {
-        log_err("ERROR:   %-5s wrongfully has 0x%.4x instead of 0x%.4x for LCID\n",
-            localeName, expectedLCID, lcid);
+    for(i=0;i<=2;i++) {
+        /* 1- test a short buffer with growing text */
+        blen=(int32_t)strlen(kwSetTestCases[i].l)+1;
+        memset(buffer,'%',1023);
+        strcpy(buffer,kwSetTestCases[i].l);
+        status = U_ZERO_ERROR;
+        res = uloc_setKeywordValue(kwSetTestCases[i].k, kwSetTestCases[i].v, buffer, blen, &status);
+        if(status != U_BUFFER_OVERFLOW_ERROR) {
+            log_err("expected buffer overflow on buffer %d got %s, len %d (%s + [%s=%s])\n", blen, u_errorName(status), res, kwSetTestCases[i].l, kwSetTestCases[i].k, kwSetTestCases[i].v);
+            return;
+        }
+        if(res!=(int32_t)strlen(kwSetTestCases[i].x)) {
+            log_err("expected result %d got %d\n", strlen(kwSetTestCases[i].x), res);
+            return;
+        }
+        if(buffer[blen]!='%') {
+            log_err("Buffer byte %d was modified: now %c\n", blen, buffer[blen]);
+            return;
+        }
+        log_verbose("1/%d-buffer modify OK\n",i);
     }
-    if(strcmp(localeName, lcidStringC) != 0) {
-        char langName[1024];
-        char langLCID[1024];
-        uloc_getLanguage(localeName, langName, sizeof(langName), &status);
-        uloc_getLanguage(lcidStringC, langLCID, sizeof(langLCID), &status);
 
-        if (expectedLCID == lcid && strcmp(langName, langLCID) == 0) {
-            log_verbose("WARNING: %-5s resolves to %s (0x%.4x)\n",
-                localeName, lcidStringC, lcid);
+    for(i=3;i<=4;i++) {
+        /* 2- test a short buffer - text the same size or shrinking   */
+        blen=(int32_t)strlen(kwSetTestCases[i].l)+1;
+        memset(buffer,'%',1023);
+        strcpy(buffer,kwSetTestCases[i].l);
+        status = U_ZERO_ERROR;
+        res = uloc_setKeywordValue(kwSetTestCases[i].k, kwSetTestCases[i].v, buffer, blen, &status);
+        if(status != U_ZERO_ERROR) {
+            log_err("expected zero error got %s\n", u_errorName(status));
+            return;
         }
-        else if (expectedLCID == lcid) {
-            log_err("ERROR:   %-5s has 0x%.4x and the number resolves wrongfully to %s\n",
-                localeName, expectedLCID, lcidStringC);
+        if(buffer[blen+1]!='%') {
+            log_err("Buffer byte %d was modified: now %c\n", blen+1, buffer[blen+1]);
+            return;
         }
-        else {
-            log_err("ERROR:   %-5s has 0x%.4x and the number resolves wrongfully to %s. It should be 0x%x.\n",
-                localeName, expectedLCID, lcidStringC, lcid);
+        if(res!=(int32_t)strlen(kwSetTestCases[i].x)) {
+            log_err("expected result %d got %d\n", strlen(kwSetTestCases[i].x), res);
+            return;
         }
+        if(strcmp(buffer,kwSetTestCases[i].x) || ((int32_t)strlen(buffer)!=res)) {
+            log_err("FAIL: #%d: %s + [%s=%s] -> %s (%d) expected %s (%d)\n", i, kwSetTestCases[i].l, kwSetTestCases[i].k,
+                kwSetTestCases[i].v, buffer, res, kwSetTestCases[i].x, strlen(buffer));
+        } else {
+            log_verbose("pass: #%d: %s + [%s=%s] -> %s\n", i, kwSetTestCases[i].l, kwSetTestCases[i].k, kwSetTestCases[i].v,
+                buffer);
+        }
+        log_verbose("2/%d-buffer modify OK\n",i);
     }
 }
 
-#endif
+static int32_t _canonicalize(int32_t selector, /* 0==getName, 1==canonicalize */
+                             const char* localeID,
+                             char* result,
+                             int32_t resultCapacity,
+                             UErrorCode* ec) {
+    /* YOU can change this to use function pointers if you like */
+    switch (selector) {
+    case 0:
+        return uloc_getName(localeID, result, resultCapacity, ec);
+    case 1:
+        return uloc_canonicalize(localeID, result, resultCapacity, ec);
+    default:
+        return -1;
+    }
+}
 
-static void
-TestLocaleStructure(void) {
-    UResourceBundle *root, *completeLoc, *currentLocale, *subtable, *completeSubtable;
-    int32_t locCount = uloc_countAvailable();
-    int32_t locIndex;
-    UErrorCode errorCode = U_ZERO_ERROR;
-    const char *currLoc;
+static void TestCanonicalization(void)
+{
+    static const struct {
+        const char *localeID;    /* input */
+        const char *getNameID;   /* expected getName() result */
+        const char *canonicalID; /* expected canonicalize() result */
+    } testCases[] = {
+        { "ca_ES_PREEURO-with-extra-stuff-that really doesn't make any sense-unless-you're trying to increase code coverage",
+          "ca_ES_PREEURO_WITH_EXTRA_STUFF_THAT REALLY DOESN'T MAKE ANY SENSE_UNLESS_YOU'RE TRYING TO INCREASE CODE COVERAGE",
+          "ca_ES_PREEURO_WITH_EXTRA_STUFF_THAT REALLY DOESN'T MAKE ANY SENSE_UNLESS_YOU'RE TRYING TO INCREASE CODE COVERAGE"},
+        { "ca_ES_PREEURO", "ca_ES_PREEURO", "ca_ES@currency=ESP" },
+        { "de_AT_PREEURO", "de_AT_PREEURO", "de_AT@currency=ATS" },
+        { "de_DE_PREEURO", "de_DE_PREEURO", "de_DE@currency=DEM" },
+        { "de_LU_PREEURO", "de_LU_PREEURO", "de_LU@currency=LUF" },
+        { "el_GR_PREEURO", "el_GR_PREEURO", "el_GR@currency=GRD" },
+        { "en_BE_PREEURO", "en_BE_PREEURO", "en_BE@currency=BEF" },
+        { "en_IE_PREEURO", "en_IE_PREEURO", "en_IE@currency=IEP" },
+        { "es_ES_PREEURO", "es_ES_PREEURO", "es_ES@currency=ESP" },
+        { "eu_ES_PREEURO", "eu_ES_PREEURO", "eu_ES@currency=ESP" },
+        { "fi_FI_PREEURO", "fi_FI_PREEURO", "fi_FI@currency=FIM" },
+        { "fr_BE_PREEURO", "fr_BE_PREEURO", "fr_BE@currency=BEF" },
+        { "fr_FR_PREEURO", "fr_FR_PREEURO", "fr_FR@currency=FRF" },
+        { "fr_LU_PREEURO", "fr_LU_PREEURO", "fr_LU@currency=LUF" },
+        { "ga_IE_PREEURO", "ga_IE_PREEURO", "ga_IE@currency=IEP" },
+        { "gl_ES_PREEURO", "gl_ES_PREEURO", "gl_ES@currency=ESP" },
+        { "it_IT_PREEURO", "it_IT_PREEURO", "it_IT@currency=ITL" },
+        { "nl_BE_PREEURO", "nl_BE_PREEURO", "nl_BE@currency=BEF" },
+        { "nl_NL_PREEURO", "nl_NL_PREEURO", "nl_NL@currency=NLG" },
+        { "pt_PT_PREEURO", "pt_PT_PREEURO", "pt_PT@currency=PTE" },
+        { "de__PHONEBOOK", "de__PHONEBOOK", "de@collation=phonebook" },
+        { "en_GB_EURO", "en_GB_EURO", "en_GB@currency=EUR" },
+        { "en_GB@EURO", "en_GB@EURO", "en_GB@currency=EUR" }, /* POSIX ID */
+        { "es__TRADITIONAL", "es__TRADITIONAL", "es@collation=traditional" },
+        { "hi__DIRECT", "hi__DIRECT", "hi@collation=direct" },
+        { "ja_JP_TRADITIONAL", "ja_JP_TRADITIONAL", "ja_JP@calendar=japanese" },
+        { "th_TH_TRADITIONAL", "th_TH_TRADITIONAL", "th_TH@calendar=buddhist" },
+        { "zh_TW_STROKE", "zh_TW_STROKE", "zh_TW@collation=stroke" },
+        { "zh__PINYIN", "zh__PINYIN", "zh@collation=pinyin" },
+        { "zh@collation=pinyin", "zh@collation=pinyin", "zh@collation=pinyin" },
+        { "zh_CN@collation=pinyin", "zh_CN@collation=pinyin", "zh_CN@collation=pinyin" },
+        { "zh_CN_STROKE", "zh_CN_STROKE", "zh_CN@collation=stroke" },
+        { "zh_CN_CA@collation=pinyin", "zh_CN_CA@collation=pinyin", "zh_CN_CA@collation=pinyin" },
+        { "en_US_POSIX", "en_US_POSIX", "en_US_POSIX" }, 
+        { "hy_AM_REVISED", "hy_AM_REVISED", "hy_AM_REVISED" }, 
+        { "no_NO_NY", "no_NO_NY", "no_NO_NY" /* not: "nn_NO" [alan ICU3.0] */ },
+        { "no@ny", "no@ny", "no__NY" /* not: "nn" [alan ICU3.0] */ }, /* POSIX ID */
+        { "no-no.utf32@B", "no_NO.utf32@B", "no_NO_B" /* not: "nb_NO_B" [alan ICU3.0] */ }, /* POSIX ID */
+        { "qz-qz@Euro", "qz_QZ@Euro", "qz_QZ@currency=EUR" }, /* qz-qz uses private use iso codes */
+        { "en-BOONT", "en__BOONT", "en__BOONT" }, /* registered name */
+        { "de-1901", "de__1901", "de__1901" }, /* registered name */
+        { "de-1906", "de__1906", "de__1906" }, /* registered name */
+        { "sr-SP-Cyrl", "sr_SP_CYRL", "sr_Cyrl_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 */
+        { "uz-UZ-Cyrl", "uz_UZ_CYRL", "uz_Cyrl_UZ" }, /* .NET name */
+        { "uz-UZ-Latn", "uz_UZ_LATN", "uz_Latn_UZ" }, /* .NET name */
+        { "zh-CHS", "zh_CHS", "zh_Hans" }, /* .NET name */
+        { "zh-CHT", "zh_CHT", "zh_Hant" }, /* .NET name This may change back to zh_Hant */
+
+        /* posix behavior that used to be performed by getName */
+        { "mr.utf8", "mr.utf8", "mr" },
+        { "de-tv.koi8r", "de_TV.koi8r", "de_TV" },
+        { "x-piglatin_ML.MBE", "x-piglatin_ML.MBE", "x-piglatin_ML" },
+        { "i-cherokee_US.utf7", "i-cherokee_US.utf7", "i-cherokee_US" },
+        { "x-filfli_MT_FILFLA.gb-18030", "x-filfli_MT_FILFLA.gb-18030", "x-filfli_MT_FILFLA" },
+        { "no-no-ny.utf8@B", "no_NO_NY.utf8@B", "no_NO_NY_B" /* not: "nn_NO" [alan ICU3.0] */ }, /* @ ignored unless variant is empty */
+
+        /* fleshing out canonicalization */
+        /* trim space and sort keywords, ';' is separator so not present at end in canonical form */
+        { "en_Hant_IL_VALLEY_GIRL@ currency = EUR; calendar = Japanese ;", "en_Hant_IL_VALLEY_GIRL@calendar=Japanese;currency=EUR", "en_Hant_IL_VALLEY_GIRL@calendar=Japanese;currency=EUR" },
+        /* already-canonical ids are not changed */
+        { "en_Hant_IL_VALLEY_GIRL@calendar=Japanese;currency=EUR", "en_Hant_IL_VALLEY_GIRL@calendar=Japanese;currency=EUR", "en_Hant_IL_VALLEY_GIRL@calendar=Japanese;currency=EUR" },
+        /* PRE_EURO and EURO conversions don't affect other keywords */
+        { "es_ES_PREEURO@CALendar=Japanese", "es_ES_PREEURO@calendar=Japanese", "es_ES@calendar=Japanese;currency=ESP" },
+        { "es_ES_EURO@SHOUT=zipeedeedoodah", "es_ES_EURO@shout=zipeedeedoodah", "es_ES@currency=EUR;shout=zipeedeedoodah" },
+        /* currency keyword overrides PRE_EURO and EURO currency */
+        { "es_ES_PREEURO@currency=EUR", "es_ES_PREEURO@currency=EUR", "es_ES@currency=EUR" },
+        { "es_ES_EURO@currency=ESP", "es_ES_EURO@currency=ESP", "es_ES@currency=ESP" },
+        /* norwegian is just too weird, if we handle things in their full generality */
+        { "no-Hant-GB_NY@currency=$$$", "no_Hant_GB_NY@currency=$$$", "no_Hant_GB_NY@currency=$$$" /* not: "nn_Hant_GB@currency=$$$" [alan ICU3.0] */ },
+
+        /* test cases reflecting internal resource bundle usage */
+        { "root@kw=foo", "root@kw=foo", "root@kw=foo" },
+        { "@calendar=gregorian", "@calendar=gregorian", "@calendar=gregorian" },
+        { "ja_JP@calendar=Japanese", "ja_JP@calendar=Japanese", "ja_JP@calendar=Japanese" },
+        { "ja_JP", "ja_JP", "ja_JP" },
+
+        /* test case for "i-default" */
+        { "i-default", "en@x=i-default", "en@x=i-default" }
+    };
+    
+    static const char* label[] = { "getName", "canonicalize" };
 
-    /* TODO: Compare against parent's data too. This code can't handle fallbacks that some tools do already. */
-/*    char locName[ULOC_FULLNAME_CAPACITY];
-    char *locNamePtr;
+    UErrorCode status = U_ZERO_ERROR;
+    int32_t i, j, resultLen = 0, origResultLen;
+    char buffer[256];
+    
+    for (i=0; i < UPRV_LENGTHOF(testCases); i++) {
+        for (j=0; j<2; ++j) {
+            const char* expected = (j==0) ? testCases[i].getNameID : testCases[i].canonicalID;
+            *buffer = 0;
+            status = U_ZERO_ERROR;
+
+            if (expected == NULL) {
+                expected = uloc_getDefault();
+            }
 
-    for (locIndex = 0; locIndex < locCount; locIndex++) {
-        errorCode=U_ZERO_ERROR;
-        strcpy(locName, uloc_getAvailable(locIndex));
-        locNamePtr = strrchr(locName, '_');
-        if (locNamePtr) {
-            *locNamePtr = 0;
-        }
-        else {
-            strcpy(locName, "root");
+            /* log_verbose("testing %s -> %s\n", testCases[i], testCases[i].canonicalID); */
+            origResultLen = _canonicalize(j, testCases[i].localeID, NULL, 0, &status);
+            if (status != U_BUFFER_OVERFLOW_ERROR) {
+                log_err("FAIL: uloc_%s(%s) => %s, expected U_BUFFER_OVERFLOW_ERROR\n",
+                        label[j], testCases[i].localeID, u_errorName(status));
+                continue;
+            }
+            status = U_ZERO_ERROR;
+            resultLen = _canonicalize(j, testCases[i].localeID, buffer, sizeof(buffer), &status);
+            if (U_FAILURE(status)) {
+                log_err("FAIL: uloc_%s(%s) => %s, expected U_ZERO_ERROR\n",
+                        label[j], testCases[i].localeID, u_errorName(status));
+                continue;
+            }
+            if(uprv_strcmp(expected, buffer) != 0) {
+                log_err("FAIL: uloc_%s(%s) => \"%s\", expected \"%s\"\n",
+                        label[j], testCases[i].localeID, buffer, expected);
+            } else {
+                log_verbose("Ok: uloc_%s(%s) => \"%s\"\n",
+                            label[j], testCases[i].localeID, buffer);
+            }
+            if (resultLen != (int32_t)strlen(buffer)) {
+                log_err("FAIL: uloc_%s(%s) => len %d, expected len %d\n",
+                        label[j], testCases[i].localeID, resultLen, strlen(buffer));
+            }
+            if (origResultLen != resultLen) {
+                log_err("FAIL: uloc_%s(%s) => preflight len %d != actual len %d\n",
+                        label[j], testCases[i].localeID, origResultLen, resultLen);
+            }
         }
+    }
+}
+
+static void TestDisplayKeywords(void)
+{
+    int32_t i;
+
+    static const struct {
+        const char *localeID;
+        const char *displayLocale;
+        UChar displayKeyword[200];
+    } testCases[] = {
+        {   "ca_ES@currency=ESP",         "de_AT", 
+            {0x0057, 0x00e4, 0x0068, 0x0072, 0x0075, 0x006e, 0x0067, 0x0000}, 
+        },
+        {   "ja_JP@calendar=japanese",         "de", 
+            { 0x004b, 0x0061, 0x006c, 0x0065, 0x006e, 0x0064, 0x0065, 0x0072, 0x0000}
+        },
+        {   "de_DE@collation=traditional",       "de_DE", 
+            {0x0053, 0x006f, 0x0072, 0x0074, 0x0069, 0x0065, 0x0072, 0x0075, 0x006e, 0x0067, 0x0000}
+        },
+    };
+    for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
+        UErrorCode status = U_ZERO_ERROR;
+        const char* keyword =NULL;
+        int32_t keywordLen = 0;
+        int32_t keywordCount = 0;
+        UChar *displayKeyword=NULL;
+        int32_t displayKeywordLen = 0;
+        UEnumeration* keywordEnum = uloc_openKeywords(testCases[i].localeID, &status);
+        for(keywordCount = uenum_count(keywordEnum, &status); keywordCount > 0 ; keywordCount--){
+              if(U_FAILURE(status)){
+                  log_err("uloc_getKeywords failed for locale id: %s with error : %s \n", testCases[i].localeID, u_errorName(status)); 
+                  break;
+              }
+              /* the uenum_next returns NUL terminated string */
+              keyword = uenum_next(keywordEnum, &keywordLen, &status);
+              /* fetch the displayKeyword */
+              displayKeywordLen = uloc_getDisplayKeyword(keyword, testCases[i].displayLocale, displayKeyword, displayKeywordLen, &status);
+              if(status==U_BUFFER_OVERFLOW_ERROR){
+                  status = U_ZERO_ERROR;
+                  displayKeywordLen++; /* for null termination */
+                  displayKeyword = (UChar*) malloc(displayKeywordLen * U_SIZEOF_UCHAR);
+                  displayKeywordLen = uloc_getDisplayKeyword(keyword, testCases[i].displayLocale, displayKeyword, displayKeywordLen, &status);
+                  if(U_FAILURE(status)){
+                      log_err("uloc_getDisplayKeyword filed for keyword : %s in locale id: %s for display locale: %s \n", testCases[i].localeID, keyword, testCases[i].displayLocale, u_errorName(status)); 
+                      break; 
+                  }
+                  if(u_strncmp(displayKeyword, testCases[i].displayKeyword, displayKeywordLen)!=0){
+                      if (status == U_USING_DEFAULT_WARNING) {
+                          log_data_err("uloc_getDisplayKeyword did not get the expected value for keyword : %s in locale id: %s for display locale: %s . Got error: %s. Perhaps you are missing data?\n", testCases[i].localeID, keyword, testCases[i].displayLocale, u_errorName(status));
+                      } else {
+                          log_err("uloc_getDisplayKeyword did not get the expected value for keyword : %s in locale id: %s for display locale: %s \n", testCases[i].localeID, keyword, testCases[i].displayLocale);
+                      }
+                      break; 
+                  }
+              }else{
+                  log_err("uloc_getDisplayKeyword did not return the expected error. Error: %s\n", u_errorName(status));
+              }
+              
+              free(displayKeyword);
 
-        root = ures_openDirect(NULL, locName, &errorCode);
-        if(U_FAILURE(errorCode)) {
-            log_err("Can't open %s\n", locName);
-            continue;
         }
-*/
-    if (locCount <= 1) {
-        log_data_err("At least root needs to be installed\n");
+        uenum_close(keywordEnum);
     }
+}
 
-    root = ures_openDirect(NULL, "root", &errorCode);
-    if(U_FAILURE(errorCode)) {
-        log_data_err("Can't open root\n");
-        return;
-    }
-    completeLoc = ures_openDirect(NULL, "en", &errorCode);
-    if(U_FAILURE(errorCode)) {
-        log_data_err("Can't open en\n");
-        return;
+static void TestDisplayKeywordValues(void){
+    int32_t i;
+
+    static const struct {
+        const char *localeID;
+        const char *displayLocale;
+        UChar displayKeywordValue[500];
+    } testCases[] = {
+        {   "ca_ES@currency=ESP",         "de_AT", 
+            {0x0053, 0x0070, 0x0061, 0x006e, 0x0069, 0x0073, 0x0063, 0x0068, 0x0065, 0x0020, 0x0050, 0x0065, 0x0073, 0x0065, 0x0074, 0x0061, 0x0000}
+        },
+        {   "de_AT@currency=ATS",         "fr_FR", 
+            {0x0073, 0x0063, 0x0068, 0x0069, 0x006c, 0x006c, 0x0069, 0x006e, 0x0067, 0x0020, 0x0061, 0x0075, 0x0074, 0x0072, 0x0069, 0x0063, 0x0068, 0x0069, 0x0065, 0x006e, 0x0000}
+        },
+        {   "de_DE@currency=DEM",         "it", 
+            {0x006d, 0x0061, 0x0072, 0x0063, 0x006f, 0x0020, 0x0074, 0x0065, 0x0064, 0x0065, 0x0073, 0x0063, 0x006f, 0x0000}
+        },
+        {   "el_GR@currency=GRD",         "en",    
+            {0x0047, 0x0072, 0x0065, 0x0065, 0x006b, 0x0020, 0x0044, 0x0072, 0x0061, 0x0063, 0x0068, 0x006d, 0x0061, 0x0000}
+        },
+        {   "eu_ES@currency=ESP",         "it_IT", 
+            {0x0070, 0x0065, 0x0073, 0x0065, 0x0074, 0x0061, 0x0020, 0x0073, 0x0070, 0x0061, 0x0067, 0x006e, 0x006f, 0x006c, 0x0061, 0x0000}
+        },
+        {   "de@collation=phonebook",     "es",    
+            {0x006F, 0x0072, 0x0064, 0x0065, 0x006E, 0x0020, 0x0064, 0x0065, 0x0020, 0x006C, 0x0069, 0x0073, 0x0074, 0x00ED, 0x006E, 0x0020, 0x0074, 0x0065, 0x006C, 0x0065, 0x0066, 0x00F3, 0x006E, 0x0069, 0x0063, 0x006F, 0x0000}
+        },
+
+        { "de_DE@collation=phonebook",  "es", 
+          {0x006F, 0x0072, 0x0064, 0x0065, 0x006E, 0x0020, 0x0064, 0x0065, 0x0020, 0x006C, 0x0069, 0x0073, 0x0074, 0x00ED, 0x006E, 0x0020, 0x0074, 0x0065, 0x006C, 0x0065, 0x0066, 0x00F3, 0x006E, 0x0069, 0x0063, 0x006F, 0x0000}
+        },
+        { "es_ES@collation=traditional","de", 
+          {0x0054, 0x0072, 0x0061, 0x0064, 0x0069, 0x0074, 0x0069, 0x006f, 0x006e, 0x0065, 0x006c, 0x006c, 0x0065, 0x0020, 0x0053, 0x006f, 0x0072, 0x0074, 0x0069, 0x0065, 0x0072, 0x0072, 0x0065, 0x0067, 0x0065, 0x006c, 0x006e, 0x0000}
+        },
+        { "ja_JP@calendar=japanese",    "de", 
+           {0x004a, 0x0061, 0x0070, 0x0061, 0x006e, 0x0069, 0x0073, 0x0063, 0x0068, 0x0065, 0x0072, 0x0020, 0x004b, 0x0061, 0x006c, 0x0065, 0x006e, 0x0064, 0x0065, 0x0072, 0x0000}
+        }, 
+    };
+    for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
+        UErrorCode status = U_ZERO_ERROR;
+        const char* keyword =NULL;
+        int32_t keywordLen = 0;
+        int32_t keywordCount = 0;
+        UChar *displayKeywordValue = NULL;
+        int32_t displayKeywordValueLen = 0;
+        UEnumeration* keywordEnum = uloc_openKeywords(testCases[i].localeID, &status);
+        for(keywordCount = uenum_count(keywordEnum, &status); keywordCount > 0 ; keywordCount--){
+              if(U_FAILURE(status)){
+                  log_err("uloc_getKeywords failed for locale id: %s in display locale: % with error : %s \n", testCases[i].localeID, testCases[i].displayLocale, u_errorName(status)); 
+                  break;
+              }
+              /* the uenum_next returns NUL terminated string */
+              keyword = uenum_next(keywordEnum, &keywordLen, &status);
+              
+              /* fetch the displayKeywordValue */
+              displayKeywordValueLen = uloc_getDisplayKeywordValue(testCases[i].localeID, keyword, testCases[i].displayLocale, displayKeywordValue, displayKeywordValueLen, &status);
+              if(status==U_BUFFER_OVERFLOW_ERROR){
+                  status = U_ZERO_ERROR;
+                  displayKeywordValueLen++; /* for null termination */
+                  displayKeywordValue = (UChar*)malloc(displayKeywordValueLen * U_SIZEOF_UCHAR);
+                  displayKeywordValueLen = uloc_getDisplayKeywordValue(testCases[i].localeID, keyword, testCases[i].displayLocale, displayKeywordValue, displayKeywordValueLen, &status);
+                  if(U_FAILURE(status)){
+                      log_err("uloc_getDisplayKeywordValue failed for keyword : %s in locale id: %s for display locale: %s with error : %s \n", testCases[i].localeID, keyword, testCases[i].displayLocale, u_errorName(status)); 
+                      break; 
+                  }
+                  if(u_strncmp(displayKeywordValue, testCases[i].displayKeywordValue, displayKeywordValueLen)!=0){
+                      if (status == U_USING_DEFAULT_WARNING) {
+                          log_data_err("uloc_getDisplayKeywordValue did not return the expected value keyword : %s in locale id: %s for display locale: %s with error : %s Perhaps you are missing data\n", testCases[i].localeID, keyword, testCases[i].displayLocale, u_errorName(status)); 
+                      } else {
+                          log_err("uloc_getDisplayKeywordValue did not return the expected value keyword : %s in locale id: %s for display locale: %s with error : %s \n", testCases[i].localeID, keyword, testCases[i].displayLocale, u_errorName(status)); 
+                      }
+                      break;   
+                  }
+              }else{
+                  log_err("uloc_getDisplayKeywordValue did not return the expected error. Error: %s\n", u_errorName(status));
+              }
+              free(displayKeywordValue);
+        }
+        uenum_close(keywordEnum);
     }
-    for (locIndex = 0; locIndex < locCount; locIndex++) {
-        errorCode=U_ZERO_ERROR;
-        currLoc = uloc_getAvailable(locIndex);
-        currentLocale = ures_open(NULL, currLoc, &errorCode);
-        if(errorCode != U_ZERO_ERROR) {
-            if(U_SUCCESS(errorCode)) {
-                /* It's installed, but there is no data.
-                   It's installed for the g18n white paper [grhoten] */
-                log_err("ERROR: Locale %-5s not installed, and it should be!\n",
-                    uloc_getAvailable(locIndex));
-            } else {
-                log_err("%%%%%%% Unexpected error %d in %s %%%%%%%",
-                    u_errorName(errorCode),
-                    uloc_getAvailable(locIndex));
-            }
-            ures_close(currentLocale);
-            continue;
+    {   
+        /* test a multiple keywords */
+        UErrorCode status = U_ZERO_ERROR;
+        const char* keyword =NULL;
+        int32_t keywordLen = 0;
+        int32_t keywordCount = 0;
+        const char* localeID = "es@collation=phonebook;calendar=buddhist;currency=DEM";
+        const char* displayLocale = "de";
+        static const UChar expected[][50] = {
+            {0x0042, 0x0075, 0x0064, 0x0064, 0x0068, 0x0069, 0x0073, 0x0074, 0x0069, 0x0073, 0x0063, 0x0068, 0x0065, 0x0072, 0x0020, 0x004b, 0x0061, 0x006c, 0x0065, 0x006e, 0x0064, 0x0065, 0x0072, 0x0000},
+
+            {0x0054, 0x0065, 0x006c, 0x0065, 0x0066, 0x006f, 0x006e, 0x0062, 0x0075, 0x0063, 0x0068, 0x002d, 0x0053, 0x006f, 0x0072, 0x0074, 0x0069, 0x0065, 0x0072, 0x0075, 0x006e, 0x0067, 0x0000},
+            {0x0044, 0x0065, 0x0075, 0x0074, 0x0073, 0x0063, 0x0068, 0x0065, 0x0020, 0x004d, 0x0061, 0x0072, 0x006b, 0x0000},
+        };
+
+        UEnumeration* keywordEnum = uloc_openKeywords(localeID, &status);
+
+        for(keywordCount = 0; keywordCount < uenum_count(keywordEnum, &status) ; keywordCount++){
+              UChar *displayKeywordValue = NULL;
+              int32_t displayKeywordValueLen = 0;
+              if(U_FAILURE(status)){
+                  log_err("uloc_getKeywords failed for locale id: %s in display locale: % with error : %s \n", localeID, displayLocale, u_errorName(status)); 
+                  break;
+              }
+              /* the uenum_next returns NUL terminated string */
+              keyword = uenum_next(keywordEnum, &keywordLen, &status);
+              
+              /* fetch the displayKeywordValue */
+              displayKeywordValueLen = uloc_getDisplayKeywordValue(localeID, keyword, displayLocale, displayKeywordValue, displayKeywordValueLen, &status);
+              if(status==U_BUFFER_OVERFLOW_ERROR){
+                  status = U_ZERO_ERROR;
+                  displayKeywordValueLen++; /* for null termination */
+                  displayKeywordValue = (UChar*)malloc(displayKeywordValueLen * U_SIZEOF_UCHAR);
+                  displayKeywordValueLen = uloc_getDisplayKeywordValue(localeID, keyword, displayLocale, displayKeywordValue, displayKeywordValueLen, &status);
+                  if(U_FAILURE(status)){
+                      log_err("uloc_getDisplayKeywordValue failed for keyword : %s in locale id: %s for display locale: %s with error : %s \n", localeID, keyword, displayLocale, u_errorName(status)); 
+                      break; 
+                  }
+                  if(u_strncmp(displayKeywordValue, expected[keywordCount], displayKeywordValueLen)!=0){
+                      if (status == U_USING_DEFAULT_WARNING) {
+                          log_data_err("uloc_getDisplayKeywordValue did not return the expected value keyword : %s in locale id: %s for display locale: %s  got error: %s. Perhaps you are missing data?\n", localeID, keyword, displayLocale, u_errorName(status));
+                      } else {
+                          log_err("uloc_getDisplayKeywordValue did not return the expected value keyword : %s in locale id: %s for display locale: %s \n", localeID, keyword, displayLocale);
+                      }
+                      break;   
+                  }
+              }else{
+                  log_err("uloc_getDisplayKeywordValue did not return the expected error. Error: %s\n", u_errorName(status));
+              }
+              free(displayKeywordValue);
         }
-        ures_getStringByKey(currentLocale, "Version", NULL, &errorCode);
-        if(errorCode != U_ZERO_ERROR) {
-            log_err("No version information is available for locale %s, and it should be!\n",
-                currLoc);
+        uenum_close(keywordEnum);
+    
+    }
+    {
+        /* Test non existent keywords */
+        UErrorCode status = U_ZERO_ERROR;
+        const char* localeID = "es";
+        const char* displayLocale = "de";
+        UChar *displayKeywordValue = NULL;
+        int32_t displayKeywordValueLen = 0;
+        
+        /* fetch the displayKeywordValue */
+        displayKeywordValueLen = uloc_getDisplayKeywordValue(localeID, "calendar", displayLocale, displayKeywordValue, displayKeywordValueLen, &status);
+        if(U_FAILURE(status)) {
+          log_err("uloc_getDisplaykeywordValue returned error status %s\n", u_errorName(status));
+        } else if(displayKeywordValueLen != 0) {
+          log_err("uloc_getDisplaykeywordValue returned %d should be 0 \n", displayKeywordValueLen);
         }
-        else if (ures_getStringByKey(currentLocale, "Version", NULL, &errorCode)[0] == (UChar)(0x78)) {
-            log_verbose("WARNING: The locale %s is experimental! It shouldn't be listed as an installed locale.\n",
-                currLoc);
+    }
+}
+
+
+static void TestGetBaseName(void) {
+    static const struct {
+        const char *localeID;
+        const char *baseName;
+    } testCases[] = {
+        { "de_DE@  C o ll A t i o n   = Phonebook   ", "de_DE" },
+        { "de@currency = euro; CoLLaTion   = PHONEBOOk", "de" },
+        { "ja@calendar = buddhist", "ja" }
+    };
+
+    int32_t i = 0, baseNameLen = 0;
+    char baseName[256];
+    UErrorCode status = U_ZERO_ERROR;
+
+    for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
+        baseNameLen = uloc_getBaseName(testCases[i].localeID, baseName, 256, &status);
+        (void)baseNameLen;    /* Suppress set but not used warning. */
+        if(strcmp(testCases[i].baseName, baseName)) {
+            log_err("For locale \"%s\" expected baseName \"%s\", but got \"%s\"\n",
+                testCases[i].localeID, testCases[i].baseName, baseName);
+            return;
         }
-        TestKeyInRootRecursive(root, "root", currentLocale, currLoc);
+    }
+}
 
-        completeSubtable = ures_getByKey(completeLoc, "Currencies", NULL, &errorCode);
-        subtable = ures_getByKey(currentLocale, "Currencies", NULL, &errorCode);
-        TestKeyInRootRecursive(completeSubtable, "en", subtable, currLoc);
+static void TestTrailingNull(void) {
+  const char* localeId = "zh_Hans";
+  UChar buffer[128]; /* sufficient for this test */
+  int32_t len;
+  UErrorCode status = U_ZERO_ERROR;
+  int i;
 
-#ifdef WIN32
-        testLCID(currentLocale, currLoc);
-#endif
+  len = uloc_getDisplayName(localeId, localeId, buffer, 128, &status);
+  if (len > 128) {
+    log_err("buffer too small");
+    return;
+  }
 
-        ures_close(completeSubtable);
-        ures_close(subtable);
-        ures_close(currentLocale);
+  for (i = 0; i < len; ++i) {
+    if (buffer[i] == 0) {
+      log_err("name contained null");
+      return;
     }
+  }
+}
 
-    ures_close(root);
-    ures_close(completeLoc);
+/* Jitterbug 4115 */
+static void TestDisplayNameWarning(void) {
+    UChar name[256];
+    int32_t size;
+    UErrorCode status = U_ZERO_ERROR;
+    
+    size = uloc_getDisplayLanguage("qqq", "kl", name, UPRV_LENGTHOF(name), &status);
+    (void)size;    /* Suppress set but not used warning. */
+    if (status != U_USING_DEFAULT_WARNING) {
+        log_err("For language \"qqq\" in locale \"kl\", expecting U_USING_DEFAULT_WARNING, but got %s\n",
+            u_errorName(status));
+    }
 }
 
-static void
-compareArrays(const char *keyName,
-              UResourceBundle *fromArray, const char *fromLocale,
-              UResourceBundle *toArray, const char *toLocale,
-              int32_t start, int32_t end)
-{
-    int32_t fromSize = ures_getSize(fromArray);
-    int32_t toSize = ures_getSize(fromArray);
-    int32_t idx;
-    UErrorCode errorCode = U_ZERO_ERROR;
 
-    if (fromSize > toSize) {
-        fromSize = toSize;
-        log_err("Arrays are different size from \"%s\" to \"%s\"\n",
-                fromLocale,
-                toLocale);
+/**
+ * Compare two locale IDs.  If they are equal, return 0.  If `string'
+ * starts with `prefix' plus an additional element, that is, string ==
+ * prefix + '_' + x, then return 1.  Otherwise return a value < 0.
+ */
+static UBool _loccmp(const char* string, const char* prefix) {
+    int32_t slen = (int32_t)uprv_strlen(string),
+            plen = (int32_t)uprv_strlen(prefix);
+    int32_t c = uprv_strncmp(string, prefix, plen);
+    /* 'root' is less than everything */
+    if (uprv_strcmp(prefix, "root") == 0) {
+        return (uprv_strcmp(string, "root") == 0) ? 0 : 1;
     }
+    if (c) return -1; /* mismatch */
+    if (slen == plen) return 0;
+    if (string[plen] == '_') return 1;
+    return -2; /* false match, e.g. "en_USX" cmp "en_US" */
+}
 
-    for (idx = start; idx <= end; idx++) {
-        const UChar *fromBundleStr = ures_getStringByIndex(fromArray, idx, NULL, &errorCode);
-        const UChar *toBundleStr = ures_getStringByIndex(toArray, idx, NULL, &errorCode);
-        if (fromBundleStr && toBundleStr && u_strcmp(fromBundleStr, toBundleStr) != 0)
-        {
-            log_err("Difference for %s at index %d from %s= \"%s\" to %s= \"%s\"\n",
-                    keyName,
-                    idx,
-                    fromLocale,
-                    austrdup(fromBundleStr),
-                    toLocale,
-                    austrdup(toBundleStr));
-        }
+static void _checklocs(const char* label,
+                       const char* req,
+                       const char* valid,
+                       const char* actual) {
+    /* We want the valid to be strictly > the bogus requested locale,
+       and the valid to be >= the actual. */
+    if (_loccmp(req, valid) > 0 &&
+        _loccmp(valid, actual) >= 0) {
+        log_verbose("%s; req=%s, valid=%s, actual=%s\n",
+                    label, req, valid, actual);
+    } else {
+        log_err("FAIL: %s; req=%s, valid=%s, actual=%s\n",
+                label, req, valid, actual);
     }
 }
 
-static void
-compareConsistentCountryInfo(const char *fromLocale, const char *toLocale) {
-    UErrorCode errorCode = U_ZERO_ERROR;
-    UResourceBundle *fromDateTimeElements, *toDateTimeElements;
-    UResourceBundle *fromArray, *toArray;
-    UResourceBundle *fromLocaleBund = ures_open(NULL, fromLocale, &errorCode);
-    UResourceBundle *toLocaleBund = ures_open(NULL, toLocale, &errorCode);
+static void TestGetLocale(void) {
+    UErrorCode ec = U_ZERO_ERROR;
+    UParseError pe;
+    UChar EMPTY[1] = {0};
 
-    if(U_FAILURE(errorCode)) {
-        log_err("Can't open resource bundle %s or %s - %s\n", fromLocale, toLocale, u_errorName(errorCode));
-        return;
+    /* === udat === */
+#if !UCONFIG_NO_FORMATTING
+    {
+        UDateFormat *obj;
+        const char *req = "en_US_REDWOODSHORES", *valid, *actual;
+        obj = udat_open(UDAT_DEFAULT, UDAT_DEFAULT,
+                        req,
+                        NULL, 0,
+                        NULL, 0, &ec);
+        if (U_FAILURE(ec)) {
+            log_data_err("udat_open failed.Error %s\n", u_errorName(ec));
+            return;
+        }
+        valid = udat_getLocaleByType(obj, ULOC_VALID_LOCALE, &ec);
+        actual = udat_getLocaleByType(obj, ULOC_ACTUAL_LOCALE, &ec);
+        if (U_FAILURE(ec)) {
+            log_err("udat_getLocaleByType() failed\n");
+            return;
+        }
+        _checklocs("udat", req, valid, actual);
+        udat_close(obj);
     }
+#endif
 
-    fromDateTimeElements = ures_getByKey(fromLocaleBund, "DateTimeElements", NULL, &errorCode);
-    toDateTimeElements = ures_getByKey(toLocaleBund, "DateTimeElements", NULL, &errorCode);
-    if (strcmp(fromLocale, "ar_IN") != 0)
+    /* === ucal === */
+#if !UCONFIG_NO_FORMATTING
     {
-        int32_t fromSize;
-        int32_t toSize;
-        int32_t idx;
-        const int32_t *fromBundleArr = ures_getIntVector(fromDateTimeElements, &fromSize, &errorCode);
-        const int32_t *toBundleArr = ures_getIntVector(toDateTimeElements, &toSize, &errorCode);
-
-        if (fromSize > toSize) {
-            fromSize = toSize;
-            log_err("Arrays are different size with key \"DateTimeElements\" from \"%s\" to \"%s\"\n",
-                    fromLocale,
-                    toLocale);
-        }
-
-        for (idx = 0; idx < fromSize; idx++) {
-            if (fromBundleArr[idx] != toBundleArr[idx]) {
-                log_err("Difference with key \"DateTimeElements\" at index %d from \"%s\" to \"%s\"\n",
-                        idx,
-                        fromLocale,
-                        toLocale);
-            }
+        UCalendar *obj;
+        const char *req = "fr_FR_PROVENCAL", *valid, *actual;
+        obj = ucal_open(NULL, 0,
+                        req,
+                        UCAL_GREGORIAN,
+                        &ec);
+        if (U_FAILURE(ec)) {
+            log_err("ucal_open failed with error: %s\n", u_errorName(ec));
+            return;
         }
+        valid = ucal_getLocaleByType(obj, ULOC_VALID_LOCALE, &ec);
+        actual = ucal_getLocaleByType(obj, ULOC_ACTUAL_LOCALE, &ec);
+        if (U_FAILURE(ec)) {
+            log_err("ucal_getLocaleByType() failed\n");
+            return;
+        }
+        _checklocs("ucal", req, valid, actual);
+        ucal_close(obj);
     }
-    ures_close(fromDateTimeElements);
-    ures_close(toDateTimeElements);
+#endif
 
-    fromArray = ures_getByKey(fromLocaleBund, "CurrencyElements", NULL, &errorCode);
-    toArray = ures_getByKey(toLocaleBund, "CurrencyElements", NULL, &errorCode);
-    if (strcmp(fromLocale, "en_CA") != 0)
+    /* === unum === */
+#if !UCONFIG_NO_FORMATTING
     {
-        /* The first one is probably localized. */
-        compareArrays("CurrencyElements", fromArray, fromLocale, toArray, toLocale, 1, 2);
+        UNumberFormat *obj;
+        const char *req = "zh_Hant_TW_TAINAN", *valid, *actual;
+        obj = unum_open(UNUM_DECIMAL,
+                        NULL, 0,
+                        req,
+                        &pe, &ec);
+        if (U_FAILURE(ec)) {
+            log_err("unum_open failed\n");
+            return;
+        }
+        valid = unum_getLocaleByType(obj, ULOC_VALID_LOCALE, &ec);
+        actual = unum_getLocaleByType(obj, ULOC_ACTUAL_LOCALE, &ec);
+        if (U_FAILURE(ec)) {
+            log_err("unum_getLocaleByType() failed\n");
+            return;
+        }
+        _checklocs("unum", req, valid, actual);
+        unum_close(obj);
     }
-    ures_close(fromArray);
-    ures_close(toArray);
+#endif
 
-    fromArray = ures_getByKey(fromLocaleBund, "NumberPatterns", NULL, &errorCode);
-    toArray = ures_getByKey(toLocaleBund, "NumberPatterns", NULL, &errorCode);
-    if (strcmp(fromLocale, "en_CA") != 0)
+    /* === umsg === */
+#if 0
+    /* commented out by weiv 01/12/2005. umsg_getLocaleByType is to be removed */
+#if !UCONFIG_NO_FORMATTING
     {
-        compareArrays("NumberPatterns", fromArray, fromLocale, toArray, toLocale, 0, 3);
+        UMessageFormat *obj;
+        const char *req = "ja_JP_TAKAYAMA", *valid, *actual;
+        UBool test;
+        obj = umsg_open(EMPTY, 0,
+                        req,
+                        &pe, &ec);
+        if (U_FAILURE(ec)) {
+            log_err("umsg_open failed\n");
+            return;
+        }
+        valid = umsg_getLocaleByType(obj, ULOC_VALID_LOCALE, &ec);
+        actual = umsg_getLocaleByType(obj, ULOC_ACTUAL_LOCALE, &ec);
+        if (U_FAILURE(ec)) {
+            log_err("umsg_getLocaleByType() failed\n");
+            return;
+        }
+        /* We want the valid to be strictly > the bogus requested locale,
+           and the valid to be >= the actual. */
+        /* TODO MessageFormat is currently just storing the locale it is given.
+           As a result, it will return whatever it was given, even if the
+           locale is invalid. */
+        test = (_cmpversion("3.2") <= 0) ?
+            /* Here is the weakened test for 3.0: */
+            (_loccmp(req, valid) >= 0) :
+            /* Here is what the test line SHOULD be: */
+            (_loccmp(req, valid) > 0);
+
+        if (test &&
+            _loccmp(valid, actual) >= 0) {
+            log_verbose("umsg; req=%s, valid=%s, actual=%s\n", req, valid, actual);
+        } else {
+            log_err("FAIL: umsg; req=%s, valid=%s, actual=%s\n", req, valid, actual);
+        }
+        umsg_close(obj);
     }
-    ures_close(fromArray);
-    ures_close(toArray);
+#endif
+#endif
 
-    /* Difficult to test properly */
-/*
-    fromArray = ures_getByKey(fromLocaleBund, "DateTimePatterns", NULL, &errorCode);
-    toArray = ures_getByKey(toLocaleBund, "DateTimePatterns", NULL, &errorCode);
+    /* === ubrk === */
+#if !UCONFIG_NO_BREAK_ITERATION
     {
-        compareArrays("DateTimePatterns", fromArray, fromLocale, toArray, toLocale);
+        UBreakIterator *obj;
+        const char *req = "ar_KW_ABDALI", *valid, *actual;
+        obj = ubrk_open(UBRK_WORD,
+                        req,
+                        EMPTY,
+                        0,
+                        &ec);
+        if (U_FAILURE(ec)) {
+            log_err("ubrk_open failed. Error: %s \n", u_errorName(ec));
+            return;
+        }
+        valid = ubrk_getLocaleByType(obj, ULOC_VALID_LOCALE, &ec);
+        actual = ubrk_getLocaleByType(obj, ULOC_ACTUAL_LOCALE, &ec);
+        if (U_FAILURE(ec)) {
+            log_err("ubrk_getLocaleByType() failed\n");
+            return;
+        }
+        _checklocs("ubrk", req, valid, actual);
+        ubrk_close(obj);
     }
-    ures_close(fromArray);
-    ures_close(toArray);*/
+#endif
 
-    fromArray = ures_getByKey(fromLocaleBund, "NumberElements", NULL, &errorCode);
-    toArray = ures_getByKey(toLocaleBund, "NumberElements", NULL, &errorCode);
-    if (strcmp(fromLocale, "en_CA") != 0)
+    /* === ucol === */
+#if !UCONFIG_NO_COLLATION
     {
-        compareArrays("NumberElements", fromArray, fromLocale, toArray, toLocale, 0, 3);
-        /* Index 4 is a script based 0 */
-        compareArrays("NumberElements", fromArray, fromLocale, toArray, toLocale, 5, 10);
+        UCollator *obj;
+        const char *req = "es_AR_BUENOSAIRES", *valid, *actual;
+        obj = ucol_open(req, &ec);
+        if (U_FAILURE(ec)) {
+            log_err("ucol_open failed - %s\n", u_errorName(ec));
+            return;
+        }
+        valid = ucol_getLocaleByType(obj, ULOC_VALID_LOCALE, &ec);
+        actual = ucol_getLocaleByType(obj, ULOC_ACTUAL_LOCALE, &ec);
+        if (U_FAILURE(ec)) {
+            log_err("ucol_getLocaleByType() failed\n");
+            return;
+        }
+        _checklocs("ucol", req, valid, actual);
+        ucol_close(obj);
     }
-    ures_close(fromArray);
-    ures_close(toArray);
-
-    ures_close(fromLocaleBund);
-    ures_close(toLocaleBund);
+#endif
 }
+static void TestEnglishExemplarCharacters(void) {
+    UErrorCode status = U_ZERO_ERROR;
+    int i;
+    USet *exSet = NULL;
+    UChar testChars[] = {
+        0x61,   /* standard */
+        0xE1,   /* auxiliary */
+        0x41,   /* index */
+        0x2D    /* punctuation */
+    };
+    ULocaleData *uld = ulocdata_open("en", &status);
+    if (U_FAILURE(status)) {
+        log_data_err("ulocdata_open() failed : %s - (Are you missing data?)\n", u_errorName(status));
+        return;
+    }
 
-static void
-TestConsistentCountryInfo(void) {
-/*    UResourceBundle *fromLocale, *toLocale;*/
-    int32_t locCount = uloc_countAvailable();
-    int32_t fromLocIndex, toLocIndex;
+    for (i = 0; i < ULOCDATA_ES_COUNT; i++) {
+        exSet = ulocdata_getExemplarSet(uld, exSet, 0, (ULocaleDataExemplarSetType)i, &status);
+        if (U_FAILURE(status)) {
+            log_err_status(status, "ulocdata_getExemplarSet() for type %d failed\n", i);
+            status = U_ZERO_ERROR;
+            continue;
+        }
+        if (!uset_contains(exSet, (UChar32)testChars[i])) {
+            log_err("Character U+%04X is not included in exemplar type %d\n", testChars[i], i);
+        }
+    }
 
-    int32_t fromCountryLen, toCountryLen;
-    char fromCountry[ULOC_FULLNAME_CAPACITY], toCountry[ULOC_FULLNAME_CAPACITY];
+    uset_close(exSet);
+    ulocdata_close(uld);
+}
 
-    int32_t fromVariantLen, toVariantLen;
-    char fromVariant[ULOC_FULLNAME_CAPACITY], toVariant[ULOC_FULLNAME_CAPACITY];
+static void TestNonexistentLanguageExemplars(void) {
+    /* JB 4068 - Nonexistent language */
+    UErrorCode ec = U_ZERO_ERROR;
+    ULocaleData *uld = ulocdata_open("qqq",&ec);
+    if (ec != U_USING_DEFAULT_WARNING) {
+        log_err_status(ec, "Exemplar set for \"qqq\", expecting U_USING_DEFAULT_WARNING, but got %s\n",
+            u_errorName(ec));
+    }
+    uset_close(ulocdata_getExemplarSet(uld, NULL, 0, ULOCDATA_ES_STANDARD, &ec));
+    ulocdata_close(uld);
+}
 
-    UErrorCode errorCode = U_ZERO_ERROR;
+static void TestLocDataErrorCodeChaining(void) {
+    UErrorCode ec = U_USELESS_COLLATOR_ERROR;
+    ulocdata_open(NULL, &ec);
+    ulocdata_getExemplarSet(NULL, NULL, 0, ULOCDATA_ES_STANDARD, &ec);
+    ulocdata_getDelimiter(NULL, ULOCDATA_DELIMITER_COUNT, NULL, -1, &ec);
+    ulocdata_getMeasurementSystem(NULL, &ec);
+    ulocdata_getPaperSize(NULL, NULL, NULL, &ec);
+    if (ec != U_USELESS_COLLATOR_ERROR) {
+        log_err("ulocdata API changed the error code to %s\n", u_errorName(ec));
+    }
+}
 
-    for (fromLocIndex = 0; fromLocIndex < locCount; fromLocIndex++) {
-        const char *fromLocale = uloc_getAvailable(fromLocIndex);
+typedef struct {
+    const char*        locale;
+    UMeasurementSystem measureSys;
+} LocToMeasureSys;
+
+static const LocToMeasureSys locToMeasures[] = {
+    { "fr_FR",            UMS_SI },
+    { "en",               UMS_US },
+    { "en_GB",            UMS_UK },
+    { "fr_FR@rg=GBZZZZ",  UMS_UK },
+    { "en@rg=frzzzz",     UMS_SI },
+    { "en_GB@rg=USZZZZ",  UMS_US },
+    { NULL, (UMeasurementSystem)0 } /* terminator */
+};
 
-        errorCode=U_ZERO_ERROR;
-        fromCountryLen = uloc_getCountry(fromLocale, fromCountry, ULOC_FULLNAME_CAPACITY, &errorCode);
-        if (fromCountryLen <= 0) {
-            /* Ignore countryless locales */
-            continue;
-        }
-        fromVariantLen = uloc_getVariant(fromLocale, fromVariant, ULOC_FULLNAME_CAPACITY, &errorCode);
-        if (fromVariantLen > 0) {
-            /* Most variants are ignorable like PREEURO, or collation variants. */
-            continue;
+static void TestLocDataWithRgTag(void) {
+    const  LocToMeasureSys* locToMeasurePtr = locToMeasures;
+    for (; locToMeasurePtr->locale != NULL; locToMeasurePtr++) {
+        UErrorCode status = U_ZERO_ERROR;
+        UMeasurementSystem measureSys = ulocdata_getMeasurementSystem(locToMeasurePtr->locale, &status);
+        if (U_FAILURE(status)) {
+            log_data_err("ulocdata_getMeasurementSystem(\"%s\", ...) failed: %s - Are you missing data?\n",
+                        locToMeasurePtr->locale, u_errorName(status));
+        } else if (measureSys != locToMeasurePtr->measureSys) {
+            log_err("ulocdata_getMeasurementSystem(\"%s\", ...), expected %d, got %d\n",
+                        locToMeasurePtr->locale, (int) locToMeasurePtr->measureSys, (int)measureSys);
         }
-        /* Start comparing only after the current index.
-           Previous loop should have already compared fromLocIndex.
-        */
-        for (toLocIndex = fromLocIndex + 1; toLocIndex < locCount; toLocIndex++) {
-            const char *toLocale = uloc_getAvailable(toLocIndex);
+    }
+}
 
-            toCountryLen = uloc_getCountry(toLocale, toCountry, ULOC_FULLNAME_CAPACITY, &errorCode);
-            if(U_FAILURE(errorCode)) {
-                log_err("Unknown failure fromLocale=%s toLocale=%s errorCode=%s\n",
-                    fromLocale, toLocale, u_errorName(errorCode));
-                continue;
-            }
+static void TestLanguageExemplarsFallbacks(void) {
+    /* Test that en_US fallsback, but en doesn't fallback. */
+    UErrorCode ec = U_ZERO_ERROR;
+    ULocaleData *uld = ulocdata_open("en_US",&ec);
+    uset_close(ulocdata_getExemplarSet(uld, NULL, 0, ULOCDATA_ES_STANDARD, &ec));
+    if (ec != U_USING_FALLBACK_WARNING) {
+        log_err_status(ec, "Exemplar set for \"en_US\", expecting U_USING_FALLBACK_WARNING, but got %s\n",
+            u_errorName(ec));
+    }
+    ulocdata_close(uld);
+    ec = U_ZERO_ERROR;
+    uld = ulocdata_open("en",&ec);
+    uset_close(ulocdata_getExemplarSet(uld, NULL, 0, ULOCDATA_ES_STANDARD, &ec));
+    if (ec != U_ZERO_ERROR) {
+        log_err_status(ec, "Exemplar set for \"en\", expecting U_ZERO_ERROR, but got %s\n",
+            u_errorName(ec));
+    }
+    ulocdata_close(uld);
+}
 
-            if (toCountryLen <= 0) {
-                /* Ignore countryless locales */
-                continue;
-            }
-            toVariantLen = uloc_getVariant(toLocale, toVariant, ULOC_FULLNAME_CAPACITY, &errorCode);
-            if (toVariantLen > 0) {
-                /* Most variants are ignorable like PREEURO, or collation variants. */
-                /* They're a variant for a reason. */
-                continue;
+static const char *acceptResult(UAcceptResult uar) {
+    return  udbg_enumName(UDBG_UAcceptResult, uar);
+}
+
+static void TestAcceptLanguage(void) {
+    UErrorCode status = U_ZERO_ERROR;
+    UAcceptResult outResult;
+    UEnumeration *available;
+    char tmp[200];
+    int i;
+    int32_t rc = 0;
+
+    struct { 
+        int32_t httpSet;       /**< Which of http[] should be used? */
+        const char *icuSet;    /**< ? */
+        const char *expect;    /**< The expected locale result */
+        UAcceptResult res;     /**< The expected error code */
+        UErrorCode expectStatus; /**< expected status */
+    } tests[] = { 
+        /*0*/{ 0, NULL, "mt_MT", ULOC_ACCEPT_VALID, U_ZERO_ERROR},
+        /*1*/{ 1, NULL, "en", ULOC_ACCEPT_VALID, U_ZERO_ERROR},
+        /*2*/{ 2, NULL, "en", ULOC_ACCEPT_FALLBACK, U_ZERO_ERROR},
+        /*3*/{ 3, NULL, "", ULOC_ACCEPT_FAILED, U_ZERO_ERROR},
+        /*4*/{ 4, NULL, "es", ULOC_ACCEPT_VALID, U_ZERO_ERROR},
+        /*5*/{ 5, NULL, "en", ULOC_ACCEPT_VALID, U_ZERO_ERROR},  /* XF */
+        /*6*/{ 6, NULL, "ja", ULOC_ACCEPT_FALLBACK, U_ZERO_ERROR},  /* XF */
+        /*7*/{ 7, NULL, "zh", ULOC_ACCEPT_FALLBACK, U_ZERO_ERROR},  /* XF */
+        /*8*/{ 8, NULL, "", ULOC_ACCEPT_FAILED, U_ZERO_ERROR },  /*  */
+        /*9*/{ 9, NULL, "", ULOC_ACCEPT_FAILED, U_ZERO_ERROR },  /*  */
+       /*10*/{10, NULL, "", ULOC_ACCEPT_FAILED, U_BUFFER_OVERFLOW_ERROR },  /*  */
+       /*11*/{11, NULL, "", ULOC_ACCEPT_FAILED, U_BUFFER_OVERFLOW_ERROR },  /*  */
+    };
+    const int32_t numTests = UPRV_LENGTHOF(tests);
+    static const char *http[] = {
+        /*0*/ "mt-mt, ja;q=0.76, en-us;q=0.95, en;q=0.92, en-gb;q=0.89, fr;q=0.87, iu-ca;q=0.84, iu;q=0.82, ja-jp;q=0.79, mt;q=0.97, de-de;q=0.74, de;q=0.71, es;q=0.68, it-it;q=0.66, it;q=0.63, vi-vn;q=0.61, vi;q=0.58, nl-nl;q=0.55, nl;q=0.53, th-th-traditional;q=.01",
+        /*1*/ "ja;q=0.5, en;q=0.8, tlh",
+        /*2*/ "en-wf, de-lx;q=0.8",
+        /*3*/ "mga-ie;q=0.9, tlh",
+        /*4*/ "xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, "
+              "xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, "
+              "xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, "
+              "xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, "
+              "xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, "
+              "xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, "
+              "xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xx-yy;q=.1, "
+              "es",
+        /*5*/ "zh-xx;q=0.9, en;q=0.6",
+        /*6*/ "ja-JA",
+        /*7*/ "zh-xx;q=0.9",
+       /*08*/ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+              "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+              "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+              "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", // 156
+       /*09*/ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+              "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+              "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+              "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB", // 157 (this hits U_STRING_NOT_TERMINATED_WARNING )
+       /*10*/ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+              "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+              "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+              "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABC", // 158
+       /*11*/ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+              "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+              "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+              "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", // 163 bytes
+    };
+
+    for(i=0;i<numTests;i++) {
+        outResult = -3;
+        status=U_ZERO_ERROR;
+        log_verbose("test #%d: http[%s], ICU[%s], expect %s, %s\n", 
+            i, http[tests[i].httpSet], tests[i].icuSet, tests[i].expect, acceptResult(tests[i].res));
+
+        available = ures_openAvailableLocales(tests[i].icuSet, &status);
+        tmp[0]=0;
+        rc = uloc_acceptLanguageFromHTTP(tmp, 199, &outResult, http[tests[i].httpSet], available, &status);
+        (void)rc;    /* Suppress set but not used warning. */
+        uenum_close(available);
+        log_verbose(" got %s, %s [%s]\n", tmp[0]?tmp:"(EMPTY)", acceptResult(outResult), u_errorName(status));
+        if(status != tests[i].expectStatus) {
+          log_err_status(status, "FAIL: expected status %s but got %s\n", u_errorName(tests[i].expectStatus), u_errorName(status));
+        } else if(U_SUCCESS(tests[i].expectStatus)) {
+            /* don't check content if expected failure */
+            if(outResult != tests[i].res) {
+            log_err_status(status, "FAIL: #%d: expected outResult of %s but got %s\n", i, 
+                acceptResult( tests[i].res), 
+                acceptResult( outResult));
+            log_info("test #%d: http[%s], ICU[%s], expect %s, %s\n", 
+                i, http[tests[i].httpSet], tests[i].icuSet, tests[i].expect,acceptResult(tests[i].res));
             }
-            if (strcmp(fromCountry, toCountry) == 0) {
-                log_verbose("comparing fromLocale=%s toLocale=%s\n",
-                    fromLocale, toLocale);
-                compareConsistentCountryInfo(fromLocale, toLocale);
+            if((outResult>0)&&uprv_strcmp(tmp, tests[i].expect)) {
+              log_err_status(status, "FAIL: #%d: expected %s but got %s\n", i, tests[i].expect, tmp);
+              log_info("test #%d: http[%s], ICU[%s], expect %s, %s\n", 
+                       i, http[tests[i].httpSet], tests[i].icuSet, tests[i].expect, acceptResult(tests[i].res));
             }
         }
     }
 }
 
-static int32_t
-findStringSetMismatch(const UChar *string, int32_t langSize,
-                      const UChar *exemplarCharacters, int32_t exemplarLen,
-                      UBool ignoreNumbers) {
-    UErrorCode errorCode = U_ZERO_ERROR;
-    USet *exemplarSet = uset_openPatternOptions(exemplarCharacters, exemplarLen, USET_CASE_INSENSITIVE, &errorCode);
-    int32_t strIdx;
-    if (U_FAILURE(errorCode)) {
-        log_err("error uset_openPattern returned %s\n", u_errorName(errorCode));
-        return -1;
+static const char* LOCALE_ALIAS[][2] = {
+    {"in", "id"},
+    {"in_ID", "id_ID"},
+    {"iw", "he"},
+    {"iw_IL", "he_IL"},
+    {"ji", "yi"},
+    {"en_BU", "en_MM"},
+    {"en_DY", "en_BJ"},
+    {"en_HV", "en_BF"},
+    {"en_NH", "en_VU"},
+    {"en_RH", "en_ZW"},
+    {"en_TP", "en_TL"},
+    {"en_ZR", "en_CD"}
+};
+static UBool isLocaleAvailable(UResourceBundle* resIndex, const char* loc){
+    UErrorCode status = U_ZERO_ERROR;
+    int32_t len = 0;
+    ures_getStringByKey(resIndex, loc,&len, &status);
+    if(U_FAILURE(status)){
+        return FALSE; 
     }
+    return TRUE;
+}
 
-    for (strIdx = 0; strIdx < langSize; strIdx++) {
-        if (!uset_contains(exemplarSet, string[strIdx])
-            && string[strIdx] != 0x0020 && string[strIdx] != 0x002e && string[strIdx] != 0x002c && string[strIdx] != 0x002d && string[strIdx] != 0x0027) {
-            if (!ignoreNumbers || (ignoreNumbers && (string[strIdx] < 0x30 || string[strIdx] > 0x39))) {
-                return strIdx;
-            }
-        }
+static void TestCalendar() {
+#if !UCONFIG_NO_FORMATTING
+    int i;
+    UErrorCode status = U_ZERO_ERROR;
+    UResourceBundle *resIndex = ures_open(NULL,"res_index", &status);
+    if(U_FAILURE(status)){
+        log_err_status(status, "Could not open res_index.res. Exiting. Error: %s\n", u_errorName(status));
+        return;
     }
-    uset_close(exemplarSet);
-    return -1;
-}
+    for (i=0; i<UPRV_LENGTHOF(LOCALE_ALIAS); i++) {
+        const char* oldLoc = LOCALE_ALIAS[i][0];
+        const char* newLoc = LOCALE_ALIAS[i][1];
+        UCalendar* c1 = NULL;
+        UCalendar* c2 = NULL;
 
-static void VerifyTranslation(void) {
-    UResourceBundle *root, *currentLocale;
-    int32_t locCount = uloc_countAvailable();
-    int32_t locIndex;
-    UErrorCode errorCode = U_ZERO_ERROR;
-    int32_t exemplarLen;
-    const UChar *exemplarCharacters;
-    const char *currLoc;
-    UScriptCode scripts[USCRIPT_CODE_LIMIT];
-    int32_t numScripts;
-    int32_t idx;
-    int32_t end;
-    UResourceBundle *resArray;
+        /*Test function "getLocale(ULocale.VALID_LOCALE)"*/
+        const char* l1 = ucal_getLocaleByType(c1, ULOC_VALID_LOCALE, &status);
+        const char* l2 = ucal_getLocaleByType(c2, ULOC_VALID_LOCALE, &status);
+
+        if(!isLocaleAvailable(resIndex, newLoc)){
+            continue;
+        }
+        c1 = ucal_open(NULL, -1, oldLoc, UCAL_GREGORIAN, &status);
+        c2 = ucal_open(NULL, -1, newLoc, UCAL_GREGORIAN, &status);
 
-    if (locCount <= 1) {
-        log_data_err("At least root needs to be installed\n");
+        if (strcmp(newLoc,l1)!=0 || strcmp(l1,l2)!=0 || status!=U_ZERO_ERROR) {
+            log_err("The locales are not equal!.Old: %s, New: %s \n", oldLoc, newLoc);
+        }
+        log_verbose("ucal_getLocaleByType old:%s   new:%s\n", l1, l2);
+        ucal_close(c1);
+        ucal_close(c2);
     }
+    ures_close(resIndex);
+#endif
+}
 
-    root = ures_openDirect(NULL, "root", &errorCode);
-    if(U_FAILURE(errorCode)) {
-        log_data_err("Can't open root\n");
+static void TestDateFormat() {
+#if !UCONFIG_NO_FORMATTING
+    int i;
+    UErrorCode status = U_ZERO_ERROR;
+    UResourceBundle *resIndex = ures_open(NULL,"res_index", &status);
+    if(U_FAILURE(status)){
+        log_err_status(status, "Could not open res_index.res. Exiting. Error: %s\n", u_errorName(status));
         return;
     }
-    for (locIndex = 0; locIndex < locCount; locIndex++) {
-        errorCode=U_ZERO_ERROR;
-        currLoc = uloc_getAvailable(locIndex);
-        currentLocale = ures_open(NULL, currLoc, &errorCode);
-        if(errorCode != U_ZERO_ERROR) {
-            if(U_SUCCESS(errorCode)) {
-                /* It's installed, but there is no data.
-                   It's installed for the g18n white paper [grhoten] */
-                log_err("ERROR: Locale %-5s not installed, and it should be!\n",
-                    uloc_getAvailable(locIndex));
-            } else {
-                log_err("%%%%%%% Unexpected error %d in %s %%%%%%%",
-                    u_errorName(errorCode),
-                    uloc_getAvailable(locIndex));
-            }
-            ures_close(currentLocale);
+    for (i=0; i<UPRV_LENGTHOF(LOCALE_ALIAS); i++) {
+        const char* oldLoc = LOCALE_ALIAS[i][0];
+        const char* newLoc = LOCALE_ALIAS[i][1];
+        UDateFormat* df1 = NULL;
+        UDateFormat* df2 = NULL;
+        const char* l1 = NULL;
+        const char* l2 = NULL;
+
+        if(!isLocaleAvailable(resIndex, newLoc)){
             continue;
         }
-        exemplarCharacters = ures_getStringByKey(currentLocale, "ExemplarCharacters", &exemplarLen, &errorCode);
-        if (U_FAILURE(errorCode)) {
-            log_err("error ures_getStringByKey returned %s\n", u_errorName(errorCode));
+        df1 = udat_open(UDAT_FULL, UDAT_FULL,oldLoc, NULL, 0, NULL, -1, &status);
+        df2 = udat_open(UDAT_FULL, UDAT_FULL,newLoc, NULL, 0, NULL, -1, &status);
+        if(U_FAILURE(status)){
+            log_err("Creation of date format failed  %s\n", u_errorName(status));
+            return;
+        }        
+        /*Test function "getLocale"*/
+        l1 = udat_getLocaleByType(df1, ULOC_VALID_LOCALE, &status);
+        l2 = udat_getLocaleByType(df2, ULOC_VALID_LOCALE, &status);
+        if(U_FAILURE(status)){
+            log_err("Fetching the locale by type failed.  %s\n", u_errorName(status));
         }
-        else if (QUICK && exemplarLen > 2048) {
-            log_verbose("skipping test for %s\n", currLoc);
+        if (strcmp(newLoc,l1)!=0 || strcmp(l1,l2)!=0) {
+            log_err("The locales are not equal!.Old: %s, New: %s \n", oldLoc, newLoc);
         }
-        else {
-            UChar langBuffer[128];
-            int32_t langSize;
-            int32_t strIdx;
-            langSize = uloc_getDisplayLanguage(currLoc, currLoc, langBuffer, sizeof(langBuffer)/sizeof(langBuffer[0]), &errorCode);
-            if (U_FAILURE(errorCode)) {
-                log_err("error uloc_getDisplayLanguage returned %s\n", u_errorName(errorCode));
-            }
-            else {
-                strIdx = findStringSetMismatch(langBuffer, langSize, exemplarCharacters, exemplarLen, FALSE);
-                if (strIdx >= 0) {
-                    log_err("getDisplayLanguage(%s) at index %d returned characters not in the exemplar characters.\n",
-                        currLoc, strIdx);
-                }
-            }
-            langSize = uloc_getDisplayCountry(currLoc, currLoc, langBuffer, sizeof(langBuffer)/sizeof(langBuffer[0]), &errorCode);
-            if (U_FAILURE(errorCode)) {
-                log_err("error uloc_getDisplayCountry returned %s\n", u_errorName(errorCode));
-            }
-            else {
-                strIdx = findStringSetMismatch(langBuffer, langSize, exemplarCharacters, exemplarLen, FALSE);
-                if (strIdx >= 0) {
-                    log_err("getDisplayCountry(%s) at index %d returned characters not in the exemplar characters.\n",
-                        currLoc, strIdx);
-                }
-            }
+        log_verbose("udat_getLocaleByType old:%s   new:%s\n", l1, l2);
+        udat_close(df1);
+        udat_close(df2);
+    }
+    ures_close(resIndex);
+#endif
+}
 
-            resArray = ures_getByKey(currentLocale, "DayNames", NULL, &errorCode);
-            if (U_FAILURE(errorCode)) {
-                log_err("error ures_getByKey returned %s\n", u_errorName(errorCode));
-            }
-            if (QUICK) {
-                end = 1;
-            }
-            else {
-                end = ures_getSize(resArray);
-            }
+static void TestCollation() {
+#if !UCONFIG_NO_COLLATION
+    int i;
+    UErrorCode status = U_ZERO_ERROR;
+    UResourceBundle *resIndex = ures_open(NULL,"res_index", &status);
+    if(U_FAILURE(status)){
+        log_err_status(status, "Could not open res_index.res. Exiting. Error: %s\n", u_errorName(status));
+        return;
+    }
+    for (i=0; i<UPRV_LENGTHOF(LOCALE_ALIAS); i++) {
+        const char* oldLoc = LOCALE_ALIAS[i][0];
+        const char* newLoc = LOCALE_ALIAS[i][1];
+        UCollator* c1 = NULL;
+        UCollator* c2 = NULL;
+        const char* l1 = NULL;
+        const char* l2 = NULL;
 
+        status = U_ZERO_ERROR;
+        if(!isLocaleAvailable(resIndex, newLoc)){
+            continue;
+        }
+        if(U_FAILURE(status)){
+            log_err("Creation of collators failed  %s\n", u_errorName(status));
+            return;
+        }
+        c1 = ucol_open(oldLoc, &status);
+        c2 = ucol_open(newLoc, &status);
+        l1 = ucol_getLocaleByType(c1, ULOC_VALID_LOCALE, &status);
+        l2 = ucol_getLocaleByType(c2, ULOC_VALID_LOCALE, &status);
+        if(U_FAILURE(status)){
+            log_err("Fetching the locale names failed failed  %s\n", u_errorName(status));
+        }        
+        if (strcmp(newLoc,l1)!=0 || strcmp(l1,l2)!=0) {
+            log_err("The locales are not equal!.Old: %s, New: %s \n", oldLoc, newLoc);
+        }
+        log_verbose("ucol_getLocaleByType old:%s   new:%s\n", l1, l2);
+        ucol_close(c1);
+        ucol_close(c2);
+    }
+    ures_close(resIndex);
+#endif
+}
 
-            for (idx = 0; idx < end; idx++) {
-                const UChar *fromBundleStr = ures_getStringByIndex(resArray, idx, &langSize, &errorCode);
-                if (U_FAILURE(errorCode)) {
-                    log_err("error ures_getStringByIndex(%d) returned %s\n", idx, u_errorName(errorCode));
-                    continue;
-                }
-                strIdx = findStringSetMismatch(fromBundleStr, langSize, exemplarCharacters, exemplarLen, TRUE);
-                if (strIdx >= 0) {
-                    log_err("getDayNames(%s, %d) at index %d returned characters not in the exemplar characters.\n",
-                        currLoc, idx, strIdx);
-                }
-            }
-            ures_close(resArray);
+typedef struct OrientationStructTag {
+    const char* localeId;
+    ULayoutType character;
+    ULayoutType line;
+} OrientationStruct;
 
-            resArray = ures_getByKey(currentLocale, "MonthNames", NULL, &errorCode);
-            if (U_FAILURE(errorCode)) {
-                log_err("error ures_getByKey returned %s\n", u_errorName(errorCode));
-            }
-            if (QUICK) {
-                end = 1;
-            }
-            else {
-                end = ures_getSize(resArray);
-            }
+static const char* ULayoutTypeToString(ULayoutType type)
+{
+    switch(type)
+    {
+    case ULOC_LAYOUT_LTR:
+        return "ULOC_LAYOUT_LTR";
+        break;
+    case ULOC_LAYOUT_RTL:
+        return "ULOC_LAYOUT_RTL";
+        break;
+    case ULOC_LAYOUT_TTB:
+        return "ULOC_LAYOUT_TTB";
+        break;
+    case ULOC_LAYOUT_BTT:
+        return "ULOC_LAYOUT_BTT";
+        break;
+    case ULOC_LAYOUT_UNKNOWN:
+        break;
+    }
 
-            for (idx = 0; idx < end; idx++) {
-                const UChar *fromBundleStr = ures_getStringByIndex(resArray, idx, &langSize, &errorCode);
-                if (U_FAILURE(errorCode)) {
-                    log_err("error ures_getStringByIndex(%d) returned %s\n", idx, u_errorName(errorCode));
-                    continue;
-                }
-                strIdx = findStringSetMismatch(fromBundleStr, langSize, exemplarCharacters, exemplarLen, TRUE);
-                if (strIdx >= 0) {
-                    log_err("getMonthNames(%s, %d) at index %d returned characters not in the exemplar characters.\n",
-                        currLoc, idx, strIdx);
-                }
-            }
-            ures_close(resArray);
+    return "Unknown enum value for ULayoutType!";
+}
 
-            errorCode = U_ZERO_ERROR;
-            numScripts = uscript_getCode(currLoc, scripts, sizeof(scripts)/sizeof(scripts[0]), &errorCode);
-            if (numScripts == 0) {
-                log_err("uscript_getCode(%s) doesn't work.\n", currLoc);
-            }
-            /* TODO: test that the scripts are a superset of exemplar characters. */
+static void  TestOrientation()
+{
+    static const OrientationStruct toTest [] = {
+        { "ar", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
+        { "aR", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
+        { "ar_Arab", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
+        { "fa", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
+        { "Fa", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
+        { "he", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
+        { "ps", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
+        { "ur", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
+        { "UR", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
+        { "en", ULOC_LAYOUT_LTR, ULOC_LAYOUT_TTB }
+    };
+
+    size_t i = 0;
+    for (; i < UPRV_LENGTHOF(toTest); ++i) {
+        UErrorCode statusCO = U_ZERO_ERROR;
+        UErrorCode statusLO = U_ZERO_ERROR;
+        const char* const localeId = toTest[i].localeId;
+        const ULayoutType co = uloc_getCharacterOrientation(localeId, &statusCO);
+        const ULayoutType expectedCO = toTest[i].character;
+        const ULayoutType lo = uloc_getLineOrientation(localeId, &statusLO);
+        const ULayoutType expectedLO = toTest[i].line;
+        if (U_FAILURE(statusCO)) {
+            log_err_status(statusCO,
+                "  unexpected failure for uloc_getCharacterOrientation(), with localId \"%s\" and status %s\n",
+                localeId,
+                u_errorName(statusCO));
+        }
+        else if (co != expectedCO) {
+            log_err(
+                "  unexpected result for uloc_getCharacterOrientation(), with localeId \"%s\". Expected %s but got result %s\n",
+                localeId,
+                ULayoutTypeToString(expectedCO),
+                ULayoutTypeToString(co));
+        }
+        if (U_FAILURE(statusLO)) {
+            log_err_status(statusLO,
+                "  unexpected failure for uloc_getLineOrientation(), with localId \"%s\" and status %s\n",
+                localeId,
+                u_errorName(statusLO));
+        }
+        else if (lo != expectedLO) {
+            log_err(
+                "  unexpected result for uloc_getLineOrientation(), with localeId \"%s\". Expected %s but got result %s\n",
+                localeId,
+                ULayoutTypeToString(expectedLO),
+                ULayoutTypeToString(lo));
         }
-        ures_close(currentLocale);
     }
-
-    ures_close(root);
 }
+
+static void  TestULocale() {
+    int i;
+    UErrorCode status = U_ZERO_ERROR;
+    UResourceBundle *resIndex = ures_open(NULL,"res_index", &status);
+    if(U_FAILURE(status)){
+        log_err_status(status, "Could not open res_index.res. Exiting. Error: %s\n", u_errorName(status));
+        return;
+    }
+    for (i=0; i<UPRV_LENGTHOF(LOCALE_ALIAS); i++) {
+        const char* oldLoc = LOCALE_ALIAS[i][0];
+        const char* newLoc = LOCALE_ALIAS[i][1];
+        UChar name1[256], name2[256];
+        char names1[256], names2[256];
+        int32_t capacity = 256;
+
+        status = U_ZERO_ERROR;
+        if(!isLocaleAvailable(resIndex, newLoc)){
+            continue;
+        }
+        uloc_getDisplayName(oldLoc, ULOC_US, name1, capacity, &status);
+        if(U_FAILURE(status)){
+            log_err("uloc_getDisplayName(%s) failed %s\n", oldLoc, u_errorName(status));
+        }
+
+        uloc_getDisplayName(newLoc, ULOC_US, name2, capacity, &status);
+        if(U_FAILURE(status)){
+            log_err("uloc_getDisplayName(%s) failed %s\n", newLoc, u_errorName(status));
+        }
+
+        if (u_strcmp(name1, name2)!=0) {
+            log_err("The locales are not equal!.Old: %s, New: %s \n", oldLoc, newLoc);
+        }
+        u_austrcpy(names1, name1);
+        u_austrcpy(names2, name2);
+        log_verbose("uloc_getDisplayName old:%s   new:%s\n", names1, names2);
+    }
+    ures_close(resIndex);
+
+}
+
+static void TestUResourceBundle() {
+    const char* us1;
+    const char* us2;
+
+    UResourceBundle* rb1 = NULL;
+    UResourceBundle* rb2 = NULL;
+    UErrorCode status = U_ZERO_ERROR;
+    int i;
+    UResourceBundle *resIndex = NULL;
+    if(U_FAILURE(status)){
+        log_err("Could not open res_index.res. Exiting. Error: %s\n", u_errorName(status));
+        return;
+    }
+    resIndex = ures_open(NULL,"res_index", &status);
+    for (i=0; i<UPRV_LENGTHOF(LOCALE_ALIAS); i++) {
+
+        const char* oldLoc = LOCALE_ALIAS[i][0];
+        const char* newLoc = LOCALE_ALIAS[i][1];
+        if(!isLocaleAvailable(resIndex, newLoc)){
+            continue;
+        }
+        rb1 = ures_open(NULL, oldLoc, &status);
+        if (U_FAILURE(status)) {
+            log_err("ures_open(%s) failed %s\n", oldLoc, u_errorName(status));
+        }
+
+        us1 = ures_getLocaleByType(rb1, ULOC_ACTUAL_LOCALE, &status);
+
+        status = U_ZERO_ERROR;
+        rb2 = ures_open(NULL, newLoc, &status);
+        if (U_FAILURE(status)) {
+            log_err("ures_open(%s) failed %s\n", oldLoc, u_errorName(status));
+        } 
+        us2 = ures_getLocaleByType(rb2, ULOC_ACTUAL_LOCALE, &status);
+
+        if (strcmp(us1,newLoc)!=0 || strcmp(us1,us2)!=0 ) {
+            log_err("The locales are not equal!.Old: %s, New: %s \n", oldLoc, newLoc);
+        }
+
+        log_verbose("ures_getStringByKey old:%s   new:%s\n", us1, us2);
+        ures_close(rb1);
+        rb1 = NULL;
+        ures_close(rb2);
+        rb2 = NULL;
+    }
+    ures_close(resIndex);
+}
+
+static void TestDisplayName() {
+    
+    UChar oldCountry[256] = {'\0'};
+    UChar newCountry[256] = {'\0'};
+    UChar oldLang[256] = {'\0'};
+    UChar newLang[256] = {'\0'};
+    char country[256] ={'\0'}; 
+    char language[256] ={'\0'};
+    int32_t capacity = 256;
+    int i =0;
+    int j=0;
+    for (i=0; i<UPRV_LENGTHOF(LOCALE_ALIAS); i++) {
+        const char* oldLoc = LOCALE_ALIAS[i][0];
+        const char* newLoc = LOCALE_ALIAS[i][1];
+        UErrorCode status = U_ZERO_ERROR;
+        int32_t available = uloc_countAvailable();
+
+        for(j=0; j<available; j++){
+            
+            const char* dispLoc = uloc_getAvailable(j);
+            int32_t oldCountryLen = uloc_getDisplayCountry(oldLoc,dispLoc, oldCountry, capacity, &status);
+            int32_t newCountryLen = uloc_getDisplayCountry(newLoc, dispLoc, newCountry, capacity, &status);
+            int32_t oldLangLen = uloc_getDisplayLanguage(oldLoc, dispLoc, oldLang, capacity, &status);
+            int32_t newLangLen = uloc_getDisplayLanguage(newLoc, dispLoc, newLang, capacity, &status );
+            
+            int32_t countryLen = uloc_getCountry(newLoc, country, capacity, &status);
+            int32_t langLen  = uloc_getLanguage(newLoc, language, capacity, &status);
+            /* there is a display name for the current country ID */
+            if(countryLen != newCountryLen ){
+                if(u_strncmp(oldCountry,newCountry,oldCountryLen)!=0){
+                    log_err("uloc_getDisplayCountry() failed for %s in display locale %s \n", oldLoc, dispLoc);
+                }
+            }
+            /* there is a display name for the current lang ID */
+            if(langLen!=newLangLen){
+                if(u_strncmp(oldLang,newLang,oldLangLen)){
+                    log_err("uloc_getDisplayLanguage() failed for %s in display locale %s \n", oldLoc, dispLoc);                }
+            }
+        }
+    }
+}
+
+static void TestGetLocaleForLCID() {
+    int32_t i, length, lengthPre;
+    const char* testLocale = 0;
+    UErrorCode status = U_ZERO_ERROR;
+    char            temp2[40], temp3[40];
+    uint32_t lcid;
+    
+    lcid = uloc_getLCID("en_US");
+    if (lcid != 0x0409) {
+        log_err("  uloc_getLCID(\"en_US\") = %d, expected 0x0409\n", lcid);
+    }
+    
+    lengthPre = uloc_getLocaleForLCID(lcid, temp2, 4, &status);
+    if (status != U_BUFFER_OVERFLOW_ERROR) {
+        log_err("  unexpected result from uloc_getLocaleForLCID with small buffer: %s\n", u_errorName(status));
+    }
+    else {
+        status = U_ZERO_ERROR;
+    }
+    
+    length = uloc_getLocaleForLCID(lcid, temp2, UPRV_LENGTHOF(temp2), &status);
+    if (U_FAILURE(status)) {
+        log_err("  unexpected result from uloc_getLocaleForLCID(0x0409): %s\n", u_errorName(status));
+        status = U_ZERO_ERROR;
+    }
+    
+    if (length != lengthPre) {
+        log_err("  uloc_getLocaleForLCID(0x0409): returned length %d does not match preflight length %d\n", length, lengthPre);
+    }
+    
+    length = uloc_getLocaleForLCID(0x12345, temp2, UPRV_LENGTHOF(temp2), &status);
+    if (U_SUCCESS(status)) {
+        log_err("  unexpected result from uloc_getLocaleForLCID(0x12345): %s, status %s\n", temp2, u_errorName(status));
+    }
+    status = U_ZERO_ERROR;
+    
+    log_verbose("Testing getLocaleForLCID vs. locale data\n");
+    for (i = 0; i < LOCALE_SIZE; i++) {
+        
+        testLocale=rawData2[NAME][i];
+        
+        log_verbose("Testing   %s ......\n", testLocale);
+        
+        sscanf(rawData2[LCID][i], "%x", &lcid);
+        length = uloc_getLocaleForLCID(lcid, temp2, UPRV_LENGTHOF(temp2), &status);
+        if (U_FAILURE(status)) {
+            log_err("  unexpected failure of uloc_getLocaleForLCID(%#04x), status %s\n", lcid, u_errorName(status));
+            status = U_ZERO_ERROR;
+            continue;
+        }
+        
+        if (length != uprv_strlen(temp2)) {
+            log_err("  returned length %d not correct for uloc_getLocaleForLCID(%#04x), expected %d\n", length, lcid, uprv_strlen(temp2));
+        }
+        
+        /* Compare language, country, script */
+        length = uloc_getLanguage(temp2, temp3, UPRV_LENGTHOF(temp3), &status);
+        if (U_FAILURE(status)) {
+            log_err("  couldn't get language in uloc_getLocaleForLCID(%#04x) = %s, status %s\n", lcid, temp2, u_errorName(status));
+            status = U_ZERO_ERROR;
+        }
+        else if (uprv_strcmp(temp3, rawData2[LANG][i]) && !(uprv_strcmp(temp3, "nn") == 0 && uprv_strcmp(rawData2[VAR][i], "NY") == 0)) {
+            log_err("  language doesn't match expected %s in in uloc_getLocaleForLCID(%#04x) = %s\n", rawData2[LANG][i], lcid, temp2);
+        }
+        
+        length = uloc_getScript(temp2, temp3, UPRV_LENGTHOF(temp3), &status);
+        if (U_FAILURE(status)) {
+            log_err("  couldn't get script in uloc_getLocaleForLCID(%#04x) = %s, status %s\n", lcid, temp2, u_errorName(status));
+            status = U_ZERO_ERROR;
+        }
+        else if (uprv_strcmp(temp3, rawData2[SCRIPT][i])) {
+            log_err("  script doesn't match expected %s in in uloc_getLocaleForLCID(%#04x) = %s\n", rawData2[SCRIPT][i], lcid, temp2);
+        }
+        
+        length = uloc_getCountry(temp2, temp3, UPRV_LENGTHOF(temp3), &status);
+        if (U_FAILURE(status)) {
+            log_err("  couldn't get country in uloc_getLocaleForLCID(%#04x) = %s, status %s\n", lcid, temp2, u_errorName(status));
+            status = U_ZERO_ERROR;
+        }
+        else if (uprv_strlen(rawData2[CTRY][i]) && uprv_strcmp(temp3, rawData2[CTRY][i])) {
+            log_err("  country doesn't match expected %s in in uloc_getLocaleForLCID(%#04x) = %s\n", rawData2[CTRY][i], lcid, temp2);
+        }
+    }
+    
+}
+
+const char* const basic_maximize_data[][2] = {
+  {
+    "zu_Zzzz_Zz",
+    "zu_Latn_ZA",
+  }, {
+    "ZU_Zz",
+    "zu_Latn_ZA"
+  }, {
+    "zu_LATN",
+    "zu_Latn_ZA"
+  }, {
+    "en_Zz",
+    "en_Latn_US"
+  }, {
+    "en_us",
+    "en_Latn_US"
+  }, {
+    "en_Kore",
+    "en_Kore_US"
+  }, {
+    "en_Kore_Zz",
+    "en_Kore_US"
+  }, {
+    "en_Kore_ZA",
+    "en_Kore_ZA"
+  }, {
+    "en_Kore_ZA_POSIX",
+    "en_Kore_ZA_POSIX"
+  }, {
+    "en_Gujr",
+    "en_Gujr_US"
+  }, {
+    "en_ZA",
+    "en_Latn_ZA"
+  }, {
+    "en_Gujr_Zz",
+    "en_Gujr_US"
+  }, {
+    "en_Gujr_ZA",
+    "en_Gujr_ZA"
+  }, {
+    "en_Gujr_ZA_POSIX",
+    "en_Gujr_ZA_POSIX"
+  }, {
+    "en_US_POSIX_1901",
+    "en_Latn_US_POSIX_1901"
+  }, {
+    "en_Latn__POSIX_1901",
+    "en_Latn_US_POSIX_1901"
+  }, {
+    "en__POSIX_1901",
+    "en_Latn_US_POSIX_1901"
+  }, {
+    "de__POSIX_1901",
+    "de_Latn_DE_POSIX_1901"
+  }, {
+    "en_US_BOSTON",
+    "en_Latn_US_BOSTON"
+  }, {
+    "th@calendar=buddhist",
+    "th_Thai_TH@calendar=buddhist"
+  }, {
+    "ar_ZZ",
+    "ar_Arab_EG"
+  }, {
+    "zh",
+    "zh_Hans_CN"
+  }, {
+    "zh_TW",
+    "zh_Hant_TW"
+  }, {
+    "zh_HK",
+    "zh_Hant_HK"
+  }, {
+    "zh_Hant",
+    "zh_Hant_TW"
+  }, {
+    "zh_Zzzz_CN",
+    "zh_Hans_CN"
+  }, {
+    "und_US",
+    "en_Latn_US"
+  }, {
+    "und_HK",
+    "zh_Hant_HK"
+  }, {
+    "zzz",
+    ""
+  }, {
+     "de_u_co_phonebk",
+     "de_Latn_DE_U_CO_PHONEBK"
+  }, {
+     "de_Latn_u_co_phonebk",
+     "de_Latn_DE_U_CO_PHONEBK"
+  }, {
+     "de_Latn_DE_u_co_phonebk",
+     "de_Latn_DE_U_CO_PHONEBK"
+  }, {
+    "_Arab@em=emoji",
+    "ar_Arab_EG@em=emoji"
+  }, {
+    "_Latn@em=emoji",
+    "en_Latn_US@em=emoji"
+  }, {
+    "_Latn_DE@em=emoji",
+    "de_Latn_DE@em=emoji"
+  }, {
+    "_Zzzz_DE@em=emoji",
+    "de_Latn_DE@em=emoji"
+  }, {
+    "_DE@em=emoji",
+    "de_Latn_DE@em=emoji"
+  }
+};
+
+const char* const basic_minimize_data[][2] = {
+  {
+    "en_Latn_US",
+    "en"
+  }, {
+    "en_Latn_US_POSIX_1901",
+    "en__POSIX_1901"
+  }, {
+    "EN_Latn_US_POSIX_1901",
+    "en__POSIX_1901"
+  }, {
+    "en_Zzzz_US_POSIX_1901",
+    "en__POSIX_1901"
+  }, {
+    "de_Latn_DE_POSIX_1901",
+    "de__POSIX_1901"
+  }, {
+    "und",
+    ""
+  }, {
+    "en_Latn_US@calendar=gregorian",
+    "en@calendar=gregorian"
+  }
+};
+
+const char* const full_data[][3] = {
+  {
+    /*   "FROM", */
+    /*   "ADD-LIKELY", */
+    /*   "REMOVE-LIKELY" */
+    /* }, { */
+    "aa",
+    "aa_Latn_ET",
+    "aa"
+  }, {
+    "af",
+    "af_Latn_ZA",
+    "af"
+  }, {
+    "ak",
+    "ak_Latn_GH",
+    "ak"
+  }, {
+    "am",
+    "am_Ethi_ET",
+    "am"
+  }, {
+    "ar",
+    "ar_Arab_EG",
+    "ar"
+  }, {
+    "as",
+    "as_Beng_IN",
+    "as"
+  }, {
+    "az",
+    "az_Latn_AZ",
+    "az"
+  }, {
+    "be",
+    "be_Cyrl_BY",
+    "be"
+  }, {
+    "bg",
+    "bg_Cyrl_BG",
+    "bg"
+  }, {
+    "bn",
+    "bn_Beng_BD",
+    "bn"
+  }, {
+    "bo",
+    "bo_Tibt_CN",
+    "bo"
+  }, {
+    "bs",
+    "bs_Latn_BA",
+    "bs"
+  }, {
+    "ca",
+    "ca_Latn_ES",
+    "ca"
+  }, {
+    "ch",
+    "ch_Latn_GU",
+    "ch"
+  }, {
+    "chk",
+    "chk_Latn_FM",
+    "chk"
+  }, {
+    "cs",
+    "cs_Latn_CZ",
+    "cs"
+  }, {
+    "cy",
+    "cy_Latn_GB",
+    "cy"
+  }, {
+    "da",
+    "da_Latn_DK",
+    "da"
+  }, {
+    "de",
+    "de_Latn_DE",
+    "de"
+  }, {
+    "dv",
+    "dv_Thaa_MV",
+    "dv"
+  }, {
+    "dz",
+    "dz_Tibt_BT",
+    "dz"
+  }, {
+    "ee",
+    "ee_Latn_GH",
+    "ee"
+  }, {
+    "el",
+    "el_Grek_GR",
+    "el"
+  }, {
+    "en",
+    "en_Latn_US",
+    "en"
+  }, {
+    "es",
+    "es_Latn_ES",
+    "es"
+  }, {
+    "et",
+    "et_Latn_EE",
+    "et"
+  }, {
+    "eu",
+    "eu_Latn_ES",
+    "eu"
+  }, {
+    "fa",
+    "fa_Arab_IR",
+    "fa"
+  }, {
+    "fi",
+    "fi_Latn_FI",
+    "fi"
+  }, {
+    "fil",
+    "fil_Latn_PH",
+    "fil"
+  }, {
+    "fo",
+    "fo_Latn_FO",
+    "fo"
+  }, {
+    "fr",
+    "fr_Latn_FR",
+    "fr"
+  }, {
+    "fur",
+    "fur_Latn_IT",
+    "fur"
+  }, {
+    "ga",
+    "ga_Latn_IE",
+    "ga"
+  }, {
+    "gaa",
+    "gaa_Latn_GH",
+    "gaa"
+  }, {
+    "gl",
+    "gl_Latn_ES",
+    "gl"
+  }, {
+    "gn",
+    "gn_Latn_PY",
+    "gn"
+  }, {
+    "gu",
+    "gu_Gujr_IN",
+    "gu"
+  }, {
+    "ha",
+    "ha_Latn_NG",
+    "ha"
+  }, {
+    "haw",
+    "haw_Latn_US",
+    "haw"
+  }, {
+    "he",
+    "he_Hebr_IL",
+    "he"
+  }, {
+    "hi",
+    "hi_Deva_IN",
+    "hi"
+  }, {
+    "hr",
+    "hr_Latn_HR",
+    "hr"
+  }, {
+    "ht",
+    "ht_Latn_HT",
+    "ht"
+  }, {
+    "hu",
+    "hu_Latn_HU",
+    "hu"
+  }, {
+    "hy",
+    "hy_Armn_AM",
+    "hy"
+  }, {
+    "id",
+    "id_Latn_ID",
+    "id"
+  }, {
+    "ig",
+    "ig_Latn_NG",
+    "ig"
+  }, {
+    "ii",
+    "ii_Yiii_CN",
+    "ii"
+  }, {
+    "is",
+    "is_Latn_IS",
+    "is"
+  }, {
+    "it",
+    "it_Latn_IT",
+    "it"
+  }, {
+    "ja",
+    "ja_Jpan_JP",
+    "ja"
+  }, {
+    "ka",
+    "ka_Geor_GE",
+    "ka"
+  }, {
+    "kaj",
+    "kaj_Latn_NG",
+    "kaj"
+  }, {
+    "kam",
+    "kam_Latn_KE",
+    "kam"
+  }, {
+    "kk",
+    "kk_Cyrl_KZ",
+    "kk"
+  }, {
+    "kl",
+    "kl_Latn_GL",
+    "kl"
+  }, {
+    "km",
+    "km_Khmr_KH",
+    "km"
+  }, {
+    "kn",
+    "kn_Knda_IN",
+    "kn"
+  }, {
+    "ko",
+    "ko_Kore_KR",
+    "ko"
+  }, {
+    "kok",
+    "kok_Deva_IN",
+    "kok"
+  }, {
+    "kpe",
+    "kpe_Latn_LR",
+    "kpe"
+  }, {
+    "ku",
+    "ku_Latn_TR",
+    "ku"
+  }, {
+    "ky",
+    "ky_Cyrl_KG",
+    "ky"
+  }, {
+    "la",
+    "la_Latn_VA",
+    "la"
+  }, {
+    "ln",
+    "ln_Latn_CD",
+    "ln"
+  }, {
+    "lo",
+    "lo_Laoo_LA",
+    "lo"
+  }, {
+    "lt",
+    "lt_Latn_LT",
+    "lt"
+  }, {
+    "lv",
+    "lv_Latn_LV",
+    "lv"
+  }, {
+    "mg",
+    "mg_Latn_MG",
+    "mg"
+  }, {
+    "mh",
+    "mh_Latn_MH",
+    "mh"
+  }, {
+    "mk",
+    "mk_Cyrl_MK",
+    "mk"
+  }, {
+    "ml",
+    "ml_Mlym_IN",
+    "ml"
+  }, {
+    "mn",
+    "mn_Cyrl_MN",
+    "mn"
+  }, {
+    "mr",
+    "mr_Deva_IN",
+    "mr"
+  }, {
+    "ms",
+    "ms_Latn_MY",
+    "ms"
+  }, {
+    "mt",
+    "mt_Latn_MT",
+    "mt"
+  }, {
+    "my",
+    "my_Mymr_MM",
+    "my"
+  }, {
+    "na",
+    "na_Latn_NR",
+    "na"
+  }, {
+    "ne",
+    "ne_Deva_NP",
+    "ne"
+  }, {
+    "niu",
+    "niu_Latn_NU",
+    "niu"
+  }, {
+    "nl",
+    "nl_Latn_NL",
+    "nl"
+  }, {
+    "nn",
+    "nn_Latn_NO",
+    "nn"
+  }, {
+    "nr",
+    "nr_Latn_ZA",
+    "nr"
+  }, {
+    "nso",
+    "nso_Latn_ZA",
+    "nso"
+  }, {
+    "ny",
+    "ny_Latn_MW",
+    "ny"
+  }, {
+    "om",
+    "om_Latn_ET",
+    "om"
+  }, {
+    "or",
+    "or_Orya_IN",
+    "or"
+  }, {
+    "pa",
+    "pa_Guru_IN",
+    "pa"
+  }, {
+    "pa_Arab",
+    "pa_Arab_PK",
+    "pa_PK"
+  }, {
+    "pa_PK",
+    "pa_Arab_PK",
+    "pa_PK"
+  }, {
+    "pap",
+    "pap_Latn_AW",
+    "pap"
+  }, {
+    "pau",
+    "pau_Latn_PW",
+    "pau"
+  }, {
+    "pl",
+    "pl_Latn_PL",
+    "pl"
+  }, {
+    "ps",
+    "ps_Arab_AF",
+    "ps"
+  }, {
+    "pt",
+    "pt_Latn_BR",
+    "pt"
+  }, {
+    "rn",
+    "rn_Latn_BI",
+    "rn"
+  }, {
+    "ro",
+    "ro_Latn_RO",
+    "ro"
+  }, {
+    "ru",
+    "ru_Cyrl_RU",
+    "ru"
+  }, {
+    "rw",
+    "rw_Latn_RW",
+    "rw"
+  }, {
+    "sa",
+    "sa_Deva_IN",
+    "sa"
+  }, {
+    "se",
+    "se_Latn_NO",
+    "se"
+  }, {
+    "sg",
+    "sg_Latn_CF",
+    "sg"
+  }, {
+    "si",
+    "si_Sinh_LK",
+    "si"
+  }, {
+    "sid",
+    "sid_Latn_ET",
+    "sid"
+  }, {
+    "sk",
+    "sk_Latn_SK",
+    "sk"
+  }, {
+    "sl",
+    "sl_Latn_SI",
+    "sl"
+  }, {
+    "sm",
+    "sm_Latn_WS",
+    "sm"
+  }, {
+    "so",
+    "so_Latn_SO",
+    "so"
+  }, {
+    "sq",
+    "sq_Latn_AL",
+    "sq"
+  }, {
+    "sr",
+    "sr_Cyrl_RS",
+    "sr"
+  }, {
+    "ss",
+    "ss_Latn_ZA",
+    "ss"
+  }, {
+    "st",
+    "st_Latn_ZA",
+    "st"
+  }, {
+    "sv",
+    "sv_Latn_SE",
+    "sv"
+  }, {
+    "sw",
+    "sw_Latn_TZ",
+    "sw"
+  }, {
+    "ta",
+    "ta_Taml_IN",
+    "ta"
+  }, {
+    "te",
+    "te_Telu_IN",
+    "te"
+  }, {
+    "tet",
+    "tet_Latn_TL",
+    "tet"
+  }, {
+    "tg",
+    "tg_Cyrl_TJ",
+    "tg"
+  }, {
+    "th",
+    "th_Thai_TH",
+    "th"
+  }, {
+    "ti",
+    "ti_Ethi_ET",
+    "ti"
+  }, {
+    "tig",
+    "tig_Ethi_ER",
+    "tig"
+  }, {
+    "tk",
+    "tk_Latn_TM",
+    "tk"
+  }, {
+    "tkl",
+    "tkl_Latn_TK",
+    "tkl"
+  }, {
+    "tn",
+    "tn_Latn_ZA",
+    "tn"
+  }, {
+    "to",
+    "to_Latn_TO",
+    "to"
+  }, {
+    "tpi",
+    "tpi_Latn_PG",
+    "tpi"
+  }, {
+    "tr",
+    "tr_Latn_TR",
+    "tr"
+  }, {
+    "ts",
+    "ts_Latn_ZA",
+    "ts"
+  }, {
+    "tt",
+    "tt_Cyrl_RU",
+    "tt"
+  }, {
+    "tvl",
+    "tvl_Latn_TV",
+    "tvl"
+  }, {
+    "ty",
+    "ty_Latn_PF",
+    "ty"
+  }, {
+    "uk",
+    "uk_Cyrl_UA",
+    "uk"
+  }, {
+    "und",
+    "en_Latn_US",
+    "en"
+  }, {
+    "und_AD",
+    "ca_Latn_AD",
+    "ca_AD"
+  }, {
+    "und_AE",
+    "ar_Arab_AE",
+    "ar_AE"
+  }, {
+    "und_AF",
+    "fa_Arab_AF",
+    "fa_AF"
+  }, {
+    "und_AL",
+    "sq_Latn_AL",
+    "sq"
+  }, {
+    "und_AM",
+    "hy_Armn_AM",
+    "hy"
+  }, {
+    "und_AO",
+    "pt_Latn_AO",
+    "pt_AO"
+  }, {
+    "und_AR",
+    "es_Latn_AR",
+    "es_AR"
+  }, {
+    "und_AS",
+    "sm_Latn_AS",
+    "sm_AS"
+  }, {
+    "und_AT",
+    "de_Latn_AT",
+    "de_AT"
+  }, {
+    "und_AW",
+    "nl_Latn_AW",
+    "nl_AW"
+  }, {
+    "und_AX",
+    "sv_Latn_AX",
+    "sv_AX"
+  }, {
+    "und_AZ",
+    "az_Latn_AZ",
+    "az"
+  }, {
+    "und_Arab",
+    "ar_Arab_EG",
+    "ar"
+  }, {
+    "und_Arab_IN",
+    "ur_Arab_IN",
+    "ur_IN"
+  }, {
+    "und_Arab_PK",
+    "ur_Arab_PK",
+    "ur"
+  }, {
+    "und_Arab_SN",
+    "ar_Arab_SN",
+    "ar_SN"
+  }, {
+    "und_Armn",
+    "hy_Armn_AM",
+    "hy"
+  }, {
+    "und_BA",
+    "bs_Latn_BA",
+    "bs"
+  }, {
+    "und_BD",
+    "bn_Beng_BD",
+    "bn"
+  }, {
+    "und_BE",
+    "nl_Latn_BE",
+    "nl_BE"
+  }, {
+    "und_BF",
+    "fr_Latn_BF",
+    "fr_BF"
+  }, {
+    "und_BG",
+    "bg_Cyrl_BG",
+    "bg"
+  }, {
+    "und_BH",
+    "ar_Arab_BH",
+    "ar_BH"
+  }, {
+    "und_BI",
+    "rn_Latn_BI",
+    "rn"
+  }, {
+    "und_BJ",
+    "fr_Latn_BJ",
+    "fr_BJ"
+  }, {
+    "und_BN",
+    "ms_Latn_BN",
+    "ms_BN"
+  }, {
+    "und_BO",
+    "es_Latn_BO",
+    "es_BO"
+  }, {
+    "und_BR",
+    "pt_Latn_BR",
+    "pt"
+  }, {
+    "und_BT",
+    "dz_Tibt_BT",
+    "dz"
+  }, {
+    "und_BY",
+    "be_Cyrl_BY",
+    "be"
+  }, {
+    "und_Beng",
+    "bn_Beng_BD",
+    "bn"
+  }, {
+    "und_Beng_IN",
+    "bn_Beng_IN",
+    "bn_IN"
+  }, {
+    "und_CD",
+    "sw_Latn_CD",
+    "sw_CD"
+  }, {
+    "und_CF",
+    "fr_Latn_CF",
+    "fr_CF"
+  }, {
+    "und_CG",
+    "fr_Latn_CG",
+    "fr_CG"
+  }, {
+    "und_CH",
+    "de_Latn_CH",
+    "de_CH"
+  }, {
+    "und_CI",
+    "fr_Latn_CI",
+    "fr_CI"
+  }, {
+    "und_CL",
+    "es_Latn_CL",
+    "es_CL"
+  }, {
+    "und_CM",
+    "fr_Latn_CM",
+    "fr_CM"
+  }, {
+    "und_CN",
+    "zh_Hans_CN",
+    "zh"
+  }, {
+    "und_CO",
+    "es_Latn_CO",
+    "es_CO"
+  }, {
+    "und_CR",
+    "es_Latn_CR",
+    "es_CR"
+  }, {
+    "und_CU",
+    "es_Latn_CU",
+    "es_CU"
+  }, {
+    "und_CV",
+    "pt_Latn_CV",
+    "pt_CV"
+  }, {
+    "und_CY",
+    "el_Grek_CY",
+    "el_CY"
+  }, {
+    "und_CZ",
+    "cs_Latn_CZ",
+    "cs"
+  }, {
+    "und_Cher",
+    "chr_Cher_US",
+    "chr"
+  }, {
+    "und_Cyrl",
+    "ru_Cyrl_RU",
+    "ru"
+  }, {
+    "und_Cyrl_KZ",
+    "ru_Cyrl_KZ",
+    "ru_KZ"
+  }, {
+    "und_DE",
+    "de_Latn_DE",
+    "de"
+  }, {
+    "und_DJ",
+    "aa_Latn_DJ",
+    "aa_DJ"
+  }, {
+    "und_DK",
+    "da_Latn_DK",
+    "da"
+  }, {
+    "und_DO",
+    "es_Latn_DO",
+    "es_DO"
+  }, {
+    "und_DZ",
+    "ar_Arab_DZ",
+    "ar_DZ"
+  }, {
+    "und_Deva",
+    "hi_Deva_IN",
+    "hi"
+  }, {
+    "und_EC",
+    "es_Latn_EC",
+    "es_EC"
+  }, {
+    "und_EE",
+    "et_Latn_EE",
+    "et"
+  }, {
+    "und_EG",
+    "ar_Arab_EG",
+    "ar"
+  }, {
+    "und_EH",
+    "ar_Arab_EH",
+    "ar_EH"
+  }, {
+    "und_ER",
+    "ti_Ethi_ER",
+    "ti_ER"
+  }, {
+    "und_ES",
+    "es_Latn_ES",
+    "es"
+  }, {
+    "und_ET",
+    "am_Ethi_ET",
+    "am"
+  }, {
+    "und_Ethi",
+    "am_Ethi_ET",
+    "am"
+  }, {
+    "und_Ethi_ER",
+    "am_Ethi_ER",
+    "am_ER"
+  }, {
+    "und_FI",
+    "fi_Latn_FI",
+    "fi"
+  }, {
+    "und_FM",
+    "en_Latn_FM",
+    "en_FM"
+  }, {
+    "und_FO",
+    "fo_Latn_FO",
+    "fo"
+  }, {
+    "und_FR",
+    "fr_Latn_FR",
+    "fr"
+  }, {
+    "und_GA",
+    "fr_Latn_GA",
+    "fr_GA"
+  }, {
+    "und_GE",
+    "ka_Geor_GE",
+    "ka"
+  }, {
+    "und_GF",
+    "fr_Latn_GF",
+    "fr_GF"
+  }, {
+    "und_GL",
+    "kl_Latn_GL",
+    "kl"
+  }, {
+    "und_GN",
+    "fr_Latn_GN",
+    "fr_GN"
+  }, {
+    "und_GP",
+    "fr_Latn_GP",
+    "fr_GP"
+  }, {
+    "und_GQ",
+    "es_Latn_GQ",
+    "es_GQ"
+  }, {
+    "und_GR",
+    "el_Grek_GR",
+    "el"
+  }, {
+    "und_GT",
+    "es_Latn_GT",
+    "es_GT"
+  }, {
+    "und_GU",
+    "en_Latn_GU",
+    "en_GU"
+  }, {
+    "und_GW",
+    "pt_Latn_GW",
+    "pt_GW"
+  }, {
+    "und_Geor",
+    "ka_Geor_GE",
+    "ka"
+  }, {
+    "und_Grek",
+    "el_Grek_GR",
+    "el"
+  }, {
+    "und_Gujr",
+    "gu_Gujr_IN",
+    "gu"
+  }, {
+    "und_Guru",
+    "pa_Guru_IN",
+    "pa"
+  }, {
+    "und_HK",
+    "zh_Hant_HK",
+    "zh_HK"
+  }, {
+    "und_HN",
+    "es_Latn_HN",
+    "es_HN"
+  }, {
+    "und_HR",
+    "hr_Latn_HR",
+    "hr"
+  }, {
+    "und_HT",
+    "ht_Latn_HT",
+    "ht"
+  }, {
+    "und_HU",
+    "hu_Latn_HU",
+    "hu"
+  }, {
+    "und_Hani",
+    "zh_Hani_CN",
+    "zh_Hani"
+  }, {
+    "und_Hans",
+    "zh_Hans_CN",
+    "zh"
+  }, {
+    "und_Hant",
+    "zh_Hant_TW",
+    "zh_TW"
+  }, {
+    "und_Hebr",
+    "he_Hebr_IL",
+    "he"
+  }, {
+    "und_IL",
+    "he_Hebr_IL",
+    "he"
+  }, {
+    "und_IN",
+    "hi_Deva_IN",
+    "hi"
+  }, {
+    "und_IQ",
+    "ar_Arab_IQ",
+    "ar_IQ"
+  }, {
+    "und_IR",
+    "fa_Arab_IR",
+    "fa"
+  }, {
+    "und_IS",
+    "is_Latn_IS",
+    "is"
+  }, {
+    "und_IT",
+    "it_Latn_IT",
+    "it"
+  }, {
+    "und_JO",
+    "ar_Arab_JO",
+    "ar_JO"
+  }, {
+    "und_JP",
+    "ja_Jpan_JP",
+    "ja"
+  }, {
+    "und_Jpan",
+    "ja_Jpan_JP",
+    "ja"
+  }, {
+    "und_KG",
+    "ky_Cyrl_KG",
+    "ky"
+  }, {
+    "und_KH",
+    "km_Khmr_KH",
+    "km"
+  }, {
+    "und_KM",
+    "ar_Arab_KM",
+    "ar_KM"
+  }, {
+    "und_KP",
+    "ko_Kore_KP",
+    "ko_KP"
+  }, {
+    "und_KR",
+    "ko_Kore_KR",
+    "ko"
+  }, {
+    "und_KW",
+    "ar_Arab_KW",
+    "ar_KW"
+  }, {
+    "und_KZ",
+    "ru_Cyrl_KZ",
+    "ru_KZ"
+  }, {
+    "und_Khmr",
+    "km_Khmr_KH",
+    "km"
+  }, {
+    "und_Knda",
+    "kn_Knda_IN",
+    "kn"
+  }, {
+    "und_Kore",
+    "ko_Kore_KR",
+    "ko"
+  }, {
+    "und_LA",
+    "lo_Laoo_LA",
+    "lo"
+  }, {
+    "und_LB",
+    "ar_Arab_LB",
+    "ar_LB"
+  }, {
+    "und_LI",
+    "de_Latn_LI",
+    "de_LI"
+  }, {
+    "und_LK",
+    "si_Sinh_LK",
+    "si"
+  }, {
+    "und_LS",
+    "st_Latn_LS",
+    "st_LS"
+  }, {
+    "und_LT",
+    "lt_Latn_LT",
+    "lt"
+  }, {
+    "und_LU",
+    "fr_Latn_LU",
+    "fr_LU"
+  }, {
+    "und_LV",
+    "lv_Latn_LV",
+    "lv"
+  }, {
+    "und_LY",
+    "ar_Arab_LY",
+    "ar_LY"
+  }, {
+    "und_Laoo",
+    "lo_Laoo_LA",
+    "lo"
+  }, {
+    "und_Latn_ES",
+    "es_Latn_ES",
+    "es"
+  }, {
+    "und_Latn_ET",
+    "en_Latn_ET",
+    "en_ET"
+  }, {
+    "und_Latn_GB",
+    "en_Latn_GB",
+    "en_GB"
+  }, {
+    "und_Latn_GH",
+    "ak_Latn_GH",
+    "ak"
+  }, {
+    "und_Latn_ID",
+    "id_Latn_ID",
+    "id"
+  }, {
+    "und_Latn_IT",
+    "it_Latn_IT",
+    "it"
+  }, {
+    "und_Latn_NG",
+    "en_Latn_NG",
+    "en_NG"
+  }, {
+    "und_Latn_TR",
+    "tr_Latn_TR",
+    "tr"
+  }, {
+    "und_Latn_ZA",
+    "en_Latn_ZA",
+    "en_ZA"
+  }, {
+    "und_MA",
+    "ar_Arab_MA",
+    "ar_MA"
+  }, {
+    "und_MC",
+    "fr_Latn_MC",
+    "fr_MC"
+  }, {
+    "und_MD",
+    "ro_Latn_MD",
+    "ro_MD"
+  }, {
+    "und_ME",
+    "sr_Latn_ME",
+    "sr_ME"
+  }, {
+    "und_MG",
+    "mg_Latn_MG",
+    "mg"
+  }, {
+    "und_MH",
+    "en_Latn_MH",
+    "en_MH"
+  }, {
+    "und_MK",
+    "mk_Cyrl_MK",
+    "mk"
+  }, {
+    "und_ML",
+    "bm_Latn_ML",
+    "bm"
+  }, {
+    "und_MM",
+    "my_Mymr_MM",
+    "my"
+  }, {
+    "und_MN",
+    "mn_Cyrl_MN",
+    "mn"
+  }, {
+    "und_MO",
+    "zh_Hant_MO",
+    "zh_MO"
+  }, {
+    "und_MQ",
+    "fr_Latn_MQ",
+    "fr_MQ"
+  }, {
+    "und_MR",
+    "ar_Arab_MR",
+    "ar_MR"
+  }, {
+    "und_MT",
+    "mt_Latn_MT",
+    "mt"
+  }, {
+    "und_MV",
+    "dv_Thaa_MV",
+    "dv"
+  }, {
+    "und_MW",
+    "en_Latn_MW",
+    "en_MW"
+  }, {
+    "und_MX",
+    "es_Latn_MX",
+    "es_MX"
+  }, {
+    "und_MY",
+    "ms_Latn_MY",
+    "ms"
+  }, {
+    "und_MZ",
+    "pt_Latn_MZ",
+    "pt_MZ"
+  }, {
+    "und_Mlym",
+    "ml_Mlym_IN",
+    "ml"
+  }, {
+    "und_Mymr",
+    "my_Mymr_MM",
+    "my"
+  }, {
+    "und_NC",
+    "fr_Latn_NC",
+    "fr_NC"
+  }, {
+    "und_NE",
+    "ha_Latn_NE",
+    "ha_NE"
+  }, {
+    "und_NG",
+    "en_Latn_NG",
+    "en_NG"
+  }, {
+    "und_NI",
+    "es_Latn_NI",
+    "es_NI"
+  }, {
+    "und_NL",
+    "nl_Latn_NL",
+    "nl"
+  }, {
+    "und_NO",
+    "nb_Latn_NO",
+    "nb"
+  }, {
+    "und_NP",
+    "ne_Deva_NP",
+    "ne"
+  }, {
+    "und_NR",
+    "en_Latn_NR",
+    "en_NR"
+  }, {
+    "und_NU",
+    "en_Latn_NU",
+    "en_NU"
+  }, {
+    "und_OM",
+    "ar_Arab_OM",
+    "ar_OM"
+  }, {
+    "und_Orya",
+    "or_Orya_IN",
+    "or"
+  }, {
+    "und_PA",
+    "es_Latn_PA",
+    "es_PA"
+  }, {
+    "und_PE",
+    "es_Latn_PE",
+    "es_PE"
+  }, {
+    "und_PF",
+    "fr_Latn_PF",
+    "fr_PF"
+  }, {
+    "und_PG",
+    "tpi_Latn_PG",
+    "tpi"
+  }, {
+    "und_PH",
+    "fil_Latn_PH",
+    "fil"
+  }, {
+    "und_PL",
+    "pl_Latn_PL",
+    "pl"
+  }, {
+    "und_PM",
+    "fr_Latn_PM",
+    "fr_PM"
+  }, {
+    "und_PR",
+    "es_Latn_PR",
+    "es_PR"
+  }, {
+    "und_PS",
+    "ar_Arab_PS",
+    "ar_PS"
+  }, {
+    "und_PT",
+    "pt_Latn_PT",
+    "pt_PT"
+  }, {
+    "und_PW",
+    "pau_Latn_PW",
+    "pau"
+  }, {
+    "und_PY",
+    "gn_Latn_PY",
+    "gn"
+  }, {
+    "und_QA",
+    "ar_Arab_QA",
+    "ar_QA"
+  }, {
+    "und_RE",
+    "fr_Latn_RE",
+    "fr_RE"
+  }, {
+    "und_RO",
+    "ro_Latn_RO",
+    "ro"
+  }, {
+    "und_RS",
+    "sr_Cyrl_RS",
+    "sr"
+  }, {
+    "und_RU",
+    "ru_Cyrl_RU",
+    "ru"
+  }, {
+    "und_RW",
+    "rw_Latn_RW",
+    "rw"
+  }, {
+    "und_SA",
+    "ar_Arab_SA",
+    "ar_SA"
+  }, {
+    "und_SD",
+    "ar_Arab_SD",
+    "ar_SD"
+  }, {
+    "und_SE",
+    "sv_Latn_SE",
+    "sv"
+  }, {
+    "und_SG",
+    "en_Latn_SG",
+    "en_SG"
+  }, {
+    "und_SI",
+    "sl_Latn_SI",
+    "sl"
+  }, {
+    "und_SJ",
+    "nb_Latn_SJ",
+    "nb_SJ"
+  }, {
+    "und_SK",
+    "sk_Latn_SK",
+    "sk"
+  }, {
+    "und_SM",
+    "it_Latn_SM",
+    "it_SM"
+  }, {
+    "und_SN",
+    "fr_Latn_SN",
+    "fr_SN"
+  }, {
+    "und_SO",
+    "so_Latn_SO",
+    "so"
+  }, {
+    "und_SR",
+    "nl_Latn_SR",
+    "nl_SR"
+  }, {
+    "und_ST",
+    "pt_Latn_ST",
+    "pt_ST"
+  }, {
+    "und_SV",
+    "es_Latn_SV",
+    "es_SV"
+  }, {
+    "und_SY",
+    "ar_Arab_SY",
+    "ar_SY"
+  }, {
+    "und_Sinh",
+    "si_Sinh_LK",
+    "si"
+  }, {
+    "und_TD",
+    "fr_Latn_TD",
+    "fr_TD"
+  }, {
+    "und_TG",
+    "fr_Latn_TG",
+    "fr_TG"
+  }, {
+    "und_TH",
+    "th_Thai_TH",
+    "th"
+  }, {
+    "und_TJ",
+    "tg_Cyrl_TJ",
+    "tg"
+  }, {
+    "und_TK",
+    "tkl_Latn_TK",
+    "tkl"
+  }, {
+    "und_TL",
+    "pt_Latn_TL",
+    "pt_TL"
+  }, {
+    "und_TM",
+    "tk_Latn_TM",
+    "tk"
+  }, {
+    "und_TN",
+    "ar_Arab_TN",
+    "ar_TN"
+  }, {
+    "und_TO",
+    "to_Latn_TO",
+    "to"
+  }, {
+    "und_TR",
+    "tr_Latn_TR",
+    "tr"
+  }, {
+    "und_TV",
+    "tvl_Latn_TV",
+    "tvl"
+  }, {
+    "und_TW",
+    "zh_Hant_TW",
+    "zh_TW"
+  }, {
+    "und_Taml",
+    "ta_Taml_IN",
+    "ta"
+  }, {
+    "und_Telu",
+    "te_Telu_IN",
+    "te"
+  }, {
+    "und_Thaa",
+    "dv_Thaa_MV",
+    "dv"
+  }, {
+    "und_Thai",
+    "th_Thai_TH",
+    "th"
+  }, {
+    "und_Tibt",
+    "bo_Tibt_CN",
+    "bo"
+  }, {
+    "und_UA",
+    "uk_Cyrl_UA",
+    "uk"
+  }, {
+    "und_UY",
+    "es_Latn_UY",
+    "es_UY"
+  }, {
+    "und_UZ",
+    "uz_Latn_UZ",
+    "uz"
+  }, {
+    "und_VA",
+    "it_Latn_VA",
+    "it_VA"
+  }, {
+    "und_VE",
+    "es_Latn_VE",
+    "es_VE"
+  }, {
+    "und_VN",
+    "vi_Latn_VN",
+    "vi"
+  }, {
+    "und_VU",
+    "bi_Latn_VU",
+    "bi"
+  }, {
+    "und_WF",
+    "fr_Latn_WF",
+    "fr_WF"
+  }, {
+    "und_WS",
+    "sm_Latn_WS",
+    "sm"
+  }, {
+    "und_YE",
+    "ar_Arab_YE",
+    "ar_YE"
+  }, {
+    "und_YT",
+    "fr_Latn_YT",
+    "fr_YT"
+  }, {
+    "und_Yiii",
+    "ii_Yiii_CN",
+    "ii"
+  }, {
+    "ur",
+    "ur_Arab_PK",
+    "ur"
+  }, {
+    "uz",
+    "uz_Latn_UZ",
+    "uz"
+  }, {
+    "uz_AF",
+    "uz_Arab_AF",
+    "uz_AF"
+  }, {
+    "uz_Arab",
+    "uz_Arab_AF",
+    "uz_AF"
+  }, {
+    "ve",
+    "ve_Latn_ZA",
+    "ve"
+  }, {
+    "vi",
+    "vi_Latn_VN",
+    "vi"
+  }, {
+    "wal",
+    "wal_Ethi_ET",
+    "wal"
+  }, {
+    "wo",
+    "wo_Latn_SN",
+    "wo"
+  }, {
+    "xh",
+    "xh_Latn_ZA",
+    "xh"
+  }, {
+    "yo",
+    "yo_Latn_NG",
+    "yo"
+  }, {
+    "zh",
+    "zh_Hans_CN",
+    "zh"
+  }, {
+    "zh_HK",
+    "zh_Hant_HK",
+    "zh_HK"
+  }, {
+    "zh_Hani",
+    "zh_Hani_CN", /* changed due to cldrbug 6204, may be an error */
+    "zh_Hani", /* changed due to cldrbug 6204, may be an error */
+  }, {
+    "zh_Hant",
+    "zh_Hant_TW",
+    "zh_TW"
+  }, {
+    "zh_MO",
+    "zh_Hant_MO",
+    "zh_MO"
+  }, {
+    "zh_TW",
+    "zh_Hant_TW",
+    "zh_TW"
+  }, {
+    "zu",
+    "zu_Latn_ZA",
+    "zu"
+  }, {
+    "und",
+    "en_Latn_US",
+    "en"
+  }, {
+    "und_ZZ",
+    "en_Latn_US",
+    "en"
+  }, {
+    "und_CN",
+    "zh_Hans_CN",
+    "zh"
+  }, {
+    "und_TW",
+    "zh_Hant_TW",
+    "zh_TW"
+  }, {
+    "und_HK",
+    "zh_Hant_HK",
+    "zh_HK"
+  }, {
+    "und_AQ",
+    "und_Latn_AQ",
+    "und_AQ"
+  }, {
+    "und_Zzzz",
+    "en_Latn_US",
+    "en"
+  }, {
+    "und_Zzzz_ZZ",
+    "en_Latn_US",
+    "en"
+  }, {
+    "und_Zzzz_CN",
+    "zh_Hans_CN",
+    "zh"
+  }, {
+    "und_Zzzz_TW",
+    "zh_Hant_TW",
+    "zh_TW"
+  }, {
+    "und_Zzzz_HK",
+    "zh_Hant_HK",
+    "zh_HK"
+  }, {
+    "und_Zzzz_AQ",
+    "und_Latn_AQ",
+    "und_AQ"
+  }, {
+    "und_Latn",
+    "en_Latn_US",
+    "en"
+  }, {
+    "und_Latn_ZZ",
+    "en_Latn_US",
+    "en"
+  }, {
+    "und_Latn_CN",
+    "za_Latn_CN",
+    "za"
+  }, {
+    "und_Latn_TW",
+    "trv_Latn_TW",
+    "trv"
+  }, {
+    "und_Latn_HK",
+    "zh_Latn_HK",
+    "zh_Latn_HK"
+  }, {
+    "und_Latn_AQ",
+    "und_Latn_AQ",
+    "und_AQ"
+  }, {
+    "und_Hans",
+    "zh_Hans_CN",
+    "zh"
+  }, {
+    "und_Hans_ZZ",
+    "zh_Hans_CN",
+    "zh"
+  }, {
+    "und_Hans_CN",
+    "zh_Hans_CN",
+    "zh"
+  }, {
+    "und_Hans_TW",
+    "zh_Hans_TW",
+    "zh_Hans_TW"
+  }, {
+    "und_Hans_HK",
+    "zh_Hans_HK",
+    "zh_Hans_HK"
+  }, {
+    "und_Hans_AQ",
+    "zh_Hans_AQ",
+    "zh_AQ"
+  }, {
+    "und_Hant",
+    "zh_Hant_TW",
+    "zh_TW"
+  }, {
+    "und_Hant_ZZ",
+    "zh_Hant_TW",
+    "zh_TW"
+  }, {
+    "und_Hant_CN",
+    "zh_Hant_CN",
+    "zh_Hant_CN"
+  }, {
+    "und_Hant_TW",
+    "zh_Hant_TW",
+    "zh_TW"
+  }, {
+    "und_Hant_HK",
+    "zh_Hant_HK",
+    "zh_HK"
+  }, {
+    "und_Hant_AQ",
+    "zh_Hant_AQ",
+    "zh_Hant_AQ"
+  }, {
+    "und_Moon",
+    "en_Moon_US",
+    "en_Moon"
+  }, {
+    "und_Moon_ZZ",
+    "en_Moon_US",
+    "en_Moon"
+  }, {
+    "und_Moon_CN",
+    "zh_Moon_CN",
+    "zh_Moon"
+  }, {
+    "und_Moon_TW",
+    "zh_Moon_TW",
+    "zh_Moon_TW"
+  }, {
+    "und_Moon_HK",
+    "zh_Moon_HK",
+    "zh_Moon_HK"
+  }, {
+    "und_Moon_AQ",
+    "und_Moon_AQ",
+    "und_Moon_AQ"
+  }, {
+    "es",
+    "es_Latn_ES",
+    "es"
+  }, {
+    "es_ZZ",
+    "es_Latn_ES",
+    "es"
+  }, {
+    "es_CN",
+    "es_Latn_CN",
+    "es_CN"
+  }, {
+    "es_TW",
+    "es_Latn_TW",
+    "es_TW"
+  }, {
+    "es_HK",
+    "es_Latn_HK",
+    "es_HK"
+  }, {
+    "es_AQ",
+    "es_Latn_AQ",
+    "es_AQ"
+  }, {
+    "es_Zzzz",
+    "es_Latn_ES",
+    "es"
+  }, {
+    "es_Zzzz_ZZ",
+    "es_Latn_ES",
+    "es"
+  }, {
+    "es_Zzzz_CN",
+    "es_Latn_CN",
+    "es_CN"
+  }, {
+    "es_Zzzz_TW",
+    "es_Latn_TW",
+    "es_TW"
+  }, {
+    "es_Zzzz_HK",
+    "es_Latn_HK",
+    "es_HK"
+  }, {
+    "es_Zzzz_AQ",
+    "es_Latn_AQ",
+    "es_AQ"
+  }, {
+    "es_Latn",
+    "es_Latn_ES",
+    "es"
+  }, {
+    "es_Latn_ZZ",
+    "es_Latn_ES",
+    "es"
+  }, {
+    "es_Latn_CN",
+    "es_Latn_CN",
+    "es_CN"
+  }, {
+    "es_Latn_TW",
+    "es_Latn_TW",
+    "es_TW"
+  }, {
+    "es_Latn_HK",
+    "es_Latn_HK",
+    "es_HK"
+  }, {
+    "es_Latn_AQ",
+    "es_Latn_AQ",
+    "es_AQ"
+  }, {
+    "es_Hans",
+    "es_Hans_ES",
+    "es_Hans"
+  }, {
+    "es_Hans_ZZ",
+    "es_Hans_ES",
+    "es_Hans"
+  }, {
+    "es_Hans_CN",
+    "es_Hans_CN",
+    "es_Hans_CN"
+  }, {
+    "es_Hans_TW",
+    "es_Hans_TW",
+    "es_Hans_TW"
+  }, {
+    "es_Hans_HK",
+    "es_Hans_HK",
+    "es_Hans_HK"
+  }, {
+    "es_Hans_AQ",
+    "es_Hans_AQ",
+    "es_Hans_AQ"
+  }, {
+    "es_Hant",
+    "es_Hant_ES",
+    "es_Hant"
+  }, {
+    "es_Hant_ZZ",
+    "es_Hant_ES",
+    "es_Hant"
+  }, {
+    "es_Hant_CN",
+    "es_Hant_CN",
+    "es_Hant_CN"
+  }, {
+    "es_Hant_TW",
+    "es_Hant_TW",
+    "es_Hant_TW"
+  }, {
+    "es_Hant_HK",
+    "es_Hant_HK",
+    "es_Hant_HK"
+  }, {
+    "es_Hant_AQ",
+    "es_Hant_AQ",
+    "es_Hant_AQ"
+  }, {
+    "es_Moon",
+    "es_Moon_ES",
+    "es_Moon"
+  }, {
+    "es_Moon_ZZ",
+    "es_Moon_ES",
+    "es_Moon"
+  }, {
+    "es_Moon_CN",
+    "es_Moon_CN",
+    "es_Moon_CN"
+  }, {
+    "es_Moon_TW",
+    "es_Moon_TW",
+    "es_Moon_TW"
+  }, {
+    "es_Moon_HK",
+    "es_Moon_HK",
+    "es_Moon_HK"
+  }, {
+    "es_Moon_AQ",
+    "es_Moon_AQ",
+    "es_Moon_AQ"
+  }, {
+    "zh",
+    "zh_Hans_CN",
+    "zh"
+  }, {
+    "zh_ZZ",
+    "zh_Hans_CN",
+    "zh"
+  }, {
+    "zh_CN",
+    "zh_Hans_CN",
+    "zh"
+  }, {
+    "zh_TW",
+    "zh_Hant_TW",
+    "zh_TW"
+  }, {
+    "zh_HK",
+    "zh_Hant_HK",
+    "zh_HK"
+  }, {
+    "zh_AQ",
+    "zh_Hans_AQ",
+    "zh_AQ"
+  }, {
+    "zh_MY",
+    "zh_Hans_MY",
+    "zh_MY"
+  }, {
+    "zh_Zzzz",
+    "zh_Hans_CN",
+    "zh"
+  }, {
+    "zh_Zzzz_ZZ",
+    "zh_Hans_CN",
+    "zh"
+  }, {
+    "zh_Zzzz_CN",
+    "zh_Hans_CN",
+    "zh"
+  }, {
+    "zh_Zzzz_TW",
+    "zh_Hant_TW",
+    "zh_TW"
+  }, {
+    "zh_Zzzz_HK",
+    "zh_Hant_HK",
+    "zh_HK"
+  }, {
+    "zh_Zzzz_AQ",
+    "zh_Hans_AQ",
+    "zh_AQ"
+  }, {
+    "zh_Latn",
+    "zh_Latn_CN",
+    "zh_Latn"
+  }, {
+    "zh_Latn_ZZ",
+    "zh_Latn_CN",
+    "zh_Latn"
+  }, {
+    "zh_Latn_CN",
+    "zh_Latn_CN",
+    "zh_Latn"
+  }, {
+    "zh_Latn_TW",
+    "zh_Latn_TW",
+    "zh_Latn_TW"
+  }, {
+    "zh_Latn_HK",
+    "zh_Latn_HK",
+    "zh_Latn_HK"
+  }, {
+    "zh_Latn_AQ",
+    "zh_Latn_AQ",
+    "zh_Latn_AQ"
+  }, {
+    "zh_Hans",
+    "zh_Hans_CN",
+    "zh"
+  }, {
+    "zh_Hans_ZZ",
+    "zh_Hans_CN",
+    "zh"
+  }, {
+    "zh_Hans_TW",
+    "zh_Hans_TW",
+    "zh_Hans_TW"
+  }, {
+    "zh_Hans_HK",
+    "zh_Hans_HK",
+    "zh_Hans_HK"
+  }, {
+    "zh_Hans_AQ",
+    "zh_Hans_AQ",
+    "zh_AQ"
+  }, {
+    "zh_Hant",
+    "zh_Hant_TW",
+    "zh_TW"
+  }, {
+    "zh_Hant_ZZ",
+    "zh_Hant_TW",
+    "zh_TW"
+  }, {
+    "zh_Hant_CN",
+    "zh_Hant_CN",
+    "zh_Hant_CN"
+  }, {
+    "zh_Hant_AQ",
+    "zh_Hant_AQ",
+    "zh_Hant_AQ"
+  }, {
+    "zh_Moon",
+    "zh_Moon_CN",
+    "zh_Moon"
+  }, {
+    "zh_Moon_ZZ",
+    "zh_Moon_CN",
+    "zh_Moon"
+  }, {
+    "zh_Moon_CN",
+    "zh_Moon_CN",
+    "zh_Moon"
+  }, {
+    "zh_Moon_TW",
+    "zh_Moon_TW",
+    "zh_Moon_TW"
+  }, {
+    "zh_Moon_HK",
+    "zh_Moon_HK",
+    "zh_Moon_HK"
+  }, {
+    "zh_Moon_AQ",
+    "zh_Moon_AQ",
+    "zh_Moon_AQ"
+  }, {
+    "art",
+    "",
+    ""
+  }, {
+    "art_ZZ",
+    "",
+    ""
+  }, {
+    "art_CN",
+    "",
+    ""
+  }, {
+    "art_TW",
+    "",
+    ""
+  }, {
+    "art_HK",
+    "",
+    ""
+  }, {
+    "art_AQ",
+    "",
+    ""
+  }, {
+    "art_Zzzz",
+    "",
+    ""
+  }, {
+    "art_Zzzz_ZZ",
+    "",
+    ""
+  }, {
+    "art_Zzzz_CN",
+    "",
+    ""
+  }, {
+    "art_Zzzz_TW",
+    "",
+    ""
+  }, {
+    "art_Zzzz_HK",
+    "",
+    ""
+  }, {
+    "art_Zzzz_AQ",
+    "",
+    ""
+  }, {
+    "art_Latn",
+    "",
+    ""
+  }, {
+    "art_Latn_ZZ",
+    "",
+    ""
+  }, {
+    "art_Latn_CN",
+    "",
+    ""
+  }, {
+    "art_Latn_TW",
+    "",
+    ""
+  }, {
+    "art_Latn_HK",
+    "",
+    ""
+  }, {
+    "art_Latn_AQ",
+    "",
+    ""
+  }, {
+    "art_Hans",
+    "",
+    ""
+  }, {
+    "art_Hans_ZZ",
+    "",
+    ""
+  }, {
+    "art_Hans_CN",
+    "",
+    ""
+  }, {
+    "art_Hans_TW",
+    "",
+    ""
+  }, {
+    "art_Hans_HK",
+    "",
+    ""
+  }, {
+    "art_Hans_AQ",
+    "",
+    ""
+  }, {
+    "art_Hant",
+    "",
+    ""
+  }, {
+    "art_Hant_ZZ",
+    "",
+    ""
+  }, {
+    "art_Hant_CN",
+    "",
+    ""
+  }, {
+    "art_Hant_TW",
+    "",
+    ""
+  }, {
+    "art_Hant_HK",
+    "",
+    ""
+  }, {
+    "art_Hant_AQ",
+    "",
+    ""
+  }, {
+    "art_Moon",
+    "",
+    ""
+  }, {
+    "art_Moon_ZZ",
+    "",
+    ""
+  }, {
+    "art_Moon_CN",
+    "",
+    ""
+  }, {
+    "art_Moon_TW",
+    "",
+    ""
+  }, {
+    "art_Moon_HK",
+    "",
+    ""
+  }, {
+    "art_Moon_AQ",
+    "",
+    ""
+  }, {
+    "de@collation=phonebook",
+    "de_Latn_DE@collation=phonebook",
+    "de@collation=phonebook"
+  }
+};
+
+typedef struct errorDataTag {
+    const char* tag;
+    const char* expected;
+    UErrorCode uerror;
+    int32_t  bufferSize;
+} errorData;
+
+const errorData maximizeErrors[] = {
+    {
+        "enfueiujhytdf",
+        NULL,
+        U_ILLEGAL_ARGUMENT_ERROR,
+        -1
+    },
+    {
+        "en_THUJIOGIURJHGJFURYHFJGURYYYHHGJURHG",
+        NULL,
+        U_ILLEGAL_ARGUMENT_ERROR,
+        -1
+    },
+    {
+        "en_THUJIOGIURJHGJFURYHFJGURYYYHHGJURHG",
+        NULL,
+        U_ILLEGAL_ARGUMENT_ERROR,
+        -1
+    },
+    {
+        "en_Latn_US_POSIX@currency=EURO",
+        "en_Latn_US_POSIX@currency=EURO",
+        U_BUFFER_OVERFLOW_ERROR,
+        29
+    },
+    {
+        "en_Latn_US_POSIX@currency=EURO",
+        "en_Latn_US_POSIX@currency=EURO",
+        U_STRING_NOT_TERMINATED_WARNING,
+        30
+    }
+};
+
+const errorData minimizeErrors[] = {
+    {
+        "enfueiujhytdf",
+        NULL,
+        U_ILLEGAL_ARGUMENT_ERROR,
+        -1
+    },
+    {
+        "en_THUJIOGIURJHGJFURYHFJGURYYYHHGJURHG",
+        NULL,
+        U_ILLEGAL_ARGUMENT_ERROR,
+        -1
+    },
+    {
+        "en_Latn_US_POSIX@currency=EURO",
+        "en__POSIX@currency=EURO",
+        U_BUFFER_OVERFLOW_ERROR,
+        22
+    },
+    {
+        "en_Latn_US_POSIX@currency=EURO",
+        "en__POSIX@currency=EURO",
+        U_STRING_NOT_TERMINATED_WARNING,
+        23
+    }
+};
+
+static int32_t getExpectedReturnValue(const errorData* data)
+{
+    if (data->uerror == U_BUFFER_OVERFLOW_ERROR ||
+        data->uerror == U_STRING_NOT_TERMINATED_WARNING)
+    {
+        return strlen(data->expected);
+    }
+    else
+    {
+        return -1;
+    }
+}
+
+static int32_t getBufferSize(const errorData* data, int32_t actualSize)
+{
+    if (data->expected == NULL)
+    {
+        return actualSize;
+    }
+    else if (data->bufferSize < 0)
+    {
+        return strlen(data->expected) + 1;
+    }
+    else
+    {
+        return data->bufferSize;
+    }
+}
+
+static void TestLikelySubtags()
+{
+    char buffer[ULOC_FULLNAME_CAPACITY + ULOC_KEYWORD_AND_VALUES_CAPACITY + 1];
+    int32_t i = 0;
+
+    for (; i < UPRV_LENGTHOF(basic_maximize_data); ++i)
+    {
+        UErrorCode status = U_ZERO_ERROR;
+        const char* const minimal = basic_maximize_data[i][0];
+        const char* const maximal = basic_maximize_data[i][1];
+
+        /* const int32_t length = */
+            uloc_addLikelySubtags(
+                minimal,
+                buffer,
+                sizeof(buffer),
+                &status);
+        if (U_FAILURE(status)) {
+            log_err_status(status, "  unexpected failure of uloc_addLikelySubtags(), minimal \"%s\" status %s\n", minimal, u_errorName(status));
+            status = U_ZERO_ERROR;
+        }
+        else if (uprv_strlen(maximal) == 0) {
+            if (uprv_stricmp(minimal, buffer) != 0) {
+                log_err("  unexpected maximal value \"%s\" in uloc_addLikelySubtags(), minimal \"%s\" = \"%s\"\n", maximal, minimal, buffer);
+            }
+        }
+        else if (uprv_stricmp(maximal, buffer) != 0) {
+            log_err("  maximal doesn't match expected %s in uloc_addLikelySubtags(), minimal \"%s\" = %s\n", maximal, minimal, buffer);
+        }
+    }
+
+    for (i = 0; i < UPRV_LENGTHOF(basic_minimize_data); ++i) {
+
+        UErrorCode status = U_ZERO_ERROR;
+        const char* const maximal = basic_minimize_data[i][0];
+        const char* const minimal = basic_minimize_data[i][1];
+
+        /* const int32_t length = */
+            uloc_minimizeSubtags(
+                maximal,
+                buffer,
+                sizeof(buffer),
+                &status);
+
+        if (U_FAILURE(status)) {
+            log_err_status(status, "  unexpected failure of uloc_MinimizeSubtags(), maximal \"%s\" status %s\n", maximal, u_errorName(status));
+            status = U_ZERO_ERROR;
+        }
+        else if (uprv_strlen(minimal) == 0) {
+            if (uprv_stricmp(maximal, buffer) != 0) {
+                log_err("  unexpected minimal value \"%s\" in uloc_minimizeSubtags(), maximal \"%s\" = \"%s\"\n", minimal, maximal, buffer);
+            }
+        }
+        else if (uprv_stricmp(minimal, buffer) != 0) {
+            log_err("  minimal doesn't match expected %s in uloc_MinimizeSubtags(), maximal \"%s\" = %s\n", minimal, maximal, buffer);
+        }
+    }
+
+    for (i = 0; i < UPRV_LENGTHOF(full_data); ++i) {
+
+        UErrorCode status = U_ZERO_ERROR;
+        const char* const minimal = full_data[i][0];
+        const char* const maximal = full_data[i][1];
+
+        /* const int32_t length = */
+            uloc_addLikelySubtags(
+                minimal,
+                buffer,
+                sizeof(buffer),
+                &status);
+        if (U_FAILURE(status)) {
+            log_err_status(status, "  unexpected failure of uloc_addLikelySubtags(), minimal \"%s\" status \"%s\"\n", minimal, u_errorName(status));
+            status = U_ZERO_ERROR;
+        }
+        else if (uprv_strlen(maximal) == 0) {
+            if (uprv_stricmp(minimal, buffer) != 0) {
+                log_err("  unexpected maximal value \"%s\" in uloc_addLikelySubtags(), minimal \"%s\" = \"%s\"\n", maximal, minimal, buffer);
+            }
+        }
+        else if (uprv_stricmp(maximal, buffer) != 0) {
+            log_err("  maximal doesn't match expected \"%s\" in uloc_addLikelySubtags(), minimal \"%s\" = \"%s\"\n", maximal, minimal, buffer);
+        }
+    }
+
+    for (i = 0; i < UPRV_LENGTHOF(full_data); ++i) {
+
+        UErrorCode status = U_ZERO_ERROR;
+        const char* const maximal = full_data[i][1];
+        const char* const minimal = full_data[i][2];
+
+        if (strlen(maximal) > 0) {
+
+            /* const int32_t length = */
+                uloc_minimizeSubtags(
+                    maximal,
+                    buffer,
+                    sizeof(buffer),
+                    &status);
+
+            if (U_FAILURE(status)) {
+                log_err_status(status, "  unexpected failure of uloc_minimizeSubtags(), maximal \"%s\" status %s\n", maximal, u_errorName(status));
+                status = U_ZERO_ERROR;
+            }
+            else if (uprv_strlen(minimal) == 0) {
+                if (uprv_stricmp(maximal, buffer) != 0) {
+                    log_err("  unexpected minimal value \"%s\" in uloc_minimizeSubtags(), maximal \"%s\" = \"%s\"\n", minimal, maximal, buffer);
+                }
+            }
+            else if (uprv_stricmp(minimal, buffer) != 0) {
+                log_err("  minimal doesn't match expected %s in uloc_MinimizeSubtags(), maximal \"%s\" = %s\n", minimal, maximal, buffer);
+            }
+        }
+    }
+
+    for (i = 0; i < UPRV_LENGTHOF(maximizeErrors); ++i) {
+
+        UErrorCode status = U_ZERO_ERROR;
+        const char* const minimal = maximizeErrors[i].tag;
+        const char* const maximal = maximizeErrors[i].expected;
+        const UErrorCode expectedStatus = maximizeErrors[i].uerror;
+        const int32_t expectedLength = getExpectedReturnValue(&maximizeErrors[i]);
+        const int32_t bufferSize = getBufferSize(&maximizeErrors[i], sizeof(buffer));
+
+        const int32_t length =
+            uloc_addLikelySubtags(
+                minimal,
+                buffer,
+                bufferSize,
+                &status);
+
+        if (status == U_ZERO_ERROR) {
+            log_err("  unexpected U_ZERO_ERROR for uloc_addLikelySubtags(), minimal \"%s\" expected status %s\n", minimal, u_errorName(expectedStatus));
+            status = U_ZERO_ERROR;
+        }
+        else if (status != expectedStatus) {
+            log_err_status(status, "  unexpected status for uloc_addLikelySubtags(), minimal \"%s\" expected status %s, but got %s\n", minimal, u_errorName(expectedStatus), u_errorName(status));
+        }
+        else if (length != expectedLength) {
+            log_err("  unexpected length for uloc_addLikelySubtags(), minimal \"%s\" expected length %d, but got %d\n", minimal, expectedLength, length);
+        }
+        else if (status == U_BUFFER_OVERFLOW_ERROR || status == U_STRING_NOT_TERMINATED_WARNING) {
+            if (uprv_strnicmp(maximal, buffer, bufferSize) != 0) {
+                log_err("  maximal doesn't match expected %s in uloc_addLikelySubtags(), minimal \"%s\" = %*s\n",
+                    maximal, minimal, (int)sizeof(buffer), buffer);
+            }
+        }
+    }
+
+    for (i = 0; i < UPRV_LENGTHOF(minimizeErrors); ++i) {
+
+        UErrorCode status = U_ZERO_ERROR;
+        const char* const maximal = minimizeErrors[i].tag;
+        const char* const minimal = minimizeErrors[i].expected;
+        const UErrorCode expectedStatus = minimizeErrors[i].uerror;
+        const int32_t expectedLength = getExpectedReturnValue(&minimizeErrors[i]);
+        const int32_t bufferSize = getBufferSize(&minimizeErrors[i], sizeof(buffer));
+
+        const int32_t length =
+            uloc_minimizeSubtags(
+                maximal,
+                buffer,
+                bufferSize,
+                &status);
+
+        if (status == U_ZERO_ERROR) {
+            log_err("  unexpected U_ZERO_ERROR for uloc_minimizeSubtags(), maximal \"%s\" expected status %s\n", maximal, u_errorName(expectedStatus));
+            status = U_ZERO_ERROR;
+        }
+        else if (status != expectedStatus) {
+            log_err_status(status, "  unexpected status for uloc_minimizeSubtags(), maximal \"%s\" expected status %s, but got %s\n", maximal, u_errorName(expectedStatus), u_errorName(status));
+        }
+        else if (length != expectedLength) {
+            log_err("  unexpected length for uloc_minimizeSubtags(), maximal \"%s\" expected length %d, but got %d\n", maximal, expectedLength, length);
+        }
+        else if (status == U_BUFFER_OVERFLOW_ERROR || status == U_STRING_NOT_TERMINATED_WARNING) {
+            if (uprv_strnicmp(minimal, buffer, bufferSize) != 0) {
+                log_err("  minimal doesn't match expected \"%s\" in uloc_minimizeSubtags(), minimal \"%s\" = \"%*s\"\n",
+                    minimal, maximal, (int)sizeof(buffer), buffer);
+            }
+        }
+    }
+}
+
+const char* const locale_to_langtag[][3] = {
+    {"",            "und",          "und"},
+    {"en",          "en",           "en"},
+    {"en_US",       "en-US",        "en-US"},
+    {"iw_IL",       "he-IL",        "he-IL"},
+    {"sr_Latn_SR",  "sr-Latn-SR",   "sr-Latn-SR"},
+    {"en__POSIX",   "en-u-va-posix", "en-u-va-posix"},
+    {"en_POSIX",    "en-u-va-posix", "en-u-va-posix"},
+    {"en_US_POSIX_VAR", "en-US-posix-x-lvariant-var", NULL},  /* variant POSIX_VAR is processed as regular variant */
+    {"en_US_VAR_POSIX", "en-US-x-lvariant-var-posix", NULL},  /* variant VAR_POSIX is processed as regular variant */
+    {"en_US_POSIX@va=posix2",   "en-US-u-va-posix2",  "en-US-u-va-posix2"},           /* if keyword va=xxx already exists, variant POSIX is simply dropped */
+    {"en_US_POSIX@ca=japanese",  "en-US-u-ca-japanese-va-posix", "en-US-u-ca-japanese-va-posix"},
+    {"und_555",     "und-555",      "und-555"},
+    {"123",         "und",          NULL},
+    {"%$#&",        "und",          NULL},
+    {"_Latn",       "und-Latn",     "und-Latn"},
+    {"_DE",         "und-DE",       "und-DE"},
+    {"und_FR",      "und-FR",       "und-FR"},
+    {"th_TH_TH",    "th-TH-x-lvariant-th", NULL},
+    {"bogus",       "bogus",        "bogus"},
+    {"foooobarrr",  "und",          NULL},
+    {"az_AZ_CYRL",  "az-Cyrl-AZ",   "az-Cyrl-AZ"},
+    {"aa_BB_CYRL",  "aa-BB-x-lvariant-cyrl", NULL},
+    {"en_US_1234",  "en-US-1234",   "en-US-1234"},
+    {"en_US_VARIANTA_VARIANTB", "en-US-varianta-variantb",  "en-US-varianta-variantb"},
+    {"ja__9876_5432",   "ja-9876-5432", "ja-9876-5432"},
+    {"zh_Hant__VAR",    "zh-Hant-x-lvariant-var", NULL},
+    {"es__BADVARIANT_GOODVAR",  "es-goodvar",   NULL},
+    {"en@calendar=gregorian",   "en-u-ca-gregory",  "en-u-ca-gregory"},
+    {"de@collation=phonebook;calendar=gregorian",   "de-u-ca-gregory-co-phonebk",   "de-u-ca-gregory-co-phonebk"},
+    {"th@numbers=thai;z=extz;x=priv-use;a=exta",   "th-a-exta-u-nu-thai-z-extz-x-priv-use", "th-a-exta-u-nu-thai-z-extz-x-priv-use"},
+    {"en@timezone=America/New_York;calendar=japanese",    "en-u-ca-japanese-tz-usnyc",    "en-u-ca-japanese-tz-usnyc"},
+    {"en@timezone=US/Eastern",  "en-u-tz-usnyc",    "en-u-tz-usnyc"},
+    {"en@x=x-y-z;a=a-b-c",  "en-x-x-y-z",   NULL},
+    {"it@collation=badcollationtype;colStrength=identical;cu=usd-eur", "it-u-cu-usd-eur-ks-identic",  NULL},
+    {"en_US_POSIX", "en-US-u-va-posix", "en-US-u-va-posix"},
+    {"en_US_POSIX@calendar=japanese;currency=EUR","en-US-u-ca-japanese-cu-eur-va-posix", "en-US-u-ca-japanese-cu-eur-va-posix"},
+    {"@x=elmer",    "x-elmer",      "x-elmer"},
+    {"en@x=elmer",  "en-x-elmer",   "en-x-elmer"},
+    {"@x=elmer;a=exta", "und-a-exta-x-elmer",   "und-a-exta-x-elmer"},
+    {"en_US@attribute=attr1-attr2;calendar=gregorian", "en-US-u-attr1-attr2-ca-gregory", "en-US-u-attr1-attr2-ca-gregory"},
+    /* #12671 */
+    {"en@a=bar;attribute=baz",  "en-a-bar-u-baz",   "en-a-bar-u-baz"},
+    {"en@a=bar;attribute=baz;x=u-foo",  "en-a-bar-u-baz-x-u-foo",   "en-a-bar-u-baz-x-u-foo"},
+    {"en@attribute=baz",    "en-u-baz", "en-u-baz"},
+    {"en@attribute=baz;calendar=islamic-civil", "en-u-baz-ca-islamic-civil",    "en-u-baz-ca-islamic-civil"},
+    {"en@a=bar;calendar=islamic-civil;x=u-foo", "en-a-bar-u-ca-islamic-civil-x-u-foo",  "en-a-bar-u-ca-islamic-civil-x-u-foo"},
+    {"en@a=bar;attribute=baz;calendar=islamic-civil;x=u-foo",   "en-a-bar-u-baz-ca-islamic-civil-x-u-foo",  "en-a-bar-u-baz-ca-islamic-civil-x-u-foo"},
+    {NULL,          NULL,           NULL}
+};
+
+static void TestToLanguageTag(void) {
+    char langtag[256];
+    int32_t i;
+    UErrorCode status;
+    int32_t len;
+    const char *inloc;
+    const char *expected;
+
+    for (i = 0; locale_to_langtag[i][0] != NULL; i++) {
+        inloc = locale_to_langtag[i][0];
+
+        /* testing non-strict mode */
+        status = U_ZERO_ERROR;
+        langtag[0] = 0;
+        expected = locale_to_langtag[i][1];
+
+        len = uloc_toLanguageTag(inloc, langtag, sizeof(langtag), FALSE, &status);
+        (void)len;    /* Suppress set but not used warning. */
+        if (U_FAILURE(status)) {
+            if (expected != NULL) {
+                log_err("Error returned by uloc_toLanguageTag for locale id [%s] - error: %s\n",
+                    inloc, u_errorName(status));
+            }
+        } else {
+            if (expected == NULL) {
+                log_err("Error should be returned by uloc_toLanguageTag for locale id [%s], but [%s] is returned without errors\n",
+                    inloc, langtag);
+            } else if (uprv_strcmp(langtag, expected) != 0) {
+                log_data_err("uloc_toLanguageTag returned language tag [%s] for input locale [%s] - expected: [%s]. Are you missing data?\n",
+                    langtag, inloc, expected);
+            }
+        }
+
+        /* testing strict mode */
+        status = U_ZERO_ERROR;
+        langtag[0] = 0;
+        expected = locale_to_langtag[i][2];
+
+        len = uloc_toLanguageTag(inloc, langtag, sizeof(langtag), TRUE, &status);
+        if (U_FAILURE(status)) {
+            if (expected != NULL) {
+                log_data_err("Error returned by uloc_toLanguageTag {strict} for locale id [%s] - error: %s Are you missing data?\n",
+                    inloc, u_errorName(status));
+            }
+        } else {
+            if (expected == NULL) {
+                log_err("Error should be returned by uloc_toLanguageTag {strict} for locale id [%s], but [%s] is returned without errors\n",
+                    inloc, langtag);
+            } else if (uprv_strcmp(langtag, expected) != 0) {
+                log_err("uloc_toLanguageTag {strict} returned language tag [%s] for input locale [%s] - expected: [%s]\n",
+                    langtag, inloc, expected);
+            }
+        }
+    }
+}
+
+#define FULL_LENGTH -1
+static const struct {
+    const char  *bcpID;
+    const char  *locID;
+    int32_t     len;
+} langtag_to_locale[] = {
+    {"en",                  "en",                   FULL_LENGTH},
+    {"en-us",               "en_US",                FULL_LENGTH},
+    {"und-US",              "_US",                  FULL_LENGTH},
+    {"und-latn",            "_Latn",                FULL_LENGTH},
+    {"en-US-posix",         "en_US_POSIX",          FULL_LENGTH},
+    {"de-de_euro",          "de",                   2},
+    {"kok-IN",              "kok_IN",               FULL_LENGTH},
+    {"123",                 "",                     0},
+    {"en_us",               "",                     0},
+    {"en-latn-x",           "en_Latn",              7},
+    {"art-lojban",          "jbo",                  FULL_LENGTH},
+    {"zh-hakka",            "hak",                  FULL_LENGTH},
+    {"zh-cmn-CH",           "cmn_CH",               FULL_LENGTH},
+    {"xxx-yy",              "xxx_YY",               FULL_LENGTH},
+    {"fr-234",              "fr_234",               FULL_LENGTH},
+    {"i-default",           "en@x=i-default",       FULL_LENGTH},
+    {"i-test",              "",                     0},
+    {"ja-jp-jp",            "ja_JP",                5},
+    {"bogus",               "bogus",                FULL_LENGTH},
+    {"boguslang",           "",                     0},
+    {"EN-lATN-us",          "en_Latn_US",           FULL_LENGTH},
+    {"und-variant-1234",    "__VARIANT_1234",       FULL_LENGTH},
+    {"und-varzero-var1-vartwo", "__VARZERO",        11},
+    {"en-u-ca-gregory",     "en@calendar=gregorian",    FULL_LENGTH},
+    {"en-U-cu-USD",         "en@currency=usd",      FULL_LENGTH},
+    {"en-US-u-va-posix",    "en_US_POSIX",          FULL_LENGTH},
+    {"en-us-u-ca-gregory-va-posix", "en_US_POSIX@calendar=gregorian",   FULL_LENGTH},
+    {"en-us-posix-u-va-posix",   "en_US_POSIX@va=posix",    FULL_LENGTH},
+    {"en-us-u-va-posix2",        "en_US@va=posix2",         FULL_LENGTH},
+    {"en-us-vari1-u-va-posix",   "en_US_VARI1@va=posix",    FULL_LENGTH},
+    {"ar-x-1-2-3",          "ar@x=1-2-3",           FULL_LENGTH},
+    {"fr-u-nu-latn-cu-eur", "fr@currency=eur;numbers=latn", FULL_LENGTH},
+    {"de-k-kext-u-co-phonebk-nu-latn",  "de@collation=phonebook;k=kext;numbers=latn",   FULL_LENGTH},
+    {"ja-u-cu-jpy-ca-jp",   "ja@calendar=yes;currency=jpy;jp=yes",  FULL_LENGTH},
+    {"en-us-u-tz-usnyc",    "en_US@timezone=America/New_York",  FULL_LENGTH},
+    {"und-a-abc-def",       "und@a=abc-def",        FULL_LENGTH},
+    {"zh-u-ca-chinese-x-u-ca-chinese",  "zh@calendar=chinese;x=u-ca-chinese",   FULL_LENGTH},
+    {"x-elmer",             "@x=elmer",             FULL_LENGTH},
+    {"en-US-u-attr1-attr2-ca-gregory", "en_US@attribute=attr1-attr2;calendar=gregorian",    FULL_LENGTH},
+    {"sr-u-kn",             "sr@colnumeric=yes",    FULL_LENGTH},
+    {"de-u-kn-co-phonebk",  "de@collation=phonebook;colnumeric=yes",    FULL_LENGTH},
+    {"en-u-attr2-attr1-kn-kb",  "en@attribute=attr1-attr2;colbackwards=yes;colnumeric=yes", FULL_LENGTH},
+    {"ja-u-ijkl-efgh-abcd-ca-japanese-xx-yyy-zzz-kn",   "ja@attribute=abcd-efgh-ijkl;calendar=japanese;colnumeric=yes;xx=yyy-zzz",  FULL_LENGTH},
+    {"de-u-xc-xphonebk-co-phonebk-ca-buddhist-mo-very-lo-extensi-xd-that-de-should-vc-probably-xz-killthebuffer",
+     "de@calendar=buddhist;collation=phonebook;de=should;lo=extensi;mo=very;vc=probably;xc=xphonebk;xd=that;xz=yes", 91},
+    /* #12761 */
+    {"en-a-bar-u-baz",      "en@a=bar;attribute=baz",   FULL_LENGTH},
+    {"en-a-bar-u-baz-x-u-foo",  "en@a=bar;attribute=baz;x=u-foo",   FULL_LENGTH},
+    {"en-u-baz",            "en@attribute=baz",     FULL_LENGTH},
+    {"en-u-baz-ca-islamic-civil",   "en@attribute=baz;calendar=islamic-civil",  FULL_LENGTH},
+    {"en-a-bar-u-ca-islamic-civil-x-u-foo", "en@a=bar;calendar=islamic-civil;x=u-foo",  FULL_LENGTH},
+    {"en-a-bar-u-baz-ca-islamic-civil-x-u-foo", "en@a=bar;attribute=baz;calendar=islamic-civil;x=u-foo",    FULL_LENGTH},
+    {"und-Arab-u-em-emoji", "_Arab@em=emoji", FULL_LENGTH},
+    {"und-Latn-u-em-emoji", "_Latn@em=emoji", FULL_LENGTH},
+    {"und-Latn-DE-u-em-emoji", "_Latn_DE@em=emoji", FULL_LENGTH},
+    {"und-Zzzz-DE-u-em-emoji", "_Zzzz_DE@em=emoji", FULL_LENGTH},
+    {"und-DE-u-em-emoji", "_DE@em=emoji", FULL_LENGTH},
+    {NULL,          NULL,           0}
+};
+
+static void TestForLanguageTag(void) {
+    char locale[256];
+    int32_t i;
+    UErrorCode status;
+    int32_t parsedLen;
+    int32_t expParsedLen;
+
+    for (i = 0; langtag_to_locale[i].bcpID != NULL; i++) {
+        status = U_ZERO_ERROR;
+        locale[0] = 0;
+        expParsedLen = langtag_to_locale[i].len;
+        if (expParsedLen == FULL_LENGTH) {
+            expParsedLen = uprv_strlen(langtag_to_locale[i].bcpID);
+        }
+        uloc_forLanguageTag(langtag_to_locale[i].bcpID, locale, sizeof(locale), &parsedLen, &status);
+        if (U_FAILURE(status)) {
+            log_err_status(status, "Error returned by uloc_forLanguageTag for language tag [%s] - error: %s\n",
+                langtag_to_locale[i].bcpID, u_errorName(status));
+        } else {
+            if (uprv_strcmp(langtag_to_locale[i].locID, locale) != 0) {
+                log_data_err("uloc_forLanguageTag returned locale [%s] for input language tag [%s] - expected: [%s]\n",
+                    locale, langtag_to_locale[i].bcpID, langtag_to_locale[i].locID);
+            }
+            if (parsedLen != expParsedLen) {
+                log_err("uloc_forLanguageTag parsed length of %d for input language tag [%s] - expected parsed length: %d\n",
+                    parsedLen, langtag_to_locale[i].bcpID, expParsedLen);
+            }
+        }
+    }
+}
+
+static void TestToUnicodeLocaleKey(void)
+{
+    /* $IN specifies the result should be the input pointer itself */
+    static const char* DATA[][2] = {
+        {"calendar",    "ca"},
+        {"CALEndar",    "ca"},  /* difference casing */
+        {"ca",          "ca"},  /* bcp key itself */
+        {"kv",          "kv"},  /* no difference between legacy and bcp */
+        {"foo",         NULL},  /* unknown, bcp ill-formed */
+        {"ZZ",          "$IN"}, /* unknown, bcp well-formed -  */
+        {NULL,          NULL}
+    };
+
+    int32_t i;
+    for (i = 0; DATA[i][0] != NULL; i++) {
+        const char* keyword = DATA[i][0];
+        const char* expected = DATA[i][1];
+        const char* bcpKey = NULL;
+
+        bcpKey = uloc_toUnicodeLocaleKey(keyword);
+        if (expected == NULL) {
+            if (bcpKey != NULL) {
+                log_err("toUnicodeLocaleKey: keyword=%s => %s, expected=NULL\n", keyword, bcpKey);
+            }
+        } else if (bcpKey == NULL) {
+            log_data_err("toUnicodeLocaleKey: keyword=%s => NULL, expected=%s\n", keyword, expected);
+        } else if (uprv_strcmp(expected, "$IN") == 0) {
+            if (bcpKey != keyword) {
+                log_err("toUnicodeLocaleKey: keyword=%s => %s, expected=%s(input pointer)\n", keyword, bcpKey, keyword);
+            }
+        } else if (uprv_strcmp(bcpKey, expected) != 0) {
+            log_err("toUnicodeLocaleKey: keyword=%s => %s, expected=%s\n", keyword, bcpKey, expected);
+        }
+    }
+}
+
+static void TestToLegacyKey(void)
+{
+    /* $IN specifies the result should be the input pointer itself */
+    static const char* DATA[][2] = {
+        {"kb",          "colbackwards"},
+        {"kB",          "colbackwards"},    /* different casing */
+        {"Collation",   "collation"},   /* keyword itself with different casing */
+        {"kv",          "kv"},  /* no difference between legacy and bcp */
+        {"foo",         "$IN"}, /* unknown, bcp ill-formed */
+        {"ZZ",          "$IN"}, /* unknown, bcp well-formed */
+        {"e=mc2",       NULL},  /* unknown, bcp/legacy ill-formed */
+        {NULL,          NULL}
+    };
+
+    int32_t i;
+    for (i = 0; DATA[i][0] != NULL; i++) {
+        const char* keyword = DATA[i][0];
+        const char* expected = DATA[i][1];
+        const char* legacyKey = NULL;
+
+        legacyKey = uloc_toLegacyKey(keyword);
+        if (expected == NULL) {
+            if (legacyKey != NULL) {
+                log_err("toLegacyKey: keyword=%s => %s, expected=NULL\n", keyword, legacyKey);
+            }
+        } else if (legacyKey == NULL) {
+            log_err("toLegacyKey: keyword=%s => NULL, expected=%s\n", keyword, expected);
+        } else if (uprv_strcmp(expected, "$IN") == 0) {
+            if (legacyKey != keyword) {
+                log_err("toLegacyKey: keyword=%s => %s, expected=%s(input pointer)\n", keyword, legacyKey, keyword);
+            }
+        } else if (uprv_strcmp(legacyKey, expected) != 0) {
+            log_data_err("toUnicodeLocaleKey: keyword=%s, %s, expected=%s\n", keyword, legacyKey, expected);
+        }
+    }
+}
+
+static void TestToUnicodeLocaleType(void)
+{
+    /* $IN specifies the result should be the input pointer itself */
+    static const char* DATA[][3] = {
+        {"tz",              "Asia/Kolkata",     "inccu"},
+        {"calendar",        "gregorian",        "gregory"},
+        {"ca",              "gregorian",        "gregory"},
+        {"ca",              "Gregorian",        "gregory"},
+        {"ca",              "buddhist",         "buddhist"},
+        {"Calendar",        "Japanese",         "japanese"},
+        {"calendar",        "Islamic-Civil",    "islamic-civil"},
+        {"calendar",        "islamicc",         "islamic-civil"},   /* bcp type alias */
+        {"colalternate",    "NON-IGNORABLE",    "noignore"},
+        {"colcaselevel",    "yes",              "true"},
+        {"rg",              "GBzzzz",           "$IN"},
+        {"tz",              "america/new_york", "usnyc"},
+        {"tz",              "Asia/Kolkata",     "inccu"},
+        {"timezone",        "navajo",           "usden"},
+        {"ca",              "aaaa",             "$IN"},     /* unknown type, well-formed type */
+        {"ca",              "gregory-japanese-islamic", "$IN"}, /* unknown type, well-formed type */
+        {"zz",              "gregorian",        NULL},      /* unknown key, ill-formed type */
+        {"co",              "foo-",             NULL},      /* unknown type, ill-formed type */
+        {"variableTop",     "00A0",             "$IN"},     /* valid codepoints type */
+        {"variableTop",     "wxyz",             "$IN"},     /* invalid codepoints type - return as is for now */
+        {"kr",              "space-punct",      "space-punct"}, /* valid reordercode type */
+        {"kr",              "digit-spacepunct", NULL},      /* invalid (bcp ill-formed) reordercode type */
+        {NULL,              NULL,               NULL}
+    };
+
+    int32_t i;
+    for (i = 0; DATA[i][0] != NULL; i++) {
+        const char* keyword = DATA[i][0];
+        const char* value = DATA[i][1];
+        const char* expected = DATA[i][2];
+        const char* bcpType = NULL;
+
+        bcpType = uloc_toUnicodeLocaleType(keyword, value);
+        if (expected == NULL) {
+            if (bcpType != NULL) {
+                log_err("toUnicodeLocaleType: keyword=%s, value=%s => %s, expected=NULL\n", keyword, value, bcpType);
+            }
+        } else if (bcpType == NULL) {
+            log_data_err("toUnicodeLocaleType: keyword=%s, value=%s => NULL, expected=%s\n", keyword, value, expected);
+        } else if (uprv_strcmp(expected, "$IN") == 0) {
+            if (bcpType != value) {
+                log_err("toUnicodeLocaleType: keyword=%s, value=%s => %s, expected=%s(input pointer)\n", keyword, value, bcpType, value);
+            }
+        } else if (uprv_strcmp(bcpType, expected) != 0) {
+            log_data_err("toUnicodeLocaleType: keyword=%s, value=%s => %s, expected=%s\n", keyword, value, bcpType, expected);
+        }
+    }
+}
+
+static void TestToLegacyType(void)
+{
+    /* $IN specifies the result should be the input pointer itself */
+    static const char* DATA[][3] = {
+        {"calendar",        "gregory",          "gregorian"},
+        {"ca",              "gregory",          "gregorian"},
+        {"ca",              "Gregory",          "gregorian"},
+        {"ca",              "buddhist",         "buddhist"},
+        {"Calendar",        "Japanese",         "japanese"},
+        {"calendar",        "Islamic-Civil",    "islamic-civil"},
+        {"calendar",        "islamicc",         "islamic-civil"},   /* bcp type alias */
+        {"colalternate",    "noignore",         "non-ignorable"},
+        {"colcaselevel",    "true",             "yes"},
+        {"rg",              "gbzzzz",           "gbzzzz"},
+        {"tz",              "usnyc",            "America/New_York"},
+        {"tz",              "inccu",            "Asia/Calcutta"},
+        {"timezone",        "usden",            "America/Denver"},
+        {"timezone",        "usnavajo",         "America/Denver"},  /* bcp type alias */
+        {"colstrength",     "quarternary",      "quaternary"},  /* type alias */
+        {"ca",              "aaaa",             "$IN"}, /* unknown type */
+        {"calendar",        "gregory-japanese-islamic", "$IN"}, /* unknown type, well-formed type */
+        {"zz",              "gregorian",        "$IN"}, /* unknown key, bcp ill-formed type */
+        {"ca",              "gregorian-calendar",   "$IN"}, /* known key, bcp ill-formed type */
+        {"co",              "e=mc2",            NULL},  /* known key, ill-formed bcp/legacy type */
+        {"variableTop",     "00A0",             "$IN"},     /* valid codepoints type */
+        {"variableTop",     "wxyz",             "$IN"},    /* invalid codepoints type - return as is for now */
+        {"kr",              "space-punct",      "space-punct"}, /* valid reordercode type */
+        {"kr",              "digit-spacepunct", "digit-spacepunct"},    /* invalid reordercode type, but ok for legacy syntax */
+        {NULL,              NULL,               NULL}
+    };
+
+    int32_t i;
+    for (i = 0; DATA[i][0] != NULL; i++) {
+        const char* keyword = DATA[i][0];
+        const char* value = DATA[i][1];
+        const char* expected = DATA[i][2];
+        const char* legacyType = NULL;
+
+        legacyType = uloc_toLegacyType(keyword, value);
+        if (expected == NULL) {
+            if (legacyType != NULL) {
+                log_err("toLegacyType: keyword=%s, value=%s => %s, expected=NULL\n", keyword, value, legacyType);
+            }
+        } else if (legacyType == NULL) {
+            log_err("toLegacyType: keyword=%s, value=%s => NULL, expected=%s\n", keyword, value, expected);
+        } else if (uprv_strcmp(expected, "$IN") == 0) {
+            if (legacyType != value) {
+                log_err("toLegacyType: keyword=%s, value=%s => %s, expected=%s(input pointer)\n", keyword, value, legacyType, value);
+            }
+        } else if (uprv_strcmp(legacyType, expected) != 0) {
+            log_data_err("toLegacyType: keyword=%s, value=%s => %s, expected=%s\n", keyword, value, legacyType, expected);
+        } else {
+            log_verbose("toLegacyType: keyword=%s, value=%s => %s\n", keyword, value, legacyType);
+        }
+    }
+}
+
+
+
+static void test_unicode_define(const char *namech, char ch, const char *nameu, UChar uch)
+{
+  UChar asUch[1];
+  asUch[0]=0;
+  log_verbose("Testing whether %s[\\x%02x,'%c'] == %s[U+%04X]\n", namech, ch,(int)ch, nameu, (int) uch);
+  u_charsToUChars(&ch, asUch, 1);
+  if(asUch[0] != uch) {
+    log_err("FAIL:  %s[\\x%02x,'%c'] maps to U+%04X, but %s = U+%04X\n", namech, ch, (int)ch, (int)asUch[0], nameu, (int)uch);
+  } else {
+    log_verbose(" .. OK, == U+%04X\n", (int)asUch[0]);
+  }
+}
+
+#define TEST_UNICODE_DEFINE(x,y) test_unicode_define(#x, (char)(x), #y, (UChar)(y))
+
+static void TestUnicodeDefines(void) {
+  TEST_UNICODE_DEFINE(ULOC_KEYWORD_SEPARATOR, ULOC_KEYWORD_SEPARATOR_UNICODE);
+  TEST_UNICODE_DEFINE(ULOC_KEYWORD_ASSIGN, ULOC_KEYWORD_ASSIGN_UNICODE);
+  TEST_UNICODE_DEFINE(ULOC_KEYWORD_ITEM_SEPARATOR, ULOC_KEYWORD_ITEM_SEPARATOR_UNICODE);
+}
+
+static void TestIsRightToLeft() {
+    // API test only. More test cases in intltest/LocaleTest.
+    if(uloc_isRightToLeft("root") || !uloc_isRightToLeft("EN-HEBR")) {
+        log_err("uloc_isRightToLeft() failed");
+    }
+}
+
+typedef struct {
+    const char * badLocaleID;
+    const char * displayLocale;
+    const char * expectedName;
+    UErrorCode   expectedStatus;
+} BadLocaleItem;
+
+static const BadLocaleItem badLocaleItems[] = {
+    { "-9223372036854775808", "en", "9223372036854775808", U_USING_DEFAULT_WARNING },
+    /* add more in the future */
+    { NULL, NULL, NULL, U_ZERO_ERROR } /* terminator */
+};
+
+enum { kUBufDispNameMax = 128, kBBufDispNameMax = 256 };
+
+static void TestBadLocaleIDs() {
+    const BadLocaleItem* itemPtr;
+    for (itemPtr = badLocaleItems; itemPtr->badLocaleID != NULL; itemPtr++) {
+        UChar ubufExpect[kUBufDispNameMax], ubufGet[kUBufDispNameMax];
+        UErrorCode status = U_ZERO_ERROR;
+        int32_t ulenExpect = u_unescape(itemPtr->expectedName, ubufExpect, kUBufDispNameMax);
+        int32_t ulenGet = uloc_getDisplayName(itemPtr->badLocaleID, itemPtr->displayLocale, ubufGet, kUBufDispNameMax, &status);
+        if (status != itemPtr->expectedStatus ||
+                (U_SUCCESS(status) && (ulenGet != ulenExpect || u_strncmp(ubufGet, ubufExpect, ulenExpect) != 0))) {
+            char bbufExpect[kBBufDispNameMax], bbufGet[kBBufDispNameMax];
+            u_austrncpy(bbufExpect, ubufExpect, ulenExpect);
+            u_austrncpy(bbufGet, ubufGet, ulenGet);
+            log_err("FAIL: For localeID %s, displayLocale %s, calling uloc_getDisplayName:\n"
+                    "    expected status %-26s, name (len %2d): %s\n"
+                    "    got      status %-26s, name (len %2d): %s\n",
+                    itemPtr->badLocaleID, itemPtr->displayLocale,
+                    u_errorName(itemPtr->expectedStatus), ulenExpect, bbufExpect,
+                    u_errorName(status), ulenGet, bbufGet );
+        }
+    }
+}
+
+typedef enum UldnNameType {
+    TEST_ULDN_LOCALE,
+    TEST_ULDN_LANGUAGE,
+    TEST_ULDN_SCRIPT,
+    TEST_ULDN_REGION,
+} UldnNameType;
+
+typedef struct {
+    const char * localeToName; // NULL to terminate a list of these
+    UldnNameType nameType;
+    const char * expectResult;
+} UldnItem;
+
+typedef struct {
+    const char *            displayLocale;
+    const UDisplayContext * displayOptions; // set of 3 UDisplayContext items
+    const UldnItem *        testItems;
+    int32_t                 countItems;
+} UldnLocAndOpts;
+
+static const UDisplayContext optStdMidLong[3] = {UDISPCTX_STANDARD_NAMES, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE,    UDISPCTX_LENGTH_FULL}; 
+static const UDisplayContext optStdMidShrt[3] = {UDISPCTX_STANDARD_NAMES, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE,    UDISPCTX_LENGTH_SHORT}; 
+static const UDisplayContext optDiaMidLong[3] = {UDISPCTX_DIALECT_NAMES,  UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE,    UDISPCTX_LENGTH_FULL}; 
+static const UDisplayContext optDiaMidShrt[3] = {UDISPCTX_DIALECT_NAMES,  UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE,    UDISPCTX_LENGTH_SHORT}; 
+
+static const UDisplayContext optStdBegLong[3] = {UDISPCTX_STANDARD_NAMES, UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, UDISPCTX_LENGTH_FULL}; 
+static const UDisplayContext optStdBegShrt[3] = {UDISPCTX_STANDARD_NAMES, UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, UDISPCTX_LENGTH_SHORT}; 
+static const UDisplayContext optDiaBegLong[3] = {UDISPCTX_DIALECT_NAMES,  UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, UDISPCTX_LENGTH_FULL}; 
+static const UDisplayContext optDiaBegShrt[3] = {UDISPCTX_DIALECT_NAMES,  UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, UDISPCTX_LENGTH_SHORT}; 
+
+static const UDisplayContext optStdLstLong[3] = {UDISPCTX_STANDARD_NAMES, UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU,       UDISPCTX_LENGTH_FULL}; 
+static const UDisplayContext optStdLstShrt[3] = {UDISPCTX_STANDARD_NAMES, UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU,       UDISPCTX_LENGTH_SHORT}; 
+static const UDisplayContext optDiaLstLong[3] = {UDISPCTX_DIALECT_NAMES,  UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU,       UDISPCTX_LENGTH_FULL}; 
+static const UDisplayContext optDiaLstShrt[3] = {UDISPCTX_DIALECT_NAMES,  UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU,       UDISPCTX_LENGTH_SHORT}; 
+
+static const UldnItem en_StdMidLong[] = {
+       { "en_US",                  TEST_ULDN_LOCALE, "English (US)" },
+       { "en_US_POSIX",            TEST_ULDN_LOCALE, "English (US, Computer)" },
+       { "en_US@calendar=chinese", TEST_ULDN_LOCALE, "English (US, Chinese Calendar)" },
+       { "en_CA",                  TEST_ULDN_LOCALE, "English (Canada)" },
+       { "pt",                     TEST_ULDN_LOCALE, "Portuguese" },
+       { "pt_BR",                  TEST_ULDN_LOCALE, "Portuguese (Brazil)" },
+       { "pt_PT",                  TEST_ULDN_LOCALE, "Portuguese (Portugal)" },
+       { "zh_Hans",                TEST_ULDN_LOCALE, "Chinese (Simplified)" },
+       { "zh_Hant_HK",             TEST_ULDN_LOCALE, "Chinese (Traditional, Hong Kong)" },
+       { "zh_HK",                  TEST_ULDN_LOCALE, "Chinese (Hong Kong)" },
+       { "Latn",                   TEST_ULDN_SCRIPT, "Latin" },
+       { "Hans",                   TEST_ULDN_SCRIPT, "Simplified Han" },
+       { "Hant",                   TEST_ULDN_SCRIPT, "Traditional Han" },
+       { "US",                     TEST_ULDN_REGION, "United States" },
+       { "CA",                     TEST_ULDN_REGION, "Canada" },
+       { "GB",                     TEST_ULDN_REGION, "United Kingdom" },
+       { "HK",                     TEST_ULDN_REGION, "Hong Kong (China)" },
+};
+
+static const UldnItem en_StdMidShrt[] = {
+       { "en_US",                  TEST_ULDN_LOCALE, "English (US)" },
+       { "en_US_POSIX",            TEST_ULDN_LOCALE, "English (US, Computer)" },
+       { "en_US@calendar=chinese", TEST_ULDN_LOCALE, "English (US, Calendar: chinese)" },
+       { "en_CA",                  TEST_ULDN_LOCALE, "English (Canada)" },
+       { "pt",                     TEST_ULDN_LOCALE, "Portuguese" },
+       { "pt_BR",                  TEST_ULDN_LOCALE, "Portuguese (Brazil)" },
+       { "pt_PT",                  TEST_ULDN_LOCALE, "Portuguese (Portugal)" },
+       { "zh_Hans",                TEST_ULDN_LOCALE, "Chinese (Simplified)" },
+       { "zh_Hant_HK",             TEST_ULDN_LOCALE, "Chinese (Traditional, Hong Kong)" },
+       { "zh_HK",                  TEST_ULDN_LOCALE, "Chinese (Hong Kong)" },
+       { "Latn",                   TEST_ULDN_SCRIPT, "Latin" },
+       { "Hans",                   TEST_ULDN_SCRIPT, "Simplified Han" },
+       { "Hant",                   TEST_ULDN_SCRIPT, "Traditional Han" },
+       { "US",                     TEST_ULDN_REGION, "US" },
+       { "CA",                     TEST_ULDN_REGION, "Canada" },
+       { "GB",                     TEST_ULDN_REGION, "UK" },
+       { "HK",                     TEST_ULDN_REGION, "Hong Kong" },
+};
+
+static const UldnItem en_DiaMidLong[] = {
+       { "en_US",                  TEST_ULDN_LOCALE, "American English" },
+       { "en_US_POSIX",            TEST_ULDN_LOCALE, "American English (Computer)" },
+       { "en_US@calendar=chinese", TEST_ULDN_LOCALE, "American English (Chinese Calendar)" },
+       { "en_CA",                  TEST_ULDN_LOCALE, "Canadian English" },
+       { "pt",                     TEST_ULDN_LOCALE, "Portuguese" },
+       { "pt_BR",                  TEST_ULDN_LOCALE, "Brazilian Portuguese" },
+       { "pt_PT",                  TEST_ULDN_LOCALE, "European Portuguese" },
+       { "zh_Hans",                TEST_ULDN_LOCALE, "Simplified Chinese" },
+       { "zh_Hant_HK",             TEST_ULDN_LOCALE, "Traditional Chinese (Hong Kong)" },
+       { "zh_HK",                  TEST_ULDN_LOCALE, "Chinese (Hong Kong)" },
+       { "Latn",                   TEST_ULDN_SCRIPT, "Latin" },
+       { "Hans",                   TEST_ULDN_SCRIPT, "Simplified Han" },
+       { "Hant",                   TEST_ULDN_SCRIPT, "Traditional Han" },
+       { "US",                     TEST_ULDN_REGION, "United States" },
+       { "CA",                     TEST_ULDN_REGION, "Canada" },
+       { "GB",                     TEST_ULDN_REGION, "United Kingdom" },
+       { "HK",                     TEST_ULDN_REGION, "Hong Kong (China)" },
+};
+
+static const UldnItem en_DiaMidShrt[] = {
+       { "en_US",                  TEST_ULDN_LOCALE, "US English" },
+       { "en_US_POSIX",            TEST_ULDN_LOCALE, "US English (Computer)" },
+       { "en_US@calendar=chinese", TEST_ULDN_LOCALE, "US English (Calendar: chinese)" },
+       { "en_CA",                  TEST_ULDN_LOCALE, "Canadian English" },
+       { "pt",                     TEST_ULDN_LOCALE, "Portuguese" },
+       { "pt_BR",                  TEST_ULDN_LOCALE, "Brazilian Portuguese" },
+       { "pt_PT",                  TEST_ULDN_LOCALE, "European Portuguese" },
+       { "zh_Hans",                TEST_ULDN_LOCALE, "Simplified Chinese" },
+       { "zh_Hant_HK",             TEST_ULDN_LOCALE, "Traditional Chinese (Hong Kong)" },
+       { "zh_HK",                  TEST_ULDN_LOCALE, "Chinese (Hong Kong)" },
+       { "Latn",                   TEST_ULDN_SCRIPT, "Latin" },
+       { "Hans",                   TEST_ULDN_SCRIPT, "Simplified Han" },
+       { "Hant",                   TEST_ULDN_SCRIPT, "Traditional Han" },
+       { "US",                     TEST_ULDN_REGION, "US" },
+       { "CA",                     TEST_ULDN_REGION, "Canada" },
+       { "GB",                     TEST_ULDN_REGION, "UK" },
+       { "HK",                     TEST_ULDN_REGION, "Hong Kong" },
+};
+
+static const UldnItem fr_StdMidLong[] = {
+       { "en_US",                  TEST_ULDN_LOCALE, "anglais (\\u00C9.-U.)" },
+       { "US",                     TEST_ULDN_REGION, "\\u00C9tats-Unis" },
+       { "HK",                     TEST_ULDN_REGION, "Hong Kong (Chine)" },
+};
+
+static const UldnItem fr_StdMidShrt[] = {
+       { "en_US",                  TEST_ULDN_LOCALE, "anglais (\\u00C9.-U.)" },
+       { "US",                     TEST_ULDN_REGION, "\\u00C9.-U." },
+       { "HK",                     TEST_ULDN_REGION, "Hong Kong" },
+};
+
+static const UldnItem fr_StdBegLong[] = {
+       { "en_US",                  TEST_ULDN_LOCALE, "Anglais (\\u00C9.-U.)" },
+};
+
+static const UldnItem fr_StdLstLong[] = {
+       { "en_US",                  TEST_ULDN_LOCALE, "Anglais (\\u00C9.-U.)" },
+       { "PS",                     TEST_ULDN_REGION, "Territoires palestiniens" },
+};
+
+static const UldnItem fr_DiaMidLong[] = {
+       { "en_US",                  TEST_ULDN_LOCALE, "anglais am\\u00E9ricain" },
+};
+
+static const UldnItem ca_StdLstLong[] = {
+       { "PS",                     TEST_ULDN_REGION, "Territoris palestins" },
+};
+
+static const UldnLocAndOpts uldnLocAndOpts[] = {
+    { "en", optStdMidLong, en_StdMidLong, UPRV_LENGTHOF(en_StdMidLong) },
+    { "en", optStdMidShrt, en_StdMidShrt, UPRV_LENGTHOF(en_StdMidShrt) },
+    { "en", optDiaMidLong, en_DiaMidLong, UPRV_LENGTHOF(en_DiaMidLong) },
+    { "en", optDiaMidShrt, en_DiaMidShrt, UPRV_LENGTHOF(en_DiaMidShrt) },
+    { "fr", optStdMidLong, fr_StdMidLong, UPRV_LENGTHOF(fr_StdMidLong) },
+    { "fr", optStdMidShrt, fr_StdMidShrt, UPRV_LENGTHOF(fr_StdMidShrt) },
+    { "fr", optStdBegLong, fr_StdBegLong, UPRV_LENGTHOF(fr_StdBegLong) },
+    { "fr", optStdLstLong, fr_StdLstLong, UPRV_LENGTHOF(fr_StdLstLong) },
+    { "fr_CA", optStdLstLong, fr_StdLstLong, UPRV_LENGTHOF(fr_StdLstLong) },
+    { "fr", optDiaMidLong, fr_DiaMidLong, UPRV_LENGTHOF(fr_DiaMidLong) },
+    { "ca", optStdLstLong, ca_StdLstLong, UPRV_LENGTHOF(ca_StdLstLong) },
+    { NULL, NULL, NULL, 0 }
+};
+
+enum { kUNameBuf = 128, kBNameBuf = 256 };
+
+static void TestUldnNameVariants() {
+    const UldnLocAndOpts * uloPtr;
+    for (uloPtr = uldnLocAndOpts; uloPtr->displayLocale != NULL; uloPtr++) {
+        UErrorCode status = U_ZERO_ERROR;
+        ULocaleDisplayNames * uldn = uldn_openForContext(uloPtr->displayLocale, (UDisplayContext*)uloPtr->displayOptions, 3, &status);
+        if (U_FAILURE(status)) {
+            log_data_err("uldn_openForContext fails, displayLocale %s, contexts %03X %03X %03X: %s - Are you missing data?\n",
+                    uloPtr->displayLocale, uloPtr->displayOptions[0], uloPtr->displayOptions[1], uloPtr->displayOptions[2],
+                    u_errorName(status) );
+            continue;
+        }
+        const UldnItem * itemPtr = uloPtr->testItems;
+        int32_t itemCount = uloPtr->countItems;
+        for (; itemCount-- > 0; itemPtr++) {
+            UChar uget[kUNameBuf], uexp[kUNameBuf];
+            int32_t ulenget, ulenexp;
+            const char* typeString;
+            
+            status = U_ZERO_ERROR;
+            switch (itemPtr->nameType) {
+                case TEST_ULDN_LOCALE:
+                    ulenget = uldn_localeDisplayName(uldn, itemPtr->localeToName, uget, kUNameBuf, &status);
+                    typeString = "locale";
+                    break;
+                case TEST_ULDN_LANGUAGE:
+                    ulenget = uldn_languageDisplayName(uldn, itemPtr->localeToName, uget, kUNameBuf, &status);
+                    typeString = "language";
+                  break;
+                case TEST_ULDN_SCRIPT:
+                    ulenget = uldn_scriptDisplayName(uldn, itemPtr->localeToName, uget, kUNameBuf, &status);
+                    typeString = "script";
+                    break;
+                case TEST_ULDN_REGION:
+                    ulenget = uldn_regionDisplayName(uldn, itemPtr->localeToName, uget, kUNameBuf, &status);
+                    typeString = "region";
+                    break;
+                default:
+                    continue;
+            }
+            if (U_FAILURE(status)) {
+                log_data_err("uldn_%sDisplayName fails, displayLocale %s, contexts %03X %03X %03X, localeToName %s: %s\n",
+                        typeString, uloPtr->displayLocale, uloPtr->displayOptions[0], uloPtr->displayOptions[1], uloPtr->displayOptions[2],
+                        itemPtr->localeToName, u_errorName(status) );
+                continue;
+            }
+            ulenexp = u_unescape(itemPtr->expectResult, uexp, kUNameBuf);
+            if (ulenget != ulenexp || u_strncmp(uget, uexp, ulenexp) != 0) {
+                char bexp[kBNameBuf], bget[kBNameBuf];
+                u_strToUTF8(bexp, kBNameBuf, NULL, uexp, ulenexp, &status);
+                u_strToUTF8(bget, kBNameBuf, NULL, uget, ulenget, &status);
+                log_data_err("uldn_%sDisplayName fails, displayLocale %s, contexts %03X %03X %03X, localeToName %s:\n    expect %2d: %s\n    get    %2d: %s\n",
+                        typeString, uloPtr->displayLocale, uloPtr->displayOptions[0], uloPtr->displayOptions[1], uloPtr->displayOptions[2],
+                        itemPtr->localeToName, ulenexp, bexp, ulenget, bget );
+            }
+        }
+        
+        uldn_close(uldn);
+    }
+}
+
+/* Apple-specific, test for Apple-specific function ualoc_getAppleParent */
+static const char* localesAndAppleParent[] = {
+    "en",               "root",
+    "en-US",            "en",
+    "en-CA",            "en_001",
+    "en-CN",            "en",
+    "en-JP",            "en",
+    "en-TW",            "en",
+    "en-001",           "en",
+    "en_001",           "en",
+    "en-150",           "en_GB",
+    "en-GB",            "en_001",
+    "en_GB",            "en_001",
+    "en-AU",            "en_GB",
+    "en-BE",            "en_150",
+    "en-DG",            "en_GB",
+    "en-FK",            "en_GB",
+    "en-GG",            "en_GB",
+    "en-GI",            "en_GB",
+    "en-HK",            "en_GB",
+    "en-IE",            "en_GB",
+    "en-IM",            "en_GB",
+    "en-IN",            "en_GB",
+    "en-IO",            "en_GB",
+    "en-JE",            "en_GB",
+    "en-JM",            "en_GB",
+    "en-MO",            "en_GB",
+    "en-MT",            "en_GB",
+    "en-MV",            "en_GB",
+    "en-NZ",            "en_AU",
+    "en-PK",            "en_GB",
+    "en-SG",            "en_GB",
+    "en-SH",            "en_GB",
+    "en-VG",            "en_GB",
+    "es",               "root",
+    "es-ES",            "es",
+    "es-419",           "es",
+    "es_419",           "es",
+    "es-MX",            "es_419",
+    "es-AR",            "es_419",
+    "es-BR",            "es_419",
+    "es-BZ",            "es_419",
+    "es-AG",            "es_419",
+    "es-AW",            "es_419",
+    "es-CA",            "es_419",
+    "es-CW",            "es_419",
+    "es-SX",            "es_419",
+    "es-TT",            "es_419",
+    "fr",               "root",
+    "fr-CA",            "fr",
+    "fr-CH",            "fr",
+    "haw",              "root",
+    "nl",               "root",
+    "nl-BE",            "nl",
+    "pt",               "root",
+    "pt-BR",            "pt",
+    "pt-PT",            "pt",
+    "pt-MO",            "pt_PT",
+    "pt-CH",            "pt_PT",
+    "pt-GQ",            "pt_PT",
+    "pt-LU",            "pt_PT",
+    "sr",               "root",
+    "sr-Cyrl",          "sr",
+    "sr-Latn",          "root",
+    "tlh",              "root",
+    "zh_CN",            "root",
+    "zh-CN",            "root",
+    "zh",               "zh_CN",
+    "zh-Hans",          "zh",
+    "zh_TW",            "root",
+    "zh-TW",            "root",
+    "zh-Hant",          "zh_TW",
+    "zh_HK",            "zh_Hant_HK",
+    "zh-HK",            "zh_Hant_HK",
+    "zh_Hant",          "zh_TW",
+    "zh-Hant-HK",       "zh_Hant",
+    "zh_Hant_HK",       "zh_Hant",
+    "zh-Hant-MO",       "zh_Hant_HK",
+    "zh-Hans-HK",       "zh_Hans",
+    "root",             "root",
+    "en-Latn",          "en",
+    "en-Latn-US",       "en_Latn",
+    "en_US_POSIX",      "en_US",
+    "en_Latn_US_POSIX", "en_Latn_US",
+    "en-u-ca-hebrew",   "root",
+    "en@calendar=hebrew", "root",
+    "en_@calendar=hebrew", "root",
+    "en-",              "root",
+    "en_",              "root",
+    "Default@2x",       "root",
+    "default",          "root",
+    NULL /* terminator */
+};
+
+static void TestGetAppleParent() {
+    const char **localesPtr = localesAndAppleParent;
+    const char * locale;
+    while ((locale = *localesPtr++) != NULL) {
+        const char * expectParent = *localesPtr++;
+        UErrorCode status = U_ZERO_ERROR;
+        char getParent[ULOC_FULLNAME_CAPACITY];
+        int32_t plen = ualoc_getAppleParent(locale, getParent, ULOC_FULLNAME_CAPACITY, &status);
+        if (U_FAILURE(status)) {
+            log_err("FAIL: ualoc_getAppleParent input \"%s\", status %s\n", locale, u_errorName(status));
+        } else if (uprv_strcmp(expectParent, getParent) != 0) {
+            log_err("FAIL: ualoc_getAppleParent input \"%s\", expected parent \"%s\", got parent \"%s\"\n", locale, expectParent, getParent);
+        }
+    }
+}
+
+/* Apple-specific, test for Apple-specific function ualoc_getLanguagesForRegion */
+enum { kUALanguageEntryMax = 10 };
+
+static void TestGetLanguagesForRegion() {
+    UALanguageEntry entries[kUALanguageEntryMax];
+    int32_t entryCount;
+    UErrorCode status;
+    const char * region;
+
+    status = U_ZERO_ERROR;
+    region = "CN";
+    entryCount = ualoc_getLanguagesForRegion(region, 0.001, entries, kUALanguageEntryMax, &status);
+    if (U_FAILURE(status)) {
+            log_err("FAIL: ualoc_getLanguagesForRegion %s, status %s\n", region, u_errorName(status));
+    } else {
+        // Expect approximately:
+        // zh_Hans 0.90 UALANGSTATUS_OFFICIAL
+        // wuu 0.06 Wu
+        // hsn 0.06 Xiang
+        // yue 0.043 Yue including Cantonese
+        // hak 0.023 Hakka
+        // nan 0.019 Minnan
+        // gan 0.017 Gan
+        // ii  0.006 Yi
+        // ug_Arab 0.0055 Uighur UALANGSTATUS_REGIONAL_OFFICIAL
+        // ...at least 4 more with fractions >= 0.001
+        if (entryCount < kUALanguageEntryMax) {
+            log_err("FAIL: ualoc_getLanguagesForRegion %s, entryCount %d is too small\n", region, entryCount);
+        } else {
+            UALanguageEntry* entryPtr = entries;
+            if (uprv_strcmp(entryPtr->languageCode, "zh_Hans") != 0 || entryPtr->userFraction < 0.8 || entryPtr->userFraction > 1.0 || entryPtr->status != UALANGSTATUS_OFFICIAL) {
+                log_err("FAIL: ualoc_getLanguagesForRegion %s, invalid entries[0] { %s, %.3f, %d }\n", region, entryPtr->languageCode, entryPtr->userFraction, (int)entryPtr->status);
+            }
+            for (entryPtr++; entryPtr < entries + kUALanguageEntryMax && uprv_strcmp(entryPtr->languageCode, "ug_Arab") != 0; entryPtr++)
+                ;
+            if (entryPtr < entries + kUALanguageEntryMax) {
+                // we found ug_Arab, make sure it has correct status
+                if (entryPtr->status != UALANGSTATUS_REGIONAL_OFFICIAL) {
+                    log_err("FAIL: ualoc_getLanguagesForRegion %s, ug_Arab had incorrect status %d\n", (int)entryPtr->status);
+                }
+            } else {
+                // did not find ug_Arab
+                log_err("FAIL: ualoc_getLanguagesForRegion %s, entries did not include ug_Arab\n", region);
+            }
+        }
+    }
+
+    status = U_ZERO_ERROR;
+    region = "CA";
+    entryCount = ualoc_getLanguagesForRegion(region, 0.001, entries, kUALanguageEntryMax, &status);
+    if (U_FAILURE(status)) {
+            log_err("FAIL: ualoc_getLanguagesForRegion %s, status %s\n", region, u_errorName(status));
+    } else {
+        // Expect approximately:
+        // en 0.85 UALANGSTATUS_OFFICIAL
+        // fr 0.22 UALANGSTATUS_OFFICIAL
+        // ...
+        if (entryCount < 2) {
+            log_err("FAIL: ualoc_getLanguagesForRegion %s, entryCount %d is too small\n", region, entryCount);
+        } else {
+            if (uprv_strcmp(entries[0].languageCode, "en") != 0 || entries[0].userFraction < 0.7 || entries[0].userFraction > 1.0 || entries[0].status != UALANGSTATUS_OFFICIAL) {
+                log_err("FAIL: ualoc_getLanguagesForRegion %s, invalid entries[0] { %s, %.3f, %d }\n", region, entries[0].languageCode, entries[0].userFraction, (int)entries[0].status);
+            }
+            if (uprv_strcmp(entries[1].languageCode, "fr") != 0 || entries[1].userFraction < 0.1 || entries[1].userFraction > 1.0 || entries[1].status != UALANGSTATUS_OFFICIAL) {
+                log_err("FAIL: ualoc_getLanguagesForRegion %s, invalid entries[1] { %s, %.3f, %d }\n", region, entries[1].languageCode, entries[1].userFraction, (int)entries[1].status);
+            }
+        }
+    }
+
+    status = U_ZERO_ERROR;
+    region = "IN";
+    entryCount = ualoc_getLanguagesForRegion(region, 0.001, NULL, 0, &status);
+    if (U_FAILURE(status)) {
+            log_err("FAIL: ualoc_getLanguagesForRegion %s, status %s\n", region, u_errorName(status));
+    } else {
+        if (entryCount < 40) {
+            log_err("FAIL: ualoc_getLanguagesForRegion %s, entryCount %d is too small\n", region, entryCount);
+        }
+    }
+}
+
+/* data for TestAppleLocalizationsToUse */
+
+typedef struct {
+    const char * const *locs;
+    int32_t             locCount;
+} AppleLocsAndCount;
+
+enum { kNumLocSets = 6 };
+
+typedef struct {
+    const char * language;
+    const char ** expLocsForSets[kNumLocSets];
+} LangAndExpLocs;
+
+
+static const char * appleLocs1[] = {
+    "Arabic",
+    "Danish",
+    "Dutch",
+    "English",
+    "Finnish",
+    "French",
+    "German",
+    "Italian",
+    "Japanese",
+    "Korean",
+    "Norwegian",
+    "Polish",
+    "Portuguese",
+    "Russian",
+    "Spanish",
+    "Swedish",
+    "Thai",
+    "Turkish",
+    "ca",
+    "cs",
+    "el",
+    "he",
+    "hr",
+    "hu",
+    "id",
+    "ms",
+    "ro",
+    "sk",
+    "uk",
+    "vi",
+    "zh_CN", "zh_TW",
+};
+
+static const char * appleLocs2[] = {
+    "ar",
+    "ca",
+    "cs",
+    "da",
+    "de",
+    "el",
+    "en", "en_AU", "en_GB",
+    "es", "es_MX",
+    "fi",
+    "fr", "fr_CA",
+    "he",
+    "hr",
+    "hu",
+    "id",
+    "it",
+    "ja",
+    "ko",
+    "ms",
+    "nl",
+    "no",
+    "pl",
+    "pt", "pt_PT",
+    "ro",
+    "ru",
+    "sk",
+    "sv",
+    "th",
+    "tr",
+    "uk",
+    "vi",
+    "zh_CN", "zh_HK", "zh_TW",
+};
+
+static const char * appleLocs3[] = {
+    "ar",
+    "ca",
+    "cs",
+    "da",
+    "de",
+    "el",
+    "en", "en_AU", "en_CA", "en_GB",
+    "es", "es_419",
+    "fi",
+    "fr", "fr_CA", "fr_FR",
+    "he",
+    "hr",
+    "hu",
+    "id",
+    "it",
+    "ja",
+    "ko",
+    "ms",
+    "nb",
+    "nl",
+    "pl",
+    "pt", "pt_BR", "pt_PT",
+    "ro",
+    "ru",
+    "sk",
+    "sv",
+    "th",
+    "tr",
+    "uk",
+    "vi",
+    "zh_CN", "zh_HK", "zh_MO", "zh_TW",
+};
+
+static const char * appleLocs4[] = {
+    "en", "en_AU", "en_CA", "en_GB", "en_IN", "en_US",
+    "es", "es_419", "es_MX",
+    "fr", "fr_CA", "fr_CH", "fr_FR",
+    "nl", "nl_BE", "nl_NL",
+    "pt", "pt_BR",
+    "ro", "ro_MD", "ro_RO",
+    "zh_Hans", "zh_Hant", "zh_Hant_HK",
+};
+
+static const char * appleLocs5[] = {
+    "en", "en_001", "en_AU", "en_GB",
+    "es", "es_ES", "es_MX",
+    "zh_CN", "zh_Hans", "zh_Hant", "zh_TW",
+    "yi",
+    "fil",
+    "haw",
+    "tlh",
+    "sr",
+    "sr-Latn",
+};
+
+// list 6
+static const char * appleLocs6[] = {
+    "en", "en_001", "en_150", "en_AU", "en_GB",
+    "es", "es_419", "es_ES", "es_MX",
+    "zh_CN", "zh_Hans", "zh_Hant", "zh_Hant_HK", "zh_HK", "zh_TW",
+    "iw",
+    "in",
+    "mo",
+    "tl",
+};
+
+static const AppleLocsAndCount locAndCountEntries[kNumLocSets] = {
+    { appleLocs1, UPRV_LENGTHOF(appleLocs1) },
+    { appleLocs2, UPRV_LENGTHOF(appleLocs2) },
+    { appleLocs3, UPRV_LENGTHOF(appleLocs3) },
+    { appleLocs4, UPRV_LENGTHOF(appleLocs4) },
+    { appleLocs5, UPRV_LENGTHOF(appleLocs5) },
+    { appleLocs6, UPRV_LENGTHOF(appleLocs6) },
+};
+
+
+static const char* l1_ar[]          = { "ar", NULL };
+static const char* l1_Ara[]         = { "Arabic", NULL };
+static const char* l1_ca[]          = { "ca", NULL };
+static const char* l1_cs[]          = { "cs", NULL };
+static const char* l1_da[]          = { "da", NULL };
+static const char* l1_Dan[]         = { "Danish", NULL };
+static const char* l1_de[]          = { "de", NULL };
+static const char* l1_Ger[]         = { "German", NULL };
+static const char* l1_el[]          = { "el", NULL };
+static const char* l1_en[]          = { "en", NULL };
+static const char* l1_Eng[]         = { "English", NULL };
+static const char* l2_en_001_[]     = { "en_001", "en", NULL };
+static const char* l2_en_CA_[]      = { "en_CA", "en", NULL };
+static const char* l2_en_GB_[]      = { "en_GB", "en", NULL };
+static const char* l2_en_US_[]      = { "en_US", "en", NULL };
+static const char* l2_en_GB_Eng[]   = { "en_GB", "English", NULL };
+static const char* l3_en_GB001_[]   = { "en_GB", "en_001", "en", NULL };
+static const char* l3_en_AUGB_[]    = { "en_AU", "en_GB", "en", NULL };
+static const char* l3_en_INGB_[]    = { "en_IN", "en_GB", "en", NULL };
+static const char* l4_en_150GB001_[] = { "en_150", "en_GB", "en_001", "en", NULL };
+static const char* l4_en_AUGB001_[] = { "en_AU", "en_GB", "en_001", "en", NULL };
+static const char* l1_es[]          = { "es", NULL };
+static const char* l1_Spa[]         = { "Spanish", NULL };
+static const char* l2_es_419_[]     = { "es_419", "es", NULL };
+static const char* l2_es_ES_[]      = { "es_ES", "es", NULL };
+static const char* l2_es_MX_[]      = { "es_MX", "es", NULL };
+static const char* l2_es_MX_Spa[]   = { "es_MX", "Spanish", NULL };
+static const char* l3_es_MX419_[]   = { "es_MX", "es_419", "es", NULL };
+static const char* l1_fi[]          = { "fi", NULL };
+static const char* l1_Fin[]         = { "Finnish", NULL };
+static const char* l1_fil[]         = { "fil", NULL };
+static const char* l1_tl[]          = { "tl", NULL };
+static const char* l1_fr[]          = { "fr", NULL };
+static const char* l1_Fre[]         = { "French", NULL };
+static const char* l2_fr_CA_[]      = { "fr_CA", "fr", NULL };
+static const char* l2_fr_CH_[]      = { "fr_CH", "fr", NULL };
+static const char* l2_fr_FR_[]      = { "fr_FR", "fr", NULL };
+static const char* l1_haw[]         = { "haw", NULL };
+static const char* l1_he[]          = { "he", NULL };
+static const char* l1_hr[]          = { "hr", NULL };
+static const char* l1_hu[]          = { "hu", NULL };
+static const char* l1_id[]          = { "id", NULL };
+static const char* l1_in[]          = { "in", NULL };
+static const char* l1_it[]          = { "it", NULL };
+static const char* l1_Ita[]         = { "Italian", NULL };
+static const char* l1_ja[]          = { "ja", NULL };
+static const char* l1_Japn[]        = { "Japanese", NULL };
+static const char* l1_ko[]          = { "ko", NULL };
+static const char* l1_Kor[]         = { "Korean", NULL };
+static const char* l1_ms[]          = { "ms", NULL };
+static const char* l1_nb[]          = { "nb", NULL };
+static const char* l1_no[]          = { "no", NULL };
+static const char* l1_Nor[]         = { "Norwegian", NULL };
+static const char* l2_no_NO_[]      = { "no_NO", "no", NULL };
+static const char* l1_nl[]          = { "nl", NULL };
+static const char* l1_Dut[]         = { "Dutch", NULL };
+static const char* l2_nl_BE_[]      = { "nl_BE", "nl", NULL };
+static const char* l1_pl[]          = { "pl", NULL };
+static const char* l1_Pol[]         = { "Polish", NULL };
+static const char* l1_pt[]          = { "pt", NULL };
+static const char* l1_pt_PT[]       = { "pt_PT", NULL };
+static const char* l1_Port[]        = { "Portuguese", NULL };
+static const char* l2_pt_BR_[]      = { "pt_BR", "pt", NULL };
+static const char* l2_pt_PT_[]      = { "pt_PT", "pt", NULL };
+static const char* l1_ro[]          = { "ro", NULL };
+static const char* l2_ro_MD_[]      = { "ro_MD", "ro", NULL };
+static const char* l1_mo[]          = { "mo", NULL };
+static const char* l1_ru[]          = { "ru", NULL };
+static const char* l1_Rus[]         = { "Russian", NULL };
+static const char* l1_sk[]          = { "sk", NULL };
+static const char* l1_sr[]          = { "sr", NULL };
+static const char* l1_srLatn[]      = { "sr-Latn", NULL };
+static const char* l1_sv[]          = { "sv", NULL };
+static const char* l1_Swe[]         = { "Swedish", NULL };
+static const char* l1_th[]          = { "th", NULL };
+static const char* l1_Thai[]        = { "Thai", NULL };
+static const char* l1_tlh[]         = { "tlh", NULL };
+static const char* l1_tr[]          = { "tr", NULL };
+static const char* l1_Tur[]         = { "Turkish", NULL };
+static const char* l1_uk[]          = { "uk", NULL };
+static const char* l1_vi[]          = { "vi", NULL };
+static const char* l1_yi[]          = { "yi", NULL };
+static const char* l1_iw[]          = { "iw", NULL };
+static const char* l1_zh_CN[]       = { "zh_CN", NULL };
+static const char* l1_zh_TW[]       = { "zh_TW", NULL };
+static const char* l1_zh_Hans[]     = { "zh_Hans", NULL };
+static const char* l1_zh_Hant[]     = { "zh_Hant", NULL };
+static const char* l1_zhHant[]      = { "zh-Hant", NULL };
+static const char* l2_zh_HKTW[]     = { "zh_HK", "zh_TW", NULL };
+static const char* l2_zh_Hant_HK_[] = { "zh_Hant_HK", "zh_Hant", NULL };
+static const char* l2_zh_CN_Hans[]  = { "zh_CN", "zh_Hans", NULL };
+static const char* l2_zh_TW_Hant[]  = { "zh_TW", "zh_Hant", NULL };
+static const char* l3_zh_MOHKTW[]   = { "zh_MO", "zh_HK", "zh_TW", NULL };
+static const char* l3_zh_HK_HantHK_Hant[] = { "zh_HK", "zh_Hant_HK", "zh_Hant", NULL };
+
+static const LangAndExpLocs appleLangAndLoc[] = {
+//    language\    result for appleLocs1      appleLocs2      appleLocs3      appleLocs4      appleLocs5      appleLocs6
+    { "zh",                 { l1_zh_CN,       l1_zh_CN,       l1_zh_CN,       l1_zh_Hans,     l1_zh_Hans,     l1_zh_Hans     } },
+    { "zh-Hans",            { l1_zh_CN,       l1_zh_CN,       l1_zh_CN,       l1_zh_Hans,     l1_zh_Hans,     l1_zh_Hans     } },
+    { "zh-Hant",            { l1_zh_TW,       l1_zh_TW,       l1_zh_TW,       l1_zh_Hant,     l1_zh_Hant,     l1_zh_Hant     } },
+    { "zh-Hans-CN",         { l1_zh_CN,       l1_zh_CN,       l1_zh_CN,       l1_zh_Hans,     l2_zh_CN_Hans,  l2_zh_CN_Hans  } },
+    { "zh-Hans-SG",         { l1_zh_CN,       l1_zh_CN,       l1_zh_CN,       l1_zh_Hans,     l1_zh_Hans,     l1_zh_Hans     } },
+    { "zh-Hant-TW",         { l1_zh_TW,       l1_zh_TW,       l1_zh_TW,       l1_zh_Hant,     l2_zh_TW_Hant,  l2_zh_TW_Hant  } },
+    { "zh-Hant-HK",         { l1_zh_TW,       l2_zh_HKTW,     l2_zh_HKTW,     l2_zh_Hant_HK_, l1_zh_Hant,     l2_zh_Hant_HK_ } },
+    { "zh-Hant-MO",         { l1_zh_TW,       l2_zh_HKTW,     l3_zh_MOHKTW,   l2_zh_Hant_HK_, l1_zh_Hant,     l2_zh_Hant_HK_ } },
+    { "zh-Hans-HK",         { l1_zh_CN,       l1_zh_CN,       l1_zh_CN,       l1_zh_Hans,     l1_zh_Hans,     l1_zh_Hans     } },
+    { "zh-CN",              { l1_zh_CN,       l1_zh_CN,       l1_zh_CN,       l1_zh_Hans,     l2_zh_CN_Hans,  l2_zh_CN_Hans  } },
+    { "zh-SG",              { l1_zh_CN,       l1_zh_CN,       l1_zh_CN,       l1_zh_Hans,     l1_zh_Hans,     l1_zh_Hans     } },
+    { "zh-TW",              { l1_zh_TW,       l1_zh_TW,       l1_zh_TW,       l1_zh_Hant,     l2_zh_TW_Hant,  l2_zh_TW_Hant  } },
+    { "zh-HK",              { l1_zh_TW,       l2_zh_HKTW,     l2_zh_HKTW,     l2_zh_Hant_HK_, l1_zh_Hant,     l3_zh_HK_HantHK_Hant } },
+    { "zh-MO",              { l1_zh_TW,       l2_zh_HKTW,     l3_zh_MOHKTW,   l2_zh_Hant_HK_, l1_zh_Hant,     l2_zh_Hant_HK_ } },
+    { "en",                 { l1_Eng,         l1_en,          l1_en,          l1_en,          l1_en,          l1_en          } },
+    { "en-US",              { l1_Eng,         l1_en,          l1_en,          l2_en_US_,      l1_en,          l1_en          } },
+    { "en_US",              { l1_Eng,         l1_en,          l1_en,          l2_en_US_,      l1_en,          l1_en          } },
+    { "en-CN",              { l1_Eng,         l1_en,          l1_en,          l1_en,          l1_en,          l1_en          } },
+    { "en-JP",              { l1_Eng,         l1_en,          l1_en,          l1_en,          l1_en,          l1_en          } },
+    { "en-TW",              { l1_Eng,         l1_en,          l1_en,          l1_en,          l1_en,          l1_en          } },
+    { "en-TR",              { l1_Eng,         l1_en,          l1_en,          l1_en,          l1_en,          l1_en          } },
+    { "en-001",             { l1_Eng,         l1_en,          l1_en,          l1_en,          l2_en_001_,     l2_en_001_     } },
+    { "en-CA",              { l1_Eng,         l1_en,          l2_en_CA_,      l2_en_CA_,      l2_en_001_,     l2_en_001_     } },
+    { "en-IL",              { l1_Eng,         l1_en,          l1_en,          l1_en,          l2_en_001_,     l2_en_001_     } },
+    { "en-GB",              { l1_Eng,         l2_en_GB_,      l2_en_GB_,      l2_en_GB_,      l3_en_GB001_,   l3_en_GB001_   } },
+    { "en-IN",              { l1_Eng,         l2_en_GB_,      l2_en_GB_,      l3_en_INGB_,    l3_en_GB001_,   l3_en_GB001_   } },
+    { "en-BD",              { l1_Eng,         l2_en_GB_,      l2_en_GB_,      l2_en_GB_,      l3_en_GB001_,   l3_en_GB001_   } },
+    { "en-GG",              { l1_Eng,         l2_en_GB_,      l2_en_GB_,      l2_en_GB_,      l3_en_GB001_,   l3_en_GB001_   } },
+    { "en-HK",              { l1_Eng,         l2_en_GB_,      l2_en_GB_,      l2_en_GB_,      l3_en_GB001_,   l3_en_GB001_   } },
+    { "en-IE",              { l1_Eng,         l2_en_GB_,      l2_en_GB_,      l2_en_GB_,      l3_en_GB001_,   l3_en_GB001_   } },
+    { "en-JM",              { l1_Eng,         l2_en_GB_,      l2_en_GB_,      l2_en_GB_,      l3_en_GB001_,   l3_en_GB001_   } },
+    { "en-MO",              { l1_Eng,         l2_en_GB_,      l2_en_GB_,      l2_en_GB_,      l3_en_GB001_,   l3_en_GB001_   } },
+    { "en-MT",              { l1_Eng,         l2_en_GB_,      l2_en_GB_,      l2_en_GB_,      l3_en_GB001_,   l3_en_GB001_   } },
+    { "en-PK",              { l1_Eng,         l2_en_GB_,      l2_en_GB_,      l2_en_GB_,      l3_en_GB001_,   l3_en_GB001_   } },
+    { "en-SG",              { l1_Eng,         l2_en_GB_,      l2_en_GB_,      l2_en_GB_,      l3_en_GB001_,   l3_en_GB001_   } },
+    { "en-VG",              { l1_Eng,         l2_en_GB_,      l2_en_GB_,      l2_en_GB_,      l3_en_GB001_,   l3_en_GB001_   } },
+    { "en-ZA",              { l1_Eng,         l2_en_GB_,      l2_en_GB_,      l2_en_GB_,      l3_en_GB001_,   l3_en_GB001_   } },
+    { "en-AU",              { l1_Eng,         l3_en_AUGB_,    l3_en_AUGB_,    l3_en_AUGB_,    l4_en_AUGB001_, l4_en_AUGB001_ } },
+    { "en-NZ",              { l1_Eng,         l3_en_AUGB_,    l3_en_AUGB_,    l3_en_AUGB_,    l4_en_AUGB001_, l4_en_AUGB001_ } },
+    { "en-WS",              { l1_Eng,         l3_en_AUGB_,    l3_en_AUGB_,    l3_en_AUGB_,    l4_en_AUGB001_, l4_en_AUGB001_ } },
+    { "en-150",             { l1_Eng,         l2_en_GB_,      l2_en_GB_,      l2_en_GB_,      l3_en_GB001_,   l4_en_150GB001_ } },
+    { "en-FR",              { l1_Eng,         l2_en_GB_,      l2_en_GB_,      l2_en_GB_,      l3_en_GB001_,   l4_en_150GB001_ } },
+    { "en-BE",              { l1_Eng,         l2_en_GB_,      l2_en_GB_,      l2_en_GB_,      l3_en_GB001_,   l4_en_150GB001_ } },
+    { "en-Latn",            { l1_Eng,         l1_en,          l1_en,          l1_en,          l1_en,          l1_en          } },
+    { "en-Latn-US",         { l1_Eng,         l1_en,          l1_en,          l1_en,/*TODO*/  l1_en,          l1_en          } },
+    { "en-US-POSIX",        { l1_Eng,         l1_en,          l1_en,          l2_en_US_,      l1_en,          l1_en          } },
+    { "en-Latn-US-POSIX",   { l1_Eng,         l1_en,          l1_en,          l1_en,          l1_en,          l1_en          } },
+    { "en-u-ca-hebrew",     { l1_Eng,         l1_en,          l1_en,          l1_en,          l1_en,          l1_en          } },
+    { "en@calendar=hebrew", { l1_Eng,         l1_en,          l1_en,          l1_en,          l1_en,          l1_en          } },
+    { "en-",                { l1_Eng,         l1_en,          l1_en,          l1_en,          l1_en,          l1_en          } },
+    { "en_",                { l1_Eng,         l1_en,          l1_en,          l1_en,          l1_en,          l1_en          } },
+    { "es",                 { l1_Spa,         l1_es,          l1_es,          l1_es,          l1_es,          l1_es          } },
+    { "es-ES",              { l1_Spa,         l1_es,          l1_es,          l1_es,          l2_es_ES_,      l2_es_ES_      } },
+    { "es-419",             { l1_Spa,         l1_es,          l2_es_419_,     l2_es_419_,     l1_es,          l2_es_419_     } },
+    { "es-MX",              { l1_Spa,         l2_es_MX_,      l2_es_419_,     l3_es_MX419_,   l2_es_MX_,      l3_es_MX419_   } },
+    { "es-AR",              { l1_Spa,         l1_es,          l2_es_419_,     l2_es_419_,     l1_es,          l2_es_419_     } },
+    { "es-BR",              { l1_Spa,         l1_es,          l2_es_419_,     l2_es_419_,     l1_es,          l2_es_419_     } },
+    { "es-BZ",              { l1_Spa,         l1_es,          l2_es_419_,     l2_es_419_,     l1_es,          l2_es_419_     } },
+    { "es-AG",              { l1_Spa,         l1_es,          l2_es_419_,     l2_es_419_,     l1_es,          l2_es_419_     } },
+    { "es-AW",              { l1_Spa,         l1_es,          l2_es_419_,     l2_es_419_,     l1_es,          l2_es_419_     } },
+    { "es-CA",              { l1_Spa,         l1_es,          l2_es_419_,     l2_es_419_,     l1_es,          l2_es_419_     } },
+    { "es-CW",              { l1_Spa,         l1_es,          l2_es_419_,     l2_es_419_,     l1_es,          l2_es_419_     } },
+    { "es-SX",              { l1_Spa,         l1_es,          l2_es_419_,     l2_es_419_,     l1_es,          l2_es_419_     } },
+    { "es-TT",              { l1_Spa,         l1_es,          l2_es_419_,     l2_es_419_,     l1_es,          l2_es_419_     } },
+    { "es-Latn",            { l1_Spa,         l1_es,          l1_es,          l1_es,          l1_es,          l1_es          } },
+    { "es-Latn-MX",         { l1_Spa,         l1_es,          l1_es,          l1_es,          l1_es,          l1_es          } },
+    { "pt",                 { l1_Port,        l1_pt,          l1_pt,          l1_pt,          NULL,           NULL  } },
+    { "pt-BR",              { l1_Port,        l1_pt,          l2_pt_BR_,      l2_pt_BR_,      NULL,           NULL  } },
+    { "pt-PT",              { l1_Port,        l2_pt_PT_,      l2_pt_PT_,      l1_pt,          NULL,           NULL  } },
+    { "pt-MO",              { l1_Port,        l2_pt_PT_,      l2_pt_PT_,      l1_pt,          NULL,           NULL  } },
+    { "pt-CH",              { l1_Port,        l2_pt_PT_,      l2_pt_PT_,      l1_pt,          NULL,           NULL  } },
+    { "pt-FR",              { l1_Port,        l2_pt_PT_,      l2_pt_PT_,      l1_pt,          NULL,           NULL  } },
+    { "pt-GQ",              { l1_Port,        l2_pt_PT_,      l2_pt_PT_,      l1_pt,          NULL,           NULL  } },
+    { "pt-LU",              { l1_Port,        l2_pt_PT_,      l2_pt_PT_,      l1_pt,          NULL,           NULL  } },
+    { "fr",                 { l1_Fre,         l1_fr,          l1_fr,          l1_fr,          NULL,           NULL  } },
+    { "fr-FR",              { l1_Fre,         l1_fr,          l2_fr_FR_,      l2_fr_FR_,      NULL,           NULL  } },
+    { "fr-CA",              { l1_Fre,         l2_fr_CA_,      l2_fr_CA_,      l2_fr_CA_,      NULL,           NULL  } },
+    { "fr-CH",              { l1_Fre,         l1_fr,          l1_fr,          l2_fr_CH_,      NULL,           NULL  } },
+    { "ar",                 { l1_Ara,         l1_ar,          l1_ar,          NULL,           NULL,           NULL  } },
+    { "da",                 { l1_Dan,         l1_da,          l1_da,          NULL,           NULL,           NULL  } },
+    { "nl",                 { l1_Dut,         l1_nl,          l1_nl,          l1_nl,          NULL,           NULL  } },
+    { "nl-BE",              { l1_Dut,         l1_nl,          l1_nl,          l2_nl_BE_,      NULL,           NULL  } },
+    { "fi",                 { l1_Fin,         l1_fi,          l1_fi,          NULL,           NULL,           NULL  } },
+    { "de",                 { l1_Ger,         l1_de,          l1_de,          NULL,           NULL,           NULL  } },
+    { "it",                 { l1_Ita,         l1_it,          l1_it,          NULL,           NULL,           NULL  } },
+    { "ja",                 { l1_Japn,        l1_ja,          l1_ja,          NULL,           NULL,           NULL  } },
+    { "ko",                 { l1_Kor,         l1_ko,          l1_ko,          NULL,           NULL,           NULL  } },
+    { "nb",                 { l1_Nor,         l1_no,          l1_nb,          NULL,           NULL,           NULL  } },
+    { "no",                 { l1_Nor,         l1_no,          l1_nb,          NULL,           NULL,           NULL  } },
+    { "pl",                 { l1_Pol,         l1_pl,          l1_pl,          NULL,           NULL,           NULL  } },
+    { "ru",                 { l1_Rus,         l1_ru,          l1_ru,          NULL,           NULL,           NULL  } },
+    { "sv",                 { l1_Swe,         l1_sv,          l1_sv,          NULL,           NULL,           NULL  } },
+    { "th",                 { l1_Thai,        l1_th,          l1_th,          NULL,           NULL,           NULL  } },
+    { "tr",                 { l1_Tur,         l1_tr,          l1_tr,          NULL,           NULL,           NULL  } },
+    { "ca",                 { l1_ca,          l1_ca,          l1_ca,          NULL,           NULL,           NULL  } },
+    { "cs",                 { l1_cs,          l1_cs,          l1_cs,          NULL,           NULL,           NULL  } },
+    { "el",                 { l1_el,          l1_el,          l1_el,          NULL,           NULL,           NULL  } },
+    { "he",                 { l1_he,          l1_he,          l1_he,          NULL,           NULL,           l1_iw } },
+    { "iw",                 { l1_he,          l1_he,          l1_he,          NULL,           NULL,           l1_iw } },
+    { "hr",                 { l1_hr,          l1_hr,          l1_hr,          NULL,           NULL,           NULL  } },
+    { "hu",                 { l1_hu,          l1_hu,          l1_hu,          NULL,           NULL,           NULL  } },
+    { "id",                 { l1_id,          l1_id,          l1_id,          NULL,           NULL,           l1_in } },
+    { "in",                 { l1_id,          l1_id,          l1_id,          NULL,           NULL,           l1_in } },
+    { "ms",                 { l1_ms,          l1_ms,          l1_ms,          NULL,           NULL,           NULL  } },
+    { "ro",                 { l1_ro,          l1_ro,          l1_ro,          l1_ro,          NULL,           l1_mo } },
+    { "mo",                 { l1_ro,          l1_ro,          l1_ro,          l2_ro_MD_,      NULL,           l1_mo } },
+    { "sk",                 { l1_sk,          l1_sk,          l1_sk,          NULL,           NULL,           NULL  } },
+    { "uk",                 { l1_uk,          l1_uk,          l1_uk,          NULL,           NULL,           NULL  } },
+    { "vi",                 { l1_vi,          l1_vi,          l1_vi,          NULL,           NULL,           NULL  } },
+    { "yi",                 { NULL,           NULL,           NULL,           NULL,           l1_yi,          NULL  } },
+    { "ji",                 { NULL,           NULL,           NULL,           NULL,           l1_yi,          NULL  } },
+    { "fil",                { NULL,           NULL,           NULL,           NULL,           l1_fil,         l1_tl } },
+    { "tl",                 { NULL,           NULL,           NULL,           NULL,           l1_fil,         l1_tl } },
+    { "haw",                { NULL,           NULL,           NULL,           NULL,           l1_haw,         NULL  } },
+    { "sr",                 { NULL,           NULL,           NULL,           NULL,           l1_sr,          NULL  } },
+    { "sr-Cyrl",            { NULL,           NULL,           NULL,           NULL,           l1_sr,          NULL  } },
+    { "sr-Latn",            { NULL,           NULL,           NULL,           NULL,           l1_srLatn,      NULL  } },
+    { "tlh",                { NULL,           NULL,           NULL,           NULL,           l1_tlh,         NULL  } },
+    { "Default@2x",         { NULL,           NULL,           NULL,           NULL,           NULL,           NULL  } },
+    { "default",            { NULL,           NULL,           NULL,           NULL,           NULL,           NULL  } },
+    { "root",               { NULL,           NULL,           NULL,           NULL,           NULL,           NULL  } },
+    { "",                   { NULL,           NULL,           NULL,           NULL,           NULL,           NULL  } },
+    { "_US",                { NULL,           NULL,           NULL,           NULL,           NULL,           NULL  } },
+    { "-US",                { NULL,           NULL,           NULL,           NULL,           NULL,           NULL  } },
+    { "-u-ca-hebrew",       { NULL,           NULL,           NULL,           NULL,           NULL,           NULL  } },
+    { "-u-ca-hebrew",       { NULL,           NULL,           NULL,           NULL,           NULL,           NULL  } },
+    { "@calendar=hebrew",   { NULL,           NULL,           NULL,           NULL,           NULL,           NULL  } },
+};
+enum { kNumAppleLangAndLoc = UPRV_LENGTHOF(appleLangAndLoc) };
+
+/* tests from <rdar://problem/21518031> */
+
+static const char * appleLocsA1[] = { "en", "fr", "no", "zh-Hant" };
+static const char * appleLocsA2[] = { "en", "fr", "nb", "zh_TW", "zh_CN", "zh-Hant" };
+static const char * appleLocsA3[] = { "en", "en_IN", "en_GB", "fr", "de", "zh_TW" };
+static const char * appleLocsA4[] = { "Spanish", "es_MX", "English", "en_GB" };
+static const char * appleLocsA5[] = { "en", "fr", "de", "pt", "pt_PT" };
+static const char * appleLocsA6[] = { "en", "no", "no_NO", "pt_PT" };
+
+static const AppleLocsAndCount locAndCountEntriesA[kNumLocSets] = {
+    { appleLocsA1, UPRV_LENGTHOF(appleLocsA1) },
+    { appleLocsA2, UPRV_LENGTHOF(appleLocsA2) },
+    { appleLocsA3, UPRV_LENGTHOF(appleLocsA3) },
+    { appleLocsA4, UPRV_LENGTHOF(appleLocsA4) },
+    { appleLocsA5, UPRV_LENGTHOF(appleLocsA5) },
+    { appleLocsA6, UPRV_LENGTHOF(appleLocsA6) },
+};
+
+static const LangAndExpLocs appleLangAndLocA[] = {
+//    language\    result for appleLocsA1     appleLocsA2         appleLocsA3     appleLocsA4     appleLocsA5     appleLocsA6
+    { "zh-Hant",            { l1_zhHant,/*0*/ l1_zhHant,/*zh_TW*/ l1_zh_TW,       NULL,           NULL,           NULL        } },
+    { "zh_Hant",            { l1_zhHant,      l1_zhHant,/*zh_TW*/ l1_zh_TW,       NULL,           NULL,           NULL        } },
+    { "zh_HK",              { l1_zhHant,      l1_zhHant,/*zh_TW*/ l1_zh_TW,       NULL,           NULL,           NULL        } },
+    { "en_IN",              { l1_en,          l1_en,              l3_en_INGB_,    l2_en_GB_Eng,   l1_en,          l1_en       } },
+    { "es_MX",              { NULL,           NULL,               NULL,           l2_es_MX_Spa,   NULL,           NULL        } },
+    { "pt_PT",              { NULL,           NULL,               NULL,           NULL,           l2_pt_PT_,      l1_pt_PT    } },
+    { "pt",                 { NULL,           NULL,               NULL,           NULL,           l1_pt,          l1_pt_PT    } },
+    { "no",                 { l1_no,          l1_nb,              NULL,           NULL,           NULL,           l1_no       } },
+    { "no_NO",              { l1_no,          l1_nb,              NULL,           NULL,           NULL,           l2_no_NO_   } },
+    { "nb",                 { l1_no,          l1_nb,              NULL,           NULL,           NULL,           l1_no       } },
+    { "nb_NO",              { l1_no,          l1_nb,              NULL,           NULL,           NULL,           l2_no_NO_   } },
+};
+enum { kNumAppleLangAndLocA = UPRV_LENGTHOF(appleLangAndLocA) };
+
+/* tests from log attached to 21682790 */
+
+static const char * appleLocsB1[] = {
+    "ar",       "Base",     "ca",       "cs",
+    "da",       "Dutch",    "el",       "English",
+    "es_MX",    "fi",       "French",   "German",
+    "he",       "hr",       "hu",       "id",
+    "Italian",  "Japanese", "ko",       "ms",
+    "no",       "pl",       "pt",       "pt_PT",
+    "ro",       "ru",       "sk",       "Spanish",
+    "sv",       "th",       "tr",       "uk",
+    "vi",       "zh_CN",    "zh_TW"
+};
+
+static const char * appleLocsB2[] = {
+    "ar",                   "ca",       "cs",
+    "da",       "Dutch",    "el",       "English",
+    "es_MX",    "fi",       "French",   "German",
+    "he",       "hr",       "hu",       "id",
+    "Italian",  "Japanese", "ko",       "ms",
+    "no",       "pl",       "pt",       "pt_PT",
+    "ro",       "ru",       "sk",       "Spanish",
+    "sv",       "th",       "tr",       "uk",
+    "vi",       "zh_CN",    "zh_TW"
+};
+
+static const char * appleLocsB3[] = {
+    "ar",       "ca",       "cs",       "da",
+    "de",       "el",       "en",       "es",
+    "es_MX",    "fi",       "French",   "he",
+    "hr",       "hu",       "id",       "Italian",
+    "ja",       "ko",       "ms",       "nl",
+    "no",       "pl",       "pt",       "pt_PT",
+    "ro",       "ru",       "sk",       "sv",
+    "th",       "tr",       "uk",       "vi",
+    "zh_CN",    "zh_TW"
+};
+
+static const char * appleLocsB4[] = {
+    "ar",       "ca",       "cs",       "da",
+    "de",       "el",       "en",       "es",
+    "es_MX",    "fi",       "fr",       "he",
+    "hr",       "hu",       "id",       "it",
+    "ja",       "ko",       "ms",       "nl",
+    "no",       "pl",       "pt",       "pt_PT",
+    "ro",       "ru",       "sk",       "sv",
+    "th",       "tr",       "uk",       "vi",
+    "zh_CN",     "zh_TW"
+};
+
+static const char * appleLocsB5[] = { "en" };
+
+static const char * appleLocsB6[] = { "English" };
+
+static const AppleLocsAndCount locAndCountEntriesB[kNumLocSets] = {
+    { appleLocsB1, UPRV_LENGTHOF(appleLocsB1) },
+    { appleLocsB2, UPRV_LENGTHOF(appleLocsB2) },
+    { appleLocsB3, UPRV_LENGTHOF(appleLocsB3) },
+    { appleLocsB4, UPRV_LENGTHOF(appleLocsB4) },
+    { appleLocsB5, UPRV_LENGTHOF(appleLocsB5) },
+    { appleLocsB6, UPRV_LENGTHOF(appleLocsB6) },
+};
+
+static const LangAndExpLocs appleLangAndLocB[] = {
+//    language\    result for appleLocsB1     appleLocsB2         appleLocsB3     appleLocsB4     appleLocsB5     appleLocsB6
+// Prefs 1, logged with sets B1-B3
+    { "en",                 { l1_Eng,         l1_Eng,             l1_en,          l1_en,          l1_en,          l1_Eng      } },
+    { "es",                 { l1_Spa,         l1_Spa,             l1_es,          l1_es,          NULL,           NULL        } },
+// Prefs 2, logged with sets B1-B6
+    { "English",            { l1_Eng,         l1_Eng,             l1_en,          l1_en,          l1_en,          l1_Eng      } },
+    { "Spanish",            { l1_Spa,         l1_Spa,             l1_es,          l1_es,          NULL,           NULL        } },
+};
+enum { kNumAppleLangAndLocB = UPRV_LENGTHOF(appleLangAndLocB) };
+
+typedef struct {
+    const AppleLocsAndCount * locAndCountEntriesPtr;
+    const LangAndExpLocs *    appleLangAndLocPtr;
+    int32_t                   appleLangAndLocCount;
+} AppleLocToUseTestSet;
+
+static const AppleLocToUseTestSet altuTestSets[] = {
+    { locAndCountEntries,  appleLangAndLoc,  kNumAppleLangAndLoc },
+    { locAndCountEntriesA, appleLangAndLocA, kNumAppleLangAndLocA },
+    { locAndCountEntriesB, appleLangAndLocB, kNumAppleLangAndLocB },
+    { NULL, NULL, 0 }
+};
+
+/* tests for multiple prefs sets */
+
+static const char * appleLocsM1[] = { "en", "en_GB", "pt", "pt_PT", "zh_CN", "zh_Hant" };
+static const char * prefLangsM1[] = { "tlh", "zh_HK", "zh_SG", "zh_Hans", "pt_BR", "pt_PT", "en_IN", "en" };
+static const char * locsToUseM1[] = { "zh_Hant" };
+
+// Tests from first pass at <rdar://problem/22012864>, 2015-11-18
+
+static const char * appleLocsM2[] = { "fr-FR", "en-US", "en-GB" };
+static const char * prefLangsM2[] = { "fr-CH" };
+static const char * locsToUseM2[] = { "fr-FR" };
+
+static const char * appleLocsM3[] = { "es-es", "fr-fr" };
+static const char * prefLangsM3[] = { "fr-US", "fr", "en-US" };
+static const char * locsToUseM3[] = { "fr-fr" };
+
+static const char * appleLocsM4[] = { "es-es", "fr-fr", "fr" };
+static const char * prefLangsM4[] = { "fr-US", "fr", "en-US" };
+static const char * locsToUseM4[] = { "fr" };
+
+// Tests from second pass at <rdar://problem/22012864>, 2015-12-08
+// Per Karan M
+static const char * appleLocsM5[] = { "en-US", "fr-FR", "de-DE", "es-ES", "es-419", "pt-PT", "pt-BR", "zh-CN", "zh-TW", "zh-HK", "ja-JP", "ko-KR" };
+static const char * prefLangsM5[] = { "fr-US", "en-US" };
+static const char * locsToUseM5[] = { "fr-FR" };
+// Per Peter E; expected result changed from "en-US" to "de-CH" per <rdar://problem/26559053>
+static const char * appleLocsM6[] = { "de-CH", "en-US" };
+static const char * prefLangsM6[] = { "de-DE", "en-US" };
+static const char * locsToUseM6[] = { "de-CH" };
+// The following is used for M7-MD
+static const char * appleLocsMx[] = { "de-DE", "en-AU", "es-ES", "fr-FR", "hi-IN", "pt-BR", "zh-HK", "zh-TW" };
+// Per Karan M
+static const char * prefLangsM7[] = { "fr-ES", "en-AU" };
+static const char * locsToUseM7[] = { "fr-FR" };
+// Per Karan M
+static const char * prefLangsM8[] = { "de-IT", "en-AU" };
+static const char * locsToUseM8[] = { "de-DE" };
+// Per Karan M
+static const char * prefLangsM9[] = { "hi-US", "en-AU" };
+static const char * locsToUseM9[] = { "hi-IN" };
+// Per Karan M
+static const char * prefLangsMA[] = { "en-IN", "zh-HK" };
+static const char * locsToUseMA[] = { "en-AU" };
+// Per Karan M
+static const char * prefLangsMB[] = { "pt-PT", "en-AU" };
+static const char * locsToUseMB[] = { "en-AU" };
+// per Paul B:
+static const char * prefLangsMC[] = { "pt-PT", "ar" };
+static const char * locsToUseMC[] = { "pt-BR" };
+// Per Karan M
+static const char * prefLangsMD[] = { "zh-CN", "en-AU" };
+static const char * locsToUseMD[] = { "en-AU" };
+// Per Karan M
+static const char * appleLocsME[] = { "de-DE", "en-AU", "es-ES", "fr-FR", "hi-IN", "pt-BR", "zh-CN", "zh-HK" };
+static const char * prefLangsME[] = { "zh-TW", "en-AU" };
+static const char * locsToUseME[] = { "zh-HK" };
+// Per Peter E in diagnosis for <rdar://problem/22012864> and <rdar://problem/23815194>
+static const char * appleLocsMF[] = { "en", "en-GB", "fr", "es" };
+static const char * prefLangsMF[] = { "en-IN", "en-GB", "de", "fr" };
+static const char * locsToUseMF[] = { "en-GB", "en" };
+// Per Karan M in <rdar://problem/23982460>
+static const char * appleLocsMG[] = { "zh-Hans", "zh-Hant", "zh-HK" };
+static const char * prefLangsMG[] = { "zh-Hans-US", "zh-HK", "en-US" };
+static const char * locsToUseMG[] = { "zh-Hans" };
+// Per <rdar://problem/25903891>
+static const char * appleLocsMH[] = { "zh-TW", "zh-CN", "zh-HK" };
+static const char * prefLangsMH[] = { "zh-Hans-HK", "zh-HK", "en" };
+static const char * locsToUseMH[] = { "zh-CN" };
+// Per <rdar://problem/26559053>
+static const char * appleLocsMI[] = { "unk", "en-US", "ar-SA" };
+static const char * prefLangsMI[] = { "ar-US" };
+static const char * locsToUseMI[] = { "ar-SA" };
+// Per <rdar://problem/30501523> - first for comparison with zh, then real test
+static const char * appleLocsMJ[] = { "zh-CN", "en-US" };
+static const char * prefLangsMJ[] = { "zh", "zh_AC" };
+static const char * locsToUseMJ[] = { "zh-CN" };
+static const char * appleLocsMK[] = { "yue-CN", "en-US" };
+static const char * prefLangsMK[] = { "yue", "yue_AC" };
+static const char * locsToUseMK[] = { "yue-CN" };
+// Per <rdar://problem/30433534>
+static const char * appleLocsML[] = { "nl_NL", "es_MX", "fr_FR", "zh_TW", "it_IT", "vi_VN", "fr_CH", "es_CL",
+                                      "en_ZA", "ko_KR", "ca_ES", "ro_RO", "en_PH", "en_CA", "en_SG", "en_IN",
+                                      "en_NZ", "it_CH", "fr_CA", "da_DK", "de_AT", "pt_BR", "yue_CN", "zh_CN",
+                                      "sv_SE", "es_ES", "ar_SA", "hu_HU", "fr_BE", "en_GB", "ja_JP", "zh_HK",
+                                      "fi_FI", "tr_TR", "nb_NO", "en_ID", "en_SA", "pl_PL", "ms_MY", "cs_CZ",
+                                      "el_GR", "id_ID", "hr_HR", "en_AE", "he_IL", "ru_RU", "wuu_CN", "de_DE",
+                                      "de_CH", "en_AU", "nl_BE", "th_TH", "pt_PT", "sk_SK", "en_US", "en_IE",
+                                      "es_CO", "uk_UA", "es_US" };
+static const char * prefLangsML[] = { "en-JP" };
+static const char * locsToUseML[] = { "en_US" };
+// Per <rdar://problem/32421203>
+static const char * appleLocsMM1[] = { "pt-PT" };
+static const char * appleLocsMM2[] = { "pt-BR" };
+static const char * appleLocsMM3[] = { "pt-PT", "pt-BR" };
+static const char * appleLocsMM4[] = { "en", "pt-PT" };
+static const char * appleLocsMM5[] = { "en", "pt-BR" };
+static const char * appleLocsMM6[] = { "en", "pt-PT", "pt-BR" };
+static const char * prefLangsMM1[] = { "pt-PT" };
+static const char * prefLangsMM2[] = { "pt-BR" };
+static const char * prefLangsMM3[] = { "pt" };
+static const char * prefLangsMM4[] = { "pt-PT", "en" };
+static const char * prefLangsMM5[] = { "pt-BR", "en" };
+static const char * prefLangsMM6[] = { "pt", "en" };
+static const char * locsToUseMMptPT[] = { "pt-PT" };
+static const char * locsToUseMMptBR[] = { "pt-BR" };
+static const char * locsToUseMMen[]   = { "en" };
+// Per <rdar://problem/32658828>
+static const char * appleLocsMN[]   = { "en-US", "en-GB" };
+static const char * prefLangsMN1[]  = { "en-KR" };
+static const char * prefLangsMN2[]  = { "en-SA" };
+static const char * prefLangsMN3[]  = { "en-TW" };
+static const char * prefLangsMN4[]  = { "en-JP" };
+static const char * locsToUseMN_U[] = { "en-US" };
+// Per <rdar://problem/36010857>
+static const char * appleLocsMO[]   = { "Dutch", "French", "German", "Italian", "Japanese", "Spanish",
+                                        "ar", "ca", "cs", "da", "el", "en_AU", "en_GB", "en_IN",
+                                        "es_419", "fi", "fr_CA", "he", "hi", "hr", "hu", "id", "ko",
+                                        "ms", "no", "pl", "pt", "pt_PT", "ro", "ru", "sk", "sv",
+                                        "th", "tr", "uk", "vi", "zh_CN", "zh_HK", "zh_TW" };
+static const char * prefLangsMO1[]  = { "en-US" };
+static const char * locsToUseMO1[]  = { "en_GB" };
+
+typedef struct {
+    const char *  name;
+    const char ** availLocs;
+    int32_t       availLocsCount;
+    const char ** prefLangs;
+    int32_t       prefLangsCount;
+    const char ** locsToUse;
+    int32_t       locsToUseCount;
+} MultiPrefTest;
+
+static const MultiPrefTest multiTestSets[] = {
+    { "M1",  appleLocsM1,  UPRV_LENGTHOF(appleLocsM1), prefLangsM1, UPRV_LENGTHOF(prefLangsM1), locsToUseM1, UPRV_LENGTHOF(locsToUseM1) },
+    //
+    { "M2",  appleLocsM2,  UPRV_LENGTHOF(appleLocsM2), prefLangsM2, UPRV_LENGTHOF(prefLangsM2), locsToUseM2, UPRV_LENGTHOF(locsToUseM2) },
+    { "M3",  appleLocsM3,  UPRV_LENGTHOF(appleLocsM3), prefLangsM3, UPRV_LENGTHOF(prefLangsM3), locsToUseM3, UPRV_LENGTHOF(locsToUseM3) },
+    { "M4",  appleLocsM4,  UPRV_LENGTHOF(appleLocsM4), prefLangsM4, UPRV_LENGTHOF(prefLangsM4), locsToUseM4, UPRV_LENGTHOF(locsToUseM4) },
+    //
+    { "M5",  appleLocsM5,  UPRV_LENGTHOF(appleLocsM5), prefLangsM5, UPRV_LENGTHOF(prefLangsM5), locsToUseM5, UPRV_LENGTHOF(locsToUseM5) },
+    { "M6",  appleLocsM6,  UPRV_LENGTHOF(appleLocsM6), prefLangsM6, UPRV_LENGTHOF(prefLangsM6), locsToUseM6, UPRV_LENGTHOF(locsToUseM6) },
+    { "M7",  appleLocsMx,  UPRV_LENGTHOF(appleLocsMx), prefLangsM7, UPRV_LENGTHOF(prefLangsM7), locsToUseM7, UPRV_LENGTHOF(locsToUseM7) },
+    { "M8",  appleLocsMx,  UPRV_LENGTHOF(appleLocsMx), prefLangsM8, UPRV_LENGTHOF(prefLangsM8), locsToUseM8, UPRV_LENGTHOF(locsToUseM8) },
+    { "M9",  appleLocsMx,  UPRV_LENGTHOF(appleLocsMx), prefLangsM9, UPRV_LENGTHOF(prefLangsM9), locsToUseM9, UPRV_LENGTHOF(locsToUseM9) },
+    { "MA",  appleLocsMx,  UPRV_LENGTHOF(appleLocsMx), prefLangsMA, UPRV_LENGTHOF(prefLangsMA), locsToUseMA, UPRV_LENGTHOF(locsToUseMA) },
+    { "MB",  appleLocsMx,  UPRV_LENGTHOF(appleLocsMx), prefLangsMB, UPRV_LENGTHOF(prefLangsMB), locsToUseMB, UPRV_LENGTHOF(locsToUseMB) },
+    { "MC",  appleLocsMx,  UPRV_LENGTHOF(appleLocsMx), prefLangsMC, UPRV_LENGTHOF(prefLangsMC), locsToUseMC, UPRV_LENGTHOF(locsToUseMC) },
+    { "MD",  appleLocsMx,  UPRV_LENGTHOF(appleLocsMx), prefLangsMD, UPRV_LENGTHOF(prefLangsMD), locsToUseMD, UPRV_LENGTHOF(locsToUseMD) },
+    { "ME",  appleLocsME,  UPRV_LENGTHOF(appleLocsME), prefLangsME, UPRV_LENGTHOF(prefLangsME), locsToUseME, UPRV_LENGTHOF(locsToUseME) },
+    { "MF",  appleLocsMF,  UPRV_LENGTHOF(appleLocsMF), prefLangsMF, UPRV_LENGTHOF(prefLangsMF), locsToUseMF, UPRV_LENGTHOF(locsToUseMF) },
+    { "MG",  appleLocsMG,  UPRV_LENGTHOF(appleLocsMG), prefLangsMG, UPRV_LENGTHOF(prefLangsMG), locsToUseMG, UPRV_LENGTHOF(locsToUseMG) },
+    { "MH",  appleLocsMH,  UPRV_LENGTHOF(appleLocsMH), prefLangsMH, UPRV_LENGTHOF(prefLangsMH), locsToUseMH, UPRV_LENGTHOF(locsToUseMH) },
+    { "MI",  appleLocsMI,  UPRV_LENGTHOF(appleLocsMI), prefLangsMI, UPRV_LENGTHOF(prefLangsMI), locsToUseMI, UPRV_LENGTHOF(locsToUseMI) },
+    { "MJ",  appleLocsMJ,  UPRV_LENGTHOF(appleLocsMJ), prefLangsMJ, UPRV_LENGTHOF(prefLangsMJ), locsToUseMJ, UPRV_LENGTHOF(locsToUseMJ) },
+    { "MK",  appleLocsMK,  UPRV_LENGTHOF(appleLocsMK), prefLangsMK, UPRV_LENGTHOF(prefLangsMK), locsToUseMK, UPRV_LENGTHOF(locsToUseMK) },
+    { "ML",  appleLocsML,  UPRV_LENGTHOF(appleLocsML), prefLangsML, UPRV_LENGTHOF(prefLangsML), locsToUseML, UPRV_LENGTHOF(locsToUseML) },
+    { "MM11",  appleLocsMM1,  UPRV_LENGTHOF(appleLocsMM1), prefLangsMM1, UPRV_LENGTHOF(prefLangsMM1), locsToUseMMptPT, UPRV_LENGTHOF(locsToUseMMptPT) },
+    { "MM21",  appleLocsMM2,  UPRV_LENGTHOF(appleLocsMM2), prefLangsMM1, UPRV_LENGTHOF(prefLangsMM1), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
+    { "MM31",  appleLocsMM3,  UPRV_LENGTHOF(appleLocsMM3), prefLangsMM1, UPRV_LENGTHOF(prefLangsMM1), locsToUseMMptPT, UPRV_LENGTHOF(locsToUseMMptPT) },
+    { "MM41",  appleLocsMM4,  UPRV_LENGTHOF(appleLocsMM4), prefLangsMM1, UPRV_LENGTHOF(prefLangsMM1), locsToUseMMptPT, UPRV_LENGTHOF(locsToUseMMptPT) },
+    { "MM51",  appleLocsMM5,  UPRV_LENGTHOF(appleLocsMM5), prefLangsMM1, UPRV_LENGTHOF(prefLangsMM1), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
+    { "MM61",  appleLocsMM6,  UPRV_LENGTHOF(appleLocsMM6), prefLangsMM1, UPRV_LENGTHOF(prefLangsMM1), locsToUseMMptPT, UPRV_LENGTHOF(locsToUseMMptPT) },
+    { "MM12",  appleLocsMM1,  UPRV_LENGTHOF(appleLocsMM1), prefLangsMM2, UPRV_LENGTHOF(prefLangsMM2), locsToUseMMptPT, UPRV_LENGTHOF(locsToUseMMptPT) },
+    { "MM22",  appleLocsMM2,  UPRV_LENGTHOF(appleLocsMM2), prefLangsMM2, UPRV_LENGTHOF(prefLangsMM2), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
+    { "MM32",  appleLocsMM3,  UPRV_LENGTHOF(appleLocsMM3), prefLangsMM2, UPRV_LENGTHOF(prefLangsMM2), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
+    { "MM42",  appleLocsMM4,  UPRV_LENGTHOF(appleLocsMM4), prefLangsMM2, UPRV_LENGTHOF(prefLangsMM2), locsToUseMMptPT, UPRV_LENGTHOF(locsToUseMMptPT) },
+    { "MM52",  appleLocsMM5,  UPRV_LENGTHOF(appleLocsMM5), prefLangsMM2, UPRV_LENGTHOF(prefLangsMM2), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
+    { "MM62",  appleLocsMM6,  UPRV_LENGTHOF(appleLocsMM6), prefLangsMM2, UPRV_LENGTHOF(prefLangsMM2), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
+    { "MM13",  appleLocsMM1,  UPRV_LENGTHOF(appleLocsMM1), prefLangsMM3, UPRV_LENGTHOF(prefLangsMM3), locsToUseMMptPT, UPRV_LENGTHOF(locsToUseMMptPT) },
+    { "MM23",  appleLocsMM2,  UPRV_LENGTHOF(appleLocsMM2), prefLangsMM3, UPRV_LENGTHOF(prefLangsMM3), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
+    { "MM33",  appleLocsMM3,  UPRV_LENGTHOF(appleLocsMM3), prefLangsMM3, UPRV_LENGTHOF(prefLangsMM3), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
+    { "MM43",  appleLocsMM4,  UPRV_LENGTHOF(appleLocsMM4), prefLangsMM3, UPRV_LENGTHOF(prefLangsMM3), locsToUseMMptPT, UPRV_LENGTHOF(locsToUseMMptPT) },
+    { "MM53",  appleLocsMM5,  UPRV_LENGTHOF(appleLocsMM5), prefLangsMM3, UPRV_LENGTHOF(prefLangsMM3), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
+    { "MM63",  appleLocsMM6,  UPRV_LENGTHOF(appleLocsMM6), prefLangsMM3, UPRV_LENGTHOF(prefLangsMM3), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
+    { "MM14",  appleLocsMM1,  UPRV_LENGTHOF(appleLocsMM1), prefLangsMM4, UPRV_LENGTHOF(prefLangsMM4), locsToUseMMptPT, UPRV_LENGTHOF(locsToUseMMptPT) },
+    { "MM24",  appleLocsMM2,  UPRV_LENGTHOF(appleLocsMM2), prefLangsMM4, UPRV_LENGTHOF(prefLangsMM4), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
+    { "MM34",  appleLocsMM3,  UPRV_LENGTHOF(appleLocsMM3), prefLangsMM4, UPRV_LENGTHOF(prefLangsMM4), locsToUseMMptPT, UPRV_LENGTHOF(locsToUseMMptPT) },
+    { "MM44",  appleLocsMM4,  UPRV_LENGTHOF(appleLocsMM4), prefLangsMM4, UPRV_LENGTHOF(prefLangsMM4), locsToUseMMptPT, UPRV_LENGTHOF(locsToUseMMptPT) },
+    { "MM54",  appleLocsMM5,  UPRV_LENGTHOF(appleLocsMM5), prefLangsMM4, UPRV_LENGTHOF(prefLangsMM4), locsToUseMMen,   UPRV_LENGTHOF(locsToUseMMen)   }, // want en, see <rdar://problem/22012864>
+    { "MM64",  appleLocsMM6,  UPRV_LENGTHOF(appleLocsMM6), prefLangsMM4, UPRV_LENGTHOF(prefLangsMM4), locsToUseMMptPT, UPRV_LENGTHOF(locsToUseMMptPT) },
+    { "MM15",  appleLocsMM1,  UPRV_LENGTHOF(appleLocsMM1), prefLangsMM5, UPRV_LENGTHOF(prefLangsMM5), locsToUseMMptPT, UPRV_LENGTHOF(locsToUseMMptPT) },
+    { "MM25",  appleLocsMM2,  UPRV_LENGTHOF(appleLocsMM2), prefLangsMM5, UPRV_LENGTHOF(prefLangsMM5), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
+    { "MM35",  appleLocsMM3,  UPRV_LENGTHOF(appleLocsMM3), prefLangsMM5, UPRV_LENGTHOF(prefLangsMM5), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
+    { "MM45",  appleLocsMM4,  UPRV_LENGTHOF(appleLocsMM4), prefLangsMM5, UPRV_LENGTHOF(prefLangsMM5), locsToUseMMptPT, UPRV_LENGTHOF(locsToUseMMptPT) },
+    { "MM55",  appleLocsMM5,  UPRV_LENGTHOF(appleLocsMM5), prefLangsMM5, UPRV_LENGTHOF(prefLangsMM5), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
+    { "MM65",  appleLocsMM6,  UPRV_LENGTHOF(appleLocsMM6), prefLangsMM5, UPRV_LENGTHOF(prefLangsMM5), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
+    { "MM16",  appleLocsMM1,  UPRV_LENGTHOF(appleLocsMM1), prefLangsMM6, UPRV_LENGTHOF(prefLangsMM6), locsToUseMMptPT, UPRV_LENGTHOF(locsToUseMMptPT) },
+    { "MM26",  appleLocsMM2,  UPRV_LENGTHOF(appleLocsMM2), prefLangsMM6, UPRV_LENGTHOF(prefLangsMM6), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
+    { "MM36",  appleLocsMM3,  UPRV_LENGTHOF(appleLocsMM3), prefLangsMM6, UPRV_LENGTHOF(prefLangsMM6), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
+    { "MM46",  appleLocsMM4,  UPRV_LENGTHOF(appleLocsMM4), prefLangsMM6, UPRV_LENGTHOF(prefLangsMM6), locsToUseMMptPT, UPRV_LENGTHOF(locsToUseMMptPT) },
+    { "MM56",  appleLocsMM5,  UPRV_LENGTHOF(appleLocsMM5), prefLangsMM6, UPRV_LENGTHOF(prefLangsMM6), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
+    { "MM66",  appleLocsMM6,  UPRV_LENGTHOF(appleLocsMM6), prefLangsMM6, UPRV_LENGTHOF(prefLangsMM6), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
+    { "MN1",   appleLocsMN,   UPRV_LENGTHOF(appleLocsMN),  prefLangsMN1, UPRV_LENGTHOF(prefLangsMN1), locsToUseMN_U,   UPRV_LENGTHOF(locsToUseMN_U) },
+    { "MN2",   appleLocsMN,   UPRV_LENGTHOF(appleLocsMN),  prefLangsMN2, UPRV_LENGTHOF(prefLangsMN2), locsToUseMN_U,   UPRV_LENGTHOF(locsToUseMN_U) },
+    { "MN3",   appleLocsMN,   UPRV_LENGTHOF(appleLocsMN),  prefLangsMN3, UPRV_LENGTHOF(prefLangsMN3), locsToUseMN_U,   UPRV_LENGTHOF(locsToUseMN_U) },
+    { "MN4",   appleLocsMN,   UPRV_LENGTHOF(appleLocsMN),  prefLangsMN4, UPRV_LENGTHOF(prefLangsMN4), locsToUseMN_U,   UPRV_LENGTHOF(locsToUseMN_U) },
+    { "MO",   appleLocsMO,   UPRV_LENGTHOF(appleLocsMO),  prefLangsMO1, UPRV_LENGTHOF(prefLangsMO1), locsToUseMO1,   UPRV_LENGTHOF(locsToUseMO1) },
+
+    { NULL, NULL, 0, NULL, 0, NULL, 0 }
+};
+
+
+/* general enums */
+
+enum { kMaxLocalizationsToUse = 8, kPrintArrayBufSize = 128 };
+
+// array, array of pointers to strings to print
+// count, count of array elements, may be -1 if array is terminated by a NULL entry
+// buf, buffer into which to put concatenated strings
+// bufSize, length of buf
+static void printStringArray(const char **array, int32_t count, char *buf, int32_t bufSize) {
+    char * bufPtr = buf;
+    const char * curEntry;
+    int32_t idx, countMax = bufSize/16;
+    if (count < 0 || count > countMax) {
+        count = countMax;
+    }
+    for (idx = 0; idx < count && (curEntry = *array++) != NULL; idx++) {
+        int32_t len = sprintf(bufPtr, "%s\"%.12s\"", (idx > 0)? ", ": "", curEntry);
+        if (len <= 0) {
+            break;
+        }
+        bufPtr += len;
+    }
+    *bufPtr = 0; /* ensure termination */
+}
+
+static UBool equalStringArrays(const char **array1, int32_t count1, const char **array2, int32_t count2) {
+    const char ** array1Ptr = array1;
+    const char ** array2Ptr = array2;
+    int32_t idx;
+    if (count1 < 0) {
+        count1 = 0;
+        while (*array1Ptr++ != NULL) {
+            count1++;
+        }
+    }
+    if (count2 < 0) {
+        count2 = 0;
+        while (*array2Ptr++ != NULL) {
+            count2++;
+        }
+    }
+    if (count1 != count2) {
+        return FALSE;
+    }
+    for (idx = 0; idx < count1; idx++) {
+        if (uprv_strcmp(array1[idx], array2[idx]) != 0) {
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+static void TestAppleLocalizationsToUse() {
+    const AppleLocToUseTestSet * testSetPtr;
+    const MultiPrefTest * multiSetPtr;
+    const char * locsToUse[kMaxLocalizationsToUse];
+    int32_t numLocsToUse;
+    UErrorCode status;
+    char printExpected[kPrintArrayBufSize];
+    char printActual[kPrintArrayBufSize];
+
+    for (testSetPtr = altuTestSets; testSetPtr->locAndCountEntriesPtr != NULL; testSetPtr++) {
+        int32_t iLocSet, iLang;
+
+        for (iLocSet = 0; iLocSet < kNumLocSets; iLocSet++) {
+            for (iLang = 0; iLang < testSetPtr->appleLangAndLocCount; iLang++) {
+                const char * language = testSetPtr->appleLangAndLocPtr[iLang].language;
+                const char ** expLocsForSet = testSetPtr->appleLangAndLocPtr[iLang].expLocsForSets[iLocSet];
+                status = U_ZERO_ERROR;
+
+                numLocsToUse = ualoc_localizationsToUse(&language, 1,
+                                                        testSetPtr->locAndCountEntriesPtr[iLocSet].locs, testSetPtr->locAndCountEntriesPtr[iLocSet].locCount,
+                                                        locsToUse, kMaxLocalizationsToUse, &status);
+                if (U_FAILURE(status)) {
+                    log_err("FAIL: ualoc_localizationsToUse testSet %d, locSet %d, lang %s, status %s\n",
+                            testSetPtr-altuTestSets, iLocSet+1, language, u_errorName(status));
+                } else if (numLocsToUse == 0 && expLocsForSet != NULL) {
+                    printStringArray(expLocsForSet, -1, printExpected, kPrintArrayBufSize);
+                    log_err("FAIL: ualoc_localizationsToUse testSet %d, locSet %d, lang %s, expect {%s}, get no results\n",
+                            testSetPtr-altuTestSets, iLocSet+1, language, printExpected);
+                } else if (numLocsToUse > 0 && expLocsForSet == NULL) {
+                    printStringArray(locsToUse, numLocsToUse, printActual, kPrintArrayBufSize);
+                    log_err("FAIL: ualoc_localizationsToUse testSet %d, locSet %d, lang %s, expect no results, get {%s}\n",
+                            testSetPtr-altuTestSets, iLocSet+1, language, printActual);
+                } else if (numLocsToUse > 0 && !equalStringArrays(expLocsForSet, -1, locsToUse, numLocsToUse)) {
+                    printStringArray(expLocsForSet, -1, printExpected, kPrintArrayBufSize);
+                    printStringArray(locsToUse, numLocsToUse, printActual, kPrintArrayBufSize);
+                    log_err("FAIL: ualoc_localizationsToUse testSet %d, locSet %d, lang %s:\n            expect {%s}\n            get    {%s}\n",
+                            testSetPtr-altuTestSets, iLocSet+1, language, printExpected, printActual);
+                }
+            }
+        }
+    }
+
+   for (multiSetPtr = multiTestSets; multiSetPtr->name != NULL; multiSetPtr++) {
+        status = U_ZERO_ERROR;
+        numLocsToUse = ualoc_localizationsToUse(multiSetPtr->prefLangs, multiSetPtr->prefLangsCount, multiSetPtr->availLocs, multiSetPtr->availLocsCount, locsToUse, kMaxLocalizationsToUse, &status);
+        if (U_FAILURE(status)) {
+            log_err("FAIL: ualoc_localizationsToUse appleLocs%s, langs prefLangs%s, status %s\n", multiSetPtr->name, multiSetPtr->name, u_errorName(status));
+        } else if (!equalStringArrays(multiSetPtr->locsToUse, multiSetPtr->locsToUseCount, locsToUse, numLocsToUse)) {
+            printStringArray(multiSetPtr->locsToUse, multiSetPtr->locsToUseCount, printExpected, kPrintArrayBufSize);
+            printStringArray(locsToUse, numLocsToUse, printActual, kPrintArrayBufSize);
+            log_err("FAIL: ualoc_localizationsToUse appleLocs%s, langs prefLangs%s:\n            expect {%s}\n            get    {%s}\n",
+                    multiSetPtr->name, multiSetPtr->name, printExpected, printActual);
+        }
+   }
+}
+