1// © 2017 and later: Unicode, Inc. and others. 2// License & terms of use: http://www.unicode.org/copyright.html 3 4#include "unicode/utypes.h" 5 6#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT 7 8#include "putilimp.h" 9#include "numbertest.h" 10 11static const char16_t *EXAMPLE_STRINGS[] = { 12 u"", 13 u"xyz", 14 u"The quick brown fox jumps over the lazy dog", 15 u"", 16 u"mixed and ASCII", 17 u"with combining characters like ", 18 u"A very very very very very very very very very very long string to force heap"}; 19 20void NumberStringBuilderTest::runIndexedTest(int32_t index, UBool exec, const char *&name, char *) { 21 if (exec) { 22 logln("TestSuite NumberStringBuilderTest: "); 23 } 24 TESTCASE_AUTO_BEGIN; 25 TESTCASE_AUTO(testInsertAppendUnicodeString); 26 TESTCASE_AUTO(testInsertAppendCodePoint); 27 TESTCASE_AUTO(testCopy); 28 TESTCASE_AUTO(testFields); 29 TESTCASE_AUTO(testUnlimitedCapacity); 30 TESTCASE_AUTO(testCodePoints); 31 TESTCASE_AUTO_END; 32} 33 34void NumberStringBuilderTest::testInsertAppendUnicodeString() { 35 UErrorCode status = U_ZERO_ERROR; 36 UnicodeString sb1; 37 NumberStringBuilder sb2; 38 for (const char16_t* strPtr : EXAMPLE_STRINGS) { 39 UnicodeString str(strPtr); 40 41 NumberStringBuilder sb3; 42 sb1.append(str); 43 // Note: UNUM_FIELD_COUNT is like passing null in Java 44 sb2.append(str, UNUM_FIELD_COUNT, status); 45 assertSuccess("Appending to sb2", status); 46 sb3.append(str, UNUM_FIELD_COUNT, status); 47 assertSuccess("Appending to sb3", status); 48 assertEqualsImpl(sb1, sb2); 49 assertEqualsImpl(str, sb3); 50 51 UnicodeString sb4; 52 NumberStringBuilder sb5; 53 sb4.append(u""); 54 sb4.append(str); 55 sb4.append(u"xx"); 56 sb5.append(u"xx", UNUM_FIELD_COUNT, status); 57 assertSuccess("Appending to sb5", status); 58 sb5.insert(2, str, UNUM_FIELD_COUNT, status); 59 assertSuccess("Inserting into sb5", status); 60 assertEqualsImpl(sb4, sb5); 61 62 int start = uprv_min(1, str.length()); 63 int end = uprv_min(10, str.length()); 64 sb4.insert(3, str, start, end - start); // UnicodeString uses length instead of end index 65 sb5.insert(3, str, start, end, UNUM_FIELD_COUNT, status); 66 assertSuccess("Inserting into sb5 again", status); 67 assertEqualsImpl(sb4, sb5); 68 69 UnicodeString sb4cp(sb4); 70 NumberStringBuilder sb5cp(sb5); 71 sb4.append(sb4cp); 72 sb5.append(sb5cp, status); 73 assertSuccess("Appending again to sb5", status); 74 assertEqualsImpl(sb4, sb5); 75 } 76} 77 78void NumberStringBuilderTest::testInsertAppendCodePoint() { 79 static const UChar32 cases[] = { 80 0, 1, 60, 127, 128, 0x7fff, 0x8000, 0xffff, 0x10000, 0x1f000, 0x10ffff}; 81 UErrorCode status = U_ZERO_ERROR; 82 UnicodeString sb1; 83 NumberStringBuilder sb2; 84 for (UChar32 cas : cases) { 85 NumberStringBuilder sb3; 86 sb1.append(cas); 87 sb2.appendCodePoint(cas, UNUM_FIELD_COUNT, status); 88 assertSuccess("Appending to sb2", status); 89 sb3.appendCodePoint(cas, UNUM_FIELD_COUNT, status); 90 assertSuccess("Appending to sb3", status); 91 assertEqualsImpl(sb1, sb2); 92 assertEquals("Length of sb3", U16_LENGTH(cas), sb3.length()); 93 assertEquals("Code point count of sb3", 1, sb3.codePointCount()); 94 assertEquals( 95 "First code unit in sb3", 96 !U_IS_SUPPLEMENTARY(cas) ? (char16_t) cas : U16_LEAD(cas), 97 sb3.charAt(0)); 98 99 UnicodeString sb4; 100 NumberStringBuilder sb5; 101 sb4.append(u"xx"); 102 sb4.insert(2, cas); 103 sb5.append(u"xx", UNUM_FIELD_COUNT, status); 104 assertSuccess("Appending to sb5", status); 105 sb5.insertCodePoint(2, cas, UNUM_FIELD_COUNT, status); 106 assertSuccess("Inserting into sb5", status); 107 assertEqualsImpl(sb4, sb5); 108 } 109} 110 111void NumberStringBuilderTest::testCopy() { 112 UErrorCode status = U_ZERO_ERROR; 113 for (UnicodeString str : EXAMPLE_STRINGS) { 114 NumberStringBuilder sb1; 115 sb1.append(str, UNUM_FIELD_COUNT, status); 116 assertSuccess("Appending to sb1 first time", status); 117 NumberStringBuilder sb2(sb1); 118 assertTrue("Content should equal itself", sb1.contentEquals(sb2)); 119 120 sb1.append("12345", UNUM_FIELD_COUNT, status); 121 assertSuccess("Appending to sb1 second time", status); 122 assertFalse("Content should no longer equal itself", sb1.contentEquals(sb2)); 123 } 124} 125 126void NumberStringBuilderTest::testFields() { 127 UErrorCode status = U_ZERO_ERROR; 128 // Note: This is a C++11 for loop that calls the UnicodeString constructor on each iteration. 129 for (UnicodeString str : EXAMPLE_STRINGS) { 130 NumberStringBuilder sb; 131 sb.append(str, UNUM_FIELD_COUNT, status); 132 assertSuccess("Appending to sb", status); 133 sb.append(str, UNUM_CURRENCY_FIELD, status); 134 assertSuccess("Appending to sb", status); 135 assertEquals("Reference string copied twice", str.length() * 2, sb.length()); 136 for (int32_t i = 0; i < str.length(); i++) { 137 assertEquals("Null field first", UNUM_FIELD_COUNT, sb.fieldAt(i)); 138 assertEquals("Currency field second", UNUM_CURRENCY_FIELD, sb.fieldAt(i + str.length())); 139 } 140 141 // Very basic FieldPosition test. More robust tests happen in NumberFormatTest. 142 // Let NumberFormatTest also take care of FieldPositionIterator material. 143 FieldPosition fp(UNUM_CURRENCY_FIELD); 144 sb.populateFieldPosition(fp, 0, status); 145 assertSuccess("Populating the FieldPosition", status); 146 assertEquals("Currency start position", str.length(), fp.getBeginIndex()); 147 assertEquals("Currency end position", str.length() * 2, fp.getEndIndex()); 148 149 if (str.length() > 0) { 150 sb.insertCodePoint(2, 100, UNUM_INTEGER_FIELD, status); 151 assertSuccess("Inserting code point into sb", status); 152 assertEquals("New length", str.length() * 2 + 1, sb.length()); 153 assertEquals("Integer field", UNUM_INTEGER_FIELD, sb.fieldAt(2)); 154 } 155 156 NumberStringBuilder old(sb); 157 sb.append(old, status); 158 assertSuccess("Appending to myself", status); 159 int32_t numNull = 0; 160 int32_t numCurr = 0; 161 int32_t numInt = 0; 162 for (int32_t i = 0; i < sb.length(); i++) { 163 UNumberFormatFields field = sb.fieldAt(i); 164 assertEquals("Field should equal location in old", old.fieldAt(i % old.length()), field); 165 if (field == UNUM_FIELD_COUNT) { 166 numNull++; 167 } else if (field == UNUM_CURRENCY_FIELD) { 168 numCurr++; 169 } else if (field == UNUM_INTEGER_FIELD) { 170 numInt++; 171 } else { 172 errln("Encountered unknown field"); 173 } 174 } 175 assertEquals("Number of null fields", str.length() * 2, numNull); 176 assertEquals("Number of currency fields", numNull, numCurr); 177 assertEquals("Number of integer fields", str.length() > 0 ? 2 : 0, numInt); 178 } 179} 180 181void NumberStringBuilderTest::testUnlimitedCapacity() { 182 UErrorCode status = U_ZERO_ERROR; 183 NumberStringBuilder builder; 184 // The builder should never fail upon repeated appends. 185 for (int i = 0; i < 1000; i++) { 186 UnicodeString message("Iteration #"); 187 message += Int64ToUnicodeString(i); 188 assertEquals(message, builder.length(), i); 189 builder.appendCodePoint(u'x', UNUM_FIELD_COUNT, status); 190 assertSuccess(message, status); 191 assertEquals(message, builder.length(), i + 1); 192 } 193} 194 195void NumberStringBuilderTest::testCodePoints() { 196 UErrorCode status = U_ZERO_ERROR; 197 NumberStringBuilder nsb; 198 assertEquals("First is -1 on empty string", -1, nsb.getFirstCodePoint()); 199 assertEquals("Last is -1 on empty string", -1, nsb.getLastCodePoint()); 200 assertEquals("Length is 0 on empty string", 0, nsb.codePointCount()); 201 202 nsb.append(u"q", UNUM_FIELD_COUNT, status); 203 assertSuccess("Spot 1", status); 204 assertEquals("First is q", u'q', nsb.getFirstCodePoint()); 205 assertEquals("Last is q", u'q', nsb.getLastCodePoint()); 206 assertEquals("0th is q", u'q', nsb.codePointAt(0)); 207 assertEquals("Before 1st is q", u'q', nsb.codePointBefore(1)); 208 assertEquals("Code point count is 1", 1, nsb.codePointCount()); 209 210 // is two char16s 211 nsb.append(u"", UNUM_FIELD_COUNT, status); 212 assertSuccess("Spot 2" ,status); 213 assertEquals("First is still q", u'q', nsb.getFirstCodePoint()); 214 assertEquals("Last is space ship", 128640, nsb.getLastCodePoint()); 215 assertEquals("1st is space ship", 128640, nsb.codePointAt(1)); 216 assertEquals("Before 1st is q", u'q', nsb.codePointBefore(1)); 217 assertEquals("Before 3rd is space ship", 128640, nsb.codePointBefore(3)); 218 assertEquals("Code point count is 2", 2, nsb.codePointCount()); 219} 220 221void NumberStringBuilderTest::assertEqualsImpl(const UnicodeString &a, const NumberStringBuilder &b) { 222 // TODO: Why won't this compile without the IntlTest:: qualifier? 223 IntlTest::assertEquals("Lengths should be the same", a.length(), b.length()); 224 IntlTest::assertEquals("Code point counts should be the same", a.countChar32(), b.codePointCount()); 225 226 if (a.length() != b.length()) { 227 return; 228 } 229 230 for (int32_t i = 0; i < a.length(); i++) { 231 IntlTest::assertEquals( 232 UnicodeString(u"Char at position ") + Int64ToUnicodeString(i) + 233 UnicodeString(u" in string ") + a, a.charAt(i), b.charAt(i)); 234 } 235} 236 237#endif /* #if !UCONFIG_NO_FORMATTING */ 238