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