]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/test/intltest/ustrtest.cpp
ICU-59117.0.1.tar.gz
[apple/icu.git] / icuSources / test / intltest / ustrtest.cpp
index c40b4c4ae5c6a7a45e5abbf58d2ef02c41fa262f..d3734fbf2bef4c4b9fa877221549531c4cd586f5 100644 (file)
@@ -1,66 +1,70 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
 /********************************************************************
  * COPYRIGHT: 
- * Copyright (c) 1997-2008, International Business Machines Corporation and
+ * Copyright (c) 1997-2016, International Business Machines Corporation and
  * others. All Rights Reserved.
  ********************************************************************/
 
 #include "ustrtest.h"
+#include "unicode/appendable.h"
+#include "unicode/std_string.h"
 #include "unicode/unistr.h"
 #include "unicode/uchar.h"
 #include "unicode/ustring.h"
 #include "unicode/locid.h"
+#include "unicode/strenum.h"
 #include "unicode/ucnv.h"
+#include "unicode/uenum.h"
+#include "unicode/utf16.h"
 #include "cmemory.h"
 #include "charstr.h"
 
 #if 0
 #include "unicode/ustream.h"
 
-#if U_IOSTREAM_SOURCE >= 199711
 #include <iostream>
 using namespace std;
-#elif U_IOSTREAM_SOURCE >= 198506
-#include <iostream.h>
-#endif
 
 #endif
 
-#define LENGTHOF(array) (int32_t)((sizeof(array)/sizeof((array)[0])))
-
 UnicodeStringTest::~UnicodeStringTest() {}
 
+extern IntlTest *createStringCaseTest();
+
 void UnicodeStringTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char *par)
 {
     if (exec) logln("TestSuite UnicodeStringTest: ");
-    switch (index) {
-        case 0:
-            name = "StringCaseTest";
-            if (exec) {
-                logln("StringCaseTest---"); logln("");
-                StringCaseTest test;
-                callTest(test, par);
-            }
-            break;
-        case 1: name = "TestBasicManipulation"; if (exec) TestBasicManipulation(); break;
-        case 2: name = "TestCompare"; if (exec) TestCompare(); break;
-        case 3: name = "TestExtract"; if (exec) TestExtract(); break;
-        case 4: name = "TestRemoveReplace"; if (exec) TestRemoveReplace(); break;
-        case 5: name = "TestSearching"; if (exec) TestSearching(); break;
-        case 6: name = "TestSpacePadding"; if (exec) TestSpacePadding(); break;
-        case 7: name = "TestPrefixAndSuffix"; if (exec) TestPrefixAndSuffix(); break;
-        case 8: name = "TestFindAndReplace"; if (exec) TestFindAndReplace(); break;
-        case 9: name = "TestBogus"; if (exec) TestBogus(); break;
-        case 10: name = "TestReverse"; if (exec) TestReverse(); break;
-        case 11: name = "TestMiscellaneous"; if (exec) TestMiscellaneous(); break;
-        case 12: name = "TestStackAllocation"; if (exec) TestStackAllocation(); break;
-        case 13: name = "TestUnescape"; if (exec) TestUnescape(); break;
-        case 14: name = "TestCountChar32"; if (exec) TestCountChar32(); break;
-        case 15: name = "TestStringEnumeration"; if (exec) TestStringEnumeration(); break;
-        case 16: name = "TestCharString"; if (exec) TestCharString(); break;
-        case 17: name = "TestNameSpace"; if (exec) TestNameSpace(); break;
-
-        default: name = ""; break; //needed to end loop
-    }
+    TESTCASE_AUTO_BEGIN;
+    TESTCASE_AUTO_CREATE_CLASS(StringCaseTest);
+    TESTCASE_AUTO(TestBasicManipulation);
+    TESTCASE_AUTO(TestCompare);
+    TESTCASE_AUTO(TestExtract);
+    TESTCASE_AUTO(TestRemoveReplace);
+    TESTCASE_AUTO(TestSearching);
+    TESTCASE_AUTO(TestSpacePadding);
+    TESTCASE_AUTO(TestPrefixAndSuffix);
+    TESTCASE_AUTO(TestFindAndReplace);
+    TESTCASE_AUTO(TestBogus);
+    TESTCASE_AUTO(TestReverse);
+    TESTCASE_AUTO(TestMiscellaneous);
+    TESTCASE_AUTO(TestStackAllocation);
+    TESTCASE_AUTO(TestUnescape);
+    TESTCASE_AUTO(TestCountChar32);
+    TESTCASE_AUTO(TestStringEnumeration);
+    TESTCASE_AUTO(TestNameSpace);
+    TESTCASE_AUTO(TestUTF32);
+    TESTCASE_AUTO(TestUTF8);
+    TESTCASE_AUTO(TestReadOnlyAlias);
+    TESTCASE_AUTO(TestAppendable);
+    TESTCASE_AUTO(TestUnicodeStringImplementsAppendable);
+    TESTCASE_AUTO(TestSizeofUnicodeString);
+    TESTCASE_AUTO(TestStartsWithAndEndsWithNulTerminated);
+    TESTCASE_AUTO(TestMoveSwap);
+    TESTCASE_AUTO(TestUInt16Pointers);
+    TESTCASE_AUTO(TestWCharPointers);
+    TESTCASE_AUTO(TestNullPointers);
+    TESTCASE_AUTO_END;
 }
 
 void
@@ -107,9 +111,9 @@ UnicodeStringTest::TestBasicManipulation()
         errln("operator+=() failed:  expected \"" + expectedValue + "\"\n,got \"" + test2 + "\"");
     
     if (test1.length() != 70)
-        errln("length() failed: expected 70, got " + test1.length());
+        errln(UnicodeString("length() failed: expected 70, got ") + test1.length());
     if (test2.length() != 30)
-        errln("length() failed: expected 30, got " + test2.length());
+        errln(UnicodeString("length() failed: expected 30, got ") + test2.length());
 
     UnicodeString test3;
     test3.append((UChar32)0x20402);
