• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)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 
testInsertAppendUnicodeString()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 
testSplice()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 
testInsertAppendCodePoint()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 
testCopy()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 
testFields()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 
testUnlimitedCapacity()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 
testCodePoints()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 
assertEqualsImpl(const UnicodeString & a,const NumberStringBuilder & b)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 */
289