| /* |
| * 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 |