@@ -117,7 +121,7 @@ UnicodeStringTest::TestBasicManipulation()
         errln((UnicodeString)"append failed for UChar32, expected \"\\\\ud841\\\\udc02\", got " + prettify(test3));
     }
     if(test3.length() != 2){
-        errln("append or length failed for UChar32, expected 2, got " + test3.length());
+        errln(UnicodeString("append or length failed for UChar32, expected 2, got ") + test3.length());
     }
     test3.append((UChar32)0x0074);
     if(test3 != CharsToUnicodeString("\\uD841\\uDC02t")){
@@ -193,9 +197,9 @@ UnicodeStringTest::TestBasicManipulation()
         }
 
         UChar buffer[10]={ 0x61, 0x62, 0x20ac, 0xd900, 0xdc05, 0,   0x62, 0xffff, 0xdbff, 0xdfff };
-        UnicodeString s, t(buffer, -1, LENGTHOF(buffer));
+        UnicodeString s, t(buffer, -1, UPRV_LENGTHOF(buffer));
 
-        if(s.setTo(buffer, -1, LENGTHOF(buffer)).length()!=u_strlen(buffer)) {
+        if(s.setTo(buffer, -1, UPRV_LENGTHOF(buffer)).length()!=u_strlen(buffer)) {
             errln("UnicodeString.setTo(buffer, length, capacity) does not work with length==-1");
         }
         if(t.length()!=u_strlen(buffer)) {
@@ -210,11 +214,11 @@ UnicodeStringTest::TestBasicManipulation()
         }
 
         buffer[u_strlen(buffer)]=0xe4;
-        UnicodeString u(buffer, -1, LENGTHOF(buffer));
-        if(s.setTo(buffer, -1, LENGTHOF(buffer)).length()!=LENGTHOF(buffer)) {
+        UnicodeString u(buffer, -1, UPRV_LENGTHOF(buffer));
+        if(s.setTo(buffer, -1, UPRV_LENGTHOF(buffer)).length()!=UPRV_LENGTHOF(buffer)) {
             errln("UnicodeString.setTo(buffer without NUL, length, capacity) does not work with length==-1");
         }
-        if(u.length()!=LENGTHOF(buffer)) {
+        if(u.length()!=UPRV_LENGTHOF(buffer)) {
             errln("UnicodeString(buffer without NUL, length, capacity) does not work with length==-1");
         }
 
@@ -229,6 +233,29 @@ UnicodeStringTest::TestBasicManipulation()
             errln("UnicodeString(const char *, length, cnv, errorCode) does not work with length==-1");
         }
     }
+
+#if U_CHARSET_IS_UTF8
+    {
+        // Test the hardcoded-UTF-8 UnicodeString optimizations.
+        static const uint8_t utf8[]={ 0x61, 0xC3, 0xA4, 0xC3, 0x9F, 0xE4, 0xB8, 0x80, 0 };
+        static const UChar utf16[]={ 0x61, 0xE4, 0xDF, 0x4E00 };
+        UnicodeString from8a = UnicodeString((const char *)utf8);
+        UnicodeString from8b = UnicodeString((const char *)utf8, (int32_t)sizeof(utf8)-1);
+        UnicodeString from16(FALSE, utf16, UPRV_LENGTHOF(utf16));
+        if(from8a != from16 || from8b != from16) {
+            errln("UnicodeString(const char * U_CHARSET_IS_UTF8) failed");
+        }
+        char buffer[16];
+        int32_t length8=from16.extract(0, 0x7fffffff, buffer, (uint32_t)sizeof(buffer));
+        if(length8!=((int32_t)sizeof(utf8)-1) || 0!=uprv_memcmp(buffer, utf8, sizeof(utf8))) {
+            errln("UnicodeString::extract(char * U_CHARSET_IS_UTF8) failed");
+        }
+        length8=from16.extract(1, 2, buffer, (uint32_t)sizeof(buffer));
+        if(length8!=4 || buffer[length8]!=0 || 0!=uprv_memcmp(buffer, utf8+1, length8)) {
+            errln("UnicodeString::extract(substring to char * U_CHARSET_IS_UTF8) failed");
+        }
+    }
+#endif
 }
 
 void
@@ -336,11 +363,11 @@ UnicodeStringTest::TestCompare()
         UnicodeString u[20]; // must be at least as long as strings[]
         int32_t i;
 
