+ 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);
+ }
+}
+
+// Try to avoid clang -Wself-move warnings from s1 = std::move(s1);
+void moveFrom(UnicodeString &dest, UnicodeString &src) {
+ dest = std::move(src);
+}
+
+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 = std::move(s1);
+ if(s4.getBuffer() != p || s4.length() != 100 || !s1.isBogus()) {
+ errln("UnicodeString = std::move(heap) did not move");
+ }
+ UnicodeString s5;
+ s5 = std::move(s2);
+ if(s5 != UNICODE_STRING_SIMPLE("defg")) {
+ errln("UnicodeString = std::move(stack) did not move");
+ }
+ UnicodeString s6;
+ s6 = std::move(s3);
+ if(s6.getBuffer() != abc || s6.length() != 3) {
+ errln("UnicodeString = std::move(alias) did not move");
+ }
+ 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");
+ }
+
+ // 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);