]> git.saurik.com Git - apple/icu.git/blob - icuSources/test/intltest/numbertest_stringbuilder.cpp
ICU-62107.0.1.tar.gz
[apple/icu.git] / icuSources / test / intltest / numbertest_stringbuilder.cpp
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
7
8 #include "putilimp.h"
9 #include "numbertest.h"
10
11 static 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
20 void 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(testSplice);
27 TESTCASE_AUTO(testInsertAppendCodePoint);
28 TESTCASE_AUTO(testCopy);
29 TESTCASE_AUTO(testFields);
30 TESTCASE_AUTO(testUnlimitedCapacity);
31 TESTCASE_AUTO(testCodePoints);
32 TESTCASE_AUTO_END;
33 }
34
35 void NumberStringBuilderTest::testInsertAppendUnicodeString() {
36 UErrorCode status = U_ZERO_ERROR;
37 UnicodeString sb1;
38 NumberStringBuilder sb2;
39 for (const char16_t* strPtr : EXAMPLE_STRINGS) {
40 UnicodeString str(strPtr);
41
42 NumberStringBuilder sb3;
43 sb1.append(str);
44 // Note: UNUM_FIELD_COUNT is like passing null in Java
45 sb2.append(str, UNUM_FIELD_COUNT, status);
46 assertSuccess("Appending to sb2", status);
47 sb3.append(str, UNUM_FIELD_COUNT, status);
48 assertSuccess("Appending to sb3", status);
49 assertEqualsImpl(sb1, sb2);
50 assertEqualsImpl(str, sb3);
51
52 UnicodeString sb4;
53 NumberStringBuilder sb5;
54 sb4.append(u"😇");
55 sb4.append(str);
56 sb4.append(u"xx");
57 sb5.append(u"😇xx", UNUM_FIELD_COUNT, status);
58 assertSuccess("Appending to sb5", status);
59 sb5.insert(2, str, UNUM_FIELD_COUNT, status);
60 assertSuccess("Inserting into sb5", status);
61 assertEqualsImpl(sb4, sb5);
62
63 int start = uprv_min(1, str.length());
64 int end = uprv_min(10, str.length());
65 sb4.insert(3, str, start, end - start); // UnicodeString uses length instead of end index
66 sb5.insert(3, str, start, end, UNUM_FIELD_COUNT, status);
67 assertSuccess("Inserting into sb5 again", status);
68 assertEqualsImpl(sb4, sb5);
69
70 UnicodeString sb4cp(sb4);
71 NumberStringBuilder sb5cp(sb5);
72 sb4.append(sb4cp);
73 sb5.append(sb5cp, status);
74 assertSuccess("Appending again to sb5", status);
75 assertEqualsImpl(sb4, sb5);
76 }
77 }
78
79 void NumberStringBuilderTest::testSplice() {
80 static const struct TestCase {
81 const char16_t* input;
82 const int32_t startThis;
83 const int32_t endThis;
84 } cases[] = {
85 { u"", 0, 0 },
86 { u"abc", 0, 0 },
87 { u"abc", 1, 1 },
88 { u"abc", 1, 2 },
89 { u"abc", 0, 2 },
90 { u"abc", 0, 3 },
91 { u"lorem ipsum dolor sit amet", 8, 8 },
92 { u"lorem ipsum dolor sit amet", 8, 11 }, // 3 chars, equal to replacement "xyz"
93 { u"lorem ipsum dolor sit amet", 8, 18 } }; // 10 chars, larger than several replacements
94
95 UErrorCode status = U_ZERO_ERROR;
96 UnicodeString sb1;
97 NumberStringBuilder sb2;
98 for (auto cas : cases) {
99 for (const char16_t* replacementPtr : EXAMPLE_STRINGS) {
100 UnicodeString replacement(replacementPtr);
101
102 // Test replacement with full string
103 sb1.remove();
104 sb1.append(cas.input);
105 sb1.replace(cas.startThis, cas.endThis - cas.startThis, replacement);
106 sb2.clear();
107 sb2.append(cas.input, UNUM_FIELD_COUNT, status);
108 sb2.splice(cas.startThis, cas.endThis, replacement, 0, replacement.length(), UNUM_FIELD_COUNT, status);
109 assertSuccess("Splicing into sb2 first time", status);
110 assertEqualsImpl(sb1, sb2);
111
112 // Test replacement with partial string
113 if (replacement.length() <= 2) {
114 continue;
115 }
116 sb1.remove();
117 sb1.append(cas.input);
118 sb1.replace(cas.startThis, cas.endThis - cas.startThis, UnicodeString(replacement, 1, 2));
119 sb2.clear();
120 sb2.append(cas.input, UNUM_FIELD_COUNT, status);
121 sb2.splice(cas.startThis, cas.endThis, replacement, 1, 3, UNUM_FIELD_COUNT, status);
122 assertSuccess("Splicing into sb2 second time", status);
123 assertEqualsImpl(sb1, sb2);
124 }
125 }
126 }
127
128 void NumberStringBuilderTest::testInsertAppendCodePoint() {
129 static const UChar32 cases[] = {
130 0, 1, 60, 127, 128, 0x7fff, 0x8000, 0xffff, 0x10000, 0x1f000, 0x10ffff};
131 UErrorCode status = U_ZERO_ERROR;
132 UnicodeString sb1;
133 NumberStringBuilder sb2;
134 for (UChar32 cas : cases) {
135 NumberStringBuilder sb3;
136 sb1.append(cas);
137 sb2.appendCodePoint(cas, UNUM_FIELD_COUNT, status);
138 assertSuccess("Appending to sb2", status);
139 sb3.appendCodePoint(cas, UNUM_FIELD_COUNT, status);
140 assertSuccess("Appending to sb3", status);
141 assertEqualsImpl(sb1, sb2);
142 assertEquals("Length of sb3", U16_LENGTH(cas), sb3.length());
143 assertEquals("Code point count of sb3", 1, sb3.codePointCount());
144 assertEquals(
145 "First code unit in sb3",
146 !U_IS_SUPPLEMENTARY(cas) ? (char16_t) cas : U16_LEAD(cas),
147 sb3.charAt(0));
148
149 UnicodeString sb4;
150 NumberStringBuilder sb5;
151 sb4.append(u"😇xx");
152 sb4.insert(2, cas);
153 sb5.append(u"😇xx", UNUM_FIELD_COUNT, status);
154 assertSuccess("Appending to sb5", status);
155 sb5.insertCodePoint(2, cas, UNUM_FIELD_COUNT, status);
156 assertSuccess("Inserting into sb5", status);
157 assertEqualsImpl(sb4, sb5);
158 }
159 }
160
161 void NumberStringBuilderTest::testCopy() {
162 UErrorCode status = U_ZERO_ERROR;
163 for (UnicodeString str : EXAMPLE_STRINGS) {
164 NumberStringBuilder sb1;
165 sb1.append(str, UNUM_FIELD_COUNT, status);
166 assertSuccess("Appending to sb1 first time", status);
167 NumberStringBuilder sb2(sb1);
168 assertTrue("Content should equal itself", sb1.contentEquals(sb2));
169
170 sb1.append("12345", UNUM_FIELD_COUNT, status);
171 assertSuccess("Appending to sb1 second time", status);
172 assertFalse("Content should no longer equal itself", sb1.contentEquals(sb2));
173 }
174 }
175
176 void NumberStringBuilderTest::testFields() {
177 UErrorCode status = U_ZERO_ERROR;
178 // Note: This is a C++11 for loop that calls the UnicodeString constructor on each iteration.
179 for (UnicodeString str : EXAMPLE_STRINGS) {
180 NumberStringBuilder sb;
181 sb.append(str, UNUM_FIELD_COUNT, status);
182 assertSuccess("Appending to sb", status);
183 sb.append(str, UNUM_CURRENCY_FIELD, status);
184 assertSuccess("Appending to sb", status);
185 assertEquals("Reference string copied twice", str.length() * 2, sb.length());
186 for (int32_t i = 0; i < str.length(); i++) {
187 assertEquals("Null field first", UNUM_FIELD_COUNT, sb.fieldAt(i));
188 assertEquals("Currency field second", UNUM_CURRENCY_FIELD, sb.fieldAt(i + str.length()));
189 }
190
191 // Very basic FieldPosition test. More robust tests happen in NumberFormatTest.
192 // Let NumberFormatTest also take care of FieldPositionIterator material.
193 FieldPosition fp(UNUM_CURRENCY_FIELD);
194 sb.nextFieldPosition(fp, status);
195 assertSuccess("Populating the FieldPosition", status);
196 assertEquals("Currency start position", str.length(), fp.getBeginIndex());
197 assertEquals("Currency end position", str.length() * 2, fp.getEndIndex());
198
199 if (str.length() > 0) {
200 sb.insertCodePoint(2, 100, UNUM_INTEGER_FIELD, status);
201 assertSuccess("Inserting code point into sb", status);
202 assertEquals("New length", str.length() * 2 + 1, sb.length());
203 assertEquals("Integer field", UNUM_INTEGER_FIELD, sb.fieldAt(2));
204 }
205
206 NumberStringBuilder old(sb);
207 sb.append(old, status);
208 assertSuccess("Appending to myself", status);
209 int32_t numNull = 0;
210 int32_t numCurr = 0;
211 int32_t numInt = 0;
212 for (int32_t i = 0; i < sb.length(); i++) {
213 UNumberFormatFields field = sb.fieldAt(i);
214 assertEquals("Field should equal location in old", old.fieldAt(i % old.length()), field);
215 if (field == UNUM_FIELD_COUNT) {
216 numNull++;
217 } else if (field == UNUM_CURRENCY_FIELD) {
218 numCurr++;
219 } else if (field == UNUM_INTEGER_FIELD) {
220 numInt++;
221 } else {
222 errln("Encountered unknown field");
223 }
224 }
225 assertEquals("Number of null fields", str.length() * 2, numNull);
226 assertEquals("Number of currency fields", numNull, numCurr);
227 assertEquals("Number of integer fields", str.length() > 0 ? 2 : 0, numInt);
228 }
229 }
230
231 void NumberStringBuilderTest::testUnlimitedCapacity() {
232 UErrorCode status = U_ZERO_ERROR;
233 NumberStringBuilder builder;
234 // The builder should never fail upon repeated appends.
235 for (int i = 0; i < 1000; i++) {
236 UnicodeString message("Iteration #");
237 message += Int64ToUnicodeString(i);
238 assertEquals(message, builder.length(), i);
239 builder.appendCodePoint(u'x', UNUM_FIELD_COUNT, status);
240 assertSuccess(message, status);
241 assertEquals(message, builder.length(), i + 1);
242 }
243 }
244
245 void NumberStringBuilderTest::testCodePoints() {
246 UErrorCode status = U_ZERO_ERROR;
247 NumberStringBuilder nsb;
248 assertEquals("First is -1 on empty string", -1, nsb.getFirstCodePoint());
249 assertEquals("Last is -1 on empty string", -1, nsb.getLastCodePoint());
250 assertEquals("Length is 0 on empty string", 0, nsb.codePointCount());
251
252 nsb.append(u"q", UNUM_FIELD_COUNT, status);
253 assertSuccess("Spot 1", status);
254 assertEquals("First is q", u'q', nsb.getFirstCodePoint());
255 assertEquals("Last is q", u'q', nsb.getLastCodePoint());
256 assertEquals("0th is q", u'q', nsb.codePointAt(0));
257 assertEquals("Before 1st is q", u'q', nsb.codePointBefore(1));
258 assertEquals("Code point count is 1", 1, nsb.codePointCount());
259
260 // 🚀 is two char16s
261 nsb.append(u"🚀", UNUM_FIELD_COUNT, status);
262 assertSuccess("Spot 2" ,status);
263 assertEquals("First is still q", u'q', nsb.getFirstCodePoint());
264 assertEquals("Last is space ship", 128640, nsb.getLastCodePoint());
265 assertEquals("1st is space ship", 128640, nsb.codePointAt(1));
266 assertEquals("Before 1st is q", u'q', nsb.codePointBefore(1));
267 assertEquals("Before 3rd is space ship", 128640, nsb.codePointBefore(3));
268 assertEquals("Code point count is 2", 2, nsb.codePointCount());
269 }
270
271 void NumberStringBuilderTest::assertEqualsImpl(const UnicodeString &a, const NumberStringBuilder &b) {
272 // TODO: Why won't this compile without the IntlTest:: qualifier?
273 IntlTest::assertEquals("Lengths should be the same", a.length(), b.length());
274 IntlTest::assertEquals("Code point counts should be the same", a.countChar32(), b.codePointCount());
275
276 if (a.length() != b.length()) {
277 return;
278 }
279
280 for (int32_t i = 0; i < a.length(); i++) {
281 IntlTest::assertEquals(
282 UnicodeString(u"Char at position ") + Int64ToUnicodeString(i) +
283 UnicodeString(u" in \"") + a + UnicodeString("\" versus \"") +
284 b.toUnicodeString() + UnicodeString("\""), a.charAt(i), b.charAt(i));
285 }
286 }
287
288 #endif /* #if !UCONFIG_NO_FORMATTING */