Add String::format variant that takes va_args
[WebKit-https.git] / Tools / TestWebKitAPI / Tests / WTF / WTFString.cpp
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 "WTFStringUtilities.h"
29 #include <limits>
30 #include <wtf/MathExtras.h>
31 #include <wtf/text/CString.h>
32 #include <wtf/text/WTFString.h>
33
34 namespace TestWebKitAPI {
35
36 TEST(WTF, StringCreationFromLiteral)
37 {
38     String stringFromLiteral(ASCIILiteral("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     String stringWithTemplate("Template Literal", String::ConstructFromLiteral);
45     ASSERT_EQ(strlen("Template Literal"), stringWithTemplate.length());
46     ASSERT_TRUE(stringWithTemplate == "Template Literal");
47     ASSERT_TRUE(stringWithTemplate.is8Bit());
48     ASSERT_TRUE(String("Template Literal") == stringWithTemplate);
49 }
50
51 TEST(WTF, StringASCII)
52 {
53     CString output;
54
55     // Null String.
56     output = String().ascii();
57     ASSERT_STREQ("", output.data());
58
59     // Empty String.
60     output = emptyString().ascii();
61     ASSERT_STREQ("", output.data());
62
63     // Regular String.
64     output = String(ASCIILiteral("foobar")).ascii();
65     ASSERT_STREQ("foobar", output.data());
66 }
67
68 static void testNumberToStringECMAScript(double number, const char* reference)
69 {
70     CString numberString = String::numberToStringECMAScript(number).latin1();
71     ASSERT_STREQ(reference, numberString.data());
72 }
73
74 TEST(WTF, StringNumberToStringECMAScriptBoundaries)
75 {
76     typedef std::numeric_limits<double> Limits;
77
78     // Infinity.
79     testNumberToStringECMAScript(Limits::infinity(), "Infinity");
80     testNumberToStringECMAScript(-Limits::infinity(), "-Infinity");
81
82     // NaN.
83     testNumberToStringECMAScript(-Limits::quiet_NaN(), "NaN");
84
85     // Zeros.
86     testNumberToStringECMAScript(0, "0");
87     testNumberToStringECMAScript(-0, "0");
88
89     // Min-Max.
90     testNumberToStringECMAScript(Limits::min(), "2.2250738585072014e-308");
91     testNumberToStringECMAScript(Limits::max(), "1.7976931348623157e+308");
92 }
93
94 TEST(WTF, StringNumberToStringECMAScriptRegularNumbers)
95 {
96     // Pi.
97     testNumberToStringECMAScript(piDouble, "3.141592653589793");
98     testNumberToStringECMAScript(piFloat, "3.1415927410125732");
99     testNumberToStringECMAScript(piOverTwoDouble, "1.5707963267948966");
100     testNumberToStringECMAScript(piOverTwoFloat, "1.5707963705062866");
101     testNumberToStringECMAScript(piOverFourDouble, "0.7853981633974483");
102     testNumberToStringECMAScript(piOverFourFloat, "0.7853981852531433");
103
104     // e.
105     const double e = 2.71828182845904523536028747135266249775724709369995;
106     testNumberToStringECMAScript(e, "2.718281828459045");
107
108     // c, speed of light in m/s.
109     const double c = 299792458;
110     testNumberToStringECMAScript(c, "299792458");
111
112     // Golen ratio.
113     const double phi = 1.6180339887498948482;
114     testNumberToStringECMAScript(phi, "1.618033988749895");
115 }
116
117 TEST(WTF, StringReplaceWithLiteral)
118 {
119     // Cases for 8Bit source.
120     String testString = "1224";
121     ASSERT_TRUE(testString.is8Bit());
122     testString.replaceWithLiteral('2', "");
123     ASSERT_STREQ("14", testString.utf8().data());
124
125     testString = "1224";
126     ASSERT_TRUE(testString.is8Bit());
127     testString.replaceWithLiteral('2', "3");
128     ASSERT_STREQ("1334", testString.utf8().data());
129
130     testString = "1224";
131     ASSERT_TRUE(testString.is8Bit());
132     testString.replaceWithLiteral('2', "555");
133     ASSERT_STREQ("15555554", testString.utf8().data());
134
135     testString = "1224";
136     ASSERT_TRUE(testString.is8Bit());
137     testString.replaceWithLiteral('3', "NotFound");
138     ASSERT_STREQ("1224", testString.utf8().data());
139
140     // Cases for 16Bit source.
141     testString = String::fromUTF8("résumé");
142     ASSERT_FALSE(testString.is8Bit());
143     testString.replaceWithLiteral(UChar(0x00E9 /*U+00E9 is 'é'*/), "e");
144     ASSERT_STREQ("resume", testString.utf8().data());
145
146     testString = String::fromUTF8("résumé");
147     ASSERT_FALSE(testString.is8Bit());
148     testString.replaceWithLiteral(UChar(0x00E9 /*U+00E9 is 'é'*/), "");
149     ASSERT_STREQ("rsum", testString.utf8().data());
150
151     testString = String::fromUTF8("résumé");
152     ASSERT_FALSE(testString.is8Bit());
153     testString.replaceWithLiteral('3', "NotFound");
154     ASSERT_STREQ("résumé", testString.utf8().data());
155 }
156
157 TEST(WTF, StringIsolatedCopy)
158 {
159     String original = "1234";
160     auto copy = WTFMove(original).isolatedCopy();
161     ASSERT_FALSE(original.impl() == copy.impl());
162 }
163
164 TEST(WTF, StringToInt)
165 {
166     bool ok = false;
167
168     EXPECT_EQ(0, String().toInt());
169     EXPECT_EQ(0, String().toInt(&ok));
170     EXPECT_FALSE(ok);
171
172     EXPECT_EQ(0, emptyString().toInt());
173     EXPECT_EQ(0, emptyString().toInt(&ok));
174     EXPECT_FALSE(ok);
175
176     EXPECT_EQ(0, String("0").toInt());
177     EXPECT_EQ(0, String("0").toInt(&ok));
178     EXPECT_TRUE(ok);
179
180     EXPECT_EQ(1, String("1").toInt());
181     EXPECT_EQ(1, String("1").toInt(&ok));
182     EXPECT_TRUE(ok);
183
184     EXPECT_EQ(2147483647, String("2147483647").toInt());
185     EXPECT_EQ(2147483647, String("2147483647").toInt(&ok));
186     EXPECT_TRUE(ok);
187
188     EXPECT_EQ(0, String("2147483648").toInt());
189     EXPECT_EQ(0, String("2147483648").toInt(&ok));
190     EXPECT_FALSE(ok);
191
192     EXPECT_EQ(-2147483648, String("-2147483648").toInt());
193     EXPECT_EQ(-2147483648, String("-2147483648").toInt(&ok));
194     EXPECT_TRUE(ok);
195
196     EXPECT_EQ(0, String("-2147483649").toInt());
197     EXPECT_EQ(0, String("-2147483649").toInt(&ok));
198     EXPECT_FALSE(ok);
199
200     // fail if we see leading junk
201     EXPECT_EQ(0, String("x1").toInt());
202     EXPECT_EQ(0, String("x1").toInt(&ok));
203     EXPECT_FALSE(ok);
204
205     // succeed if we see leading spaces
206     EXPECT_EQ(1, String(" 1").toInt());
207     EXPECT_EQ(1, String(" 1").toInt(&ok));
208     EXPECT_TRUE(ok);
209
210     // silently ignore trailing junk
211     EXPECT_EQ(1, String("1x").toInt());
212     EXPECT_EQ(1, String("1x").toInt(&ok));
213     EXPECT_TRUE(ok);
214 }
215
216 TEST(WTF, StringToDouble)
217 {
218     bool ok = false;
219
220     EXPECT_EQ(0.0, String().toDouble());
221     EXPECT_EQ(0.0, String().toDouble(&ok));
222     EXPECT_FALSE(ok);
223
224     EXPECT_EQ(0.0, emptyString().toDouble());
225     EXPECT_EQ(0.0, emptyString().toDouble(&ok));
226     EXPECT_FALSE(ok);
227
228     EXPECT_EQ(0.0, String("0").toDouble());
229     EXPECT_EQ(0.0, String("0").toDouble(&ok));
230     EXPECT_TRUE(ok);
231
232     EXPECT_EQ(1.0, String("1").toDouble());
233     EXPECT_EQ(1.0, String("1").toDouble(&ok));
234     EXPECT_TRUE(ok);
235
236     // fail if we see leading junk
237     EXPECT_EQ(0.0, String("x1").toDouble());
238     EXPECT_EQ(0.0, String("x1").toDouble(&ok));
239     EXPECT_FALSE(ok);
240
241     // succeed if we see leading spaces
242     EXPECT_EQ(1.0, String(" 1").toDouble());
243     EXPECT_EQ(1.0, String(" 1").toDouble(&ok));
244     EXPECT_TRUE(ok);
245
246     // ignore trailing junk, but return false for "ok"
247     // FIXME: This is an inconsistency with toInt, which always guarantees
248     // it will return 0 if it's also going to return false for ok.
249     EXPECT_EQ(1.0, String("1x").toDouble());
250     EXPECT_EQ(1.0, String("1x").toDouble(&ok));
251     EXPECT_FALSE(ok);
252
253     // parse only numbers, not special values such as "infinity"
254     EXPECT_EQ(0.0, String("infinity").toDouble());
255     EXPECT_EQ(0.0, String("infinity").toDouble(&ok));
256     EXPECT_FALSE(ok);
257
258     // parse only numbers, not special values such as "nan"
259     EXPECT_EQ(0.0, String("nan").toDouble());
260     EXPECT_EQ(0.0, String("nan").toDouble(&ok));
261     EXPECT_FALSE(ok);
262 }
263
264 TEST(WTF, StringhasInfixStartingAt)
265 {
266     EXPECT_TRUE(String("Test").is8Bit());
267     EXPECT_TRUE(String("Te").is8Bit());
268     EXPECT_TRUE(String("st").is8Bit());
269     EXPECT_TRUE(String("Test").hasInfixStartingAt(String("Te"), 0));
270     EXPECT_FALSE(String("Test").hasInfixStartingAt(String("Te"), 2));
271     EXPECT_TRUE(String("Test").hasInfixStartingAt(String("st"), 2));
272     EXPECT_FALSE(String("Test").hasInfixStartingAt(String("ST"), 2));
273
274     EXPECT_FALSE(String::fromUTF8("中国").is8Bit());
275     EXPECT_FALSE(String::fromUTF8("中").is8Bit());
276     EXPECT_FALSE(String::fromUTF8("国").is8Bit());
277     EXPECT_TRUE(String::fromUTF8("中国").hasInfixStartingAt(String::fromUTF8("中"), 0));
278     EXPECT_FALSE(String::fromUTF8("中国").hasInfixStartingAt(String::fromUTF8("中"), 1));
279     EXPECT_TRUE(String::fromUTF8("中国").hasInfixStartingAt(String::fromUTF8("国"), 1));
280
281     EXPECT_FALSE(String::fromUTF8("中国").hasInfixStartingAt(String("Te"), 0));
282     EXPECT_FALSE(String("Test").hasInfixStartingAt(String::fromUTF8("中"), 2));
283 }
284
285 TEST(WTF, StringExistingHash)
286 {
287     String string1("Template Literal");
288     ASSERT_FALSE(string1.isNull());
289     ASSERT_FALSE(string1.impl()->hasHash());
290     string1.impl()->hash();
291     ASSERT_EQ(string1.existingHash(), string1.impl()->existingHash());
292     String string2;
293     ASSERT_EQ(string2.existingHash(), 0u);
294 }
295
296 TEST(WTF, StringUnicodeEqualUCharArray)
297 {
298     String string1("abc");
299     ASSERT_FALSE(string1.isNull());
300     ASSERT_TRUE(string1.is8Bit());
301     UChar ab[] = { 'a', 'b' };
302     UChar abc[] = { 'a', 'b', 'c' };
303     UChar abcd[] = { 'a', 'b', 'c', 'd' };
304     UChar aBc[] = { 'a', 'B', 'c' };
305     ASSERT_FALSE(equal(string1, ab));
306     ASSERT_TRUE(equal(string1, abc));
307     ASSERT_FALSE(equal(string1, abcd));
308     ASSERT_FALSE(equal(string1, aBc));
309
310     String string2(abc, 3);
311     ASSERT_FALSE(equal(string2, ab));
312     ASSERT_TRUE(equal(string2, abc));
313     ASSERT_FALSE(equal(string2, abcd));
314     ASSERT_FALSE(equal(string2, aBc));
315 }
316
317 TEST(WTF, StringRightBasic)
318 {
319     auto reference = String::fromUTF8("Cappuccino");
320     EXPECT_EQ(String::fromUTF8(""), reference.right(0));
321     EXPECT_EQ(String::fromUTF8("o"), reference.right(1));
322     EXPECT_EQ(String::fromUTF8("no"), reference.right(2));
323     EXPECT_EQ(String::fromUTF8("ino"), reference.right(3));
324     EXPECT_EQ(String::fromUTF8("cino"), reference.right(4));
325     EXPECT_EQ(String::fromUTF8("ccino"), reference.right(5));
326     EXPECT_EQ(String::fromUTF8("uccino"), reference.right(6));
327     EXPECT_EQ(String::fromUTF8("puccino"), reference.right(7));
328     EXPECT_EQ(String::fromUTF8("ppuccino"), reference.right(8));
329     EXPECT_EQ(String::fromUTF8("appuccino"), reference.right(9));
330     EXPECT_EQ(String::fromUTF8("Cappuccino"), reference.right(10));
331 }
332
333 TEST(WTF, StringLeftBasic)
334 {
335     auto reference = String::fromUTF8("Cappuccino");
336     EXPECT_EQ(String::fromUTF8(""), reference.left(0));
337     EXPECT_EQ(String::fromUTF8("C"), reference.left(1));
338     EXPECT_EQ(String::fromUTF8("Ca"), reference.left(2));
339     EXPECT_EQ(String::fromUTF8("Cap"), reference.left(3));
340     EXPECT_EQ(String::fromUTF8("Capp"), reference.left(4));
341     EXPECT_EQ(String::fromUTF8("Cappu"), reference.left(5));
342     EXPECT_EQ(String::fromUTF8("Cappuc"), reference.left(6));
343     EXPECT_EQ(String::fromUTF8("Cappucc"), reference.left(7));
344     EXPECT_EQ(String::fromUTF8("Cappucci"), reference.left(8));
345     EXPECT_EQ(String::fromUTF8("Cappuccin"), reference.left(9));
346     EXPECT_EQ(String::fromUTF8("Cappuccino"), reference.left(10));
347 }
348
349 TEST(WTF, StringReverseFindBasic)
350 {
351     auto reference = String::fromUTF8("Cappuccino");
352     EXPECT_EQ(reference.reverseFind('o'), 9U);
353     EXPECT_EQ(reference.reverseFind('n'), 8U);
354     EXPECT_EQ(reference.reverseFind('c'), 6U);
355     EXPECT_EQ(reference.reverseFind('p'), 3U);
356     EXPECT_EQ(reference.reverseFind('k'), notFound);
357
358     EXPECT_EQ(reference.reverseFind('o', 8), notFound);
359     EXPECT_EQ(reference.reverseFind('c', 8), 6U);
360     EXPECT_EQ(reference.reverseFind('c', 6), 6U);
361     EXPECT_EQ(reference.reverseFind('c', 5), 5U);
362     EXPECT_EQ(reference.reverseFind('c', 4), notFound);
363 }
364
365 WTF_ATTRIBUTE_PRINTF(2, 3)
366 static void testWithFormatAndArguments(const char* expected, const char* format, ...)
367 {
368     va_list arguments;
369     va_start(arguments, format);
370
371 #if COMPILER(GCC_OR_CLANG)
372 #pragma GCC diagnostic push
373 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
374 #endif
375     String result = String::formatWithArguments(format, arguments);
376 #if COMPILER(GCC_OR_CLANG)
377 #pragma GCC diagnostic pop
378 #endif
379
380     va_end(arguments);
381
382     EXPECT_STREQ(expected, result.utf8().data());
383 }
384
385 TEST(WTF, StringFormatWithArguments)
386 {
387     testWithFormatAndArguments("hello cruel world", "%s %s %s", "hello", "cruel" , "world");
388
389     testWithFormatAndArguments("hello 17890 world", "%s%u%s", "hello ", 17890u, " world");
390
391     testWithFormatAndArguments("hello 17890.000 world", "%s %.3f %s", "hello", 17890.0f, "world");
392     testWithFormatAndArguments("hello 17890.50 world", "%s %.2f %s", "hello", 17890.5f, "world");
393
394     testWithFormatAndArguments("hello -17890 world", "%s %.0f %s", "hello", -17890.0f, "world");
395     testWithFormatAndArguments("hello -17890.5 world", "%s %.1f %s", "hello", -17890.5f, "world");
396
397     testWithFormatAndArguments("hello 17890 world", "%s %.0f %s", "hello", 17890.0, "world");
398     testWithFormatAndArguments("hello 17890.5 world", "%s %.1f %s", "hello", 17890.5, "world");
399
400     testWithFormatAndArguments("hello -17890 world", "%s %.0f %s", "hello", -17890.0, "world");
401     testWithFormatAndArguments("hello -17890.5 world", "%s %.1f %s", "hello", -17890.5, "world");
402 }
403
404 } // namespace TestWebKitAPI