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