-        for(i=0; i<(int32_t)(sizeof(strings)/sizeof(strings[0])); ++i) {
+        for(i=0; i<UPRV_LENGTHOF(strings); ++i) {
             u[i]=UnicodeString(TRUE, strings[i], -1);
         }
 
-        for(i=0; i<(int32_t)(sizeof(strings)/sizeof(strings[0])-1); ++i) {
+        for(i=0; i<UPRV_LENGTHOF(strings)-1; ++i) {
             if(u[i].compareCodePointOrder(u[i+1])>=0 || u[i].compareCodePointOrder(0, INT32_MAX, u[i+1].getBuffer())>=0) {
                 errln("error: UnicodeString::compareCodePointOrder() fails for string %d and the following one\n", i);
             }
@@ -692,14 +719,15 @@ UnicodeStringTest::TestSearching()
           (startPos = test1.indexOf(test2, startPos)) != -1 ? (++occurrences, startPos += 4) : 0)
         ;
     if (occurrences != 6)
-        errln("indexOf failed: expected to find 6 occurrences, found " + occurrences);
-    
+        errln(UnicodeString("indexOf failed: expected to find 6 occurrences, found ") + occurrences);
+
     for ( occurrences = 0, startPos = 10;
           startPos != -1 && startPos < test1.length();
           (startPos = test1.indexOf(test2, startPos)) != -1 ? (++occurrences, startPos += 4) : 0)
         ;
     if (occurrences != 4)
-        errln("indexOf with starting offset failed: expected to find 4 occurrences, found " + occurrences);
+        errln(UnicodeString("indexOf with starting offset failed: "
+                            "expected to find 4 occurrences, found ") + occurrences);
 
     int32_t endPos = 28;
     for ( occurrences = 0, startPos = 5;
@@ -707,7 +735,8 @@ UnicodeStringTest::TestSearching()
           (startPos = test1.indexOf(test2, startPos, endPos - startPos)) != -1 ? (++occurrences, startPos += 4) : 0)
         ;
     if (occurrences != 4)
-        errln("indexOf with starting and ending offsets failed: expected to find 4 occurrences, found " + occurrences);
+        errln(UnicodeString("indexOf with starting and ending offsets failed: "
+                            "expected to find 4 occurrences, found ") + occurrences);
 
     //using UChar32 string
     for ( startPos=0, occurrences=0;
@@ -722,7 +751,7 @@ UnicodeStringTest::TestSearching()
           (startPos = test3.indexOf(test4, startPos)) != -1 ? (++occurrences, startPos += 2) : 0)
         ;
     if (occurrences != 2)
-        errln("indexOf failed: expected to find 2 occurrences, found " + occurrences);
+        errln(UnicodeString("indexOf failed: expected to find 2 occurrences, found ") + occurrences);
     //---
 
     for ( occurrences = 0, startPos = 0;
@@ -730,21 +759,24 @@ UnicodeStringTest::TestSearching()
           (startPos = test1.indexOf(testChar, startPos)) != -1 ? (++occurrences, startPos += 1) : 0)
         ;
     if (occurrences != 16)
-        errln("indexOf with character failed: expected to find 16 occurrences, found " + occurrences);
+        errln(UnicodeString("indexOf with character failed: "
+                            "expected to find 16 occurrences, found ") + occurrences);
 
     for ( occurrences = 0, startPos = 10;
           startPos != -1 && startPos < test1.length();
           (startPos = test1.indexOf(testChar, startPos)) != -1 ? (++occurrences, startPos += 1) : 0)
         ;
     if (occurrences != 12)
-        errln("indexOf with character & start offset failed: expected to find 12 occurrences, found " + occurrences);
+        errln(UnicodeString("indexOf with character & start offset failed: "
+                            "expected to find 12 occurrences, found ") + occurrences);
 
     for ( occurrences = 0, startPos = 5, endPos = 28;
           startPos != -1 && startPos < test1.length();
           (startPos = test1.indexOf(testChar, startPos, endPos - startPos)) != -1 ? (++occurrences, startPos += 1) : 0)
         ;
     if (occurrences != 10)
-        errln("indexOf with character & start & end offsets failed: expected to find 10 occurrences, found " + occurrences);
+        errln(UnicodeString("indexOf with character & start & end offsets failed: "
+                            "expected to find 10 occurrences, found ") + occurrences);
 
     //testing for UChar32
     UnicodeString subString;
@@ -787,14 +819,16 @@ UnicodeStringTest::TestSearching()
           (startPos = test1.lastIndexOf(test2, 5, startPos - 5)) != -1 ? ++occurrences : 0)
         ;
     if (occurrences != 4)
-        errln("lastIndexOf with starting and ending offsets failed: expected to find 4 occurrences, found " + occurrences);
+        errln(UnicodeString("lastIndexOf with starting and ending offsets failed: "
+                            "expected to find 4 occurrences, found ") + occurrences);
 
     for ( occurrences = 0, startPos = 32;
           startPos != -1;
           (startPos = test1.lastIndexOf(testChar, 5, startPos - 5)) != -1 ? ++occurrences : 0)
         ;
     if (occurrences != 11)
-        errln("lastIndexOf with character & start & end offsets failed: expected to find 11 occurrences, found " + occurrences);
+        errln(UnicodeString("lastIndexOf with character & start & end offsets failed: "
+                            "expected to find 11 occurrences, found ") + occurrences);
 
     //testing UChar32
     startPos=test3.length();
@@ -939,6 +973,17 @@ UnicodeStringTest::TestPrefixAndSuffix()
     }
 }
 
+void
+UnicodeStringTest::TestStartsWithAndEndsWithNulTerminated() {
+    UnicodeString test("abcde");
+    const UChar ab[] = { 0x61, 0x62, 0 };
+    const UChar de[] = { 0x64, 0x65, 0 };
+    assertTrue("abcde.startsWith(ab, -1)", test.startsWith(ab, -1));
+    assertTrue("abcde.startsWith(ab, 0, -1)", test.startsWith(ab, 0, -1));
+    assertTrue("abcde.endsWith(de, -1)", test.endsWith(de, -1));
+    assertTrue("abcde.endsWith(de, 0, -1)", test.endsWith(de, 0, -1));
+}
+
 void
 UnicodeStringTest::TestFindAndReplace()
 {
@@ -979,6 +1024,16 @@ UnicodeStringTest::TestReverse()
     if(test.char32At(0)!=0x1ed0 || test.char32At(1)!=0xc4 || test.char32At(2)!=0x1d15f || test.char32At(4)!=0x2f999) {
         errln("reverse() failed with supplementary characters");
     }
+
+    // Test case for ticket #8091:
+    // UnicodeString::reverse() failed to see a lead surrogate in the middle of
+    // an odd-length string that contains no other lead surrogates.
+    test=UNICODE_STRING_SIMPLE("ab\\U0001F4A9e").unescape();
+    UnicodeString expected=UNICODE_STRING_SIMPLE("e\\U0001F4A9ba").unescape();
+    test.reverse();
+    if(test!=expected) {
+        errln("reverse() failed with only lead surrogate in the middle");
+    }
 }
 
 void
@@ -1093,6 +1148,38 @@ UnicodeStringTest::TestMiscellaneous()
     if(test1.hasMetaData() || UnicodeString().hasMetaData()) {
         errln("UnicodeString::hasMetaData() returns TRUE");
     }
+
+    // test getTerminatedBuffer() on a truncated, shared, heap-allocated string
+    test1=UNICODE_STRING_SIMPLE("abcdefghijklmnopqrstuvwxyz0123456789.");
+    test1.truncate(36);  // ensure length()<getCapacity()
+    test2=test1;  // share the buffer
+    test1.truncate(5);
+    if(test1.length()!=5 || test1.getTerminatedBuffer()[5]!=0) {
+        errln("UnicodeString(shared buffer).truncate() failed");
+    }
+    if(test2.length()!=36 || test2[5]!=0x66 || u_strlen(test2.getTerminatedBuffer())!=36) {
+        errln("UnicodeString(shared buffer).truncate().getTerminatedBuffer() "
+              "modified another copy of the string!");
+    }
+    test1=UNICODE_STRING_SIMPLE("abcdefghijklmnopqrstuvwxyz0123456789.");
+    test1.truncate(36);  // ensure length()<getCapacity()
+    test2=test1;  // share the buffer
+    test1.remove();
+    if(test1.length()!=0 || test1.getTerminatedBuffer()[0]!=0) {
+        errln("UnicodeString(shared buffer).remove() failed");
+    }
+    if(test2.length()!=36 || test2[0]!=0x61 || u_strlen(test2.getTerminatedBuffer())!=36) {
+        errln("UnicodeString(shared buffer).remove().getTerminatedBuffer() "
+              "modified another copy of the string!");
+    }
+
+    // ticket #9740
+    test1.setTo(TRUE, ucs, 3);
+    assertEquals("length of read-only alias", 3, test1.length());
+    test1.trim();
+    assertEquals("length of read-only alias after trim()", 2, test1.length());
+    assertEquals("length of terminated buffer of read-only alias + trim()",
+                 2, u_strlen(test1.getTerminatedBuffer()));
 }
 
 void
