blob: b1e1ce9da2c0f8a27fe328f1618b6a653f3ffabb [file] [log] [blame]
/*
* Copyright (C) 2012-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "WTFStringUtilities.h"
#include <limits>
#include <sstream>
#include <wtf/MathExtras.h>
#include <wtf/text/CString.h>
#include <wtf/text/WTFString.h>
namespace TestWebKitAPI {
TEST(WTF, StringCreationFromLiteral)
{
String stringFromLiteralViaASCII("Explicit construction syntax"_s);
EXPECT_EQ(strlen("Explicit construction syntax"), stringFromLiteralViaASCII.length());
EXPECT_EQ("Explicit construction syntax"_s, stringFromLiteralViaASCII);
EXPECT_TRUE(stringFromLiteralViaASCII.is8Bit());
EXPECT_EQ(String("Explicit construction syntax"_s), stringFromLiteralViaASCII);
String stringFromLiteral = "String Literal"_str;
EXPECT_EQ(strlen("String Literal"), stringFromLiteral.length());
EXPECT_EQ("String Literal"_s, stringFromLiteral);
EXPECT_TRUE(stringFromLiteral.is8Bit());
EXPECT_EQ(String("String Literal"_s), stringFromLiteral);
}
TEST(WTF, StringASCII)
{
CString output;
// Null String.
output = String().ascii();
EXPECT_STREQ("", output.data());
// Empty String.
output = emptyString().ascii();
EXPECT_STREQ("", output.data());
// Regular String.
output = String("foobar"_s).ascii();
EXPECT_STREQ("foobar", output.data());
}
TEST(WTF, StringStartsWithEmptyVsNull)
{
String nullString;
String emptyString = WTF::emptyString();
String stringWithCharacters("hello"_s);
EXPECT_TRUE(stringWithCharacters.startsWith(nullString));
EXPECT_TRUE(stringWithCharacters.startsWith(emptyString));
}
static inline const char* testStringNumberFixedPrecision(double number)
{
static char testBuffer[100] = { };
std::strncpy(testBuffer, String::numberToStringFixedPrecision(number).utf8().data(), 99);
return testBuffer;
}
TEST(WTF, StringNumberFixedPrecision)
{
using Limits = std::numeric_limits<double>;
EXPECT_STREQ("Infinity", testStringNumberFixedPrecision(Limits::infinity()));
EXPECT_STREQ("-Infinity", testStringNumberFixedPrecision(-Limits::infinity()));
EXPECT_STREQ("NaN", testStringNumberFixedPrecision(-Limits::quiet_NaN()));
EXPECT_STREQ("0", testStringNumberFixedPrecision(0));
EXPECT_STREQ("0", testStringNumberFixedPrecision(-0));
EXPECT_STREQ("2.22507e-308", testStringNumberFixedPrecision(Limits::min()));
EXPECT_STREQ("-1.79769e+308", testStringNumberFixedPrecision(Limits::lowest()));
EXPECT_STREQ("1.79769e+308", testStringNumberFixedPrecision(Limits::max()));
EXPECT_STREQ("3.14159", testStringNumberFixedPrecision(piDouble));
EXPECT_STREQ("3.14159", testStringNumberFixedPrecision(piFloat));
EXPECT_STREQ("1.5708", testStringNumberFixedPrecision(piOverTwoDouble));
EXPECT_STREQ("1.5708", testStringNumberFixedPrecision(piOverTwoFloat));
EXPECT_STREQ("0.785398", testStringNumberFixedPrecision(piOverFourDouble));
EXPECT_STREQ("0.785398", testStringNumberFixedPrecision(piOverFourFloat));
EXPECT_STREQ("2.71828", testStringNumberFixedPrecision(2.71828182845904523536028747135266249775724709369995));
EXPECT_STREQ("2.99792e+8", testStringNumberFixedPrecision(299792458));
EXPECT_STREQ("1.61803", testStringNumberFixedPrecision(1.6180339887498948482));
EXPECT_STREQ("1000", testStringNumberFixedPrecision(1e3));
EXPECT_STREQ("1e+10", testStringNumberFixedPrecision(1e10));
EXPECT_STREQ("1e+20", testStringNumberFixedPrecision(1e20));
EXPECT_STREQ("1e+21", testStringNumberFixedPrecision(1e21));
EXPECT_STREQ("1e+30", testStringNumberFixedPrecision(1e30));
EXPECT_STREQ("1100", testStringNumberFixedPrecision(1.1e3));
EXPECT_STREQ("1.1e+10", testStringNumberFixedPrecision(1.1e10));
EXPECT_STREQ("1.1e+20", testStringNumberFixedPrecision(1.1e20));
EXPECT_STREQ("1.1e+21", testStringNumberFixedPrecision(1.1e21));
EXPECT_STREQ("1.1e+30", testStringNumberFixedPrecision(1.1e30));
}
static inline const char* testStringNumberFixedWidth(double number)
{
static char testBuffer[100] = { };
std::strncpy(testBuffer, String::numberToStringFixedWidth(number, 6).utf8().data(), 99);
return testBuffer;
}
TEST(WTF, StringNumberFixedWidth)
{
using Limits = std::numeric_limits<double>;
EXPECT_STREQ("Infinity", testStringNumberFixedWidth(Limits::infinity()));
EXPECT_STREQ("-Infinity", testStringNumberFixedWidth(-Limits::infinity()));
EXPECT_STREQ("NaN", testStringNumberFixedWidth(-Limits::quiet_NaN()));
EXPECT_STREQ("0.000000", testStringNumberFixedWidth(0));
EXPECT_STREQ("0.000000", testStringNumberFixedWidth(-0));
EXPECT_STREQ("0.000000", testStringNumberFixedWidth(Limits::min()));
EXPECT_STREQ("", testStringNumberFixedWidth(Limits::lowest()));
EXPECT_STREQ("", testStringNumberFixedWidth(Limits::max()));
EXPECT_STREQ("3.141593", testStringNumberFixedWidth(piDouble));
EXPECT_STREQ("3.141593", testStringNumberFixedWidth(piFloat));
EXPECT_STREQ("1.570796", testStringNumberFixedWidth(piOverTwoDouble));
EXPECT_STREQ("1.570796", testStringNumberFixedWidth(piOverTwoFloat));
EXPECT_STREQ("0.785398", testStringNumberFixedWidth(piOverFourDouble));
EXPECT_STREQ("0.785398", testStringNumberFixedWidth(piOverFourFloat));
EXPECT_STREQ("2.718282", testStringNumberFixedWidth(2.71828182845904523536028747135266249775724709369995));
EXPECT_STREQ("299792458.000000", testStringNumberFixedWidth(299792458));
EXPECT_STREQ("1.618034", testStringNumberFixedWidth(1.6180339887498948482));
EXPECT_STREQ("1000.000000", testStringNumberFixedWidth(1e3));
EXPECT_STREQ("10000000000.000000", testStringNumberFixedWidth(1e10));
EXPECT_STREQ("100000000000000000000.000000", testStringNumberFixedWidth(1e20));
EXPECT_STREQ("", testStringNumberFixedWidth(1e21));
EXPECT_STREQ("1100.000000", testStringNumberFixedWidth(1.1e3));
EXPECT_STREQ("11000000000.000000", testStringNumberFixedWidth(1.1e10));
EXPECT_STREQ("110000000000000000000.000000", testStringNumberFixedWidth(1.1e20));
EXPECT_STREQ("", testStringNumberFixedWidth(1.1e21));
}
static inline const char* testStringNumber(double number)
{
static char testBuffer[100] = { };
std::strncpy(testBuffer, String::number(number).utf8().data(), 99);
return testBuffer;
}
TEST(WTF, StringNumber)
{
using Limits = std::numeric_limits<double>;
EXPECT_STREQ("Infinity", testStringNumber(Limits::infinity()));
EXPECT_STREQ("-Infinity", testStringNumber(-Limits::infinity()));
EXPECT_STREQ("NaN", testStringNumber(-Limits::quiet_NaN()));
EXPECT_STREQ("0", testStringNumber(0));
EXPECT_STREQ("0", testStringNumber(-0));
EXPECT_STREQ("2.2250738585072014e-308", testStringNumber(Limits::min()));
EXPECT_STREQ("-1.7976931348623157e+308", testStringNumber(Limits::lowest()));
EXPECT_STREQ("1.7976931348623157e+308", testStringNumber(Limits::max()));
EXPECT_STREQ("3.141592653589793", testStringNumber(piDouble));
EXPECT_STREQ("3.1415927410125732", testStringNumber(piFloat));
EXPECT_STREQ("1.5707963267948966", testStringNumber(piOverTwoDouble));
EXPECT_STREQ("1.5707963705062866", testStringNumber(piOverTwoFloat));
EXPECT_STREQ("0.7853981633974483", testStringNumber(piOverFourDouble));
EXPECT_STREQ("0.7853981852531433", testStringNumber(piOverFourFloat));
EXPECT_STREQ("2.718281828459045", testStringNumber(2.71828182845904523536028747135266249775724709369995));
EXPECT_STREQ("299792458", testStringNumber(299792458));
EXPECT_STREQ("1.618033988749895", testStringNumber(1.6180339887498948482));
EXPECT_STREQ("1000", testStringNumber(1e3));
EXPECT_STREQ("10000000000", testStringNumber(1e10));
EXPECT_STREQ("100000000000000000000", testStringNumber(1e20));
EXPECT_STREQ("1e+21", testStringNumber(1e21));
EXPECT_STREQ("1e+30", testStringNumber(1e30));
EXPECT_STREQ("1100", testStringNumber(1.1e3));
EXPECT_STREQ("11000000000", testStringNumber(1.1e10));
EXPECT_STREQ("110000000000000000000", testStringNumber(1.1e20));
EXPECT_STREQ("1.1e+21", testStringNumber(1.1e21));
EXPECT_STREQ("1.1e+30", testStringNumber(1.1e30));
}
TEST(WTF, StringNumberIntMin)
{
constexpr int intMin = std::numeric_limits<int>::min();
String result = String::number(intMin);
std::stringstream stringStream;
stringStream << intMin;
std::string expectedString;
stringStream >> expectedString;
EXPECT_TRUE(result == String::fromLatin1(expectedString.c_str()));
}
TEST(WTF, StringReplaceWithLiteral)
{
// Cases for 8Bit source.
String testString = "1224"_s;
EXPECT_TRUE(testString.is8Bit());
testString = makeStringByReplacingAll(testString, '2', ""_s);
EXPECT_STREQ("14", testString.utf8().data());
testString = "1224"_s;
EXPECT_TRUE(testString.is8Bit());
testString = makeStringByReplacingAll(testString, '2', "3"_s);
EXPECT_STREQ("1334", testString.utf8().data());
testString = "1224"_s;
EXPECT_TRUE(testString.is8Bit());
testString = makeStringByReplacingAll(testString, '2', "555"_s);
EXPECT_STREQ("15555554", testString.utf8().data());
testString = "1224"_s;
EXPECT_TRUE(testString.is8Bit());
testString = makeStringByReplacingAll(testString, '3', "NotFound"_s);
EXPECT_STREQ("1224", testString.utf8().data());
// Cases for 16Bit source.
testString = String::fromUTF8("résumé");
EXPECT_FALSE(testString.is8Bit());
testString = makeStringByReplacingAll(testString, UChar(0x00E9 /*U+00E9 is 'é'*/), "e"_s);
EXPECT_STREQ("resume", testString.utf8().data());
testString = String::fromUTF8("résumé");
EXPECT_FALSE(testString.is8Bit());
testString = makeStringByReplacingAll(testString, UChar(0x00E9 /*U+00E9 is 'é'*/), ""_s);
EXPECT_STREQ("rsum", testString.utf8().data());
testString = String::fromUTF8("résumé");
EXPECT_FALSE(testString.is8Bit());
testString = makeStringByReplacingAll(testString, '3', "NotFound"_s);
EXPECT_STREQ("résumé", testString.utf8().data());
}
TEST(WTF, StringIsolatedCopy)
{
String original = "1234"_s;
auto copy = WTFMove(original).isolatedCopy();
EXPECT_FALSE(original.impl() == copy.impl());
}
TEST(WTF, StringToDouble)
{
bool ok = false;
EXPECT_EQ(0.0, String().toDouble());
EXPECT_EQ(0.0, String().toDouble(&ok));
EXPECT_FALSE(ok);
EXPECT_EQ(0.0, emptyString().toDouble());
EXPECT_EQ(0.0, emptyString().toDouble(&ok));
EXPECT_FALSE(ok);
EXPECT_EQ(0.0, String("0"_s).toDouble());
EXPECT_EQ(0.0, String("0"_s).toDouble(&ok));
EXPECT_TRUE(ok);
EXPECT_EQ(1.0, String("1"_s).toDouble());
EXPECT_EQ(1.0, String("1"_s).toDouble(&ok));
EXPECT_TRUE(ok);
// fail if we see leading junk
EXPECT_EQ(0.0, String("x1"_s).toDouble());
EXPECT_EQ(0.0, String("x1"_s).toDouble(&ok));
EXPECT_FALSE(ok);
// succeed if we see leading spaces
EXPECT_EQ(1.0, String(" 1"_s).toDouble());
EXPECT_EQ(1.0, String(" 1"_s).toDouble(&ok));
EXPECT_TRUE(ok);
// ignore trailing junk, but return false for "ok"
// FIXME: This is an inconsistency with toInt, which always guarantees
// it will return 0 if it's also going to return false for ok.
EXPECT_EQ(1.0, String("1x"_s).toDouble());
EXPECT_EQ(1.0, String("1x"_s).toDouble(&ok));
EXPECT_FALSE(ok);
// parse only numbers, not special values such as "infinity"
EXPECT_EQ(0.0, String("infinity"_s).toDouble());
EXPECT_EQ(0.0, String("infinity"_s).toDouble(&ok));
EXPECT_FALSE(ok);
// parse only numbers, not special values such as "nan"
EXPECT_EQ(0.0, String("nan"_s).toDouble());
EXPECT_EQ(0.0, String("nan"_s).toDouble(&ok));
EXPECT_FALSE(ok);
}
TEST(WTF, StringhasInfixStartingAt)
{
EXPECT_TRUE(String("Test"_s).is8Bit());
EXPECT_TRUE(String("Te"_s).is8Bit());
EXPECT_TRUE(String("st"_s).is8Bit());
EXPECT_TRUE(String("Test"_s).hasInfixStartingAt("Te"_s, 0));
EXPECT_FALSE(String("Test"_s).hasInfixStartingAt("Te"_s, 2));
EXPECT_TRUE(String("Test"_s).hasInfixStartingAt("st"_s, 2));
EXPECT_FALSE(String("Test"_s).hasInfixStartingAt("ST"_s, 2));
EXPECT_FALSE(String::fromUTF8("中国").is8Bit());
EXPECT_FALSE(String::fromUTF8("中").is8Bit());
EXPECT_FALSE(String::fromUTF8("国").is8Bit());
EXPECT_TRUE(String::fromUTF8("中国").hasInfixStartingAt(String::fromUTF8("中"), 0));
EXPECT_FALSE(String::fromUTF8("中国").hasInfixStartingAt(String::fromUTF8("中"), 1));
EXPECT_TRUE(String::fromUTF8("中国").hasInfixStartingAt(String::fromUTF8("国"), 1));
EXPECT_FALSE(String::fromUTF8("中国").hasInfixStartingAt("Te"_s, 0));
EXPECT_FALSE(String("Test"_s).hasInfixStartingAt(String::fromUTF8("中"), 2));
}
TEST(WTF, StringExistingHash)
{
String string1("Template Literal"_s);
EXPECT_FALSE(string1.isNull());
EXPECT_FALSE(string1.impl()->hasHash());
string1.impl()->hash();
EXPECT_EQ(string1.existingHash(), string1.impl()->existingHash());
String string2;
EXPECT_EQ(string2.existingHash(), 0u);
}
TEST(WTF, StringUnicodeEqualUCharArray)
{
String string1("abc"_s);
EXPECT_FALSE(string1.isNull());
EXPECT_TRUE(string1.is8Bit());
UChar ab[] = { 'a', 'b' };
UChar abc[] = { 'a', 'b', 'c' };
UChar abcd[] = { 'a', 'b', 'c', 'd' };
UChar aBc[] = { 'a', 'B', 'c' };
EXPECT_FALSE(equal(string1, ab));
EXPECT_TRUE(equal(string1, abc));
EXPECT_FALSE(equal(string1, abcd));
EXPECT_FALSE(equal(string1, aBc));
String string2(abc, 3);
EXPECT_FALSE(equal(string2, ab));
EXPECT_TRUE(equal(string2, abc));
EXPECT_FALSE(equal(string2, abcd));
EXPECT_FALSE(equal(string2, aBc));
}
TEST(WTF, StringRightBasic)
{
auto reference = String::fromUTF8("Cappuccino");
EXPECT_EQ(String::fromUTF8(""), reference.right(0));
EXPECT_EQ(String::fromUTF8("o"), reference.right(1));
EXPECT_EQ(String::fromUTF8("no"), reference.right(2));
EXPECT_EQ(String::fromUTF8("ino"), reference.right(3));
EXPECT_EQ(String::fromUTF8("cino"), reference.right(4));
EXPECT_EQ(String::fromUTF8("ccino"), reference.right(5));
EXPECT_EQ(String::fromUTF8("uccino"), reference.right(6));
EXPECT_EQ(String::fromUTF8("puccino"), reference.right(7));
EXPECT_EQ(String::fromUTF8("ppuccino"), reference.right(8));
EXPECT_EQ(String::fromUTF8("appuccino"), reference.right(9));
EXPECT_EQ(String::fromUTF8("Cappuccino"), reference.right(10));
}
TEST(WTF, StringLeftBasic)
{
auto reference = String::fromUTF8("Cappuccino");
EXPECT_EQ(String::fromUTF8(""), reference.left(0));
EXPECT_EQ(String::fromUTF8("C"), reference.left(1));
EXPECT_EQ(String::fromUTF8("Ca"), reference.left(2));
EXPECT_EQ(String::fromUTF8("Cap"), reference.left(3));
EXPECT_EQ(String::fromUTF8("Capp"), reference.left(4));
EXPECT_EQ(String::fromUTF8("Cappu"), reference.left(5));
EXPECT_EQ(String::fromUTF8("Cappuc"), reference.left(6));
EXPECT_EQ(String::fromUTF8("Cappucc"), reference.left(7));
EXPECT_EQ(String::fromUTF8("Cappucci"), reference.left(8));
EXPECT_EQ(String::fromUTF8("Cappuccin"), reference.left(9));
EXPECT_EQ(String::fromUTF8("Cappuccino"), reference.left(10));
}
TEST(WTF, StringReverseFindBasic)
{
auto reference = String::fromUTF8("Cappuccino");
EXPECT_EQ(reference.reverseFind('o'), 9U);
EXPECT_EQ(reference.reverseFind('n'), 8U);
EXPECT_EQ(reference.reverseFind('c'), 6U);
EXPECT_EQ(reference.reverseFind('p'), 3U);
EXPECT_EQ(reference.reverseFind('k'), notFound);
EXPECT_EQ(reference.reverseFind('o', 8), notFound);
EXPECT_EQ(reference.reverseFind('c', 8), 6U);
EXPECT_EQ(reference.reverseFind('c', 6), 6U);
EXPECT_EQ(reference.reverseFind('c', 5), 5U);
EXPECT_EQ(reference.reverseFind('c', 4), notFound);
}
TEST(WTF, StringSplitWithConsecutiveSeparators)
{
String string { " This is a sentence. "_s };
Vector<String> actual = string.split(' ');
Vector<String> expected { "This"_s, "is"_s, "a"_s, "sentence."_s };
ASSERT_EQ(expected.size(), actual.size());
for (auto i = 0u; i < actual.size(); ++i)
EXPECT_STREQ(expected[i].utf8().data(), actual[i].utf8().data()) << "Vectors differ at index " << i;
actual = string.splitAllowingEmptyEntries(' ');
expected = { ""_s, "This"_s, ""_s, ""_s, ""_s, ""_s, "is"_s, ""_s, "a"_s, ""_s, ""_s, ""_s, ""_s, ""_s, ""_s, "sentence."_s, ""_s };
ASSERT_EQ(expected.size(), actual.size());
for (auto i = 0u; i < actual.size(); ++i)
EXPECT_STREQ(expected[i].utf8().data(), actual[i].utf8().data()) << "Vectors differ at index " << i;
}
} // namespace TestWebKitAPI