]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/test/cintltst/cloctst.c
ICU-64232.0.1.tar.gz
[apple/icu.git] / icuSources / test / cintltst / cloctst.c
index 281aa1ebbcfcf5ec592095a812ce3528a0493a6b..c38033aa4fd723c04ea5384076a60a7fb706235d 100644 (file)
@@ -1,3 +1,5 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
 /********************************************************************
  * COPYRIGHT:
  * Copyright (c) 1997-2016, International Business Machines Corporation and
@@ -21,6 +23,7 @@
 #include "cstring.h"
 #include "uparse.h"
 #include "uresimp.h"
+#include "uassert.h"
 #include "cmemory.h"
 
 #include "unicode/putil.h"
@@ -38,7 +41,9 @@
 #include "unicode/uldnames.h"
 #include "unicode/parseerr.h" /* may not be included with some uconfig switches */
 #include "udbgutil.h"
+#if !U_PLATFORM_HAS_WIN32_API
 #include "unicode/ualoc.h" /* Apple-specific */
+#endif
 
 static void TestNullDefault(void);
 static void TestNonexistentLanguageExemplars(void);
@@ -50,11 +55,17 @@ static void TestDisplayNameBrackets(void);
 static void TestUnicodeDefines(void);
 
 static void TestIsRightToLeft(void);
-static void TestUldnNameVariants(void);
+static void TestBadLocaleIDs(void);
+static void TestBug20370(void);
+static void TestBug20321UnicodeLocaleKey(void);
 
+static void TestUldnNameVariants(void);
+static void TestRootUndEmpty(void);
+#if !U_PLATFORM_HAS_WIN32_API
 static void TestGetLanguagesForRegion(void);
 static void TestGetAppleParent(void);
 static void TestAppleLocalizationsToUse(void);
+#endif
 
 void PrintDataTable();
 
