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