| OLD | NEW |
| (Empty) |
| 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 "wtf/text/StringBuilder.h" | |
| 33 | |
| 34 #include "testing/gtest/include/gtest/gtest.h" | |
| 35 #include "wtf/Assertions.h" | |
| 36 #include "wtf/text/CString.h" | |
| 37 #include "wtf/text/CharacterNames.h" | |
| 38 #include "wtf/text/WTFString.h" | |
| 39 | |
| 40 namespace WTF { | |
| 41 | |
| 42 namespace { | |
| 43 | |
| 44 void expectBuilderContent(const String& expected, | |
| 45 const StringBuilder& builder) { | |
| 46 // Not using builder.toString() because it changes internal state of builder. | |
| 47 if (builder.is8Bit()) | |
| 48 EXPECT_EQ(expected, String(builder.characters8(), builder.length())); | |
| 49 else | |
| 50 EXPECT_EQ(expected, String(builder.characters16(), builder.length())); | |
| 51 } | |
| 52 | |
| 53 void expectEmpty(const StringBuilder& builder) { | |
| 54 EXPECT_EQ(0U, builder.length()); | |
| 55 EXPECT_TRUE(builder.isEmpty()); | |
| 56 EXPECT_EQ(0, builder.characters8()); | |
| 57 } | |
| 58 | |
| 59 } // namespace | |
| 60 | |
| 61 TEST(StringBuilderTest, DefaultConstructor) { | |
| 62 StringBuilder builder; | |
| 63 expectEmpty(builder); | |
| 64 } | |
| 65 | |
| 66 TEST(StringBuilderTest, Append) { | |
| 67 StringBuilder builder; | |
| 68 builder.append(String("0123456789")); | |
| 69 expectBuilderContent("0123456789", builder); | |
| 70 builder.append("abcd"); | |
| 71 expectBuilderContent("0123456789abcd", builder); | |
| 72 builder.append("efgh", 3); | |
| 73 expectBuilderContent("0123456789abcdefg", builder); | |
| 74 builder.append(""); | |
| 75 expectBuilderContent("0123456789abcdefg", builder); | |
| 76 builder.append('#'); | |
| 77 expectBuilderContent("0123456789abcdefg#", builder); | |
| 78 | |
| 79 builder.toString(); // Test after reifyString(). | |
| 80 StringBuilder builder1; | |
| 81 builder.append("", 0); | |
| 82 expectBuilderContent("0123456789abcdefg#", builder); | |
| 83 builder1.append(builder.characters8(), builder.length()); | |
| 84 builder1.append("XYZ"); | |
| 85 builder.append(builder1.characters8(), builder1.length()); | |
| 86 expectBuilderContent("0123456789abcdefg#0123456789abcdefg#XYZ", builder); | |
| 87 | |
| 88 StringBuilder builder2; | |
| 89 builder2.reserveCapacity(100); | |
| 90 builder2.append("xyz"); | |
| 91 const LChar* characters = builder2.characters8(); | |
| 92 builder2.append("0123456789"); | |
| 93 EXPECT_EQ(characters, builder2.characters8()); | |
| 94 | |
| 95 StringBuilder builder3; | |
| 96 builder3.append("xyz", 1, 2); | |
| 97 expectBuilderContent("yz", builder3); | |
| 98 | |
| 99 StringBuilder builder4; | |
| 100 builder4.append("abc", 5, 3); | |
| 101 expectEmpty(builder4); | |
| 102 | |
| 103 StringBuilder builder5; | |
| 104 builder5.append(StringView(StringView("def"), 1, 1)); | |
| 105 expectBuilderContent("e", builder5); | |
| 106 | |
| 107 // append() has special code paths for String backed StringView instead of | |
| 108 // just char* backed ones. | |
| 109 StringBuilder builder6; | |
| 110 builder6.append(String("ghi"), 1, 2); | |
| 111 expectBuilderContent("hi", builder6); | |
| 112 | |
| 113 // Test appending UChar32 characters to StringBuilder. | |
| 114 StringBuilder builderForUChar32Append; | |
| 115 UChar32 frakturAChar = 0x1D504; | |
| 116 // The fraktur A is not in the BMP, so it's two UTF-16 code units long. | |
| 117 builderForUChar32Append.append(frakturAChar); | |
| 118 EXPECT_FALSE(builderForUChar32Append.is8Bit()); | |
| 119 EXPECT_EQ(2U, builderForUChar32Append.length()); | |
| 120 builderForUChar32Append.append(static_cast<UChar32>('A')); | |
| 121 EXPECT_EQ(3U, builderForUChar32Append.length()); | |
| 122 const UChar resultArray[] = {U16_LEAD(frakturAChar), U16_TRAIL(frakturAChar), | |
| 123 'A'}; | |
| 124 expectBuilderContent(String(resultArray, WTF_ARRAY_LENGTH(resultArray)), | |
| 125 builderForUChar32Append); | |
| 126 } | |
| 127 | |
| 128 TEST(StringBuilderTest, AppendSharingImpl) { | |
| 129 String string("abc"); | |
| 130 StringBuilder builder1; | |
| 131 builder1.append(string); | |
| 132 EXPECT_EQ(string.impl(), builder1.toString().impl()); | |
| 133 EXPECT_EQ(string.impl(), builder1.toAtomicString().impl()); | |
| 134 | |
| 135 StringBuilder builder2; | |
| 136 builder2.append(string, 0, string.length()); | |
| 137 EXPECT_EQ(string.impl(), builder2.toString().impl()); | |
| 138 EXPECT_EQ(string.impl(), builder2.toAtomicString().impl()); | |
| 139 } | |
| 140 | |
| 141 TEST(StringBuilderTest, ToString) { | |
| 142 StringBuilder builder; | |
| 143 builder.append("0123456789"); | |
| 144 String string = builder.toString(); | |
| 145 EXPECT_EQ(String("0123456789"), string); | |
| 146 EXPECT_EQ(string.impl(), builder.toString().impl()); | |
| 147 | |
| 148 // Changing the StringBuilder should not affect the original result of | |
| 149 // toString(). | |
| 150 builder.append("abcdefghijklmnopqrstuvwxyz"); | |
| 151 EXPECT_EQ(String("0123456789"), string); | |
| 152 | |
| 153 // Changing the StringBuilder should not affect the original result of | |
| 154 // toString() in case the capacity is not changed. | |
| 155 builder.reserveCapacity(200); | |
| 156 string = builder.toString(); | |
| 157 EXPECT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyz"), string); | |
| 158 builder.append("ABC"); | |
| 159 EXPECT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyz"), string); | |
| 160 | |
| 161 // Changing the original result of toString() should not affect the content of | |
| 162 // the StringBuilder. | |
| 163 String string1 = builder.toString(); | |
| 164 EXPECT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABC"), string1); | |
| 165 string1.append("DEF"); | |
| 166 EXPECT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABC"), | |
| 167 builder.toString()); | |
| 168 EXPECT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABCDEF"), string1); | |
| 169 | |
| 170 // Resizing the StringBuilder should not affect the original result of | |
| 171 // toString(). | |
| 172 string1 = builder.toString(); | |
| 173 builder.resize(10); | |
| 174 builder.append("###"); | |
| 175 EXPECT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABC"), string1); | |
| 176 } | |
| 177 | |
| 178 TEST(StringBuilderTest, Clear) { | |
| 179 StringBuilder builder; | |
| 180 builder.append("0123456789"); | |
| 181 builder.clear(); | |
| 182 expectEmpty(builder); | |
| 183 } | |
| 184 | |
| 185 TEST(StringBuilderTest, Array) { | |
| 186 StringBuilder builder; | |
| 187 builder.append("0123456789"); | |
| 188 EXPECT_EQ('0', static_cast<char>(builder[0])); | |
| 189 EXPECT_EQ('9', static_cast<char>(builder[9])); | |
| 190 builder.toString(); // Test after reifyString(). | |
| 191 EXPECT_EQ('0', static_cast<char>(builder[0])); | |
| 192 EXPECT_EQ('9', static_cast<char>(builder[9])); | |
| 193 } | |
| 194 | |
| 195 TEST(StringBuilderTest, Resize) { | |
| 196 StringBuilder builder; | |
| 197 builder.append("0123456789"); | |
| 198 builder.resize(10); | |
| 199 EXPECT_EQ(10U, builder.length()); | |
| 200 expectBuilderContent("0123456789", builder); | |
| 201 builder.resize(8); | |
| 202 EXPECT_EQ(8U, builder.length()); | |
| 203 expectBuilderContent("01234567", builder); | |
| 204 | |
| 205 builder.toString(); | |
| 206 builder.resize(7); | |
| 207 EXPECT_EQ(7U, builder.length()); | |
| 208 expectBuilderContent("0123456", builder); | |
| 209 builder.resize(0); | |
| 210 expectEmpty(builder); | |
| 211 } | |
| 212 | |
| 213 TEST(StringBuilderTest, Equal) { | |
| 214 StringBuilder builder1; | |
| 215 StringBuilder builder2; | |
| 216 EXPECT_TRUE(builder1 == builder2); | |
| 217 EXPECT_TRUE(equal(builder1, static_cast<LChar*>(0), 0)); | |
| 218 EXPECT_TRUE(builder1 == String()); | |
| 219 EXPECT_TRUE(String() == builder1); | |
| 220 EXPECT_TRUE(builder1 != String("abc")); | |
| 221 | |
| 222 builder1.append("123"); | |
| 223 builder1.reserveCapacity(32); | |
| 224 builder2.append("123"); | |
| 225 builder1.reserveCapacity(64); | |
| 226 EXPECT_TRUE(builder1 == builder2); | |
| 227 EXPECT_TRUE(builder1 == String("123")); | |
| 228 EXPECT_TRUE(String("123") == builder1); | |
| 229 | |
| 230 builder2.append("456"); | |
| 231 EXPECT_TRUE(builder1 != builder2); | |
| 232 EXPECT_TRUE(builder2 != builder1); | |
| 233 EXPECT_TRUE(String("123") != builder2); | |
| 234 EXPECT_TRUE(builder2 != String("123")); | |
| 235 builder2.toString(); // Test after reifyString(). | |
| 236 EXPECT_TRUE(builder1 != builder2); | |
| 237 | |
| 238 builder2.resize(3); | |
| 239 EXPECT_TRUE(builder1 == builder2); | |
| 240 | |
| 241 builder1.toString(); // Test after reifyString(). | |
| 242 EXPECT_TRUE(builder1 == builder2); | |
| 243 } | |
| 244 | |
| 245 TEST(StringBuilderTest, ToAtomicString) { | |
| 246 StringBuilder builder; | |
| 247 builder.append("123"); | |
| 248 AtomicString atomicString = builder.toAtomicString(); | |
| 249 EXPECT_EQ(String("123"), atomicString); | |
| 250 | |
| 251 builder.reserveCapacity(256); | |
| 252 for (int i = builder.length(); i < 128; i++) | |
| 253 builder.append('x'); | |
| 254 AtomicString atomicString1 = builder.toAtomicString(); | |
| 255 EXPECT_EQ(128u, atomicString1.length()); | |
| 256 EXPECT_EQ('x', atomicString1[127]); | |
| 257 | |
| 258 // Later change of builder should not affect the atomic string. | |
| 259 for (int i = builder.length(); i < 256; i++) | |
| 260 builder.append('x'); | |
| 261 EXPECT_EQ(128u, atomicString1.length()); | |
| 262 | |
| 263 String string = builder.toString(); | |
| 264 AtomicString atomicString2 = builder.toAtomicString(); | |
| 265 // They should share the same StringImpl. | |
| 266 EXPECT_EQ(atomicString2.impl(), string.impl()); | |
| 267 } | |
| 268 | |
| 269 TEST(StringBuilderTest, ToAtomicStringOnEmpty) { | |
| 270 { // Default constructed. | |
| 271 StringBuilder builder; | |
| 272 AtomicString atomicString = builder.toAtomicString(); | |
| 273 EXPECT_EQ(emptyAtom, atomicString); | |
| 274 } | |
| 275 { // With capacity. | |
| 276 StringBuilder builder; | |
| 277 builder.reserveCapacity(64); | |
| 278 AtomicString atomicString = builder.toAtomicString(); | |
| 279 EXPECT_EQ(emptyAtom, atomicString); | |
| 280 } | |
| 281 { // AtomicString constructed from a null string. | |
| 282 StringBuilder builder; | |
| 283 builder.append(String()); | |
| 284 AtomicString atomicString = builder.toAtomicString(); | |
| 285 EXPECT_EQ(emptyAtom, atomicString); | |
| 286 } | |
| 287 { // AtomicString constructed from an empty string. | |
| 288 StringBuilder builder; | |
| 289 builder.append(emptyString); | |
| 290 AtomicString atomicString = builder.toAtomicString(); | |
| 291 EXPECT_EQ(emptyAtom, atomicString); | |
| 292 } | |
| 293 { // AtomicString constructed from an empty StringBuilder. | |
| 294 StringBuilder builder; | |
| 295 StringBuilder emptyBuilder; | |
| 296 builder.append(emptyBuilder); | |
| 297 AtomicString atomicString = builder.toAtomicString(); | |
| 298 EXPECT_EQ(emptyAtom, atomicString); | |
| 299 } | |
| 300 { // AtomicString constructed from an empty char* string. | |
| 301 StringBuilder builder; | |
| 302 builder.append("", 0); | |
| 303 AtomicString atomicString = builder.toAtomicString(); | |
| 304 EXPECT_EQ(emptyAtom, atomicString); | |
| 305 } | |
| 306 { // Cleared StringBuilder. | |
| 307 StringBuilder builder; | |
| 308 builder.append("WebKit"); | |
| 309 builder.clear(); | |
| 310 AtomicString atomicString = builder.toAtomicString(); | |
| 311 EXPECT_EQ(emptyAtom, atomicString); | |
| 312 } | |
| 313 } | |
| 314 | |
| 315 TEST(StringBuilderTest, Substring) { | |
| 316 { // Default constructed. | |
| 317 StringBuilder builder; | |
| 318 String substring = builder.substring(0, 10); | |
| 319 EXPECT_EQ(emptyString, substring); | |
| 320 } | |
| 321 { // With capacity. | |
| 322 StringBuilder builder; | |
| 323 builder.reserveCapacity(64); | |
| 324 builder.append("abc"); | |
| 325 String substring = builder.substring(2, 10); | |
| 326 EXPECT_EQ(String("c"), substring); | |
| 327 } | |
| 328 } | |
| 329 | |
| 330 TEST(StringBuilderTest, AppendNumberDoubleUChar) { | |
| 331 const double someNumber = 1.2345; | |
| 332 StringBuilder reference; | |
| 333 reference.append(replacementCharacter); // Make it UTF-16. | |
| 334 reference.append(String::number(someNumber)); | |
| 335 StringBuilder test; | |
| 336 test.append(replacementCharacter); | |
| 337 test.appendNumber(someNumber); | |
| 338 EXPECT_EQ(reference, test); | |
| 339 } | |
| 340 | |
| 341 } // namespace WTF | |
| OLD | NEW |