@@ -89,12 +100,12 @@ static const char* const rawData2[LOCALE_INFO_SIZE][LOCALE_SIZE] = {
     /* display script code (English) */
     {   "",     "",     "",     "",     "",     "Simplified Han", "", "", ""       },
     /* display country (English) */
-    {   "United States",    "France",   "Spain",  "Greece",   "Norway", "China", "Germany", "", "Japan"       },
+    {   "United States",    "France",   "Spain",  "Greece",   "Norway", "China mainland", "Germany", "", "Japan"       },
     /* display variant (English) */
     {   "",     "",     "",     "",     "NY",  "", "", "", ""       },
     /* display name (English) */
     {   "English (United States)", "French (France)", "Catalan (Spain)", 
-        "Greek (Greece)", "Norwegian (Norway, NY)", "Chinese (Simplified, China)", 
+        "Greek (Greece)", "Norwegian (Norway, NY)", "Chinese, Simplified (China mainland)", 
         "German (Germany, Sort Order=Phonebook Sort Order)", "Spanish (Sort Order=Traditional Sort Order)", "Japanese (Japan, Calendar=Japanese Calendar)" },
 
     /* display language (French) */
@@ -102,12 +113,12 @@ static const char* const rawData2[LOCALE_INFO_SIZE][LOCALE_SIZE] = {
     /* display script code (French) */
     {   "",     "",     "",     "",     "",     "sinogrammes simplifi\\u00e9s", "", "", ""         },
     /* display country (French) */
-    {   "\\u00C9tats-Unis",    "France",   "Espagne",  "Gr\\u00E8ce",   "Norv\\u00E8ge",    "Chine", "Allemagne", "", "Japon"       },
+    {   "\\u00C9tats-Unis",    "France",   "Espagne",  "Gr\\u00E8ce",   "Norv\\u00E8ge",    "Chine continentale", "Allemagne", "", "Japon"       },
     /* display variant (French) */
     {   "",     "",     "",     "",     "NY",   "", "", "", ""       },
     /* display name (French) */
     {   "anglais (\\u00C9tats-Unis)", "fran\\u00E7ais (France)", "catalan (Espagne)", 
-        "grec (Gr\\u00E8ce)", "norv\\u00E9gien (Norv\\u00E8ge, NY)",  "chinois (simplifi\\u00e9, Chine)", 
+        "grec (Gr\\u00E8ce)", "norv\\u00E9gien (Norv\\u00E8ge, NY)",  "chinois simplifi\\u00e9 (Chine continentale)", 
         "allemand (Allemagne, ordre de tri=ordre de l\\u2019annuaire)", "espagnol (ordre de tri=ordre traditionnel)", "japonais (Japon, calendrier=calendrier japonais)" },
 
     /* display language (Catalan) */
@@ -115,12 +126,12 @@ static const char* const rawData2[LOCALE_INFO_SIZE][LOCALE_SIZE] = {
     /* display script code (Catalan) */
     {   "",     "",     "",     "",     "",     "han simplificat", "", "", ""         },
     /* display country (Catalan) */
-    {   "Estats Units", "Fran\\u00E7a", "Espanya",  "Gr\\u00E8cia", "Noruega",  "Xina", "Alemanya", "", "Jap\\u00F3"    },
+    {   "Estats Units", "Fran\\u00E7a", "Espanya",  "Gr\\u00E8cia", "Noruega",  "Xina continental", "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)", 
+    "grec (Gr\\u00E8cia)", "noruec (Noruega, NY)", "xin\\u00E8s simplificat (Xina continental)", 
     "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) */
@@ -145,7 +156,7 @@ static const char* const rawData2[LOCALE_INFO_SIZE][LOCALE_SIZE] = {
         "\\u0399\\u03c3\\u03c0\\u03b1\\u03bd\\u03af\\u03b1",
         "\\u0395\\u03bb\\u03bb\\u03ac\\u03b4\\u03b1",
         "\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03af\\u03b1",
-        "\\u039A\\u03AF\\u03BD\\u03B1", 
+        "\\u039A\\u03AF\\u03BD\\u03B1 \\u03B7\\u03C0\\u03B5\\u03B9\\u03C1\\u03C9\\u03C4\\u03B9\\u03BA\\u03AE", 
         "\\u0393\\u03B5\\u03C1\\u03BC\\u03B1\\u03BD\\u03AF\\u03B1", 
         "", 
         "\\u0399\\u03B1\\u03C0\\u03C9\\u03BD\\u03AF\\u03B1"   
@@ -159,7 +170,7 @@ static const char* const rawData2[LOCALE_INFO_SIZE][LOCALE_SIZE] = {
         "\\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\\u03bf, \\u039A\\u03AF\\u03BD\\u03B1)",
+        "\\u0391\\u03c0\\u03bb\\u03bf\\u03c0\\u03bf\\u03b9\\u03b7\\u03bc\\u03ad\\u03bd\\u03b1 \\u039A\\u03B9\\u03BD\\u03B5\\u03B6\\u03B9\\u03BA\\u03AC (\\u039A\\u03AF\\u03BD\\u03B1 \\u03B7\\u03C0\\u03B5\\u03B9\\u03C1\\u03C9\\u03C4\\u03B9\\u03BA\\u03AE)",
         "\\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)"
@@ -230,6 +241,7 @@ void addLocaleTest(TestNode** root)
     TESTCASE(TestKeywordVariants);
     TESTCASE(TestKeywordVariantParsing);
     TESTCASE(TestCanonicalization);
+    TESTCASE(TestCanonicalizationBuffer);
     TESTCASE(TestKeywordSet);
     TESTCASE(TestKeywordSetError);
     TESTCASE(TestDisplayKeywords);
@@ -254,7 +266,10 @@ void addLocaleTest(TestNode** root)
     TESTCASE(TestOrientation);
     TESTCASE(TestLikelySubtags);
     TESTCASE(TestToLanguageTag);
+    TESTCASE(TestBug20132);
     TESTCASE(TestForLanguageTag);
+    TESTCASE(TestInvalidLanguageTag);
+    TESTCASE(TestLangAndRegionCanonicalize);
     TESTCASE(TestTrailingNull);
     TESTCASE(TestUnicodeDefines);
     TESTCASE(TestEnglishExemplarCharacters);
@@ -264,10 +279,16 @@ void addLocaleTest(TestNode** root)
     TESTCASE(TestToLegacyKey);
     TESTCASE(TestToUnicodeLocaleType);
     TESTCASE(TestToLegacyType);
+    TESTCASE(TestBadLocaleIDs);
+    TESTCASE(TestBug20370);
+    TESTCASE(TestBug20321UnicodeLocaleKey);
     TESTCASE(TestUldnNameVariants);
+    TESTCASE(TestRootUndEmpty);
+#if !U_PLATFORM_HAS_WIN32_API
     TESTCASE(TestGetLanguagesForRegion);
     TESTCASE(TestGetAppleParent);
     TESTCASE(TestAppleLocalizationsToUse);
+#endif
 }
 
 
@@ -421,10 +442,7 @@ static void TestPrefixes() {
         {"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},
-        
+        {"hy", "", "", "AREVMDA", "hy_AREVMDA", "hy__AREVMDA", "hyw"},
         {"de", "", "", "1901", "de-1901", "de__1901", NULL},
         {"mr", "", "", "", "mr.utf8", "mr.utf8", "mr"},
         {"de", "", "TV", "", "de-tv.koi8r", "de_TV.koi8r", "de_TV"},
@@ -437,11 +455,16 @@ static void TestPrefixes() {
         {"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 */
-        
+
+        // Before ICU 64, ICU locale canonicalization had some additional mappings.
+        // They were removed for ICU-20187 "drop support for long-obsolete locale ID variants".
+        // The following now use standard canonicalization.
+        {"zh", "Hans", "", "PINYIN", "zh-Hans-pinyin", "zh_Hans__PINYIN", "zh_Hans__PINYIN"},
+        {"zh", "Hant", "TW", "STROKE", "zh-hant_TW_STROKE", "zh_Hant_TW_STROKE", "zh_Hant_TW_STROKE"},
+
         {NULL,NULL,NULL,NULL,NULL,NULL,NULL}
     };
     
@@ -742,8 +765,8 @@ static void TestDisplayNames()
         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)";
+                "\\u30a2\\u30bc\\u30eb\\u30d0\\u30a4\\u30b8\\u30e3\\u30f3\\u8a9e"
+                "\\uff08\\u30ad\\u30ea\\u30eb\\u6587\\u5b57\\uff09";
         UErrorCode ec=U_ZERO_ERROR;
         UChar result[256];
         int32_t len;
@@ -1062,11 +1085,11 @@ static const DisplayNameBracketsItem displayNameBracketsItems[] = {
     { "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"         },
+                                "\\u82F1\\u8BED\\uFF08\\u79D1\\u79D1\\u65AF\\uFF3B\\u57FA\\u6797\\uFF3D\\u7FA4\\u5C9B\\uFF09",
+                                "\\u82F1\\u8BED\\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"                                     },
+                                "\\u6CD5\\u8BED\\uFF08\\u521A\\u679C\\uFF3B\\u5E03\\uFF3D\\uFF09",
+                                "\\u6CD5\\u8BED\\uFF08\\u521A\\u679C\\uFF3B\\u5E03\\uFF3D\\uFF09"                                     },
     { NULL, NULL, NULL,         NULL,                       NULL,                                  NULL                               }
 };
 
@@ -1726,7 +1749,7 @@ static void TestKeywordVariants(void)
             "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",
+            "de_DE_EURO",
             {"","","","","","",""},
             0,
             U_INVALID_FORMAT_ERROR /* must have '=' after '@' */
@@ -1797,6 +1820,7 @@ static void TestKeywordVariants(void)
 
         status = U_ZERO_ERROR;
         resultLen = uloc_getName(testCases[i].localeID, buffer, 256, &status);
+        U_ASSERT(resultLen < 256);
         if (U_SUCCESS(status)) {
             if (testCases[i].expectedLocaleID == 0) {
                 log_err("Expected uloc_getName(\"%s\") to fail; got \"%s\"\n",
@@ -1814,6 +1838,7 @@ static void TestKeywordVariants(void)
 
         status = U_ZERO_ERROR;
         resultLen = uloc_getBaseName(testCases[i].localeID, buffer, 256, &status);
+        U_ASSERT(resultLen < 256);
         if (U_SUCCESS(status)) {
             if (testCases[i].expectedLocaleIDNoKeywords == 0) {
                 log_err("Expected uloc_getBaseName(\"%s\") to fail; got \"%s\"\n",
@@ -1831,6 +1856,7 @@ static void TestKeywordVariants(void)
 
         status = U_ZERO_ERROR;
         resultLen = uloc_canonicalize(testCases[i].localeID, buffer, 256, &status);
+        U_ASSERT(resultLen < 256);
         if (U_SUCCESS(status)) {
             if (testCases[i].expectedCanonicalID == 0) {
                 log_err("Expected uloc_canonicalize(\"%s\") to fail; got \"%s\"\n",
@@ -1853,27 +1879,38 @@ static void TestKeywordVariantParsing(void)
     static const struct {
         const char *localeID;
         const char *keyword;
-        const char *expectedValue;
+        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", "Phonebook" },
+        { "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 = U_ZERO_ERROR;
-    
+    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(uprv_strcmp(testCases[i].expectedValue, buffer) != 0) {
-            log_err("Expected to extract \"%s\" from \"%s\" for keyword \"%s\". Got \"%s\" instead\n",
-                testCases[i].expectedValue, testCases[i].localeID, testCases[i].keyword, buffer);
+        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);
+            
         }
     }
 }
@@ -1926,7 +1963,40 @@ static const struct {
   /* 4. removal of only item */
   { "de@collation=phonebook", "collation", NULL, "de" },
 #endif
-  { "de@collation=phonebook", "Currency", "CHF", "de@collation=phonebook;currency=CHF" }
+  { "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 },
 };
 
 
@@ -1939,31 +2009,59 @@ static void TestKeywordSet(void)
     char cbuffer[1024];
 
     for(i = 0; i < UPRV_LENGTHOF(kwSetTestCases); i++) {
-        UErrorCode status = U_ZERO_ERROR;
-        memset(buffer,'%',1023);
-        strcpy(buffer, kwSetTestCases[i].l);
+      UErrorCode status = U_ZERO_ERROR;
+      memset(buffer,'%',1023);
+      strcpy(buffer, kwSetTestCases[i].l);
 
+      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);
         }
-          /* sanity check test case results for canonicity */
+        /* 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);
         }
 
+        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: got error %s\n", i, u_errorName(status));
-          continue;
-        }
-        if(strcmp(buffer,kwSetTestCases[i].x) || ((int32_t)strlen(buffer)!=resultLen)) {
-          log_err("FAIL: #%d: %s + [%s=%s] -> %s (%d) expected %s (%d)\n", i, kwSetTestCases[i].l, kwSetTestCases[i].k,
+          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);
+          }
+        }
+      }
     }
 }
 
@@ -2070,57 +2168,21 @@ static void TestCanonicalization(void)
         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" },
+        { "ca_ES-with-extra-stuff-that really doesn't make any sense-unless-you're trying to increase code coverage",
+          "ca_ES_WITH_EXTRA_STUFF_THAT REALLY DOESN'T MAKE ANY SENSE_UNLESS_YOU'RE TRYING TO INCREASE CODE COVERAGE",
+          "ca_ES_WITH_EXTRA_STUFF_THAT REALLY DOESN'T MAKE ANY SENSE_UNLESS_YOU'RE TRYING TO INCREASE CODE COVERAGE"},
         { "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 */
+        { "qz-qz@Euro", "qz_QZ@Euro", "qz_QZ_EURO" }, /* 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" },
@@ -2135,12 +2197,6 @@ static void TestCanonicalization(void)
         { "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] */ },
 
@@ -2151,9 +2207,55 @@ static void TestCanonicalization(void)
         { "ja_JP", "ja_JP", "ja_JP" },
 
         /* test case for "i-default" */
-        { "i-default", "en@x=i-default", "en@x=i-default" }
+        { "i-default", "en@x=i-default", "en@x=i-default" },
+
+        // Before ICU 64, ICU locale canonicalization had some additional mappings.
+        // They were removed for ICU-20187 "drop support for long-obsolete locale ID variants".
+        // The following now use standard canonicalization.
+        { "ca_ES_PREEURO", "ca_ES_PREEURO", "ca_ES_PREEURO" },
+        { "de_AT_PREEURO", "de_AT_PREEURO", "de_AT_PREEURO" },
+        { "de_DE_PREEURO", "de_DE_PREEURO", "de_DE_PREEURO" },
+        { "de_LU_PREEURO", "de_LU_PREEURO", "de_LU_PREEURO" },
+        { "el_GR_PREEURO", "el_GR_PREEURO", "el_GR_PREEURO" },
+        { "en_BE_PREEURO", "en_BE_PREEURO", "en_BE_PREEURO" },
+        { "en_IE_PREEURO", "en_IE_PREEURO", "en_IE_PREEURO" },
+        { "es_ES_PREEURO", "es_ES_PREEURO", "es_ES_PREEURO" },
+        { "eu_ES_PREEURO", "eu_ES_PREEURO", "eu_ES_PREEURO" },
+        { "fi_FI_PREEURO", "fi_FI_PREEURO", "fi_FI_PREEURO" },
+        { "fr_BE_PREEURO", "fr_BE_PREEURO", "fr_BE_PREEURO" },
+        { "fr_FR_PREEURO", "fr_FR_PREEURO", "fr_FR_PREEURO" },
+        { "fr_LU_PREEURO", "fr_LU_PREEURO", "fr_LU_PREEURO" },
+        { "ga_IE_PREEURO", "ga_IE_PREEURO", "ga_IE_PREEURO" },
+        { "gl_ES_PREEURO", "gl_ES_PREEURO", "gl_ES_PREEURO" },
+        { "it_IT_PREEURO", "it_IT_PREEURO", "it_IT_PREEURO" },
+        { "nl_BE_PREEURO", "nl_BE_PREEURO", "nl_BE_PREEURO" },
+        { "nl_NL_PREEURO", "nl_NL_PREEURO", "nl_NL_PREEURO" },
+        { "pt_PT_PREEURO", "pt_PT_PREEURO", "pt_PT_PREEURO" },
+        { "de__PHONEBOOK", "de__PHONEBOOK", "de__PHONEBOOK" },
+        { "en_GB_EURO", "en_GB_EURO", "en_GB_EURO" },
+        { "en_GB@EURO", "en_GB@EURO", "en_GB_EURO" }, /* POSIX ID */
+        { "es__TRADITIONAL", "es__TRADITIONAL", "es__TRADITIONAL" },
+        { "hi__DIRECT", "hi__DIRECT", "hi__DIRECT" },
+        { "ja_JP_TRADITIONAL", "ja_JP_TRADITIONAL", "ja_JP_TRADITIONAL" },
+        { "th_TH_TRADITIONAL", "th_TH_TRADITIONAL", "th_TH_TRADITIONAL" },
+        { "zh_TW_STROKE", "zh_TW_STROKE", "zh_TW_STROKE" },
+        { "zh__PINYIN", "zh__PINYIN", "zh__PINYIN" },
+        { "zh_CN_STROKE", "zh_CN_STROKE", "zh_CN_STROKE" },
+        { "sr-SP-Cyrl", "sr_SP_CYRL", "sr_SP_CYRL" }, /* .NET name */
+        { "sr-SP-Latn", "sr_SP_LATN", "sr_SP_LATN" }, /* .NET name */
+        { "sr_YU_CYRILLIC", "sr_YU_CYRILLIC", "sr_YU_CYRILLIC" }, /* Linux name */
+        { "uz-UZ-Cyrl", "uz_UZ_CYRL", "uz_UZ_CYRL" }, /* .NET name */
+        { "uz-UZ-Latn", "uz_UZ_LATN", "uz_UZ_LATN" }, /* .NET name */
+        { "zh-CHS", "zh_CHS", "zh_CHS" }, /* .NET name */
+        { "zh-CHT", "zh_CHT", "zh_CHT" }, /* .NET name This may change back to zh_Hant */
+        /* PRE_EURO and EURO conversions don't affect other keywords */
+        { "es_ES_PREEURO@CALendar=Japanese", "es_ES_PREEURO@calendar=Japanese", "es_ES_PREEURO@calendar=Japanese" },
+        { "es_ES_EURO@SHOUT=zipeedeedoodah", "es_ES_EURO@shout=zipeedeedoodah", "es_ES_EURO@shout=zipeedeedoodah" },
+        /* currency keyword overrides PRE_EURO and EURO currency */
+        { "es_ES_PREEURO@currency=EUR", "es_ES_PREEURO@currency=EUR", "es_ES_PREEURO@currency=EUR" },
+        { "es_ES_EURO@currency=ESP", "es_ES_EURO@currency=ESP", "es_ES_EURO@currency=ESP" },
     };
-    
+
     static const char* label[] = { "getName", "canonicalize" };
 
     UErrorCode status = U_ZERO_ERROR;
@@ -2203,6 +2305,42 @@ static void TestCanonicalization(void)
     }
 }
 
+static void TestCanonicalizationBuffer(void)
+{
+    UErrorCode status = U_ZERO_ERROR;
+    char buffer[256];
+
+    // ULOC_FULLNAME_CAPACITY == 157 (uloc.h)
+    static const char name[] =
+        "zh@x"
+        "=foo-bar-baz-foo-bar-baz-foo-bar-baz-foo-bar-baz"
+        "-foo-bar-baz-foo-bar-baz-foo-bar-baz-foo-bar-baz"
+        "-foo-bar-baz-foo-bar-baz-foo-bar-baz-foo-bar-baz"
+        "-foo-barz"
+    ;
+    static const size_t len = sizeof(name) - 1;  // Without NUL terminator.
+
+    int32_t reslen = uloc_canonicalize(name, buffer, (int32_t)len, &status);
+
+    if (U_FAILURE(status)) {
+        log_err("FAIL: uloc_canonicalize(%s) => %s, expected !U_FAILURE()\n",
+                name, u_errorName(status));
+        return;
+    }
+
+    if (reslen != len) {
+        log_err("FAIL: uloc_canonicalize(%s) => \"%i\", expected \"%u\"\n",
+                name, reslen, len);
+        return;
+    }
+
+    if (uprv_strncmp(name, buffer, len) != 0) {
+        log_err("FAIL: uloc_canonicalize(%s) => \"%.*s\", expected \"%s\"\n",
+                name, reslen, buffer, name);
+        return;
+    }
+}
+
 static void TestDisplayKeywords(void)
 {
     int32_t i;
@@ -2804,16 +2942,20 @@ static void TestAcceptLanguage(void) {
         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 },
-        /*1*/{ 1, NULL, "en", ULOC_ACCEPT_VALID },
-        /*2*/{ 2, NULL, "en", ULOC_ACCEPT_FALLBACK },
-        /*3*/{ 3, NULL, "", ULOC_ACCEPT_FAILED },
-        /*4*/{ 4, NULL, "es", ULOC_ACCEPT_VALID },
-        
-        /*5*/{ 5, NULL, "en", ULOC_ACCEPT_VALID },  /* XF */
-        /*6*/{ 6, NULL, "ja", ULOC_ACCEPT_FALLBACK },  /* XF */
-        /*7*/{ 7, NULL, "zh", ULOC_ACCEPT_FALLBACK },  /* XF */
+        /*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[] = {
@@ -2829,10 +2971,25 @@ static void TestAcceptLanguage(void) {
               "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++) {
@@ -2847,17 +3004,22 @@ static void TestAcceptLanguage(void) {
         (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(outResult != tests[i].res) {
+        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((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));
+            }
+            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));
+            }
         }
     }
 }
@@ -3049,7 +3211,26 @@ static void  TestOrientation()
         { "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 }
+        { "en", ULOC_LAYOUT_LTR, ULOC_LAYOUT_TTB },
+        // Additional Apple tests for rdar://51447187
+        { "sd",       ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
+        { "sd_Arab",  ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
+        { "sd_Deva",  ULOC_LAYOUT_LTR, ULOC_LAYOUT_TTB },
+        { "mni_Beng", ULOC_LAYOUT_LTR, ULOC_LAYOUT_TTB },
+        { "mni_Mtei", ULOC_LAYOUT_LTR, ULOC_LAYOUT_TTB },
+        { "sat_Deva", ULOC_LAYOUT_LTR, ULOC_LAYOUT_TTB },
+        { "sat_Olck", ULOC_LAYOUT_LTR, ULOC_LAYOUT_TTB },
+        { "ks",       ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
+        { "ks_Arab",  ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
+        { "ks_Aran",  ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
+        { "ks_Deva",  ULOC_LAYOUT_LTR, ULOC_LAYOUT_TTB },
+        { "pa",       ULOC_LAYOUT_LTR, ULOC_LAYOUT_TTB },
+        { "pa_Guru",  ULOC_LAYOUT_LTR, ULOC_LAYOUT_TTB },
+        { "pa_Arab",  ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
+        { "pa_Aran",  ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
+        { "ur",       ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
+        { "ur_Arab",  ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
+        { "ur_Aran",  ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
     };
 
     size_t i = 0;
@@ -3403,6 +3584,45 @@ const char* const basic_maximize_data[][2] = {
   }, {
      "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"
+  }, { // start Apple tests for <rdar://problem/47494884>
+    "ur",
+    "ur_Aran_PK"
+  }, {
+    "ks",
+    "ks_Aran_IN"
+  }, {
+    "und_Aran_PK",
+    "ur_Aran_PK"
+  }, {
+    "und_Aran_IN",
+    "ks_Aran_IN"
+  }, {
+    "ur_PK",
+    "ur_Aran_PK"
+  }, {
+    "ks_IN",
+    "ks_Aran_IN"
+  }, {
+    "ur_Arab",
+    "ur_Arab_PK"
+  }, {
+    "ks_Arab",
+    "ks_Arab_IN"
   }
 };
 
@@ -3795,10 +4015,14 @@ const char* const full_data[][3] = {
   }, {
     "pa_Arab",
     "pa_Arab_PK",
+    "pa_Arab"
+  }, {
+    "pa_Aran",
+    "pa_Aran_PK",
     "pa_PK"
   }, {
     "pa_PK",
-    "pa_Arab_PK",
+    "pa_Aran_PK", // <rdar://problem/50687287>
     "pa_PK"
   }, {
     "pap",
@@ -4027,11 +4251,11 @@ const char* const full_data[][3] = {
   }, {
     "und_Arab_IN",
     "ur_Arab_IN",
-    "ur_IN"
+    "ur_Arab_IN" // Apple <rdar://problem/47494884>
   }, {
     "und_Arab_PK",
     "ur_Arab_PK",
-    "ur"
+    "ur_Arab", // Apple <rdar://problem/47494884>
   }, {
     "und_Arab_SN",
     "ar_Arab_SN",
@@ -4870,7 +5094,7 @@ const char* const full_data[][3] = {
     "ii"
   }, {
     "ur",
-    "ur_Arab_PK",
+    "ur_Aran_PK", // Apple <rdar://problem/47494884>
     "ur"
   }, {
     "uz",
@@ -5042,8 +5266,8 @@ const char* const full_data[][3] = {
     "zh_TW"
   }, {
     "und_Hant_CN",
-    "yue_Hant_CN",
-    "yue_Hant_CN"
+    "zh_Hant_CN",
+    "zh_Hant_CN"
   }, {
     "und_Hant_TW",
     "zh_Hant_TW",
@@ -5248,6 +5472,10 @@ const char* const full_data[][3] = {
     "zh_AQ",
     "zh_Hans_AQ",
     "zh_AQ"
+  }, {
+    "zh_MY",
+    "zh_Hans_MY",
+    "zh_MY"
   }, {
     "zh_Zzzz",
     "zh_Hans_CN",
@@ -5579,7 +5807,7 @@ 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);
+        return (int32_t)strlen(data->expected);
     }
     else
     {
@@ -5595,7 +5823,7 @@ static int32_t getBufferSize(const errorData* data, int32_t actualSize)
     }
     else if (data->bufferSize < 0)
     {
-        return strlen(data->expected) + 1;
+        return (int32_t)strlen(data->expected) + 1;
     }
     else
     {
@@ -5807,7 +6035,6 @@ const char* const locale_to_langtag[][3] = {
     {"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"},
@@ -5827,6 +6054,20 @@ const char* const locale_to_langtag[][3] = {
     {"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"},
+    {"en@9=efg;a=baz",    "en-9-efg-a-baz", "en-9-efg-a-baz"},
+
+    // Before ICU 64, ICU locale canonicalization had some additional mappings.
+    // They were removed for ICU-20187 "drop support for long-obsolete locale ID variants".
+    // The following now uses standard canonicalization.
+    {"az_AZ_CYRL", "az-AZ-x-lvariant-cyrl", NULL},
+
     {NULL,          NULL,           NULL}
 };
 
@@ -5886,13 +6127,53 @@ static void TestToLanguageTag(void) {
     }
 }
 
+static void TestBug20132(void) {
+    char langtag[256];
+    UErrorCode status;
+    int32_t len;
+
+    static const char inloc[] = "en-C";
+    static const char expected[] = "en-x-lvariant-c";
+    const int32_t expected_len = (int32_t)uprv_strlen(expected);
+
+    /* Before ICU-20132 was fixed, calling uloc_toLanguageTag() with a too small
+     * buffer would not immediately return the buffer size actually needed, but
+     * instead require several iterations before getting the correct size. */
+
+    status = U_ZERO_ERROR;
+    len = uloc_toLanguageTag(inloc, langtag, 1, FALSE, &status);
+
+    if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR) {
+        log_data_err("Error returned by uloc_toLanguageTag for locale id [%s] - error: %s Are you missing data?\n",
+            inloc, u_errorName(status));
+    }
+
+    if (len != expected_len) {
+        log_err("Bad length returned by uloc_toLanguageTag for locale id [%s]: %i != %i\n", inloc, len, expected_len);
+    }
+
+    status = U_ZERO_ERROR;
+    len = uloc_toLanguageTag(inloc, langtag, expected_len, FALSE, &status);
+
+    if (U_FAILURE(status)) {
+        log_data_err("Error returned by uloc_toLanguageTag for locale id [%s] - error: %s Are you missing data?\n",
+            inloc, u_errorName(status));
+    }
+
+    if (len != expected_len) {
+        log_err("Bad length returned by uloc_toLanguageTag for locale id [%s]: %i != %i\n", inloc, len, expected_len);
+    } else if (uprv_strncmp(langtag, expected, expected_len) != 0) {
+        log_data_err("uloc_toLanguageTag returned language tag [%.*s] for input locale [%s] - expected: [%s]. Are you missing data?\n",
+            len, langtag, inloc, expected);
+    }
+}
+
 #define FULL_LENGTH -1
 static const struct {
     const char  *bcpID;
     const char  *locID;
     int32_t     len;
 } langtag_to_locale[] = {
-    {"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},
     {"en",                  "en",                   FULL_LENGTH},
     {"en-us",               "en_US",                FULL_LENGTH},
     {"und-US",              "_US",                  FULL_LENGTH},
@@ -5906,6 +6187,7 @@ static const struct {
     {"art-lojban",          "jbo",                  FULL_LENGTH},
     {"zh-hakka",            "hak",                  FULL_LENGTH},
     {"zh-cmn-CH",           "cmn_CH",               FULL_LENGTH},
+    {"zh-cmn-CH-u-co-pinyin", "cmn_CH@collation=pinyin", FULL_LENGTH},
     {"xxx-yy",              "xxx_YY",               FULL_LENGTH},
     {"fr-234",              "fr_234",               FULL_LENGTH},
     {"i-default",           "en@x=i-default",       FULL_LENGTH},
@@ -5936,10 +6218,43 @@ static const struct {
     {"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},
-    {NULL,          NULL,           0}
+    {"de-1901-1901", "de__1901", 7},
+    {"de-DE-1901-1901", "de_DE_1901", 10},
+    {"en-a-bbb-a-ccc", "en@a=bbb", 8},
+    /* #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},
+    // #20098
+    {"hant-cmn-cn", "hant", 4},
+    {"zh-cmn-TW", "cmn_TW", FULL_LENGTH},
+    {"zh-x_t-ab", "zh", 2},
+    {"zh-hans-cn-u-ca-x_t-u", "zh_Hans_CN@calendar=yes",  15},
+    /* #20140 dupe keys in U-extension */
+    {"zh-u-ca-chinese-ca-gregory", "zh@calendar=chinese", FULL_LENGTH},
+    {"zh-u-ca-gregory-co-pinyin-ca-chinese", "zh@calendar=gregorian;collation=pinyin", FULL_LENGTH},
+    {"de-latn-DE-1901-u-co-phonebk-co-pinyin-ca-gregory", "de_Latn_DE_1901@calendar=gregorian;collation=phonebook", FULL_LENGTH},
+    {"th-u-kf-nu-thai-kf-false", "th@colcasefirst=yes;numbers=thai", FULL_LENGTH},
+    /* #9562 IANA language tag data update */
+    {"en-gb-oed", "en_GB_OXENDICT", FULL_LENGTH},
+    {"i-navajo", "nv", FULL_LENGTH},
+    {"i-navajo-a-foo", "nv@a=foo", FULL_LENGTH},
+    {"i-navajo-latn-us", "nv_Latn_US", FULL_LENGTH},
+    {"sgn-br", "bzs", FULL_LENGTH},
+    {"sgn-br-u-co-phonebk", "bzs@collation=phonebook", FULL_LENGTH},
+    {"ja-latn-hepburn-heploc", "ja_Latn__ALALC97", FULL_LENGTH},
+    {"ja-latn-hepburn-heploc-u-ca-japanese", "ja_Latn__ALALC97@calendar=japanese", FULL_LENGTH},
+    {"en-a-bcde-0-fgh", "en@0=fgh;a=bcde", FULL_LENGTH},
 };
 
 static void TestForLanguageTag(void) {
@@ -5949,12 +6264,12 @@ static void TestForLanguageTag(void) {
     int32_t parsedLen;
     int32_t expParsedLen;
 
-    for (i = 0; langtag_to_locale[i].bcpID != NULL; i++) {
+    for (i = 0; i < UPRV_LENGTHOF(langtag_to_locale); 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);
+            expParsedLen = (int32_t)uprv_strlen(langtag_to_locale[i].bcpID);
         }
         uloc_forLanguageTag(langtag_to_locale[i].bcpID, locale, sizeof(locale), &parsedLen, &status);
         if (U_FAILURE(status)) {
@@ -5973,6 +6288,72 @@ static void TestForLanguageTag(void) {
     }
 }
 
+/* See https://unicode-org.atlassian.net/browse/ICU-20149 .
+ * Depending on the resolution of that bug, this test may have
+ * to be revised.
+ */
+static void TestInvalidLanguageTag(void) {
+    static const char* invalid_lang_tags[] = {
+        "zh-u-foo-foo-co-pinyin", /* duplicate attribute in U extension */
+        "zh-cmn-hans-u-foo-foo-co-pinyin", /* duplicate attribute in U extension */
+#if 0
+        /*
+         * These do not lead to an error. Instead, parsing stops at the 1st
+         * invalid subtag.
+         */
+        "de-DE-1901-1901", /* duplicate variant */
+        "en-a-bbb-a-ccc", /* duplicate extension */
+#endif
+        NULL
+    };
+    char locale[256];
+    for (const char** tag = invalid_lang_tags; *tag != NULL; tag++) {
+        UErrorCode status = U_ZERO_ERROR;
+        uloc_forLanguageTag(*tag, locale, sizeof(locale), NULL, &status);
+        if (status != U_ILLEGAL_ARGUMENT_ERROR) {
+            log_err("Error returned by uloc_forLanguageTag for input language tag [%s] : %s - expected error:  %s\n",
+                    *tag, u_errorName(status), u_errorName(U_ILLEGAL_ARGUMENT_ERROR));
+        }
+    }
+}
+
+static const struct {
+    const char  *input;
+    const char  *canonical;
+} langtag_to_canonical[] = {
+    {"de-DD", "de-DE"},
+    {"de-DD-u-co-phonebk", "de-DE-u-co-phonebk"},
+    {"jw-id", "jv-ID"},
+    {"jw-id-u-ca-islamic-civil", "jv-ID-u-ca-islamic-civil"},
+    {"mo-md", "ro-MD"},
+    {"my-bu-u-nu-mymr", "my-MM-u-nu-mymr"},
+    {"yuu-ru", "yug-RU"},
+};
+
+
+static void TestLangAndRegionCanonicalize(void) {
+    char locale[256];
+    char canonical[256];
+    int32_t i;
+    UErrorCode status;
+    for (i = 0; i < UPRV_LENGTHOF(langtag_to_canonical); i++) {
+        status = U_ZERO_ERROR;
+        const char* input = langtag_to_canonical[i].input;
+        uloc_forLanguageTag(input, locale, sizeof(locale), NULL, &status);
+        uloc_toLanguageTag(locale, canonical, sizeof(canonical), TRUE, &status);
+        if (U_FAILURE(status)) {
+            log_err_status(status, "Error returned by uloc_forLanguageTag or uloc_toLanguageTag "
+                           "for language tag [%s] - error: %s\n", input, u_errorName(status));
+        } else {
+            const char* expected_canonical = langtag_to_canonical[i].canonical;
+            if (uprv_strcmp(expected_canonical, canonical) != 0) {
+                log_data_err("input language tag [%s] is canonicalized to [%s] - expected: [%s]\n",
+                    input, canonical, expected_canonical);
+            }
+        }
+    }
+}
+
 static void TestToUnicodeLocaleKey(void)
 {
     /* $IN specifies the result should be the input pointer itself */
@@ -6009,6 +6390,39 @@ static void TestToUnicodeLocaleKey(void)
     }
 }
 
+static void TestBug20321UnicodeLocaleKey(void)
+{
+    // key = alphanum alpha ;
+    static const char* invalid[] = {
+        "a0",
+        "00",
+        "a@",
+        "0@",
+        "@a",
+        "@a",
+        "abc",
+        "0bc",
+    };
+    for (int i = 0; i < UPRV_LENGTHOF(invalid); i++) {
+        const char* bcpKey = NULL;
+        bcpKey = uloc_toUnicodeLocaleKey(invalid[i]);
+        if (bcpKey != NULL) {
+            log_err("toUnicodeLocaleKey: keyword=%s => %s, expected=NULL\n", invalid[i], bcpKey);
+        }
+    }
+    static const char* valid[] = {
+        "aa",
+        "0a",
+    };
+    for (int i = 0; i < UPRV_LENGTHOF(valid); i++) {
+        const char* bcpKey = NULL;
+        bcpKey = uloc_toUnicodeLocaleKey(valid[i]);
+        if (bcpKey == NULL) {
+            log_err("toUnicodeLocaleKey: keyword=%s => NULL, expected!=NULL\n", valid[i]);
+        }
+    }
+}
+
 static void TestToLegacyKey(void)
 {
     /* $IN specifies the result should be the input pointer itself */
@@ -6150,6 +6564,8 @@ static void TestToLegacyType(void)
             }
         } 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);
         }
     }
 }
@@ -6184,17 +6600,68 @@ static void TestIsRightToLeft() {
     }
 }
 
+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 );
+        }
+    }
+}
+
+// Test case for ICU-20370.
+// The issue shows as an Addresss Sanitizer failure.
+static void TestBug20370() {
+    const char *localeID = "x-privatebutreallylongtagfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobar";
+    uint32_t lcid = uloc_getLCID(localeID);
+    if (lcid != 0) {
+        log_err("FAIL: Expected LCID value of 0 for invalid localeID input.");
+    }
+}
+
 typedef enum UldnNameType {
     TEST_ULDN_LOCALE,
     TEST_ULDN_LANGUAGE,
     TEST_ULDN_SCRIPT,
     TEST_ULDN_REGION,
+    TEST_ULOC_LOCALE,   // only valid with optStdMidLong
+    TEST_ULOC_LANGUAGE, // only valid with optStdMidLong
+    TEST_ULOC_SCRIPT,   // only valid with optStdMidLong
+    TEST_ULOC_REGION,   // only valid with optStdMidLong
 } UldnNameType;
 
 typedef struct {
     const char * localeToName; // NULL to terminate a list of these
     UldnNameType nameType;
-    const char * expectResult;
+    const UChar * expectResult;
 } UldnItem;
 
 typedef struct {
@@ -6220,107 +6687,265 @@ static const UDisplayContext optDiaLstLong[3] = {UDISPCTX_DIALECT_NAMES,  UDISPC
 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)" },
+       { "en_US",                  TEST_ULDN_LOCALE, u"English (US)" },
+       { "en_US_POSIX",            TEST_ULDN_LOCALE, u"English (US, Computer)" },
+       { "en_US@calendar=chinese", TEST_ULDN_LOCALE, u"English (US, Chinese Calendar)" },
+       { "en_CA",                  TEST_ULDN_LOCALE, u"English (Canada)" },
+       { "pt",                     TEST_ULDN_LOCALE, u"Portuguese" },
+       { "pt_BR",                  TEST_ULDN_LOCALE, u"Portuguese (Brazil)" },
+       { "pt_PT",                  TEST_ULDN_LOCALE, u"Portuguese (Portugal)" },
+       { "zh_Hans",                TEST_ULDN_LOCALE, u"Chinese, Simplified" },                  // Apple <rdar://problem/50750364>
+       { "zh_Hans_CN",             TEST_ULDN_LOCALE, u"Chinese, Simplified (China mainland)" }, // Apple <rdar://problem/50750364>
+       { "zh_Hant",                TEST_ULDN_LOCALE, u"Chinese, Traditional" },                 // Apple <rdar://problem/50750364>
+       { "zh_Hant_HK",             TEST_ULDN_LOCALE, u"Chinese, Traditional (Hong Kong)" },     // Apple <rdar://problem/50750364>
+       { "yue_Hans",               TEST_ULDN_LOCALE, u"Cantonese, Simplified" },                // Apple <rdar://problem/50750364>
+       { "yue_Hans_CN",            TEST_ULDN_LOCALE, u"Cantonese, Simplified (China mainland)" }, // Apple <rdar://problem/50750364>
+       { "yue_Hant",               TEST_ULDN_LOCALE, u"Cantonese, Traditional" },               // Apple <rdar://problem/50750364>
+       { "yue_Hant_HK",            TEST_ULDN_LOCALE, u"Cantonese, Traditional (Hong Kong)" },   // Apple <rdar://problem/50750364>
+       { "zh_Hans@calendar=chinese",     TEST_ULDN_LOCALE, u"Chinese, Simplified (Chinese Calendar)" },                  // Apple <rdar://problem/50750364>
+       { "zh_Hans_CN@calendar=chinese",  TEST_ULDN_LOCALE, u"Chinese, Simplified (China mainland, Chinese Calendar)" }, // Apple <rdar://problem/50750364>
+       { "zh_Hant@calendar=chinese",     TEST_ULDN_LOCALE, u"Chinese, Traditional (Chinese Calendar)" },                 // Apple <rdar://problem/50750364>
+       { "zh_Hant_HK@calendar=chinese",  TEST_ULDN_LOCALE, u"Chinese, Traditional (Hong Kong, Chinese Calendar)" },     // Apple <rdar://problem/50750364>
+       { "yue_Hans@calendar=chinese",    TEST_ULDN_LOCALE, u"Cantonese, Simplified (Chinese Calendar)" },                // Apple <rdar://problem/50750364>
+       { "yue_Hans_CN@calendar=chinese", TEST_ULDN_LOCALE, u"Cantonese, Simplified (China mainland, Chinese Calendar)" }, // Apple <rdar://problem/50750364>
+       { "yue_Hant@calendar=chinese",    TEST_ULDN_LOCALE, u"Cantonese, Traditional (Chinese Calendar)" },               // Apple <rdar://problem/50750364>
+       { "yue_Hant_HK@calendar=chinese", TEST_ULDN_LOCALE, u"Cantonese, Traditional (Hong Kong, Chinese Calendar)" },   // Apple <rdar://problem/50750364>
+       { "zh_HK",                  TEST_ULDN_LOCALE, u"Chinese (Hong Kong)" },
+       { "Latn",                   TEST_ULDN_SCRIPT, u"Latin" },
+       { "Hans",                   TEST_ULDN_SCRIPT, u"Simplified Han" },
+       { "Hant",                   TEST_ULDN_SCRIPT, u"Traditional Han" },
+       { "US",                     TEST_ULDN_REGION, u"United States" },
+       { "CA",                     TEST_ULDN_REGION, u"Canada" },
+       { "GB",                     TEST_ULDN_REGION, u"United Kingdom" },
+       { "HK",                     TEST_ULDN_REGION, u"Hong Kong" },
+       { "ps_Arab",                TEST_ULDN_LOCALE, u"Pashto (Arabic)" },
+       { "ps_Arab_AF",             TEST_ULDN_LOCALE, u"Pashto (Arabic, Afghanistan)" },
+       { "ks_Arab",                TEST_ULDN_LOCALE, u"Kashmiri (Naskh)" }, // Apple <rdar://problem/50687287>
+       { "ks_Aran",                TEST_ULDN_LOCALE, u"Kashmiri (Nastaliq)" }, // Apple <rdar://problem/47494884>
+       { "ks_Arab_IN",             TEST_ULDN_LOCALE, u"Kashmiri (Naskh, India)" }, // Apple <rdar://problem/50687287>
+       { "ks_Aran_IN",             TEST_ULDN_LOCALE, u"Kashmiri (Nastaliq, India)" }, // Apple <rdar://problem/47494884>
+       { "pa_Arab",                TEST_ULDN_LOCALE, u"Punjabi (Naskh)" }, // Apple <rdar://problem/50687287>
+       { "pa_Aran",                TEST_ULDN_LOCALE, u"Punjabi (Nastaliq)" }, // Apple <rdar://problem/50687287>
+       { "pa_Arab_PK",             TEST_ULDN_LOCALE, u"Punjabi (Naskh, Pakistan)" }, // Apple <rdar://problem/50687287>
+       { "pa_Aran_PK",             TEST_ULDN_LOCALE, u"Punjabi (Nastaliq, Pakistan)" }, // Apple <rdar://problem/50687287>
+       { "ur_Arab",                TEST_ULDN_LOCALE, u"Urdu (Naskh)" }, // Apple <rdar://problem/50687287>
+       { "ur_Aran",                TEST_ULDN_LOCALE, u"Urdu (Nastaliq)" }, // Apple <rdar://problem/47494884>
+       { "ur_Arab_PK",             TEST_ULDN_LOCALE, u"Urdu (Naskh, Pakistan)" }, // Apple <rdar://problem/50687287>
+       { "ur_Aran_PK",             TEST_ULDN_LOCALE, u"Urdu (Nastaliq, Pakistan)" }, // Apple <rdar://problem/47494884>
+       { "ps_Arab@calendar=islamic",    TEST_ULDN_LOCALE, u"Pashto (Arabic, Islamic Calendar)" },
+       { "ps_Arab_AF@calendar=islamic", TEST_ULDN_LOCALE, u"Pashto (Arabic, Afghanistan, Islamic Calendar)" },
+       { "ks_Arab@calendar=islamic",    TEST_ULDN_LOCALE, u"Kashmiri (Naskh, Islamic Calendar)" }, // Apple <rdar://problem/50687287>
+       { "ks_Aran@calendar=islamic",    TEST_ULDN_LOCALE, u"Kashmiri (Nastaliq, Islamic Calendar)" }, // Apple <rdar://problem/47494884>
+       { "ks_Arab_IN@calendar=islamic", TEST_ULDN_LOCALE, u"Kashmiri (Naskh, India, Islamic Calendar)" }, // Apple <rdar://problem/50687287>
+       { "ks_Aran_IN@calendar=islamic", TEST_ULDN_LOCALE, u"Kashmiri (Nastaliq, India, Islamic Calendar)" }, // Apple <rdar://problem/47494884>
+       { "pa_Arab@calendar=islamic",    TEST_ULDN_LOCALE, u"Punjabi (Naskh, Islamic Calendar)" }, // Apple <rdar://problem/50687287>
+       { "pa_Aran@calendar=islamic",    TEST_ULDN_LOCALE, u"Punjabi (Nastaliq, Islamic Calendar)" }, // Apple <rdar://problem/50687287>
+       { "pa_Arab_PK@calendar=islamic", TEST_ULDN_LOCALE, u"Punjabi (Naskh, Pakistan, Islamic Calendar)" }, // Apple <rdar://problem/50687287>
+       { "pa_Aran_PK@calendar=islamic", TEST_ULDN_LOCALE, u"Punjabi (Nastaliq, Pakistan, Islamic Calendar)" }, // Apple <rdar://problem/50687287>
+       { "ur_Arab@calendar=islamic",    TEST_ULDN_LOCALE, u"Urdu (Naskh, Islamic Calendar)" }, // Apple <rdar://problem/50687287>
+       { "ur_Aran@calendar=islamic",    TEST_ULDN_LOCALE, u"Urdu (Nastaliq, Islamic Calendar)" }, // Apple <rdar://problem/47494884>
+       { "ur_Arab_PK@calendar=islamic", TEST_ULDN_LOCALE, u"Urdu (Naskh, Pakistan, Islamic Calendar)" }, // Apple <rdar://problem/50687287>
+       { "ur_Aran_PK@calendar=islamic", TEST_ULDN_LOCALE, u"Urdu (Nastaliq, Pakistan, Islamic Calendar)" }, // Apple <rdar://problem/47494884>
+       { "Arab",                   TEST_ULDN_SCRIPT, u"Arabic" },
+       { "Aran",                   TEST_ULDN_SCRIPT, u"Nastaliq" }, // Apple <rdar://problem/47494884>
+       { "Qaag",                   TEST_ULDN_SCRIPT, u"Zawgyi" },   // Apple <rdar://problem/51471316>
+       { "my_Qaag",                TEST_ULDN_LOCALE, u"Burmese (Zawgyi)" }, // Apple <rdar://problem/51471316>
+
+       { "zh_Hans",                TEST_ULOC_LOCALE, u"Chinese, Simplified" },                  // Apple <rdar://problem/51418203>
+       { "zh_Hans_CN",             TEST_ULOC_LOCALE, u"Chinese, Simplified (China mainland)" }, // Apple <rdar://problem/51418203>
+       { "zh_Hant",                TEST_ULOC_LOCALE, u"Chinese, Traditional" },                 // Apple <rdar://problem/51418203>
+       { "zh_Hant_HK",             TEST_ULOC_LOCALE, u"Chinese, Traditional (Hong Kong)" },     // Apple <rdar://problem/51418203>
+       { "yue_Hans",               TEST_ULOC_LOCALE, u"Cantonese, Simplified" },                // Apple <rdar://problem/51418203>
+       { "yue_Hans_CN",            TEST_ULOC_LOCALE, u"Cantonese, Simplified (China mainland)" }, // Apple <rdar://problem/51418203>
+       { "yue_Hant",               TEST_ULOC_LOCALE, u"Cantonese, Traditional" },               // Apple <rdar://problem/51418203>
+       { "yue_Hant_HK",            TEST_ULOC_LOCALE, u"Cantonese, Traditional (Hong Kong)" },   // Apple <rdar://problem/51418203>
+       { "zh_Hans@calendar=chinese",     TEST_ULOC_LOCALE, u"Chinese, Simplified (Chinese Calendar)" },                  // Apple <rdar://problem/50750364>
+       { "zh_Hans_CN@calendar=chinese",  TEST_ULOC_LOCALE, u"Chinese, Simplified (China mainland, Chinese Calendar)" }, // Apple <rdar://problem/50750364>
+       { "zh_Hant@calendar=chinese",     TEST_ULOC_LOCALE, u"Chinese, Traditional (Chinese Calendar)" },                 // Apple <rdar://problem/50750364>
+       { "zh_Hant_HK@calendar=chinese",  TEST_ULOC_LOCALE, u"Chinese, Traditional (Hong Kong, Chinese Calendar)" },     // Apple <rdar://problem/50750364>
+       { "yue_Hans@calendar=chinese",    TEST_ULOC_LOCALE, u"Cantonese, Simplified (Chinese Calendar)" },                // Apple <rdar://problem/50750364>
+       { "yue_Hans_CN@calendar=chinese", TEST_ULOC_LOCALE, u"Cantonese, Simplified (China mainland, Chinese Calendar)" }, // Apple <rdar://problem/50750364>
+       { "yue_Hant@calendar=chinese",    TEST_ULOC_LOCALE, u"Cantonese, Traditional (Chinese Calendar)" },               // Apple <rdar://problem/50750364>
+       { "yue_Hant_HK@calendar=chinese", TEST_ULOC_LOCALE, u"Cantonese, Traditional (Hong Kong, Chinese Calendar)" },   // Apple <rdar://problem/50750364>
+       { "ks_Arab",                TEST_ULOC_LOCALE, u"Kashmiri (Naskh)" }, // Apple <rdar://problem/51418203>
+       { "ks_Aran",                TEST_ULOC_LOCALE, u"Kashmiri (Nastaliq)" }, // Apple <rdar://problem/47494884>
+       { "ks_Arab_IN",             TEST_ULOC_LOCALE, u"Kashmiri (Naskh, India)" }, // Apple <rdar://problem/51418203>
+       { "ks_Aran_IN",             TEST_ULOC_LOCALE, u"Kashmiri (Nastaliq, India)" }, // Apple <rdar://problem/47494884>
+       { "pa_Arab",                TEST_ULOC_LOCALE, u"Punjabi (Naskh)" }, // Apple <rdar://problem/51418203>
+       { "pa_Aran",                TEST_ULOC_LOCALE, u"Punjabi (Nastaliq)" }, // Apple <rdar://problem/51418203>
+       { "pa_Arab_PK",             TEST_ULOC_LOCALE, u"Punjabi (Naskh, Pakistan)" }, // Apple <rdar://problem/51418203>
+       { "pa_Aran_PK",             TEST_ULOC_LOCALE, u"Punjabi (Nastaliq, Pakistan)" }, // Apple <rdar://problem/51418203>
+       { "ur_Arab",                TEST_ULOC_LOCALE, u"Urdu (Naskh)" }, // Apple <rdar://problem/51418203>
+       { "ur_Aran",                TEST_ULOC_LOCALE, u"Urdu (Nastaliq)" }, // Apple <rdar://problem/47494884>
+       { "ur_Arab_PK",             TEST_ULOC_LOCALE, u"Urdu (Naskh, Pakistan)" }, // Apple <rdar://problem/51418203>
+       { "ur_Aran_PK",             TEST_ULOC_LOCALE, u"Urdu (Nastaliq, Pakistan)" }, // Apple <rdar://problem/47494884>
+       { "ks_Arab@calendar=islamic",    TEST_ULOC_LOCALE, u"Kashmiri (Naskh, Islamic Calendar)" }, // Apple <rdar://problem/50687287>
+       { "ks_Aran@calendar=islamic",    TEST_ULOC_LOCALE, u"Kashmiri (Nastaliq, Islamic Calendar)" }, // Apple <rdar://problem/47494884>
+       { "ks_Arab_IN@calendar=islamic", TEST_ULOC_LOCALE, u"Kashmiri (Naskh, India, Islamic Calendar)" }, // Apple <rdar://problem/50687287>
+       { "ks_Aran_IN@calendar=islamic", TEST_ULOC_LOCALE, u"Kashmiri (Nastaliq, India, Islamic Calendar)" }, // Apple <rdar://problem/47494884>
+       { "pa_Arab@calendar=islamic",    TEST_ULOC_LOCALE, u"Punjabi (Naskh, Islamic Calendar)" }, // Apple <rdar://problem/50687287>
+       { "pa_Aran@calendar=islamic",    TEST_ULOC_LOCALE, u"Punjabi (Nastaliq, Islamic Calendar)" }, // Apple <rdar://problem/50687287>
+       { "pa_Arab_PK@calendar=islamic", TEST_ULOC_LOCALE, u"Punjabi (Naskh, Pakistan, Islamic Calendar)" }, // Apple <rdar://problem/50687287>
+       { "pa_Aran_PK@calendar=islamic", TEST_ULOC_LOCALE, u"Punjabi (Nastaliq, Pakistan, Islamic Calendar)" }, // Apple <rdar://problem/50687287>
+       { "ur_Arab@calendar=islamic",    TEST_ULOC_LOCALE, u"Urdu (Naskh, Islamic Calendar)" }, // Apple <rdar://problem/50687287>
+       { "ur_Aran@calendar=islamic",    TEST_ULOC_LOCALE, u"Urdu (Nastaliq, Islamic Calendar)" }, // Apple <rdar://problem/47494884>
+       { "ur_Arab_PK@calendar=islamic", TEST_ULOC_LOCALE, u"Urdu (Naskh, Pakistan, Islamic Calendar)" }, // Apple <rdar://problem/50687287>
+       { "ur_Aran_PK@calendar=islamic", TEST_ULOC_LOCALE, u"Urdu (Nastaliq, Pakistan, Islamic Calendar)" }, // Apple <rdar://problem/47494884>
+       { "my_Qaag",                TEST_ULOC_LOCALE, u"Burmese (Zawgyi)" }, // Apple <rdar://problem/51471316>
 };
 
 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" },
+       { "en_US",                  TEST_ULDN_LOCALE, u"English (US)" },
+       { "en_US_POSIX",            TEST_ULDN_LOCALE, u"English (US, Computer)" },
+       { "en_US@calendar=chinese", TEST_ULDN_LOCALE, u"English (US, Calendar: chinese)" },
+       { "en_CA",                  TEST_ULDN_LOCALE, u"English (Canada)" },
+       { "pt",                     TEST_ULDN_LOCALE, u"Portuguese" },
+       { "pt_BR",                  TEST_ULDN_LOCALE, u"Portuguese (Brazil)" },
+       { "pt_PT",                  TEST_ULDN_LOCALE, u"Portuguese (Portugal)" },
+       { "zh_Hans",                TEST_ULDN_LOCALE, u"Chinese, Simplified" },
+       { "zh_Hant_HK",             TEST_ULDN_LOCALE, u"Chinese, Traditional (Hong Kong)" },
+       { "zh_HK",                  TEST_ULDN_LOCALE, u"Chinese (Hong Kong)" },
+       { "Latn",                   TEST_ULDN_SCRIPT, u"Latin" },
+       { "Hans",                   TEST_ULDN_SCRIPT, u"Simplified Han" },
+       { "Hant",                   TEST_ULDN_SCRIPT, u"Traditional Han" },
+       { "US",                     TEST_ULDN_REGION, u"US" },
+       { "CA",                     TEST_ULDN_REGION, u"Canada" },
+       { "GB",                     TEST_ULDN_REGION, u"UK" },
+       { "HK",                     TEST_ULDN_REGION, u"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)" },
+       { "en_US",                  TEST_ULDN_LOCALE, u"American English" },
+       { "en_US_POSIX",            TEST_ULDN_LOCALE, u"American English (Computer)" },
+       { "en_US@calendar=chinese", TEST_ULDN_LOCALE, u"American English (Chinese Calendar)" },
+       { "en_CA",                  TEST_ULDN_LOCALE, u"Canadian English" },
+       { "pt",                     TEST_ULDN_LOCALE, u"Portuguese" },
+       { "pt_BR",                  TEST_ULDN_LOCALE, u"Brazilian Portuguese" },
+       { "pt_PT",                  TEST_ULDN_LOCALE, u"European Portuguese" },
+       { "zh_Hans",                TEST_ULDN_LOCALE, u"Chinese, Simplified" },
+       { "zh_Hant_HK",             TEST_ULDN_LOCALE, u"Chinese, Traditional (Hong Kong)" },
+       { "zh_HK",                  TEST_ULDN_LOCALE, u"Chinese (Hong Kong)" },
+       { "Latn",                   TEST_ULDN_SCRIPT, u"Latin" },
+       { "Hans",                   TEST_ULDN_SCRIPT, u"Simplified Han" },
+       { "Hant",                   TEST_ULDN_SCRIPT, u"Traditional Han" },
+       { "US",                     TEST_ULDN_REGION, u"United States" },
+       { "CA",                     TEST_ULDN_REGION, u"Canada" },
+       { "GB",                     TEST_ULDN_REGION, u"United Kingdom" },
+       { "HK",                     TEST_ULDN_REGION, u"Hong Kong" },
 };
 
 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" },
+       { "en_US",                  TEST_ULDN_LOCALE, u"US English" },
+       { "en_US_POSIX",            TEST_ULDN_LOCALE, u"US English (Computer)" },
+       { "en_US@calendar=chinese", TEST_ULDN_LOCALE, u"US English (Calendar: chinese)" },
+       { "en_CA",                  TEST_ULDN_LOCALE, u"Canadian English" },
+       { "pt",                     TEST_ULDN_LOCALE, u"Portuguese" },
+       { "pt_BR",                  TEST_ULDN_LOCALE, u"Brazilian Portuguese" },
+       { "pt_PT",                  TEST_ULDN_LOCALE, u"European Portuguese" },
+       { "zh_Hans",                TEST_ULDN_LOCALE, u"Chinese, Simplified" },
+       { "zh_Hant_HK",             TEST_ULDN_LOCALE, u"Chinese, Traditional (Hong Kong)" },
+       { "zh_HK",                  TEST_ULDN_LOCALE, u"Chinese (Hong Kong)" },
+       { "Latn",                   TEST_ULDN_SCRIPT, u"Latin" },
+       { "Hans",                   TEST_ULDN_SCRIPT, u"Simplified Han" },
+       { "Hant",                   TEST_ULDN_SCRIPT, u"Traditional Han" },
+       { "US",                     TEST_ULDN_REGION, u"US" },
+       { "CA",                     TEST_ULDN_REGION, u"Canada" },
+       { "GB",                     TEST_ULDN_REGION, u"UK" },
+       { "HK",                     TEST_ULDN_REGION, u"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, "R.A.S. chinoise de Hong Kong" },
+       { "en_US",                  TEST_ULDN_LOCALE, u"anglais (É.-U.)" },
+       { "US",                     TEST_ULDN_REGION, u"États-Unis" },
+       { "HK",                     TEST_ULDN_REGION, u"Hong Kong" },
 };
 
 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" },
+       { "en_US",                  TEST_ULDN_LOCALE, u"anglais (É.-U.)" },
+       { "US",                     TEST_ULDN_REGION, u"É.-U." },
+       { "HK",                     TEST_ULDN_REGION, u"Hong Kong" },
 };
 
 static const UldnItem fr_StdBegLong[] = {
-       { "en_US",                  TEST_ULDN_LOCALE, "Anglais (\\u00C9.-U.)" },
+       { "en_US",                  TEST_ULDN_LOCALE, u"Anglais (É.-U.)" },
 };
 
 static const UldnItem fr_StdLstLong[] = {
-       { "en_US",                  TEST_ULDN_LOCALE, "Anglais (\\u00C9.-U.)" },
+       { "en_US",                  TEST_ULDN_LOCALE, u"Anglais (É.-U.)" },
+       { "PS",                     TEST_ULDN_REGION, u"Territoires palestiniens" },
 };
 
 static const UldnItem fr_DiaMidLong[] = {
-       { "en_US",                  TEST_ULDN_LOCALE, "anglais am\\u00E9ricain" },
+       { "en_US",                  TEST_ULDN_LOCALE, u"anglais américain" },
+};
+
+static const UldnItem ca_StdLstLong[] = {
+       { "PS",                     TEST_ULDN_REGION, u"Territoris palestins" },
+};
+
+static const UldnItem ur_StdMidLong[] = {
+       { "ps_Arab",                TEST_ULDN_LOCALE, u"پشتو (عربی)" },
+       { "ps_Arab_AF",             TEST_ULDN_LOCALE, u"پشتو (عربی،افغانستان)" },
+       { "ur_Aran",                TEST_ULDN_LOCALE, u"اردو (نستعلیق)" }, // Apple <rdar://problem/47494884>
+       { "ur_Arab",                TEST_ULDN_LOCALE, u"اردو (نسخ)" }, // Apple <rdar://problem/50687287>
+       { "ur_Aran_PK",             TEST_ULDN_LOCALE, u"اردو (نستعلیق،پاکستان)" }, // Apple <rdar://problem/47494884>
+       { "ur_Arab_PK",             TEST_ULDN_LOCALE, u"اردو (نسخ،پاکستان)" }, // Apple <rdar://problem/50687287>
+
+       { "ps_Arab",                TEST_ULOC_LOCALE, u"پشتو (عربی)" },
+       { "ps_Arab_AF",             TEST_ULOC_LOCALE, u"پشتو (عربی،افغانستان)" },
+       { "ur_Aran",                TEST_ULOC_LOCALE, u"اردو (نستعلیق)" },     // Apple <rdar://problem/47494884>
+       { "ur_Arab",                TEST_ULOC_LOCALE, u"اردو (نسخ)" },         // Apple <rdar://problem/51418203>
+       { "ur_Aran_PK",             TEST_ULOC_LOCALE, u"اردو (نستعلیق،پاکستان)" }, // Apple <rdar://problem/47494884>
+       { "ur_Arab_PK",             TEST_ULOC_LOCALE, u"اردو (نسخ،پاکستان)" }, // Apple <rdar://problem/51418203>
+};
+
+static const UldnItem pa_Arab_StdMidLong[] = {
+       { "pa_Aran",                TEST_ULDN_LOCALE, u"پنجابی (نستعلیق)" }, // Apple <rdar://problem/47494884>
+       { "pa_Arab",                TEST_ULDN_LOCALE, u"پنجابی (نسخ)" }, // Apple <rdar://problem/50687287>
+       { "pa_Aran_PK",             TEST_ULDN_LOCALE, u"پنجابی (نستعلیق, پاکستان)" }, // Apple <rdar://problem/47494884>
+       { "pa_Arab_PK",             TEST_ULDN_LOCALE, u"پنجابی (نسخ, پاکستان)" }, // Apple <rdar://problem/50687287>
+
+       { "pa_Aran",                TEST_ULOC_LOCALE, u"پنجابی (نستعلیق)" },      // Apple <rdar://problem/51418203>
+       { "pa_Arab",                TEST_ULOC_LOCALE, u"پنجابی (نسخ)" },          // Apple <rdar://problem/51418203>
+       { "pa_Aran_PK",             TEST_ULOC_LOCALE, u"پنجابی (نستعلیق, پاکستان)" }, // Apple <rdar://problem/51418203>
+       { "pa_Arab_PK",             TEST_ULOC_LOCALE, u"پنجابی (نسخ, پاکستان)" }, // Apple <rdar://problem/51418203>
+};
+
+static const UldnItem zh_StdMidLong[] = {
+       { "zh_Hans",                TEST_ULDN_LOCALE, u"简体中文" },           // Apple <rdar://problem/50750364>
+       { "zh_Hans_CN",             TEST_ULDN_LOCALE, u"简体中文(中国大陆)" }, // Apple <rdar://problem/50750364>
+       { "zh_Hant",                TEST_ULDN_LOCALE, u"繁体中文" },           // Apple <rdar://problem/50750364>
+       { "zh_Hant_HK",             TEST_ULDN_LOCALE, u"繁体中文(香港)" },    // Apple <rdar://problem/50750364>
+       { "yue_Hans",               TEST_ULDN_LOCALE, u"简体粤语" },           // Apple <rdar://problem/50750364>
+       { "yue_Hans_CN",            TEST_ULDN_LOCALE, u"简体粤语(中国大陆)" }, // Apple <rdar://problem/50750364>
+       { "yue_Hant",               TEST_ULDN_LOCALE, u"繁体粤语" },           // Apple <rdar://problem/50750364>
+       { "yue_Hant_HK",            TEST_ULDN_LOCALE, u"繁体粤语(香港)" },    // Apple <rdar://problem/50750364>
+       { "ps_Arab",                TEST_ULDN_LOCALE, u"普什图语(阿拉伯文)" },
+       { "ps_Arab_AF",             TEST_ULDN_LOCALE, u"普什图语(阿拉伯文,阿富汗)" },
+       { "ur_Aran",                TEST_ULDN_LOCALE, u"乌尔都语(波斯体)" }, // Apple <rdar://problem/47494884>
+       { "ur_Arab",                TEST_ULDN_LOCALE, u"乌尔都语(誊抄体)" }, // Apple <rdar://problem/50687287>
+       { "ur_Aran_PK",             TEST_ULDN_LOCALE, u"乌尔都语(波斯体,巴基斯坦)" }, // Apple <rdar://problem/47494884>
+       { "ur_Arab_PK",             TEST_ULDN_LOCALE, u"乌尔都语(誊抄体,巴基斯坦)" }, // Apple <rdar://problem/50687287>
+
+       { "zh_Hans",                TEST_ULOC_LOCALE, u"简体中文" },           // Apple <rdar://problem/51418203>
+       { "zh_Hans_CN",             TEST_ULOC_LOCALE, u"简体中文(中国大陆)" }, // Apple <rdar://problem/51418203>
+       { "zh_Hant",                TEST_ULOC_LOCALE, u"繁体中文" },           // Apple <rdar://problem/51418203>
+       { "zh_Hant_HK",             TEST_ULOC_LOCALE, u"繁体中文(香港)" },    // Apple <rdar://problem/51418203>
+       { "yue_Hans",               TEST_ULOC_LOCALE, u"简体粤语" },           // Apple <rdar://problem/51418203>
+       { "yue_Hans_CN",            TEST_ULOC_LOCALE, u"简体粤语(中国大陆)" }, // Apple <rdar://problem/51418203>
+       { "yue_Hant",               TEST_ULOC_LOCALE, u"繁体粤语" },           // Apple <rdar://problem/51418203>
+       { "yue_Hant_HK",            TEST_ULOC_LOCALE, u"繁体粤语(香港)" },    // Apple <rdar://problem/51418203>
+       { "ur_Aran",                TEST_ULOC_LOCALE, u"乌尔都语(波斯体)" }, // Apple <rdar://problem/47494884>
+       { "ur_Arab",                TEST_ULOC_LOCALE, u"乌尔都语(誊抄体)" }, // Apple <rdar://problem/51418203>
+       { "ur_Aran_PK",             TEST_ULOC_LOCALE, u"乌尔都语(波斯体,巴基斯坦)" }, // Apple <rdar://problem/47494884>
+       { "ur_Arab_PK",             TEST_ULOC_LOCALE, u"乌尔都语(誊抄体,巴基斯坦)" }, // Apple <rdar://problem/51418203>
+};
+
+static const UldnItem hi_Latn_StdMidLong[] = { // Apple <rdar://problem/53216112>
+       { "en",                     TEST_ULDN_LOCALE, u"English" },
+       { "hi_Deva",                TEST_ULDN_LOCALE, u"Hindi (Devanagari)" },
+       { "hi_Latn",                TEST_ULDN_LOCALE, u"Hindi (Latin)" },
+       { "hi_Latn_IN",             TEST_ULDN_LOCALE, u"Hindi (Latin, Bhaarat)" },
 };
 
 static const UldnLocAndOpts uldnLocAndOpts[] = {
@@ -6332,7 +6957,16 @@ static const UldnLocAndOpts uldnLocAndOpts[] = {
     { "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) },
+    { "ur", optStdMidLong,      ur_StdMidLong,      UPRV_LENGTHOF(ur_StdMidLong) },
+    { "ur_Arab", optStdMidLong, ur_StdMidLong,      UPRV_LENGTHOF(ur_StdMidLong) },
+    { "ur_Aran", optStdMidLong, ur_StdMidLong,      UPRV_LENGTHOF(ur_StdMidLong) },
+    { "pa_Arab", optStdMidLong, pa_Arab_StdMidLong, UPRV_LENGTHOF(pa_Arab_StdMidLong) },
+    { "pa_Aran", optStdMidLong, pa_Arab_StdMidLong, UPRV_LENGTHOF(pa_Arab_StdMidLong) },
+    { "zh", optStdMidLong,      zh_StdMidLong,      UPRV_LENGTHOF(zh_StdMidLong) },
+    { "hi_Latn", optStdMidLong, hi_Latn_StdMidLong, UPRV_LENGTHOF(hi_Latn_StdMidLong) },
     { NULL, NULL, NULL, 0 }
 };
 
@@ -6352,43 +6986,58 @@ static void TestUldnNameVariants() {
         const UldnItem * itemPtr = uloPtr->testItems;
         int32_t itemCount = uloPtr->countItems;
         for (; itemCount-- > 0; itemPtr++) {
-            UChar uget[kUNameBuf], uexp[kUNameBuf];
+            UChar uget[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";
+                    typeString = "uldn_localeDisplayName";
                     break;
                 case TEST_ULDN_LANGUAGE:
                     ulenget = uldn_languageDisplayName(uldn, itemPtr->localeToName, uget, kUNameBuf, &status);
-                    typeString = "language";
+                    typeString = "uldn_languageDisplayName";
                   break;
                 case TEST_ULDN_SCRIPT:
                     ulenget = uldn_scriptDisplayName(uldn, itemPtr->localeToName, uget, kUNameBuf, &status);
-                    typeString = "script";
+                    typeString = "uldn_scriptDisplayName";
                     break;
                 case TEST_ULDN_REGION:
                     ulenget = uldn_regionDisplayName(uldn, itemPtr->localeToName, uget, kUNameBuf, &status);
-                    typeString = "region";
+                    typeString = "uldn_regionDisplayName";
+                    break;
+                case TEST_ULOC_LOCALE:
+                    ulenget = uloc_getDisplayName(itemPtr->localeToName, uloPtr->displayLocale, uget, kUNameBuf, &status);
+                    typeString = "uloc_getDisplayName";
+                    break;
+                case TEST_ULOC_LANGUAGE:
+                    ulenget = uloc_getDisplayLanguage(itemPtr->localeToName, uloPtr->displayLocale, uget, kUNameBuf, &status);
+                    typeString = "uloc_getDisplayLanguage";
+                    break;
+                case TEST_ULOC_SCRIPT:
+                    ulenget = uloc_getDisplayScript(itemPtr->localeToName, uloPtr->displayLocale, uget, kUNameBuf, &status);
+                    typeString = "uloc_getDisplayScript";
+                    break;
+                case TEST_ULOC_REGION:
+                    ulenget = uloc_getDisplayCountry(itemPtr->localeToName, uloPtr->displayLocale, uget, kUNameBuf, &status);
+                    typeString = "uloc_getDisplayCountry";
                     break;
                 default:
                     continue;
             }
             if (U_FAILURE(status)) {
-                log_data_err("uldn_%sDisplayName fails, displayLocale %s, contexts %03X %03X %03X, localeToName %s: %s\n",
+                log_data_err("%s 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) {
+            ulenexp = u_strlen(itemPtr->expectResult);
+            if (ulenget != ulenexp || u_strncmp(uget, itemPtr->expectResult, ulenexp) != 0) {
                 char bexp[kBNameBuf], bget[kBNameBuf];
-                u_strToUTF8(bexp, kBNameBuf, NULL, uexp, ulenexp, &status);
+                u_strToUTF8(bexp, kBNameBuf, NULL, itemPtr->expectResult, 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",
+                log_data_err("%s 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 );
             }
@@ -6398,11 +7047,193 @@ static void TestUldnNameVariants() {
     }
 }
 
+#define ULOC_UND_TESTNUM 9
+
+static const char* for_empty[ULOC_UND_TESTNUM] = { // ""
+    "",                 // uloc_getName
+    "",                 // uloc_getLanguage
+    "en_Latn_US_POSIX", // uloc_addLikelySubtags
+    "en__POSIX",        // uloc_minimizeSubtags
+    "en_US_POSIX",      // uloc_canonicalize
+    "",                 // uloc_getParent
+    "und",              // uloc_toLanguageTag
+    "",                 // uloc_getDisplayName in en
+    "",                 // uloc_getDisplayLanguage in en
+};
+static const char* for_root[ULOC_UND_TESTNUM] = { // "root"
+    "root",             // uloc_getName
+    "root",             // uloc_getLanguage
+    "root",             // uloc_addLikelySubtags
+    "root",             // uloc_minimizeSubtags
+    "root",             // uloc_canonicalize
+    "",                 // uloc_getParent
+    "root",             // uloc_toLanguageTag
+    "Root",             // uloc_getDisplayName in en
+    "Root",             // uloc_getDisplayLanguage in en
+};
+static const char* for_und[ULOC_UND_TESTNUM] = { // "und"
+    "und",              // uloc_getName
+    "und",              // uloc_getLanguage
+    "en_Latn_US",       // uloc_addLikelySubtags
+    "und",              // uloc_minimizeSubtags
+    "und",              // uloc_canonicalize
+    "",                 // uloc_getParent
+    "und",              // uloc_toLanguageTag
+    "Unknown language", // uloc_getDisplayName in en
+    "Unknown language", // uloc_getDisplayLanguage in en
+};
+static const char* for_und_ZZ[ULOC_UND_TESTNUM] = { // "und_ZZ"
+    "und_ZZ",           // uloc_getName
+    "und",              // uloc_getLanguage
+    "en_Latn_US",       // uloc_addLikelySubtags
+    "und",              // uloc_minimizeSubtags
+    "und_ZZ",           // uloc_canonicalize
+    "und",              // uloc_getParent
+    "und-ZZ",           // uloc_toLanguageTag
+    "Unknown language (Unknown Region)", // uloc_getDisplayName in en
+    "Unknown language", // uloc_getDisplayLanguage in en
+};
+static const char* for_empty_ZZ[ULOC_UND_TESTNUM] = { // "_ZZ"
+    "_ZZ",              // uloc_getName
+    "",                 // uloc_getLanguage
+    "en_Latn_US",       // uloc_addLikelySubtags
+    "und",              // uloc_minimizeSubtags
+    "_ZZ",              // uloc_canonicalize
+    "",                 // uloc_getParent
+    "und-ZZ",           // uloc_toLanguageTag
+    "Unknown Region",   // uloc_getDisplayName in en
+    "",                 // uloc_getDisplayLanguage in en
+};
+
+typedef struct {
+    const char * locale;
+    const char ** expResults;
+} RootUndEmptyItem;
+
+static const RootUndEmptyItem rootUndEmptryItems[] = {
+    { "",       for_empty },
+    { "root",   for_root },
+    { "und",    for_und },
+    { "und_ZZ", for_und_ZZ },
+    { "_ZZ",    for_empty_ZZ },
+    { NULL, NULL }
+};
+
+enum { kULocMax = 64, kBLocMax = 128 };
+
+static void TestRootUndEmpty() {
+    const RootUndEmptyItem* itemPtr;
+    for (itemPtr = rootUndEmptryItems; itemPtr->locale != NULL; itemPtr++) {
+        const char* loc = itemPtr->locale;
+        const char** expResultsPtr = itemPtr->expResults;
+        const char* bexp;
+        char bget[kBLocMax];
+        UChar uexp[kULocMax];
+        UChar uget[kULocMax];
+        int32_t ulen, blen;
+        UErrorCode status;
+
+        status = U_ZERO_ERROR;
+        bexp = *expResultsPtr++;
+        blen = uloc_getName(loc, bget, kBLocMax, &status);
+        if (U_FAILURE(status)) {
+            log_err("loc \"%s\", uloc_getName status: %s\n", loc, u_errorName(status) );
+        } else if (uprv_strcmp(bget, bexp) != 0) {
+            log_err("loc \"%s\", uloc_getName expect \"%s\", get \"%s\"\n", loc, bexp, bget );
+        }
+
+        status = U_ZERO_ERROR;
+        bexp = *expResultsPtr++;
+        blen = uloc_getLanguage(loc, bget, kBLocMax, &status);
+        if (U_FAILURE(status)) {
+            log_err("loc \"%s\", uloc_getLanguage status: %s\n", loc, u_errorName(status) );
+        } else if (uprv_strcmp(bget, bexp) != 0) {
+            log_err("loc \"%s\", uloc_getLanguage expect \"%s\", get \"%s\"\n", loc, bexp, bget );
+        }
+
+        status = U_ZERO_ERROR;
+        bexp = *expResultsPtr++;
+        blen = uloc_addLikelySubtags(loc, bget, kBLocMax, &status);
+        if (U_FAILURE(status)) {
+            log_err("loc \"%s\", uloc_addLikelySubtags status: %s\n", loc, u_errorName(status) );
+        } else if (uprv_strcmp(bget, bexp) != 0) {
+            log_err("loc \"%s\", uloc_addLikelySubtags expect \"%s\", get \"%s\"\n", loc, bexp, bget );
+        }
+
+        status = U_ZERO_ERROR;
+        bexp = *expResultsPtr++;
+        blen = uloc_minimizeSubtags(loc, bget, kBLocMax, &status);
+        if (U_FAILURE(status)) {
+            log_err("loc \"%s\", uloc_minimizeSubtags status: %s\n", loc, u_errorName(status) );
+        } else if (uprv_strcmp(bget, bexp) != 0) {
+            log_err("loc \"%s\", uloc_minimizeSubtags expect \"%s\", get \"%s\"\n", loc, bexp, bget );
+        }
+
+        status = U_ZERO_ERROR;
+        bexp = *expResultsPtr++;
+        blen = uloc_canonicalize(loc, bget, kBLocMax, &status);
+         if (U_FAILURE(status)) {
+            log_err("loc \"%s\", uloc_canonicalize status: %s\n", loc, u_errorName(status) );
+        } else if (uprv_strcmp(bget, bexp) != 0) {
+            log_err("loc \"%s\", uloc_canonicalize expect \"%s\", get \"%s\"\n", loc, bexp, bget );
+        }
+
+        status = U_ZERO_ERROR;
+        bexp = *expResultsPtr++;
+        blen = uloc_getParent(loc, bget, kBLocMax, &status);
+        if (U_FAILURE(status)) {
+            log_err("loc \"%s\", uloc_getParent status: %s\n", loc, u_errorName(status) );
+        } else if (uprv_strcmp(bget, bexp) != 0) {
+            log_err("loc \"%s\", uloc_getParent expect \"%s\", get \"%s\"\n", loc, bexp, bget );
+        }
+
+        status = U_ZERO_ERROR;
+        bexp = *expResultsPtr++;
+        blen = uloc_toLanguageTag(loc, bget, kBLocMax, TRUE, &status);
+        if (U_FAILURE(status)) {
+            log_err("loc \"%s\", uloc_toLanguageTag status: %s\n", loc, u_errorName(status) );
+        } else if (uprv_strcmp(bget, bexp) != 0) {
+            log_err("loc \"%s\", uloc_toLanguageTag expect \"%s\", get \"%s\"\n", loc, bexp, bget );
+        }
+
+        status = U_ZERO_ERROR;
+        bexp = *expResultsPtr++;
+        u_unescape(bexp, uexp, kULocMax);
+        uexp[kULocMax-1] = 0; // force zero term
+        ulen = uloc_getDisplayName(loc, "en", uget, kULocMax, &status);
+        if (U_FAILURE(status)) {
+            log_err("loc \"%s\", uloc_getDisplayName en status: %s\n", loc, u_errorName(status) );
+        } else if (u_strcmp(uget, uexp) != 0) {
+            u_austrncpy(bget, uget, kBLocMax);
+            bget[kBLocMax-1] = 0;
+            log_err("loc \"%s\", uloc_getDisplayName en expect \"%s\", get \"%s\"\n", loc, bexp, bget );
+        }
+        
+        status = U_ZERO_ERROR;
+        bexp = *expResultsPtr++;
+        u_unescape(bexp, uexp, kULocMax);
+        uexp[kULocMax-1] = 0; // force zero term
+        ulen = uloc_getDisplayLanguage(loc, "en", uget, kULocMax, &status);
+        if (U_FAILURE(status)) {
+            log_err("loc \"%s\", uloc_getDisplayLanguage en status: %s\n", loc, u_errorName(status) );
+        } else if (u_strcmp(uget, uexp) != 0) {
+            u_austrncpy(bget, uget, kBLocMax);
+            bget[kBLocMax-1] = 0;
+            log_err("loc \"%s\", uloc_getDisplayLanguage en expect \"%s\", get \"%s\"\n", loc, bexp, bget );
+        }
+   }
+}
+
+
+#if !U_PLATFORM_HAS_WIN32_API
 /* 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",
@@ -6420,6 +7251,7 @@ static const char* localesAndAppleParent[] = {
     "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",
@@ -6435,6 +7267,13 @@ static const char* localesAndAppleParent[] = {
     "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",
@@ -6576,6 +7415,28 @@ static void TestGetLanguagesForRegion() {
             log_err("FAIL: ualoc_getLanguagesForRegion %s, entryCount %d is too small\n", region, entryCount);
         }
     }
+
+    status = U_ZERO_ERROR;
+    region = "FO";
+    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:
+        // fo 0.93 UALANGSTATUS_OFFICIAL
+        // da 0.03 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, "fo") != 0 || entries[0].userFraction < 0.90 || entries[0].userFraction > 0.98 || 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, "da") != 0 || entries[1].userFraction < 0.02 || entries[1].userFraction > 0.04 || 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);
+            }
+        }
+    }
 }
 
 /* data for TestAppleLocalizationsToUse */
@@ -6676,7 +7537,7 @@ static const char * appleLocs3[] = {
     "hr",
     "hu",
     "id",
-    "it",
+    "it", "it_CH", // <rdar://problem/35829322>
     "ja",
     "ko",
     "ms",
@@ -6699,6 +7560,7 @@ 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",
+    "it", "it_CH", "it_IT", // <rdar://problem/35829322>
     "nl", "nl_BE", "nl_NL",
     "pt", "pt_BR",
     "ro", "ro_MD", "ro_RO",
@@ -6782,6 +7644,8 @@ 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* l2_it_CH[]       = { "it_CH", "it", NULL }; // <rdar://problem/35829322>
+static const char* l2_it_IT[]       = { "it_IT", "it", NULL }; // <rdar://problem/35829322>
 static const char* l1_Ita[]         = { "Italian", NULL };
 static const char* l1_ja[]          = { "ja", NULL };
 static const char* l1_Japn[]        = { "Japanese", NULL };
@@ -6851,26 +7715,34 @@ static const LangAndExpLocs appleLangAndLoc[] = {
     { "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-AU",              { l1_Eng,         l3_en_AUGB_,    l3_en_AUGB_,    l3_en_AUGB_,    l4_en_AUGB001_, l4_en_AUGB001_ } },
+    { "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-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-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-BD",              { l1_Eng,         l2_en_GB_,      l2_en_GB_,      l2_en_GB_,      l3_en_GB001_,   l3_en_GB001_   } },
+    { "en-LK",              { 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-NZ",              { l1_Eng,         l3_en_AUGB_,    l3_en_AUGB_,    l3_en_AUGB_,    l4_en_AUGB001_, l4_en_AUGB001_ } },
     { "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-IL",              { l1_Eng,         l1_en,          l1_en,          l1_en,          l2_en_001_,     l2_en_001_     } },
-    { "en-001",             { l1_Eng,         l1_en,          l1_en,          l1_en,          l2_en_001_,     l2_en_001_     } },
+    { "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          } },
@@ -6884,7 +7756,15 @@ static const LangAndExpLocs appleLangAndLoc[] = {
     { "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-BO",              { l1_Spa,         l1_es,          l2_es_419_,     l2_es_419_,     l1_es,          l2_es_419_     } }, // <rdar://problem/34459988>
     { "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  } },
@@ -6892,6 +7772,7 @@ static const LangAndExpLocs appleLangAndLoc[] = {
     { "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  } },
@@ -6904,7 +7785,10 @@ static const LangAndExpLocs appleLangAndLoc[] = {
     { "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  } },
+    { "it",                 { l1_Ita,         l1_it,          l1_it,          l1_it,          NULL,           NULL  } },
+    { "it_CH",              { l1_Ita,         l1_it,          l2_it_CH,       l2_it_CH,       NULL,           NULL  } }, // <rdar://problem/35829322>
+    { "it_IT",              { l1_Ita,         l1_it,          l1_it,          l2_it_IT,       NULL,           NULL  } }, // <rdar://problem/35829322>
+    { "it_VA",              { l1_Ita,         l1_it,          l1_it,          l1_it,          NULL,           NULL  } }, // <rdar://problem/35829322>
     { "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  } },
@@ -6925,7 +7809,7 @@ static const LangAndExpLocs appleLangAndLoc[] = {
     { "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 } },
+    { "mo",                 { l1_ro,          l1_ro,          l1_ro,          l1_ro,          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  } },
@@ -7143,6 +8027,81 @@ static const char * locsToUseMH[] = { "zh-CN" };
 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" };
+// Per <rdar://problem/47494729>
+static const char * appleLocsMP[]   = { "en-IN", "hi-IN" };
+static const char * prefLangsMP[]   = { "hi-Latn-IN", "en-IN" };
+static const char * locsToUseMP[]   = { "en-IN" };
+// Per <rdar://problem/34459988&35829322>
+static const char * appleLocsMQa[]   = { "en_AU", "en_IE", "en_IN", "en_SA", "en_UK", "en_US", "es_AR", "es_CO", "es_ES", "es_MX", "fr_CA", "fr_FR", "it_CH", "it_IT", "zh_CN", "zh_HK", "zh_TW" };
+static const char * appleLocsMQb[]   = { "en_AU", "en_IE", "en_IN", "en_SA", "en_UK", "en", "es_AR", "es_CO", "es", "es_MX", "fr_CA", "fr", "it_CH", "it", "zh_CN", "zh_HK", "zh_TW" };
+static const char * prefLangsMQ1[]  = { "es-BO" };
+static const char * locsToUseMQ1[]  = { "es_MX" };
+static const char * prefLangsMQ2[]  = { "it-VA" };
+static const char * locsToUseMQ2a[]  = { "it_IT" };
+static const char * locsToUseMQ2b[]  = { "it" };
+// Per <rdar://problem/50913699>
+static const char * appleLocsMRa[]   = { "en", "hi" };
+static const char * appleLocsMRb[]   = { "en", "hi", "hi_Latn" };
+static const char * prefLangsMRx[]   = { "hi_Latn_IN", "en_IN", "hi_IN" };
+static const char * prefLangsMRy[]   = { "hi_Latn", "en", "hi" };
+static const char * locsToUseMRa[]   = { "en" };
+static const char * locsToUseMRb[]   = { "hi_Latn", "en" };
+// For <rdar://problem/50280505>
+static const char * appleLocsMSa[]   = { "en", "en_GB" };
+static const char * appleLocsMSb[]   = { "en", "en_GB", "en_AU" };
+static const char * prefLangsMSx[]   = { "en_NZ" };
+static const char * prefLangsMSy[]   = { "en_NZ", "en_AU" };
+static const char * locsToUseMSa[]   = { "en_GB", "en" };
+static const char * locsToUseMSb[]   = { "en_AU", "en_GB", "en" };
 
 typedef struct {
     const char *  name;
@@ -7175,6 +8134,64 @@ static const MultiPrefTest multiTestSets[] = {
     { "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) },
+    { "MP",    appleLocsMP,   UPRV_LENGTHOF(appleLocsMP),  prefLangsMP,  UPRV_LENGTHOF(prefLangsMP),  locsToUseMP,     UPRV_LENGTHOF(locsToUseMP) },
+    { "MQ1a",  appleLocsMQa,  UPRV_LENGTHOF(appleLocsMQa), prefLangsMQ1, UPRV_LENGTHOF(prefLangsMQ1), locsToUseMQ1,    UPRV_LENGTHOF(locsToUseMQ1) },
+//  { "MQ1b",  appleLocsMQb,  UPRV_LENGTHOF(appleLocsMQb), prefLangsMQ1, UPRV_LENGTHOF(prefLangsMQ1), locsToUseMQ1,    UPRV_LENGTHOF(locsToUseMQ1) }, // still to do for <rdar://problem/34459988>
+    { "MQ2a",  appleLocsMQa,  UPRV_LENGTHOF(appleLocsMQa), prefLangsMQ2, UPRV_LENGTHOF(prefLangsMQ2), locsToUseMQ2a,   UPRV_LENGTHOF(locsToUseMQ2a) },
+    { "MQ2b",  appleLocsMQb,  UPRV_LENGTHOF(appleLocsMQb), prefLangsMQ2, UPRV_LENGTHOF(prefLangsMQ2), locsToUseMQ2b,   UPRV_LENGTHOF(locsToUseMQ2b) },
+    { "MRa",   appleLocsMRa,  UPRV_LENGTHOF(appleLocsMRa), prefLangsMRx, UPRV_LENGTHOF(prefLangsMRx), locsToUseMRa,    UPRV_LENGTHOF(locsToUseMRa) },
+    { "MRb",   appleLocsMRb,  UPRV_LENGTHOF(appleLocsMRb), prefLangsMRx, UPRV_LENGTHOF(prefLangsMRx), locsToUseMRb,    UPRV_LENGTHOF(locsToUseMRb) },
+    { "MRa",   appleLocsMRa,  UPRV_LENGTHOF(appleLocsMRa), prefLangsMRy, UPRV_LENGTHOF(prefLangsMRy), locsToUseMRa,    UPRV_LENGTHOF(locsToUseMRa) },
+    { "MRb",   appleLocsMRb,  UPRV_LENGTHOF(appleLocsMRb), prefLangsMRy, UPRV_LENGTHOF(prefLangsMRy), locsToUseMRb,    UPRV_LENGTHOF(locsToUseMRb) },
+    { "MSax",  appleLocsMSa,  UPRV_LENGTHOF(appleLocsMSa), prefLangsMSx, UPRV_LENGTHOF(prefLangsMSx), locsToUseMSa,    UPRV_LENGTHOF(locsToUseMSa) },
+    { "MSay",  appleLocsMSa,  UPRV_LENGTHOF(appleLocsMSa), prefLangsMSy, UPRV_LENGTHOF(prefLangsMSy), locsToUseMSa,    UPRV_LENGTHOF(locsToUseMSa) },
+    { "MSbx",  appleLocsMSb,  UPRV_LENGTHOF(appleLocsMSb), prefLangsMSx, UPRV_LENGTHOF(prefLangsMSx), locsToUseMSb,    UPRV_LENGTHOF(locsToUseMSb) },
+    { "MSby",  appleLocsMSb,  UPRV_LENGTHOF(appleLocsMSb), prefLangsMSy, UPRV_LENGTHOF(prefLangsMSy), locsToUseMSb,    UPRV_LENGTHOF(locsToUseMSb) },
+
     { NULL, NULL, 0, NULL, 0, NULL, 0 }
 };
 
@@ -7286,3 +8303,4 @@ static void TestAppleLocalizationsToUse() {
         }
    }
 }
+#endif