[WTF] Clean up StringStatics.cpp by using LazyNeverDestroyed<> for Atoms
[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.append("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.append("", 0);
77     expectBuilderContent("0123456789abcdefg#", builder);
78     builder1.append(builder.characters8(), builder.length());
79     builder1.append("XYZ");
80     builder.append(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.append(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.append(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
104 TEST(StringBuilderTest, ToString)
105 {
106     StringBuilder builder;
107     builder.append("0123456789");
108     String string = builder.toString();
109     ASSERT_EQ(String("0123456789"), string);
110     ASSERT_EQ(string.impl(), builder.toString().impl());
111
112     // Changing the StringBuilder should not affect the original result of toString().
113     builder.append("abcdefghijklmnopqrstuvwxyz");
114     ASSERT_EQ(String("0123456789"), string);
115
116     // Changing the StringBuilder should not affect the original result of toString() in case the capacity is not changed.
117     builder.reserveCapacity(200);
118     string = builder.toString();
119     ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyz"), string);
120     builder.append("ABC");
121     ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyz"), string);
122
123     // Changing the original result of toString() should not affect the content of the StringBuilder.
124     String string1 = builder.toString();
125     ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABC"), string1);
126     string1.append("DEF");
127     ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABC"), builder.toString());
128     ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABCDEF"), string1);
129
130     // Resizing the StringBuilder should not affect the original result of toString().
131     string1 = builder.toString();
132     builder.resize(10);
133     builder.append("###");
134     ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABC"), string1);
135 }
136
137 TEST(StringBuilderTest, ToStringPreserveCapacity)
138 {
139     StringBuilder builder;
140     builder.append("0123456789");
141     unsigned capacity = builder.capacity();
142     String string = builder.toStringPreserveCapacity();
143     ASSERT_EQ(capacity, builder.capacity());
144     ASSERT_EQ(String("0123456789"), string);
145     ASSERT_EQ(string.impl(), builder.toStringPreserveCapacity().impl());
146     ASSERT_EQ(string.characters8(), builder.characters8());
147
148     // Changing the StringBuilder should not affect the original result of toStringPreserveCapacity().
149     builder.append("abcdefghijklmnopqrstuvwxyz");
150     ASSERT_EQ(String("0123456789"), string);
151
152     // Changing the StringBuilder should not affect the original result of toStringPreserveCapacity() in case the capacity is not changed.
153     builder.reserveCapacity(200);
154     capacity = builder.capacity();
155     string = builder.toStringPreserveCapacity();
156     ASSERT_EQ(capacity, builder.capacity());
157     ASSERT_EQ(string.characters8(), builder.characters8());
158     ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyz"), string);
159     builder.append("ABC");
160     ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyz"), string);
161
162     // Changing the original result of toStringPreserveCapacity() should not affect the content of the StringBuilder.
163     capacity = builder.capacity();
164     String string1 = builder.toStringPreserveCapacity();
165     ASSERT_EQ(capacity, builder.capacity());
166     ASSERT_EQ(string1.characters8(), builder.characters8());
167     ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABC"), string1);
168     string1.append("DEF");
169     ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABC"), builder.toStringPreserveCapacity());
170     ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABCDEF"), string1);
171
172     // Resizing the StringBuilder should not affect the original result of toStringPreserveCapacity().
173     capacity = builder.capacity();
174     string1 = builder.toStringPreserveCapacity();
175     ASSERT_EQ(capacity, builder.capacity());
176     ASSERT_EQ(string.characters8(), builder.characters8());
177     builder.resize(10);
178     builder.append("###");
179     ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABC"), string1);
180 }
181
182 TEST(StringBuilderTest, Clear)
183 {
184     StringBuilder builder;
185     builder.append("0123456789");
186     builder.clear();
187     expectEmpty(builder);
188 }
189
190 TEST(StringBuilderTest, Array)
191 {
192     StringBuilder builder;
193     builder.append("0123456789");
194     EXPECT_EQ('0', static_cast<char>(builder[0]));
195     EXPECT_EQ('9', static_cast<char>(builder[9]));
196     builder.toString(); // Test after reifyString().
197     EXPECT_EQ('0', static_cast<char>(builder[0]));
198     EXPECT_EQ('9', static_cast<char>(builder[9]));
199 }
200
201 TEST(StringBuilderTest, Resize)
202 {
203     StringBuilder builder;
204     builder.append("0123456789");
205     builder.resize(10);
206     EXPECT_EQ(10U, builder.length());
207     expectBuilderContent("0123456789", builder);
208     builder.resize(8);
209     EXPECT_EQ(8U, builder.length());
210     expectBuilderContent("01234567", builder);
211
212     builder.toString();
213     builder.resize(7);
214     EXPECT_EQ(7U, builder.length());
215     expectBuilderContent("0123456", builder);
216     builder.resize(0);
217     expectEmpty(builder);
218 }
219
220 TEST(StringBuilderTest, Equal)
221 {
222     StringBuilder builder1;
223     StringBuilder builder2;
224     ASSERT_TRUE(builder1 == builder2);
225     ASSERT_TRUE(equal(builder1, static_cast<LChar*>(0), 0));
226     ASSERT_TRUE(builder1 == String());
227     ASSERT_TRUE(String() == builder1);
228     ASSERT_TRUE(builder1 != String("abc"));
229
230     builder1.append("123");
231     builder1.reserveCapacity(32);
232     builder2.append("123");
233     builder1.reserveCapacity(64);
234     ASSERT_TRUE(builder1 == builder2);
235     ASSERT_TRUE(builder1 == String("123"));
236     ASSERT_TRUE(String("123") == builder1);
237
238     builder2.append("456");
239     ASSERT_TRUE(builder1 != builder2);
240     ASSERT_TRUE(builder2 != builder1);
241     ASSERT_TRUE(String("123") != builder2);
242     ASSERT_TRUE(builder2 != String("123"));
243     builder2.toString(); // Test after reifyString().
244     ASSERT_TRUE(builder1 != builder2);
245
246     builder2.resize(3);
247     ASSERT_TRUE(builder1 == builder2);
248
249     builder1.toString(); // Test after reifyString().
250     ASSERT_TRUE(builder1 == builder2);
251 }
252
253 TEST(StringBuilderTest, CanShrink)
254 {
255     StringBuilder builder;
256     builder.reserveCapacity(256);
257     ASSERT_TRUE(builder.canShrink());
258     for (int i = 0; i < 256; i++)
259         builder.append('x');
260     ASSERT_EQ(builder.length(), builder.capacity());
261     ASSERT_FALSE(builder.canShrink());
262 }
263
264 TEST(StringBuilderTest, ToAtomicString)
265 {
266     StringBuilder builder;
267     builder.append("123");
268     AtomicString atomicString = builder.toAtomicString();
269     ASSERT_EQ(String("123"), atomicString);
270
271     builder.reserveCapacity(256);
272     ASSERT_TRUE(builder.canShrink());
273     for (int i = builder.length(); i < 128; i++)
274         builder.append('x');
275     AtomicString atomicString1 = builder.toAtomicString();
276     ASSERT_EQ(128u, atomicString1.length());
277     ASSERT_EQ('x', atomicString1[127]);
278
279     // Later change of builder should not affect the atomic string.
280     for (int i = builder.length(); i < 256; i++)
281         builder.append('x');
282     ASSERT_EQ(128u, atomicString1.length());
283
284     ASSERT_FALSE(builder.canShrink());
285     String string = builder.toString();
286     AtomicString atomicString2 = builder.toAtomicString();
287     // They should share the same StringImpl.
288     ASSERT_EQ(atomicString2.impl(), string.impl());
289 }
290
291 TEST(StringBuilderTest, ToAtomicStringOnEmpty)
292 {
293     { // Default constructed.
294         StringBuilder builder;
295         AtomicString atomicString = builder.toAtomicString();
296         ASSERT_EQ(emptyAtom(), atomicString);
297     }
298     { // With capacity.
299         StringBuilder builder;
300         builder.reserveCapacity(64);
301         AtomicString atomicString = builder.toAtomicString();
302         ASSERT_EQ(emptyAtom(), atomicString);
303     }
304     { // AtomicString constructed from a null string.
305         StringBuilder builder;
306         builder.append(String());
307         AtomicString atomicString = builder.toAtomicString();
308         ASSERT_EQ(emptyAtom(), atomicString);
309     }
310     { // AtomicString constructed from an empty string.
311         StringBuilder builder;
312         builder.append(emptyString());
313         AtomicString atomicString = builder.toAtomicString();
314         ASSERT_EQ(emptyAtom(), atomicString);
315     }
316     { // AtomicString constructed from an empty StringBuilder.
317         StringBuilder builder;
318         StringBuilder emptyBuilder;
319         builder.append(emptyBuilder);
320         AtomicString atomicString = builder.toAtomicString();
321         ASSERT_EQ(emptyAtom(), atomicString);
322     }
323     { // AtomicString constructed from an empty char* string.
324         StringBuilder builder;
325         builder.append("", 0);
326         AtomicString atomicString = builder.toAtomicString();
327         ASSERT_EQ(emptyAtom(), atomicString);
328     }
329     { // Cleared StringBuilder.
330         StringBuilder builder;
331         builder.appendLiteral("WebKit");
332         builder.clear();
333         AtomicString atomicString = builder.toAtomicString();
334         ASSERT_EQ(emptyAtom(), atomicString);
335     }
336 }
337
338 } // namespace