X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/46f4442e9a5a4f3b98b7c1083586332f6a8a99a4..refs/heads/master:/icuSources/test/intltest/ustrtest.cpp diff --git a/icuSources/test/intltest/ustrtest.cpp b/icuSources/test/intltest/ustrtest.cpp index c40b4c4a..b6515ea8 100644 --- a/icuSources/test/intltest/ustrtest.cpp +++ b/icuSources/test/intltest/ustrtest.cpp @@ -1,66 +1,73 @@ +// © 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 + #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 using namespace std; -#elif U_IOSTREAM_SOURCE >= 198506 -#include -#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(TestUnicodeStringInsertAppendToSelf); + TESTCASE_AUTO_END; } void @@ -70,7 +77,7 @@ UnicodeStringTest::TestBasicManipulation() UnicodeString expectedValue; UnicodeString *c; - c=(UnicodeString *)test1.clone(); + c=test1.clone(); test1.insert(24, "good "); expectedValue = "Now is the time for all good men to come swiftly to the aid of the party.\n"; if (test1 != expectedValue) @@ -107,9 +114,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 +124,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 +200,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 +217,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 +236,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 +366,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=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 +722,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 +738,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 +754,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 +762,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 +822,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 +976,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 +1027,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 @@ -1068,31 +1126,61 @@ UnicodeStringTest::TestMiscellaneous() errln("UnicodeString(u[-1]).getTerminatedBuffer() returns a bad buffer"); } - test1=UNICODE_STRING("la", 2); - test1.append(UNICODE_STRING(" lila", 5).getTerminatedBuffer(), 0, -1); - if(test1!=UNICODE_STRING("la lila", 7)) { - errln("UnicodeString::append(const UChar *, start, length) failed"); - } + // NOTE: Some compilers will optimize u"la" to point to the same static memory + // as u" lila", offset by 3 code units + test1=UnicodeString(TRUE, u"la", 2); + test1.append(UnicodeString(TRUE, u" lila", 5).getTerminatedBuffer(), 0, -1); + assertEquals("UnicodeString::append(const UChar *, start, length) failed", + u"la lila", test1); - test1.insert(3, UNICODE_STRING("dudum ", 6), 0, INT32_MAX); - if(test1!=UNICODE_STRING("la dudum lila", 13)) { - errln("UnicodeString::insert(start, const UniStr &, start, length) failed"); - } + test1.insert(3, UnicodeString(TRUE, u"dudum ", 6), 0, INT32_MAX); + assertEquals("UnicodeString::insert(start, const UniStr &, start, length) failed", + u"la dudum lila", test1); static const UChar ucs[]={ 0x68, 0x6d, 0x20, 0 }; test1.insert(9, ucs, -1); - if(test1!=UNICODE_STRING("la dudum hm lila", 16)) { - errln("UnicodeString::insert(start, const UChar *, length) failed"); - } + assertEquals("UnicodeString::insert(start, const UChar *, length) failed", + u"la dudum hm lila", test1); test1.replace(9, 2, (UChar)0x2b); - if(test1!=UNICODE_STRING("la dudum + lila", 15)) { - errln("UnicodeString::replace(start, length, UChar) failed"); - } + assertEquals("UnicodeString::replace(start, length, UChar) failed", + u"la dudum + lila", test1); 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()clone(); + UnicodeString *c=test->clone(); workingBuffer[1] = 0x109; if(test->charAt(1) != 0x109) { @@ -1202,7 +1290,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 +1298,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 +1306,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 +1409,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 +1558,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(test1.getBuffer()), + test1.length(), test1.getCapacity()).isBogus() || + test3!=test1) { errln("bogus.setTo(writable alias) failed"); } @@ -1525,8 +1616,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 +1666,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(s6); + if(s1.getBuffer() != abc || s1.length() != 3) { + errln("UnicodeString move assignment operator did not move"); + } + UnicodeString s7(static_cast(s4)); + if(s7.getBuffer() != p || s7.length() != 100 || !s4.isBogus()) { + errln("UnicodeString move constructor did not move"); + } + + // 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. + moveFrom(s1, s1); + moveFrom(s2, s2); + moveFrom(s3, s3); + moveFrom(s4, s4); + moveFrom(s5, s5); + moveFrom(s6, s6); + moveFrom(s7, 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); + assertSuccess(WHERE, 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); + assertSuccess(WHERE, 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); +} + +void UnicodeStringTest::TestUnicodeStringInsertAppendToSelf() { + IcuTestErrorCode status(*this, "TestUnicodeStringAppendToSelf"); + + // Test append operation + UnicodeString str(u"foo "); + str.append(str); + str.append(str); + str.append(str); + assertEquals("", u"foo foo foo foo foo foo foo foo ", str); + + // Test append operation with readonly alias to start + str = UnicodeString(TRUE, u"foo ", 4); + str.append(str); + str.append(str); + str.append(str); + assertEquals("", u"foo foo foo foo foo foo foo foo ", str); + + // Test append operation with aliased substring + str = u"abcde"; + UnicodeString sub = str.tempSubString(1, 2); + str.append(sub); + assertEquals("", u"abcdebc", str); + + // Test append operation with double-aliased substring + str = UnicodeString(TRUE, u"abcde", 5); + sub = str.tempSubString(1, 2); + str.append(sub); + assertEquals("", u"abcdebc", str); + + // Test insert operation + str = u"a-*b"; + str.insert(2, str); + str.insert(4, str); + str.insert(8, str); + assertEquals("", u"a-a-a-a-a-a-a-a-*b*b*b*b*b*b*b*b", str); + + // Test insert operation with readonly alias to start + str = UnicodeString(TRUE, u"a-*b", 4); + str.insert(2, str); + str.insert(4, str); + str.insert(8, str); + assertEquals("", u"a-a-a-a-a-a-a-a-*b*b*b*b*b*b*b*b", str); + + // Test insert operation with aliased substring + str = u"abcde"; + sub = str.tempSubString(1, 3); + str.insert(2, sub); + assertEquals("", u"abbcdcde", str); + + // Test insert operation with double-aliased substring + str = UnicodeString(TRUE, u"abcde", 5); + sub = str.tempSubString(1, 3); + str.insert(2, sub); + assertEquals("", u"abbcdcde", str); +}