X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/38fbf2fd31f5cd99b500914d6037b1d06b608645..0f5d89e82340278ed3d7d50029f37cab2c41a57e:/icuSources/test/intltest/convtest.cpp diff --git a/icuSources/test/intltest/convtest.cpp b/icuSources/test/intltest/convtest.cpp index 203a4386..3a0e5414 100644 --- a/icuSources/test/intltest/convtest.cpp +++ b/icuSources/test/intltest/convtest.cpp @@ -37,6 +37,7 @@ #include "unicode/uniset.h" #include "unicode/ustring.h" #include "unicode/ures.h" +#include "unicode/utf16.h" #include "convtest.h" #include "cmemory.h" #include "unicode/tstdtmod.h" @@ -67,21 +68,16 @@ ConversionTest::~ConversionTest() { void ConversionTest::runIndexedTest(int32_t index, UBool exec, const char *&name, char * /*par*/) { if (exec) logln("TestSuite ConversionTest: "); - switch (index) { + TESTCASE_AUTO_BEGIN; #if !UCONFIG_NO_FILE_IO - case 0: name="TestToUnicode"; if (exec) TestToUnicode(); break; - case 1: name="TestFromUnicode"; if (exec) TestFromUnicode(); break; - case 2: name="TestGetUnicodeSet"; if (exec) TestGetUnicodeSet(); break; - case 3: name="TestDefaultIgnorableCallback"; if (exec) TestDefaultIgnorableCallback(); break; -#else - case 0: - case 1: - case 2: - case 3: name="skip"; break; + TESTCASE_AUTO(TestToUnicode); + TESTCASE_AUTO(TestFromUnicode); + TESTCASE_AUTO(TestGetUnicodeSet); #endif - case 4: name="TestGetUnicodeSet2"; if (exec) TestGetUnicodeSet2(); break; - default: name=""; break; //needed to end loop - } + TESTCASE_AUTO(TestGetUnicodeSet2); + TESTCASE_AUTO(TestDefaultIgnorableCallback); + TESTCASE_AUTO(TestUTF8ToUTF8Overflow); + TESTCASE_AUTO_END; } // test data interface ----------------------------------------------------- *** @@ -722,6 +718,127 @@ ConversionTest::TestDefaultIgnorableCallback() { delete set_ignorable; } +void +ConversionTest::TestUTF8ToUTF8Overflow() { + IcuTestErrorCode errorCode(*this, "TestUTF8ToUTF8Overflow"); + LocalUConverterPointer cnv1(ucnv_open("UTF-8", errorCode)); + LocalUConverterPointer cnv2(ucnv_open("UTF-8", errorCode)); + static const char *text = "aä"; // ä: 2 bytes + const char *source = text; + const char *sourceLimit = text + strlen(text); + char result[20]; + char *target = result; + const char *targetLimit = result + sizeof(result); + UChar buffer16[20]; + UChar *pivotSource = buffer16; + UChar *pivotTarget = buffer16; + const UChar *pivotLimit = buffer16 + UPRV_LENGTHOF(buffer16); + int32_t length; + + // Convert with insufficient target capacity. + result[2] = 5; + ucnv_convertEx(cnv2.getAlias(), cnv1.getAlias(), + &target, result + 2, &source, sourceLimit, + buffer16, &pivotSource, &pivotTarget, pivotLimit, + FALSE, FALSE, errorCode); + assertEquals("overflow", U_BUFFER_OVERFLOW_ERROR, errorCode.reset()); + length = (int32_t)(target - result); + assertEquals("number of bytes written", 2, length); + assertEquals("next byte not clobbered", 5, result[2]); + + // Convert the rest and flush. + ucnv_convertEx(cnv2.getAlias(), cnv1.getAlias(), + &target, targetLimit, &source, sourceLimit, + buffer16, &pivotSource, &pivotTarget, pivotLimit, + FALSE, TRUE, errorCode); + + assertSuccess("UTF-8->UTF-8", errorCode); + length = (int32_t)(target - result); + assertEquals("3 bytes", 3, length); + if (length == 3) { + assertTrue("result same as input", memcmp(text, result, length) == 0); + } + + ucnv_reset(cnv1.getAlias()); + ucnv_reset(cnv2.getAlias()); + memset(result, 0, sizeof(result)); + static const char *text2 = "a🚲"; // U+1F6B2 bicycle: 4 bytes + source = text2; + sourceLimit = text2 + strlen(text2); + target = result; + pivotSource = pivotTarget = buffer16; + + // Convert with insufficient target capacity. + result[3] = 5; + ucnv_convertEx(cnv2.getAlias(), cnv1.getAlias(), + &target, result + 3, &source, sourceLimit, + buffer16, &pivotSource, &pivotTarget, pivotLimit, + FALSE, FALSE, errorCode); + assertEquals("text2 overflow", U_BUFFER_OVERFLOW_ERROR, errorCode.reset()); + length = (int32_t)(target - result); + assertEquals("text2 number of bytes written", 3, length); + assertEquals("text2 next byte not clobbered", 5, result[3]); + + // Convert the rest and flush. + ucnv_convertEx(cnv2.getAlias(), cnv1.getAlias(), + &target, targetLimit, &source, sourceLimit, + buffer16, &pivotSource, &pivotTarget, pivotLimit, + FALSE, TRUE, errorCode); + + assertSuccess("text2 UTF-8->UTF-8", errorCode); + length = (int32_t)(target - result); + assertEquals("text2 5 bytes", 5, length); + if (length == 5) { + assertTrue("text2 result same as input", memcmp(text2, result, length) == 0); + } + + ucnv_reset(cnv1.getAlias()); + ucnv_reset(cnv2.getAlias()); + memset(result, 0, sizeof(result)); + static const char *illFormed = "\xf1\x91\x93\x96\x91\x94"; // U+514D6 + two more trail bytes + source = illFormed; + sourceLimit = illFormed + strlen(illFormed); + target = result; + pivotSource = pivotTarget = buffer16; + + ucnv_setToUCallBack(cnv1.getAlias(), UCNV_TO_U_CALLBACK_STOP, nullptr, nullptr, nullptr, errorCode); + + // Convert only two bytes and flush (but expect failure). + char errorBytes[10]; + int8_t errorLength; + result[0] = 5; + ucnv_convertEx(cnv2.getAlias(), cnv1.getAlias(), + &target, targetLimit, &source, source + 2, + buffer16, &pivotSource, &pivotTarget, pivotLimit, + FALSE, TRUE, errorCode); + assertEquals("illFormed truncated", U_TRUNCATED_CHAR_FOUND, errorCode.reset()); + length = (int32_t)(target - result); + assertEquals("illFormed number of bytes written", 0, length); + errorLength = UPRV_LENGTHOF(errorBytes); + ucnv_getInvalidChars(cnv1.getAlias(), errorBytes, &errorLength, errorCode); + assertEquals("illFormed truncated errorLength", 2, (int32_t)errorLength); + if (errorLength == 2) { + assertEquals("illFormed truncated errorBytes", 0xf191, + ((int32_t)(uint8_t)errorBytes[0] << 8) | (uint8_t)errorBytes[1]); + } + + // Continue conversion starting with a trail byte. + ucnv_convertEx(cnv2.getAlias(), cnv1.getAlias(), + &target, targetLimit, &source, sourceLimit, + buffer16, &pivotSource, &pivotTarget, pivotLimit, + FALSE, TRUE, errorCode); + + assertEquals("illFormed trail byte", U_ILLEGAL_CHAR_FOUND, errorCode.reset()); + length = (int32_t)(target - result); + assertEquals("illFormed trail byte number of bytes written", 0, length); + errorLength = UPRV_LENGTHOF(errorBytes); + ucnv_getInvalidChars(cnv1.getAlias(), errorBytes, &errorLength, errorCode); + assertEquals("illFormed trail byte errorLength", 1, (int32_t)errorLength); + if (errorLength == 1) { + assertEquals("illFormed trail byte errorBytes", 0x93, (int32_t)(uint8_t)errorBytes[0]); + } +} + // open testdata or ICU data converter ------------------------------------- *** UConverter *