@@ -1202,7 +1289,7 @@ UnicodeStringTest::TestStackAllocation()
 
     // test the UChar32 constructor
     UnicodeString c32Test((UChar32)0x10ff2a);
-    if( c32Test.length() != UTF_CHAR_LENGTH(0x10ff2a) ||
+    if( c32Test.length() != U16_LENGTH(0x10ff2a) ||
         c32Test.char32At(c32Test.length() - 1) != 0x10ff2a
     ) {
         errln("The UnicodeString(UChar32) constructor does not work with a 0x10ff2a filler");
@@ -1210,7 +1297,7 @@ UnicodeStringTest::TestStackAllocation()
 
     // test the (new) capacity constructor
     UnicodeString capTest(5, (UChar32)0x2a, 5);
-    if( capTest.length() != 5 * UTF_CHAR_LENGTH(0x2a) ||
+    if( capTest.length() != 5 * U16_LENGTH(0x2a) ||
         capTest.char32At(0) != 0x2a ||
         capTest.char32At(4) != 0x2a
     ) {
@@ -1218,7 +1305,7 @@ UnicodeStringTest::TestStackAllocation()
     }
 
     capTest = UnicodeString(5, (UChar32)0x10ff2a, 5);
-    if( capTest.length() != 5 * UTF_CHAR_LENGTH(0x10ff2a) ||
+    if( capTest.length() != 5 * U16_LENGTH(0x10ff2a) ||
         capTest.char32At(0) != 0x10ff2a ||
         capTest.char32At(4) != 0x10ff2a
     ) {
@@ -1321,7 +1408,7 @@ UnicodeStringTest::TestCountChar32(void) {
         0xd804, 0xdc04, 0xd805, 0xdc05,
         0x67
     };
-    UnicodeString string(str, LENGTHOF(str));
+    UnicodeString string(str, UPRV_LENGTHOF(str));
     int32_t start, length, number;
 
     /* test hasMoreChar32Than() */
@@ -1470,7 +1557,10 @@ UnicodeStringTest::TestBogus() {
 
     // writable alias to another string's buffer: very bad idea, just convenient for this test
     test3.setToBogus();
-    if(!test3.isBogus() || test3.setTo((UChar *)test1.getBuffer(), test1.length(), test1.getCapacity()).isBogus() || test3!=test1) {
+    if(!test3.isBogus() ||
+            test3.setTo(const_cast<UChar *>(test1.getBuffer()),
+                        test1.length(), test1.getCapacity()).isBogus() ||
+            test3!=test1) {
         errln("bogus.setTo(writable alias) failed");
     }
 
@@ -1525,8 +1615,8 @@ UnicodeStringTest::TestBogus() {
     // test that NULL primitive input string values are treated like
     // empty strings, not errors (bogus)
     test2.setTo((UChar32)0x10005);
-    if(test2.insert(1, NULL, 1).length()!=2) {
-        errln("UniStr.insert(...NULL...) should not modify the string but does");
+    if(test2.insert(1, nullptr, 1).length()!=2) {
+        errln("UniStr.insert(...nullptr...) should not modify the string but does");
     }
 
     UErrorCode errorCode=U_ZERO_ERROR;
@@ -1575,11 +1665,11 @@ public:
     TestEnumeration() : i(0) {}
 
     virtual int32_t count(UErrorCode& /*status*/) const {
-        return LENGTHOF(testEnumStrings);
+        return UPRV_LENGTHOF(testEnumStrings);
     }
 
     virtual const UnicodeString *snext(UErrorCode &status) {
-        if(U_SUCCESS(status) && i<LENGTHOF(testEnumStrings)) {
+        if(U_SUCCESS(status) && i<UPRV_LENGTHOF(testEnumStrings)) {
             unistr=UnicodeString(testEnumStrings[i++], "");
             return &unistr;
         }
@@ -1601,7 +1691,7 @@ public:
 private:
     static const char fgClassID;
 
-    int32_t i, length;
+    int32_t i;
 };
 
 const char TestEnumeration::fgClassID=0;
@@ -1617,7 +1707,7 @@ UnicodeStringTest::TestStringEnumeration() {
     const char *pc;
 
     // test the next() default implementation and ensureCharsCapacity()
-    for(i=0; i<LENGTHOF(testEnumStrings); ++i) {
+    for(i=0; i<UPRV_LENGTHOF(testEnumStrings); ++i) {
         status=U_ZERO_ERROR;
         pc=ten.next(&length, status);
         s=UnicodeString(testEnumStrings[i], "");
@@ -1632,7 +1722,7 @@ UnicodeStringTest::TestStringEnumeration() {
 
     // test the unext() default implementation
     ten.reset(status);
-    for(i=0; i<LENGTHOF(testEnumStrings); ++i) {
+    for(i=0; i<UPRV_LENGTHOF(testEnumStrings); ++i) {
         status=U_ZERO_ERROR;
         pu=ten.unext(&length, status);
         s=UnicodeString(testEnumStrings[i], "");
@@ -1649,16 +1739,46 @@ UnicodeStringTest::TestStringEnumeration() {
     if(ten.clone()!=NULL) {
         errln("StringEnumeration.clone()!=NULL");
     }
-}
 
-void
-UnicodeStringTest::TestCharString() {
-    static const char originalCStr[] =
-        "This is a large string that is meant to over flow the internal buffer of CharString. At the time of writing this test, the internal buffer is 128 bytes.";
-    CharString chStr(originalCStr);
-    if (strcmp(originalCStr, chStr) != 0) {
-        errln("CharString doesn't work with large strings.");
+    // test that uenum_openFromStringEnumeration() works
+    // Need a heap allocated string enumeration because it is adopted by the UEnumeration.
+    StringEnumeration *newTen = new TestEnumeration;
+    status=U_ZERO_ERROR;
+    UEnumeration *uten = uenum_openFromStringEnumeration(newTen, &status);
+    if (uten==NULL || U_FAILURE(status)) {
+        errln("fail at file %s, line %d, UErrorCode is %s\n", __FILE__, __LINE__, u_errorName(status));
+        return;
+    }
+    
+    // test  uenum_next()
+    for(i=0; i<UPRV_LENGTHOF(testEnumStrings); ++i) {
+        status=U_ZERO_ERROR;
+        pc=uenum_next(uten, &length, &status);
+        if(U_FAILURE(status) || pc==NULL || strcmp(pc, testEnumStrings[i]) != 0) {
+            errln("File %s, line %d, StringEnumeration.next(%d) failed", __FILE__, __LINE__, i);
+        }
+    }
+    status=U_ZERO_ERROR;
+    if(uenum_next(uten, &length, &status)!=NULL) {
+        errln("File %s, line %d, uenum_next(done)!=NULL");
+    }
+
+    // test the uenum_unext()
+    uenum_reset(uten, &status);
+    for(i=0; i<UPRV_LENGTHOF(testEnumStrings); ++i) {
+        status=U_ZERO_ERROR;
+        pu=uenum_unext(uten, &length, &status);
+        s=UnicodeString(testEnumStrings[i], "");
+        if(U_FAILURE(status) || pu==NULL || length!=s.length() || UnicodeString(TRUE, pu, length)!=s) {
+            errln("File %s, Line %d, uenum_unext(%d) failed", __FILE__, __LINE__, i);
+        }
     }
+    status=U_ZERO_ERROR;
+    if(uenum_unext(uten, &length, &status)!=NULL) {
+        errln("File %s, Line %d, uenum_unext(done)!=NULL" __FILE__, __LINE__);
+    }
+
+    uenum_close(uten);
 }
 
 /*
@@ -1667,24 +1787,21 @@ UnicodeStringTest::TestCharString() {
  *
  * Define a (bogus) UnicodeString class in another namespace and check for ambiguity.
  */
-#if U_HAVE_NAMESPACE
 namespace bogus {
     class UnicodeString {
     public:
         enum EInvariant { kInvariant };
         UnicodeString() : i(1) {}
-        UnicodeString(UBool /*isTerminated*/, const UChar * /*text*/, int32_t textLength) : i(textLength) {}
+        UnicodeString(UBool /*isTerminated*/, const UChar * /*text*/, int32_t textLength) : i(textLength) {(void)i;}
         UnicodeString(const char * /*src*/, int32_t length, enum EInvariant /*inv*/
 ) : i(length) {}
     private:
         int32_t i;
     };
 }
-#endif
 
 void
 UnicodeStringTest::TestNameSpace() {
-#if U_HAVE_NAMESPACE
     // Provoke name collision unless the UnicodeString macros properly
     // qualify the icu::UnicodeString class.
     using namespace bogus;
@@ -1699,5 +1816,440 @@ UnicodeStringTest::TestNameSpace() {
     if(s4.length()!=9) {
         errln("Something wrong with UnicodeString::operator+().");
     }
+}
+
+void
+UnicodeStringTest::TestUTF32() {
+    // Input string length US_STACKBUF_SIZE to cause overflow of the
+    // initially chosen fStackBuffer due to supplementary characters.
+    static const UChar32 utf32[] = {
+        0x41, 0xd900, 0x61, 0xdc00, -1, 0x110000, 0x5a, 0x50000, 0x7a,
+        0x10000, 0x20000, 0xe0000, 0x10ffff
+    };
+    static const UChar expected_utf16[] = {
+        0x41, 0xfffd, 0x61, 0xfffd, 0xfffd, 0xfffd, 0x5a, 0xd900, 0xdc00, 0x7a,
+        0xd800, 0xdc00, 0xd840, 0xdc00, 0xdb40, 0xdc00, 0xdbff, 0xdfff
+    };
+    UnicodeString from32 = UnicodeString::fromUTF32(utf32, UPRV_LENGTHOF(utf32));
+    UnicodeString expected(FALSE, expected_utf16, UPRV_LENGTHOF(expected_utf16));
+    if(from32 != expected) {
+        errln("UnicodeString::fromUTF32() did not create the expected string.");
+    }
+
+    static const UChar utf16[] = {
+        0x41, 0xd900, 0x61, 0xdc00, 0x5a, 0xd900, 0xdc00, 0x7a, 0xd800, 0xdc00, 0xdbff, 0xdfff
+    };
+    static const UChar32 expected_utf32[] = {
+        0x41, 0xfffd, 0x61, 0xfffd, 0x5a, 0x50000, 0x7a, 0x10000, 0x10ffff
+    };
+    UChar32 result32[16];
+    UErrorCode errorCode = U_ZERO_ERROR;
+    int32_t length32 =
+        UnicodeString(FALSE, utf16, UPRV_LENGTHOF(utf16)).
+        toUTF32(result32, UPRV_LENGTHOF(result32), errorCode);
+    if( length32 != UPRV_LENGTHOF(expected_utf32) ||
+        0 != uprv_memcmp(result32, expected_utf32, length32*4) ||
+        result32[length32] != 0
+    ) {
+        errln("UnicodeString::toUTF32() did not create the expected string.");
+    }
+}
+
+class TestCheckedArrayByteSink : public CheckedArrayByteSink {
+public:
+    TestCheckedArrayByteSink(char* outbuf, int32_t capacity)
+            : CheckedArrayByteSink(outbuf, capacity), calledFlush(FALSE) {}
+    virtual void Flush() { calledFlush = TRUE; }
+    UBool calledFlush;
+};
+
+void
+UnicodeStringTest::TestUTF8() {
+    static const uint8_t utf8[] = {
+        // Code points:
+        // 0x41, 0xd900,
+        // 0x61, 0xdc00,
+        // 0x110000, 0x5a,
+        // 0x50000, 0x7a,
+        // 0x10000, 0x20000,
+        // 0xe0000, 0x10ffff
+        0x41, 0xed, 0xa4, 0x80,
+        0x61, 0xed, 0xb0, 0x80,
+        0xf4, 0x90, 0x80, 0x80, 0x5a,
+        0xf1, 0x90, 0x80, 0x80, 0x7a,
+        0xf0, 0x90, 0x80, 0x80, 0xf0, 0xa0, 0x80, 0x80,
+        0xf3, 0xa0, 0x80, 0x80, 0xf4, 0x8f, 0xbf, 0xbf
+    };
+    static const UChar expected_utf16[] = {
+        0x41, 0xfffd,
+        0x61, 0xfffd,
+        0xfffd, 0x5a,
+        0xd900, 0xdc00, 0x7a,
+        0xd800, 0xdc00, 0xd840, 0xdc00,
+        0xdb40, 0xdc00, 0xdbff, 0xdfff
+    };
+    UnicodeString from8 = UnicodeString::fromUTF8(StringPiece((const char *)utf8, (int32_t)sizeof(utf8)));
+    UnicodeString expected(FALSE, expected_utf16, UPRV_LENGTHOF(expected_utf16));
+
+    if(from8 != expected) {
+        errln("UnicodeString::fromUTF8(StringPiece) did not create the expected string.");
+    }
+    std::string utf8_string((const char *)utf8, sizeof(utf8));
+    UnicodeString from8b = UnicodeString::fromUTF8(utf8_string);
+    if(from8b != expected) {
+        errln("UnicodeString::fromUTF8(std::string) did not create the expected string.");
+    }
+
+    static const UChar utf16[] = {
+        0x41, 0xd900, 0x61, 0xdc00, 0x5a, 0xd900, 0xdc00, 0x7a, 0xd800, 0xdc00, 0xdbff, 0xdfff
+    };
+    static const uint8_t expected_utf8[] = {
+        0x41, 0xef, 0xbf, 0xbd, 0x61, 0xef, 0xbf, 0xbd, 0x5a, 0xf1, 0x90, 0x80, 0x80, 0x7a,
+        0xf0, 0x90, 0x80, 0x80, 0xf4, 0x8f, 0xbf, 0xbf
+    };
+    UnicodeString us(FALSE, utf16, UPRV_LENGTHOF(utf16));
+
+    char buffer[64];
+    TestCheckedArrayByteSink sink(buffer, (int32_t)sizeof(buffer));
+    us.toUTF8(sink);
+    if( sink.NumberOfBytesWritten() != (int32_t)sizeof(expected_utf8) ||
+        0 != uprv_memcmp(buffer, expected_utf8, sizeof(expected_utf8))
+    ) {
+        errln("UnicodeString::toUTF8() did not create the expected string.");
+    }
+    if(!sink.calledFlush) {
+        errln("UnicodeString::toUTF8(sink) did not sink.Flush().");
+    }
+    // Initial contents for testing that toUTF8String() appends.
+    std::string result8 = "-->";
+    std::string expected8 = "-->" + std::string((const char *)expected_utf8, sizeof(expected_utf8));
+    // Use the return value just for testing.
+    std::string &result8r = us.toUTF8String(result8);
+    if(result8r != expected8 || &result8r != &result8) {
+        errln("UnicodeString::toUTF8String() did not create the expected string.");
+    }
+}
+
+// Test if this compiler supports Return Value Optimization of unnamed temporary objects.
+static UnicodeString wrapUChars(const UChar *uchars) {
+    return UnicodeString(TRUE, uchars, -1);
+}
+
+void
+UnicodeStringTest::TestReadOnlyAlias() {
+    UChar uchars[]={ 0x61, 0x62, 0 };
+    UnicodeString alias(TRUE, uchars, 2);
+    if(alias.length()!=2 || alias.getBuffer()!=uchars || alias.getTerminatedBuffer()!=uchars) {
+        errln("UnicodeString read-only-aliasing constructor does not behave as expected.");
+        return;
+    }
+    alias.truncate(1);
+    if(alias.length()!=1 || alias.getBuffer()!=uchars) {
+        errln("UnicodeString(read-only-alias).truncate() did not preserve aliasing as expected.");
+    }
+    if(alias.getTerminatedBuffer()==uchars) {
+        errln("UnicodeString(read-only-alias).truncate().getTerminatedBuffer() "
+              "did not allocate and copy as expected.");
+    }
+    if(uchars[1]!=0x62) {
+        errln("UnicodeString(read-only-alias).truncate().getTerminatedBuffer() "
+              "modified the original buffer.");
+    }
+    if(1!=u_strlen(alias.getTerminatedBuffer())) {
+        errln("UnicodeString(read-only-alias).truncate().getTerminatedBuffer() "
+              "does not return a buffer terminated at the proper length.");
+    }
+
+    alias.setTo(TRUE, uchars, 2);
+    if(alias.length()!=2 || alias.getBuffer()!=uchars || alias.getTerminatedBuffer()!=uchars) {
+        errln("UnicodeString read-only-aliasing setTo() does not behave as expected.");
+        return;
+    }
+    alias.remove();
+    if(alias.length()!=0) {
+        errln("UnicodeString(read-only-alias).remove() did not work.");
+    }
+    if(alias.getTerminatedBuffer()==uchars) {
+        errln("UnicodeString(read-only-alias).remove().getTerminatedBuffer() "
+              "did not un-alias as expected.");
+    }
+    if(uchars[0]!=0x61) {
+        errln("UnicodeString(read-only-alias).remove().getTerminatedBuffer() "
+              "modified the original buffer.");
+    }
+    if(0!=u_strlen(alias.getTerminatedBuffer())) {
+        errln("UnicodeString.setTo(read-only-alias).remove().getTerminatedBuffer() "
+              "does not return a buffer terminated at length 0.");
+    }
+
+    UnicodeString longString=UNICODE_STRING_SIMPLE("abcdefghijklmnopqrstuvwxyz0123456789");
+    alias.setTo(FALSE, longString.getBuffer(), longString.length());
+    alias.remove(0, 10);
+    if(longString.compare(10, INT32_MAX, alias)!=0 || alias.getBuffer()!=longString.getBuffer()+10) {
+        errln("UnicodeString.setTo(read-only-alias).remove(0, 10) did not preserve aliasing as expected.");
+    }
+    alias.setTo(FALSE, longString.getBuffer(), longString.length());
+    alias.remove(27, 99);
+    if(longString.compare(0, 27, alias)!=0 || alias.getBuffer()!=longString.getBuffer()) {
+        errln("UnicodeString.setTo(read-only-alias).remove(27, 99) did not preserve aliasing as expected.");
+    }
+    alias.setTo(FALSE, longString.getBuffer(), longString.length());
+    alias.retainBetween(6, 30);
+    if(longString.compare(6, 24, alias)!=0 || alias.getBuffer()!=longString.getBuffer()+6) {
+        errln("UnicodeString.setTo(read-only-alias).retainBetween(6, 30) did not preserve aliasing as expected.");
+    }
+
+    UChar abc[]={ 0x61, 0x62, 0x63, 0 };
+    UBool hasRVO= wrapUChars(abc).getBuffer()==abc;
+
+    UnicodeString temp;
+    temp.fastCopyFrom(longString.tempSubString());
+    if(temp!=longString || (hasRVO && temp.getBuffer()!=longString.getBuffer())) {
+        errln("UnicodeString.tempSubString() failed");
+    }
+    temp.fastCopyFrom(longString.tempSubString(-3, 5));
+    if(longString.compare(0, 5, temp)!=0 || (hasRVO && temp.getBuffer()!=longString.getBuffer())) {
+        errln("UnicodeString.tempSubString(-3, 5) failed");
+    }
+    temp.fastCopyFrom(longString.tempSubString(17));
+    if(longString.compare(17, INT32_MAX, temp)!=0 || (hasRVO && temp.getBuffer()!=longString.getBuffer()+17)) {
+        errln("UnicodeString.tempSubString(17) failed");
+    }
+    temp.fastCopyFrom(longString.tempSubString(99));
+    if(!temp.isEmpty()) {
+        errln("UnicodeString.tempSubString(99) failed");
+    }
+    temp.fastCopyFrom(longString.tempSubStringBetween(6));
+    if(longString.compare(6, INT32_MAX, temp)!=0 || (hasRVO && temp.getBuffer()!=longString.getBuffer()+6)) {
+        errln("UnicodeString.tempSubStringBetween(6) failed");
+    }
+    temp.fastCopyFrom(longString.tempSubStringBetween(8, 18));
+    if(longString.compare(8, 10, temp)!=0 || (hasRVO && temp.getBuffer()!=longString.getBuffer()+8)) {
+        errln("UnicodeString.tempSubStringBetween(8, 18) failed");
+    }
+    UnicodeString bogusString;
+    bogusString.setToBogus();
+    temp.fastCopyFrom(bogusString.tempSubStringBetween(8, 18));
+    if(!temp.isBogus()) {
+        errln("UnicodeString.setToBogus().tempSubStringBetween(8, 18) failed");
+    }
+}
+
+void
+UnicodeStringTest::doTestAppendable(UnicodeString &dest, Appendable &app) {
+    static const UChar cde[3]={ 0x63, 0x64, 0x65 };
+    static const UChar fg[3]={ 0x66, 0x67, 0 };
+    if(!app.reserveAppendCapacity(12)) {
+        errln("Appendable.reserve(12) failed");
+    }
+    app.appendCodeUnit(0x61);
+    app.appendCodePoint(0x62);
+    app.appendCodePoint(0x50000);
+    app.appendString(cde, 3);
+    app.appendString(fg, -1);
+    UChar scratch[3];
+    int32_t capacity=-1;
+    UChar *buffer=app.getAppendBuffer(3, 3, scratch, 3, &capacity);
+    if(capacity<3) {
+        errln("Appendable.getAppendBuffer(min=3) returned capacity=%d<3", (int)capacity);
+        return;
+    }
+    static const UChar hij[3]={ 0x68, 0x69, 0x6a };
+    u_memcpy(buffer, hij, 3);
+    app.appendString(buffer, 3);
+    if(dest!=UNICODE_STRING_SIMPLE("ab\\U00050000cdefghij").unescape()) {
+        errln("Appendable.append(...) failed");
+    }
+    buffer=app.getAppendBuffer(0, 3, scratch, 3, &capacity);
+    if(buffer!=NULL || capacity!=0) {
+        errln("Appendable.getAppendBuffer(min=0) failed");
+    }
+    capacity=1;
+    buffer=app.getAppendBuffer(3, 3, scratch, 2, &capacity);
+    if(buffer!=NULL || capacity!=0) {
+        errln("Appendable.getAppendBuffer(scratch<min) failed");
+    }
+}
+
+class SimpleAppendable : public Appendable {
+public:
+    explicit SimpleAppendable(UnicodeString &dest) : str(dest) {}
+    virtual UBool appendCodeUnit(UChar c) { str.append(c); return TRUE; }
+    SimpleAppendable &reset() { str.remove(); return *this; }
+private:
+    UnicodeString &str;
+};
+
+void
+UnicodeStringTest::TestAppendable() {
+    UnicodeString dest;
+    SimpleAppendable app(dest);
+    doTestAppendable(dest, app);
+}
+
+void
+UnicodeStringTest::TestUnicodeStringImplementsAppendable() {
+    UnicodeString dest;
+    UnicodeStringAppendable app(dest);
+    doTestAppendable(dest, app);
+}
+
+void
+UnicodeStringTest::TestSizeofUnicodeString() {
+    // See the comments in unistr.h near the declaration of UnicodeString's fields.
+    // See the API comments for UNISTR_OBJECT_SIZE.
+    size_t sizeofUniStr=sizeof(UnicodeString);
+    size_t expected=UNISTR_OBJECT_SIZE;
+    if(expected!=sizeofUniStr) {
+        // Possible cause: UNISTR_OBJECT_SIZE may not be a multiple of sizeof(pointer),
+        // of the compiler might add more internal padding than expected.
+        errln("sizeof(UnicodeString)=%d, expected UNISTR_OBJECT_SIZE=%d",
+              (int)sizeofUniStr, (int)expected);
+    }
+    if(sizeofUniStr<32) {
+        errln("sizeof(UnicodeString)=%d < 32, probably too small", (int)sizeofUniStr);
+    }
+    // We assume that the entire UnicodeString object,
+    // minus the vtable pointer and 2 bytes for flags and short length,
+    // is available for internal storage of UChars.
+    int32_t expectedStackBufferLength=((int32_t)UNISTR_OBJECT_SIZE-sizeof(void *)-2)/U_SIZEOF_UCHAR;
+    UnicodeString s;
+    const UChar *emptyBuffer=s.getBuffer();
+    for(int32_t i=0; i<expectedStackBufferLength; ++i) {
+        s.append((UChar)0x2e);
+    }
+    const UChar *fullBuffer=s.getBuffer();
+    if(fullBuffer!=emptyBuffer) {
+        errln("unexpected reallocation when filling with assumed stack buffer size of %d",
+              expectedStackBufferLength);
+    }
+    const UChar *terminatedBuffer=s.getTerminatedBuffer();
+    if(terminatedBuffer==emptyBuffer) {
+        errln("unexpected keeping stack buffer when overfilling assumed stack buffer size of %d",
+              expectedStackBufferLength);
+    }
+}
+
+void
+UnicodeStringTest::TestMoveSwap() {
+    static const UChar abc[3] = { 0x61, 0x62, 0x63 };  // "abc"
+    UnicodeString s1(FALSE, abc, UPRV_LENGTHOF(abc));  // read-only alias
+    UnicodeString s2(100, 0x7a, 100);  // 100 * 'z' should be on the heap
+    UnicodeString s3("defg", 4, US_INV);  // in stack buffer
+    const UChar *p = s2.getBuffer();
+    s1.swap(s2);
+    if(s1.getBuffer() != p || s1.length() != 100 || s2.getBuffer() != abc || s2.length() != 3) {
+        errln("UnicodeString.swap() did not swap");
+    }
+    swap(s2, s3);
+    if(s2 != UNICODE_STRING_SIMPLE("defg") || s3.getBuffer() != abc || s3.length() != 3) {
+        errln("swap(UnicodeString) did not swap back");
+    }
+    UnicodeString s4;
+    s4.moveFrom(s1);
+    if(s4.getBuffer() != p || s4.length() != 100 || !s1.isBogus()) {
+        errln("UnicodeString.moveFrom(heap) did not move");
+    }
+    UnicodeString s5;
+    s5.moveFrom(s2);
+    if(s5 != UNICODE_STRING_SIMPLE("defg")) {
+        errln("UnicodeString.moveFrom(stack) did not move");
+    }
+    UnicodeString s6;
+    s6.moveFrom(s3);
+    if(s6.getBuffer() != abc || s6.length() != 3) {
+        errln("UnicodeString.moveFrom(alias) did not move");
+    }
+#if U_HAVE_RVALUE_REFERENCES
+    infoln("TestMoveSwap() with rvalue references");
+    s1 = static_cast<UnicodeString &&>(s6);
+    if(s1.getBuffer() != abc || s1.length() != 3) {
+        errln("UnicodeString move assignment operator did not move");
+    }
+    UnicodeString s7(static_cast<UnicodeString &&>(s4));
+    if(s7.getBuffer() != p || s7.length() != 100 || !s4.isBogus()) {
+        errln("UnicodeString move constructor did not move");
+    }
+#else
+    infoln("TestMoveSwap() without rvalue references");
+    UnicodeString s7;
+#endif
+
+    // Move self assignment leaves the object valid but in an undefined state.
+    // Do it to make sure there is no crash,
+    // but do not check for any particular resulting value.
+    s1.moveFrom(s1);
+    s2.moveFrom(s2);
+    s3.moveFrom(s3);
+    s4.moveFrom(s4);
+    s5.moveFrom(s5);
+    s6.moveFrom(s6);
+    s7.moveFrom(s7);
+    // Simple copy assignment must work.
+    UnicodeString simple = UNICODE_STRING_SIMPLE("simple");
+    s1 = s6 = s4 = s7 = simple;
+    if(s1 != simple || s4 != simple || s6 != simple || s7 != simple) {
+        errln("UnicodeString copy after self-move did not work");
+    }
+}
+
+void
+UnicodeStringTest::TestUInt16Pointers() {
+    static const uint16_t carr[] = { 0x61, 0x62, 0x63, 0 };
+    uint16_t arr[4];
+
+    UnicodeString expected(u"abc");
+    assertEquals("abc from pointer", expected, UnicodeString(carr));
+    assertEquals("abc from pointer+length", expected, UnicodeString(carr, 3));
+    assertEquals("abc from read-only-alias pointer", expected, UnicodeString(TRUE, carr, 3));
+
+    UnicodeString alias(arr, 0, 4);
+    alias.append(u'a').append(u'b').append(u'c');
+    assertEquals("abc from writable alias", expected, alias);
+    assertEquals("buffer=abc from writable alias", expected, UnicodeString(arr, 3));
+
+    UErrorCode errorCode = U_ZERO_ERROR;
+    int32_t length = UnicodeString(u"def").extract(arr, 4, errorCode);
+    TEST_ASSERT_STATUS(errorCode);
+    assertEquals("def from extract()", UnicodeString(u"def"), UnicodeString(arr, length));
+}
+
+void
+UnicodeStringTest::TestWCharPointers() {
+#if U_SIZEOF_WCHAR_T==2
+    static const wchar_t carr[] = { 0x61, 0x62, 0x63, 0 };
+    wchar_t arr[4];
+
+    UnicodeString expected(u"abc");
+    assertEquals("abc from pointer", expected, UnicodeString(carr));
+    assertEquals("abc from pointer+length", expected, UnicodeString(carr, 3));
+    assertEquals("abc from read-only-alias pointer", expected, UnicodeString(TRUE, carr, 3));
+
+    UnicodeString alias(arr, 0, 4);
+    alias.append(u'a').append(u'b').append(u'c');
+    assertEquals("abc from writable alias", expected, alias);
+    assertEquals("buffer=abc from writable alias", expected, UnicodeString(arr, 3));
+
+    UErrorCode errorCode = U_ZERO_ERROR;
+    int32_t length = UnicodeString(u"def").extract(arr, 4, errorCode);
+    TEST_ASSERT_STATUS(errorCode);
+    assertEquals("def from extract()", UnicodeString(u"def"), UnicodeString(arr, length));
 #endif
 }
+
+void
+UnicodeStringTest::TestNullPointers() {
+    assertTrue("empty from nullptr", UnicodeString(nullptr).isEmpty());
+    assertTrue("empty from nullptr+length", UnicodeString(nullptr, 2).isEmpty());
+    assertTrue("empty from read-only-alias nullptr", UnicodeString(TRUE, nullptr, 3).isEmpty());
+
+    UnicodeString alias(nullptr, 4, 4);  // empty, no alias
+    assertTrue("empty from writable alias", alias.isEmpty());
+    alias.append(u'a').append(u'b').append(u'c');
+    UnicodeString expected(u"abc");
+    assertEquals("abc from writable alias", expected, alias);
+
+    UErrorCode errorCode = U_ZERO_ERROR;
+    UnicodeString(u"def").extract(nullptr, 0, errorCode);
+    assertEquals("buffer overflow extracting to nullptr", U_BUFFER_OVERFLOW_ERROR, errorCode);
+}