1 // © 2017 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 #include "unicode/utypes.h"
6 #if !UCONFIG_NO_FORMATTING
9 #include "numbertest.h"
11 static const char16_t *EXAMPLE_STRINGS
[] = {
14 u
"The quick brown fox jumps over the lazy dog",
17 u
"with combining characters like 🇦🇧🇨🇩",
18 u
"A very very very very very very very very very very long string to force heap"};
20 void NumberStringBuilderTest::runIndexedTest(int32_t index
, UBool exec
, const char *&name
, char *) {
22 logln("TestSuite NumberStringBuilderTest: ");
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
);
35 void NumberStringBuilderTest::testInsertAppendUnicodeString() {
36 UErrorCode status
= U_ZERO_ERROR
;
38 NumberStringBuilder sb2
;
39 for (const char16_t* strPtr
: EXAMPLE_STRINGS
) {
40 UnicodeString
str(strPtr
);
42 NumberStringBuilder sb3
;
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
);
53 NumberStringBuilder sb5
;
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
);
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
);
70 UnicodeString
sb4cp(sb4
);
71 NumberStringBuilder
sb5cp(sb5
);
73 sb5
.append(sb5cp
, status
);
74 assertSuccess("Appending again to sb5", status
);
75 assertEqualsImpl(sb4
, sb5
);
79 void NumberStringBuilderTest::testSplice() {
80 static const struct TestCase
{
81 const char16_t* input
;
82 const int32_t startThis
;
83 const int32_t endThis
;
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
95 UErrorCode status
= U_ZERO_ERROR
;
97 NumberStringBuilder sb2
;
98 for (auto cas
: cases
) {
99 for (const char16_t* replacementPtr
: EXAMPLE_STRINGS
) {
100 UnicodeString
replacement(replacementPtr
);
102 // Test replacement with full string
104 sb1
.append(cas
.input
);
105 sb1
.replace(cas
.startThis
, cas
.endThis
- cas
.startThis
, replacement
);
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
);
112 // Test replacement with partial string
113 if (replacement
.length() <= 2) {
117 sb1
.append(cas
.input
);
118 sb1
.replace(cas
.startThis
, cas
.endThis
- cas
.startThis
, UnicodeString(replacement
, 1, 2));
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
);
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
;
133 NumberStringBuilder sb2
;
134 for (UChar32 cas
: cases
) {
135 NumberStringBuilder sb3
;
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());
145 "First code unit in sb3",
146 !U_IS_SUPPLEMENTARY(cas
) ? (char16_t) cas
: U16_LEAD(cas
),
150 NumberStringBuilder sb5
;
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
);
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
));
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
));
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()));
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());
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));
206 NumberStringBuilder
old(sb
);
207 sb
.append(old
, status
);
208 assertSuccess("Appending to myself", status
);
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
) {
217 } else if (field
== UNUM_CURRENCY_FIELD
) {
219 } else if (field
== UNUM_INTEGER_FIELD
) {
222 errln("Encountered unknown field");
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
);
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);
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());
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());
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());
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());
276 if (a
.length() != b
.length()) {
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
));
288 #endif /* #if !UCONFIG_NO_FORMATTING */