Home | History | Annotate | Download | only in text
      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