X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/b331163bffd790ced0e88b73f44f86d49ccc48a5..refs/heads/master:/icuSources/test/intltest/ustrtest.cpp?ds=sidebyside diff --git a/icuSources/test/intltest/ustrtest.cpp b/icuSources/test/intltest/ustrtest.cpp index 97151d95..b6515ea8 100644 --- a/icuSources/test/intltest/ustrtest.cpp +++ b/icuSources/test/intltest/ustrtest.cpp @@ -1,9 +1,13 @@ +// © 2016 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html /******************************************************************** * COPYRIGHT: - * Copyright (c) 1997-2014, 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" @@ -11,6 +15,7 @@ #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" @@ -27,44 +32,42 @@ using namespace std; 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 = "TestNameSpace"; if (exec) TestNameSpace(); break; - case 17: name = "TestUTF32"; if (exec) TestUTF32(); break; - case 18: name = "TestUTF8"; if (exec) TestUTF8(); break; - case 19: name = "TestReadOnlyAlias"; if (exec) TestReadOnlyAlias(); break; - case 20: name = "TestAppendable"; if (exec) TestAppendable(); break; - case 21: name = "TestUnicodeStringImplementsAppendable"; if (exec) TestUnicodeStringImplementsAppendable(); break; - case 22: name = "TestSizeofUnicodeString"; if (exec) TestSizeofUnicodeString(); break; - case 23: name = "TestStartsWithAndEndsWithNulTerminated"; if (exec) TestStartsWithAndEndsWithNulTerminated(); 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 @@ -74,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) @@ -363,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); } @@ -1123,27 +1126,25 @@ 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"); @@ -1253,7 +1254,7 @@ UnicodeStringTest::TestStackAllocation() errln("UnicodeString.setTo(readonly alias) does not alias correctly"); } - UnicodeString *c=(UnicodeString *)test->clone(); + UnicodeString *c=test->clone(); workingBuffer[1] = 0x109; if(test->charAt(1) != 0x109) { @@ -1557,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"); } @@ -1612,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; @@ -1878,9 +1882,9 @@ UnicodeStringTest::TestUTF8() { 0xf3, 0xa0, 0x80, 0x80, 0xf4, 0x8f, 0xbf, 0xbf }; static const UChar expected_utf16[] = { - 0x41, 0xfffd, - 0x61, 0xfffd, - 0xfffd, 0x5a, + 0x41, 0xfffd, 0xfffd, 0xfffd, + 0x61, 0xfffd, 0xfffd, 0xfffd, + 0xfffd, 0xfffd, 0xfffd, 0xfffd,0x5a, 0xd900, 0xdc00, 0x7a, 0xd800, 0xdc00, 0xd840, 0xdc00, 0xdb40, 0xdc00, 0xdbff, 0xdfff @@ -1891,13 +1895,11 @@ UnicodeStringTest::TestUTF8() { if(from8 != expected) { errln("UnicodeString::fromUTF8(StringPiece) did not create the expected string."); } -#if U_HAVE_STD_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."); } -#endif static const UChar utf16[] = { 0x41, 0xd900, 0x61, 0xdc00, 0x5a, 0xd900, 0xdc00, 0x7a, 0xd800, 0xdc00, 0xdbff, 0xdfff @@ -1919,7 +1921,6 @@ UnicodeStringTest::TestUTF8() { if(!sink.calledFlush) { errln("UnicodeString::toUTF8(sink) did not sink.Flush()."); } -#if U_HAVE_STD_STRING // Initial contents for testing that toUTF8String() appends. std::string result8 = "-->"; std::string expected8 = "-->" + std::string((const char *)expected_utf8, sizeof(expected_utf8)); @@ -1928,7 +1929,6 @@ UnicodeStringTest::TestUTF8() { if(result8r != expected8 || &result8r != &result8) { errln("UnicodeString::toUTF8String() did not create the expected string."); } -#endif } // Test if this compiler supports Return Value Optimization of unnamed temporary objects. @@ -2098,20 +2098,215 @@ UnicodeStringTest::TestUnicodeStringImplementsAppendable() { 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; - switch(sizeof(void *)) { - case 4: - expected=32; - break; - case 8: - expected=40; - break; - default: - logln("This platform has neither 32-bit nor 64-bit pointers."); - return; - } + size_t expected=UNISTR_OBJECT_SIZE; if(expected!=sizeofUniStr) { - errln("sizeof(UnicodeString)=%d, expected %d", (int)sizeofUniStr, (int)expected); + // 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(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); }