Rename StringBuilder::append(UChar32) to StringBuilder::appendCharacter(UChar32)...
[WebKit-https.git] / Tools / TestWebKitAPI / Tests / WTF / StringBuilder.cpp
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
3  * Copyright (C) 2013 Apple Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *     * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include "config.h"
33 #include "WTFStringUtilities.h"
34
35 namespace TestWebKitAPI {
36
37 static void expectBuilderContent(const String& expected, const StringBuilder& builder)
38 {
39     // Not using builder.toString() or builder.toStringPreserveCapacity() because they all
40     // change internal state of builder.
41     if (builder.is8Bit())
42         EXPECT_EQ(expected, String(builder.characters8(), builder.length()));
43     else
44         EXPECT_EQ(expected, String(builder.characters16(), builder.length()));
45 }
46
47 void expectEmpty(const StringBuilder& builder)
48 {
49     EXPECT_EQ(0U, builder.length());
50     EXPECT_TRUE(builder.isEmpty());
51     EXPECT_EQ(0, builder.characters8());
52 }
53
54 TEST(StringBuilderTest, DefaultConstructor)
55 {
56     StringBuilder builder;
57     expectEmpty(builder);
58 }
59
60 TEST(StringBuilderTest, Append)
61 {
62     StringBuilder builder;
63     builder.append(String("0123456789"));
64     expectBuilderContent("0123456789", builder);
65     builder.append("abcd");
66     expectBuilderContent("0123456789abcd", builder);
67     builder.appendCharacters("efgh", 3);
68     expectBuilderContent("0123456789abcdefg", builder);
69     builder.append("");
70     expectBuilderContent("0123456789abcdefg", builder);
71     builder.append('#');
72     expectBuilderContent("0123456789abcdefg#", builder);
73
74     builder.toString(); // Test after reifyString().
75     StringBuilder builder1;
76     builder.appendCharacters("", 0);
77     expectBuilderContent("0123456789abcdefg#", builder);
78     builder1.appendCharacters(builder.characters8(), builder.length());
79     builder1.append("XYZ");
80     builder.appendCharacters(builder1.characters8(), builder1.length());
81     expectBuilderContent("0123456789abcdefg#0123456789abcdefg#XYZ", builder);
82
83     StringBuilder builder2;
84     builder2.reserveCapacity(100);
85     builder2.append("xyz");
86     const LChar* characters = builder2.characters8();
87     builder2.append("0123456789");
88     ASSERT_EQ(characters, builder2.characters8());
89     builder2.toStringPreserveCapacity(); // Test after reifyString with buffer preserved.
90     builder2.append("abcd");
91     ASSERT_EQ(characters, builder2.characters8());
92
93     // Test appending UChar32 characters to StringBuilder.
94     StringBuilder builderForUChar32Append;
95     UChar32 frakturAChar = 0x1D504;
96     builderForUChar32Append.appendCharacter(frakturAChar); // The fraktur A is not in the BMP, so it's two UTF-16 code units long.
97     ASSERT_EQ(2U, builderForUChar32Append.length());
98     builderForUChar32Append.appendCharacter(static_cast<UChar32>('A'));
99     ASSERT_EQ(3U, builderForUChar32Append.length());
100     const UChar resultArray[] = { U16_LEAD(frakturAChar), U16_TRAIL(frakturAChar), 'A' };
101     expectBuilderContent(String(resultArray, WTF_ARRAY_LENGTH(resultArray)), builderForUChar32Append);
102     {
103         StringBuilder builder;
104         StringBuilder builder2;
105         UChar32 frakturAChar = 0x1D504;
106         const UChar data[] = { U16_LEAD(frakturAChar), U16_TRAIL(frakturAChar) };
107         builder2.appendCharacters(data, 2);
108         ASSERT_EQ(2U, builder2.length());
109         String result2 = builder2.toString();
110         ASSERT_EQ(2U, result2.length());
111         builder.append(builder2);
112         builder.appendCharacters(data, 2);
113         ASSERT_EQ(4U, builder.length());
114         const UChar resultArray[] = { U16_LEAD(frakturAChar), U16_TRAIL(frakturAChar), U16_LEAD(frakturAChar), U16_TRAIL(frakturAChar) };
115         expectBuilderContent(String(resultArray, WTF_ARRAY_LENGTH(resultArray)), builder);
116     }
117 }
118
119 TEST(StringBuilderTest, FlexibleAppend)
120 {
121     {
122         StringBuilder builder;
123         builder.flexibleAppend(String("0123456789"));
124         expectBuilderContent("0123456789", builder);
125         builder.flexibleAppend("abcd");
126         expectBuilderContent("0123456789abcd", builder);
127         builder.flexibleAppend('e');
128         expectBuilderContent("0123456789abcde", builder);
129         builder.flexibleAppend("");
130         expectBuilderContent("0123456789abcde", builder);
131     }
132
133     {
134         StringBuilder builder;
135         builder.flexibleAppend(String("0123456789"), "abcd", 'e', "");
136         expectBuilderContent("0123456789abcde", builder);
137         builder.flexibleAppend(String("A"), "B", 'C', "");
138         expectBuilderContent("0123456789abcdeABC", builder);
139     }
140 }
141
142 TEST(StringBuilderTest, ToString)
143 {
144     StringBuilder builder;
145     builder.append("0123456789");
146     String string = builder.toString();
147     ASSERT_EQ(String("0123456789"), string);
148     ASSERT_EQ(string.impl(), builder.toString().impl());
149
150     // Changing the StringBuilder should not affect the original result of toString().
151     builder.append("abcdefghijklmnopqrstuvwxyz");
152     ASSERT_EQ(String("0123456789"), string);
153
154     // Changing the StringBuilder should not affect the original result of toString() in case the capacity is not changed.
155     builder.reserveCapacity(200);
156     string = builder.toString();
157     ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyz"), string);
158     builder.append("ABC");
159     ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyz"), string);
160
161     // Changing the original result of toString() should not affect the content of the StringBuilder.
162     String string1 = builder.toString();
163     ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABC"), string1);
164     string1.append("DEF");
165     ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABC"), builder.toString());
166     ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABCDEF"), string1);
167
168     // Resizing the StringBuilder should not affect the original result of toString().
169     string1 = builder.toString();
170     builder.resize(10);
171     builder.append("###");
172     ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABC"), string1);
173 }
174
175 TEST(StringBuilderTest, ToStringPreserveCapacity)
176 {
177     StringBuilder builder;
178     builder.append("0123456789");
179     unsigned capacity = builder.capacity();
180     String string = builder.toStringPreserveCapacity();
181     ASSERT_EQ(capacity, builder.capacity());
182     ASSERT_EQ(String("0123456789"), string);
183     ASSERT_EQ(string.impl(), builder.toStringPreserveCapacity().impl());
184     ASSERT_EQ(string.characters8(), builder.characters8());
185
186     // Changing the StringBuilder should not affect the original result of toStringPreserveCapacity().
187     builder.append("abcdefghijklmnopqrstuvwxyz");
188     ASSERT_EQ(String("0123456789"), string);
189
190     // Changing the StringBuilder should not affect the original result of toStringPreserveCapacity() in case the capacity is not changed.
191     builder.reserveCapacity(200);
192     capacity = builder.capacity();
193     string = builder.toStringPreserveCapacity();
194     ASSERT_EQ(capacity, builder.capacity());
195     ASSERT_EQ(string.characters8(), builder.characters8());
196     ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyz"), string);
197     builder.append("ABC");
198     ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyz"), string);
199
200     // Changing the original result of toStringPreserveCapacity() should not affect the content of the StringBuilder.
201     capacity = builder.capacity();
202     String string1 = builder.toStringPreserveCapacity();
203     ASSERT_EQ(capacity, builder.capacity());
204     ASSERT_EQ(string1.characters8(), builder.characters8());
205     ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABC"), string1);
206     string1.append("DEF");
207     ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABC"), builder.toStringPreserveCapacity());
208     ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABCDEF"), string1);
209
210     // Resizing the StringBuilder should not affect the original result of toStringPreserveCapacity().
211     capacity = builder.capacity();
212     string1 = builder.toStringPreserveCapacity();
213     ASSERT_EQ(capacity, builder.capacity());
214     ASSERT_EQ(string.characters8(), builder.characters8());
215     builder.resize(10);
216     builder.append("###");
217     ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABC"), string1);
218 }
219
220 TEST(StringBuilderTest, Clear)
221 {
222     StringBuilder builder;
223     builder.append("0123456789");
224     builder.clear();
225     expectEmpty(builder);
226 }
227
228 TEST(StringBuilderTest, Array)
229 {
230     StringBuilder builder;
231     builder.append("0123456789");
232     EXPECT_EQ('0', static_cast<char>(builder[0]));
233     EXPECT_EQ('9', static_cast<char>(builder[9]));
234     builder.toString(); // Test after reifyString().
235     EXPECT_EQ('0', static_cast<char>(builder[0]));
236     EXPECT_EQ('9', static_cast<char>(builder[9]));
237 }
238
239 TEST(StringBuilderTest, Resize)
240 {
241     StringBuilder builder;
242     builder.append("0123456789");
243     builder.resize(10);
244     EXPECT_EQ(10U, builder.length());
245     expectBuilderContent("0123456789", builder);
246     builder.resize(8);
247     EXPECT_EQ(8U, builder.length());
248     expectBuilderContent("01234567", builder);
249
250     builder.toString();
251     builder.resize(7);
252     EXPECT_EQ(7U, builder.length());
253     expectBuilderContent("0123456", builder);
254     builder.resize(0);
255     expectEmpty(builder);
256 }
257
258 TEST(StringBuilderTest, Equal)
259 {
260     StringBuilder builder1;
261     StringBuilder builder2;
262     ASSERT_TRUE(builder1 == builder2);
263     ASSERT_TRUE(equal(builder1, static_cast<LChar*>(0), 0));
264     ASSERT_TRUE(builder1 == String());
265     ASSERT_TRUE(String() == builder1);
266     ASSERT_TRUE(builder1 != String("abc"));
267
268     builder1.append("123");
269     builder1.reserveCapacity(32);
270     builder2.append("123");
271     builder1.reserveCapacity(64);
272     ASSERT_TRUE(builder1 == builder2);
273     ASSERT_TRUE(builder1 == String("123"));
274     ASSERT_TRUE(String("123") == builder1);
275
276     builder2.append("456");
277     ASSERT_TRUE(builder1 != builder2);
278     ASSERT_TRUE(builder2 != builder1);
279     ASSERT_TRUE(String("123") != builder2);
280     ASSERT_TRUE(builder2 != String("123"));
281     builder2.toString(); // Test after reifyString().
282     ASSERT_TRUE(builder1 != builder2);
283
284     builder2.resize(3);
285     ASSERT_TRUE(builder1 == builder2);
286
287     builder1.toString(); // Test after reifyString().
288     ASSERT_TRUE(builder1 == builder2);
289 }
290
291 TEST(StringBuilderTest, CanShrink)
292 {
293     StringBuilder builder;
294     builder.reserveCapacity(256);
295     ASSERT_TRUE(builder.canShrink());
296     for (int i = 0; i < 256; i++)
297         builder.append('x');
298     ASSERT_EQ(builder.length(), builder.capacity());
299     ASSERT_FALSE(builder.canShrink());
300 }
301
302 TEST(StringBuilderTest, ToAtomString)
303 {
304     StringBuilder builder;
305     builder.append("123");
306     AtomString atomString = builder.toAtomString();
307     ASSERT_EQ(String("123"), atomString);
308
309     builder.reserveCapacity(256);
310     ASSERT_TRUE(builder.canShrink());
311     for (int i = builder.length(); i < 128; i++)
312         builder.append('x');
313     AtomString atomString1 = builder.toAtomString();
314     ASSERT_EQ(128u, atomString1.length());
315     ASSERT_EQ('x', atomString1[127]);
316
317     // Later change of builder should not affect the atomic string.
318     for (int i = builder.length(); i < 256; i++)
319         builder.append('x');
320     ASSERT_EQ(128u, atomString1.length());
321
322     ASSERT_FALSE(builder.canShrink());
323     String string = builder.toString();
324     AtomString atomString2 = builder.toAtomString();
325     // They should share the same StringImpl.
326     ASSERT_EQ(atomString2.impl(), string.impl());
327 }
328
329 TEST(StringBuilderTest, ToAtomStringOnEmpty)
330 {
331     { // Default constructed.
332         StringBuilder builder;
333         AtomString atomString = builder.toAtomString();
334         ASSERT_EQ(emptyAtom(), atomString);
335     }
336     { // With capacity.
337         StringBuilder builder;
338         builder.reserveCapacity(64);
339         AtomString atomString = builder.toAtomString();
340         ASSERT_EQ(emptyAtom(), atomString);
341     }
342     { // AtomString constructed from a null string.
343         StringBuilder builder;
344         builder.append(String());
345         AtomString atomString = builder.toAtomString();
346         ASSERT_EQ(emptyAtom(), atomString);
347     }
348     { // AtomString constructed from an empty string.
349         StringBuilder builder;
350         builder.append(emptyString());
351         AtomString atomString = builder.toAtomString();
352         ASSERT_EQ(emptyAtom(), atomString);
353     }
354     { // AtomString constructed from an empty StringBuilder.
355         StringBuilder builder;
356         StringBuilder emptyBuilder;
357         builder.append(emptyBuilder);
358         AtomString atomString = builder.toAtomString();
359         ASSERT_EQ(emptyAtom(), atomString);
360     }
361     { // AtomString constructed from an empty char* string.
362         StringBuilder builder;
363         builder.appendCharacters("", 0);
364         AtomString atomString = builder.toAtomString();
365         ASSERT_EQ(emptyAtom(), atomString);
366     }
367     { // Cleared StringBuilder.
368         StringBuilder builder;
369         builder.appendLiteral("WebKit");
370         builder.clear();
371         AtomString atomString = builder.toAtomString();
372         ASSERT_EQ(emptyAtom(), atomString);
373     }
374 }
375
376 } // namespace