• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include "config.h"
27 
28 #include "wtf/MathExtras.h"
29 #include "wtf/text/CString.h"
30 #include "wtf/text/WTFString.h"
31 #include <gtest/gtest.h>
32 #include <limits>
33 
34 namespace {
35 
TEST(WTF,StringCreationFromLiteral)36 TEST(WTF, StringCreationFromLiteral)
37 {
38     String stringFromLiteral("Explicit construction syntax");
39     ASSERT_EQ(strlen("Explicit construction syntax"), stringFromLiteral.length());
40     ASSERT_TRUE(stringFromLiteral == "Explicit construction syntax");
41     ASSERT_TRUE(stringFromLiteral.is8Bit());
42     ASSERT_TRUE(String("Explicit construction syntax") == stringFromLiteral);
43 }
44 
TEST(WTF,StringASCII)45 TEST(WTF, StringASCII)
46 {
47     CString output;
48 
49     // Null String.
50     output = String().ascii();
51     ASSERT_STREQ("", output.data());
52 
53     // Empty String.
54     output = emptyString().ascii();
55     ASSERT_STREQ("", output.data());
56 
57     // Regular String.
58     output = String("foobar").ascii();
59     ASSERT_STREQ("foobar", output.data());
60 }
61 
testNumberToStringECMAScript(double number,const char * reference)62 static void testNumberToStringECMAScript(double number, const char* reference)
63 {
64     CString numberString = String::numberToStringECMAScript(number).latin1();
65     ASSERT_STREQ(reference, numberString.data());
66 }
67 
TEST(WTF,StringNumberToStringECMAScriptBoundaries)68 TEST(WTF, StringNumberToStringECMAScriptBoundaries)
69 {
70     typedef std::numeric_limits<double> Limits;
71 
72     // Infinity.
73     testNumberToStringECMAScript(Limits::infinity(), "Infinity");
74     testNumberToStringECMAScript(-Limits::infinity(), "-Infinity");
75 
76     // NaN.
77     testNumberToStringECMAScript(-Limits::quiet_NaN(), "NaN");
78 
79     // Zeros.
80     testNumberToStringECMAScript(0, "0");
81     testNumberToStringECMAScript(-0, "0");
82 
83     // Min-Max.
84     testNumberToStringECMAScript(Limits::min(), "2.2250738585072014e-308");
85     testNumberToStringECMAScript(Limits::max(), "1.7976931348623157e+308");
86 }
87 
TEST(WTF,StringNumberToStringECMAScriptRegularNumbers)88 TEST(WTF, StringNumberToStringECMAScriptRegularNumbers)
89 {
90     // Pi.
91     testNumberToStringECMAScript(piDouble, "3.141592653589793");
92     testNumberToStringECMAScript(piFloat, "3.1415927410125732");
93     testNumberToStringECMAScript(piOverTwoDouble, "1.5707963267948966");
94     testNumberToStringECMAScript(piOverTwoFloat, "1.5707963705062866");
95     testNumberToStringECMAScript(piOverFourDouble, "0.7853981633974483");
96     testNumberToStringECMAScript(piOverFourFloat, "0.7853981852531433");
97 
98     // e.
99     const double e = 2.71828182845904523536028747135266249775724709369995;
100     testNumberToStringECMAScript(e, "2.718281828459045");
101 
102     // c, speed of light in m/s.
103     const double c = 299792458;
104     testNumberToStringECMAScript(c, "299792458");
105 
106     // Golen ratio.
107     const double phi = 1.6180339887498948482;
108     testNumberToStringECMAScript(phi, "1.618033988749895");
109 }
110 
TEST(WTF,StringReplaceWithLiteral)111 TEST(WTF, StringReplaceWithLiteral)
112 {
113     // Cases for 8Bit source.
114     String testString = "1224";
115     ASSERT_TRUE(testString.is8Bit());
116     testString.replaceWithLiteral('2', "");
117     ASSERT_STREQ("14", testString.utf8().data());
118 
119     testString = "1224";
120     ASSERT_TRUE(testString.is8Bit());
121     testString.replaceWithLiteral('2', "3");
122     ASSERT_STREQ("1334", testString.utf8().data());
123 
124     testString = "1224";
125     ASSERT_TRUE(testString.is8Bit());
126     testString.replaceWithLiteral('2', "555");
127     ASSERT_STREQ("15555554", testString.utf8().data());
128 
129     testString = "1224";
130     ASSERT_TRUE(testString.is8Bit());
131     testString.replaceWithLiteral('3', "NotFound");
132     ASSERT_STREQ("1224", testString.utf8().data());
133 
134     // Cases for 16Bit source.
135     testString = String::fromUTF8("résumé");
136     ASSERT_FALSE(testString.is8Bit());
137     testString.replaceWithLiteral(UChar(0x00E9 /*U+00E9 is 'é'*/), "e");
138     ASSERT_STREQ("resume", testString.utf8().data());
139 
140     testString = String::fromUTF8("résumé");
141     ASSERT_FALSE(testString.is8Bit());
142     testString.replaceWithLiteral(UChar(0x00E9 /*U+00E9 is 'é'*/), "");
143     ASSERT_STREQ("rsum", testString.utf8().data());
144 
145     testString = String::fromUTF8("résumé");
146     ASSERT_FALSE(testString.is8Bit());
147     testString.replaceWithLiteral('3', "NotFound");
148     ASSERT_STREQ("résumé", testString.utf8().data());
149 }
150 
TEST(WTF,StringComparisonOfSameStringVectors)151 TEST(WTF, StringComparisonOfSameStringVectors)
152 {
153     Vector<String> stringVector;
154     stringVector.append("one");
155     stringVector.append("two");
156 
157     Vector<String> sameStringVector;
158     sameStringVector.append("one");
159     sameStringVector.append("two");
160 
161     ASSERT_EQ(stringVector, sameStringVector);
162 }
163 
TEST(WTF,SimplifyWhiteSpace)164 TEST(WTF, SimplifyWhiteSpace)
165 {
166     String extraSpaces("  Hello  world  ");
167     ASSERT_EQ(String("Hello world"), extraSpaces.simplifyWhiteSpace());
168     ASSERT_EQ(String("  Hello  world  "), extraSpaces.simplifyWhiteSpace(WTF::DoNotStripWhiteSpace));
169 
170     String extraSpacesAndNewlines(" \nHello\n world\n ");
171     ASSERT_EQ(String("Hello world"), extraSpacesAndNewlines.simplifyWhiteSpace());
172     ASSERT_EQ(String("  Hello  world  "), extraSpacesAndNewlines.simplifyWhiteSpace(WTF::DoNotStripWhiteSpace));
173 
174     String extraSpacesAndTabs(" \nHello\t world\t ");
175     ASSERT_EQ(String("Hello world"), extraSpacesAndTabs.simplifyWhiteSpace());
176     ASSERT_EQ(String("  Hello  world  "), extraSpacesAndTabs.simplifyWhiteSpace(WTF::DoNotStripWhiteSpace));
177 }
178 
179 struct CaseFoldingTestData {
180     const char* sourceDescription;
181     const char* source;
182     const char** localeList;
183     size_t localeListLength;
184     const char* expected;
185 };
186 
187 // \xC4\xB0 = U+0130 (capital dotted I)
188 // \xC4\xB1 = U+0131 (lowercase dotless I)
189 const char* turkicInput = "Isi\xC4\xB0 \xC4\xB0s\xC4\xB1I";
190 const char* greekInput = "\xCE\x9F\xCE\x94\xCE\x8C\xCE\xA3 \xCE\x9F\xCE\xB4\xCF\x8C\xCF\x82 \xCE\xA3\xCE\xBF \xCE\xA3\xCE\x9F o\xCE\xA3 \xCE\x9F\xCE\xA3 \xCF\x83 \xE1\xBC\x95\xCE\xBE";
191 const char* lithuanianInput = "I \xC3\x8F J J\xCC\x88 \xC4\xAE \xC4\xAE\xCC\x88 \xC3\x8C \xC3\x8D \xC4\xA8 xi\xCC\x87\xCC\x88 xj\xCC\x87\xCC\x88 x\xC4\xAF\xCC\x87\xCC\x88 xi\xCC\x87\xCC\x80 xi\xCC\x87\xCC\x81 xi\xCC\x87\xCC\x83 XI X\xC3\x8F XJ XJ\xCC\x88 X\xC4\xAE X\xC4\xAE\xCC\x88";
192 
193 
194 const char* turkicLocales[] = {
195     "tr", "tr-TR", "tr_TR", "tr@foo=bar", "tr-US", "TR", "tr-tr", "tR",
196     "az", "az-AZ", "az_AZ", "az@foo=bar", "az-US", "Az", "AZ-AZ", };
197 const char* nonTurkicLocales[] = {
198     "en", "en-US", "en_US", "en@foo=bar", "EN", "En",
199     "ja", "el", "fil", "fi", "lt", };
200 const char* greekLocales[] = {
201     "el", "el-GR", "el_GR", "el@foo=bar", "el-US", "EL", "el-gr", "eL",
202 };
203 const char* nonGreekLocales[] = {
204     "en", "en-US", "en_US", "en@foo=bar", "EN", "En",
205     "ja", "tr", "az", "fil", "fi", "lt", };
206 const char* lithuanianLocales[] = {
207     "lt", "lt-LT", "lt_LT", "lt@foo=bar", "lt-US", "LT", "lt-lt", "lT",
208 };
209 // Should not have "tr" or "az" because "lt" and 'tr/az' rules conflict with each other.
210 const char* nonLithuanianLocales[] = {
211     "en", "en-US", "en_US", "en@foo=bar", "EN", "En", "ja", "fil", "fi", "el", };
212 
TEST(WTF,StringToUpperLocale)213 TEST(WTF, StringToUpperLocale)
214 {
215     CaseFoldingTestData testDataList[] = {
216         {
217             "Turkic input",
218             turkicInput,
219             turkicLocales,
220             sizeof(turkicLocales) / sizeof(const char*),
221             "IS\xC4\xB0\xC4\xB0 \xC4\xB0SII",
222         }, {
223             "Turkic input",
224             turkicInput,
225             nonTurkicLocales,
226             sizeof(nonTurkicLocales) / sizeof(const char*),
227             "ISI\xC4\xB0 \xC4\xB0SII",
228         }, {
229             "Greek input",
230             greekInput,
231             greekLocales,
232             sizeof(greekLocales) / sizeof(const char*),
233             "\xCE\x9F\xCE\x94\xCE\x9F\xCE\xA3 \xCE\x9F\xCE\x94\xCE\x9F\xCE\xA3 \xCE\xA3\xCE\x9F \xCE\xA3\xCE\x9F \x4F\xCE\xA3 \xCE\x9F\xCE\xA3 \xCE\xA3 \xCE\x95\xCE\x9E",
234         }, {
235             "Greek input",
236             greekInput,
237             nonGreekLocales,
238             sizeof(nonGreekLocales) / sizeof(const char*),
239             "\xCE\x9F\xCE\x94\xCE\x8C\xCE\xA3 \xCE\x9F\xCE\x94\xCE\x8C\xCE\xA3 \xCE\xA3\xCE\x9F \xCE\xA3\xCE\x9F \x4F\xCE\xA3 \xCE\x9F\xCE\xA3 \xCE\xA3 \xE1\xBC\x9D\xCE\x9E",
240         }, {
241             "Lithuanian input",
242             lithuanianInput,
243             lithuanianLocales,
244             sizeof(lithuanianLocales) / sizeof(const char*),
245             "I \xC3\x8F J J\xCC\x88 \xC4\xAE \xC4\xAE\xCC\x88 \xC3\x8C \xC3\x8D \xC4\xA8 XI\xCC\x88 XJ\xCC\x88 X\xC4\xAE\xCC\x88 XI\xCC\x80 XI\xCC\x81 XI\xCC\x83 XI X\xC3\x8F XJ XJ\xCC\x88 X\xC4\xAE X\xC4\xAE\xCC\x88",
246         }, {
247             "Lithuanian input",
248             lithuanianInput,
249             nonLithuanianLocales,
250             sizeof(nonLithuanianLocales) / sizeof(const char*),
251             "I \xC3\x8F J J\xCC\x88 \xC4\xAE \xC4\xAE\xCC\x88 \xC3\x8C \xC3\x8D \xC4\xA8 XI\xCC\x87\xCC\x88 XJ\xCC\x87\xCC\x88 X\xC4\xAE\xCC\x87\xCC\x88 XI\xCC\x87\xCC\x80 XI\xCC\x87\xCC\x81 XI\xCC\x87\xCC\x83 XI X\xC3\x8F XJ XJ\xCC\x88 X\xC4\xAE X\xC4\xAE\xCC\x88",
252         },
253     };
254 
255     for (size_t i = 0; i < sizeof(testDataList) / sizeof(testDataList[0]); ++i) {
256         const char* expected = testDataList[i].expected;
257         String source = String::fromUTF8(testDataList[i].source);
258         for (size_t j = 0; j < testDataList[i].localeListLength; ++j) {
259             const char* locale = testDataList[i].localeList[j];
260             EXPECT_STREQ(expected, source.upper(locale).utf8().data()) << testDataList[i].sourceDescription << "; locale=" << locale;
261         }
262     }
263 }
264 
TEST(WTF,StringToLowerLocale)265 TEST(WTF, StringToLowerLocale)
266 {
267     CaseFoldingTestData testDataList[] = {
268         {
269             "Turkic input",
270             turkicInput,
271             turkicLocales,
272             sizeof(turkicLocales) / sizeof(const char*),
273             "\xC4\xB1sii is\xC4\xB1\xC4\xB1",
274         }, {
275             "Turkic input",
276             turkicInput,
277             nonTurkicLocales,
278             sizeof(nonTurkicLocales) / sizeof(const char*),
279             // U+0130 is lowercased to U+0069 followed by U+0307
280             "isii\xCC\x87 i\xCC\x87s\xC4\xB1i",
281         }, {
282             "Greek input",
283             greekInput,
284             greekLocales,
285             sizeof(greekLocales) / sizeof(const char*),
286             "\xCE\xBF\xCE\xB4\xCF\x8C\xCF\x82 \xCE\xBF\xCE\xB4\xCF\x8C\xCF\x82 \xCF\x83\xCE\xBF \xCF\x83\xCE\xBF \x6F\xCF\x82 \xCE\xBF\xCF\x82 \xCF\x83 \xE1\xBC\x95\xCE\xBE",
287         }, {
288             "Greek input",
289             greekInput,
290             nonGreekLocales,
291             sizeof(greekLocales) / sizeof(const char*),
292             "\xCE\xBF\xCE\xB4\xCF\x8C\xCF\x82 \xCE\xBF\xCE\xB4\xCF\x8C\xCF\x82 \xCF\x83\xCE\xBF \xCF\x83\xCE\xBF \x6F\xCF\x82 \xCE\xBF\xCF\x82 \xCF\x83 \xE1\xBC\x95\xCE\xBE",
293         }, {
294             "Lithuanian input",
295             lithuanianInput,
296             lithuanianLocales,
297             sizeof(lithuanianLocales) / sizeof(const char*),
298             "i \xC3\xAF j j\xCC\x87\xCC\x88 \xC4\xAF \xC4\xAF\xCC\x87\xCC\x88 i\xCC\x87\xCC\x80 i\xCC\x87\xCC\x81 i\xCC\x87\xCC\x83 xi\xCC\x87\xCC\x88 xj\xCC\x87\xCC\x88 x\xC4\xAF\xCC\x87\xCC\x88 xi\xCC\x87\xCC\x80 xi\xCC\x87\xCC\x81 xi\xCC\x87\xCC\x83 xi x\xC3\xAF xj xj\xCC\x87\xCC\x88 x\xC4\xAF x\xC4\xAF\xCC\x87\xCC\x88",
299         }, {
300             "Lithuanian input",
301             lithuanianInput,
302             nonLithuanianLocales,
303             sizeof(nonLithuanianLocales) / sizeof(const char*),
304             "\x69 \xC3\xAF \x6A \x6A\xCC\x88 \xC4\xAF \xC4\xAF\xCC\x88 \xC3\xAC \xC3\xAD \xC4\xA9 \x78\x69\xCC\x87\xCC\x88 \x78\x6A\xCC\x87\xCC\x88 \x78\xC4\xAF\xCC\x87\xCC\x88 \x78\x69\xCC\x87\xCC\x80 \x78\x69\xCC\x87\xCC\x81 \x78\x69\xCC\x87\xCC\x83 \x78\x69 \x78\xC3\xAF \x78\x6A \x78\x6A\xCC\x88 \x78\xC4\xAF \x78\xC4\xAF\xCC\x88",
305         },
306     };
307 
308     for (size_t i = 0; i < sizeof(testDataList) / sizeof(testDataList[0]); ++i) {
309         const char* expected = testDataList[i].expected;
310         String source = String::fromUTF8(testDataList[i].source);
311         for (size_t j = 0; j < testDataList[i].localeListLength; ++j) {
312             const char* locale = testDataList[i].localeList[j];
313             EXPECT_STREQ(expected, source.lower(locale).utf8().data()) << testDataList[i].sourceDescription << "; locale=" << locale;
314         }
315     }
316 }
317 
318 } // namespace
319