summaryrefslogtreecommitdiff
path: root/Tools/TestWebKitAPI/Tests/WTF
diff options
context:
space:
mode:
Diffstat (limited to 'Tools/TestWebKitAPI/Tests/WTF')
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/AtomicString.cpp56
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/BloomFilter.cpp250
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/CString.cpp196
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/CheckedArithmeticOperations.cpp487
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/Condition.cpp257
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/DateMath.cpp208
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/Deque.cpp191
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/Functional.cpp218
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/HashMap.cpp511
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/HashSet.cpp280
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/IntegerToStringConversion.cpp132
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/ListHashSet.cpp269
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/Lock.cpp160
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/MD5.cpp47
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/MathExtras.cpp177
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/MediaTime.cpp214
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/MetaAllocator.cpp957
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/MoveOnly.h98
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/NakedPtr.cpp230
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/Optional.cpp96
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/ParkingLot.cpp273
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/RedBlackTree.cpp322
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/Ref.cpp161
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/RefCounter.cpp158
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/RefLogger.h56
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/RefPtr.cpp398
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/RunLoop.cpp57
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/SHA1.cpp57
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/SaturatedArithmeticOperations.cpp105
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/StringBuilder.cpp338
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/StringHasher.cpp444
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/StringImpl.cpp548
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/StringOperators.cpp187
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/StringView.cpp736
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/TemporaryChange.cpp47
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/Vector.cpp617
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/WTFString.cpp284
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/WeakPtr.cpp187
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/WorkQueue.cpp203
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/darwin/OSObjectPtr.cpp66
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/glib/GMainLoopSource.cpp547
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/glib/GUniquePtr.cpp195
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/glib/WorkQueueGLib.cpp71
43 files changed, 11091 insertions, 0 deletions
diff --git a/Tools/TestWebKitAPI/Tests/WTF/AtomicString.cpp b/Tools/TestWebKitAPI/Tests/WTF/AtomicString.cpp
new file mode 100644
index 000000000..e23943143
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/AtomicString.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2012 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 <wtf/text/AtomicString.h>
+
+namespace TestWebKitAPI {
+
+TEST(WTF, AtomicStringCreationFromLiteral)
+{
+ AtomicString stringWithTemplate("Template Literal", AtomicString::ConstructFromLiteral);
+ ASSERT_EQ(strlen("Template Literal"), stringWithTemplate.length());
+ ASSERT_TRUE(stringWithTemplate == "Template Literal");
+ ASSERT_TRUE(stringWithTemplate.string().is8Bit());
+
+ const char* programmaticStringData = "Explicit Size Literal";
+ AtomicString programmaticString(programmaticStringData, strlen(programmaticStringData), AtomicString::ConstructFromLiteral);
+ ASSERT_EQ(strlen(programmaticStringData), programmaticString.length());
+ ASSERT_TRUE(programmaticString.string().is8Bit());
+ ASSERT_EQ(programmaticStringData, reinterpret_cast<const char*>(programmaticString.string().characters8()));
+}
+
+TEST(WTF, AtomicStringCreationFromLiteralUniqueness)
+{
+ AtomicString string1("Template Literal", AtomicString::ConstructFromLiteral);
+ AtomicString string2("Template Literal", AtomicString::ConstructFromLiteral);
+ ASSERT_EQ(string1.impl(), string2.impl());
+
+ AtomicString string3("Template Literal");
+ ASSERT_EQ(string1.impl(), string3.impl());
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/BloomFilter.cpp b/Tools/TestWebKitAPI/Tests/WTF/BloomFilter.cpp
new file mode 100644
index 000000000..802165211
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/BloomFilter.cpp
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2015 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 <wtf/BloomFilter.h>
+#include <wtf/RandomNumber.h>
+#include <wtf/SHA1.h>
+
+namespace TestWebKitAPI {
+
+static Vector<unsigned> generateRandomHashes(size_t hashCount)
+{
+ Vector<unsigned> hashes;
+ for (unsigned i = 0; i < hashCount; ++i)
+ hashes.append(static_cast<unsigned>(randomNumber() * std::numeric_limits<unsigned>::max()));
+ return hashes;
+}
+
+static Vector<SHA1::Digest> generateRandomDigests(size_t hashCount)
+{
+ Vector<SHA1::Digest> hashes;
+ SHA1 sha1;
+ for (unsigned i = 0; i < hashCount; ++i) {
+ double random = randomNumber();
+ sha1.addBytes(reinterpret_cast<uint8_t*>(&random), sizeof(double));
+ SHA1::Digest digest;
+ sha1.computeHash(digest);
+ hashes.append(digest);
+ }
+ return hashes;
+}
+
+TEST(WTF_BloomFilter, Basic)
+{
+ const unsigned hashCount = 1000;
+ auto hashes = generateRandomHashes(hashCount);
+
+ BloomFilter<16> filter;
+ for (auto hash : hashes)
+ filter.add(hash);
+
+ for (auto hash : hashes)
+ EXPECT_TRUE(filter.mayContain(hash));
+
+ auto moreHashes = generateRandomHashes(hashCount);
+ unsigned mayContainCount = 0;
+ for (auto hash : moreHashes)
+ mayContainCount += filter.mayContain(hash) ? 1 : 0;
+ // False positive rate is ~0.09% so this should always be true.
+ EXPECT_TRUE(mayContainCount < hashCount / 10);
+
+ for (auto hash : moreHashes)
+ filter.add(hash);
+
+ for (auto hash : hashes)
+ EXPECT_TRUE(filter.mayContain(hash));
+ for (auto hash : moreHashes)
+ EXPECT_TRUE(filter.mayContain(hash));
+}
+
+TEST(WTF_BloomFilter, BasicDigest)
+{
+ const unsigned hashCount = 1000;
+ auto hashes = generateRandomDigests(hashCount);
+
+ BloomFilter<20> filter;
+ for (auto hash : hashes)
+ filter.add(hash);
+
+ for (auto hash : hashes)
+ EXPECT_TRUE(filter.mayContain(hash));
+
+ auto moreHashes = generateRandomDigests(hashCount);
+ unsigned mayContainCount = 0;
+ for (auto hash : moreHashes)
+ mayContainCount += filter.mayContain(hash) ? 1 : 0;
+ // False positive rate is ~0.000004% so this should always be true.
+ EXPECT_TRUE(mayContainCount < hashCount / 10);
+
+ for (auto hash : moreHashes)
+ filter.add(hash);
+
+ for (auto hash : hashes)
+ EXPECT_TRUE(filter.mayContain(hash));
+ for (auto hash : moreHashes)
+ EXPECT_TRUE(filter.mayContain(hash));
+}
+
+TEST(WTF_BloomFilter, BasicCounting)
+{
+ const unsigned hashCount = 1000;
+ auto hashes = generateRandomHashes(hashCount);
+
+ CountingBloomFilter<16> filter;
+ for (auto hash : hashes)
+ filter.add(hash);
+
+ for (auto hash : hashes)
+ EXPECT_TRUE(filter.mayContain(hash));
+
+ for (auto hash : hashes)
+ filter.add(hash);
+
+ for (auto hash : hashes)
+ EXPECT_TRUE(filter.mayContain(hash));
+
+ for (auto hash : hashes)
+ filter.remove(hash);
+
+ for (auto hash : hashes)
+ EXPECT_TRUE(filter.mayContain(hash));
+
+ auto moreHashes = generateRandomHashes(hashCount);
+ unsigned mayContainCount = 0;
+ for (auto hash : moreHashes)
+ mayContainCount += filter.mayContain(hash) ? 1 : 0;
+ // False positive rate is ~0.09% so this should always be true.
+ EXPECT_TRUE(mayContainCount < hashCount / 10);
+
+ for (auto hash : moreHashes)
+ filter.add(hash);
+ for (auto hash : hashes)
+ filter.remove(hash);
+
+ for (auto hash : moreHashes)
+ EXPECT_TRUE(filter.mayContain(hash));
+
+ for (auto hash : moreHashes)
+ filter.remove(hash);
+
+ for (auto hash : hashes)
+ EXPECT_TRUE(!filter.mayContain(hash));
+ for (auto hash : moreHashes)
+ EXPECT_TRUE(!filter.mayContain(hash));
+}
+
+TEST(WTF_BloomFilter, Clear)
+{
+ const unsigned hashCount = 1000;
+ auto hashes = generateRandomHashes(hashCount);
+
+ BloomFilter<16> filter;
+ for (auto hash : hashes)
+ filter.add(hash);
+
+ filter.clear();
+
+ for (auto hash : hashes)
+ EXPECT_TRUE(!filter.mayContain(hash));
+}
+
+TEST(WTF_BloomFilter, ClearCounting)
+{
+ const unsigned hashCount = 1000;
+ auto hashes = generateRandomHashes(hashCount);
+
+ CountingBloomFilter<16> filter;
+ for (auto hash : hashes)
+ filter.add(hash);
+ for (auto hash : hashes)
+ filter.add(hash);
+
+ filter.clear();
+
+ for (auto hash : hashes)
+ EXPECT_TRUE(!filter.mayContain(hash));
+}
+
+TEST(WTF_BloomFilter, CountingOverflow)
+{
+ const unsigned hashCount = 1000;
+ auto hashes = generateRandomHashes(hashCount);
+
+ CountingBloomFilter<16> filter;
+ for (auto hash : hashes)
+ filter.add(hash);
+
+ for (unsigned i = 0; i < filter.maximumCount() + 100; ++i)
+ filter.add(hashes[0]);
+
+ for (auto hash : hashes)
+ EXPECT_TRUE(filter.mayContain(hash));
+
+ for (auto hash : hashes)
+ filter.remove(hash);
+
+ unsigned mayContainCount = 0;
+ for (auto hash : hashes) {
+ if (hash == hashes[0])
+ EXPECT_TRUE(filter.mayContain(hash));
+ else
+ mayContainCount += filter.mayContain(hash) ? 1 : 0;
+ }
+ // False positive rate should be very low.
+ EXPECT_TRUE(mayContainCount < hashCount / 100);
+
+ for (unsigned i = 0; i < filter.maximumCount() + 100; ++i)
+ filter.remove(hashes[0]);
+
+ // The bucket has overflowed and is stuck.
+ EXPECT_TRUE(filter.mayContain(hashes[0]));
+}
+
+TEST(WTF_BloomFilter, Combine)
+{
+ const unsigned hashCount = 1000;
+ auto hashes = generateRandomHashes(hashCount);
+
+ BloomFilter<16> filter;
+ for (auto hash : hashes)
+ filter.add(hash);
+
+ auto moreHashes = generateRandomHashes(hashCount);
+
+ BloomFilter<16> anotherFilter;
+ for (auto hash : moreHashes)
+ anotherFilter.add(hash);
+
+ filter.add(anotherFilter);
+
+ for (auto hash : hashes)
+ EXPECT_TRUE(filter.mayContain(hash));
+ for (auto hash : moreHashes)
+ EXPECT_TRUE(filter.mayContain(hash));
+}
+
+}
diff --git a/Tools/TestWebKitAPI/Tests/WTF/CString.cpp b/Tools/TestWebKitAPI/Tests/WTF/CString.cpp
new file mode 100644
index 000000000..735d7dd8b
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/CString.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2012 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 <wtf/text/CString.h>
+
+TEST(WTF, CStringNullStringConstructor)
+{
+ CString string;
+ ASSERT_TRUE(string.isNull());
+ ASSERT_EQ(string.data(), static_cast<const char*>(0));
+ ASSERT_EQ(string.length(), static_cast<size_t>(0));
+
+ CString stringFromCharPointer(static_cast<const char*>(0));
+ ASSERT_TRUE(stringFromCharPointer.isNull());
+ ASSERT_EQ(stringFromCharPointer.data(), static_cast<const char*>(0));
+ ASSERT_EQ(stringFromCharPointer.length(), static_cast<size_t>(0));
+
+ CString stringFromCharAndLength(static_cast<const char*>(0), 0);
+ ASSERT_TRUE(stringFromCharAndLength.isNull());
+ ASSERT_EQ(stringFromCharAndLength.data(), static_cast<const char*>(0));
+ ASSERT_EQ(stringFromCharAndLength.length(), static_cast<size_t>(0));
+}
+
+TEST(WTF, CStringEmptyEmptyConstructor)
+{
+ const char* emptyString = "";
+ CString string(emptyString);
+ ASSERT_FALSE(string.isNull());
+ ASSERT_EQ(string.length(), static_cast<size_t>(0));
+ ASSERT_EQ(string.data()[0], 0);
+
+ CString stringWithLength(emptyString, 0);
+ ASSERT_FALSE(stringWithLength.isNull());
+ ASSERT_EQ(stringWithLength.length(), static_cast<size_t>(0));
+ ASSERT_EQ(stringWithLength.data()[0], 0);
+}
+
+TEST(WTF, CStringEmptyRegularConstructor)
+{
+ const char* referenceString = "WebKit";
+
+ CString string(referenceString);
+ ASSERT_FALSE(string.isNull());
+ ASSERT_EQ(string.length(), strlen(referenceString));
+ ASSERT_STREQ(referenceString, string.data());
+
+ CString stringWithLength(referenceString, 6);
+ ASSERT_FALSE(stringWithLength.isNull());
+ ASSERT_EQ(stringWithLength.length(), strlen(referenceString));
+ ASSERT_STREQ(referenceString, stringWithLength.data());
+}
+
+TEST(WTF, CStringUninitializedConstructor)
+{
+ char* buffer;
+ CString emptyString = CString::newUninitialized(0, buffer);
+ ASSERT_FALSE(emptyString.isNull());
+ ASSERT_EQ(buffer, emptyString.data());
+ ASSERT_EQ(buffer[0], 0);
+
+ const size_t length = 25;
+ CString uninitializedString = CString::newUninitialized(length, buffer);
+ ASSERT_FALSE(uninitializedString.isNull());
+ ASSERT_EQ(buffer, uninitializedString.data());
+ ASSERT_EQ(uninitializedString.data()[length], 0);
+}
+
+TEST(WTF, CStringZeroTerminated)
+{
+ const char* referenceString = "WebKit";
+ CString stringWithLength(referenceString, 3);
+ ASSERT_EQ(stringWithLength.data()[3], 0);
+}
+
+TEST(WTF, CStringCopyOnWrite)
+{
+ const char* initialString = "Webkit";
+ CString string(initialString);
+ CString copy = string;
+
+ string.mutableData()[3] = 'K';
+ ASSERT_TRUE(string != copy);
+ ASSERT_STREQ(string.data(), "WebKit");
+ ASSERT_STREQ(copy.data(), initialString);
+}
+
+TEST(WTF, CStringComparison)
+{
+ // Comparison with another CString.
+ CString a;
+ CString b;
+ ASSERT_TRUE(a == b);
+ ASSERT_FALSE(a != b);
+ a = "a";
+ b = CString();
+ ASSERT_FALSE(a == b);
+ ASSERT_TRUE(a != b);
+ a = "a";
+ b = "b";
+ ASSERT_FALSE(a == b);
+ ASSERT_TRUE(a != b);
+ a = "a";
+ b = "a";
+ ASSERT_TRUE(a == b);
+ ASSERT_FALSE(a != b);
+ a = "a";
+ b = "aa";
+ ASSERT_FALSE(a == b);
+ ASSERT_TRUE(a != b);
+ a = "";
+ b = "";
+ ASSERT_TRUE(a == b);
+ ASSERT_FALSE(a != b);
+ a = "";
+ b = CString();
+ ASSERT_FALSE(a == b);
+ ASSERT_TRUE(a != b);
+ a = "a";
+ b = "";
+ ASSERT_FALSE(a == b);
+ ASSERT_TRUE(a != b);
+
+ // Comparison with a const char*.
+ CString c;
+ const char* d = 0;
+ ASSERT_TRUE(c == d);
+ ASSERT_FALSE(c != d);
+ c = "c";
+ d = 0;
+ ASSERT_FALSE(c == d);
+ ASSERT_TRUE(c != d);
+ c = CString();
+ d = "d";
+ ASSERT_FALSE(c == d);
+ ASSERT_TRUE(c != d);
+ c = "c";
+ d = "d";
+ ASSERT_FALSE(c == d);
+ ASSERT_TRUE(c != d);
+ c = "c";
+ d = "c";
+ ASSERT_TRUE(c == d);
+ ASSERT_FALSE(c != d);
+ c = "c";
+ d = "cc";
+ ASSERT_FALSE(c == d);
+ ASSERT_TRUE(c != d);
+ c = "cc";
+ d = "c";
+ ASSERT_FALSE(c == d);
+ ASSERT_TRUE(c != d);
+ c = "";
+ d = "";
+ ASSERT_TRUE(c == d);
+ ASSERT_FALSE(c != d);
+ c = "";
+ d = 0;
+ ASSERT_FALSE(c == d);
+ ASSERT_TRUE(c != d);
+ c = CString();
+ d = "";
+ ASSERT_FALSE(c == d);
+ ASSERT_TRUE(c != d);
+ c = "a";
+ d = "";
+ ASSERT_FALSE(c == d);
+ ASSERT_TRUE(c != d);
+ c = "";
+ d = "b";
+ ASSERT_FALSE(c == d);
+ ASSERT_TRUE(c != d);
+}
diff --git a/Tools/TestWebKitAPI/Tests/WTF/CheckedArithmeticOperations.cpp b/Tools/TestWebKitAPI/Tests/WTF/CheckedArithmeticOperations.cpp
new file mode 100644
index 000000000..d6b548316
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/CheckedArithmeticOperations.cpp
@@ -0,0 +1,487 @@
+/*
+ * Copyright (C) 2011, 2015 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 <wtf/CheckedArithmetic.h>
+
+namespace TestWebKitAPI {
+
+class OverflowCrashLogger {
+protected:
+ void overflowed()
+ {
+ m_overflowCount++;
+ }
+
+ void clearOverflow()
+ {
+ m_overflowCount = 0;
+ }
+
+ static void crash()
+ {
+ s_didCrash = true;
+ }
+
+public:
+ void reset()
+ {
+ m_overflowCount = 0;
+ s_didCrash = false;
+ }
+
+ bool hasOverflowed() const { return m_overflowCount > 0; }
+ int overflowCount() const { return m_overflowCount; }
+
+ bool didCrash() const { return s_didCrash; }
+
+private:
+ int m_overflowCount { 0 };
+ static bool s_didCrash;
+};
+
+bool OverflowCrashLogger::s_didCrash = false;
+
+template <typename type>
+static void resetOverflow(Checked<type, OverflowCrashLogger>& value)
+{
+ value.reset();
+ value = 100;
+ value *= std::numeric_limits<type>::max();
+}
+
+#define CheckedArithmeticTest(type, Coercer, MixedSignednessTester) \
+ TEST(WTF, Checked_##type) \
+ { \
+ typedef Coercer<type> CoercerType; \
+ typedef MixedSignednessTester<type, CoercerType> MixedSignednessTesterType; \
+ CheckedArithmeticTester<type, CoercerType, MixedSignednessTesterType>::run(); \
+ }
+
+#define coerceLiteral(x) Coercer::coerce(x)
+
+template <typename type, typename Coercer, typename MixedSignednessTester>
+class CheckedArithmeticTester {
+public:
+ static void run()
+ {
+ Checked<type, RecordOverflow> value;
+ EXPECT_EQ(coerceLiteral(0), value.unsafeGet());
+ EXPECT_EQ(std::numeric_limits<type>::max(), (value + std::numeric_limits<type>::max()).unsafeGet());
+ EXPECT_EQ(std::numeric_limits<type>::max(), (std::numeric_limits<type>::max() + value).unsafeGet());
+ EXPECT_EQ(std::numeric_limits<type>::min(), (value + std::numeric_limits<type>::min()).unsafeGet());
+ EXPECT_EQ(std::numeric_limits<type>::min(), (std::numeric_limits<type>::min() + value).unsafeGet());
+
+ EXPECT_EQ(coerceLiteral(0), (value * coerceLiteral(0)).unsafeGet());
+ EXPECT_EQ(coerceLiteral(0), (coerceLiteral(0) * value).unsafeGet());
+ EXPECT_EQ(coerceLiteral(0), (value * value).unsafeGet());
+ EXPECT_EQ(coerceLiteral(0), (value - coerceLiteral(0)).unsafeGet());
+ EXPECT_EQ(coerceLiteral(0), (coerceLiteral(0) - value).unsafeGet());
+ EXPECT_EQ(coerceLiteral(0), (value - value).unsafeGet());
+ EXPECT_EQ(coerceLiteral(0), (value++).unsafeGet());
+ EXPECT_EQ(coerceLiteral(1), (value--).unsafeGet());
+ EXPECT_EQ(coerceLiteral(1), (++value).unsafeGet());
+ EXPECT_EQ(coerceLiteral(0), (--value).unsafeGet());
+ EXPECT_EQ(coerceLiteral(10), (value += coerceLiteral(10)).unsafeGet());
+ EXPECT_EQ(coerceLiteral(10), value.unsafeGet());
+ EXPECT_EQ(coerceLiteral(100), (value *= coerceLiteral(10)).unsafeGet());
+ EXPECT_EQ(coerceLiteral(100), value.unsafeGet());
+ EXPECT_EQ(coerceLiteral(0), (value -= coerceLiteral(100)).unsafeGet());
+ EXPECT_EQ(coerceLiteral(0), value.unsafeGet());
+ value = 10;
+ EXPECT_EQ(coerceLiteral(10), value.unsafeGet());
+ EXPECT_EQ(coerceLiteral(0), (value - coerceLiteral(10)).unsafeGet());
+ EXPECT_EQ(coerceLiteral(10), value.unsafeGet());
+
+ value = std::numeric_limits<type>::min();
+ EXPECT_EQ(true, (Checked<type, RecordOverflow>(value - coerceLiteral(1))).hasOverflowed());
+ EXPECT_EQ(true, !((value--).hasOverflowed()));
+ EXPECT_EQ(true, value.hasOverflowed());
+ value = std::numeric_limits<type>::max();
+ EXPECT_EQ(true, !value.hasOverflowed());
+ EXPECT_EQ(true, (Checked<type, RecordOverflow>(value + coerceLiteral(1))).hasOverflowed());
+ EXPECT_EQ(true, !(value++).hasOverflowed());
+ EXPECT_EQ(true, value.hasOverflowed());
+ value = std::numeric_limits<type>::max();
+ EXPECT_EQ(true, (value += coerceLiteral(1)).hasOverflowed());
+ EXPECT_EQ(true, value.hasOverflowed());
+
+ value = 10;
+ type _value = 0;
+ EXPECT_EQ(true, CheckedState::DidNotOverflow == (value * Checked<type, RecordOverflow>(0)).safeGet(_value));
+ _value = 0;
+ EXPECT_EQ(true, CheckedState::DidNotOverflow == (Checked<type, RecordOverflow>(0) * value).safeGet(_value));
+ _value = 0;
+ EXPECT_EQ(true, CheckedState::DidOverflow == (value * Checked<type, RecordOverflow>(std::numeric_limits<type>::max())).safeGet(_value));
+ _value = 0;
+ EXPECT_EQ(true, CheckedState::DidOverflow == (Checked<type, RecordOverflow>(std::numeric_limits<type>::max()) * value).safeGet(_value));
+ value = 0;
+ _value = 0;
+ EXPECT_EQ(true, CheckedState::DidNotOverflow == (value * Checked<type, RecordOverflow>(std::numeric_limits<type>::max())).safeGet(_value));
+ _value = 0;
+ EXPECT_EQ(true, CheckedState::DidNotOverflow == (Checked<type, RecordOverflow>(std::numeric_limits<type>::max()) * value).safeGet(_value));
+ value = 1;
+ _value = 0;
+ EXPECT_EQ(true, CheckedState::DidNotOverflow == (value * Checked<type, RecordOverflow>(std::numeric_limits<type>::max())).safeGet(_value));
+ _value = 0;
+ EXPECT_EQ(true, CheckedState::DidNotOverflow == (Checked<type, RecordOverflow>(std::numeric_limits<type>::max()) * value).safeGet(_value));
+ _value = 0;
+ value = 0;
+ EXPECT_EQ(true, CheckedState::DidNotOverflow == (value * Checked<type, RecordOverflow>(std::numeric_limits<type>::max())).safeGet(_value));
+ _value = 0;
+ EXPECT_EQ(true, CheckedState::DidNotOverflow == (Checked<type, RecordOverflow>(std::numeric_limits<type>::max()) * (type)0).safeGet(_value));
+ _value = 0;
+ value = 1;
+ EXPECT_EQ(true, CheckedState::DidNotOverflow == (value * Checked<type, RecordOverflow>(std::numeric_limits<type>::max())).safeGet(_value));
+ _value = 0;
+ EXPECT_EQ(true, CheckedState::DidNotOverflow == (Checked<type, RecordOverflow>(std::numeric_limits<type>::max()) * (type)1).safeGet(_value));
+ _value = 0;
+ value = 2;
+ EXPECT_EQ(true, CheckedState::DidOverflow == (value * Checked<type, RecordOverflow>(std::numeric_limits<type>::max())).safeGet(_value));
+ _value = 0;
+ EXPECT_EQ(true, CheckedState::DidOverflow == (Checked<type, RecordOverflow>(std::numeric_limits<type>::max()) * (type)2).safeGet(_value));
+ value = 10;
+ EXPECT_EQ(true, (value * Checked<type, RecordOverflow>(std::numeric_limits<type>::max())).hasOverflowed());
+
+
+ Checked<type, OverflowCrashLogger> nvalue; // to hold a not overflowed value.
+ Checked<type, OverflowCrashLogger> ovalue; // to hold an overflowed value.
+ bool unused;
+
+ _value = 75;
+ type _largeValue = 100;
+ type _smallValue = 50;
+
+ value = _smallValue;
+ nvalue = _value;
+ ovalue = _value;
+
+ // Make sure the OverflowCrashLogger is working as expected.
+ EXPECT_EQ(false, (ovalue.hasOverflowed()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), ovalue.hasOverflowed()));
+ EXPECT_EQ(false, (resetOverflow(ovalue), ovalue.didCrash()));
+ EXPECT_EQ(true, (unused = (ovalue == ovalue), ovalue.didCrash()));
+ EXPECT_EQ(false, (resetOverflow(ovalue), ovalue.didCrash()));
+
+ EXPECT_EQ(false, nvalue.hasOverflowed());
+ EXPECT_EQ(false, nvalue.didCrash());
+
+ // Test operator== that should not overflow nor crash.
+ EXPECT_EQ(true, (nvalue == nvalue));
+ EXPECT_EQ(true, (nvalue == Checked<type, OverflowCrashLogger>(_value)));
+ EXPECT_EQ(false, (nvalue == value));
+ EXPECT_EQ(true, (nvalue == _value));
+ EXPECT_EQ(false, (nvalue == Checked<type, OverflowCrashLogger>(std::numeric_limits<type>::max())));
+ EXPECT_EQ(false, (nvalue == std::numeric_limits<type>::max()));
+
+ EXPECT_EQ(false, nvalue.hasOverflowed());
+ EXPECT_EQ(false, nvalue.didCrash());
+
+ // Test operator!= that should not overflow nor crash.
+ EXPECT_EQ(false, (nvalue != nvalue));
+ EXPECT_EQ(false, (nvalue != Checked<type, OverflowCrashLogger>(_value)));
+ EXPECT_EQ(true, (nvalue != value));
+ EXPECT_EQ(false, (nvalue != _value));
+ EXPECT_EQ(true, (nvalue != Checked<type, OverflowCrashLogger>(std::numeric_limits<type>::max())));
+ EXPECT_EQ(true, (nvalue != std::numeric_limits<type>::max()));
+
+ EXPECT_EQ(false, nvalue.hasOverflowed());
+ EXPECT_EQ(false, nvalue.didCrash());
+
+ // Test operator< that should not overflow nor crash.
+ EXPECT_EQ(false, (nvalue < nvalue));
+ EXPECT_EQ(false, (nvalue < value));
+ EXPECT_EQ(true, (nvalue < Checked<type, OverflowCrashLogger>(_largeValue)));
+ EXPECT_EQ(false, (nvalue < Checked<type, OverflowCrashLogger>(_value)));
+ EXPECT_EQ(false, (nvalue < Checked<type, OverflowCrashLogger>(_smallValue)));
+ EXPECT_EQ(true, (nvalue < _largeValue));
+ EXPECT_EQ(false, (nvalue < _value));
+ EXPECT_EQ(false, (nvalue < _smallValue));
+ EXPECT_EQ(true, (nvalue < Checked<type, OverflowCrashLogger>(std::numeric_limits<type>::max())));
+ EXPECT_EQ(true, (nvalue < std::numeric_limits<type>::max()));
+
+ EXPECT_EQ(false, nvalue.hasOverflowed());
+ EXPECT_EQ(false, nvalue.didCrash());
+
+ // Test operator<= that should not overflow nor crash.
+ EXPECT_EQ(true, (nvalue <= nvalue));
+ EXPECT_EQ(false, (nvalue <= value));
+ EXPECT_EQ(true, (nvalue <= Checked<type, OverflowCrashLogger>(_largeValue)));
+ EXPECT_EQ(true, (nvalue <= Checked<type, OverflowCrashLogger>(_value)));
+ EXPECT_EQ(false, (nvalue <= Checked<type, OverflowCrashLogger>(_smallValue)));
+ EXPECT_EQ(true, (nvalue <= _largeValue));
+ EXPECT_EQ(true, (nvalue <= _value));
+ EXPECT_EQ(false, (nvalue <= _smallValue));
+ EXPECT_EQ(true, (nvalue <= Checked<type, OverflowCrashLogger>(std::numeric_limits<type>::max())));
+ EXPECT_EQ(true, (nvalue <= std::numeric_limits<type>::max()));
+
+ EXPECT_EQ(false, nvalue.hasOverflowed());
+ EXPECT_EQ(false, nvalue.didCrash());
+
+ // Test operator> that should not overflow nor crash.
+ EXPECT_EQ(false, (nvalue > nvalue));
+ EXPECT_EQ(true, (nvalue > value));
+ EXPECT_EQ(false, (nvalue > Checked<type, OverflowCrashLogger>(_largeValue)));
+ EXPECT_EQ(false, (nvalue > Checked<type, OverflowCrashLogger>(_value)));
+ EXPECT_EQ(true, (nvalue > Checked<type, OverflowCrashLogger>(_smallValue)));
+ EXPECT_EQ(false, (nvalue > _largeValue));
+ EXPECT_EQ(false, (nvalue > _value));
+ EXPECT_EQ(true, (nvalue > _smallValue));
+ EXPECT_EQ(false, (nvalue > Checked<type, OverflowCrashLogger>(std::numeric_limits<type>::max())));
+ EXPECT_EQ(false, (nvalue > std::numeric_limits<type>::max()));
+
+ EXPECT_EQ(false, nvalue.hasOverflowed());
+ EXPECT_EQ(false, nvalue.didCrash());
+
+ // Test operator>= that should not overflow nor crash.
+ EXPECT_EQ(true, (nvalue >= nvalue));
+ EXPECT_EQ(true, (nvalue >= value));
+ EXPECT_EQ(false, (nvalue >= Checked<type, OverflowCrashLogger>(_largeValue)));
+ EXPECT_EQ(true, (nvalue >= Checked<type, OverflowCrashLogger>(_value)));
+ EXPECT_EQ(true, (nvalue >= Checked<type, OverflowCrashLogger>(_smallValue)));
+ EXPECT_EQ(false, (nvalue >= _largeValue));
+ EXPECT_EQ(true, (nvalue >= _value));
+ EXPECT_EQ(true, (nvalue >= _smallValue));
+ EXPECT_EQ(false, (nvalue >= Checked<type, OverflowCrashLogger>(std::numeric_limits<type>::max())));
+ EXPECT_EQ(false, (nvalue >= std::numeric_limits<type>::max()));
+
+ EXPECT_EQ(false, nvalue.hasOverflowed());
+ EXPECT_EQ(false, nvalue.didCrash());
+
+ // Test operator== with an overflowed value.
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue == ovalue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue == Checked<type, OverflowCrashLogger>(_value)), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue == value), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue == _value), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue == _value * std::numeric_limits<type>::max()), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue == Checked<type, OverflowCrashLogger>(std::numeric_limits<type>::max())), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue == std::numeric_limits<type>::max()), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue == nvalue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (nvalue == ovalue), ovalue.didCrash()));
+
+ EXPECT_EQ(false, nvalue.hasOverflowed());
+
+ // Test operator!= with an overflowed value.
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue != ovalue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue != Checked<type, OverflowCrashLogger>(_value)), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue != value), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue != _value), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue != _value * std::numeric_limits<type>::max()), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue != Checked<type, OverflowCrashLogger>(std::numeric_limits<type>::max())), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue != std::numeric_limits<type>::max()), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue != nvalue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (nvalue != ovalue), ovalue.didCrash()));
+
+ EXPECT_EQ(false, nvalue.hasOverflowed());
+
+ // Test operator< with an overflowed value.
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue < ovalue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue < value), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue < Checked<type, OverflowCrashLogger>(_largeValue)), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue < Checked<type, OverflowCrashLogger>(_value)), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue < Checked<type, OverflowCrashLogger>(_smallValue)), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue < _largeValue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue < _value), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue < _smallValue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue < Checked<type, OverflowCrashLogger>(std::numeric_limits<type>::max())), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue < std::numeric_limits<type>::max()), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue < nvalue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (nvalue < ovalue), ovalue.didCrash()));
+
+ EXPECT_EQ(false, nvalue.hasOverflowed());
+
+ // Test operator<= with an overflowed value.
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue <= ovalue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue <= value), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue <= Checked<type, OverflowCrashLogger>(_largeValue)), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue <= Checked<type, OverflowCrashLogger>(_value)), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue <= Checked<type, OverflowCrashLogger>(_smallValue)), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue <= _largeValue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue <= _value), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue <= _smallValue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue <= Checked<type, OverflowCrashLogger>(std::numeric_limits<type>::max())), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue <= std::numeric_limits<type>::max()), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue <= nvalue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (nvalue <= ovalue), ovalue.didCrash()));
+
+ EXPECT_EQ(false, nvalue.hasOverflowed());
+
+ // Test operator> with an overflowed value.
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue > ovalue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue > value), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue > Checked<type, OverflowCrashLogger>(_largeValue)), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue > Checked<type, OverflowCrashLogger>(_value)), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue > Checked<type, OverflowCrashLogger>(_smallValue)), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue > _largeValue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue > _value), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue > _smallValue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue > Checked<type, OverflowCrashLogger>(std::numeric_limits<type>::max())), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue > std::numeric_limits<type>::max()), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue > nvalue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (nvalue > ovalue), ovalue.didCrash()));
+
+ EXPECT_EQ(false, nvalue.hasOverflowed());
+
+ // Test operator>= with an overflowed value.
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue >= ovalue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue >= value), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue >= Checked<type, OverflowCrashLogger>(_largeValue)), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue >= Checked<type, OverflowCrashLogger>(_value)), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue >= Checked<type, OverflowCrashLogger>(_smallValue)), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue >= _largeValue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue >= _value), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue >= _smallValue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue >= Checked<type, OverflowCrashLogger>(std::numeric_limits<type>::max())), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue >= std::numeric_limits<type>::max()), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (ovalue >= nvalue), ovalue.didCrash()));
+ EXPECT_EQ(true, (resetOverflow(ovalue), unused = (nvalue >= ovalue), ovalue.didCrash()));
+
+ EXPECT_EQ(false, nvalue.hasOverflowed());
+
+ MixedSignednessTester::run();
+ }
+};
+
+template <typename type, typename Coercer>
+class AllowMixedSignednessTest {
+public:
+ static void run()
+ {
+ Checked<type, RecordOverflow> value;
+ value = 10;
+
+ EXPECT_EQ(coerceLiteral(0), (value + -10).unsafeGet());
+ EXPECT_EQ(0U, (value - 10U).unsafeGet());
+ EXPECT_EQ(coerceLiteral(0), (-10 + value).unsafeGet());
+ EXPECT_EQ(0U, (10U - value).unsafeGet());
+ value = std::numeric_limits<type>::min();
+ EXPECT_EQ(true, (Checked<type, RecordOverflow>(value - 1)).hasOverflowed());
+ EXPECT_EQ(true, !(value--).hasOverflowed());
+ EXPECT_EQ(true, value.hasOverflowed());
+ value = std::numeric_limits<type>::max();
+ EXPECT_EQ(true, !value.hasOverflowed());
+ EXPECT_EQ(true, (Checked<type, RecordOverflow>(value + 1)).hasOverflowed());
+ EXPECT_EQ(true, !(value++).hasOverflowed());
+ EXPECT_EQ(true, value.hasOverflowed());
+ value = std::numeric_limits<type>::max();
+ EXPECT_EQ(true, (value += 1).hasOverflowed());
+ EXPECT_EQ(true, value.hasOverflowed());
+ value = std::numeric_limits<type>::min();
+ EXPECT_EQ(true, (value - 1U).hasOverflowed());
+ EXPECT_EQ(true, !(value--).hasOverflowed());
+ EXPECT_EQ(true, value.hasOverflowed());
+ value = std::numeric_limits<type>::max();
+ EXPECT_EQ(true, !value.hasOverflowed());
+ EXPECT_EQ(true, (Checked<type, RecordOverflow>(value + 1U)).hasOverflowed());
+ EXPECT_EQ(true, !(value++).hasOverflowed());
+ EXPECT_EQ(true, value.hasOverflowed());
+ value = std::numeric_limits<type>::max();
+ EXPECT_EQ(true, (value += 1U).hasOverflowed());
+ EXPECT_EQ(true, value.hasOverflowed());
+ }
+};
+
+template <typename type, typename Coercer>
+class IgnoreMixedSignednessTest {
+public:
+ static void run() { }
+};
+
+template <typename type> class CoerceLiteralToUnsigned {
+public:
+ static unsigned coerce(type x) { return static_cast<unsigned>(x); }
+};
+
+template <typename type> class CoerceLiteralNop {
+public:
+ static type coerce(type x) { return x; }
+};
+
+CheckedArithmeticTest(int8_t, CoerceLiteralNop, IgnoreMixedSignednessTest)
+CheckedArithmeticTest(int16_t, CoerceLiteralNop, IgnoreMixedSignednessTest)
+CheckedArithmeticTest(int32_t, CoerceLiteralNop, AllowMixedSignednessTest)
+CheckedArithmeticTest(uint32_t, CoerceLiteralToUnsigned, AllowMixedSignednessTest)
+CheckedArithmeticTest(int64_t, CoerceLiteralNop, IgnoreMixedSignednessTest)
+CheckedArithmeticTest(uint64_t, CoerceLiteralToUnsigned, IgnoreMixedSignednessTest)
+
+TEST(CheckedArithmeticTest, IsInBounds)
+{
+ // bigger precision, signed, signed
+ EXPECT_TRUE(WTF::isInBounds<int32_t>(std::numeric_limits<int16_t>::max()));
+ EXPECT_TRUE(WTF::isInBounds<int32_t>(std::numeric_limits<int16_t>::min()));
+
+ // bigger precision, unsigned, signed
+ EXPECT_TRUE(WTF::isInBounds<uint32_t>(std::numeric_limits<int32_t>::max()));
+ EXPECT_FALSE(WTF::isInBounds<uint32_t>(std::numeric_limits<int16_t>::min()));
+
+ EXPECT_FALSE(WTF::isInBounds<uint32_t>((int32_t)-1));
+ EXPECT_FALSE(WTF::isInBounds<uint16_t>((int32_t)-1));
+ EXPECT_FALSE(WTF::isInBounds<unsigned long>((int)-1));
+
+ EXPECT_TRUE(WTF::isInBounds<uint32_t>((int32_t)1));
+ EXPECT_TRUE(WTF::isInBounds<uint32_t>((int16_t)1));
+ EXPECT_TRUE(WTF::isInBounds<unsigned>((int)1));
+
+ EXPECT_TRUE(WTF::isInBounds<uint32_t>((int32_t)0));
+ EXPECT_TRUE(WTF::isInBounds<uint16_t>((int32_t)0));
+ EXPECT_TRUE(WTF::isInBounds<uint32_t>((int16_t)0));
+ EXPECT_TRUE(WTF::isInBounds<unsigned>((int)0));
+
+ EXPECT_TRUE(WTF::isInBounds<uint32_t>(std::numeric_limits<int32_t>::max()));
+ EXPECT_TRUE(WTF::isInBounds<uint32_t>(std::numeric_limits<int16_t>::max()));
+ EXPECT_TRUE(WTF::isInBounds<unsigned>(std::numeric_limits<int>::max()));
+
+ // bigger precision, signed, unsigned
+ EXPECT_TRUE(WTF::isInBounds<int32_t>(std::numeric_limits<uint16_t>::max()));
+ EXPECT_FALSE(WTF::isInBounds<int32_t>(std::numeric_limits<uint32_t>::max()));
+ EXPECT_TRUE(WTF::isInBounds<int32_t>((uint32_t)0));
+
+ // bigger precision, unsigned, unsigned
+ EXPECT_TRUE(WTF::isInBounds<uint32_t>(std::numeric_limits<uint16_t>::max()));
+ EXPECT_TRUE(WTF::isInBounds<uint32_t>(std::numeric_limits<uint16_t>::min()));
+
+ // lower precision, signed signed
+ EXPECT_FALSE(WTF::isInBounds<int16_t>(std::numeric_limits<int32_t>::max()));
+ EXPECT_FALSE(WTF::isInBounds<int16_t>(std::numeric_limits<int32_t>::min()));
+ EXPECT_TRUE(WTF::isInBounds<int16_t>((int32_t)-1));
+ EXPECT_TRUE(WTF::isInBounds<int16_t>((int32_t)0));
+ EXPECT_TRUE(WTF::isInBounds<int16_t>((int32_t)1));
+ // lower precision, unsigned, signed
+ EXPECT_FALSE(WTF::isInBounds<uint16_t>(std::numeric_limits<int32_t>::max()));
+ EXPECT_FALSE(WTF::isInBounds<uint16_t>(std::numeric_limits<int32_t>::min()));
+ EXPECT_FALSE(WTF::isInBounds<uint16_t>((int32_t)-1));
+ EXPECT_TRUE(WTF::isInBounds<uint16_t>((int32_t)0));
+ EXPECT_TRUE(WTF::isInBounds<uint16_t>((int32_t)1));
+ // lower precision, signed, unsigned
+ EXPECT_FALSE(WTF::isInBounds<int16_t>(std::numeric_limits<uint32_t>::max()));
+ EXPECT_TRUE(WTF::isInBounds<int16_t>((uint32_t)0));
+ EXPECT_TRUE(WTF::isInBounds<int16_t>((uint32_t)1));
+ // lower precision, unsigned, unsigned
+ EXPECT_FALSE(WTF::isInBounds<uint16_t>(std::numeric_limits<uint32_t>::max()));
+ EXPECT_TRUE(WTF::isInBounds<uint16_t>((uint32_t)0));
+ EXPECT_TRUE(WTF::isInBounds<uint16_t>((uint32_t)1));
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/Condition.cpp b/Tools/TestWebKitAPI/Tests/WTF/Condition.cpp
new file mode 100644
index 000000000..c450d8953
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/Condition.cpp
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2015 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 <mutex>
+#include <thread>
+#include <wtf/Condition.h>
+#include <wtf/DataLog.h>
+#include <wtf/Deque.h>
+#include <wtf/Lock.h>
+#include <wtf/StringPrintStream.h>
+#include <wtf/Threading.h>
+#include <wtf/Vector.h>
+
+using namespace WTF;
+
+namespace TestWebKitAPI {
+
+namespace {
+
+const bool verbose = false;
+
+enum NotifyStyle {
+ AlwaysNotifyOne,
+ TacticallyNotifyAll
+};
+
+template<typename Functor>
+void wait(Condition& condition, std::unique_lock<Lock>& locker, const Functor& predicate, std::chrono::microseconds timeout)
+{
+ if (timeout == std::chrono::microseconds::max())
+ condition.wait(locker, predicate);
+ else {
+ // This tests timeouts in the sense that it verifies that we can call wait() again after a
+ // timeout happened. That's a non-trivial piece of functionality since upon timeout the
+ // ParkingLot has to remove us from the queue.
+ while (!predicate())
+ condition.waitFor(locker, timeout, predicate);
+ }
+}
+
+void notify(NotifyStyle notifyStyle, Condition& condition, bool shouldNotify)
+{
+ switch (notifyStyle) {
+ case AlwaysNotifyOne:
+ condition.notifyOne();
+ break;
+ case TacticallyNotifyAll:
+ if (shouldNotify)
+ condition.notifyAll();
+ break;
+ }
+}
+
+void runTest(
+ unsigned numProducers,
+ unsigned numConsumers,
+ unsigned maxQueueSize,
+ unsigned numMessagesPerProducer,
+ NotifyStyle notifyStyle,
+ std::chrono::microseconds timeout = std::chrono::microseconds::max(),
+ std::chrono::microseconds delay = std::chrono::microseconds::zero())
+{
+ Deque<unsigned> queue;
+ bool shouldContinue = true;
+ Lock lock;
+ Condition emptyCondition;
+ Condition fullCondition;
+
+ Vector<ThreadIdentifier> consumerThreads;
+ Vector<ThreadIdentifier> producerThreads;
+
+ Vector<unsigned> received;
+ Lock receivedLock;
+
+ for (unsigned i = numConsumers; i--;) {
+ ThreadIdentifier threadIdentifier = createThread(
+ "Consumer thread",
+ [&] () {
+ for (;;) {
+ unsigned result;
+ unsigned shouldNotify = false;
+ {
+ std::unique_lock<Lock> locker(lock);
+ wait(
+ emptyCondition, locker,
+ [&] () {
+ if (verbose)
+ dataLog(toString(currentThread(), ": Checking consumption predicate with shouldContinue = ", shouldContinue, ", queue.size() == ", queue.size(), "\n"));
+ return !shouldContinue || !queue.isEmpty();
+ },
+ timeout);
+ if (!shouldContinue && queue.isEmpty())
+ return;
+ shouldNotify = queue.size() == maxQueueSize;
+ result = queue.takeFirst();
+ }
+ notify(notifyStyle, fullCondition, shouldNotify);
+
+ {
+ std::lock_guard<Lock> locker(receivedLock);
+ received.append(result);
+ }
+ }
+ });
+ consumerThreads.append(threadIdentifier);
+ }
+
+ std::this_thread::sleep_for(delay);
+
+ for (unsigned i = numProducers; i--;) {
+ ThreadIdentifier threadIdentifier = createThread(
+ "Producer Thread",
+ [&] () {
+ for (unsigned i = 0; i < numMessagesPerProducer; ++i) {
+ bool shouldNotify = false;
+ {
+ std::unique_lock<Lock> locker(lock);
+ wait(
+ fullCondition, locker,
+ [&] () {
+ if (verbose)
+ dataLog(toString(currentThread(), ": Checking production predicate with shouldContinue = ", shouldContinue, ", queue.size() == ", queue.size(), "\n"));
+ return queue.size() < maxQueueSize;
+ },
+ timeout);
+ shouldNotify = queue.isEmpty();
+ queue.append(i);
+ }
+ notify(notifyStyle, emptyCondition, shouldNotify);
+ }
+ });
+ producerThreads.append(threadIdentifier);
+ }
+
+ for (ThreadIdentifier threadIdentifier : producerThreads)
+ waitForThreadCompletion(threadIdentifier);
+
+ {
+ std::lock_guard<Lock> locker(lock);
+ shouldContinue = false;
+ }
+ emptyCondition.notifyAll();
+
+ for (ThreadIdentifier threadIdentifier : consumerThreads)
+ waitForThreadCompletion(threadIdentifier);
+
+ EXPECT_EQ(numProducers * numMessagesPerProducer, received.size());
+ std::sort(received.begin(), received.end());
+ for (unsigned messageIndex = 0; messageIndex < numMessagesPerProducer; ++messageIndex) {
+ for (unsigned producerIndex = 0; producerIndex < numProducers; ++producerIndex)
+ EXPECT_EQ(messageIndex, received[messageIndex * numProducers + producerIndex]);
+ }
+}
+
+} // anonymous namespace
+
+TEST(WTF_Condition, OneProducerOneConsumerOneSlot)
+{
+ runTest(1, 1, 1, 100000, TacticallyNotifyAll);
+}
+
+TEST(WTF_Condition, OneProducerOneConsumerOneSlotTimeout)
+{
+ runTest(
+ 1, 1, 1, 100000, TacticallyNotifyAll,
+ std::chrono::microseconds(10000),
+ std::chrono::microseconds(1000000));
+}
+
+TEST(WTF_Condition, OneProducerOneConsumerHundredSlots)
+{
+ runTest(1, 1, 100, 1000000, TacticallyNotifyAll);
+}
+
+TEST(WTF_Condition, TenProducersOneConsumerOneSlot)
+{
+ runTest(10, 1, 1, 10000, TacticallyNotifyAll);
+}
+
+TEST(WTF_Condition, TenProducersOneConsumerHundredSlotsNotifyAll)
+{
+ runTest(10, 1, 100, 10000, TacticallyNotifyAll);
+}
+
+TEST(WTF_Condition, TenProducersOneConsumerHundredSlotsNotifyOne)
+{
+ runTest(10, 1, 100, 10000, AlwaysNotifyOne);
+}
+
+TEST(WTF_Condition, OneProducerTenConsumersOneSlot)
+{
+ runTest(1, 10, 1, 10000, TacticallyNotifyAll);
+}
+
+TEST(WTF_Condition, OneProducerTenConsumersHundredSlotsNotifyAll)
+{
+ runTest(1, 10, 100, 100000, TacticallyNotifyAll);
+}
+
+TEST(WTF_Condition, OneProducerTenConsumersHundredSlotsNotifyOne)
+{
+ runTest(1, 10, 100, 100000, AlwaysNotifyOne);
+}
+
+TEST(WTF_Condition, TenProducersTenConsumersOneSlot)
+{
+ runTest(10, 10, 1, 50000, TacticallyNotifyAll);
+}
+
+TEST(WTF_Condition, TenProducersTenConsumersHundredSlotsNotifyAll)
+{
+ runTest(10, 10, 100, 50000, TacticallyNotifyAll);
+}
+
+TEST(WTF_Condition, TenProducersTenConsumersHundredSlotsNotifyOne)
+{
+ runTest(10, 10, 100, 50000, AlwaysNotifyOne);
+}
+
+TEST(WTF_Condition, TimeoutTimesOut)
+{
+ Lock lock;
+ Condition condition;
+
+ lock.lock();
+ bool result = condition.waitFor(
+ lock, std::chrono::microseconds(10000), [] () -> bool { return false; });
+ lock.unlock();
+
+ EXPECT_FALSE(result);
+}
+
+} // namespace TestWebKitAPI
+
diff --git a/Tools/TestWebKitAPI/Tests/WTF/DateMath.cpp b/Tools/TestWebKitAPI/Tests/WTF/DateMath.cpp
new file mode 100644
index 000000000..463041d48
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/DateMath.cpp
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2015 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 "Test.h"
+#include <wtf/DateMath.h>
+
+namespace TestWebKitAPI {
+
+// Note: The results of these function look weird if you do not understand the following mappings:
+// dayOfWeek: [0, 6] 0 being Monday, day: [1, 31], month: [0, 11], year: ex: 2011,
+// hours: [0, 23], minutes: [0, 59], seconds: [0, 59], utcOffset: [-720,720].
+
+TEST(WTF_DateMath, dateToDaysFrom1970)
+{
+ EXPECT_EQ(0.0, dateToDaysFrom1970(1970, 0, 1));
+ EXPECT_EQ(157.0, dateToDaysFrom1970(1970, 5, 7));
+ EXPECT_EQ(-145.0, dateToDaysFrom1970(1969, 7, 9));
+ EXPECT_EQ(16322, dateToDaysFrom1970(2014, 8, 9));
+}
+
+
+TEST(WTF_DateMath, isLeapYear)
+{
+ EXPECT_TRUE(isLeapYear(1804));
+ EXPECT_FALSE(isLeapYear(1900));
+ EXPECT_TRUE(isLeapYear(1968));
+ EXPECT_TRUE(isLeapYear(1976));
+ EXPECT_TRUE(isLeapYear(2000));
+ EXPECT_FALSE(isLeapYear(2010));
+ EXPECT_TRUE(isLeapYear(2012));
+ EXPECT_FALSE(isLeapYear(2100));
+}
+
+TEST(WTF_DateMath, msToYear)
+{
+ EXPECT_EQ(1962, msToYear(-220953600000));
+ EXPECT_EQ(1970, msToYear(0));
+ EXPECT_EQ(1970, msToYear(100));
+ EXPECT_EQ(1977, msToYear(220953600000));
+ EXPECT_EQ(2013, msToYear(1365318000000));
+}
+
+TEST(WTF_DateMath, msToDays)
+{
+ EXPECT_EQ(0, msToDays(0));
+ EXPECT_EQ(2557, msToDays(220953600000));
+ EXPECT_EQ(255, msToDays(22095360000));
+ EXPECT_EQ(25, msToDays(2209536000));
+ EXPECT_EQ(2, msToDays(220953600));
+ EXPECT_EQ(0, msToDays(22095360));
+ EXPECT_EQ(0, msToDays(2209536));
+}
+
+TEST(WTF_DateMath, msToMinutes)
+{
+ EXPECT_EQ(0, msToMinutes(0));
+ EXPECT_EQ(0, msToMinutes(220953600000));
+ EXPECT_EQ(36, msToMinutes(22095360000));
+ EXPECT_EQ(36, msToMinutes(22095360000));
+ EXPECT_EQ(45, msToMinutes(2209536000));
+ EXPECT_EQ(22, msToMinutes(220953600));
+ EXPECT_EQ(8, msToMinutes(22095360));
+ EXPECT_EQ(36, msToMinutes(2209536));
+}
+
+TEST(WTF_DateMath, msToHours)
+{
+ EXPECT_EQ(0, msToHours(0));
+ EXPECT_EQ(8, msToHours(220953600000));
+ EXPECT_EQ(17, msToHours(22095360000));
+ EXPECT_EQ(13, msToHours(2209536000));
+ EXPECT_EQ(13, msToHours(220953600));
+ EXPECT_EQ(6, msToHours(22095360));
+ EXPECT_EQ(0, msToHours(2209536));
+}
+
+TEST(WTF_DateMath, dayInYear)
+{
+ EXPECT_EQ(59, dayInYear(2015, 2, 1));
+ EXPECT_EQ(60, dayInYear(2012, 2, 1));
+ EXPECT_EQ(0, dayInYear(2015, 0, 1));
+ EXPECT_EQ(31, dayInYear(2015, 1, 1));
+}
+
+TEST(WTF_DateMath, monthFromDayInYear)
+{
+ EXPECT_EQ(2, monthFromDayInYear(59, false));
+ EXPECT_EQ(1, monthFromDayInYear(59, true));
+ EXPECT_EQ(2, monthFromDayInYear(60, true));
+ EXPECT_EQ(0, monthFromDayInYear(0, false));
+ EXPECT_EQ(0, monthFromDayInYear(0, true));
+ EXPECT_EQ(1, monthFromDayInYear(31, true));
+ EXPECT_EQ(1, monthFromDayInYear(31, false));
+}
+
+TEST(WTF_DateMath, dayInMonthFromDayInYear)
+{
+ EXPECT_EQ(1, dayInMonthFromDayInYear(0, false));
+ EXPECT_EQ(1, dayInMonthFromDayInYear(0, true));
+ EXPECT_EQ(1, dayInMonthFromDayInYear(59, false));
+ EXPECT_EQ(29, dayInMonthFromDayInYear(59, true));
+ EXPECT_EQ(1, dayInMonthFromDayInYear(60, true));
+ EXPECT_EQ(1, dayInMonthFromDayInYear(0, false));
+ EXPECT_EQ(1, dayInMonthFromDayInYear(0, true));
+ EXPECT_EQ(31, dayInMonthFromDayInYear(30, true));
+ EXPECT_EQ(31, dayInMonthFromDayInYear(30, false));
+ EXPECT_EQ(31, dayInMonthFromDayInYear(365, true));
+ EXPECT_EQ(32, dayInMonthFromDayInYear(365, false));
+ EXPECT_EQ(32, dayInMonthFromDayInYear(366, true));
+}
+
+TEST(WTF_DateMath, calculateLocalTimeOffset)
+{
+ // DST Start: April 30, 1967 (02:00 am)
+ LocalTimeOffset dstStart1967 = calculateLocalTimeOffset(-84301200000, WTF::LocalTime);
+ EXPECT_TRUE(dstStart1967.isDST);
+ EXPECT_EQ(-25200000, dstStart1967.offset);
+
+ // November 1, 1967 (02:00 am)
+ LocalTimeOffset dstAlmostEnd1967 = calculateLocalTimeOffset(-68317200000, WTF::LocalTime);
+ EXPECT_TRUE(dstAlmostEnd1967.isDST);
+ EXPECT_EQ(-25200000, dstAlmostEnd1967.offset);
+
+ // DST End: November 11, 1967 (02:00 am)
+ LocalTimeOffset dstEnd1967 = calculateLocalTimeOffset(-67536000000, WTF::LocalTime);
+ EXPECT_FALSE(dstEnd1967.isDST);
+ EXPECT_EQ(-25200000, dstStart1967.offset);
+
+ // DST Start: April 3, 1988 (02:00 am)
+ LocalTimeOffset dstStart1988 = calculateLocalTimeOffset(576054000000, WTF::LocalTime);
+ EXPECT_TRUE(dstStart1988.isDST);
+ EXPECT_EQ(-25200000, dstStart1988.offset);
+
+ // DST End: November 4, 2012 (02:00 am)
+ LocalTimeOffset dstEnd2012 = calculateLocalTimeOffset(1352012400000, WTF::LocalTime);
+ EXPECT_FALSE(dstEnd2012.isDST);
+ EXPECT_EQ(-28800000, dstEnd2012.offset);
+
+ // DST Begin: March 8, 2015
+ LocalTimeOffset dstBegin2015 = calculateLocalTimeOffset(1425801600000, WTF::LocalTime);
+ EXPECT_TRUE(dstBegin2015.isDST);
+ EXPECT_EQ(-25200000, dstBegin2015.offset);
+
+ LocalTimeOffset dstBegin2015UTC = calculateLocalTimeOffset(1425801600000, WTF::UTCTime);
+ EXPECT_FALSE(dstBegin2015UTC.isDST);
+ EXPECT_EQ(-28800000, dstBegin2015UTC.offset);
+
+ // DST End: November 1, 2015
+ LocalTimeOffset dstEnd2015 = calculateLocalTimeOffset(1446361200000, WTF::LocalTime);
+ EXPECT_FALSE(dstEnd2015.isDST);
+ EXPECT_EQ(-28800000, dstEnd2015.offset);
+
+ // DST Begin: March 13, 2016
+ LocalTimeOffset dstBegin2016 = calculateLocalTimeOffset(1458111600000, WTF::LocalTime);
+ EXPECT_TRUE(dstBegin2016.isDST);
+ EXPECT_EQ(-25200000, dstBegin2016.offset);
+
+ // DST End: November 6, 2016
+ LocalTimeOffset dstEnd2016 = calculateLocalTimeOffset(1478415600000, WTF::LocalTime);
+ EXPECT_FALSE(dstEnd2016.isDST);
+ EXPECT_EQ(-28800000, dstEnd2016.offset);
+
+ // DST Begin: March 12, 2017
+ LocalTimeOffset dstBegin2017 = calculateLocalTimeOffset(1489305600000, WTF::LocalTime);
+ EXPECT_TRUE(dstBegin2017.isDST);
+ EXPECT_EQ(-25200000, dstBegin2017.offset);
+
+ // DST End: November 5, 2017
+ LocalTimeOffset dstEnd2017 = calculateLocalTimeOffset(1509865200000, WTF::LocalTime);
+ EXPECT_FALSE(dstEnd2017.isDST);
+ EXPECT_EQ(-28800000, dstEnd2017.offset);
+
+ // DST Begin: March 11, 2018
+ LocalTimeOffset dstBegin2018 = calculateLocalTimeOffset(1520755200000, WTF::LocalTime);
+ EXPECT_TRUE(dstBegin2018.isDST);
+ EXPECT_EQ(-25200000, dstBegin2018.offset);
+
+ // DST End: November 4, 2018
+ LocalTimeOffset dstEnd2018 = calculateLocalTimeOffset(1541314800000, WTF::LocalTime);
+ EXPECT_FALSE(dstEnd2018.isDST);
+ EXPECT_EQ(-28800000, dstEnd2018.offset);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/Deque.cpp b/Tools/TestWebKitAPI/Tests/WTF/Deque.cpp
new file mode 100644
index 000000000..db9b0ac13
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/Deque.cpp
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2011 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 "MoveOnly.h"
+#include <wtf/Deque.h>
+
+namespace TestWebKitAPI {
+
+TEST(WTF_Deque, Iterator)
+{
+ Deque<int> deque;
+ deque.append(11);
+ deque.prepend(10);
+ deque.append(12);
+ deque.append(13);
+
+ Deque<int>::iterator it = deque.begin();
+ Deque<int>::iterator end = deque.end();
+ EXPECT_TRUE(end != it);
+
+ EXPECT_EQ(10, *it);
+ ++it;
+ EXPECT_EQ(11, *it);
+ ++it;
+ EXPECT_EQ(12, *it);
+ ++it;
+ EXPECT_EQ(13, *it);
+ ++it;
+
+ EXPECT_TRUE(end == it);
+}
+
+TEST(WTF_Deque, InitializerList)
+{
+ Deque<int> deque = { 1, 2, 3, 4 };
+
+ EXPECT_EQ(4u, deque.size());
+
+ auto it = deque.begin();
+ auto end = deque.end();
+ EXPECT_TRUE(end != it);
+
+ EXPECT_EQ(1, *it);
+ ++it;
+ EXPECT_EQ(2, *it);
+ ++it;
+ EXPECT_EQ(3, *it);
+ ++it;
+ EXPECT_EQ(4, *it);
+ ++it;
+
+ EXPECT_TRUE(end == it);
+}
+
+TEST(WTF, DequeReverseIterator)
+{
+ Deque<int> deque;
+ deque.append(11);
+ deque.prepend(10);
+ deque.append(12);
+ deque.append(13);
+
+ Deque<int>::reverse_iterator it = deque.rbegin();
+ Deque<int>::reverse_iterator end = deque.rend();
+ EXPECT_TRUE(end != it);
+
+ EXPECT_EQ(13, *it);
+ ++it;
+ EXPECT_EQ(12, *it);
+ ++it;
+ EXPECT_EQ(11, *it);
+ ++it;
+ EXPECT_EQ(10, *it);
+ ++it;
+
+ EXPECT_TRUE(end == it);
+}
+
+TEST(WTF_Deque, Remove)
+{
+ Deque<int> deque;
+ deque.append(11);
+ deque.prepend(10);
+ deque.append(12);
+ deque.append(13);
+
+ EXPECT_EQ(10, deque.first());
+ EXPECT_EQ(13, deque.last());
+
+ deque.removeLast();
+ EXPECT_EQ(10, deque.first());
+ EXPECT_EQ(12, deque.last());
+
+ deque.removeFirst();
+ EXPECT_EQ(11, deque.first());
+ EXPECT_EQ(12, deque.last());
+
+ deque.removeFirst();
+ EXPECT_EQ(12, deque.first());
+ EXPECT_EQ(12, deque.last());
+
+ deque.removeLast();
+ EXPECT_TRUE(deque.isEmpty());
+}
+
+TEST(WTF_Deque, MoveOnly)
+{
+ Deque<MoveOnly> deque;
+
+ deque.append(MoveOnly(1));
+ deque.prepend(MoveOnly(0));
+
+ EXPECT_EQ(0U, deque.first().value());
+ EXPECT_EQ(1U, deque.last().value());
+
+ auto first = deque.takeFirst();
+ EXPECT_EQ(0U, first.value());
+
+ auto last = deque.takeLast();
+ EXPECT_EQ(1U, last.value());
+}
+
+TEST(WTF_Deque, MoveConstructor)
+{
+ Deque<MoveOnly, 4> deque;
+
+ for (unsigned i = 0; i < 10; ++i)
+ deque.append(MoveOnly(i));
+
+ EXPECT_EQ(10u, deque.size());
+
+ Deque<MoveOnly, 4> deque2 = WTF::move(deque);
+
+ EXPECT_EQ(10u, deque2.size());
+
+ unsigned i = 0;
+ for (auto& element : deque2) {
+ EXPECT_EQ(i, element.value());
+ ++i;
+ }
+}
+
+TEST(WTF_Deque, MoveAssignmentOperator)
+{
+ Deque<MoveOnly, 4> deque1;
+
+ for (unsigned i = 0; i < 10; ++i)
+ deque1.append(MoveOnly(i));
+
+ EXPECT_EQ(10u, deque1.size());
+
+ Deque<MoveOnly, 4> deque2;
+ for (unsigned i = 0; i < 10; ++i)
+ deque2.append(MoveOnly(i * 2));
+
+ deque1 = WTF::move(deque2);
+
+ EXPECT_EQ(10u, deque2.size());
+
+ unsigned i = 0;
+ for (auto& element : deque1) {
+ EXPECT_EQ(i * 2, element.value());
+ ++i;
+ }
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/Functional.cpp b/Tools/TestWebKitAPI/Tests/WTF/Functional.cpp
new file mode 100644
index 000000000..cf8c3c39c
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/Functional.cpp
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2011 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 <wtf/RefCounted.h>
+#include <wtf/Functional.h>
+
+namespace TestWebKitAPI {
+
+static int returnFortyTwo()
+{
+ return 42;
+}
+
+TEST(FunctionalTest, Basic)
+{
+ Function<int ()> emptyFunction;
+ ASSERT_TRUE(emptyFunction.isNull());
+
+ Function<int ()> returnFortyTwoFunction = bind(returnFortyTwo);
+ ASSERT_FALSE(returnFortyTwoFunction.isNull());
+ ASSERT_EQ(42, returnFortyTwoFunction());
+}
+
+static int multiplyByTwo(int n)
+{
+ return n * 2;
+}
+
+static double multiplyByOneAndAHalf(double d)
+{
+ return d * 1.5;
+}
+
+TEST(FunctionalTest, UnaryBind)
+{
+ Function<int ()> multiplyFourByTwoFunction = bind(multiplyByTwo, 4);
+ ASSERT_EQ(8, multiplyFourByTwoFunction());
+
+ Function<double ()> multiplyByOneAndAHalfFunction = bind(multiplyByOneAndAHalf, 3);
+ ASSERT_EQ(4.5, multiplyByOneAndAHalfFunction());
+}
+
+static int multiply(int x, int y)
+{
+ return x * y;
+}
+
+static int subtract(int x, int y)
+{
+ return x - y;
+}
+
+TEST(FunctionalTest, BinaryBind)
+{
+ Function<int ()> multiplyFourByTwoFunction = bind(multiply, 4, 2);
+ ASSERT_EQ(8, multiplyFourByTwoFunction());
+
+ Function<int ()> subtractTwoFromFourFunction = bind(subtract, 4, 2);
+ ASSERT_EQ(2, subtractTwoFromFourFunction());
+}
+
+class A {
+public:
+ explicit A(int i)
+ : m_i(i)
+ {
+ }
+
+ int f() { return m_i; }
+ int addF(int j) { return m_i + j; }
+
+private:
+ int m_i;
+};
+
+TEST(FunctionalTest, MemberFunctionBind)
+{
+ A a(10);
+ Function<int ()> function1 = bind(&A::f, &a);
+ ASSERT_EQ(10, function1());
+
+ Function<int ()> function2 = bind(&A::addF, &a, 15);
+ ASSERT_EQ(25, function2());
+}
+
+class B {
+public:
+ B()
+ : m_numRefCalls(0)
+ , m_numDerefCalls(0)
+ {
+ }
+
+ ~B()
+ {
+ }
+
+ void ref()
+ {
+ m_numRefCalls++;
+ }
+
+ void deref()
+ {
+ m_numDerefCalls++;
+ }
+
+ void f() { ASSERT_GT(m_numRefCalls, 0); }
+ void g(int) { ASSERT_GT(m_numRefCalls, 0); }
+
+ int m_numRefCalls;
+ int m_numDerefCalls;
+};
+
+TEST(FunctionalTest, MemberFunctionBindRefDeref)
+{
+ B b;
+
+ {
+ Function<void ()> function1 = bind(&B::f, &b);
+ function1();
+
+ Function<void ()> function2 = bind(&B::g, &b, 10);
+ function2();
+ }
+
+ ASSERT_TRUE(b.m_numRefCalls == b.m_numDerefCalls);
+ ASSERT_GT(b.m_numRefCalls, 0);
+
+}
+
+class Number : public RefCounted<Number> {
+public:
+ static PassRefPtr<Number> create(int value)
+ {
+ return adoptRef(new Number(value));
+ }
+
+ ~Number()
+ {
+ m_value = 0;
+ }
+
+ int value() const { return m_value; }
+
+private:
+ explicit Number(int value)
+ : m_value(value)
+ {
+ }
+
+ int m_value;
+};
+
+static int multiplyNumberByTwo(Number* number)
+{
+ return number->value() * 2;
+}
+
+TEST(FunctionalTest, RefCountedStorage)
+{
+ RefPtr<Number> five = Number::create(5);
+ Function<int ()> multiplyFiveByTwoFunction = bind(multiplyNumberByTwo, five);
+ ASSERT_EQ(10, multiplyFiveByTwoFunction());
+
+ Function<int ()> multiplyFourByTwoFunction = bind(multiplyNumberByTwo, Number::create(4));
+ ASSERT_EQ(8, multiplyFourByTwoFunction());
+
+ RefPtr<Number> six = Number::create(6);
+ Function<int ()> multiplySixByTwoFunction = bind(multiplyNumberByTwo, six.release());
+ ASSERT_FALSE(six);
+ ASSERT_EQ(12, multiplySixByTwoFunction());
+}
+
+namespace RefAndDerefTests {
+
+ template<typename T> struct RefCounted {
+ void ref();
+ void deref();
+ };
+ struct Connection : RefCounted<Connection> { };
+ COMPILE_ASSERT(WTF::HasRefAndDeref<Connection>::value, class_has_ref_and_deref);
+
+ struct NoRefOrDeref { };
+ COMPILE_ASSERT(!WTF::HasRefAndDeref<NoRefOrDeref>::value, class_has_no_ref_or_deref);
+
+ struct RefOnly { void ref(); };
+ COMPILE_ASSERT(!WTF::HasRefAndDeref<RefOnly>::value, class_has_ref_only);
+
+ struct DerefOnly { void deref(); };
+ COMPILE_ASSERT(!WTF::HasRefAndDeref<DerefOnly>::value, class_has_deref_only);
+
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/HashMap.cpp b/Tools/TestWebKitAPI/Tests/WTF/HashMap.cpp
new file mode 100644
index 000000000..a281f230a
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/HashMap.cpp
@@ -0,0 +1,511 @@
+/*
+ * Copyright (C) 2011 Google 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 "Counters.h"
+#include "MoveOnly.h"
+#include "RefLogger.h"
+#include <string>
+#include <wtf/HashMap.h>
+#include <wtf/text/StringHash.h>
+
+namespace TestWebKitAPI {
+
+typedef WTF::HashMap<int, int> IntHashMap;
+
+TEST(WTF_HashMap, HashTableIteratorComparison)
+{
+ IntHashMap map;
+ map.add(1, 2);
+ ASSERT_TRUE(map.begin() != map.end());
+ ASSERT_FALSE(map.begin() == map.end());
+
+ IntHashMap::const_iterator begin = map.begin();
+ ASSERT_TRUE(begin == map.begin());
+ ASSERT_TRUE(map.begin() == begin);
+ ASSERT_TRUE(begin != map.end());
+ ASSERT_TRUE(map.end() != begin);
+ ASSERT_FALSE(begin != map.begin());
+ ASSERT_FALSE(map.begin() != begin);
+ ASSERT_FALSE(begin == map.end());
+ ASSERT_FALSE(map.end() == begin);
+}
+
+struct TestDoubleHashTraits : HashTraits<double> {
+ static const int minimumTableSize = 8;
+};
+
+typedef HashMap<double, int64_t, DefaultHash<double>::Hash, TestDoubleHashTraits> DoubleHashMap;
+
+static int bucketForKey(double key)
+{
+ return DefaultHash<double>::Hash::hash(key) & (TestDoubleHashTraits::minimumTableSize - 1);
+}
+
+TEST(WTF_HashMap, DoubleHashCollisions)
+{
+ // The "clobber" key here is one that ends up stealing the bucket that the -0 key
+ // originally wants to be in. This makes the 0 and -0 keys collide and the test then
+ // fails unless the FloatHash::equals() implementation can distinguish them.
+ const double clobberKey = 6;
+ const double zeroKey = 0;
+ const double negativeZeroKey = -zeroKey;
+
+ DoubleHashMap map;
+
+ map.add(clobberKey, 1);
+ map.add(zeroKey, 2);
+ map.add(negativeZeroKey, 3);
+
+ ASSERT_EQ(bucketForKey(clobberKey), bucketForKey(negativeZeroKey));
+ ASSERT_EQ(map.get(clobberKey), 1);
+ ASSERT_EQ(map.get(zeroKey), 2);
+ ASSERT_EQ(map.get(negativeZeroKey), 3);
+}
+
+TEST(WTF_HashMap, MoveOnlyValues)
+{
+ HashMap<unsigned, MoveOnly> moveOnlyValues;
+
+ for (size_t i = 0; i < 100; ++i) {
+ MoveOnly moveOnly(i + 1);
+ moveOnlyValues.set(i + 1, WTF::move(moveOnly));
+ }
+
+ for (size_t i = 0; i < 100; ++i) {
+ auto it = moveOnlyValues.find(i + 1);
+ ASSERT_FALSE(it == moveOnlyValues.end());
+ }
+
+ for (size_t i = 0; i < 50; ++i)
+ ASSERT_EQ(moveOnlyValues.take(i + 1).value(), i + 1);
+
+ for (size_t i = 50; i < 100; ++i)
+ ASSERT_TRUE(moveOnlyValues.remove(i + 1));
+
+ ASSERT_TRUE(moveOnlyValues.isEmpty());
+}
+
+TEST(WTF_HashMap, MoveOnlyKeys)
+{
+ HashMap<MoveOnly, unsigned> moveOnlyKeys;
+
+ for (size_t i = 0; i < 100; ++i) {
+ MoveOnly moveOnly(i + 1);
+ moveOnlyKeys.set(WTF::move(moveOnly), i + 1);
+ }
+
+ for (size_t i = 0; i < 100; ++i) {
+ auto it = moveOnlyKeys.find(MoveOnly(i + 1));
+ ASSERT_FALSE(it == moveOnlyKeys.end());
+ }
+
+ for (size_t i = 0; i < 100; ++i)
+ ASSERT_FALSE(moveOnlyKeys.add(MoveOnly(i + 1), i + 1).isNewEntry);
+
+ for (size_t i = 0; i < 100; ++i)
+ ASSERT_TRUE(moveOnlyKeys.remove(MoveOnly(i + 1)));
+
+ ASSERT_TRUE(moveOnlyKeys.isEmpty());
+}
+
+TEST(WTF_HashMap, InitializerList)
+{
+ HashMap<unsigned, std::string> map = {
+ { 1, "one" },
+ { 2, "two" },
+ { 3, "three" },
+ { 4, "four" },
+ };
+
+ EXPECT_EQ(4u, map.size());
+
+ EXPECT_EQ("one", map.get(1));
+ EXPECT_EQ("two", map.get(2));
+ EXPECT_EQ("three", map.get(3));
+ EXPECT_EQ("four", map.get(4));
+ EXPECT_EQ(std::string(), map.get(5));
+}
+
+TEST(WTF_HashMap, EfficientGetter)
+{
+ HashMap<unsigned, CopyMoveCounter> map;
+ map.set(1, CopyMoveCounter());
+
+ {
+ CopyMoveCounter::TestingScope scope;
+ map.get(1);
+ EXPECT_EQ(0U, CopyMoveCounter::constructionCount);
+ EXPECT_EQ(1U, CopyMoveCounter::copyCount);
+ EXPECT_EQ(0U, CopyMoveCounter::moveCount);
+ }
+
+ {
+ CopyMoveCounter::TestingScope scope;
+ map.get(2);
+ EXPECT_EQ(1U, CopyMoveCounter::constructionCount);
+ EXPECT_EQ(0U, CopyMoveCounter::copyCount);
+ EXPECT_EQ(1U, CopyMoveCounter::moveCount);
+ }
+}
+
+TEST(WTF_HashMap, UniquePtrKey)
+{
+ ConstructorDestructorCounter::TestingScope scope;
+
+ HashMap<std::unique_ptr<ConstructorDestructorCounter>, int> map;
+
+ auto uniquePtr = std::make_unique<ConstructorDestructorCounter>();
+ map.add(WTF::move(uniquePtr), 2);
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(0u, ConstructorDestructorCounter::destructionCount);
+
+ map.clear();
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(1u, ConstructorDestructorCounter::destructionCount);
+}
+
+TEST(WTF_HashMap, UniquePtrKey_CustomDeleter)
+{
+ ConstructorDestructorCounter::TestingScope constructorDestructorCounterScope;
+ DeleterCounter<ConstructorDestructorCounter>::TestingScope deleterCounterScope;
+
+ HashMap<std::unique_ptr<ConstructorDestructorCounter, DeleterCounter<ConstructorDestructorCounter>>, int> map;
+
+ std::unique_ptr<ConstructorDestructorCounter, DeleterCounter<ConstructorDestructorCounter>> uniquePtr(new ConstructorDestructorCounter(), DeleterCounter<ConstructorDestructorCounter>());
+ map.add(WTF::move(uniquePtr), 2);
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(0u, ConstructorDestructorCounter::destructionCount);
+
+ EXPECT_EQ(0u, DeleterCounter<ConstructorDestructorCounter>::deleterCount);
+
+ map.clear();
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(1u, ConstructorDestructorCounter::destructionCount);
+
+ EXPECT_EQ(1u, DeleterCounter<ConstructorDestructorCounter>::deleterCount);
+}
+
+TEST(WTF_HashMap, UniquePtrKey_FindUsingRawPointer)
+{
+ HashMap<std::unique_ptr<int>, int> map;
+
+ auto uniquePtr = std::make_unique<int>(5);
+ int* ptr = uniquePtr.get();
+ map.add(WTF::move(uniquePtr), 2);
+
+ auto it = map.find(ptr);
+ ASSERT_TRUE(it != map.end());
+ EXPECT_EQ(ptr, it->key.get());
+ EXPECT_EQ(2, it->value);
+}
+
+TEST(WTF_HashMap, UniquePtrKey_ContainsUsingRawPointer)
+{
+ HashMap<std::unique_ptr<int>, int> map;
+
+ auto uniquePtr = std::make_unique<int>(5);
+ int* ptr = uniquePtr.get();
+ map.add(WTF::move(uniquePtr), 2);
+
+ EXPECT_EQ(true, map.contains(ptr));
+}
+
+TEST(WTF_HashMap, UniquePtrKey_GetUsingRawPointer)
+{
+ HashMap<std::unique_ptr<int>, int> map;
+
+ auto uniquePtr = std::make_unique<int>(5);
+ int* ptr = uniquePtr.get();
+ map.add(WTF::move(uniquePtr), 2);
+
+ int value = map.get(ptr);
+ EXPECT_EQ(2, value);
+}
+
+TEST(WTF_HashMap, UniquePtrKey_RemoveUsingRawPointer)
+{
+ ConstructorDestructorCounter::TestingScope scope;
+
+ HashMap<std::unique_ptr<ConstructorDestructorCounter>, int> map;
+
+ auto uniquePtr = std::make_unique<ConstructorDestructorCounter>();
+ ConstructorDestructorCounter* ptr = uniquePtr.get();
+ map.add(WTF::move(uniquePtr), 2);
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(0u, ConstructorDestructorCounter::destructionCount);
+
+ bool result = map.remove(ptr);
+ EXPECT_EQ(true, result);
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(1u, ConstructorDestructorCounter::destructionCount);
+}
+
+TEST(WTF_HashMap, UniquePtrKey_TakeUsingRawPointer)
+{
+ ConstructorDestructorCounter::TestingScope scope;
+
+ HashMap<std::unique_ptr<ConstructorDestructorCounter>, int> map;
+
+ auto uniquePtr = std::make_unique<ConstructorDestructorCounter>();
+ ConstructorDestructorCounter* ptr = uniquePtr.get();
+ map.add(WTF::move(uniquePtr), 2);
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(0u, ConstructorDestructorCounter::destructionCount);
+
+ int result = map.take(ptr);
+ EXPECT_EQ(2, result);
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(1u, ConstructorDestructorCounter::destructionCount);
+}
+
+TEST(WTF_HashMap, RefPtrKey_Add)
+{
+ HashMap<RefPtr<RefLogger>, int> map;
+
+ DerivedRefLogger a("a");
+ RefPtr<RefLogger> ptr(&a);
+ map.add(ptr, 0);
+
+ ASSERT_STREQ("ref(a) ref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_HashMap, RefPtrKey_AddUsingRelease)
+{
+ HashMap<RefPtr<RefLogger>, int> map;
+
+ DerivedRefLogger a("a");
+ RefPtr<RefLogger> ptr(&a);
+ map.add(ptr.release(), 0);
+
+ EXPECT_STREQ("ref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_HashMap, RefPtrKey_AddUsingMove)
+{
+ HashMap<RefPtr<RefLogger>, int> map;
+
+ DerivedRefLogger a("a");
+ RefPtr<RefLogger> ptr(&a);
+ map.add(WTF::move(ptr), 0);
+
+ EXPECT_STREQ("ref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_HashMap, RefPtrKey_AddUsingRaw)
+{
+ HashMap<RefPtr<RefLogger>, int> map;
+
+ DerivedRefLogger a("a");
+ RefPtr<RefLogger> ptr(&a);
+ map.add(ptr.get(), 0);
+
+ EXPECT_STREQ("ref(a) ref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_HashMap, RefPtrKey_AddKeyAlreadyPresent)
+{
+ HashMap<RefPtr<RefLogger>, int> map;
+
+ DerivedRefLogger a("a");
+
+ {
+ RefPtr<RefLogger> ptr(&a);
+ map.add(ptr, 0);
+ }
+
+ EXPECT_STREQ("ref(a) ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> ptr2(&a);
+ auto addResult = map.add(ptr2, 0);
+ EXPECT_FALSE(addResult.isNewEntry);
+ }
+
+ EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_HashMap, RefPtrKey_AddUsingReleaseKeyAlreadyPresent)
+{
+ HashMap<RefPtr<RefLogger>, int> map;
+
+ DerivedRefLogger a("a");
+
+ {
+ RefPtr<RefLogger> ptr(&a);
+ map.add(ptr, 0);
+ }
+
+ EXPECT_STREQ("ref(a) ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> ptr2(&a);
+ auto addResult = map.add(ptr2.release(), 0);
+ EXPECT_FALSE(addResult.isNewEntry);
+ }
+
+ EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_HashMap, RefPtrKey_AddUsingMoveKeyAlreadyPresent)
+{
+ HashMap<RefPtr<RefLogger>, int> map;
+
+ DerivedRefLogger a("a");
+
+ {
+ RefPtr<RefLogger> ptr(&a);
+ map.add(ptr, 0);
+ }
+
+ EXPECT_STREQ("ref(a) ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> ptr2(&a);
+ auto addResult = map.add(WTF::move(ptr2), 0);
+ EXPECT_FALSE(addResult.isNewEntry);
+ }
+
+ EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_HashMap, RefPtrKey_Set)
+{
+ HashMap<RefPtr<RefLogger>, int> map;
+
+ DerivedRefLogger a("a");
+ RefPtr<RefLogger> ptr(&a);
+ map.set(ptr, 0);
+
+ ASSERT_STREQ("ref(a) ref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_HashMap, RefPtrKey_SetUsingRelease)
+{
+ HashMap<RefPtr<RefLogger>, int> map;
+
+ DerivedRefLogger a("a");
+ RefPtr<RefLogger> ptr(&a);
+ map.set(ptr.release(), 0);
+
+ EXPECT_STREQ("ref(a) ", takeLogStr().c_str());
+}
+
+
+TEST(WTF_HashMap, RefPtrKey_SetUsingMove)
+{
+ HashMap<RefPtr<RefLogger>, int> map;
+
+ DerivedRefLogger a("a");
+ RefPtr<RefLogger> ptr(&a);
+ map.set(WTF::move(ptr), 0);
+
+ EXPECT_STREQ("ref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_HashMap, RefPtrKey_SetUsingRaw)
+{
+ HashMap<RefPtr<RefLogger>, int> map;
+
+ DerivedRefLogger a("a");
+ RefPtr<RefLogger> ptr(&a);
+ map.set(ptr.get(), 0);
+
+ EXPECT_STREQ("ref(a) ref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_HashMap, RefPtrKey_SetKeyAlreadyPresent)
+{
+ HashMap<RefPtr<RefLogger>, int> map;
+
+ DerivedRefLogger a("a");
+
+ RefPtr<RefLogger> ptr(&a);
+ map.set(ptr, 0);
+
+ EXPECT_STREQ("ref(a) ref(a) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> ptr2(&a);
+ auto addResult = map.set(ptr2, 1);
+ EXPECT_FALSE(addResult.isNewEntry);
+ EXPECT_EQ(1, map.get(ptr.get()));
+ }
+
+ EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_HashMap, RefPtrKey_SetUsingReleaseKeyAlreadyPresent)
+{
+ HashMap<RefPtr<RefLogger>, int> map;
+
+ DerivedRefLogger a("a");
+
+ RefPtr<RefLogger> ptr(&a);
+ map.set(ptr, 0);
+
+ EXPECT_STREQ("ref(a) ref(a) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> ptr2(&a);
+ auto addResult = map.set(ptr2.release(), 1);
+ EXPECT_FALSE(addResult.isNewEntry);
+ EXPECT_EQ(1, map.get(ptr.get()));
+ }
+
+ EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_HashMap, RefPtrKey_SetUsingMoveKeyAlreadyPresent)
+{
+ HashMap<RefPtr<RefLogger>, int> map;
+
+ DerivedRefLogger a("a");
+
+ RefPtr<RefLogger> ptr(&a);
+ map.set(ptr, 0);
+
+ EXPECT_STREQ("ref(a) ref(a) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> ptr2(&a);
+ auto addResult = map.set(WTF::move(ptr2), 1);
+ EXPECT_FALSE(addResult.isNewEntry);
+ EXPECT_EQ(1, map.get(ptr.get()));
+ }
+
+ EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/HashSet.cpp b/Tools/TestWebKitAPI/Tests/WTF/HashSet.cpp
new file mode 100644
index 000000000..79cb5e727
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/HashSet.cpp
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2012 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 "Counters.h"
+#include "MoveOnly.h"
+#include <wtf/HashSet.h>
+
+namespace TestWebKitAPI {
+
+template<int initialCapacity>
+ struct InitialCapacityTestHashTraits : public WTF::UnsignedWithZeroKeyHashTraits<int> {
+ static const int minimumTableSize = initialCapacity;
+};
+
+template<unsigned size>
+void testInitialCapacity()
+{
+ const unsigned initialCapacity = WTF::HashTableCapacityForSize<size>::value;
+ HashSet<int, DefaultHash<int>::Hash, InitialCapacityTestHashTraits<initialCapacity> > testSet;
+
+ // Initial capacity is null.
+ ASSERT_EQ(0u, testSet.capacity());
+
+ // Adding items up to size should never change the capacity.
+ for (size_t i = 0; i < size; ++i) {
+ testSet.add(i);
+ ASSERT_EQ(initialCapacity, static_cast<unsigned>(testSet.capacity()));
+ }
+
+ // Adding items up to less than half the capacity should not change the capacity.
+ unsigned capacityLimit = initialCapacity / 2 - 1;
+ for (size_t i = size; i < capacityLimit; ++i) {
+ testSet.add(i);
+ ASSERT_EQ(initialCapacity, static_cast<unsigned>(testSet.capacity()));
+ }
+
+ // Adding one more item increase the capacity.
+ testSet.add(initialCapacity);
+ EXPECT_GT(static_cast<unsigned>(testSet.capacity()), initialCapacity);
+}
+
+template<unsigned size> void generateTestCapacityUpToSize();
+template<> void generateTestCapacityUpToSize<0>()
+{
+}
+template<unsigned size> void generateTestCapacityUpToSize()
+{
+ generateTestCapacityUpToSize<size - 1>();
+ testInitialCapacity<size>();
+}
+
+TEST(WTF_HashSet, InitialCapacity)
+{
+ generateTestCapacityUpToSize<128>();
+}
+
+TEST(WTF_HashSet, MoveOnly)
+{
+ HashSet<MoveOnly> hashSet;
+
+ for (size_t i = 0; i < 100; ++i) {
+ MoveOnly moveOnly(i + 1);
+ hashSet.add(WTF::move(moveOnly));
+ }
+
+ for (size_t i = 0; i < 100; ++i)
+ EXPECT_TRUE(hashSet.contains(MoveOnly(i + 1)));
+
+ for (size_t i = 0; i < 100; ++i)
+ EXPECT_TRUE(hashSet.remove(MoveOnly(i + 1)));
+
+ EXPECT_TRUE(hashSet.isEmpty());
+
+ for (size_t i = 0; i < 100; ++i)
+ hashSet.add(MoveOnly(i + 1));
+
+ for (size_t i = 0; i < 100; ++i)
+ EXPECT_TRUE(hashSet.take(MoveOnly(i + 1)) == MoveOnly(i + 1));
+
+ EXPECT_TRUE(hashSet.isEmpty());
+
+ for (size_t i = 0; i < 100; ++i)
+ hashSet.add(MoveOnly(i + 1));
+
+ HashSet<MoveOnly> secondSet;
+
+ for (size_t i = 0; i < 100; ++i)
+ secondSet.add(hashSet.takeAny());
+
+ EXPECT_TRUE(hashSet.isEmpty());
+
+ for (size_t i = 0; i < 100; ++i)
+ EXPECT_TRUE(secondSet.contains(MoveOnly(i + 1)));
+}
+
+
+TEST(WTF_HashSet, UniquePtrKey)
+{
+ ConstructorDestructorCounter::TestingScope scope;
+
+ HashSet<std::unique_ptr<ConstructorDestructorCounter>> set;
+
+ auto uniquePtr = std::make_unique<ConstructorDestructorCounter>();
+ set.add(WTF::move(uniquePtr));
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(0u, ConstructorDestructorCounter::destructionCount);
+
+ set.clear();
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(1u, ConstructorDestructorCounter::destructionCount);
+}
+
+TEST(WTF_HashSet, UniquePtrKey_FindUsingRawPointer)
+{
+ HashSet<std::unique_ptr<int>> set;
+
+ auto uniquePtr = std::make_unique<int>(5);
+ int* ptr = uniquePtr.get();
+ set.add(WTF::move(uniquePtr));
+
+ auto it = set.find(ptr);
+ ASSERT_TRUE(it != set.end());
+ EXPECT_EQ(ptr, it->get());
+ EXPECT_EQ(5, *it->get());
+}
+
+TEST(WTF_HashSet, UniquePtrKey_ContainsUsingRawPointer)
+{
+ HashSet<std::unique_ptr<int>> set;
+
+ auto uniquePtr = std::make_unique<int>(5);
+ int* ptr = uniquePtr.get();
+ set.add(WTF::move(uniquePtr));
+
+ EXPECT_EQ(true, set.contains(ptr));
+}
+
+TEST(WTF_HashSet, UniquePtrKey_RemoveUsingRawPointer)
+{
+ ConstructorDestructorCounter::TestingScope scope;
+
+ HashSet<std::unique_ptr<ConstructorDestructorCounter>> set;
+
+ auto uniquePtr = std::make_unique<ConstructorDestructorCounter>();
+ ConstructorDestructorCounter* ptr = uniquePtr.get();
+ set.add(WTF::move(uniquePtr));
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(0u, ConstructorDestructorCounter::destructionCount);
+
+ bool result = set.remove(ptr);
+ EXPECT_EQ(true, result);
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(1u, ConstructorDestructorCounter::destructionCount);
+}
+
+TEST(WTF_HashSet, UniquePtrKey_TakeUsingRawPointer)
+{
+ ConstructorDestructorCounter::TestingScope scope;
+
+ HashSet<std::unique_ptr<ConstructorDestructorCounter>> set;
+
+ auto uniquePtr = std::make_unique<ConstructorDestructorCounter>();
+ ConstructorDestructorCounter* ptr = uniquePtr.get();
+ set.add(WTF::move(uniquePtr));
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(0u, ConstructorDestructorCounter::destructionCount);
+
+ auto result = set.take(ptr);
+ EXPECT_EQ(ptr, result.get());
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(0u, ConstructorDestructorCounter::destructionCount);
+
+ result = nullptr;
+
+ EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
+ EXPECT_EQ(1u, ConstructorDestructorCounter::destructionCount);
+}
+
+TEST(WTF_HashSet, CopyEmpty)
+{
+ {
+ HashSet<unsigned> foo;
+ HashSet<unsigned> bar(foo);
+
+ EXPECT_EQ(0u, bar.capacity());
+ EXPECT_EQ(0u, bar.size());
+ }
+ {
+ HashSet<unsigned> foo({ 1, 5, 64, 42 });
+ EXPECT_EQ(4u, foo.size());
+ foo.remove(1);
+ foo.remove(5);
+ foo.remove(42);
+ foo.remove(64);
+ HashSet<unsigned> bar(foo);
+
+ EXPECT_EQ(0u, bar.capacity());
+ EXPECT_EQ(0u, bar.size());
+ }
+}
+
+TEST(WTF_HashSet, CopyAllocateAtLeastMinimumCapacity)
+{
+ HashSet<unsigned> foo({ 42 });
+ EXPECT_EQ(1u, foo.size());
+ HashSet<unsigned> bar(foo);
+
+ EXPECT_EQ(8u, bar.capacity());
+ EXPECT_EQ(1u, bar.size());
+}
+
+TEST(WTF_HashSet, CopyCapacityIsNotOnBoundary)
+{
+ // Starting at 4 because the minimum size is 8.
+ // With a size of 8, a medium load can be up to 3.3333->3.
+ // Adding 1 to 3 would reach max load.
+ // While correct, that's not really what we care about here.
+ for (unsigned size = 4; size < 100; ++size) {
+ HashSet<unsigned> source;
+ for (unsigned i = 1; i < size + 1; ++i)
+ source.add(i);
+
+ HashSet<unsigned> copy1(source);
+ HashSet<unsigned> copy2(source);
+ HashSet<unsigned> copy3(source);
+
+ EXPECT_EQ(size, copy1.size());
+ EXPECT_EQ(size, copy2.size());
+ EXPECT_EQ(size, copy3.size());
+ for (unsigned i = 1; i < size + 1; ++i) {
+ EXPECT_TRUE(copy1.contains(i));
+ EXPECT_TRUE(copy2.contains(i));
+ EXPECT_TRUE(copy3.contains(i));
+ }
+ EXPECT_FALSE(copy1.contains(size + 2));
+ EXPECT_FALSE(copy2.contains(size + 2));
+ EXPECT_FALSE(copy3.contains(size + 2));
+
+ EXPECT_TRUE(copy2.remove(1));
+ EXPECT_EQ(copy1.capacity(), copy2.capacity());
+ EXPECT_FALSE(copy2.contains(1));
+
+ EXPECT_TRUE(copy3.add(size + 2).isNewEntry);
+ EXPECT_EQ(copy1.capacity(), copy3.capacity());
+ EXPECT_TRUE(copy3.contains(size + 2));
+ }
+}
+
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/IntegerToStringConversion.cpp b/Tools/TestWebKitAPI/Tests/WTF/IntegerToStringConversion.cpp
new file mode 100644
index 000000000..49a2de326
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/IntegerToStringConversion.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2012 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 <limits>
+#include <wtf/StringExtras.h>
+#include <wtf/text/CString.h>
+#include <wtf/text/WTFString.h>
+
+template<typename IntegerType> struct PrintfFormatTrait { static const char format[]; };
+
+template<> struct PrintfFormatTrait<short> { static const char format[]; };
+const char PrintfFormatTrait<short>::format[] = "%hd";
+
+template<> struct PrintfFormatTrait<int> { static const char format[]; };
+const char PrintfFormatTrait<int>::format[] = "%d";
+
+template<> struct PrintfFormatTrait<long> { static const char format[]; };
+const char PrintfFormatTrait<long>::format[] = "%ld";
+
+template<> struct PrintfFormatTrait<long long> { static const char format[]; };
+#if OS(WINDOWS)
+const char PrintfFormatTrait<long long>::format[] = "%I64i";
+#else
+const char PrintfFormatTrait<long long>::format[] = "%lli";
+#endif // OS(WINDOWS)
+
+template<> struct PrintfFormatTrait<unsigned short> { static const char format[]; };
+const char PrintfFormatTrait<unsigned short>::format[] = "%hu";
+
+template<> struct PrintfFormatTrait<unsigned> { static const char format[]; };
+const char PrintfFormatTrait<unsigned>::format[] = "%u";
+
+template<> struct PrintfFormatTrait<unsigned long> { static const char format[]; };
+const char PrintfFormatTrait<unsigned long>::format[] = "%lu";
+
+template<> struct PrintfFormatTrait<unsigned long long> { static const char format[]; };
+#if OS(WINDOWS)
+const char PrintfFormatTrait<unsigned long long>::format[] = "%I64u";
+#else
+const char PrintfFormatTrait<unsigned long long>::format[] = "%llu";
+#endif // OS(WINDOWS)
+
+
+// FIXME: use snprintf from StringExtras.h
+template<typename IntegerType>
+void testBoundaries()
+{
+ const unsigned bufferSize = 256;
+ Vector<char, bufferSize> buffer;
+ buffer.resize(bufferSize);
+
+ const IntegerType min = std::numeric_limits<IntegerType>::min();
+ CString minStringData = String::number(min).latin1();
+ snprintf(buffer.data(), bufferSize, PrintfFormatTrait<IntegerType>::format, min);
+ ASSERT_STREQ(buffer.data(), minStringData.data());
+
+ const IntegerType max = std::numeric_limits<IntegerType>::max();
+ CString maxStringData = String::number(max).latin1();
+ snprintf(buffer.data(), bufferSize, PrintfFormatTrait<IntegerType>::format, max);
+ ASSERT_STREQ(buffer.data(), maxStringData.data());
+}
+
+template<typename IntegerType>
+void testNumbers()
+{
+ const unsigned bufferSize = 256;
+ Vector<char, bufferSize> buffer;
+ buffer.resize(bufferSize);
+
+ for (int i = -100; i < 100; ++i) {
+ const IntegerType number = static_cast<IntegerType>(i);
+ CString numberStringData = String::number(number).latin1();
+ snprintf(buffer.data(), bufferSize, PrintfFormatTrait<IntegerType>::format, number);
+ ASSERT_STREQ(buffer.data(), numberStringData.data());
+ }
+}
+
+TEST(WTF, IntegerToStringConversionSignedIntegerBoundaries)
+{
+ testBoundaries<short>();
+ testBoundaries<int>();
+ testBoundaries<long>();
+ testBoundaries<long long>();
+}
+
+TEST(WTF, IntegerToStringConversionSignedIntegerRegularNumbers)
+{
+ testNumbers<short>();
+ testNumbers<int>();
+ testNumbers<long>();
+ testNumbers<long long>();
+}
+
+TEST(WTF, IntegerToStringConversionUnsignedIntegerBoundaries)
+{
+ testBoundaries<unsigned short>();
+ testBoundaries<unsigned int>();
+ testBoundaries<unsigned long>();
+ testBoundaries<unsigned long long>();
+}
+
+TEST(WTF, IntegerToStringConversionUnsignedIntegerRegularNumbers)
+{
+ testNumbers<unsigned short>();
+ testNumbers<unsigned int>();
+ testNumbers<unsigned long>();
+ testNumbers<unsigned long long>();
+}
diff --git a/Tools/TestWebKitAPI/Tests/WTF/ListHashSet.cpp b/Tools/TestWebKitAPI/Tests/WTF/ListHashSet.cpp
new file mode 100644
index 000000000..d81dcfcfe
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/ListHashSet.cpp
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2012 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 "MoveOnly.h"
+#include <wtf/ListHashSet.h>
+
+namespace TestWebKitAPI {
+
+TEST(WTF_ListHashSet, RemoveFirst)
+{
+ ListHashSet<int> list;
+ list.add(1);
+ list.add(2);
+ list.add(3);
+
+ ASSERT_EQ(1, list.first());
+
+ list.removeFirst();
+ ASSERT_EQ(2, list.first());
+
+ list.removeFirst();
+ ASSERT_EQ(3, list.first());
+
+ list.removeFirst();
+ ASSERT_TRUE(list.isEmpty());
+}
+
+TEST(WTF_ListHashSet, RemoveLast)
+{
+ ListHashSet<int> list;
+ list.add(1);
+ list.add(2);
+ list.add(3);
+
+ ASSERT_EQ(3, list.last());
+
+ list.removeLast();
+ ASSERT_EQ(2, list.last());
+
+ list.removeLast();
+ ASSERT_EQ(1, list.last());
+
+ list.removeLast();
+ ASSERT_TRUE(list.isEmpty());
+}
+
+TEST(WTF_ListHashSet, AppendOrMoveToLastNewItems)
+{
+ ListHashSet<int> list;
+ ListHashSet<int>::AddResult result = list.appendOrMoveToLast(1);
+ ASSERT_TRUE(result.isNewEntry);
+ result = list.add(2);
+ ASSERT_TRUE(result.isNewEntry);
+ result = list.appendOrMoveToLast(3);
+ ASSERT_TRUE(result.isNewEntry);
+
+ ASSERT_EQ(list.size(), 3u);
+
+ // The list should be in order 1, 2, 3.
+ ListHashSet<int>::iterator iterator = list.begin();
+ ASSERT_EQ(1, *iterator);
+ ++iterator;
+ ASSERT_EQ(2, *iterator);
+ ++iterator;
+ ASSERT_EQ(3, *iterator);
+ ++iterator;
+}
+
+TEST(WTF_ListHashSet, AppendOrMoveToLastWithDuplicates)
+{
+ ListHashSet<int> list;
+
+ // Add a single element twice.
+ ListHashSet<int>::AddResult result = list.add(1);
+ ASSERT_TRUE(result.isNewEntry);
+ result = list.appendOrMoveToLast(1);
+ ASSERT_FALSE(result.isNewEntry);
+ ASSERT_EQ(1u, list.size());
+
+ list.add(2);
+ list.add(3);
+ ASSERT_EQ(3u, list.size());
+
+ // Appending 2 move it to the end.
+ ASSERT_EQ(3, list.last());
+ result = list.appendOrMoveToLast(2);
+ ASSERT_FALSE(result.isNewEntry);
+ ASSERT_EQ(2, list.last());
+
+ // Inverse the list by moving each element to end end.
+ result = list.appendOrMoveToLast(3);
+ ASSERT_FALSE(result.isNewEntry);
+ result = list.appendOrMoveToLast(2);
+ ASSERT_FALSE(result.isNewEntry);
+ result = list.appendOrMoveToLast(1);
+ ASSERT_FALSE(result.isNewEntry);
+ ASSERT_EQ(3u, list.size());
+
+ ListHashSet<int>::iterator iterator = list.begin();
+ ASSERT_EQ(3, *iterator);
+ ++iterator;
+ ASSERT_EQ(2, *iterator);
+ ++iterator;
+ ASSERT_EQ(1, *iterator);
+ ++iterator;
+}
+
+TEST(WTF_ListHashSet, PrependOrMoveToLastNewItems)
+{
+ ListHashSet<int> list;
+ ListHashSet<int>::AddResult result = list.prependOrMoveToFirst(1);
+ ASSERT_TRUE(result.isNewEntry);
+ result = list.add(2);
+ ASSERT_TRUE(result.isNewEntry);
+ result = list.prependOrMoveToFirst(3);
+ ASSERT_TRUE(result.isNewEntry);
+
+ ASSERT_EQ(list.size(), 3u);
+
+ // The list should be in order 3, 1, 2.
+ ListHashSet<int>::iterator iterator = list.begin();
+ ASSERT_EQ(3, *iterator);
+ ++iterator;
+ ASSERT_EQ(1, *iterator);
+ ++iterator;
+ ASSERT_EQ(2, *iterator);
+ ++iterator;
+}
+
+TEST(WTF_ListHashSet, PrependOrMoveToLastWithDuplicates)
+{
+ ListHashSet<int> list;
+
+ // Add a single element twice.
+ ListHashSet<int>::AddResult result = list.add(1);
+ ASSERT_TRUE(result.isNewEntry);
+ result = list.prependOrMoveToFirst(1);
+ ASSERT_FALSE(result.isNewEntry);
+ ASSERT_EQ(1u, list.size());
+
+ list.add(2);
+ list.add(3);
+ ASSERT_EQ(3u, list.size());
+
+ // Prepending 2 move it to the beginning.
+ ASSERT_EQ(1, list.first());
+ result = list.prependOrMoveToFirst(2);
+ ASSERT_FALSE(result.isNewEntry);
+ ASSERT_EQ(2, list.first());
+
+ // Inverse the list by moving each element to the first position.
+ result = list.prependOrMoveToFirst(1);
+ ASSERT_FALSE(result.isNewEntry);
+ result = list.prependOrMoveToFirst(2);
+ ASSERT_FALSE(result.isNewEntry);
+ result = list.prependOrMoveToFirst(3);
+ ASSERT_FALSE(result.isNewEntry);
+ ASSERT_EQ(3u, list.size());
+
+ ListHashSet<int>::iterator iterator = list.begin();
+ ASSERT_EQ(3, *iterator);
+ ++iterator;
+ ASSERT_EQ(2, *iterator);
+ ++iterator;
+ ASSERT_EQ(1, *iterator);
+ ++iterator;
+}
+
+TEST(WTF_ListHashSet, ReverseIterator)
+{
+ ListHashSet<int> list;
+
+ list.add(1);
+ list.add(2);
+ list.add(3);
+
+ auto it = list.rbegin();
+ ASSERT_EQ(3, *it);
+ ++it;
+ ASSERT_EQ(2, *it);
+ ++it;
+ ASSERT_EQ(1, *it);
+ ++it;
+ ASSERT_TRUE(it == list.rend());
+
+ const auto& listHashSet = list;
+
+ auto constIt = listHashSet.rbegin();
+ ASSERT_EQ(3, *constIt);
+ ++constIt;
+ ASSERT_EQ(2, *constIt);
+ ++constIt;
+ ASSERT_EQ(1, *constIt);
+ ++constIt;
+ ASSERT_TRUE(constIt == listHashSet.rend());
+}
+
+TEST(WTF_ListHashSet, MoveOnly)
+{
+ ListHashSet<MoveOnly> list;
+ list.add(MoveOnly(2));
+ list.add(MoveOnly(4));
+
+ // { 2, 4 }
+ ASSERT_EQ(2U, list.first().value());
+ ASSERT_EQ(4U, list.last().value());
+
+ list.appendOrMoveToLast(MoveOnly(3));
+
+ // { 2, 4, 3 }
+ ASSERT_EQ(3U, list.last().value());
+
+ // { 4, 3, 2 }
+ list.appendOrMoveToLast(MoveOnly(2));
+ ASSERT_EQ(4U, list.first().value());
+ ASSERT_EQ(2U, list.last().value());
+
+ list.prependOrMoveToFirst(MoveOnly(5));
+
+ // { 5, 2, 4, 3 }
+ ASSERT_EQ(5U, list.first().value());
+
+ list.prependOrMoveToFirst(MoveOnly(3));
+
+ // { 3, 5, 4, 2 }
+ ASSERT_EQ(3U, list.first().value());
+ ASSERT_EQ(2U, list.last().value());
+
+ list.insertBefore(MoveOnly(4), MoveOnly(1));
+ list.insertBefore(list.end(), MoveOnly(6));
+
+ // { 3, 5, 1, 4, 2, 6 }
+ ASSERT_EQ(3U, list.takeFirst().value());
+ ASSERT_EQ(5U, list.takeFirst().value());
+ ASSERT_EQ(1U, list.takeFirst().value());
+
+ // { 4, 2, 6 }
+ ASSERT_EQ(6U, list.takeLast().value());
+ ASSERT_EQ(2U, list.takeLast().value());
+ ASSERT_EQ(4U, list.takeLast().value());
+
+ ASSERT_TRUE(list.isEmpty());
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/Lock.cpp b/Tools/TestWebKitAPI/Tests/WTF/Lock.cpp
new file mode 100644
index 000000000..fcf8a4bea
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/Lock.cpp
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2015 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 <wtf/Lock.h>
+#include <wtf/Threading.h>
+#include <wtf/ThreadingPrimitives.h>
+#include <wtf/WordLock.h>
+
+using namespace WTF;
+
+namespace TestWebKitAPI {
+
+struct LockInspector {
+ template<typename LockType>
+ static bool isFullyReset(LockType& lock)
+ {
+ return lock.isFullyReset();
+ }
+};
+
+template<typename LockType>
+void runLockTest(unsigned numThreadGroups, unsigned numThreadsPerGroup, unsigned workPerCriticalSection, unsigned numIterations)
+{
+ std::unique_ptr<LockType[]> locks = std::make_unique<LockType[]>(numThreadGroups);
+ std::unique_ptr<double[]> words = std::make_unique<double[]>(numThreadGroups);
+ std::unique_ptr<ThreadIdentifier[]> threads = std::make_unique<ThreadIdentifier[]>(numThreadGroups * numThreadsPerGroup);
+
+ for (unsigned threadGroupIndex = numThreadGroups; threadGroupIndex--;) {
+ words[threadGroupIndex] = 0;
+
+ for (unsigned threadIndex = numThreadsPerGroup; threadIndex--;) {
+ threads[threadGroupIndex * numThreadsPerGroup + threadIndex] = createThread(
+ "Lock test thread",
+ [threadGroupIndex, &locks, &words, numIterations, workPerCriticalSection] () {
+ for (unsigned i = numIterations; i--;) {
+ locks[threadGroupIndex].lock();
+ for (unsigned j = workPerCriticalSection; j--;)
+ words[threadGroupIndex]++;
+ locks[threadGroupIndex].unlock();
+ }
+ });
+ }
+ }
+
+ for (unsigned threadIndex = numThreadGroups * numThreadsPerGroup; threadIndex--;)
+ waitForThreadCompletion(threads[threadIndex]);
+
+ double expected = 0;
+ for (uint64_t i = static_cast<uint64_t>(numIterations) * workPerCriticalSection * numThreadsPerGroup; i--;)
+ expected++;
+
+ for (unsigned threadGroupIndex = numThreadGroups; threadGroupIndex--;)
+ EXPECT_EQ(expected, words[threadGroupIndex]);
+
+ // Now test that the locks correctly reset themselves. We expect that if a single thread locks
+ // each of the locks twice in a row, then the lock should be in a pristine state.
+ for (unsigned threadGroupIndex = numThreadGroups; threadGroupIndex--;) {
+ for (unsigned i = 2; i--;) {
+ locks[threadGroupIndex].lock();
+ locks[threadGroupIndex].unlock();
+ }
+
+ EXPECT_EQ(true, LockInspector::isFullyReset(locks[threadGroupIndex]));
+ }
+}
+
+TEST(WTF_WordLock, UncontendedShortSection)
+{
+ runLockTest<WordLock>(1, 1, 1, 10000000);
+}
+
+TEST(WTF_WordLock, UncontendedLongSection)
+{
+ runLockTest<WordLock>(1, 1, 10000, 1000);
+}
+
+TEST(WTF_WordLock, ContendedShortSection)
+{
+ runLockTest<WordLock>(1, 10, 1, 5000000);
+}
+
+TEST(WTF_WordLock, ContendedLongSection)
+{
+ runLockTest<WordLock>(1, 10, 10000, 10000);
+}
+
+TEST(WTF_WordLock, ManyContendedShortSections)
+{
+ runLockTest<WordLock>(10, 10, 1, 500000);
+}
+
+TEST(WTF_WordLock, ManyContendedLongSections)
+{
+ runLockTest<WordLock>(10, 10, 10000, 500);
+}
+
+TEST(WTF_Lock, UncontendedShortSection)
+{
+ runLockTest<Lock>(1, 1, 1, 10000000);
+}
+
+TEST(WTF_Lock, UncontendedLongSection)
+{
+ runLockTest<Lock>(1, 1, 10000, 1000);
+}
+
+TEST(WTF_Lock, ContendedShortSection)
+{
+ runLockTest<Lock>(1, 10, 1, 10000000);
+}
+
+TEST(WTF_Lock, ContendedLongSection)
+{
+ runLockTest<Lock>(1, 10, 10000, 10000);
+}
+
+TEST(WTF_Lock, ManyContendedShortSections)
+{
+ runLockTest<Lock>(10, 10, 1, 500000);
+}
+
+TEST(WTF_Lock, ManyContendedLongSections)
+{
+ runLockTest<Lock>(10, 10, 10000, 1000);
+}
+
+TEST(WTF_Lock, ManyContendedLongerSections)
+{
+ runLockTest<Lock>(10, 10, 100000, 1);
+}
+
+TEST(WTF_Lock, SectionAddressCollision)
+{
+ runLockTest<Lock>(4, 2, 10000, 2000);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/MD5.cpp b/Tools/TestWebKitAPI/Tests/WTF/MD5.cpp
new file mode 100644
index 000000000..2c862a9cf
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/MD5.cpp
@@ -0,0 +1,47 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ */
+
+#include "config.h"
+#include <wtf/MD5.h>
+#include <wtf/StringExtras.h>
+#include <wtf/text/CString.h>
+
+namespace TestWebKitAPI {
+
+static void expectMD5(CString input, CString expected)
+{
+ MD5 md5;
+ md5.addBytes(reinterpret_cast<const uint8_t*>(input.data()), input.length());
+ MD5::Digest digest;
+ md5.checksum(digest);
+ char* buf = 0;
+ CString actual = CString::newUninitialized(32, buf);
+ for (size_t i = 0; i < MD5::hashSize; i++, buf += 2)
+ snprintf(buf, 3, "%02x", digest[i]);
+
+ ASSERT_EQ(expected.length(), actual.length());
+ ASSERT_STREQ(expected.data(), actual.data());
+}
+
+TEST(WTF_MD5, Computation)
+{
+ // MD5 Test suite from http://www.ietf.org/rfc/rfc1321.txt.
+ expectMD5("", "d41d8cd98f00b204e9800998ecf8427e");
+ expectMD5("a", "0cc175b9c0f1b6a831c399e269772661");
+ expectMD5("abc", "900150983cd24fb0d6963f7d28e17f72");
+ expectMD5("message digest", "f96b697d7cb7938d525a2f31aaf161d0");
+ expectMD5("abcdefghijklmnopqrstuvwxyz", "c3fcd3d76192e4007dfb496cca67e13b");
+ expectMD5("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "d174ab98d277d9f5a5611c2c9f419d9f");
+ expectMD5("12345678901234567890123456789012345678901234567890123456789012345678901234567890", "57edf4a22be3c955ac49da2e2107b67a");
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/MathExtras.cpp b/Tools/TestWebKitAPI/Tests/WTF/MathExtras.cpp
new file mode 100644
index 000000000..7cbb29766
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/MathExtras.cpp
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2012 Intel Corporation
+ *
+ * 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 <wtf/MathExtras.h>
+
+namespace TestWebKitAPI {
+
+TEST(WTF, Lrint)
+{
+ EXPECT_EQ(lrint(-7.5), -8);
+ EXPECT_EQ(lrint(-8.5), -8);
+ EXPECT_EQ(lrint(-0.5), 0);
+ EXPECT_EQ(lrint(0.5), 0);
+ EXPECT_EQ(lrint(-0.5), 0);
+ EXPECT_EQ(lrint(1.3), 1);
+ EXPECT_EQ(lrint(1.7), 2);
+ EXPECT_EQ(lrint(0), 0);
+ EXPECT_EQ(lrint(-0), 0);
+ if (sizeof(long int) == 8) {
+ // Largest double number with 0.5 precision and one halfway rounding case below.
+ EXPECT_EQ(lrint(pow(2.0, 52) - 0.5), pow(2.0, 52));
+ EXPECT_EQ(lrint(pow(2.0, 52) - 1.5), pow(2.0, 52) - 2);
+ // Smallest double number with 0.5 precision and one halfway rounding case above.
+ EXPECT_EQ(lrint(-pow(2.0, 52) + 0.5), -pow(2.0, 52));
+ EXPECT_EQ(lrint(-pow(2.0, 52) + 1.5), -pow(2.0, 52) + 2);
+ }
+}
+
+TEST(WTF, clampToIntLong)
+{
+ if (sizeof(long) == sizeof(int))
+ return;
+
+ long maxInt = std::numeric_limits<int>::max();
+ long minInt = std::numeric_limits<int>::min();
+ long overflowInt = maxInt + 1;
+ long underflowInt = minInt - 1;
+
+ EXPECT_GT(overflowInt, maxInt);
+ EXPECT_LT(underflowInt, minInt);
+
+ EXPECT_EQ(clampTo<int>(maxInt), maxInt);
+ EXPECT_EQ(clampTo<int>(minInt), minInt);
+
+ EXPECT_EQ(clampTo<int>(overflowInt), maxInt);
+ EXPECT_EQ(clampTo<int>(underflowInt), minInt);
+}
+
+TEST(WTF, clampToIntLongLong)
+{
+ long long maxInt = std::numeric_limits<int>::max();
+ long long minInt = std::numeric_limits<int>::min();
+ long long overflowInt = maxInt + 1;
+ long long underflowInt = minInt - 1;
+
+ EXPECT_GT(overflowInt, maxInt);
+ EXPECT_LT(underflowInt, minInt);
+
+ EXPECT_EQ(clampTo<int>(maxInt), maxInt);
+ EXPECT_EQ(clampTo<int>(minInt), minInt);
+
+ EXPECT_EQ(clampTo<int>(overflowInt), maxInt);
+ EXPECT_EQ(clampTo<int>(underflowInt), minInt);
+}
+
+TEST(WTF, clampToIntegerFloat)
+{
+ // This test is inaccurate as floats will round the min / max integer
+ // due to the narrow mantissa. However it will properly checks within
+ // (close to the extreme) and outside the integer range.
+ float maxInt = std::numeric_limits<int>::max();
+ float minInt = std::numeric_limits<int>::min();
+ float overflowInt = maxInt * 1.1;
+ float underflowInt = minInt * 1.1;
+
+ EXPECT_GT(overflowInt, maxInt);
+ EXPECT_LT(underflowInt, minInt);
+
+ // If maxInt == 2^31 - 1 (ie on I32 architecture), the closest float used to represent it is 2^31.
+ EXPECT_NEAR(clampToInteger(maxInt), maxInt, 1);
+ EXPECT_EQ(clampToInteger(minInt), minInt);
+
+ EXPECT_NEAR(clampToInteger(overflowInt), maxInt, 1);
+ EXPECT_EQ(clampToInteger(underflowInt), minInt);
+}
+
+TEST(WTF, clampToIntegerDouble)
+{
+ double maxInt = std::numeric_limits<int>::max();
+ double minInt = std::numeric_limits<int>::min();
+ double overflowInt = maxInt + 1;
+ double underflowInt = minInt - 1;
+
+ EXPECT_GT(overflowInt, maxInt);
+ EXPECT_LT(underflowInt, minInt);
+
+ EXPECT_EQ(clampToInteger(maxInt), maxInt);
+ EXPECT_EQ(clampToInteger(minInt), minInt);
+
+ EXPECT_EQ(clampToInteger(overflowInt), maxInt);
+ EXPECT_EQ(clampToInteger(underflowInt), minInt);
+}
+
+TEST(WTF, clampToFloat)
+{
+ double maxFloat = std::numeric_limits<float>::max();
+ double minFloat = -maxFloat;
+ double overflowFloat = maxFloat * 1.1;
+ double underflowFloat = minFloat * 1.1;
+
+ EXPECT_GT(overflowFloat, maxFloat);
+ EXPECT_LT(underflowFloat, minFloat);
+
+ EXPECT_EQ(clampToFloat(maxFloat), maxFloat);
+ EXPECT_EQ(clampToFloat(minFloat), minFloat);
+
+ EXPECT_EQ(clampToFloat(overflowFloat), maxFloat);
+ EXPECT_EQ(clampToFloat(underflowFloat), minFloat);
+
+ EXPECT_EQ(clampToFloat(std::numeric_limits<float>::infinity()), maxFloat);
+ EXPECT_EQ(clampToFloat(-std::numeric_limits<float>::infinity()), minFloat);
+}
+
+TEST(WTF, clampToUnsignedLong)
+{
+ if (sizeof(unsigned long) == sizeof(unsigned))
+ return;
+
+ unsigned long maxUnsigned = std::numeric_limits<unsigned>::max();
+ unsigned long overflowUnsigned = maxUnsigned + 1;
+
+ EXPECT_GT(overflowUnsigned, maxUnsigned);
+
+ EXPECT_EQ(clampTo<unsigned>(maxUnsigned), maxUnsigned);
+
+ EXPECT_EQ(clampTo<unsigned>(overflowUnsigned), maxUnsigned);
+ EXPECT_EQ(clampTo<unsigned>(-1), 0u);
+}
+
+TEST(WTF, clampToUnsignedLongLong)
+{
+ unsigned long long maxUnsigned = std::numeric_limits<unsigned>::max();
+ unsigned long long overflowUnsigned = maxUnsigned + 1;
+
+ EXPECT_GT(overflowUnsigned, maxUnsigned);
+
+ EXPECT_EQ(clampTo<unsigned>(maxUnsigned), maxUnsigned);
+
+ EXPECT_EQ(clampTo<unsigned>(overflowUnsigned), maxUnsigned);
+ EXPECT_EQ(clampTo<unsigned>(-1), 0u);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/MediaTime.cpp b/Tools/TestWebKitAPI/Tests/WTF/MediaTime.cpp
new file mode 100644
index 000000000..248fa333b
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/MediaTime.cpp
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2012 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.
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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.
+ */
+
+#define _USE_MATH_DEFINES 1
+#include "config.h"
+
+#include <wtf/MediaTime.h>
+
+using namespace std;
+
+namespace WTF {
+
+std::ostream& operator<<(std::ostream& out, const MediaTime& val)
+{
+ out << "{ ";
+ if (val.isInvalid())
+ out << "invalid";
+ else if (val.isPositiveInfinite())
+ out << "+infinite";
+ else if (val.isNegativeInfinite())
+ out << "-infinite";
+ else if (val.hasDoubleValue())
+ out << "double: " << val.toDouble();
+ else
+ out << "value: " << val.timeValue() << ", scale: " << val.timeScale();
+ return out << " }";
+}
+
+}
+
+namespace TestWebKitAPI {
+
+TEST(WTF, MediaTime)
+{
+ // Comparison Operators
+ EXPECT_EQ(MediaTime::positiveInfiniteTime() > MediaTime::negativeInfiniteTime(), true);
+ EXPECT_EQ(MediaTime::negativeInfiniteTime() < MediaTime::positiveInfiniteTime(), true);
+ EXPECT_EQ(MediaTime::negativeInfiniteTime() == MediaTime::negativeInfiniteTime(), true);
+ EXPECT_EQ(MediaTime::positiveInfiniteTime() == MediaTime::positiveInfiniteTime(), true);
+ EXPECT_EQ(MediaTime::positiveInfiniteTime() != MediaTime::negativeInfiniteTime(), true);
+ EXPECT_EQ(MediaTime::invalidTime() == MediaTime::invalidTime(), true);
+ EXPECT_EQ(MediaTime::invalidTime() != MediaTime::invalidTime(), false);
+ EXPECT_EQ(MediaTime::invalidTime() != MediaTime::zeroTime(), true);
+ EXPECT_EQ(MediaTime::invalidTime() > MediaTime::negativeInfiniteTime(), true);
+ EXPECT_EQ(MediaTime::invalidTime() > MediaTime::positiveInfiniteTime(), true);
+ EXPECT_EQ(MediaTime::negativeInfiniteTime() < MediaTime::invalidTime(), true);
+ EXPECT_EQ(MediaTime::positiveInfiniteTime() < MediaTime::invalidTime(), true);
+ EXPECT_EQ(MediaTime::indefiniteTime() == MediaTime::indefiniteTime(), true);
+ EXPECT_EQ(MediaTime::indefiniteTime() != MediaTime::indefiniteTime(), false);
+ EXPECT_EQ(MediaTime::indefiniteTime() != MediaTime::zeroTime(), true);
+ EXPECT_EQ(MediaTime::indefiniteTime() > MediaTime::negativeInfiniteTime(), true);
+ EXPECT_EQ(MediaTime::indefiniteTime() < MediaTime::positiveInfiniteTime(), true);
+ EXPECT_EQ(MediaTime::negativeInfiniteTime() < MediaTime::indefiniteTime(), true);
+ EXPECT_EQ(MediaTime::positiveInfiniteTime() > MediaTime::indefiniteTime(), true);
+ EXPECT_EQ(MediaTime(1, 1) < MediaTime::indefiniteTime(), true);
+ EXPECT_EQ(MediaTime::indefiniteTime() > MediaTime(1, 1), true);
+ EXPECT_EQ(MediaTime(1, 1) < MediaTime(2, 1), true);
+ EXPECT_EQ(MediaTime(2, 1) > MediaTime(1, 1), true);
+ EXPECT_EQ(MediaTime(1, 1) != MediaTime(2, 1), true);
+ EXPECT_EQ(MediaTime(2, 1) == MediaTime(2, 1), true);
+ EXPECT_EQ(MediaTime(2, 1) == MediaTime(4, 2), true);
+
+ // Addition Operators
+ EXPECT_EQ(MediaTime::positiveInfiniteTime() + MediaTime::positiveInfiniteTime(), MediaTime::positiveInfiniteTime());
+ EXPECT_EQ(MediaTime::negativeInfiniteTime() + MediaTime::negativeInfiniteTime(), MediaTime::negativeInfiniteTime());
+ EXPECT_EQ(MediaTime::positiveInfiniteTime() + MediaTime::negativeInfiniteTime(), MediaTime::invalidTime());
+ EXPECT_EQ(MediaTime::negativeInfiniteTime() + MediaTime::positiveInfiniteTime(), MediaTime::invalidTime());
+ EXPECT_EQ(MediaTime::positiveInfiniteTime() + MediaTime(1, 1), MediaTime::positiveInfiniteTime());
+ EXPECT_EQ(MediaTime(1, 1) + MediaTime::positiveInfiniteTime(), MediaTime::positiveInfiniteTime());
+ EXPECT_EQ(MediaTime::negativeInfiniteTime() + MediaTime(1, 1), MediaTime::negativeInfiniteTime());
+ EXPECT_EQ(MediaTime(1, 1) + MediaTime::negativeInfiniteTime(), MediaTime::negativeInfiniteTime());
+ EXPECT_EQ(MediaTime::invalidTime() + MediaTime::positiveInfiniteTime(), MediaTime::invalidTime());
+ EXPECT_EQ(MediaTime::invalidTime() + MediaTime::negativeInfiniteTime(), MediaTime::invalidTime());
+ EXPECT_EQ(MediaTime::invalidTime() + MediaTime::invalidTime(), MediaTime::invalidTime());
+ EXPECT_EQ(MediaTime::invalidTime() + MediaTime(1, 1), MediaTime::invalidTime());
+ EXPECT_EQ(MediaTime::indefiniteTime() + MediaTime::positiveInfiniteTime(), MediaTime::indefiniteTime());
+ EXPECT_EQ(MediaTime::indefiniteTime() + MediaTime::negativeInfiniteTime(), MediaTime::indefiniteTime());
+ EXPECT_EQ(MediaTime::indefiniteTime() + MediaTime::indefiniteTime(), MediaTime::indefiniteTime());
+ EXPECT_EQ(MediaTime::indefiniteTime() + MediaTime(1, 1), MediaTime::indefiniteTime());
+ EXPECT_EQ(MediaTime(1, 1) + MediaTime(1, 1), MediaTime(2, 1));
+ EXPECT_EQ(MediaTime(1, 2) + MediaTime(1, 3), MediaTime(5, 6));
+ EXPECT_EQ(MediaTime(1, numeric_limits<int32_t>::max()-1) + MediaTime(1, numeric_limits<int32_t>::max()-2), MediaTime(2, numeric_limits<int32_t>::max()));
+
+ // Subtraction Operators
+ EXPECT_EQ(MediaTime::positiveInfiniteTime() - MediaTime::positiveInfiniteTime(), MediaTime::invalidTime());
+ EXPECT_EQ(MediaTime::negativeInfiniteTime() - MediaTime::negativeInfiniteTime(), MediaTime::invalidTime());
+ EXPECT_EQ(MediaTime::positiveInfiniteTime() - MediaTime::negativeInfiniteTime(), MediaTime::positiveInfiniteTime());
+ EXPECT_EQ(MediaTime::negativeInfiniteTime() - MediaTime::positiveInfiniteTime(), MediaTime::negativeInfiniteTime());
+ EXPECT_EQ(MediaTime::positiveInfiniteTime() - MediaTime(1, 1), MediaTime::positiveInfiniteTime());
+ EXPECT_EQ(MediaTime(1, 1) - MediaTime::positiveInfiniteTime(), MediaTime::negativeInfiniteTime());
+ EXPECT_EQ(MediaTime::negativeInfiniteTime() - MediaTime(1, 1), MediaTime::negativeInfiniteTime());
+ EXPECT_EQ(MediaTime(1, 1) - MediaTime::negativeInfiniteTime(), MediaTime::positiveInfiniteTime());
+ EXPECT_EQ(MediaTime::invalidTime() - MediaTime::positiveInfiniteTime(), MediaTime::invalidTime());
+ EXPECT_EQ(MediaTime::invalidTime() - MediaTime::negativeInfiniteTime(), MediaTime::invalidTime());
+ EXPECT_EQ(MediaTime::invalidTime() - MediaTime::invalidTime(), MediaTime::invalidTime());
+ EXPECT_EQ(MediaTime::invalidTime() - MediaTime(1, 1), MediaTime::invalidTime());
+ EXPECT_EQ(MediaTime::indefiniteTime() - MediaTime::positiveInfiniteTime(), MediaTime::indefiniteTime());
+ EXPECT_EQ(MediaTime::indefiniteTime() - MediaTime::negativeInfiniteTime(), MediaTime::indefiniteTime());
+ EXPECT_EQ(MediaTime::indefiniteTime() - MediaTime::indefiniteTime(), MediaTime::indefiniteTime());
+ EXPECT_EQ(MediaTime::indefiniteTime() - MediaTime(1, 1), MediaTime::indefiniteTime());
+ EXPECT_EQ(MediaTime(3, 1) - MediaTime(2, 1), MediaTime(1, 1));
+ EXPECT_EQ(MediaTime(1, 2) - MediaTime(1, 3), MediaTime(1, 6));
+ EXPECT_EQ(MediaTime(2, numeric_limits<int32_t>::max()-1) - MediaTime(1, numeric_limits<int32_t>::max()-2), MediaTime(1, numeric_limits<int32_t>::max()));
+
+ // Multiplication Operators
+ EXPECT_EQ(MediaTime::positiveInfiniteTime(), MediaTime::positiveInfiniteTime() * 2);
+ EXPECT_EQ(MediaTime::negativeInfiniteTime(), MediaTime::negativeInfiniteTime() * 2);
+ EXPECT_EQ(MediaTime::negativeInfiniteTime(), MediaTime::positiveInfiniteTime() * -2);
+ EXPECT_EQ(MediaTime::positiveInfiniteTime(), MediaTime::negativeInfiniteTime() * -2);
+ EXPECT_EQ(MediaTime::invalidTime(), MediaTime::invalidTime() * 2);
+ EXPECT_EQ(MediaTime::invalidTime(), MediaTime::invalidTime() * -2);
+ EXPECT_EQ(MediaTime::indefiniteTime(), MediaTime::indefiniteTime() * 2);
+ EXPECT_EQ(MediaTime::indefiniteTime(), MediaTime::indefiniteTime() * -2);
+ EXPECT_EQ(MediaTime(6, 1), MediaTime(3, 1) * 2);
+ EXPECT_EQ(MediaTime(0, 1), MediaTime(0, 1) * 2);
+ EXPECT_EQ(MediaTime(int64_t(1) << 60, 1), MediaTime(int64_t(1) << 60, 2) * 2);
+ EXPECT_EQ(MediaTime::positiveInfiniteTime(), MediaTime(numeric_limits<int64_t>::max(), 1) * 2);
+ EXPECT_EQ(MediaTime::positiveInfiniteTime(), MediaTime(numeric_limits<int64_t>::min(), 1) * -2);
+ EXPECT_EQ(MediaTime::negativeInfiniteTime(), MediaTime(numeric_limits<int64_t>::max(), 1) * -2);
+ EXPECT_EQ(MediaTime::negativeInfiniteTime(), MediaTime(numeric_limits<int64_t>::min(), 1) * 2);
+
+ // Constants
+ EXPECT_EQ(MediaTime::zeroTime(), MediaTime(0, 1));
+ EXPECT_EQ(MediaTime::invalidTime(), MediaTime(-1, 1, 0));
+ EXPECT_EQ(MediaTime::positiveInfiniteTime(), MediaTime(0, 1, MediaTime::PositiveInfinite));
+ EXPECT_EQ(MediaTime::negativeInfiniteTime(), MediaTime(0, 1, MediaTime::NegativeInfinite));
+ EXPECT_EQ(MediaTime::indefiniteTime(), MediaTime(0, 1, MediaTime::Indefinite));
+
+ // Absolute Functions
+ EXPECT_EQ(abs(MediaTime::positiveInfiniteTime()), MediaTime::positiveInfiniteTime());
+ EXPECT_EQ(abs(MediaTime::negativeInfiniteTime()), MediaTime::positiveInfiniteTime());
+ EXPECT_EQ(abs(MediaTime::invalidTime()), MediaTime::invalidTime());
+ EXPECT_EQ(abs(MediaTime(1, 1)), MediaTime(1, 1));
+ EXPECT_EQ(abs(MediaTime(-1, 1)), MediaTime(1, 1));
+ EXPECT_EQ(abs(MediaTime(-1, -1)), MediaTime(-1, -1));
+ EXPECT_EQ(abs(MediaTime(1, -1)), MediaTime(-1, -1));
+
+ // Floating Point Functions
+ EXPECT_EQ(MediaTime::createWithFloat(1.0f), MediaTime(1, 1));
+ EXPECT_EQ(MediaTime::createWithFloat(1.5f), MediaTime(3, 2));
+ EXPECT_EQ(MediaTime::createWithDouble(1.0), MediaTime(1, 1));
+ EXPECT_EQ(MediaTime::createWithDouble(1.5), MediaTime(3, 2));
+ EXPECT_EQ(MediaTime(1, 1).toFloat(), 1.0f);
+ EXPECT_EQ(MediaTime(3, 2).toFloat(), 1.5f);
+ EXPECT_EQ(MediaTime(1, 1).toDouble(), 1.0);
+ EXPECT_EQ(MediaTime(3, 2).toDouble(), 1.5);
+ EXPECT_EQ(MediaTime(1, 1 << 16).toFloat(), 1 / pow(2.0f, 16.0f));
+ EXPECT_EQ(MediaTime(1, 1 << 30).toDouble(), 1 / pow(2.0, 30.0));
+ EXPECT_EQ(MediaTime::createWithDouble(M_PI, 1 << 30), MediaTime(3373259426U, 1 << 30));
+ EXPECT_EQ(MediaTime::createWithFloat(INFINITY), MediaTime::positiveInfiniteTime());
+ EXPECT_EQ(MediaTime::createWithFloat(-INFINITY), MediaTime::negativeInfiniteTime());
+ EXPECT_EQ(MediaTime::createWithFloat(NAN), MediaTime::invalidTime());
+ EXPECT_EQ(MediaTime::createWithDouble(INFINITY), MediaTime::positiveInfiniteTime());
+ EXPECT_EQ(MediaTime::createWithDouble(-INFINITY), MediaTime::negativeInfiniteTime());
+ EXPECT_EQ(MediaTime::createWithDouble(NAN), MediaTime::invalidTime());
+
+ // Floating Point Round Trip
+ EXPECT_EQ(10.0123456789f, MediaTime::createWithFloat(10.0123456789f).toFloat());
+ EXPECT_EQ(10.0123456789, MediaTime::createWithDouble(10.0123456789).toDouble());
+
+ // Floating Point Math
+ EXPECT_EQ(1.5 + 3.3, (MediaTime::createWithDouble(1.5) + MediaTime::createWithDouble(3.3)).toDouble());
+ EXPECT_EQ(1.5 - 3.3, (MediaTime::createWithDouble(1.5) - MediaTime::createWithDouble(3.3)).toDouble());
+ EXPECT_EQ(-3.3, (-MediaTime::createWithDouble(3.3)).toDouble());
+ EXPECT_EQ(3.3 * 2, (MediaTime::createWithDouble(3.3) * 2).toDouble());
+
+ // Floating Point and non-Floating Point math
+ EXPECT_EQ(2.0, (MediaTime::createWithDouble(1.5) + MediaTime(1, 2)).toDouble());
+ EXPECT_EQ(1.0, (MediaTime::createWithDouble(1.5) - MediaTime(1, 2)).toDouble());
+
+ // Overflow Behavior
+ EXPECT_EQ(MediaTime::createWithFloat(pow(2.0f, 64.0f)), MediaTime::positiveInfiniteTime());
+ EXPECT_EQ(MediaTime::createWithFloat(-pow(2.0f, 64.0f)), MediaTime::negativeInfiniteTime());
+ EXPECT_EQ(MediaTime::createWithFloat(pow(2.0f, 63.0f), 2).timeScale(), 1);
+ EXPECT_EQ(MediaTime::createWithFloat(pow(2.0f, 63.0f), 3).timeScale(), 1);
+ EXPECT_EQ(MediaTime::createWithDouble(pow(2.0, 64.0)), MediaTime::positiveInfiniteTime());
+ EXPECT_EQ(MediaTime::createWithDouble(-pow(2.0, 64.0)), MediaTime::negativeInfiniteTime());
+ EXPECT_EQ(MediaTime::createWithDouble(pow(2.0, 63.0), 2).timeScale(), 1);
+ EXPECT_EQ(MediaTime::createWithDouble(pow(2.0, 63.0), 3).timeScale(), 1);
+ EXPECT_EQ((MediaTime(numeric_limits<int64_t>::max(), 2) + MediaTime(numeric_limits<int64_t>::max(), 2)).timeScale(), 1);
+ EXPECT_EQ((MediaTime(numeric_limits<int64_t>::min(), 2) - MediaTime(numeric_limits<int64_t>::max(), 2)).timeScale(), 1);
+ EXPECT_EQ(MediaTime(numeric_limits<int64_t>::max(), 1) + MediaTime(numeric_limits<int64_t>::max(), 1), MediaTime::positiveInfiniteTime());
+ EXPECT_EQ(MediaTime(numeric_limits<int64_t>::min(), 1) + MediaTime(numeric_limits<int64_t>::min(), 1), MediaTime::negativeInfiniteTime());
+ EXPECT_EQ(MediaTime(numeric_limits<int64_t>::min(), 1) - MediaTime(numeric_limits<int64_t>::max(), 1), MediaTime::negativeInfiniteTime());
+ EXPECT_EQ(MediaTime(numeric_limits<int64_t>::max(), 1) - MediaTime(numeric_limits<int64_t>::min(), 1), MediaTime::positiveInfiniteTime());
+}
+
+}
+
diff --git a/Tools/TestWebKitAPI/Tests/WTF/MetaAllocator.cpp b/Tools/TestWebKitAPI/Tests/WTF/MetaAllocator.cpp
new file mode 100644
index 000000000..59af4f849
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/MetaAllocator.cpp
@@ -0,0 +1,957 @@
+/*
+ * Copyright (C) 2011 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.
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 <stdarg.h>
+#include <wtf/MetaAllocator.h>
+#include <wtf/Vector.h>
+
+#if OS(WINDOWS)
+#undef small
+#endif
+
+using namespace WTF;
+
+namespace TestWebKitAPI {
+
+class MetaAllocatorTest: public testing::Test {
+public:
+ enum SanityCheckMode { RunSanityCheck, DontRunSanityCheck };
+
+ enum HeapGrowthMode { DontGrowHeap, ForTestDemandAllocCoalesce, ForTestDemandAllocDontCoalesce };
+
+ HeapGrowthMode currentHeapGrowthMode;
+ size_t allowAllocatePages;
+ size_t requestedNumPages;
+
+ class SimpleTestAllocator: public MetaAllocator {
+ public:
+ SimpleTestAllocator(MetaAllocatorTest* parent)
+ : MetaAllocator(32)
+ , m_parent(parent)
+ {
+ addFreshFreeSpace(reinterpret_cast<void*>(basePage * pageSize()), defaultPagesInHeap * pageSize());
+ }
+
+ virtual ~SimpleTestAllocator()
+ {
+ EXPECT_TRUE(!m_parent->allocatorDestroyed);
+ m_parent->allocatorDestroyed = true;
+ }
+
+ virtual void* allocateNewSpace(size_t& numPages)
+ {
+ switch (m_parent->currentHeapGrowthMode) {
+ case DontGrowHeap:
+ return 0;
+
+ case ForTestDemandAllocCoalesce:
+ case ForTestDemandAllocDontCoalesce: {
+ EXPECT_TRUE(m_parent->allowAllocatePages);
+ EXPECT_TRUE(m_parent->allowAllocatePages >= numPages);
+ m_parent->requestedNumPages = numPages;
+ numPages = m_parent->allowAllocatePages;
+
+ unsigned offset;
+ if (m_parent->currentHeapGrowthMode == ForTestDemandAllocCoalesce)
+ offset = 0;
+ else
+ offset = 1;
+
+ void* result = reinterpret_cast<void*>((basePage + defaultPagesInHeap + offset) * pageSize());
+
+ m_parent->allowAllocatePages = 0;
+ m_parent->currentHeapGrowthMode = DontGrowHeap;
+
+ for (size_t counter = 0; counter < numPages + offset; ++counter) {
+ m_parent->pageMap->append(false);
+ for (unsigned byteCounter = 0; byteCounter < pageSize(); ++byteCounter)
+ m_parent->memoryMap->append(false);
+ }
+
+ m_parent->additionalPagesInHeap += numPages;
+
+ return result;
+ }
+
+ default:
+ CRASH();
+ return 0;
+ }
+ }
+
+ virtual void notifyNeedPage(void* page)
+ {
+ // the page should be both free and unmapped.
+ EXPECT_TRUE(!m_parent->pageState(reinterpret_cast<uintptr_t>(page) / pageSize()));
+ for (uintptr_t address = reinterpret_cast<uintptr_t>(page); address < reinterpret_cast<uintptr_t>(page) + pageSize(); ++address)
+ EXPECT_TRUE(!m_parent->byteState(reinterpret_cast<void*>(address)));
+ m_parent->pageState(reinterpret_cast<uintptr_t>(page) / pageSize()) = true;
+ }
+
+ virtual void notifyPageIsFree(void* page)
+ {
+ // the page should be free of objects at this point, but it should still
+ // be mapped.
+ EXPECT_TRUE(m_parent->pageState(reinterpret_cast<uintptr_t>(page) / pageSize()));
+ for (uintptr_t address = reinterpret_cast<uintptr_t>(page); address < reinterpret_cast<uintptr_t>(page) + pageSize(); ++address)
+ EXPECT_TRUE(!m_parent->byteState(reinterpret_cast<void*>(address)));
+ m_parent->pageState(reinterpret_cast<uintptr_t>(page) / pageSize()) = false;
+ }
+
+ private:
+ MetaAllocatorTest* m_parent;
+ };
+
+ static const unsigned basePage = 1;
+ static const unsigned defaultPagesInHeap = 100;
+
+ unsigned additionalPagesInHeap;
+
+ Vector<bool, 0>* memoryMap;
+ Vector<bool, 0>* pageMap;
+ bool allocatorDestroyed;
+
+ SimpleTestAllocator* allocator;
+
+ virtual void SetUp()
+ {
+ memoryMap = new Vector<bool, 0>();
+ pageMap = new Vector<bool, 0>();
+
+ for (unsigned page = basePage; page < basePage + defaultPagesInHeap; ++page) {
+ pageMap->append(false);
+ for (unsigned byteInPage = 0; byteInPage < pageSize(); ++byteInPage)
+ memoryMap->append(false);
+ }
+
+ allocatorDestroyed = false;
+
+ currentHeapGrowthMode = DontGrowHeap;
+ allowAllocatePages = 0;
+ additionalPagesInHeap = 0;
+ requestedNumPages = 0;
+
+ allocator = new SimpleTestAllocator(this);
+ }
+
+ virtual void TearDown()
+ {
+ EXPECT_TRUE(currentHeapGrowthMode == DontGrowHeap);
+ EXPECT_EQ(allowAllocatePages, static_cast<size_t>(0));
+ EXPECT_EQ(requestedNumPages, static_cast<size_t>(0));
+
+ // memory should be free.
+ for (unsigned page = basePage; page < basePage + defaultPagesInHeap; ++page) {
+ EXPECT_TRUE(!pageState(page));
+ for (unsigned byteInPage = 0; byteInPage < pageSize(); ++byteInPage)
+ EXPECT_TRUE(!byteState(page * pageSize() + byteInPage));
+ }
+
+ // NOTE: this automatically tests that the allocator did not leak
+ // memory, so long as these tests are running with !defined(NDEBUG).
+ // See MetaAllocator::m_mallocBalance.
+ delete allocator;
+
+ EXPECT_TRUE(allocatorDestroyed);
+
+ delete memoryMap;
+ delete pageMap;
+ }
+
+ MetaAllocatorHandle* allocate(size_t sizeInBytes, SanityCheckMode sanityCheckMode = RunSanityCheck)
+ {
+ MetaAllocatorHandle* handle = allocator->allocate(sizeInBytes, 0).leakRef();
+ EXPECT_TRUE(handle);
+ EXPECT_EQ(handle->sizeInBytes(), sizeInBytes);
+
+ uintptr_t startByte = reinterpret_cast<uintptr_t>(handle->start());
+ uintptr_t endByte = startByte + sizeInBytes;
+ for (uintptr_t currentByte = startByte; currentByte < endByte; ++currentByte) {
+ EXPECT_TRUE(!byteState(currentByte));
+ byteState(currentByte) = true;
+ EXPECT_TRUE(pageState(currentByte / pageSize()));
+ }
+
+ if (sanityCheckMode == RunSanityCheck)
+ sanityCheck();
+
+ return handle;
+ }
+
+ void free(MetaAllocatorHandle* handle, SanityCheckMode sanityCheckMode = RunSanityCheck)
+ {
+ EXPECT_TRUE(handle);
+
+ notifyFree(handle->start(), handle->sizeInBytes());
+ handle->deref();
+
+ if (sanityCheckMode == RunSanityCheck)
+ sanityCheck();
+ }
+
+ void notifyFree(void* start, size_t sizeInBytes)
+ {
+ uintptr_t startByte = reinterpret_cast<uintptr_t>(start);
+ uintptr_t endByte = startByte + sizeInBytes;
+ for (uintptr_t currentByte = startByte; currentByte < endByte; ++currentByte) {
+ EXPECT_TRUE(byteState(currentByte));
+ byteState(currentByte) = false;
+ }
+ }
+
+ void sanityCheck()
+ {
+#ifndef NDEBUG
+ EXPECT_EQ(allocator->bytesReserved() - allocator->bytesAllocated(), allocator->debugFreeSpaceSize());
+#endif
+ EXPECT_EQ(allocator->bytesReserved(), (defaultPagesInHeap + additionalPagesInHeap) * pageSize());
+ EXPECT_EQ(allocator->bytesAllocated(), bytesAllocated());
+ EXPECT_EQ(allocator->bytesCommitted(), bytesCommitted());
+ }
+
+ void confirm(MetaAllocatorHandle* handle)
+ {
+ uintptr_t startByte = reinterpret_cast<uintptr_t>(handle->start());
+ confirm(startByte, startByte + handle->sizeInBytes(), true);
+ }
+
+ void confirmHighWatermark(MetaAllocatorHandle* handle)
+ {
+ confirm(reinterpret_cast<uintptr_t>(handle->end()), (basePage + defaultPagesInHeap) * pageSize(), false);
+ }
+
+ void confirm(uintptr_t startByte, uintptr_t endByte, bool value)
+ {
+ for (uintptr_t currentByte = startByte; currentByte < endByte; ++currentByte) {
+ EXPECT_EQ(byteState(currentByte), value);
+ if (value)
+ EXPECT_TRUE(pageState(currentByte / pageSize()));
+ }
+ if (!value) {
+ uintptr_t firstFreePage = (startByte + pageSize() - 1) / pageSize();
+ uintptr_t lastFreePage = (endByte - pageSize()) / pageSize();
+ for (uintptr_t currentPage = firstFreePage; currentPage <= lastFreePage; ++currentPage)
+ EXPECT_TRUE(!pageState(currentPage));
+ }
+ }
+
+ size_t bytesAllocated()
+ {
+ size_t result = 0;
+ for (unsigned index = 0; index < memoryMap->size(); ++index) {
+ if (memoryMap->at(index))
+ result++;
+ }
+ return result;
+ }
+
+ size_t bytesCommitted()
+ {
+ size_t result = 0;
+ for (unsigned index = 0; index < pageMap->size(); ++index) {
+ if (pageMap->at(index))
+ result++;
+ }
+ return result * pageSize();
+ }
+
+ bool& byteState(void* address)
+ {
+ return byteState(reinterpret_cast<uintptr_t>(address));
+ }
+
+ bool& byteState(uintptr_t address)
+ {
+ uintptr_t byteIndex = address - basePage * pageSize();
+ return memoryMap->at(byteIndex);
+ }
+
+ bool& pageState(uintptr_t page)
+ {
+ uintptr_t pageIndex = page - basePage;
+ return pageMap->at(pageIndex);
+ }
+
+ // Test helpers
+
+ void testOneAlloc(size_t size)
+ {
+ // Tests the most basic behavior: allocate one thing and free it. Also
+ // verifies that the state of pages is correct.
+
+ MetaAllocatorHandle* handle = allocate(size);
+ EXPECT_EQ(handle->start(), reinterpret_cast<void*>(basePage * pageSize()));
+ EXPECT_EQ(handle->sizeInBytes(), size);
+ EXPECT_TRUE(pageState(basePage));
+
+ confirm(handle);
+ confirmHighWatermark(handle);
+
+ free(handle);
+ }
+
+ void testRepeatAllocFree(size_t firstSize, ...)
+ {
+ // Tests right-coalescing by repeatedly allocating and freeing. The idea
+ // is that if you allocate something and then free it, then the heap should
+ // look identical to what it was before the allocation due to a right-coalesce
+ // of the freed chunk and the already-free memory, and so subsequent
+ // allocations should behave the same as the first one.
+
+ MetaAllocatorHandle* handle = allocate(firstSize);
+ EXPECT_EQ(handle->start(), reinterpret_cast<void*>(basePage * pageSize()));
+ EXPECT_EQ(handle->sizeInBytes(), firstSize);
+
+ confirm(handle);
+ confirmHighWatermark(handle);
+
+ free(handle);
+
+ va_list argList;
+ va_start(argList, firstSize);
+ while (size_t sizeInBytes = va_arg(argList, int)) {
+ handle = allocate(sizeInBytes);
+ EXPECT_EQ(handle->start(), reinterpret_cast<void*>(basePage * pageSize()));
+ EXPECT_EQ(handle->sizeInBytes(), sizeInBytes);
+
+ confirm(handle);
+ confirmHighWatermark(handle);
+
+ free(handle);
+ }
+ va_end(argList);
+ }
+
+ void testSimpleFullCoalesce(size_t firstSize, size_t secondSize, size_t thirdSize)
+ {
+ // Allocates something of size firstSize, then something of size secondSize, and then
+ // frees the first allocation, and then the second, and then attempts to allocate the
+ // third, asserting that it allocated at the base address of the heap.
+
+ // Note that this test may cause right-allocation, which will cause the test to fail.
+ // Thus the correct way of running this test is to ensure that secondSize is
+ // picked in such a way that it never straddles a page.
+
+ MetaAllocatorHandle* firstHandle = allocate(firstSize);
+ EXPECT_EQ(firstHandle->start(), reinterpret_cast<void*>(basePage * pageSize()));
+ EXPECT_EQ(firstHandle->sizeInBytes(), firstSize);
+
+ confirm(firstHandle);
+ confirmHighWatermark(firstHandle);
+
+ MetaAllocatorHandle* secondHandle = allocate(secondSize);
+ EXPECT_EQ(secondHandle->start(), reinterpret_cast<void*>(basePage * pageSize() + firstSize));
+ EXPECT_EQ(secondHandle->sizeInBytes(), secondSize);
+
+ confirm(firstHandle);
+ confirm(secondHandle);
+ confirmHighWatermark(secondHandle);
+
+ free(firstHandle);
+
+ confirm(secondHandle);
+ confirmHighWatermark(secondHandle);
+
+ free(secondHandle);
+
+ confirm(basePage * pageSize(), (basePage + defaultPagesInHeap) * pageSize(), false);
+
+ MetaAllocatorHandle* thirdHandle = allocate(thirdSize);
+ EXPECT_EQ(thirdHandle->start(), reinterpret_cast<void*>(basePage * pageSize()));
+ EXPECT_EQ(thirdHandle->sizeInBytes(), thirdSize);
+
+ confirm(thirdHandle);
+ confirmHighWatermark(thirdHandle);
+
+ free(thirdHandle);
+ }
+
+ enum TestFIFOAllocMode { FillAtEnd, EagerFill };
+ void testFIFOAlloc(TestFIFOAllocMode mode, ...)
+ {
+ // This will test the simple case of no-coalesce (freeing the left-most
+ // chunk in memory when the chunk to the right of it is allocated) and
+ // fully exercise left-coalescing and full-coalescing. In EagerFill
+ // mode, this also tests perfect-fit allocation and no-coalescing free.
+
+ size_t totalSize = 0;
+
+ Vector<MetaAllocatorHandle*, 0> handles;
+
+ va_list argList;
+ va_start(argList, mode);
+ while (size_t sizeInBytes = va_arg(argList, int)) {
+ MetaAllocatorHandle* handle = allocate(sizeInBytes);
+ EXPECT_EQ(handle->start(), reinterpret_cast<void*>(basePage * pageSize() + totalSize));
+ EXPECT_EQ(handle->sizeInBytes(), sizeInBytes);
+
+ confirm(handle);
+ confirmHighWatermark(handle);
+
+ handles.append(handle);
+ totalSize += sizeInBytes;
+ }
+ va_end(argList);
+
+ for (unsigned index = 0; index < handles.size(); ++index)
+ confirm(handles.at(index));
+
+ size_t sizeSoFar = 0;
+ for (unsigned index = 0; index < handles.size(); ++index) {
+ sizeSoFar += handles.at(index)->sizeInBytes();
+ free(handles.at(index));
+ if (mode == EagerFill) {
+ MetaAllocatorHandle* handle = allocate(sizeSoFar);
+ EXPECT_EQ(handle->start(), reinterpret_cast<void*>(basePage * pageSize()));
+ EXPECT_EQ(handle->sizeInBytes(), sizeSoFar);
+
+ confirm(basePage * pageSize(), basePage * pageSize() + totalSize, true);
+ if (index < handles.size() - 1)
+ confirmHighWatermark(handles.last());
+ else
+ confirmHighWatermark(handle);
+
+ free(handle);
+
+ confirm(basePage * pageSize(), basePage * pageSize() + sizeSoFar, false);
+ }
+ }
+
+ ASSERT(sizeSoFar == totalSize);
+
+ confirm(basePage * pageSize(), (basePage + defaultPagesInHeap) * pageSize(), false);
+
+ if (mode == FillAtEnd) {
+ MetaAllocatorHandle* finalHandle = allocate(totalSize);
+ EXPECT_EQ(finalHandle->start(), reinterpret_cast<void*>(basePage * pageSize()));
+ EXPECT_EQ(finalHandle->sizeInBytes(), totalSize);
+
+ confirm(finalHandle);
+ confirmHighWatermark(finalHandle);
+
+ free(finalHandle);
+ }
+ }
+
+ void testFillHeap(size_t sizeInBytes, size_t numAllocations)
+ {
+ Vector<MetaAllocatorHandle*, 0> handles;
+
+ for (size_t index = 0; index < numAllocations; ++index)
+ handles.append(allocate(sizeInBytes, DontRunSanityCheck));
+
+ sanityCheck();
+
+ EXPECT_TRUE(!allocator->allocate(sizeInBytes, 0));
+
+ for (size_t index = 0; index < numAllocations; ++index)
+ free(handles.at(index), DontRunSanityCheck);
+
+ sanityCheck();
+ }
+
+ void testRightAllocation(size_t firstLeftSize, size_t firstRightSize, size_t secondLeftSize, size_t secondRightSize)
+ {
+ MetaAllocatorHandle* firstLeft = allocate(firstLeftSize);
+ EXPECT_EQ(firstLeft->start(), reinterpret_cast<void*>(basePage * pageSize()));
+
+ MetaAllocatorHandle* firstRight = allocate(firstRightSize);
+ EXPECT_EQ(firstRight->end(), reinterpret_cast<void*>((basePage + defaultPagesInHeap) * pageSize()));
+
+ MetaAllocatorHandle* secondLeft = allocate(secondLeftSize);
+ EXPECT_EQ(secondLeft->start(), reinterpret_cast<void*>(basePage * pageSize() + firstLeft->sizeInBytes()));
+
+ MetaAllocatorHandle* secondRight = allocate(secondRightSize);
+ EXPECT_EQ(secondRight->end(), reinterpret_cast<void*>((basePage + defaultPagesInHeap) * pageSize() - firstRight->sizeInBytes()));
+
+ free(firstLeft);
+ free(firstRight);
+ free(secondLeft);
+ free(secondRight);
+
+ MetaAllocatorHandle* final = allocate(defaultPagesInHeap * pageSize());
+ EXPECT_EQ(final->start(), reinterpret_cast<void*>(basePage * pageSize()));
+
+ free(final);
+ }
+
+ void testBestFit(size_t firstSize, size_t step, unsigned numSlots, SanityCheckMode sanityCheckMode)
+ {
+ Vector<MetaAllocatorHandle*, 0> handlesToFree;
+ Vector<MetaAllocatorHandle*, 0> handles;
+ Vector<void*, 0> locations;
+
+ size_t size = firstSize;
+ for (unsigned index = 0; index < numSlots; ++index) {
+ MetaAllocatorHandle* toFree = allocate(size, sanityCheckMode);
+ if (!handles.isEmpty()) {
+ while (toFree->start() != handles.last()->end()) {
+ handlesToFree.append(toFree);
+ toFree = allocate(size, sanityCheckMode);
+ }
+ }
+
+ MetaAllocatorHandle* fragger = allocate(32, sanityCheckMode);
+ EXPECT_EQ(fragger->start(), toFree->end());
+
+ locations.append(toFree->start());
+
+ handlesToFree.append(toFree);
+ handles.append(fragger);
+
+ size += step;
+ }
+
+ ASSERT(locations.size() == numSlots);
+
+ for (unsigned index = 0; index < handlesToFree.size(); ++index)
+ free(handlesToFree.at(index), sanityCheckMode);
+
+ size = firstSize;
+ for (unsigned index = 0; index < numSlots; ++index) {
+ MetaAllocatorHandle* bestFit = allocate(size - 32, sanityCheckMode);
+
+ EXPECT_TRUE(bestFit->start() == locations.at(index)
+ || bestFit->end() == reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(locations.at(index)) + size));
+
+ MetaAllocatorHandle* small = allocate(32, sanityCheckMode);
+ if (bestFit->start() == locations.at(index))
+ EXPECT_EQ(small->start(), bestFit->end());
+ else
+ EXPECT_EQ(small->end(), bestFit->start());
+
+ free(bestFit, sanityCheckMode);
+ free(small, sanityCheckMode);
+
+ size += step;
+ }
+
+ for (unsigned index = 0; index < numSlots; ++index)
+ free(handles.at(index), sanityCheckMode);
+
+ MetaAllocatorHandle* final = allocate(defaultPagesInHeap * pageSize(), sanityCheckMode);
+ EXPECT_EQ(final->start(), reinterpret_cast<void*>(basePage * pageSize()));
+
+ free(final, sanityCheckMode);
+ }
+
+ void testShrink(size_t firstSize, size_t secondSize)
+ {
+ // Allocate the thing that will be shrunk
+ MetaAllocatorHandle* handle = allocate(firstSize);
+
+ // Shrink it, and make sure that our state reflects the shrinkage.
+ notifyFree(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(handle->start()) + secondSize), firstSize - secondSize);
+
+ handle->shrink(secondSize);
+ EXPECT_EQ(handle->sizeInBytes(), secondSize);
+
+ sanityCheck();
+
+ // Assert that the heap is not empty.
+ EXPECT_TRUE(!allocator->allocate(defaultPagesInHeap * pageSize(), 0));
+
+ // Allocate the remainder of the heap.
+ MetaAllocatorHandle* remainder = allocate(defaultPagesInHeap * pageSize() - secondSize);
+ EXPECT_EQ(remainder->start(), handle->end());
+
+ free(remainder);
+ free(handle);
+
+ // Assert that the heap is empty and finish up.
+ MetaAllocatorHandle* final = allocate(defaultPagesInHeap * pageSize());
+ EXPECT_EQ(final->start(), reinterpret_cast<void*>(basePage * pageSize()));
+
+ free(final);
+ }
+
+ void testDemandAllocCoalesce(size_t firstSize, size_t numPages, size_t secondSize)
+ {
+ EXPECT_TRUE(!allocator->allocate((defaultPagesInHeap + numPages) * pageSize(), 0));
+
+ MetaAllocatorHandle* firstHandle = allocate(firstSize);
+
+ EXPECT_TRUE(!allocator->allocate(secondSize, 0));
+ EXPECT_TRUE(!allocator->allocate((defaultPagesInHeap + numPages) * pageSize(), 0));
+
+ currentHeapGrowthMode = ForTestDemandAllocCoalesce;
+ allowAllocatePages = numPages;
+
+ MetaAllocatorHandle* secondHandle = allocate(secondSize);
+
+ EXPECT_TRUE(currentHeapGrowthMode == DontGrowHeap);
+ EXPECT_EQ(allowAllocatePages, static_cast<size_t>(0));
+ EXPECT_EQ(requestedNumPages, (secondSize + pageSize() - 1) / pageSize());
+ EXPECT_EQ(secondHandle->start(), reinterpret_cast<void*>((basePage + defaultPagesInHeap) * pageSize()));
+
+ requestedNumPages = 0;
+
+ free(firstHandle);
+ free(secondHandle);
+
+ free(allocate((defaultPagesInHeap + numPages) * pageSize()));
+ }
+
+ void testDemandAllocDontCoalesce(size_t firstSize, size_t numPages, size_t secondSize)
+ {
+ free(allocate(firstSize));
+ free(allocate(defaultPagesInHeap * pageSize()));
+ EXPECT_TRUE(!allocator->allocate((defaultPagesInHeap + numPages) * pageSize(), 0));
+
+ MetaAllocatorHandle* firstHandle = allocate(firstSize);
+
+ EXPECT_TRUE(!allocator->allocate(secondSize, 0));
+ EXPECT_TRUE(!allocator->allocate((defaultPagesInHeap + numPages) * pageSize(), 0));
+
+ currentHeapGrowthMode = ForTestDemandAllocDontCoalesce;
+ allowAllocatePages = numPages;
+
+ MetaAllocatorHandle* secondHandle = allocate(secondSize);
+
+ EXPECT_TRUE(currentHeapGrowthMode == DontGrowHeap);
+ EXPECT_EQ(allowAllocatePages, static_cast<size_t>(0));
+ EXPECT_EQ(requestedNumPages, (secondSize + pageSize() - 1) / pageSize());
+ EXPECT_EQ(secondHandle->start(), reinterpret_cast<void*>((basePage + defaultPagesInHeap + 1) * pageSize()));
+
+ requestedNumPages = 0;
+
+ EXPECT_TRUE(!allocator->allocate((defaultPagesInHeap + numPages) * pageSize(), 0));
+
+ free(firstHandle);
+ free(secondHandle);
+
+ EXPECT_TRUE(!allocator->allocate((defaultPagesInHeap + numPages) * pageSize(), 0));
+
+ firstHandle = allocate(firstSize);
+ secondHandle = allocate(secondSize);
+ EXPECT_EQ(firstHandle->start(), reinterpret_cast<void*>(basePage * pageSize()));
+ EXPECT_EQ(secondHandle->start(), reinterpret_cast<void*>((basePage + defaultPagesInHeap + 1) * pageSize()));
+ free(firstHandle);
+ free(secondHandle);
+ }
+};
+
+TEST_F(MetaAllocatorTest, Empty)
+{
+ // Tests that creating and destroying an allocator works.
+}
+
+TEST_F(MetaAllocatorTest, AllocZero)
+{
+ // Tests that allocating a zero-length block returns 0 and
+ // does not change anything in memory.
+
+ ASSERT(!allocator->allocate(0, 0));
+
+ MetaAllocatorHandle* final = allocate(defaultPagesInHeap * pageSize());
+ EXPECT_EQ(final->start(), reinterpret_cast<void*>(basePage * pageSize()));
+ free(final);
+}
+
+TEST_F(MetaAllocatorTest, OneAlloc32)
+{
+ testOneAlloc(32);
+}
+
+TEST_F(MetaAllocatorTest, OneAlloc64)
+{
+ testOneAlloc(64);
+}
+
+TEST_F(MetaAllocatorTest, OneAllocTwoPages)
+{
+ testOneAlloc(pageSize() * 2);
+}
+
+TEST_F(MetaAllocatorTest, RepeatAllocFree32Twice)
+{
+ testRepeatAllocFree(32, 32, 0);
+}
+
+TEST_F(MetaAllocatorTest, RepeatAllocFree32Then64)
+{
+ testRepeatAllocFree(32, 64, 0);
+}
+
+TEST_F(MetaAllocatorTest, RepeatAllocFree64Then32)
+{
+ testRepeatAllocFree(64, 32, 0);
+}
+
+TEST_F(MetaAllocatorTest, RepeatAllocFree32TwiceThen64)
+{
+ testRepeatAllocFree(32, 32, 64, 0);
+}
+
+TEST_F(MetaAllocatorTest, RepeatAllocFree32Then64Twice)
+{
+ testRepeatAllocFree(32, 64, 64, 0);
+}
+
+TEST_F(MetaAllocatorTest, RepeatAllocFree64Then32Then64)
+{
+ testRepeatAllocFree(64, 32, 64, 0);
+}
+
+TEST_F(MetaAllocatorTest, RepeatAllocFree32Thrice)
+{
+ testRepeatAllocFree(32, 32, 32, 0);
+}
+
+TEST_F(MetaAllocatorTest, RepeatAllocFree32Then64Then32)
+{
+ testRepeatAllocFree(32, 32, 32, 0);
+}
+
+TEST_F(MetaAllocatorTest, RepeatAllocFree64Then32Twice)
+{
+ testRepeatAllocFree(64, 32, 32, 0);
+}
+
+TEST_F(MetaAllocatorTest, RepeatAllocFreeTwoPagesThen32)
+{
+ testRepeatAllocFree(static_cast<int>(pageSize() * 2), 32, 0);
+}
+
+TEST_F(MetaAllocatorTest, RepeatAllocFree32ThenTwoPages)
+{
+ testRepeatAllocFree(32, static_cast<int>(pageSize() * 2), 0);
+}
+
+TEST_F(MetaAllocatorTest, RepeatAllocFreePageThenTwoPages)
+{
+ testRepeatAllocFree(static_cast<int>(pageSize()), static_cast<int>(pageSize() * 2), 0);
+}
+
+TEST_F(MetaAllocatorTest, RepeatAllocFreeTwoPagesThenPage)
+{
+ testRepeatAllocFree(static_cast<int>(pageSize() * 2), static_cast<int>(pageSize()), 0);
+}
+
+TEST_F(MetaAllocatorTest, SimpleFullCoalesce32Plus32Then128)
+{
+ testSimpleFullCoalesce(32, 32, 128);
+}
+
+TEST_F(MetaAllocatorTest, SimpleFullCoalesce32Plus64Then128)
+{
+ testSimpleFullCoalesce(32, 64, 128);
+}
+
+TEST_F(MetaAllocatorTest, SimpleFullCoalesce64Plus32Then128)
+{
+ testSimpleFullCoalesce(64, 32, 128);
+}
+
+TEST_F(MetaAllocatorTest, SimpleFullCoalesce32PlusPageLess32ThenPage)
+{
+ testSimpleFullCoalesce(32, pageSize() - 32, pageSize());
+}
+
+TEST_F(MetaAllocatorTest, SimpleFullCoalesce32PlusPageLess32ThenTwoPages)
+{
+ testSimpleFullCoalesce(32, pageSize() - 32, pageSize() * 2);
+}
+
+TEST_F(MetaAllocatorTest, SimpleFullCoalescePagePlus32ThenTwoPages)
+{
+ testSimpleFullCoalesce(pageSize(), 32, pageSize() * 2);
+}
+
+TEST_F(MetaAllocatorTest, SimpleFullCoalescePagePlusPageThenTwoPages)
+{
+ testSimpleFullCoalesce(pageSize(), pageSize(), pageSize() * 2);
+}
+
+TEST_F(MetaAllocatorTest, FIFOAllocFillAtEnd32Twice)
+{
+ testFIFOAlloc(FillAtEnd, 32, 32, 0);
+}
+
+TEST_F(MetaAllocatorTest, FIFOAllocFillAtEnd32Thrice)
+{
+ testFIFOAlloc(FillAtEnd, 32, 32, 32, 0);
+}
+
+TEST_F(MetaAllocatorTest, FIFOAllocFillAtEnd32FourTimes)
+{
+ testFIFOAlloc(FillAtEnd, 32, 32, 32, 32, 0);
+}
+
+TEST_F(MetaAllocatorTest, FIFOAllocFillAtEndPageLess32Then32ThenPageLess64Then64)
+{
+ testFIFOAlloc(FillAtEnd, static_cast<int>(pageSize() - 32), 32, static_cast<int>(pageSize() - 64), 64, 0);
+}
+
+TEST_F(MetaAllocatorTest, FIFOAllocEagerFill32Twice)
+{
+ testFIFOAlloc(EagerFill, 32, 32, 0);
+}
+
+TEST_F(MetaAllocatorTest, FIFOAllocEagerFill32Thrice)
+{
+ testFIFOAlloc(EagerFill, 32, 32, 32, 0);
+}
+
+TEST_F(MetaAllocatorTest, FIFOAllocEagerFill32FourTimes)
+{
+ testFIFOAlloc(EagerFill, 32, 32, 32, 32, 0);
+}
+
+TEST_F(MetaAllocatorTest, FIFOAllocEagerFillPageLess32Then32ThenPageLess64Then64)
+{
+ testFIFOAlloc(EagerFill, static_cast<int>(pageSize() - 32), 32, static_cast<int>(pageSize() - 64), 64, 0);
+}
+
+TEST_F(MetaAllocatorTest, FillHeap32)
+{
+ testFillHeap(32, defaultPagesInHeap * pageSize() / 32);
+}
+
+TEST_F(MetaAllocatorTest, FillHeapPage)
+{
+ testFillHeap(pageSize(), defaultPagesInHeap);
+}
+
+TEST_F(MetaAllocatorTest, FillHeapTwoPages)
+{
+ testFillHeap(pageSize() * 2, defaultPagesInHeap / 2);
+}
+
+TEST_F(MetaAllocatorTest, RightAllocation32ThenPageThen32ThenPage)
+{
+ testRightAllocation(32, pageSize(), 32, pageSize());
+}
+
+TEST_F(MetaAllocatorTest, RightAllocationQuarterPageThenPageThenQuarterPageThenPage)
+{
+ testRightAllocation(pageSize() / 4, pageSize(), pageSize() / 4, pageSize());
+}
+
+TEST_F(MetaAllocatorTest, BestFit64Plus64Thrice)
+{
+ testBestFit(64, 64, 3, RunSanityCheck);
+}
+
+TEST_F(MetaAllocatorTest, BestFit64Plus64TenTimes)
+{
+ testBestFit(64, 64, 10, DontRunSanityCheck);
+}
+
+TEST_F(MetaAllocatorTest, BestFit64Plus64HundredTimes)
+{
+ testBestFit(64, 64, 100, DontRunSanityCheck);
+}
+
+TEST_F(MetaAllocatorTest, BestFit96Plus64Thrice)
+{
+ testBestFit(96, 64, 3, RunSanityCheck);
+}
+
+TEST_F(MetaAllocatorTest, BestFit96Plus64TenTimes)
+{
+ testBestFit(96, 64, 10, DontRunSanityCheck);
+}
+
+TEST_F(MetaAllocatorTest, BestFit96Plus64HundredTimes)
+{
+ testBestFit(96, 64, 100, DontRunSanityCheck);
+}
+
+TEST_F(MetaAllocatorTest, BestFit96Plus96Thrice)
+{
+ testBestFit(96, 96, 3, RunSanityCheck);
+}
+
+TEST_F(MetaAllocatorTest, BestFit96Plus96TenTimes)
+{
+ testBestFit(96, 96, 10, DontRunSanityCheck);
+}
+
+TEST_F(MetaAllocatorTest, BestFit96Plus96EightyTimes)
+{
+ testBestFit(96, 96, 80, DontRunSanityCheck);
+}
+
+TEST_F(MetaAllocatorTest, Shrink64To32)
+{
+ testShrink(64, 32);
+}
+
+TEST_F(MetaAllocatorTest, ShrinkPageTo32)
+{
+ testShrink(pageSize(), 32);
+}
+
+TEST_F(MetaAllocatorTest, ShrinkPageToPageLess32)
+{
+ testShrink(pageSize(), pageSize() - 32);
+}
+
+TEST_F(MetaAllocatorTest, ShrinkTwoPagesTo32)
+{
+ testShrink(pageSize() * 2, 32);
+}
+
+TEST_F(MetaAllocatorTest, ShrinkTwoPagesToPagePlus32)
+{
+ testShrink(pageSize() * 2, pageSize() + 32);
+}
+
+TEST_F(MetaAllocatorTest, ShrinkTwoPagesToPage)
+{
+ testShrink(pageSize() * 2, pageSize());
+}
+
+TEST_F(MetaAllocatorTest, ShrinkTwoPagesToPageLess32)
+{
+ testShrink(pageSize() * 2, pageSize() - 32);
+}
+
+TEST_F(MetaAllocatorTest, ShrinkTwoPagesToTwoPagesLess32)
+{
+ testShrink(pageSize() * 2, pageSize() * 2 - 32);
+}
+
+TEST_F(MetaAllocatorTest, DemandAllocCoalescePageThenDoubleHeap)
+{
+ testDemandAllocCoalesce(pageSize(), defaultPagesInHeap, defaultPagesInHeap * pageSize());
+}
+
+TEST_F(MetaAllocatorTest, DemandAllocCoalescePageThenTripleHeap)
+{
+ testDemandAllocCoalesce(pageSize(), defaultPagesInHeap * 2, defaultPagesInHeap * pageSize());
+}
+
+TEST_F(MetaAllocatorTest, DemandAllocDontCoalescePageThenDoubleHeap)
+{
+ testDemandAllocDontCoalesce(pageSize(), defaultPagesInHeap, defaultPagesInHeap * pageSize());
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/MoveOnly.h b/Tools/TestWebKitAPI/Tests/WTF/MoveOnly.h
new file mode 100644
index 000000000..cecc49152
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/MoveOnly.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef MoveOnly_h
+#define MoveOnly_h
+
+#include <wtf/HashFunctions.h>
+#include <wtf/HashTraits.h>
+
+class MoveOnly {
+public:
+ MoveOnly()
+ : m_value(0)
+ {
+ }
+
+ MoveOnly(unsigned value)
+ : m_value(value)
+ {
+ }
+
+ unsigned value() const
+ {
+ return m_value;
+ }
+
+ MoveOnly(MoveOnly&& other)
+ : m_value(other.m_value)
+ {
+ other.m_value = 0;
+ }
+
+ MoveOnly& operator=(MoveOnly&& other)
+ {
+ if (this == &other)
+ return *this;
+
+ m_value = other.m_value;
+ other.m_value = 0;
+ return *this;
+ }
+
+ friend bool operator==(const MoveOnly& a, const MoveOnly& b)
+ {
+ return a.m_value == b.m_value;
+ }
+
+private:
+ unsigned m_value;
+};
+
+namespace WTF {
+
+template<> struct HashTraits<MoveOnly> : public GenericHashTraits<MoveOnly> {
+ static void constructDeletedValue(MoveOnly& slot) { slot = MoveOnly(std::numeric_limits<unsigned>::max()); }
+ static bool isDeletedValue(const MoveOnly& slot) { return slot.value() == std::numeric_limits<unsigned>::max(); }
+};
+
+template<> struct DefaultHash<MoveOnly> {
+ struct Hash {
+ static unsigned hash(const MoveOnly& key)
+ {
+ return intHash(key.value());
+ }
+
+ static bool equal(const MoveOnly& a, const MoveOnly& b)
+ {
+ return a == b;
+ }
+
+ static const bool safeToCompareToEmptyOrDeleted = true;
+ };
+};
+} // namespace WTF
+
+#endif // MoveOnly_h
diff --git a/Tools/TestWebKitAPI/Tests/WTF/NakedPtr.cpp b/Tools/TestWebKitAPI/Tests/WTF/NakedPtr.cpp
new file mode 100644
index 000000000..414507f15
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/NakedPtr.cpp
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2015 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. ``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
+ * 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 "RefLogger.h"
+#include <wtf/NakedPtr.h>
+
+namespace TestWebKitAPI {
+
+// For these tests, we need a base class and a derived class. For this purpose,
+// we reuse the RefLogger and DerivedRefLogger classes.
+
+TEST(WTF_NakedPtr, Basic)
+{
+ DerivedRefLogger a("a");
+
+ NakedPtr<RefLogger> empty;
+ ASSERT_EQ(nullptr, empty.get());
+
+ {
+ NakedPtr<RefLogger> ptr(&a);
+ ASSERT_EQ(&a, ptr.get());
+ ASSERT_EQ(&a, &*ptr);
+ ASSERT_EQ(&a.name, &ptr->name);
+ }
+
+ {
+ NakedPtr<RefLogger> ptr = &a;
+ ASSERT_EQ(&a, ptr.get());
+ }
+
+ {
+ NakedPtr<RefLogger> p1 = &a;
+ NakedPtr<RefLogger> p2(p1);
+ ASSERT_EQ(&a, p1.get());
+ ASSERT_EQ(&a, p2.get());
+ }
+
+ {
+ NakedPtr<RefLogger> p1 = &a;
+ NakedPtr<RefLogger> p2 = p1;
+ ASSERT_EQ(&a, p1.get());
+ ASSERT_EQ(&a, p2.get());
+ }
+
+ {
+ NakedPtr<RefLogger> p1 = &a;
+ NakedPtr<RefLogger> p2 = WTF::move(p1);
+ ASSERT_EQ(&a, p1.get());
+ ASSERT_EQ(&a, p2.get());
+ }
+
+ {
+ NakedPtr<RefLogger> p1 = &a;
+ NakedPtr<RefLogger> p2(WTF::move(p1));
+ ASSERT_EQ(&a, p1.get());
+ ASSERT_EQ(&a, p2.get());
+ }
+
+ {
+ NakedPtr<DerivedRefLogger> p1 = &a;
+ NakedPtr<RefLogger> p2 = p1;
+ ASSERT_EQ(&a, p1.get());
+ ASSERT_EQ(&a, p2.get());
+ }
+
+ {
+ NakedPtr<DerivedRefLogger> p1 = &a;
+ NakedPtr<RefLogger> p2 = WTF::move(p1);
+ ASSERT_EQ(&a, p1.get());
+ ASSERT_EQ(&a, p2.get());
+ }
+
+ {
+ NakedPtr<RefLogger> ptr(&a);
+ ASSERT_EQ(&a, ptr.get());
+ ptr.clear();
+ ASSERT_EQ(nullptr, ptr.get());
+ }
+}
+
+TEST(WTF_NakedPtr, Assignment)
+{
+ DerivedRefLogger a("a");
+ RefLogger b("b");
+ DerivedRefLogger c("c");
+
+ {
+ NakedPtr<RefLogger> p1(&a);
+ NakedPtr<RefLogger> p2(&b);
+ ASSERT_EQ(&a, p1.get());
+ ASSERT_EQ(&b, p2.get());
+ p1 = p2;
+ ASSERT_EQ(&b, p1.get());
+ ASSERT_EQ(&b, p2.get());
+ }
+
+ {
+ NakedPtr<RefLogger> ptr(&a);
+ ASSERT_EQ(&a, ptr.get());
+ ptr = &b;
+ ASSERT_EQ(&b, ptr.get());
+ }
+
+ {
+ NakedPtr<RefLogger> ptr(&a);
+ ASSERT_EQ(&a, ptr.get());
+ ptr = nullptr;
+ ASSERT_EQ(nullptr, ptr.get());
+ }
+
+ {
+ NakedPtr<RefLogger> p1(&a);
+ NakedPtr<RefLogger> p2(&b);
+ ASSERT_EQ(&a, p1.get());
+ ASSERT_EQ(&b, p2.get());
+ p1 = WTF::move(p2);
+ ASSERT_EQ(&b, p1.get());
+ ASSERT_EQ(&b, p2.get());
+ }
+
+ {
+ NakedPtr<RefLogger> p1(&a);
+ NakedPtr<DerivedRefLogger> p2(&c);
+ ASSERT_EQ(&a, p1.get());
+ ASSERT_EQ(&c, p2.get());
+ p1 = p2;
+ ASSERT_EQ(&c, p1.get());
+ ASSERT_EQ(&c, p2.get());
+ }
+
+ {
+ NakedPtr<RefLogger> ptr(&a);
+ ASSERT_EQ(&a, ptr.get());
+ ptr = &c;
+ ASSERT_EQ(&c, ptr.get());
+ }
+
+ {
+ NakedPtr<RefLogger> p1(&a);
+ NakedPtr<DerivedRefLogger> p2(&c);
+ ASSERT_EQ(&a, p1.get());
+ ASSERT_EQ(&c, p2.get());
+ p1 = WTF::move(p2);
+ ASSERT_EQ(&c, p1.get());
+ ASSERT_EQ(&c, p2.get());
+ }
+
+ {
+ NakedPtr<RefLogger> ptr(&a);
+ ASSERT_EQ(&a, ptr.get());
+ ptr = ptr;
+ ASSERT_EQ(&a, ptr.get());
+ }
+
+ {
+ NakedPtr<RefLogger> ptr(&a);
+ ASSERT_EQ(&a, ptr.get());
+ ptr = WTF::move(ptr);
+ ASSERT_EQ(&a, ptr.get());
+ }
+}
+
+TEST(WTF_NakedPtr, Swap)
+{
+ RefLogger a("a");
+ RefLogger b("b");
+
+ {
+ NakedPtr<RefLogger> p1(&a);
+ NakedPtr<RefLogger> p2(&b);
+ ASSERT_EQ(&a, p1.get());
+ ASSERT_EQ(&b, p2.get());
+ p1.swap(p2);
+ ASSERT_EQ(&b, p1.get());
+ ASSERT_EQ(&a, p2.get());
+ }
+
+ {
+ NakedPtr<RefLogger> p1(&a);
+ NakedPtr<RefLogger> p2(&b);
+ ASSERT_EQ(&a, p1.get());
+ ASSERT_EQ(&b, p2.get());
+ std::swap(p1, p2);
+ ASSERT_EQ(&b, p1.get());
+ ASSERT_EQ(&a, p2.get());
+ }
+}
+
+NakedPtr<RefLogger> nakedPtrFoo(RefLogger& logger)
+{
+ return NakedPtr<RefLogger>(&logger);
+}
+
+TEST(WTF_NakedPtr, ReturnValue)
+{
+ DerivedRefLogger a("a");
+
+ {
+ auto ptr = nakedPtrFoo(a);
+ ASSERT_EQ(&a, ptr.get());
+ ASSERT_EQ(&a, &*ptr);
+ ASSERT_EQ(&a.name, &ptr->name);
+ }
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/Optional.cpp b/Tools/TestWebKitAPI/Tests/WTF/Optional.cpp
new file mode 100644
index 000000000..05f413b97
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/Optional.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2014 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 <wtf/Optional.h>
+
+namespace TestWebKitAPI {
+
+TEST(WTF_Optional, Disengaged)
+{
+ {
+ Optional<int> optional;
+
+ EXPECT_FALSE(static_cast<bool>(optional));
+ }
+
+ {
+ Optional<int> optional { Nullopt };
+
+ EXPECT_FALSE(static_cast<bool>(optional));
+ }
+}
+
+TEST(WTF_Optional, Engaged)
+{
+ Optional<int> optional { 10 };
+
+ EXPECT_TRUE(static_cast<bool>(optional));
+ EXPECT_EQ(10, optional.value());
+}
+
+TEST(WTF_Optional, Destructor)
+{
+ static bool didCallDestructor = false;
+ struct A {
+ ~A()
+ {
+ EXPECT_FALSE(didCallDestructor);
+ didCallDestructor = true;
+ }
+ };
+
+ {
+ Optional<A> optional { InPlace };
+
+ EXPECT_TRUE(static_cast<bool>(optional));
+ }
+
+ EXPECT_TRUE(didCallDestructor);
+}
+
+TEST(WTF_Optional, Callback)
+{
+ bool called = false;
+ Optional<int> a;
+ int result = a.valueOrCompute([&] {
+ called = true;
+ return 300;
+ });
+ EXPECT_TRUE(called);
+ EXPECT_EQ(result, 300);
+
+ a = 250;
+ called = false;
+ result = a.valueOrCompute([&] {
+ called = true;
+ return 300;
+ });
+ EXPECT_FALSE(called);
+ EXPECT_EQ(result, 250);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/ParkingLot.cpp b/Tools/TestWebKitAPI/Tests/WTF/ParkingLot.cpp
new file mode 100644
index 000000000..cad99d519
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/ParkingLot.cpp
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2015 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 <condition_variable>
+#include <mutex>
+#include <thread>
+#include <wtf/DataLog.h>
+#include <wtf/HashSet.h>
+#include <wtf/ListDump.h>
+#include <wtf/ParkingLot.h>
+#include <wtf/Threading.h>
+#include <wtf/ThreadingPrimitives.h>
+
+using namespace WTF;
+
+namespace TestWebKitAPI {
+
+namespace {
+
+struct SingleLatchTest {
+ void initialize(unsigned numThreads)
+ {
+ // This implements a fair (FIFO) semaphore, and it starts out unavailable.
+ semaphore.store(0);
+
+ for (unsigned i = numThreads; i--;) {
+ threads.append(
+ createThread(
+ "Parking Test Thread",
+ [&] () {
+ EXPECT_NE(0u, currentThread());
+
+ down();
+
+ std::lock_guard<std::mutex> locker(lock);
+ awake.add(currentThread());
+ lastAwoken = currentThread();
+ condition.notify_one();
+ }));
+ }
+ }
+
+ void unparkOne(unsigned singleUnparkIndex)
+ {
+ EXPECT_EQ(0u, lastAwoken);
+
+ unsigned numWaitingOnAddress = 0;
+ Vector<ThreadIdentifier, 8> queue;
+ ParkingLot::forEach(
+ [&] (ThreadIdentifier threadIdentifier, const void* address) {
+ if (address != &semaphore)
+ return;
+
+ queue.append(threadIdentifier);
+
+ numWaitingOnAddress++;
+ });
+
+ EXPECT_LE(numWaitingOnAddress, threads.size() - singleUnparkIndex);
+
+ up();
+
+ {
+ std::unique_lock<std::mutex> locker(lock);
+ while (awake.size() < singleUnparkIndex + 1)
+ condition.wait(locker);
+ EXPECT_NE(0u, lastAwoken);
+ if (!queue.isEmpty() && queue[0] != lastAwoken) {
+ dataLog("Woke up wrong thread: queue = ", listDump(queue), ", last awoken = ", lastAwoken, "\n");
+ EXPECT_EQ(queue[0], lastAwoken);
+ }
+ lastAwoken = 0;
+ }
+ }
+
+ void finish(unsigned numSingleUnparks)
+ {
+ unsigned numWaitingOnAddress = 0;
+ ParkingLot::forEach(
+ [&] (ThreadIdentifier, const void* address) {
+ if (address != &semaphore)
+ return;
+
+ numWaitingOnAddress++;
+ });
+
+ EXPECT_LE(numWaitingOnAddress, threads.size() - numSingleUnparks);
+
+ semaphore.store(threads.size() - numSingleUnparks);
+ ParkingLot::unparkAll(&semaphore);
+
+ numWaitingOnAddress = 0;
+ ParkingLot::forEach(
+ [&] (ThreadIdentifier, const void* address) {
+ if (address != &semaphore)
+ return;
+
+ numWaitingOnAddress++;
+ });
+
+ EXPECT_EQ(0u, numWaitingOnAddress);
+
+ {
+ std::unique_lock<std::mutex> locker(lock);
+ while (awake.size() < threads.size())
+ condition.wait(locker);
+ }
+
+ for (ThreadIdentifier threadIdentifier : threads)
+ waitForThreadCompletion(threadIdentifier);
+ }
+
+ // Semaphore operations.
+ void down()
+ {
+ for (;;) {
+ int oldSemaphoreValue = semaphore.load();
+ int newSemaphoreValue = oldSemaphoreValue - 1;
+ if (!semaphore.compareExchangeWeak(oldSemaphoreValue, newSemaphoreValue))
+ continue;
+
+ if (oldSemaphoreValue > 0) {
+ // We acquired the semaphore. Done.
+ return;
+ }
+
+ // We need to wait.
+ if (ParkingLot::compareAndPark(&semaphore, newSemaphoreValue)) {
+ // We did wait, and then got woken up. This means that someone who up'd the semaphore
+ // passed ownership onto us.
+ return;
+ }
+
+ // We never parked, because the semaphore value changed. Undo our decrement and try again.
+ for (;;) {
+ int oldSemaphoreValue = semaphore.load();
+ if (semaphore.compareExchangeWeak(oldSemaphoreValue, oldSemaphoreValue + 1))
+ break;
+ }
+ }
+ }
+ void up()
+ {
+ int oldSemaphoreValue;
+ for (;;) {
+ oldSemaphoreValue = semaphore.load();
+ if (semaphore.compareExchangeWeak(oldSemaphoreValue, oldSemaphoreValue + 1))
+ break;
+ }
+
+ // Check if anyone was waiting on the semaphore. If they were, then pass ownership to them.
+ if (oldSemaphoreValue < 0)
+ ParkingLot::unparkOne(&semaphore);
+ }
+
+ Atomic<int> semaphore;
+ std::mutex lock;
+ std::condition_variable condition;
+ HashSet<ThreadIdentifier> awake;
+ Vector<ThreadIdentifier> threads;
+ ThreadIdentifier lastAwoken { 0 };
+};
+
+void runParkingTest(unsigned numLatches, unsigned delay, unsigned numThreads, unsigned numSingleUnparks)
+{
+ std::unique_ptr<SingleLatchTest[]> tests = std::make_unique<SingleLatchTest[]>(numLatches);
+
+ for (unsigned latchIndex = numLatches; latchIndex--;)
+ tests[latchIndex].initialize(numThreads);
+
+ for (unsigned unparkIndex = 0; unparkIndex < numSingleUnparks; ++unparkIndex) {
+ std::this_thread::sleep_for(std::chrono::microseconds(delay));
+ for (unsigned latchIndex = numLatches; latchIndex--;)
+ tests[latchIndex].unparkOne(unparkIndex);
+ }
+
+ for (unsigned latchIndex = numLatches; latchIndex--;)
+ tests[latchIndex].finish(numSingleUnparks);
+}
+
+void repeatParkingTest(unsigned numRepeats, unsigned numLatches, unsigned delay, unsigned numThreads, unsigned numSingleUnparks)
+{
+ while (numRepeats--)
+ runParkingTest(numLatches, delay, numThreads, numSingleUnparks);
+}
+
+} // anonymous namespace
+
+TEST(WTF_ParkingLot, UnparkAllOneFast)
+{
+ repeatParkingTest(10000, 1, 0, 1, 0);
+}
+
+TEST(WTF_ParkingLot, UnparkAllHundredFast)
+{
+ repeatParkingTest(100, 1, 0, 100, 0);
+}
+
+TEST(WTF_ParkingLot, UnparkOneOneFast)
+{
+ repeatParkingTest(1000, 1, 0, 1, 1);
+}
+
+TEST(WTF_ParkingLot, UnparkOneHundredFast)
+{
+ repeatParkingTest(20, 1, 0, 100, 100);
+}
+
+TEST(WTF_ParkingLot, UnparkOneFiftyThenFiftyAllFast)
+{
+ repeatParkingTest(50, 1, 0, 100, 50);
+}
+
+TEST(WTF_ParkingLot, UnparkAllOne)
+{
+ repeatParkingTest(100, 1, 10000, 1, 0);
+}
+
+TEST(WTF_ParkingLot, UnparkAllHundred)
+{
+ repeatParkingTest(100, 1, 10000, 100, 0);
+}
+
+TEST(WTF_ParkingLot, UnparkOneOne)
+{
+ repeatParkingTest(10, 1, 10000, 1, 1);
+}
+
+TEST(WTF_ParkingLot, UnparkOneFifty)
+{
+ repeatParkingTest(1, 1, 10000, 50, 50);
+}
+
+TEST(WTF_ParkingLot, UnparkOneFiftyThenFiftyAll)
+{
+ repeatParkingTest(2, 1, 10000, 100, 50);
+}
+
+TEST(WTF_ParkingLot, HundredUnparkAllOneFast)
+{
+ repeatParkingTest(100, 100, 0, 1, 0);
+}
+
+TEST(WTF_ParkingLot, HundredUnparkAllOne)
+{
+ repeatParkingTest(1, 100, 10000, 1, 0);
+}
+
+} // namespace TestWebKitAPI
+
diff --git a/Tools/TestWebKitAPI/Tests/WTF/RedBlackTree.cpp b/Tools/TestWebKitAPI/Tests/WTF/RedBlackTree.cpp
new file mode 100644
index 000000000..5e5c8adc4
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/RedBlackTree.cpp
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2011 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.
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 <wtf/RedBlackTree.h>
+#include <wtf/Vector.h>
+
+using namespace WTF;
+
+namespace TestWebKitAPI {
+
+class TestNode : public RedBlackTree<TestNode, char>::Node {
+public:
+ TestNode(char key, unsigned value)
+ : m_key(key)
+ , m_value(value)
+ {
+ }
+
+ char key()
+ {
+ return m_key;
+ }
+
+ char m_key;
+ unsigned m_value;
+};
+
+class RedBlackTreeTest : public testing::Test {
+public:
+ unsigned m_counter;
+
+ virtual void SetUp()
+ {
+ m_counter = 0;
+ }
+
+ virtual void TearDown()
+ {
+ }
+
+ struct Pair {
+ char key;
+ unsigned value;
+
+ Pair() { }
+
+ Pair(char key, unsigned value)
+ : key(key)
+ , value(value)
+ {
+ }
+
+ bool operator==(const Pair& other) const
+ {
+ return key == other.key;
+ }
+
+ bool operator<(const Pair& other) const
+ {
+ return key < other.key;
+ }
+ };
+
+ typedef Vector<Pair, 16> PairVector;
+
+ PairVector findExact(PairVector& asVector, char key)
+ {
+ PairVector result;
+
+ for (size_t index = 0; index < asVector.size(); ++index) {
+ if (asVector.at(index).key == key)
+ result.append(asVector.at(index));
+ }
+
+ std::sort(result.begin(), result.end());
+
+ return result;
+ }
+
+ void remove(PairVector& asVector, size_t index)
+ {
+ asVector.at(index) = asVector.last();
+ asVector.removeLast();
+ }
+
+ PairVector findLeastGreaterThanOrEqual(PairVector& asVector, char key)
+ {
+ char bestKey = 0; // assignment to make gcc happy
+ bool foundKey = false;
+
+ for (size_t index = 0; index < asVector.size(); ++index) {
+ if (asVector.at(index).key >= key) {
+ if (asVector.at(index).key < bestKey || !foundKey) {
+ foundKey = true;
+ bestKey = asVector.at(index).key;
+ }
+ }
+ }
+
+ PairVector result;
+
+ if (!foundKey)
+ return result;
+
+ return findExact(asVector, bestKey);
+ }
+
+ void assertFoundAndRemove(PairVector& asVector, char key, unsigned value)
+ {
+ bool found = false;
+ size_t foundIndex = 0; // make compilers happy
+
+ for (size_t index = 0; index < asVector.size(); ++index) {
+ if (asVector.at(index).key == key
+ && asVector.at(index).value == value) {
+ EXPECT_TRUE(!found);
+
+ found = true;
+ foundIndex = index;
+ }
+ }
+
+ EXPECT_TRUE(found);
+
+ remove(asVector, foundIndex);
+ }
+
+ // This deliberately passes a copy of the vector.
+ void assertEqual(RedBlackTree<TestNode, char>& asTree, PairVector asVector)
+ {
+ for (TestNode* current = asTree.first(); current; current = current->successor())
+ assertFoundAndRemove(asVector, current->m_key, current->m_value);
+ }
+
+ void assertSameValuesForKey(RedBlackTree<TestNode, char>& asTree, TestNode* node, PairVector foundValues, char key)
+ {
+ if (node) {
+ EXPECT_EQ(node->m_key, key);
+
+ TestNode* prevNode = node;
+ do {
+ node = prevNode;
+ prevNode = prevNode->predecessor();
+ } while (prevNode && prevNode->m_key == key);
+
+ EXPECT_EQ(node->m_key, key);
+ EXPECT_TRUE(!prevNode || prevNode->m_key < key);
+
+ do {
+ assertFoundAndRemove(foundValues, node->m_key, node->m_value);
+
+ node = node->successor();
+ EXPECT_TRUE(!node || node->m_key >= key);
+ } while (node && node->m_key == key);
+ }
+
+ EXPECT_TRUE(foundValues.isEmpty());
+ }
+
+ // The control string is a null-terminated list of commands. Each
+ // command is two characters, with the first identifying the operation
+ // and the second giving a key. The commands are:
+ // +x Add x
+ // *x Find all elements equal to x
+ // @x Find all elements that have the smallest key that is greater than or equal to x
+ // !x Remove all elements equal to x
+ void testDriver(const char* controlString)
+ {
+ PairVector asVector;
+ RedBlackTree<TestNode, char> asTree;
+
+ for (const char* current = controlString; *current; current += 2) {
+ char command = current[0];
+ char key = current[1];
+ unsigned value = ++m_counter;
+
+ ASSERT(command);
+ ASSERT(key);
+
+ switch (command) {
+ case '+': {
+ TestNode* node = new TestNode(key, value);
+ asTree.insert(node);
+ asVector.append(Pair(key, value));
+ break;
+ }
+
+ case '*': {
+ TestNode* node = asTree.findExact(key);
+ if (node)
+ EXPECT_EQ(node->m_key, key);
+ assertSameValuesForKey(asTree, node, findExact(asVector, key), key);
+ break;
+ }
+
+ case '@': {
+ TestNode* node = asTree.findLeastGreaterThanOrEqual(key);
+ if (node) {
+ EXPECT_TRUE(node->m_key >= key);
+ assertSameValuesForKey(asTree, node, findLeastGreaterThanOrEqual(asVector, key), node->m_key);
+ } else
+ EXPECT_TRUE(findLeastGreaterThanOrEqual(asVector, key).isEmpty());
+ break;
+ }
+
+ case '!': {
+ while (true) {
+ TestNode* node = asTree.remove(key);
+ if (node) {
+ EXPECT_EQ(node->m_key, key);
+ assertFoundAndRemove(asVector, node->m_key, node->m_value);
+ } else {
+ EXPECT_TRUE(findExact(asVector, key).isEmpty());
+ break;
+ }
+ }
+ break;
+ }
+
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+
+ EXPECT_EQ(asTree.size(), asVector.size());
+ assertEqual(asTree, asVector);
+ }
+ }
+};
+
+TEST_F(RedBlackTreeTest, Empty)
+{
+ testDriver("");
+}
+
+TEST_F(RedBlackTreeTest, EmptyGetFindRemove)
+{
+ testDriver("*x@y!z");
+}
+
+TEST_F(RedBlackTreeTest, SingleAdd)
+{
+ testDriver("+a");
+}
+
+TEST_F(RedBlackTreeTest, SingleAddGetFindRemoveNotFound)
+{
+ testDriver("+a*x@y!z");
+}
+
+TEST_F(RedBlackTreeTest, SingleAddGetFindRemove)
+{
+ testDriver("+a*a@a!a");
+}
+
+TEST_F(RedBlackTreeTest, TwoAdds)
+{
+ testDriver("+a+b");
+}
+
+TEST_F(RedBlackTreeTest, ThreeAdds)
+{
+ testDriver("+a+b+c");
+}
+
+TEST_F(RedBlackTreeTest, FourAdds)
+{
+ testDriver("+a+b+c+d");
+}
+
+TEST_F(RedBlackTreeTest, LotsOfRepeatAdds)
+{
+ testDriver("+a+b+c+d+a+b+c+d+a+b+c+d+a+b+c+d+a+b+c+d+a+b+c+d+a+b+c+d+a+b+c+d+a+b+c+d+a+b+c+d+a+b+c+d+a+b+c+d");
+}
+
+TEST_F(RedBlackTreeTest, LotsOfRepeatAndUniqueAdds)
+{
+ testDriver("+a+b+c+d+a+b+c+d+a+b+c+d+a+b+c+d+a+b+c+d+a+b+c+d+a+b+c+d+a+b+c+d+a+b+c+d+a+b+c+d+a+b+c+d+a+b+c+d+e+f+g+h+i+j+k+l+m+n+o+p+q+r+s+t+u+v+x+y+z");
+}
+
+TEST_F(RedBlackTreeTest, LotsOfRepeatAndUniqueAddsAndGetsAndRemoves)
+{
+ testDriver("+a+b+c+d+a+b+c+d+a+b+c+d+a+b+c+d+a+b+c+d+a+b+c+d+a+b+c+d+a+b+c+d+a+b+c+d+a+b+c+d+a+b+c+d+a+b+c+d+e+f+g+h+i+j+k+l+m+n+o+p+q+r+s+t+u+v+x+y+z*a*b*c*d*e*f*g*h*i*j*k*l*m*n*o*p*q*r*s*t*u*v*w*x*y*z!a!b!c!d!e!f!g!h!i!j!k!l!m!n!o!p!q!r!s!t!u!v!w!x!y!z");
+}
+
+TEST_F(RedBlackTreeTest, SimpleBestFitSearch)
+{
+ testDriver("+d+d+m+w@d@m@w@a@g@q");
+}
+
+TEST_F(RedBlackTreeTest, BiggerBestFitSearch)
+{
+ testDriver("+d+d+d+d+d+d+d+d+d+d+f+f+f+f+f+f+f+h+h+i+j+k+l+m+o+p+q+r+z@a@b@c@d@e@f@g@h@i@j@k@l@m@n@o@p@q@r@s@t@u@v@w@x@y@z");
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/Ref.cpp b/Tools/TestWebKitAPI/Tests/WTF/Ref.cpp
new file mode 100644
index 000000000..8c622d07b
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/Ref.cpp
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2013 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 "RefLogger.h"
+#include <wtf/Ref.h>
+#include <wtf/RefPtr.h>
+
+namespace TestWebKitAPI {
+
+TEST(WTF_Ref, Basic)
+{
+ DerivedRefLogger a("a");
+
+ {
+ Ref<RefLogger> ptr(a);
+ ASSERT_EQ(&a, ptr.ptr());
+ ASSERT_EQ(&a.name, &ptr->name);
+ }
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ Ref<RefLogger> ptr(adoptRef(a));
+ ASSERT_EQ(&a, ptr.ptr());
+ ASSERT_EQ(&a.name, &ptr->name);
+ }
+ ASSERT_STREQ("deref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_Ref, Assignment)
+{
+ DerivedRefLogger a("a");
+ RefLogger b("b");
+ DerivedRefLogger c("c");
+
+ {
+ Ref<RefLogger> ptr(a);
+ ASSERT_EQ(&a, ptr.ptr());
+ log() << "| ";
+ ptr = b;
+ ASSERT_EQ(&b, ptr.ptr());
+ log() << "| ";
+ }
+ ASSERT_STREQ("ref(a) | ref(b) deref(a) | deref(b) ", takeLogStr().c_str());
+
+ {
+ Ref<RefLogger> ptr(a);
+ ASSERT_EQ(&a, ptr.ptr());
+ log() << "| ";
+ ptr = c;
+ ASSERT_EQ(&c, ptr.ptr());
+ log() << "| ";
+ }
+ ASSERT_STREQ("ref(a) | ref(c) deref(a) | deref(c) ", takeLogStr().c_str());
+
+ {
+ Ref<RefLogger> ptr(a);
+ ASSERT_EQ(&a, ptr.ptr());
+ log() << "| ";
+ ptr = adoptRef(b);
+ ASSERT_EQ(&b, ptr.ptr());
+ log() << "| ";
+ }
+ ASSERT_STREQ("ref(a) | deref(a) | deref(b) ", takeLogStr().c_str());
+
+ {
+ Ref<RefLogger> ptr(a);
+ ASSERT_EQ(&a, ptr.ptr());
+ log() << "| ";
+ ptr = adoptRef(c);
+ ASSERT_EQ(&c, ptr.ptr());
+ log() << "| ";
+ }
+ ASSERT_STREQ("ref(a) | deref(a) | deref(c) ", takeLogStr().c_str());
+}
+
+static Ref<RefLogger> passWithRef(Ref<RefLogger>&& reference)
+{
+ return WTF::move(reference);
+}
+
+static RefPtr<RefLogger> passWithPassRefPtr(PassRefPtr<RefLogger> reference)
+{
+ return reference;
+}
+
+TEST(WTF_Ref, ReturnValue)
+{
+ DerivedRefLogger a("a");
+ RefLogger b("b");
+ DerivedRefLogger c("c");
+
+ {
+ Ref<RefLogger> ptr(passWithRef(Ref<RefLogger>(a)));
+ ASSERT_EQ(&a, ptr.ptr());
+ }
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ Ref<RefLogger> ptr(a);
+ ASSERT_EQ(&a, ptr.ptr());
+ log() << "| ";
+ ptr = passWithRef(b);
+ ASSERT_EQ(&b, ptr.ptr());
+ log() << "| ";
+ }
+ ASSERT_STREQ("ref(a) | ref(b) deref(a) | deref(b) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> ptr(passWithRef(a));
+ ASSERT_EQ(&a, ptr.get());
+ }
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> ptr(passWithPassRefPtr(passWithRef(a)));
+ ASSERT_EQ(&a, ptr.get());
+ }
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ RefPtr<DerivedRefLogger> ptr(&a);
+ RefPtr<RefLogger> ptr2(WTF::move(ptr));
+ ASSERT_EQ(nullptr, ptr.get());
+ ASSERT_EQ(&a, ptr2.get());
+ }
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ Ref<DerivedRefLogger> derivedReference(a);
+ Ref<RefLogger> baseReference(passWithRef(derivedReference.copyRef()));
+ ASSERT_EQ(&a, derivedReference.ptr());
+ ASSERT_EQ(&a, baseReference.ptr());
+ }
+ ASSERT_STREQ("ref(a) ref(a) deref(a) deref(a) ", takeLogStr().c_str());
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/RefCounter.cpp b/Tools/TestWebKitAPI/Tests/WTF/RefCounter.cpp
new file mode 100644
index 000000000..f8771e0c2
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/RefCounter.cpp
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2011 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 <wtf/Ref.h>
+#include <wtf/RefCounter.h>
+#include <wtf/text/WTFString.h>
+
+namespace TestWebKitAPI {
+
+static const int CallbackExpected = 0xC0FFEE;
+static const int CallbackNotExpected = 0xDECAF;
+
+enum CounterType { };
+typedef RefCounter::Token<CounterType> TokenType;
+
+TEST(WTF, RefCounter)
+{
+ // RefCounter API is pretty simple, containing the following 4 methods to test:
+ //
+ // 1) RefCounter(std::function<void()>);
+ // 2) ~RefCounter();
+ // 3) Ref<Count> token() const;
+ // 4) unsigned value() const;
+ //
+ // We'll test:
+ // 1) Construction:
+ // 1a) with a callback
+ // 1b) without a callback
+ // 2) Destruction where the RefCounter::Count has:
+ // 2a) a non-zero reference count (Count outlives RefCounter).
+ // 2b) a zero reference count (Count is deleted by RefCounter's destructor).
+ // 3) Call count to ref/deref the Count object, where:
+ // 3a) ref with callback from 0 -> 1.
+ // 3b) ref with callback from 1 -> >1.
+ // 3c) deref with callback from >1 -> 1.
+ // 3d) deref with callback from 1 -> 0.
+ // 3d) deref with callback from 1 -> 0.
+ // 3e) ref with callback from 1 -> >1 AFTER RefCounter has been destroyed.
+ // 3f) deref with callback from >1 -> 1 AFTER RefCounter has been destroyed.
+ // 3g) deref with callback from 1 -> 0 AFTER RefCounter has been destroyed.
+ // 3h) ref without callback
+ // 3i) deref without callback
+ // 3j) ref using a Ref rather than a RefPtr (make sure there is no unnecessary reference count churn).
+ // 3k) deref using a Ref rather than a RefPtr (make sure there is no unnecessary reference count churn).
+ // 4) Test the value of the counter:
+ // 4a) at construction.
+ // 4b) as read within the callback.
+ // 4c) as read after the ref/deref.
+
+ // These values will outlive the following block.
+ int callbackValue = CallbackNotExpected;
+ TokenType incTo1Again;
+
+ {
+ // Testing (1a) - Construction with a callback.
+ RefCounter* counterPtr = nullptr;
+ RefCounter counter([&](bool value) {
+ // Check that the callback is called at the expected times, and the correct number of times.
+ EXPECT_EQ(callbackValue, CallbackExpected);
+ // Value provided should be equal to the counter value.
+ EXPECT_EQ(value, counterPtr->value());
+ // return the value of the counter in the callback.
+ callbackValue = value;
+ });
+ counterPtr = &counter;
+ // Testing (4a) - after construction value() is 0.
+ EXPECT_EQ(0, static_cast<int>(counter.value()));
+
+ // Testing (3a) - ref with callback from 0 -> 1.
+ callbackValue = CallbackExpected;
+ TokenType incTo1(counter.token<CounterType>());
+ // Testing (4b) & (4c) - values within & after callback.
+ EXPECT_EQ(true, callbackValue);
+ EXPECT_EQ(1, static_cast<int>(counter.value()));
+
+ // Testing (3b) - ref with callback from 1 -> 2.
+ TokenType incTo2(incTo1);
+ // Testing (4b) & (4c) - values within & after callback.
+ EXPECT_EQ(2, static_cast<int>(counter.value()));
+
+ // Testing (3c) - deref with callback from >1 -> 1.
+ incTo1 = nullptr;
+ // Testing (4b) & (4c) - values within & after callback.
+ EXPECT_EQ(1, static_cast<int>(counter.value()));
+
+ {
+ // Testing (3j) - ref using a Ref rather than a RefPtr.
+ TokenType incTo2Again(counter.token<CounterType>());
+ // Testing (4b) & (4c) - values within & after callback.
+ EXPECT_EQ(2, static_cast<int>(counter.value()));
+ // Testing (3k) - deref using a Ref rather than a RefPtr.
+ }
+ EXPECT_EQ(1, static_cast<int>(counter.value()));
+ // Testing (4b) & (4c) - values within & after callback.
+
+ // Testing (3d) - deref with callback from 1 -> 0.
+ callbackValue = CallbackExpected;
+ incTo2 = nullptr;
+ // Testing (4b) & (4c) - values within & after callback.
+ EXPECT_EQ(0, callbackValue);
+ EXPECT_EQ(0, static_cast<int>(counter.value()));
+
+ // Testing (2a) - Destruction where the RefCounter::Count has a non-zero reference count.
+ callbackValue = CallbackExpected;
+ incTo1Again = counter.token<CounterType>();
+ EXPECT_EQ(1, callbackValue);
+ EXPECT_EQ(1, static_cast<int>(counter.value()));
+ callbackValue = CallbackNotExpected;
+ }
+
+ // Testing (3e) - ref with callback from 1 -> >1 AFTER RefCounter has been destroyed.
+ TokenType incTo2Again = incTo1Again;
+ // Testing (3f) - deref with callback from >1 -> 1 AFTER RefCounter has been destroyed.
+ incTo1Again = nullptr;
+ // Testing (3g) - deref with callback from 1 -> 0 AFTER RefCounter has been destroyed.
+ incTo2Again = nullptr;
+
+ // Testing (1b) - Construction without a callback.
+ RefCounter counter;
+ // Testing (4a) - after construction value() is 0.
+ EXPECT_EQ(0, static_cast<int>(counter.value()));
+ // Testing (3h) - ref without callback
+ TokenType incTo1(counter.token<CounterType>());
+ // Testing (4c) - value as read after the ref.
+ EXPECT_EQ(1, static_cast<int>(counter.value()));
+ // Testing (3i) - deref without callback
+ incTo1 = nullptr;
+ // Testing (4c) - value as read after the deref.
+ EXPECT_EQ(0, static_cast<int>(counter.value()));
+ // Testing (2b) - Destruction where the RefCounter::Count has a zero reference count.
+ // ... not a lot to test here! - we can at least ensure this code path is run & we don't crash!
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/RefLogger.h b/Tools/TestWebKitAPI/Tests/WTF/RefLogger.h
new file mode 100644
index 000000000..c5cfb071f
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/RefLogger.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef RefLogger_h
+
+namespace TestWebKitAPI {
+
+inline std::ostringstream& log()
+{
+ static std::ostringstream log;
+ return log;
+}
+
+inline std::string takeLogStr()
+{
+ std::string string = log().str();
+ log().str("");
+ return string;
+}
+
+struct RefLogger {
+ RefLogger(const char* name) : name(*name) { }
+ void ref() { log() << "ref(" << &name << ") "; }
+ void deref() { log() << "deref(" << &name << ") "; }
+ const char& name;
+};
+
+struct DerivedRefLogger : RefLogger {
+ DerivedRefLogger(const char* name) : RefLogger(name) { log().str(""); }
+};
+
+}
+
+#endif
diff --git a/Tools/TestWebKitAPI/Tests/WTF/RefPtr.cpp b/Tools/TestWebKitAPI/Tests/WTF/RefPtr.cpp
new file mode 100644
index 000000000..b726d7ddf
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/RefPtr.cpp
@@ -0,0 +1,398 @@
+/*
+ * Copyright (C) 2013 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 "RefLogger.h"
+#include <wtf/RefPtr.h>
+
+namespace TestWebKitAPI {
+
+TEST(WTF_RefPtr, Basic)
+{
+ DerivedRefLogger a("a");
+
+ RefPtr<RefLogger> empty;
+ ASSERT_EQ(nullptr, empty.get());
+
+ {
+ RefPtr<RefLogger> ptr(&a);
+ ASSERT_EQ(&a, ptr.get());
+ ASSERT_EQ(&a, &*ptr);
+ ASSERT_EQ(&a.name, &ptr->name);
+ }
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> ptr = &a;
+ ASSERT_EQ(&a, ptr.get());
+ }
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> p1 = &a;
+ RefPtr<RefLogger> p2(p1);
+ ASSERT_EQ(&a, p1.get());
+ ASSERT_EQ(&a, p2.get());
+ }
+ ASSERT_STREQ("ref(a) ref(a) deref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> p1 = &a;
+ RefPtr<RefLogger> p2 = p1;
+ ASSERT_EQ(&a, p1.get());
+ ASSERT_EQ(&a, p2.get());
+ }
+ ASSERT_STREQ("ref(a) ref(a) deref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> p1 = &a;
+ RefPtr<RefLogger> p2 = WTF::move(p1);
+ ASSERT_EQ(nullptr, p1.get());
+ ASSERT_EQ(&a, p2.get());
+ }
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> p1 = &a;
+ RefPtr<RefLogger> p2(WTF::move(p1));
+ ASSERT_EQ(nullptr, p1.get());
+ ASSERT_EQ(&a, p2.get());
+ }
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ RefPtr<DerivedRefLogger> p1 = &a;
+ RefPtr<RefLogger> p2 = p1;
+ ASSERT_EQ(&a, p1.get());
+ ASSERT_EQ(&a, p2.get());
+ }
+ ASSERT_STREQ("ref(a) ref(a) deref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ RefPtr<DerivedRefLogger> p1 = &a;
+ RefPtr<RefLogger> p2 = WTF::move(p1);
+ ASSERT_EQ(nullptr, p1.get());
+ ASSERT_EQ(&a, p2.get());
+ }
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> ptr(&a);
+ ASSERT_EQ(&a, ptr.get());
+ ptr = nullptr;
+ ASSERT_EQ(nullptr, ptr.get());
+ }
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> ptr(&a);
+ ASSERT_EQ(&a, ptr.get());
+ ptr.release();
+ ASSERT_EQ(nullptr, ptr.get());
+ }
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_RefPtr, AssignPassRefToRefPtr)
+{
+ DerivedRefLogger a("a");
+ {
+ Ref<RefLogger> passRef(a);
+ RefPtr<RefLogger> ptr = WTF::move(passRef);
+ ASSERT_EQ(&a, ptr.get());
+ ptr.release();
+ ASSERT_EQ(nullptr, ptr.get());
+ }
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_RefPtr, Adopt)
+{
+ DerivedRefLogger a("a");
+
+ RefPtr<RefLogger> empty;
+ ASSERT_EQ(nullptr, empty.get());
+
+ {
+ RefPtr<RefLogger> ptr(adoptRef(&a));
+ ASSERT_EQ(&a, ptr.get());
+ ASSERT_EQ(&a, &*ptr);
+ ASSERT_EQ(&a.name, &ptr->name);
+ }
+ ASSERT_STREQ("deref(a) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> ptr = adoptRef(&a);
+ ASSERT_EQ(&a, ptr.get());
+ }
+ ASSERT_STREQ("deref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_RefPtr, Assignment)
+{
+ DerivedRefLogger a("a");
+ RefLogger b("b");
+ DerivedRefLogger c("c");
+
+ {
+ RefPtr<RefLogger> p1(&a);
+ RefPtr<RefLogger> p2(&b);
+ ASSERT_EQ(&a, p1.get());
+ ASSERT_EQ(&b, p2.get());
+ log() << "| ";
+ p1 = p2;
+ ASSERT_EQ(&b, p1.get());
+ ASSERT_EQ(&b, p2.get());
+ log() << "| ";
+ }
+ ASSERT_STREQ("ref(a) ref(b) | ref(b) deref(a) | deref(b) deref(b) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> ptr(&a);
+ ASSERT_EQ(&a, ptr.get());
+ log() << "| ";
+ ptr = &b;
+ ASSERT_EQ(&b, ptr.get());
+ log() << "| ";
+ }
+ ASSERT_STREQ("ref(a) | ref(b) deref(a) | deref(b) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> ptr(&a);
+ ASSERT_EQ(&a, ptr.get());
+ log() << "| ";
+ ptr = adoptRef(&b);
+ ASSERT_EQ(&b, ptr.get());
+ log() << "| ";
+ }
+ ASSERT_STREQ("ref(a) | deref(a) | deref(b) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> ptr(&a);
+ ASSERT_EQ(&a, ptr.get());
+ ptr = nullptr;
+ ASSERT_EQ(nullptr, ptr.get());
+ }
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> p1(&a);
+ RefPtr<RefLogger> p2(&b);
+ ASSERT_EQ(&a, p1.get());
+ ASSERT_EQ(&b, p2.get());
+ log() << "| ";
+ p1 = WTF::move(p2);
+ ASSERT_EQ(&b, p1.get());
+ ASSERT_EQ(nullptr, p2.get());
+ log() << "| ";
+ }
+ ASSERT_STREQ("ref(a) ref(b) | deref(a) | deref(b) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> p1(&a);
+ RefPtr<DerivedRefLogger> p2(&c);
+ ASSERT_EQ(&a, p1.get());
+ ASSERT_EQ(&c, p2.get());
+ log() << "| ";
+ p1 = p2;
+ ASSERT_EQ(&c, p1.get());
+ ASSERT_EQ(&c, p2.get());
+ log() << "| ";
+ }
+ ASSERT_STREQ("ref(a) ref(c) | ref(c) deref(a) | deref(c) deref(c) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> ptr(&a);
+ ASSERT_EQ(&a, ptr.get());
+ log() << "| ";
+ ptr = &c;
+ ASSERT_EQ(&c, ptr.get());
+ log() << "| ";
+ }
+ ASSERT_STREQ("ref(a) | ref(c) deref(a) | deref(c) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> ptr(&a);
+ ASSERT_EQ(&a, ptr.get());
+ log() << "| ";
+ ptr = adoptRef(&c);
+ ASSERT_EQ(&c, ptr.get());
+ log() << "| ";
+ }
+ ASSERT_STREQ("ref(a) | deref(a) | deref(c) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> p1(&a);
+ RefPtr<DerivedRefLogger> p2(&c);
+ ASSERT_EQ(&a, p1.get());
+ ASSERT_EQ(&c, p2.get());
+ log() << "| ";
+ p1 = WTF::move(p2);
+ ASSERT_EQ(&c, p1.get());
+ ASSERT_EQ(nullptr, p2.get());
+ log() << "| ";
+ }
+ ASSERT_STREQ("ref(a) ref(c) | deref(a) | deref(c) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> ptr(&a);
+ ASSERT_EQ(&a, ptr.get());
+ log() << "| ";
+ ptr = ptr;
+ ASSERT_EQ(&a, ptr.get());
+ log() << "| ";
+ }
+ ASSERT_STREQ("ref(a) | ref(a) deref(a) | deref(a) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> ptr(&a);
+ ASSERT_EQ(&a, ptr.get());
+ ptr = WTF::move(ptr);
+ ASSERT_EQ(&a, ptr.get());
+ }
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_RefPtr, Swap)
+{
+ RefLogger a("a");
+ RefLogger b("b");
+
+ {
+ RefPtr<RefLogger> p1(&a);
+ RefPtr<RefLogger> p2(&b);
+ ASSERT_EQ(&a, p1.get());
+ ASSERT_EQ(&b, p2.get());
+ p1.swap(p2);
+ ASSERT_EQ(&b, p1.get());
+ ASSERT_EQ(&a, p2.get());
+ log() << "| ";
+ }
+ ASSERT_STREQ("ref(a) ref(b) | deref(a) deref(b) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> p1(&a);
+ RefPtr<RefLogger> p2(&b);
+ ASSERT_EQ(&a, p1.get());
+ ASSERT_EQ(&b, p2.get());
+ std::swap(p1, p2);
+ ASSERT_EQ(&b, p1.get());
+ ASSERT_EQ(&a, p2.get());
+ log() << "| ";
+ }
+ ASSERT_STREQ("ref(a) ref(b) | deref(a) deref(b) ", takeLogStr().c_str());
+}
+
+TEST(WTF_RefPtr, ReleaseNonNull)
+{
+ RefLogger a("a");
+
+ {
+ RefPtr<RefLogger> refPtr = &a;
+ RefPtr<RefLogger> ref = refPtr.releaseNonNull();
+ }
+
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_RefPtr, Release)
+{
+ DerivedRefLogger a("a");
+ RefLogger b("b");
+ DerivedRefLogger c("c");
+
+ {
+ RefPtr<RefLogger> p1 = &a;
+ RefPtr<RefLogger> p2 = p1.release();
+ ASSERT_EQ(nullptr, p1.get());
+ ASSERT_EQ(&a, p2.get());
+ }
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> p1 = &a;
+ RefPtr<RefLogger> p2(p1.release());
+ ASSERT_EQ(nullptr, p1.get());
+ ASSERT_EQ(&a, p2.get());
+ }
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ RefPtr<DerivedRefLogger> p1 = &a;
+ RefPtr<RefLogger> p2 = p1.release();
+ ASSERT_EQ(nullptr, p1.get());
+ ASSERT_EQ(&a, p2.get());
+ }
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> p1(&a);
+ RefPtr<RefLogger> p2(&b);
+ ASSERT_EQ(&a, p1.get());
+ ASSERT_EQ(&b, p2.get());
+ log() << "| ";
+ p1 = p2.release();
+ ASSERT_EQ(&b, p1.get());
+ ASSERT_EQ(nullptr, p2.get());
+ log() << "| ";
+ }
+ ASSERT_STREQ("ref(a) ref(b) | deref(a) | deref(b) ", takeLogStr().c_str());
+
+ {
+ RefPtr<RefLogger> p1(&a);
+ RefPtr<DerivedRefLogger> p2(&c);
+ ASSERT_EQ(&a, p1.get());
+ ASSERT_EQ(&c, p2.get());
+ log() << "| ";
+ p1 = p2.release();
+ ASSERT_EQ(&c, p1.get());
+ ASSERT_EQ(nullptr, p2.get());
+ log() << "| ";
+ }
+ ASSERT_STREQ("ref(a) ref(c) | deref(a) | deref(c) ", takeLogStr().c_str());
+}
+
+RefPtr<RefLogger> f1(RefLogger& logger)
+{
+ return RefPtr<RefLogger>(&logger);
+}
+
+TEST(WTF_RefPtr, ReturnValue)
+{
+ DerivedRefLogger a("a");
+
+ {
+ f1(a);
+ }
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+ {
+ auto ptr = f1(a);
+ }
+ ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/RunLoop.cpp b/Tools/TestWebKitAPI/Tests/WTF/RunLoop.cpp
new file mode 100644
index 000000000..e7e3d9f99
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/RunLoop.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2015 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 "PlatformUtilities.h"
+#include <wtf/RunLoop.h>
+
+namespace TestWebKitAPI {
+
+static bool testFinished;
+static int count = 100;
+
+TEST(WTF_RunLoop, Deadlock)
+{
+ RunLoop::initializeMainRunLoop();
+
+ struct DispatchFromDestructorTester {
+ ~DispatchFromDestructorTester() {
+ RunLoop::main().dispatch([] {
+ if (!(--count))
+ testFinished = true;
+ });
+ }
+ };
+
+ for (int i = 0; i < count; ++i) {
+ auto capture = std::make_shared<DispatchFromDestructorTester>();
+ RunLoop::main().dispatch([capture] { });
+ }
+
+ Util::run(&testFinished);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/SHA1.cpp b/Tools/TestWebKitAPI/Tests/WTF/SHA1.cpp
new file mode 100644
index 000000000..dcf9d27b3
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/SHA1.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2011 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 <wtf/SHA1.h>
+#include <wtf/text/CString.h>
+
+namespace TestWebKitAPI {
+
+static void expectSHA1(CString input, int repeat, CString expected)
+{
+ SHA1 sha1;
+ for (int i = 0; i < repeat; ++i)
+ sha1.addBytes(input);
+ CString actual = sha1.computeHexDigest();
+
+ ASSERT_EQ(expected.length(), actual.length());
+ ASSERT_STREQ(expected.data(), actual.data());
+}
+
+TEST(WTF_SHA1, Computation)
+{
+ // Examples taken from sample code in RFC 3174.
+ expectSHA1("abc", 1, "A9993E364706816ABA3E25717850C26C9CD0D89D");
+ expectSHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 1, "84983E441C3BD26EBAAE4AA1F95129E5E54670F1");
+ expectSHA1("a", 1000000, "34AA973CD4C4DAA4F61EEB2BDBAD27316534016F");
+ expectSHA1("0123456701234567012345670123456701234567012345670123456701234567", 10, "DEA356A2CDDD90C7A7ECEDC5EBB563934F460452");
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/SaturatedArithmeticOperations.cpp b/Tools/TestWebKitAPI/Tests/WTF/SaturatedArithmeticOperations.cpp
new file mode 100644
index 000000000..e854e256e
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/SaturatedArithmeticOperations.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2012, Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "limits.h"
+#include <wtf/SaturatedArithmetic.h>
+
+namespace TestWebKitAPI {
+
+TEST(WTF, SaturatedArithmeticAddition)
+{
+ ASSERT_EQ(saturatedAddition(0, 0), 0);
+ ASSERT_EQ(saturatedAddition(0, 1), 1);
+ ASSERT_EQ(saturatedAddition(0, 100), 100);
+ ASSERT_EQ(saturatedAddition(100, 50), 150);
+
+ ASSERT_EQ(saturatedAddition(0, -1), -1);
+ ASSERT_EQ(saturatedAddition(1, -1), 0);
+ ASSERT_EQ(saturatedAddition(100, -50), 50);
+ ASSERT_EQ(saturatedAddition(50, -100), -50);
+
+ ASSERT_EQ(saturatedAddition(INT_MAX - 1, 0), INT_MAX - 1);
+ ASSERT_EQ(saturatedAddition(INT_MAX - 1, 1), INT_MAX);
+ ASSERT_EQ(saturatedAddition(INT_MAX - 1, 2), INT_MAX);
+ ASSERT_EQ(saturatedAddition(0, INT_MAX - 1), INT_MAX - 1);
+ ASSERT_EQ(saturatedAddition(1, INT_MAX - 1), INT_MAX);
+ ASSERT_EQ(saturatedAddition(2, INT_MAX - 1), INT_MAX);
+ ASSERT_EQ(saturatedAddition(INT_MAX - 1, INT_MAX - 1), INT_MAX);
+ ASSERT_EQ(saturatedAddition(INT_MAX, INT_MAX), INT_MAX);
+
+ ASSERT_EQ(saturatedAddition(INT_MIN, 0), INT_MIN);
+ ASSERT_EQ(saturatedAddition(INT_MIN + 1, 0), INT_MIN + 1);
+ ASSERT_EQ(saturatedAddition(INT_MIN + 1, 1), INT_MIN + 2);
+ ASSERT_EQ(saturatedAddition(INT_MIN + 1, 2), INT_MIN + 3);
+ ASSERT_EQ(saturatedAddition(INT_MIN + 1, -1), INT_MIN);
+ ASSERT_EQ(saturatedAddition(INT_MIN + 1, -2), INT_MIN);
+ ASSERT_EQ(saturatedAddition(0, INT_MIN + 1), INT_MIN + 1);
+ ASSERT_EQ(saturatedAddition(-1, INT_MIN + 1), INT_MIN);
+ ASSERT_EQ(saturatedAddition(-2, INT_MIN + 1), INT_MIN);
+
+ ASSERT_EQ(saturatedAddition(INT_MAX / 2, 10000), INT_MAX / 2 + 10000);
+ ASSERT_EQ(saturatedAddition(INT_MAX / 2 + 1, INT_MAX / 2 + 1), INT_MAX);
+ ASSERT_EQ(saturatedAddition(INT_MIN, INT_MAX), -1);
+}
+
+TEST(WTF, SaturatedArithmeticSubtraction)
+{
+ ASSERT_EQ(saturatedSubtraction(0, 0), 0);
+ ASSERT_EQ(saturatedSubtraction(0, 1), -1);
+ ASSERT_EQ(saturatedSubtraction(0, 100), -100);
+ ASSERT_EQ(saturatedSubtraction(100, 50), 50);
+
+ ASSERT_EQ(saturatedSubtraction(0, -1), 1);
+ ASSERT_EQ(saturatedSubtraction(1, -1), 2);
+ ASSERT_EQ(saturatedSubtraction(100, -50), 150);
+ ASSERT_EQ(saturatedSubtraction(50, -100), 150);
+
+ ASSERT_EQ(saturatedSubtraction(INT_MAX, 0), INT_MAX);
+ ASSERT_EQ(saturatedSubtraction(INT_MAX, 1), INT_MAX - 1);
+ ASSERT_EQ(saturatedSubtraction(INT_MAX - 1, 0), INT_MAX - 1);
+ ASSERT_EQ(saturatedSubtraction(INT_MAX - 1, -1), INT_MAX);
+ ASSERT_EQ(saturatedSubtraction(INT_MAX - 1, -2), INT_MAX);
+ ASSERT_EQ(saturatedSubtraction(0, INT_MAX - 1), -INT_MAX + 1);
+ ASSERT_EQ(saturatedSubtraction(-1, INT_MAX - 1), -INT_MAX);
+ ASSERT_EQ(saturatedSubtraction(-2, INT_MAX - 1), -INT_MAX - 1);
+ ASSERT_EQ(saturatedSubtraction(-3, INT_MAX - 1), -INT_MAX - 1);
+
+ ASSERT_EQ(saturatedSubtraction(INT_MIN, 0), INT_MIN);
+ ASSERT_EQ(saturatedSubtraction(INT_MIN + 1, 0), INT_MIN + 1);
+ ASSERT_EQ(saturatedSubtraction(INT_MIN + 1, 1), INT_MIN);
+ ASSERT_EQ(saturatedSubtraction(INT_MIN + 1, 2), INT_MIN);
+
+ ASSERT_EQ(saturatedSubtraction(INT_MIN, INT_MIN), 0);
+ ASSERT_EQ(saturatedSubtraction(INT_MAX, INT_MAX), 0);
+ ASSERT_EQ(saturatedSubtraction(INT_MAX, INT_MIN), INT_MAX);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/StringBuilder.cpp b/Tools/TestWebKitAPI/Tests/WTF/StringBuilder.cpp
new file mode 100644
index 000000000..11bf3590e
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/StringBuilder.cpp
@@ -0,0 +1,338 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ * Copyright (C) 2013 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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"
+
+namespace TestWebKitAPI {
+
+static void expectBuilderContent(const String& expected, const StringBuilder& builder)
+{
+ // Not using builder.toString() or builder.toStringPreserveCapacity() because they all
+ // change internal state of builder.
+ if (builder.is8Bit())
+ EXPECT_EQ(expected, String(builder.characters8(), builder.length()));
+ else
+ EXPECT_EQ(expected, String(builder.characters16(), builder.length()));
+}
+
+void expectEmpty(const StringBuilder& builder)
+{
+ EXPECT_EQ(0U, builder.length());
+ EXPECT_TRUE(builder.isEmpty());
+ EXPECT_EQ(0, builder.characters8());
+}
+
+TEST(StringBuilderTest, DefaultConstructor)
+{
+ StringBuilder builder;
+ expectEmpty(builder);
+}
+
+TEST(StringBuilderTest, Append)
+{
+ StringBuilder builder;
+ builder.append(String("0123456789"));
+ expectBuilderContent("0123456789", builder);
+ builder.append("abcd");
+ expectBuilderContent("0123456789abcd", builder);
+ builder.append("efgh", 3);
+ expectBuilderContent("0123456789abcdefg", builder);
+ builder.append("");
+ expectBuilderContent("0123456789abcdefg", builder);
+ builder.append('#');
+ expectBuilderContent("0123456789abcdefg#", builder);
+
+ builder.toString(); // Test after reifyString().
+ StringBuilder builder1;
+ builder.append("", 0);
+ expectBuilderContent("0123456789abcdefg#", builder);
+ builder1.append(builder.characters8(), builder.length());
+ builder1.append("XYZ");
+ builder.append(builder1.characters8(), builder1.length());
+ expectBuilderContent("0123456789abcdefg#0123456789abcdefg#XYZ", builder);
+
+ StringBuilder builder2;
+ builder2.reserveCapacity(100);
+ builder2.append("xyz");
+ const LChar* characters = builder2.characters8();
+ builder2.append("0123456789");
+ ASSERT_EQ(characters, builder2.characters8());
+ builder2.toStringPreserveCapacity(); // Test after reifyString with buffer preserved.
+ builder2.append("abcd");
+ ASSERT_EQ(characters, builder2.characters8());
+
+ // Test appending UChar32 characters to StringBuilder.
+ StringBuilder builderForUChar32Append;
+ UChar32 frakturAChar = 0x1D504;
+ builderForUChar32Append.append(frakturAChar); // The fraktur A is not in the BMP, so it's two UTF-16 code units long.
+ ASSERT_EQ(2U, builderForUChar32Append.length());
+ builderForUChar32Append.append(static_cast<UChar32>('A'));
+ ASSERT_EQ(3U, builderForUChar32Append.length());
+ const UChar resultArray[] = { U16_LEAD(frakturAChar), U16_TRAIL(frakturAChar), 'A' };
+ expectBuilderContent(String(resultArray, WTF_ARRAY_LENGTH(resultArray)), builderForUChar32Append);
+}
+
+TEST(StringBuilderTest, ToString)
+{
+ StringBuilder builder;
+ builder.append("0123456789");
+ String string = builder.toString();
+ ASSERT_EQ(String("0123456789"), string);
+ ASSERT_EQ(string.impl(), builder.toString().impl());
+
+ // Changing the StringBuilder should not affect the original result of toString().
+ builder.append("abcdefghijklmnopqrstuvwxyz");
+ ASSERT_EQ(String("0123456789"), string);
+
+ // Changing the StringBuilder should not affect the original result of toString() in case the capacity is not changed.
+ builder.reserveCapacity(200);
+ string = builder.toString();
+ ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyz"), string);
+ builder.append("ABC");
+ ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyz"), string);
+
+ // Changing the original result of toString() should not affect the content of the StringBuilder.
+ String string1 = builder.toString();
+ ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABC"), string1);
+ string1.append("DEF");
+ ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABC"), builder.toString());
+ ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABCDEF"), string1);
+
+ // Resizing the StringBuilder should not affect the original result of toString().
+ string1 = builder.toString();
+ builder.resize(10);
+ builder.append("###");
+ ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABC"), string1);
+}
+
+TEST(StringBuilderTest, ToStringPreserveCapacity)
+{
+ StringBuilder builder;
+ builder.append("0123456789");
+ unsigned capacity = builder.capacity();
+ String string = builder.toStringPreserveCapacity();
+ ASSERT_EQ(capacity, builder.capacity());
+ ASSERT_EQ(String("0123456789"), string);
+ ASSERT_EQ(string.impl(), builder.toStringPreserveCapacity().impl());
+ ASSERT_EQ(string.characters8(), builder.characters8());
+
+ // Changing the StringBuilder should not affect the original result of toStringPreserveCapacity().
+ builder.append("abcdefghijklmnopqrstuvwxyz");
+ ASSERT_EQ(String("0123456789"), string);
+
+ // Changing the StringBuilder should not affect the original result of toStringPreserveCapacity() in case the capacity is not changed.
+ builder.reserveCapacity(200);
+ capacity = builder.capacity();
+ string = builder.toStringPreserveCapacity();
+ ASSERT_EQ(capacity, builder.capacity());
+ ASSERT_EQ(string.characters8(), builder.characters8());
+ ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyz"), string);
+ builder.append("ABC");
+ ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyz"), string);
+
+ // Changing the original result of toStringPreserveCapacity() should not affect the content of the StringBuilder.
+ capacity = builder.capacity();
+ String string1 = builder.toStringPreserveCapacity();
+ ASSERT_EQ(capacity, builder.capacity());
+ ASSERT_EQ(string1.characters8(), builder.characters8());
+ ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABC"), string1);
+ string1.append("DEF");
+ ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABC"), builder.toStringPreserveCapacity());
+ ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABCDEF"), string1);
+
+ // Resizing the StringBuilder should not affect the original result of toStringPreserveCapacity().
+ capacity = builder.capacity();
+ string1 = builder.toStringPreserveCapacity();
+ ASSERT_EQ(capacity, builder.capacity());
+ ASSERT_EQ(string.characters8(), builder.characters8());
+ builder.resize(10);
+ builder.append("###");
+ ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABC"), string1);
+}
+
+TEST(StringBuilderTest, Clear)
+{
+ StringBuilder builder;
+ builder.append("0123456789");
+ builder.clear();
+ expectEmpty(builder);
+}
+
+TEST(StringBuilderTest, Array)
+{
+ StringBuilder builder;
+ builder.append("0123456789");
+ EXPECT_EQ('0', static_cast<char>(builder[0]));
+ EXPECT_EQ('9', static_cast<char>(builder[9]));
+ builder.toString(); // Test after reifyString().
+ EXPECT_EQ('0', static_cast<char>(builder[0]));
+ EXPECT_EQ('9', static_cast<char>(builder[9]));
+}
+
+TEST(StringBuilderTest, Resize)
+{
+ StringBuilder builder;
+ builder.append("0123456789");
+ builder.resize(10);
+ EXPECT_EQ(10U, builder.length());
+ expectBuilderContent("0123456789", builder);
+ builder.resize(8);
+ EXPECT_EQ(8U, builder.length());
+ expectBuilderContent("01234567", builder);
+
+ builder.toString();
+ builder.resize(7);
+ EXPECT_EQ(7U, builder.length());
+ expectBuilderContent("0123456", builder);
+ builder.resize(0);
+ expectEmpty(builder);
+}
+
+TEST(StringBuilderTest, Equal)
+{
+ StringBuilder builder1;
+ StringBuilder builder2;
+ ASSERT_TRUE(builder1 == builder2);
+ ASSERT_TRUE(equal(builder1, static_cast<LChar*>(0), 0));
+ ASSERT_TRUE(builder1 == String());
+ ASSERT_TRUE(String() == builder1);
+ ASSERT_TRUE(builder1 != String("abc"));
+
+ builder1.append("123");
+ builder1.reserveCapacity(32);
+ builder2.append("123");
+ builder1.reserveCapacity(64);
+ ASSERT_TRUE(builder1 == builder2);
+ ASSERT_TRUE(builder1 == String("123"));
+ ASSERT_TRUE(String("123") == builder1);
+
+ builder2.append("456");
+ ASSERT_TRUE(builder1 != builder2);
+ ASSERT_TRUE(builder2 != builder1);
+ ASSERT_TRUE(String("123") != builder2);
+ ASSERT_TRUE(builder2 != String("123"));
+ builder2.toString(); // Test after reifyString().
+ ASSERT_TRUE(builder1 != builder2);
+
+ builder2.resize(3);
+ ASSERT_TRUE(builder1 == builder2);
+
+ builder1.toString(); // Test after reifyString().
+ ASSERT_TRUE(builder1 == builder2);
+}
+
+TEST(StringBuilderTest, CanShrink)
+{
+ StringBuilder builder;
+ builder.reserveCapacity(256);
+ ASSERT_TRUE(builder.canShrink());
+ for (int i = 0; i < 256; i++)
+ builder.append('x');
+ ASSERT_EQ(builder.length(), builder.capacity());
+ ASSERT_FALSE(builder.canShrink());
+}
+
+TEST(StringBuilderTest, ToAtomicString)
+{
+ StringBuilder builder;
+ builder.append("123");
+ AtomicString atomicString = builder.toAtomicString();
+ ASSERT_EQ(String("123"), atomicString);
+
+ builder.reserveCapacity(256);
+ ASSERT_TRUE(builder.canShrink());
+ for (int i = builder.length(); i < 128; i++)
+ builder.append('x');
+ AtomicString atomicString1 = builder.toAtomicString();
+ ASSERT_EQ(128u, atomicString1.length());
+ ASSERT_EQ('x', atomicString1[127]);
+
+ // Later change of builder should not affect the atomic string.
+ for (int i = builder.length(); i < 256; i++)
+ builder.append('x');
+ ASSERT_EQ(128u, atomicString1.length());
+
+ ASSERT_FALSE(builder.canShrink());
+ String string = builder.toString();
+ AtomicString atomicString2 = builder.toAtomicString();
+ // They should share the same StringImpl.
+ ASSERT_EQ(atomicString2.impl(), string.impl());
+}
+
+TEST(StringBuilderTest, ToAtomicStringOnEmpty)
+{
+ { // Default constructed.
+ StringBuilder builder;
+ AtomicString atomicString = builder.toAtomicString();
+ ASSERT_EQ(emptyAtom, atomicString);
+ }
+ { // With capacity.
+ StringBuilder builder;
+ builder.reserveCapacity(64);
+ AtomicString atomicString = builder.toAtomicString();
+ ASSERT_EQ(emptyAtom, atomicString);
+ }
+ { // AtomicString constructed from a null string.
+ StringBuilder builder;
+ builder.append(String());
+ AtomicString atomicString = builder.toAtomicString();
+ ASSERT_EQ(emptyAtom, atomicString);
+ }
+ { // AtomicString constructed from an empty string.
+ StringBuilder builder;
+ builder.append(emptyString());
+ AtomicString atomicString = builder.toAtomicString();
+ ASSERT_EQ(emptyAtom, atomicString);
+ }
+ { // AtomicString constructed from an empty StringBuilder.
+ StringBuilder builder;
+ StringBuilder emptyBuilder;
+ builder.append(emptyBuilder);
+ AtomicString atomicString = builder.toAtomicString();
+ ASSERT_EQ(emptyAtom, atomicString);
+ }
+ { // AtomicString constructed from an empty char* string.
+ StringBuilder builder;
+ builder.append("", 0);
+ AtomicString atomicString = builder.toAtomicString();
+ ASSERT_EQ(emptyAtom, atomicString);
+ }
+ { // Cleared StringBuilder.
+ StringBuilder builder;
+ builder.appendLiteral("WebKit");
+ builder.clear();
+ AtomicString atomicString = builder.toAtomicString();
+ ASSERT_EQ(emptyAtom, atomicString);
+ }
+}
+
+} // namespace
diff --git a/Tools/TestWebKitAPI/Tests/WTF/StringHasher.cpp b/Tools/TestWebKitAPI/Tests/WTF/StringHasher.cpp
new file mode 100644
index 000000000..a4d223c99
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/StringHasher.cpp
@@ -0,0 +1,444 @@
+/*
+ * Copyright (C) 2013 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 <wtf/StringHasher.h>
+
+namespace TestWebKitAPI {
+
+static const LChar nullLChars[2] = { 0, 0 };
+static const UChar nullUChars[2] = { 0, 0 };
+
+static const unsigned emptyStringHash = 0x4EC889EU;
+static const unsigned singleNullCharacterHash = 0x3D3ABF44U;
+
+static const LChar testALChars[6] = { 0x41, 0x95, 0xFF, 0x50, 0x01, 0 };
+static const UChar testAUChars[6] = { 0x41, 0x95, 0xFF, 0x50, 0x01, 0 };
+static const UChar testBUChars[6] = { 0x41, 0x95, 0xFFFF, 0x1080, 0x01, 0 };
+
+static const unsigned testAHash1 = 0xEA32B004;
+static const unsigned testAHash2 = 0x93F0F71E;
+static const unsigned testAHash3 = 0xCB609EB1;
+static const unsigned testAHash4 = 0x7984A706;
+static const unsigned testAHash5 = 0x0427561F;
+
+static const unsigned testBHash1 = 0xEA32B004;
+static const unsigned testBHash2 = 0x93F0F71E;
+static const unsigned testBHash3 = 0x59EB1B2C;
+static const unsigned testBHash4 = 0xA7BCCC0A;
+static const unsigned testBHash5 = 0x79201649;
+
+TEST(WTF, StringHasher)
+{
+ StringHasher hasher;
+
+ // The initial state of the hasher.
+ ASSERT_EQ(emptyStringHash, hasher.hash());
+ ASSERT_EQ(emptyStringHash & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+}
+
+TEST(WTF, StringHasher_addCharacter)
+{
+ StringHasher hasher;
+
+ // Hashing a single character.
+ hasher = StringHasher();
+ hasher.addCharacter(0);
+ ASSERT_EQ(singleNullCharacterHash, hasher.hash());
+ ASSERT_EQ(singleNullCharacterHash & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+
+ // Hashing five characters, checking the intermediate state after each is added.
+ hasher = StringHasher();
+ hasher.addCharacter(testAUChars[0]);
+ ASSERT_EQ(testAHash1, hasher.hash());
+ ASSERT_EQ(testAHash1 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher.addCharacter(testAUChars[1]);
+ ASSERT_EQ(testAHash2, hasher.hash());
+ ASSERT_EQ(testAHash2 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher.addCharacter(testAUChars[2]);
+ ASSERT_EQ(testAHash3, hasher.hash());
+ ASSERT_EQ(testAHash3 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher.addCharacter(testAUChars[3]);
+ ASSERT_EQ(testAHash4, hasher.hash());
+ ASSERT_EQ(testAHash4 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher.addCharacter(testAUChars[4]);
+ ASSERT_EQ(testAHash5, hasher.hash());
+ ASSERT_EQ(testAHash5 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+
+ // Hashing a second set of five characters, including non-Latin-1 characters.
+ hasher = StringHasher();
+ hasher.addCharacter(testBUChars[0]);
+ ASSERT_EQ(testBHash1, hasher.hash());
+ ASSERT_EQ(testBHash1 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher.addCharacter(testBUChars[1]);
+ ASSERT_EQ(testBHash2, hasher.hash());
+ ASSERT_EQ(testBHash2 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher.addCharacter(testBUChars[2]);
+ ASSERT_EQ(testBHash3, hasher.hash());
+ ASSERT_EQ(testBHash3 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher.addCharacter(testBUChars[3]);
+ ASSERT_EQ(testBHash4, hasher.hash());
+ ASSERT_EQ(testBHash4 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher.addCharacter(testBUChars[4]);
+ ASSERT_EQ(testBHash5, hasher.hash());
+ ASSERT_EQ(testBHash5 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+}
+
+TEST(WTF, StringHasher_addCharacters)
+{
+ StringHasher hasher;
+
+ // Hashing zero characters.
+ hasher = StringHasher();
+ hasher.addCharacters(static_cast<LChar*>(0), 0);
+ ASSERT_EQ(emptyStringHash, hasher.hash());
+ ASSERT_EQ(emptyStringHash & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher = StringHasher();
+ hasher.addCharacters(nullLChars, 0);
+ ASSERT_EQ(emptyStringHash, hasher.hash());
+ ASSERT_EQ(emptyStringHash & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher = StringHasher();
+ hasher.addCharacters(nullLChars);
+ ASSERT_EQ(emptyStringHash, hasher.hash());
+ ASSERT_EQ(emptyStringHash & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher = StringHasher();
+ hasher.addCharacters(static_cast<UChar*>(0), 0);
+ ASSERT_EQ(emptyStringHash, hasher.hash());
+ ASSERT_EQ(emptyStringHash & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher = StringHasher();
+ hasher.addCharacters(nullUChars, 0);
+ ASSERT_EQ(emptyStringHash, hasher.hash());
+ ASSERT_EQ(emptyStringHash & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher = StringHasher();
+ hasher.addCharacters(nullUChars);
+ ASSERT_EQ(emptyStringHash, hasher.hash());
+ ASSERT_EQ(emptyStringHash & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+
+ // Hashing one character.
+ hasher = StringHasher();
+ hasher.addCharacters(nullLChars, 1);
+ ASSERT_EQ(singleNullCharacterHash, hasher.hash());
+ ASSERT_EQ(singleNullCharacterHash & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher = StringHasher();
+ hasher.addCharacters(nullUChars, 1);
+ ASSERT_EQ(singleNullCharacterHash, hasher.hash());
+ ASSERT_EQ(singleNullCharacterHash & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+
+ // Hashing five characters, all at once.
+ hasher = StringHasher();
+ hasher.addCharacters(testALChars, 5);
+ ASSERT_EQ(testAHash5, hasher.hash());
+ ASSERT_EQ(testAHash5 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher = StringHasher();
+ hasher.addCharacters(testALChars);
+ ASSERT_EQ(testAHash5, hasher.hash());
+ ASSERT_EQ(testAHash5 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher = StringHasher();
+ hasher.addCharacters(testAUChars, 5);
+ ASSERT_EQ(testAHash5, hasher.hash());
+ ASSERT_EQ(testAHash5 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher = StringHasher();
+ hasher.addCharacters(testAUChars);
+ ASSERT_EQ(testAHash5, hasher.hash());
+ ASSERT_EQ(testAHash5 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher = StringHasher();
+ hasher.addCharacters(testBUChars, 5);
+ ASSERT_EQ(testBHash5, hasher.hash());
+ ASSERT_EQ(testBHash5 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher = StringHasher();
+ hasher.addCharacters(testBUChars);
+ ASSERT_EQ(testBHash5, hasher.hash());
+ ASSERT_EQ(testBHash5 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+
+ // Hashing five characters, in groups of two, then the last one.
+ hasher = StringHasher();
+ hasher.addCharacters(testALChars, 2);
+ ASSERT_EQ(testAHash2, hasher.hash());
+ ASSERT_EQ(testAHash2 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher.addCharacters(testALChars + 2, 2);
+ ASSERT_EQ(testAHash4, hasher.hash());
+ ASSERT_EQ(testAHash4 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher.addCharacters(testALChars + 4, 1);
+ ASSERT_EQ(testAHash5, hasher.hash());
+ ASSERT_EQ(testAHash5 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher = StringHasher();
+ hasher.addCharacters(testALChars, 2);
+ hasher.addCharacters(testALChars + 2, 2);
+ hasher.addCharacters(testALChars + 4);
+ ASSERT_EQ(testAHash5, hasher.hash());
+ ASSERT_EQ(testAHash5 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher = StringHasher();
+ hasher.addCharacters(testAUChars, 2);
+ ASSERT_EQ(testAHash2, hasher.hash());
+ ASSERT_EQ(testAHash2 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher.addCharacters(testAUChars + 2, 2);
+ ASSERT_EQ(testAHash4, hasher.hash());
+ ASSERT_EQ(testAHash4 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher.addCharacters(testAUChars + 4, 1);
+ ASSERT_EQ(testAHash5, hasher.hash());
+ ASSERT_EQ(testAHash5 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher = StringHasher();
+ hasher.addCharacters(testAUChars, 2);
+ hasher.addCharacters(testAUChars + 2, 2);
+ hasher.addCharacters(testAUChars + 4);
+ ASSERT_EQ(testAHash5, hasher.hash());
+ ASSERT_EQ(testAHash5 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher = StringHasher();
+ hasher.addCharacters(testBUChars, 2);
+ ASSERT_EQ(testBHash2, hasher.hash());
+ ASSERT_EQ(testBHash2 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher.addCharacters(testBUChars + 2, 2);
+ ASSERT_EQ(testBHash4, hasher.hash());
+ ASSERT_EQ(testBHash4 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher.addCharacters(testBUChars + 4, 1);
+ ASSERT_EQ(testBHash5, hasher.hash());
+ ASSERT_EQ(testBHash5 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher = StringHasher();
+ hasher.addCharacters(testBUChars, 2);
+ hasher.addCharacters(testBUChars + 2, 2);
+ hasher.addCharacters(testBUChars + 4);
+ ASSERT_EQ(testBHash5, hasher.hash());
+ ASSERT_EQ(testBHash5 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+
+ // Hashing five characters, the first three, then the last two.
+ hasher = StringHasher();
+ hasher.addCharacters(testALChars, 3);
+ ASSERT_EQ(testAHash3, hasher.hash());
+ ASSERT_EQ(testAHash3 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher.addCharacters(testALChars + 3, 2);
+ ASSERT_EQ(testAHash5, hasher.hash());
+ ASSERT_EQ(testAHash5 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher = StringHasher();
+ hasher.addCharacters(testALChars, 3);
+ ASSERT_EQ(testAHash3, hasher.hash());
+ ASSERT_EQ(testAHash3 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher.addCharacters(testALChars + 3);
+ ASSERT_EQ(testAHash5, hasher.hash());
+ ASSERT_EQ(testAHash5 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher = StringHasher();
+ hasher.addCharacters(testAUChars, 3);
+ ASSERT_EQ(testAHash3, hasher.hash());
+ ASSERT_EQ(testAHash3 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher.addCharacters(testAUChars + 3, 2);
+ ASSERT_EQ(testAHash5, hasher.hash());
+ ASSERT_EQ(testAHash5 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher = StringHasher();
+ hasher.addCharacters(testAUChars, 3);
+ ASSERT_EQ(testAHash3, hasher.hash());
+ ASSERT_EQ(testAHash3 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher.addCharacters(testAUChars + 3, 2);
+ ASSERT_EQ(testAHash5, hasher.hash());
+ ASSERT_EQ(testAHash5 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher = StringHasher();
+ hasher.addCharacters(testBUChars, 3);
+ ASSERT_EQ(testBHash3, hasher.hash());
+ ASSERT_EQ(testBHash3 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher.addCharacters(testBUChars + 3, 2);
+ ASSERT_EQ(testBHash5, hasher.hash());
+ ASSERT_EQ(testBHash5 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher = StringHasher();
+ hasher.addCharacters(testBUChars, 3);
+ hasher.addCharacters(testBUChars + 3);
+ ASSERT_EQ(testBHash5, hasher.hash());
+ ASSERT_EQ(testBHash5 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+}
+
+TEST(WTF, StringHasher_addCharactersAssumingAligned)
+{
+ StringHasher hasher;
+
+ // Hashing zero characters.
+ hasher = StringHasher();
+ hasher.addCharactersAssumingAligned(static_cast<LChar*>(0), 0);
+ ASSERT_EQ(emptyStringHash, hasher.hash());
+ ASSERT_EQ(emptyStringHash & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher = StringHasher();
+ hasher.addCharactersAssumingAligned(nullLChars, 0);
+ ASSERT_EQ(emptyStringHash, hasher.hash());
+ ASSERT_EQ(emptyStringHash & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher = StringHasher();
+ hasher.addCharactersAssumingAligned(static_cast<UChar*>(0), 0);
+ ASSERT_EQ(emptyStringHash, hasher.hash());
+ ASSERT_EQ(emptyStringHash & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher = StringHasher();
+ hasher.addCharactersAssumingAligned(nullUChars, 0);
+ ASSERT_EQ(emptyStringHash, hasher.hash());
+ ASSERT_EQ(emptyStringHash & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher = StringHasher();
+ hasher.addCharactersAssumingAligned(nullUChars);
+ ASSERT_EQ(emptyStringHash, hasher.hash());
+ ASSERT_EQ(emptyStringHash & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+
+ // Hashing one character.
+ hasher = StringHasher();
+ hasher.addCharactersAssumingAligned(nullLChars, 1);
+ ASSERT_EQ(singleNullCharacterHash, hasher.hash());
+ ASSERT_EQ(singleNullCharacterHash & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher = StringHasher();
+ hasher.addCharactersAssumingAligned(nullUChars, 1);
+ ASSERT_EQ(singleNullCharacterHash, hasher.hash());
+ ASSERT_EQ(singleNullCharacterHash & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+
+ // Hashing five characters, all at once.
+ hasher = StringHasher();
+ hasher.addCharactersAssumingAligned(testALChars, 5);
+ ASSERT_EQ(testAHash5, hasher.hash());
+ ASSERT_EQ(testAHash5 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher = StringHasher();
+ hasher.addCharactersAssumingAligned(testALChars);
+ ASSERT_EQ(testAHash5, hasher.hash());
+ ASSERT_EQ(testAHash5 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher = StringHasher();
+ hasher.addCharactersAssumingAligned(testAUChars, 5);
+ ASSERT_EQ(testAHash5, hasher.hash());
+ ASSERT_EQ(testAHash5 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher = StringHasher();
+ hasher.addCharactersAssumingAligned(testAUChars);
+ ASSERT_EQ(testAHash5, hasher.hash());
+ ASSERT_EQ(testAHash5 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher = StringHasher();
+ hasher.addCharactersAssumingAligned(testBUChars, 5);
+ ASSERT_EQ(testBHash5, hasher.hash());
+ ASSERT_EQ(testBHash5 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher = StringHasher();
+ hasher.addCharactersAssumingAligned(testBUChars);
+ ASSERT_EQ(testBHash5, hasher.hash());
+ ASSERT_EQ(testBHash5 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+
+ // Hashing five characters, in groups of two, then the last one.
+ hasher = StringHasher();
+ hasher.addCharactersAssumingAligned(testALChars, 2);
+ ASSERT_EQ(testAHash2, hasher.hash());
+ ASSERT_EQ(testAHash2 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher.addCharactersAssumingAligned(testALChars + 2, 2);
+ ASSERT_EQ(testAHash4, hasher.hash());
+ ASSERT_EQ(testAHash4 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher.addCharactersAssumingAligned(testALChars + 4, 1);
+ ASSERT_EQ(testAHash5, hasher.hash());
+ ASSERT_EQ(testAHash5 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher = StringHasher();
+ hasher.addCharactersAssumingAligned(testALChars, 2);
+ hasher.addCharactersAssumingAligned(testALChars + 2, 2);
+ hasher.addCharactersAssumingAligned(testALChars + 4);
+ ASSERT_EQ(testAHash5, hasher.hash());
+ ASSERT_EQ(testAHash5 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher = StringHasher();
+ hasher.addCharactersAssumingAligned(testAUChars, 2);
+ ASSERT_EQ(testAHash2, hasher.hash());
+ ASSERT_EQ(testAHash2 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher.addCharactersAssumingAligned(testAUChars + 2, 2);
+ ASSERT_EQ(testAHash4, hasher.hash());
+ ASSERT_EQ(testAHash4 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher.addCharactersAssumingAligned(testAUChars + 4, 1);
+ ASSERT_EQ(testAHash5, hasher.hash());
+ ASSERT_EQ(testAHash5 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher = StringHasher();
+ hasher.addCharactersAssumingAligned(testAUChars, 2);
+ hasher.addCharactersAssumingAligned(testAUChars + 2, 2);
+ hasher.addCharactersAssumingAligned(testAUChars + 4);
+ ASSERT_EQ(testAHash5, hasher.hash());
+ ASSERT_EQ(testAHash5 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher = StringHasher();
+ hasher.addCharactersAssumingAligned(testBUChars, 2);
+ ASSERT_EQ(testBHash2, hasher.hash());
+ ASSERT_EQ(testBHash2 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher.addCharactersAssumingAligned(testBUChars + 2, 2);
+ ASSERT_EQ(testBHash4, hasher.hash());
+ ASSERT_EQ(testBHash4 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher.addCharactersAssumingAligned(testBUChars + 4, 1);
+ ASSERT_EQ(testBHash5, hasher.hash());
+ ASSERT_EQ(testBHash5 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher = StringHasher();
+ hasher.addCharactersAssumingAligned(testBUChars, 2);
+ hasher.addCharactersAssumingAligned(testBUChars + 2, 2);
+ hasher.addCharactersAssumingAligned(testBUChars + 4);
+ ASSERT_EQ(testBHash5, hasher.hash());
+ ASSERT_EQ(testBHash5 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+
+ // Hashing five characters, first two characters one at a time,
+ // then two more, then the last one.
+ hasher = StringHasher();
+ hasher.addCharacter(testBUChars[0]);
+ ASSERT_EQ(testBHash1, hasher.hash());
+ ASSERT_EQ(testBHash1 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher.addCharacter(testBUChars[1]);
+ ASSERT_EQ(testBHash2, hasher.hash());
+ ASSERT_EQ(testBHash2 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher.addCharactersAssumingAligned(testBUChars[2], testBUChars[3]);
+ ASSERT_EQ(testBHash4, hasher.hash());
+ ASSERT_EQ(testBHash4 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+ hasher.addCharactersAssumingAligned(testBUChars + 4);
+ ASSERT_EQ(testBHash5, hasher.hash());
+ ASSERT_EQ(testBHash5 & 0xFFFFFF, hasher.hashWithTop8BitsMasked());
+}
+
+TEST(WTF, StringHasher_computeHash)
+{
+ ASSERT_EQ(emptyStringHash, StringHasher::computeHash(static_cast<LChar*>(0), 0));
+ ASSERT_EQ(emptyStringHash, StringHasher::computeHash(nullLChars, 0));
+ ASSERT_EQ(emptyStringHash, StringHasher::computeHash(static_cast<UChar*>(0), 0));
+ ASSERT_EQ(emptyStringHash, StringHasher::computeHash(nullUChars, 0));
+
+ ASSERT_EQ(singleNullCharacterHash, StringHasher::computeHash(nullLChars, 1));
+ ASSERT_EQ(singleNullCharacterHash, StringHasher::computeHash(nullUChars, 1));
+
+ ASSERT_EQ(testAHash5, StringHasher::computeHash(testALChars, 5));
+ ASSERT_EQ(testAHash5, StringHasher::computeHash(testAUChars, 5));
+ ASSERT_EQ(testBHash5, StringHasher::computeHash(testBUChars, 5));
+}
+
+TEST(WTF, StringHasher_computeHashAndMaskTop8Bits)
+{
+ ASSERT_EQ(emptyStringHash & 0xFFFFFF, StringHasher::computeHashAndMaskTop8Bits(static_cast<LChar*>(0), 0));
+ ASSERT_EQ(emptyStringHash & 0xFFFFFF, StringHasher::computeHashAndMaskTop8Bits(nullLChars, 0));
+ ASSERT_EQ(emptyStringHash & 0xFFFFFF, StringHasher::computeHashAndMaskTop8Bits(static_cast<UChar*>(0), 0));
+ ASSERT_EQ(emptyStringHash & 0xFFFFFF, StringHasher::computeHashAndMaskTop8Bits(nullUChars, 0));
+
+ ASSERT_EQ(singleNullCharacterHash & 0xFFFFFF, StringHasher::computeHashAndMaskTop8Bits(nullLChars, 1));
+ ASSERT_EQ(singleNullCharacterHash & 0xFFFFFF, StringHasher::computeHashAndMaskTop8Bits(nullUChars, 1));
+
+ ASSERT_EQ(testAHash5 & 0xFFFFFF, StringHasher::computeHashAndMaskTop8Bits(testALChars, 5));
+ ASSERT_EQ(testAHash5 & 0xFFFFFF, StringHasher::computeHashAndMaskTop8Bits(testAUChars, 5));
+ ASSERT_EQ(testBHash5 & 0xFFFFFF, StringHasher::computeHashAndMaskTop8Bits(testBUChars, 5));
+}
+
+TEST(WTF, StringHasher_hashMemory)
+{
+ ASSERT_EQ(emptyStringHash & 0xFFFFFF, StringHasher::hashMemory(0, 0));
+ ASSERT_EQ(emptyStringHash & 0xFFFFFF, StringHasher::hashMemory(nullUChars, 0));
+ ASSERT_EQ(emptyStringHash & 0xFFFFFF, StringHasher::hashMemory<0>(0));
+ ASSERT_EQ(emptyStringHash & 0xFFFFFF, StringHasher::hashMemory<0>(nullUChars));
+
+ ASSERT_EQ(singleNullCharacterHash & 0xFFFFFF, StringHasher::hashMemory(nullUChars, 2));
+ ASSERT_EQ(singleNullCharacterHash & 0xFFFFFF, StringHasher::hashMemory<2>(nullUChars));
+
+ ASSERT_EQ(testAHash5 & 0xFFFFFF, StringHasher::hashMemory(testAUChars, 10));
+ ASSERT_EQ(testAHash5 & 0xFFFFFF, StringHasher::hashMemory<10>(testAUChars));
+ ASSERT_EQ(testBHash5 & 0xFFFFFF, StringHasher::hashMemory(testBUChars, 10));
+ ASSERT_EQ(testBHash5 & 0xFFFFFF, StringHasher::hashMemory<10>(testBUChars));
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/StringImpl.cpp b/Tools/TestWebKitAPI/Tests/WTF/StringImpl.cpp
new file mode 100644
index 000000000..75fadf8c4
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/StringImpl.cpp
@@ -0,0 +1,548 @@
+/*
+ * Copyright (C) 2012 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 <wtf/text/SymbolImpl.h>
+#include <wtf/text/WTFString.h>
+
+namespace TestWebKitAPI {
+
+TEST(WTF, StringImplCreationFromLiteral)
+{
+ // Constructor using the template to determine the size.
+ RefPtr<StringImpl> stringWithTemplate = StringImpl::createFromLiteral("Template Literal");
+ ASSERT_EQ(strlen("Template Literal"), stringWithTemplate->length());
+ ASSERT_TRUE(equal(stringWithTemplate.get(), "Template Literal"));
+ ASSERT_TRUE(stringWithTemplate->is8Bit());
+
+ // Constructor taking the size explicitely.
+ const char* programmaticStringData = "Explicit Size Literal";
+ RefPtr<StringImpl> programmaticString = StringImpl::createFromLiteral(programmaticStringData, strlen(programmaticStringData));
+ ASSERT_EQ(strlen(programmaticStringData), programmaticString->length());
+ ASSERT_TRUE(equal(programmaticString.get(), programmaticStringData));
+ ASSERT_EQ(programmaticStringData, reinterpret_cast<const char*>(programmaticString->characters8()));
+ ASSERT_TRUE(programmaticString->is8Bit());
+
+ // Constructor without explicit size.
+ const char* stringWithoutLengthLiteral = "No Size Literal";
+ RefPtr<StringImpl> programmaticStringNoLength = StringImpl::createFromLiteral(stringWithoutLengthLiteral);
+ ASSERT_EQ(strlen(stringWithoutLengthLiteral), programmaticStringNoLength->length());
+ ASSERT_TRUE(equal(programmaticStringNoLength.get(), stringWithoutLengthLiteral));
+ ASSERT_EQ(stringWithoutLengthLiteral, reinterpret_cast<const char*>(programmaticStringNoLength->characters8()));
+ ASSERT_TRUE(programmaticStringNoLength->is8Bit());
+}
+
+TEST(WTF, StringImplReplaceWithLiteral)
+{
+ RefPtr<StringImpl> testStringImpl = StringImpl::createFromLiteral("1224");
+ ASSERT_TRUE(testStringImpl->is8Bit());
+
+ // Cases for 8Bit source.
+ testStringImpl = testStringImpl->replace('2', "", 0);
+ ASSERT_TRUE(equal(testStringImpl.get(), "14"));
+
+ testStringImpl = StringImpl::createFromLiteral("1224");
+ ASSERT_TRUE(testStringImpl->is8Bit());
+
+ testStringImpl = testStringImpl->replace('3', "NotFound", 8);
+ ASSERT_TRUE(equal(testStringImpl.get(), "1224"));
+
+ testStringImpl = testStringImpl->replace('2', "3", 1);
+ ASSERT_TRUE(equal(testStringImpl.get(), "1334"));
+
+ testStringImpl = StringImpl::createFromLiteral("1224");
+ ASSERT_TRUE(testStringImpl->is8Bit());
+ testStringImpl = testStringImpl->replace('2', "555", 3);
+ ASSERT_TRUE(equal(testStringImpl.get(), "15555554"));
+
+ // Cases for 16Bit source.
+ String testString = String::fromUTF8("résumé");
+ ASSERT_FALSE(testString.impl()->is8Bit());
+
+ testStringImpl = testString.impl()->replace('2', "NotFound", 8);
+ ASSERT_TRUE(equal(testStringImpl.get(), String::fromUTF8("résumé").impl()));
+
+ testStringImpl = testString.impl()->replace(UChar(0x00E9 /*U+00E9 is 'é'*/), "e", 1);
+ ASSERT_TRUE(equal(testStringImpl.get(), "resume"));
+
+ testString = String::fromUTF8("résumé");
+ ASSERT_FALSE(testString.impl()->is8Bit());
+ testStringImpl = testString.impl()->replace(UChar(0x00E9 /*U+00E9 is 'é'*/), "", 0);
+ ASSERT_TRUE(equal(testStringImpl.get(), "rsum"));
+
+ testString = String::fromUTF8("résumé");
+ ASSERT_FALSE(testString.impl()->is8Bit());
+ testStringImpl = testString.impl()->replace(UChar(0x00E9 /*U+00E9 is 'é'*/), "555", 3);
+ ASSERT_TRUE(equal(testStringImpl.get(), "r555sum555"));
+}
+
+TEST(WTF, StringImplEqualIgnoringASCIICaseBasic)
+{
+ RefPtr<StringImpl> a = StringImpl::createFromLiteral("aBcDeFG");
+ RefPtr<StringImpl> b = StringImpl::createFromLiteral("ABCDEFG");
+ RefPtr<StringImpl> c = StringImpl::createFromLiteral("abcdefg");
+ const char d[] = "aBcDeFG";
+ RefPtr<StringImpl> empty = StringImpl::create(reinterpret_cast<const LChar*>(""));
+ RefPtr<StringImpl> shorter = StringImpl::createFromLiteral("abcdef");
+ RefPtr<StringImpl> different = StringImpl::createFromLiteral("abcrefg");
+
+ // Identity.
+ ASSERT_TRUE(equalIgnoringASCIICase(a.get(), a.get()));
+ ASSERT_TRUE(equalIgnoringASCIICase(b.get(), b.get()));
+ ASSERT_TRUE(equalIgnoringASCIICase(c.get(), c.get()));
+ ASSERT_TRUE(equalIgnoringASCIICase(a.get(), d));
+ ASSERT_TRUE(equalIgnoringASCIICase(b.get(), d));
+ ASSERT_TRUE(equalIgnoringASCIICase(c.get(), d));
+
+ // Transitivity.
+ ASSERT_TRUE(equalIgnoringASCIICase(a.get(), b.get()));
+ ASSERT_TRUE(equalIgnoringASCIICase(b.get(), c.get()));
+ ASSERT_TRUE(equalIgnoringASCIICase(a.get(), c.get()));
+
+ // Negative cases.
+ ASSERT_FALSE(equalIgnoringASCIICase(a.get(), empty.get()));
+ ASSERT_FALSE(equalIgnoringASCIICase(b.get(), empty.get()));
+ ASSERT_FALSE(equalIgnoringASCIICase(c.get(), empty.get()));
+ ASSERT_FALSE(equalIgnoringASCIICase(a.get(), shorter.get()));
+ ASSERT_FALSE(equalIgnoringASCIICase(b.get(), shorter.get()));
+ ASSERT_FALSE(equalIgnoringASCIICase(c.get(), shorter.get()));
+ ASSERT_FALSE(equalIgnoringASCIICase(a.get(), different.get()));
+ ASSERT_FALSE(equalIgnoringASCIICase(b.get(), different.get()));
+ ASSERT_FALSE(equalIgnoringASCIICase(c.get(), different.get()));
+ ASSERT_FALSE(equalIgnoringASCIICase(empty.get(), d));
+ ASSERT_FALSE(equalIgnoringASCIICase(shorter.get(), d));
+ ASSERT_FALSE(equalIgnoringASCIICase(different.get(), d));
+}
+
+TEST(WTF, StringImplEqualIgnoringASCIICaseWithNull)
+{
+ RefPtr<StringImpl> reference = StringImpl::createFromLiteral("aBcDeFG");
+ ASSERT_FALSE(equalIgnoringASCIICase(nullptr, reference.get()));
+ ASSERT_FALSE(equalIgnoringASCIICase(reference.get(), nullptr));
+ ASSERT_TRUE(equalIgnoringASCIICase(nullptr, nullptr));
+}
+
+TEST(WTF, StringImplEqualIgnoringASCIICaseWithEmpty)
+{
+ RefPtr<StringImpl> a = StringImpl::create(reinterpret_cast<const LChar*>(""));
+ RefPtr<StringImpl> b = StringImpl::create(reinterpret_cast<const LChar*>(""));
+ ASSERT_TRUE(equalIgnoringASCIICase(a.get(), b.get()));
+ ASSERT_TRUE(equalIgnoringASCIICase(b.get(), a.get()));
+}
+
+static RefPtr<StringImpl> stringFromUTF8(const char* characters)
+{
+ return String::fromUTF8(characters).impl();
+}
+
+TEST(WTF, StringImplEqualIgnoringASCIICaseWithLatin1Characters)
+{
+ RefPtr<StringImpl> a = stringFromUTF8("aBcéeFG");
+ RefPtr<StringImpl> b = stringFromUTF8("ABCÉEFG");
+ RefPtr<StringImpl> c = stringFromUTF8("ABCéEFG");
+ RefPtr<StringImpl> d = stringFromUTF8("abcéefg");
+ const char e[] = "aBcéeFG";
+
+ // Identity.
+ ASSERT_TRUE(equalIgnoringASCIICase(a.get(), a.get()));
+ ASSERT_TRUE(equalIgnoringASCIICase(b.get(), b.get()));
+ ASSERT_TRUE(equalIgnoringASCIICase(c.get(), c.get()));
+ ASSERT_TRUE(equalIgnoringASCIICase(d.get(), d.get()));
+
+ // All combination.
+ ASSERT_FALSE(equalIgnoringASCIICase(a.get(), b.get()));
+ ASSERT_TRUE(equalIgnoringASCIICase(a.get(), c.get()));
+ ASSERT_TRUE(equalIgnoringASCIICase(a.get(), d.get()));
+ ASSERT_FALSE(equalIgnoringASCIICase(b.get(), c.get()));
+ ASSERT_FALSE(equalIgnoringASCIICase(b.get(), d.get()));
+ ASSERT_TRUE(equalIgnoringASCIICase(c.get(), d.get()));
+ ASSERT_FALSE(equalIgnoringASCIICase(a.get(), e));
+ ASSERT_FALSE(equalIgnoringASCIICase(b.get(), e));
+ ASSERT_FALSE(equalIgnoringASCIICase(c.get(), e));
+ ASSERT_FALSE(equalIgnoringASCIICase(d.get(), e));
+}
+
+TEST(WTF, StringImplFindIgnoringASCIICaseBasic)
+{
+ RefPtr<StringImpl> referenceA = stringFromUTF8("aBcéeFG");
+ RefPtr<StringImpl> referenceB = stringFromUTF8("ABCÉEFG");
+
+ // Search the exact string.
+ EXPECT_EQ(static_cast<size_t>(0), referenceA->findIgnoringASCIICase(referenceA.get()));
+ EXPECT_EQ(static_cast<size_t>(0), referenceB->findIgnoringASCIICase(referenceB.get()));
+
+ // A and B are distinct by the non-ascii character é/É.
+ EXPECT_EQ(static_cast<size_t>(notFound), referenceA->findIgnoringASCIICase(referenceB.get()));
+ EXPECT_EQ(static_cast<size_t>(notFound), referenceB->findIgnoringASCIICase(referenceA.get()));
+
+ // Find the prefix.
+ EXPECT_EQ(static_cast<size_t>(0), referenceA->findIgnoringASCIICase(StringImpl::createFromLiteral("a").get()));
+ EXPECT_EQ(static_cast<size_t>(0), referenceA->findIgnoringASCIICase(stringFromUTF8("abcé").get()));
+ EXPECT_EQ(static_cast<size_t>(0), referenceA->findIgnoringASCIICase(StringImpl::createFromLiteral("A").get()));
+ EXPECT_EQ(static_cast<size_t>(0), referenceA->findIgnoringASCIICase(stringFromUTF8("ABCé").get()));
+ EXPECT_EQ(static_cast<size_t>(0), referenceB->findIgnoringASCIICase(StringImpl::createFromLiteral("a").get()));
+ EXPECT_EQ(static_cast<size_t>(0), referenceB->findIgnoringASCIICase(stringFromUTF8("abcÉ").get()));
+ EXPECT_EQ(static_cast<size_t>(0), referenceB->findIgnoringASCIICase(StringImpl::createFromLiteral("A").get()));
+ EXPECT_EQ(static_cast<size_t>(0), referenceB->findIgnoringASCIICase(stringFromUTF8("ABCÉ").get()));
+
+ // Not a prefix.
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(StringImpl::createFromLiteral("x").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("accé").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("abcÉ").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(StringImpl::createFromLiteral("X").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("ABDé").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("ABCÉ").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(StringImpl::createFromLiteral("y").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("accÉ").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("abcé").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(StringImpl::createFromLiteral("Y").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("ABdÉ").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("ABCé").get()));
+
+ // Find the infix.
+ EXPECT_EQ(static_cast<size_t>(2), referenceA->findIgnoringASCIICase(stringFromUTF8("cée").get()));
+ EXPECT_EQ(static_cast<size_t>(3), referenceA->findIgnoringASCIICase(stringFromUTF8("ée").get()));
+ EXPECT_EQ(static_cast<size_t>(2), referenceA->findIgnoringASCIICase(stringFromUTF8("cé").get()));
+ EXPECT_EQ(static_cast<size_t>(2), referenceA->findIgnoringASCIICase(stringFromUTF8("c").get()));
+ EXPECT_EQ(static_cast<size_t>(3), referenceA->findIgnoringASCIICase(stringFromUTF8("é").get()));
+ EXPECT_EQ(static_cast<size_t>(2), referenceA->findIgnoringASCIICase(stringFromUTF8("Cée").get()));
+ EXPECT_EQ(static_cast<size_t>(3), referenceA->findIgnoringASCIICase(stringFromUTF8("éE").get()));
+ EXPECT_EQ(static_cast<size_t>(2), referenceA->findIgnoringASCIICase(stringFromUTF8("Cé").get()));
+ EXPECT_EQ(static_cast<size_t>(2), referenceA->findIgnoringASCIICase(stringFromUTF8("C").get()));
+
+ EXPECT_EQ(static_cast<size_t>(2), referenceB->findIgnoringASCIICase(stringFromUTF8("cÉe").get()));
+ EXPECT_EQ(static_cast<size_t>(3), referenceB->findIgnoringASCIICase(stringFromUTF8("Ée").get()));
+ EXPECT_EQ(static_cast<size_t>(2), referenceB->findIgnoringASCIICase(stringFromUTF8("cÉ").get()));
+ EXPECT_EQ(static_cast<size_t>(2), referenceB->findIgnoringASCIICase(stringFromUTF8("c").get()));
+ EXPECT_EQ(static_cast<size_t>(3), referenceB->findIgnoringASCIICase(stringFromUTF8("É").get()));
+ EXPECT_EQ(static_cast<size_t>(2), referenceB->findIgnoringASCIICase(stringFromUTF8("CÉe").get()));
+ EXPECT_EQ(static_cast<size_t>(3), referenceB->findIgnoringASCIICase(stringFromUTF8("ÉE").get()));
+ EXPECT_EQ(static_cast<size_t>(2), referenceB->findIgnoringASCIICase(stringFromUTF8("CÉ").get()));
+ EXPECT_EQ(static_cast<size_t>(2), referenceB->findIgnoringASCIICase(stringFromUTF8("C").get()));
+
+ // Not an infix.
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("céd").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("Ée").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("bé").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("x").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("É").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("CÉe").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("éd").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("CÉ").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("Y").get()));
+
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("cée").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("Éc").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("cé").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("W").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("é").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("bÉe").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("éE").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("BÉ").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("z").get()));
+
+ // Find the suffix.
+ EXPECT_EQ(static_cast<size_t>(6), referenceA->findIgnoringASCIICase(StringImpl::createFromLiteral("g").get()));
+ EXPECT_EQ(static_cast<size_t>(4), referenceA->findIgnoringASCIICase(stringFromUTF8("efg").get()));
+ EXPECT_EQ(static_cast<size_t>(3), referenceA->findIgnoringASCIICase(stringFromUTF8("éefg").get()));
+ EXPECT_EQ(static_cast<size_t>(6), referenceA->findIgnoringASCIICase(StringImpl::createFromLiteral("G").get()));
+ EXPECT_EQ(static_cast<size_t>(4), referenceA->findIgnoringASCIICase(stringFromUTF8("EFG").get()));
+ EXPECT_EQ(static_cast<size_t>(3), referenceA->findIgnoringASCIICase(stringFromUTF8("éEFG").get()));
+
+ EXPECT_EQ(static_cast<size_t>(6), referenceB->findIgnoringASCIICase(StringImpl::createFromLiteral("g").get()));
+ EXPECT_EQ(static_cast<size_t>(4), referenceB->findIgnoringASCIICase(stringFromUTF8("efg").get()));
+ EXPECT_EQ(static_cast<size_t>(3), referenceB->findIgnoringASCIICase(stringFromUTF8("Éefg").get()));
+ EXPECT_EQ(static_cast<size_t>(6), referenceB->findIgnoringASCIICase(StringImpl::createFromLiteral("G").get()));
+ EXPECT_EQ(static_cast<size_t>(4), referenceB->findIgnoringASCIICase(stringFromUTF8("EFG").get()));
+ EXPECT_EQ(static_cast<size_t>(3), referenceB->findIgnoringASCIICase(stringFromUTF8("ÉEFG").get()));
+
+ // Not a suffix.
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(StringImpl::createFromLiteral("X").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("edg").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("Éefg").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(StringImpl::createFromLiteral("w").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("dFG").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA->findIgnoringASCIICase(stringFromUTF8("ÉEFG").get()));
+
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(StringImpl::createFromLiteral("Z").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("ffg").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("éefg").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(StringImpl::createFromLiteral("r").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("EgG").get()));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB->findIgnoringASCIICase(stringFromUTF8("éEFG").get()));
+}
+
+TEST(WTF, StringImplFindIgnoringASCIICaseWithValidOffset)
+{
+ RefPtr<StringImpl> reference = stringFromUTF8("ABCÉEFGaBcéeFG");
+ EXPECT_EQ(static_cast<size_t>(0), reference->findIgnoringASCIICase(stringFromUTF8("ABC").get(), 0));
+ EXPECT_EQ(static_cast<size_t>(7), reference->findIgnoringASCIICase(stringFromUTF8("ABC").get(), 1));
+ EXPECT_EQ(static_cast<size_t>(0), reference->findIgnoringASCIICase(stringFromUTF8("ABCÉ").get(), 0));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference->findIgnoringASCIICase(stringFromUTF8("ABCÉ").get(), 1));
+ EXPECT_EQ(static_cast<size_t>(7), reference->findIgnoringASCIICase(stringFromUTF8("ABCé").get(), 0));
+ EXPECT_EQ(static_cast<size_t>(7), reference->findIgnoringASCIICase(stringFromUTF8("ABCé").get(), 1));
+}
+
+TEST(WTF, StringImplFindIgnoringASCIICaseWithInvalidOffset)
+{
+ RefPtr<StringImpl> reference = stringFromUTF8("ABCÉEFGaBcéeFG");
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference->findIgnoringASCIICase(stringFromUTF8("ABC").get(), 15));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference->findIgnoringASCIICase(stringFromUTF8("ABC").get(), 16));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference->findIgnoringASCIICase(stringFromUTF8("ABCÉ").get(), 17));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference->findIgnoringASCIICase(stringFromUTF8("ABCÉ").get(), 42));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference->findIgnoringASCIICase(stringFromUTF8("ABCÉ").get(), std::numeric_limits<unsigned>::max()));
+}
+
+TEST(WTF, StringImplFindIgnoringASCIICaseOnNull)
+{
+ RefPtr<StringImpl> reference = stringFromUTF8("ABCÉEFG");
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference->findIgnoringASCIICase(nullptr));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference->findIgnoringASCIICase(nullptr, 0));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference->findIgnoringASCIICase(nullptr, 3));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference->findIgnoringASCIICase(nullptr, 7));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference->findIgnoringASCIICase(nullptr, 8));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference->findIgnoringASCIICase(nullptr, 42));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference->findIgnoringASCIICase(nullptr, std::numeric_limits<unsigned>::max()));
+}
+
+TEST(WTF, StringImplFindIgnoringASCIICaseOnEmpty)
+{
+ RefPtr<StringImpl> reference = stringFromUTF8("ABCÉEFG");
+ RefPtr<StringImpl> empty = StringImpl::create(reinterpret_cast<const LChar*>(""));
+ EXPECT_EQ(static_cast<size_t>(0), reference->findIgnoringASCIICase(empty.get()));
+ EXPECT_EQ(static_cast<size_t>(0), reference->findIgnoringASCIICase(empty.get(), 0));
+ EXPECT_EQ(static_cast<size_t>(3), reference->findIgnoringASCIICase(empty.get(), 3));
+ EXPECT_EQ(static_cast<size_t>(7), reference->findIgnoringASCIICase(empty.get(), 7));
+ EXPECT_EQ(static_cast<size_t>(7), reference->findIgnoringASCIICase(empty.get(), 8));
+ EXPECT_EQ(static_cast<size_t>(7), reference->findIgnoringASCIICase(empty.get(), 42));
+ EXPECT_EQ(static_cast<size_t>(7), reference->findIgnoringASCIICase(empty.get(), std::numeric_limits<unsigned>::max()));
+}
+
+TEST(WTF, StringImplFindIgnoringASCIICaseWithPatternLongerThanReference)
+{
+ RefPtr<StringImpl> reference = stringFromUTF8("ABCÉEFG");
+ RefPtr<StringImpl> pattern = stringFromUTF8("XABCÉEFG");
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference->findIgnoringASCIICase(pattern.get()));
+ EXPECT_EQ(static_cast<size_t>(1), pattern->findIgnoringASCIICase(reference.get()));
+}
+
+TEST(WTF, StringImplStartsWithIgnoringASCIICaseBasic)
+{
+ RefPtr<StringImpl> reference = stringFromUTF8("aBcéX");
+ RefPtr<StringImpl> referenceEquivalent = stringFromUTF8("AbCéx");
+
+ // Identity.
+ ASSERT_TRUE(reference->startsWithIgnoringASCIICase(reference.get()));
+ ASSERT_TRUE(reference->startsWithIgnoringASCIICase(*reference.get()));
+ ASSERT_TRUE(reference->startsWithIgnoringASCIICase(referenceEquivalent.get()));
+ ASSERT_TRUE(reference->startsWithIgnoringASCIICase(*referenceEquivalent.get()));
+ ASSERT_TRUE(referenceEquivalent->startsWithIgnoringASCIICase(reference.get()));
+ ASSERT_TRUE(referenceEquivalent->startsWithIgnoringASCIICase(*reference.get()));
+ ASSERT_TRUE(referenceEquivalent->startsWithIgnoringASCIICase(referenceEquivalent.get()));
+ ASSERT_TRUE(referenceEquivalent->startsWithIgnoringASCIICase(*referenceEquivalent.get()));
+
+ // Proper prefixes.
+ RefPtr<StringImpl> aLower = StringImpl::createFromLiteral("a");
+ ASSERT_TRUE(reference->startsWithIgnoringASCIICase(aLower.get()));
+ ASSERT_TRUE(reference->startsWithIgnoringASCIICase(*aLower.get()));
+ RefPtr<StringImpl> aUpper = StringImpl::createFromLiteral("A");
+ ASSERT_TRUE(reference->startsWithIgnoringASCIICase(aUpper.get()));
+ ASSERT_TRUE(reference->startsWithIgnoringASCIICase(*aUpper.get()));
+
+ RefPtr<StringImpl> abcLower = StringImpl::createFromLiteral("abc");
+ ASSERT_TRUE(reference->startsWithIgnoringASCIICase(abcLower.get()));
+ ASSERT_TRUE(reference->startsWithIgnoringASCIICase(*abcLower.get()));
+ RefPtr<StringImpl> abcUpper = StringImpl::createFromLiteral("ABC");
+ ASSERT_TRUE(reference->startsWithIgnoringASCIICase(abcUpper.get()));
+ ASSERT_TRUE(reference->startsWithIgnoringASCIICase(*abcUpper.get()));
+
+ RefPtr<StringImpl> abcAccentLower = stringFromUTF8("abcé");
+ ASSERT_TRUE(reference->startsWithIgnoringASCIICase(abcAccentLower.get()));
+ ASSERT_TRUE(reference->startsWithIgnoringASCIICase(*abcAccentLower.get()));
+ RefPtr<StringImpl> abcAccentUpper = stringFromUTF8("ABCé");
+ ASSERT_TRUE(reference->startsWithIgnoringASCIICase(abcAccentUpper.get()));
+ ASSERT_TRUE(reference->startsWithIgnoringASCIICase(*abcAccentUpper.get()));
+
+ // Negative cases.
+ RefPtr<StringImpl> differentFirstChar = stringFromUTF8("bBcéX");
+ RefPtr<StringImpl> differentFirstCharProperPrefix = stringFromUTF8("CBcé");
+ ASSERT_FALSE(reference->startsWithIgnoringASCIICase(differentFirstChar.get()));
+ ASSERT_FALSE(reference->startsWithIgnoringASCIICase(*differentFirstChar.get()));
+ ASSERT_FALSE(reference->startsWithIgnoringASCIICase(differentFirstCharProperPrefix.get()));
+ ASSERT_FALSE(reference->startsWithIgnoringASCIICase(*differentFirstCharProperPrefix.get()));
+
+ RefPtr<StringImpl> uppercaseAccent = stringFromUTF8("aBcÉX");
+ RefPtr<StringImpl> uppercaseAccentProperPrefix = stringFromUTF8("aBcÉX");
+ ASSERT_FALSE(reference->startsWithIgnoringASCIICase(uppercaseAccent.get()));
+ ASSERT_FALSE(reference->startsWithIgnoringASCIICase(*uppercaseAccent.get()));
+ ASSERT_FALSE(reference->startsWithIgnoringASCIICase(uppercaseAccentProperPrefix.get()));
+ ASSERT_FALSE(reference->startsWithIgnoringASCIICase(*uppercaseAccentProperPrefix.get()));
+}
+
+TEST(WTF, StringImplStartsWithIgnoringASCIICaseWithNull)
+{
+ RefPtr<StringImpl> reference = StringImpl::createFromLiteral("aBcDeFG");
+ ASSERT_FALSE(reference->startsWithIgnoringASCIICase(nullptr));
+
+ RefPtr<StringImpl> empty = StringImpl::create(reinterpret_cast<const LChar*>(""));
+ ASSERT_FALSE(empty->startsWithIgnoringASCIICase(nullptr));
+}
+
+TEST(WTF, StringImplStartsWithIgnoringASCIICaseWithEmpty)
+{
+ RefPtr<StringImpl> reference = StringImpl::createFromLiteral("aBcDeFG");
+ RefPtr<StringImpl> empty = StringImpl::create(reinterpret_cast<const LChar*>(""));
+ ASSERT_TRUE(reference->startsWithIgnoringASCIICase(empty.get()));
+ ASSERT_TRUE(reference->startsWithIgnoringASCIICase(*empty.get()));
+ ASSERT_TRUE(empty->startsWithIgnoringASCIICase(empty.get()));
+ ASSERT_TRUE(empty->startsWithIgnoringASCIICase(*empty.get()));
+ ASSERT_FALSE(empty->startsWithIgnoringASCIICase(reference.get()));
+ ASSERT_FALSE(empty->startsWithIgnoringASCIICase(*reference.get()));
+}
+
+TEST(WTF, StringImplEndsWithIgnoringASCIICaseBasic)
+{
+ RefPtr<StringImpl> reference = stringFromUTF8("XÉCbA");
+ RefPtr<StringImpl> referenceEquivalent = stringFromUTF8("xÉcBa");
+
+ // Identity.
+ ASSERT_TRUE(reference->endsWithIgnoringASCIICase(reference.get()));
+ ASSERT_TRUE(reference->endsWithIgnoringASCIICase(*reference.get()));
+ ASSERT_TRUE(reference->endsWithIgnoringASCIICase(referenceEquivalent.get()));
+ ASSERT_TRUE(reference->endsWithIgnoringASCIICase(*referenceEquivalent.get()));
+ ASSERT_TRUE(referenceEquivalent->endsWithIgnoringASCIICase(reference.get()));
+ ASSERT_TRUE(referenceEquivalent->endsWithIgnoringASCIICase(*reference.get()));
+ ASSERT_TRUE(referenceEquivalent->endsWithIgnoringASCIICase(referenceEquivalent.get()));
+ ASSERT_TRUE(referenceEquivalent->endsWithIgnoringASCIICase(*referenceEquivalent.get()));
+
+ // Proper suffixes.
+ RefPtr<StringImpl> aLower = StringImpl::createFromLiteral("a");
+ ASSERT_TRUE(reference->endsWithIgnoringASCIICase(aLower.get()));
+ ASSERT_TRUE(reference->endsWithIgnoringASCIICase(*aLower.get()));
+ RefPtr<StringImpl> aUpper = StringImpl::createFromLiteral("a");
+ ASSERT_TRUE(reference->endsWithIgnoringASCIICase(aUpper.get()));
+ ASSERT_TRUE(reference->endsWithIgnoringASCIICase(*aUpper.get()));
+
+ RefPtr<StringImpl> abcLower = StringImpl::createFromLiteral("cba");
+ ASSERT_TRUE(reference->endsWithIgnoringASCIICase(abcLower.get()));
+ ASSERT_TRUE(reference->endsWithIgnoringASCIICase(*abcLower.get()));
+ RefPtr<StringImpl> abcUpper = StringImpl::createFromLiteral("CBA");
+ ASSERT_TRUE(reference->endsWithIgnoringASCIICase(abcUpper.get()));
+ ASSERT_TRUE(reference->endsWithIgnoringASCIICase(*abcUpper.get()));
+
+ RefPtr<StringImpl> abcAccentLower = stringFromUTF8("Écba");
+ ASSERT_TRUE(reference->endsWithIgnoringASCIICase(abcAccentLower.get()));
+ ASSERT_TRUE(reference->endsWithIgnoringASCIICase(*abcAccentLower.get()));
+ RefPtr<StringImpl> abcAccentUpper = stringFromUTF8("ÉCBA");
+ ASSERT_TRUE(reference->endsWithIgnoringASCIICase(abcAccentUpper.get()));
+ ASSERT_TRUE(reference->endsWithIgnoringASCIICase(*abcAccentUpper.get()));
+
+ // Negative cases.
+ RefPtr<StringImpl> differentLastChar = stringFromUTF8("XÉCbB");
+ RefPtr<StringImpl> differentLastCharProperSuffix = stringFromUTF8("ÉCbb");
+ ASSERT_FALSE(reference->endsWithIgnoringASCIICase(differentLastChar.get()));
+ ASSERT_FALSE(reference->endsWithIgnoringASCIICase(*differentLastChar.get()));
+ ASSERT_FALSE(reference->endsWithIgnoringASCIICase(differentLastCharProperSuffix.get()));
+ ASSERT_FALSE(reference->endsWithIgnoringASCIICase(*differentLastCharProperSuffix.get()));
+
+ RefPtr<StringImpl> lowercaseAccent = stringFromUTF8("aBcéX");
+ RefPtr<StringImpl> loweraseAccentProperSuffix = stringFromUTF8("aBcéX");
+ ASSERT_FALSE(reference->endsWithIgnoringASCIICase(lowercaseAccent.get()));
+ ASSERT_FALSE(reference->endsWithIgnoringASCIICase(*lowercaseAccent.get()));
+ ASSERT_FALSE(reference->endsWithIgnoringASCIICase(loweraseAccentProperSuffix.get()));
+ ASSERT_FALSE(reference->endsWithIgnoringASCIICase(*loweraseAccentProperSuffix.get()));
+}
+
+TEST(WTF, StringImplEndsWithIgnoringASCIICaseWithNull)
+{
+ RefPtr<StringImpl> reference = StringImpl::createFromLiteral("aBcDeFG");
+ ASSERT_FALSE(reference->endsWithIgnoringASCIICase(nullptr));
+
+ RefPtr<StringImpl> empty = StringImpl::create(reinterpret_cast<const LChar*>(""));
+ ASSERT_FALSE(empty->endsWithIgnoringASCIICase(nullptr));
+}
+
+TEST(WTF, StringImplEndsWithIgnoringASCIICaseWithEmpty)
+{
+ RefPtr<StringImpl> reference = StringImpl::createFromLiteral("aBcDeFG");
+ RefPtr<StringImpl> empty = StringImpl::create(reinterpret_cast<const LChar*>(""));
+ ASSERT_TRUE(reference->endsWithIgnoringASCIICase(empty.get()));
+ ASSERT_TRUE(reference->endsWithIgnoringASCIICase(*empty.get()));
+ ASSERT_TRUE(empty->endsWithIgnoringASCIICase(empty.get()));
+ ASSERT_TRUE(empty->endsWithIgnoringASCIICase(*empty.get()));
+ ASSERT_FALSE(empty->endsWithIgnoringASCIICase(reference.get()));
+ ASSERT_FALSE(empty->endsWithIgnoringASCIICase(*reference.get()));
+}
+
+TEST(WTF, StringImplCreateSymbolEmpty)
+{
+ RefPtr<StringImpl> reference = StringImpl::createSymbolEmpty();
+ ASSERT_TRUE(reference->isSymbol());
+ ASSERT_FALSE(reference->isAtomic());
+ ASSERT_EQ(0u, reference->length());
+ ASSERT_TRUE(equal(reference.get(), ""));
+}
+
+TEST(WTF, StringImplCreateSymbol)
+{
+ RefPtr<StringImpl> original = stringFromUTF8("original");
+ RefPtr<StringImpl> reference = StringImpl::createSymbol(original);
+ ASSERT_TRUE(reference->isSymbol());
+ ASSERT_FALSE(reference->isAtomic());
+ ASSERT_FALSE(original->isSymbol());
+ ASSERT_FALSE(original->isAtomic());
+ ASSERT_EQ(original->length(), reference->length());
+ ASSERT_TRUE(equal(reference.get(), "original"));
+}
+
+TEST(WTF, StringImplSymbolToAtomicString)
+{
+ RefPtr<StringImpl> original = stringFromUTF8("original");
+ RefPtr<StringImpl> reference = StringImpl::createSymbol(original);
+ ASSERT_TRUE(reference->isSymbol());
+ ASSERT_FALSE(reference->isAtomic());
+
+ RefPtr<StringImpl> atomic = AtomicStringImpl::add(reference.get());
+ ASSERT_TRUE(atomic->isAtomic());
+ ASSERT_FALSE(atomic->isSymbol());
+ ASSERT_TRUE(reference->isSymbol());
+ ASSERT_FALSE(reference->isAtomic());
+}
+
+TEST(WTF, StringImplSymbolEmptyToAtomicString)
+{
+ RefPtr<StringImpl> reference = StringImpl::createSymbolEmpty();
+ ASSERT_TRUE(reference->isSymbol());
+ ASSERT_FALSE(reference->isAtomic());
+
+ RefPtr<StringImpl> atomic = AtomicStringImpl::add(reference.get());
+ ASSERT_TRUE(atomic->isAtomic());
+ ASSERT_FALSE(atomic->isSymbol());
+ ASSERT_TRUE(reference->isSymbol());
+ ASSERT_FALSE(reference->isAtomic());
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/StringOperators.cpp b/Tools/TestWebKitAPI/Tests/WTF/StringOperators.cpp
new file mode 100644
index 000000000..149b85b21
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/StringOperators.cpp
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2011 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"
+
+#define WTF_STRINGTYPEADAPTER_COPIED_WTF_STRING() (++wtfStringCopyCount)
+
+static int wtfStringCopyCount;
+
+#include <wtf/text/WTFString.h>
+
+namespace TestWebKitAPI {
+
+#define EXPECT_N_WTF_STRING_COPIES(count, expr) \
+ do { \
+ wtfStringCopyCount = 0; \
+ String __testString = expr; \
+ (void)__testString; \
+ EXPECT_EQ(count, wtfStringCopyCount) << #expr; \
+ } while (false)
+
+TEST(WTF, StringOperators)
+{
+ String string("String");
+ AtomicString atomicString("AtomicString");
+ ASCIILiteral literal("ASCIILiteral");
+
+ EXPECT_EQ(0, wtfStringCopyCount);
+
+ EXPECT_N_WTF_STRING_COPIES(2, string + string);
+ EXPECT_N_WTF_STRING_COPIES(2, string + atomicString);
+ EXPECT_N_WTF_STRING_COPIES(2, atomicString + string);
+ EXPECT_N_WTF_STRING_COPIES(2, atomicString + atomicString);
+
+ EXPECT_N_WTF_STRING_COPIES(1, "C string" + string);
+ EXPECT_N_WTF_STRING_COPIES(1, string + "C string");
+ EXPECT_N_WTF_STRING_COPIES(1, "C string" + atomicString);
+ EXPECT_N_WTF_STRING_COPIES(1, atomicString + "C string");
+
+ EXPECT_N_WTF_STRING_COPIES(1, literal + string);
+ EXPECT_N_WTF_STRING_COPIES(1, string + literal);
+ EXPECT_N_WTF_STRING_COPIES(1, literal + atomicString);
+ EXPECT_N_WTF_STRING_COPIES(1, atomicString + literal);
+
+ EXPECT_N_WTF_STRING_COPIES(2, "C string" + string + "C string" + string);
+ EXPECT_N_WTF_STRING_COPIES(2, "C string" + (string + "C string" + string));
+ EXPECT_N_WTF_STRING_COPIES(2, ("C string" + string) + ("C string" + string));
+ EXPECT_N_WTF_STRING_COPIES(2, string + "C string" + string + "C string");
+ EXPECT_N_WTF_STRING_COPIES(2, string + ("C string" + string + "C string"));
+ EXPECT_N_WTF_STRING_COPIES(2, (string + "C string") + (string + "C string"));
+
+ EXPECT_N_WTF_STRING_COPIES(2, literal + string + literal + string);
+ EXPECT_N_WTF_STRING_COPIES(2, literal + (string + literal + string));
+ EXPECT_N_WTF_STRING_COPIES(2, (literal + string) + (literal + string));
+ EXPECT_N_WTF_STRING_COPIES(2, string + literal + string + literal);
+ EXPECT_N_WTF_STRING_COPIES(2, string + (literal + string + literal));
+ EXPECT_N_WTF_STRING_COPIES(2, (string + literal) + (string + literal));
+
+ EXPECT_N_WTF_STRING_COPIES(2, literal + string + "C string" + string);
+ EXPECT_N_WTF_STRING_COPIES(2, literal + (string + "C string" + string));
+ EXPECT_N_WTF_STRING_COPIES(2, (literal + string) + ("C string" + string));
+ EXPECT_N_WTF_STRING_COPIES(2, "C string" + string + literal + string);
+ EXPECT_N_WTF_STRING_COPIES(2, "C string" + (string + literal + string));
+ EXPECT_N_WTF_STRING_COPIES(2, ("C string" + string) + (literal + string));
+
+ EXPECT_N_WTF_STRING_COPIES(2, literal + atomicString + "C string" + atomicString);
+ EXPECT_N_WTF_STRING_COPIES(2, literal + (atomicString + "C string" + atomicString));
+ EXPECT_N_WTF_STRING_COPIES(2, (literal + atomicString) + ("C string" + atomicString));
+ EXPECT_N_WTF_STRING_COPIES(2, "C string" + atomicString + literal + atomicString);
+ EXPECT_N_WTF_STRING_COPIES(2, "C string" + (atomicString + literal + atomicString));
+ EXPECT_N_WTF_STRING_COPIES(2, ("C string" + atomicString) + (literal + atomicString));
+
+ EXPECT_N_WTF_STRING_COPIES(2, literal + atomicString + "C string" + string);
+ EXPECT_N_WTF_STRING_COPIES(2, literal + (atomicString + "C string" + string));
+ EXPECT_N_WTF_STRING_COPIES(2, (literal + atomicString) + ("C string" + string));
+ EXPECT_N_WTF_STRING_COPIES(2, "C string" + atomicString + literal + string);
+ EXPECT_N_WTF_STRING_COPIES(2, "C string" + (atomicString + literal + string));
+ EXPECT_N_WTF_STRING_COPIES(2, ("C string" + atomicString) + (literal + string));
+
+ EXPECT_N_WTF_STRING_COPIES(2, literal + string + "C string" + atomicString);
+ EXPECT_N_WTF_STRING_COPIES(2, literal + (string + "C string" + atomicString));
+ EXPECT_N_WTF_STRING_COPIES(2, (literal + string) + ("C string" + atomicString));
+ EXPECT_N_WTF_STRING_COPIES(2, "C string" + string + literal + atomicString);
+ EXPECT_N_WTF_STRING_COPIES(2, "C string" + (string + literal + atomicString));
+ EXPECT_N_WTF_STRING_COPIES(2, ("C string" + string) + (literal + atomicString));
+
+ EXPECT_N_WTF_STRING_COPIES(2, "C string" + atomicString + "C string" + atomicString);
+ EXPECT_N_WTF_STRING_COPIES(2, "C string" + (atomicString + "C string" + atomicString));
+ EXPECT_N_WTF_STRING_COPIES(2, ("C string" + atomicString) + ("C string" + atomicString));
+ EXPECT_N_WTF_STRING_COPIES(2, atomicString + "C string" + atomicString + "C string");
+ EXPECT_N_WTF_STRING_COPIES(2, atomicString + ("C string" + atomicString + "C string"));
+ EXPECT_N_WTF_STRING_COPIES(2, (atomicString + "C string") + (atomicString + "C string"));
+
+ EXPECT_N_WTF_STRING_COPIES(2, literal + atomicString + literal + atomicString);
+ EXPECT_N_WTF_STRING_COPIES(2, literal + (atomicString + literal + atomicString));
+ EXPECT_N_WTF_STRING_COPIES(2, (literal + atomicString) + (literal + atomicString));
+ EXPECT_N_WTF_STRING_COPIES(2, atomicString + literal + atomicString + literal);
+ EXPECT_N_WTF_STRING_COPIES(2, atomicString + (literal + atomicString + literal));
+ EXPECT_N_WTF_STRING_COPIES(2, (atomicString + literal) + (atomicString + literal));
+
+ EXPECT_N_WTF_STRING_COPIES(2, "C string" + string + "C string" + atomicString);
+ EXPECT_N_WTF_STRING_COPIES(2, "C string" + (string + "C string" + atomicString));
+ EXPECT_N_WTF_STRING_COPIES(2, ("C string" + string) + ("C string" + atomicString));
+ EXPECT_N_WTF_STRING_COPIES(2, string + "C string" + atomicString + "C string");
+ EXPECT_N_WTF_STRING_COPIES(2, string + ("C string" + atomicString + "C string"));
+ EXPECT_N_WTF_STRING_COPIES(2, (string + "C string") + (atomicString + "C string"));
+
+ EXPECT_N_WTF_STRING_COPIES(2, literal + string + literal + atomicString);
+ EXPECT_N_WTF_STRING_COPIES(2, literal + (string + literal + atomicString));
+ EXPECT_N_WTF_STRING_COPIES(2, (literal + string) + (literal + atomicString));
+ EXPECT_N_WTF_STRING_COPIES(2, string + literal + atomicString + literal);
+ EXPECT_N_WTF_STRING_COPIES(2, string + (literal + atomicString + literal));
+ EXPECT_N_WTF_STRING_COPIES(2, (string + literal) + (atomicString + literal));
+
+ EXPECT_N_WTF_STRING_COPIES(2, "C string" + atomicString + "C string" + string);
+ EXPECT_N_WTF_STRING_COPIES(2, "C string" + (atomicString + "C string" + string));
+ EXPECT_N_WTF_STRING_COPIES(2, ("C string" + atomicString) + ("C string" + string));
+ EXPECT_N_WTF_STRING_COPIES(2, atomicString + "C string" + string + "C string");
+ EXPECT_N_WTF_STRING_COPIES(2, atomicString + ("C string" + string + "C string"));
+ EXPECT_N_WTF_STRING_COPIES(2, (atomicString + "C string") + (string + "C string"));
+
+ EXPECT_N_WTF_STRING_COPIES(2, literal + atomicString + literal + string);
+ EXPECT_N_WTF_STRING_COPIES(2, literal + (atomicString + literal + string));
+ EXPECT_N_WTF_STRING_COPIES(2, (literal + atomicString) + (literal + string));
+ EXPECT_N_WTF_STRING_COPIES(2, atomicString + literal + string + literal);
+ EXPECT_N_WTF_STRING_COPIES(2, atomicString + (literal + string + literal));
+ EXPECT_N_WTF_STRING_COPIES(2, (atomicString + literal) + (string + literal));
+
+#if COMPILER(MSVC)
+ EXPECT_N_WTF_STRING_COPIES(1, L"wide string" + string);
+ EXPECT_N_WTF_STRING_COPIES(1, string + L"wide string");
+ EXPECT_N_WTF_STRING_COPIES(1, L"wide string" + atomicString);
+ EXPECT_N_WTF_STRING_COPIES(1, atomicString + L"wide string");
+
+ EXPECT_N_WTF_STRING_COPIES(2, L"wide string" + string + L"wide string" + string);
+ EXPECT_N_WTF_STRING_COPIES(2, L"wide string" + (string + L"wide string" + string));
+ EXPECT_N_WTF_STRING_COPIES(2, (L"wide string" + string) + (L"wide string" + string));
+ EXPECT_N_WTF_STRING_COPIES(2, string + L"wide string" + string + L"wide string");
+ EXPECT_N_WTF_STRING_COPIES(2, string + (L"wide string" + string + L"wide string"));
+ EXPECT_N_WTF_STRING_COPIES(2, (string + L"wide string") + (string + L"wide string"));
+
+ EXPECT_N_WTF_STRING_COPIES(2, L"wide string" + atomicString + L"wide string" + atomicString);
+ EXPECT_N_WTF_STRING_COPIES(2, L"wide string" + (atomicString + L"wide string" + atomicString));
+ EXPECT_N_WTF_STRING_COPIES(2, (L"wide string" + atomicString) + (L"wide string" + atomicString));
+ EXPECT_N_WTF_STRING_COPIES(2, atomicString + L"wide string" + atomicString + L"wide string");
+ EXPECT_N_WTF_STRING_COPIES(2, atomicString + (L"wide string" + atomicString + L"wide string"));
+ EXPECT_N_WTF_STRING_COPIES(2, (atomicString + L"wide string") + (atomicString + L"wide string"));
+
+ EXPECT_N_WTF_STRING_COPIES(2, L"wide string" + string + L"wide string" + atomicString);
+ EXPECT_N_WTF_STRING_COPIES(2, L"wide string" + (string + L"wide string" + atomicString));
+ EXPECT_N_WTF_STRING_COPIES(2, (L"wide string" + string) + (L"wide string" + atomicString));
+ EXPECT_N_WTF_STRING_COPIES(2, string + L"wide string" + atomicString + L"wide string");
+ EXPECT_N_WTF_STRING_COPIES(2, string + (L"wide string" + atomicString + L"wide string"));
+ EXPECT_N_WTF_STRING_COPIES(2, (string + L"wide string") + (atomicString + L"wide string"));
+
+ EXPECT_N_WTF_STRING_COPIES(2, L"wide string" + atomicString + L"wide string" + string);
+ EXPECT_N_WTF_STRING_COPIES(2, L"wide string" + (atomicString + L"wide string" + string));
+ EXPECT_N_WTF_STRING_COPIES(2, (L"wide string" + atomicString) + (L"wide string" + string));
+ EXPECT_N_WTF_STRING_COPIES(2, atomicString + L"wide string" + string + L"wide string");
+ EXPECT_N_WTF_STRING_COPIES(2, atomicString + (L"wide string" + string + L"wide string"));
+ EXPECT_N_WTF_STRING_COPIES(2, (atomicString + L"wide string") + (string + L"wide string"));
+#endif
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/StringView.cpp b/Tools/TestWebKitAPI/Tests/WTF/StringView.cpp
new file mode 100644
index 000000000..408cc642e
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/StringView.cpp
@@ -0,0 +1,736 @@
+/*
+ * Copyright (C) 2014 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 <wtf/text/StringBuilder.h>
+#include <wtf/text/StringView.h>
+
+namespace TestWebKitAPI {
+
+TEST(WTF, StringViewEmptyVsNull)
+{
+ StringView nullView;
+ EXPECT_TRUE(nullView.isNull());
+ EXPECT_TRUE(nullView.isEmpty());
+
+ // Test in a boolean context to test operator bool().
+ if (nullView)
+ FAIL();
+ else
+ SUCCEED();
+
+ if (!nullView)
+ SUCCEED();
+ else
+ FAIL();
+
+ StringView emptyView = StringView::empty();
+ EXPECT_FALSE(emptyView.isNull());
+ EXPECT_TRUE(emptyView.isEmpty());
+
+ // Test in a boolean context to test operator bool().
+ if (emptyView)
+ SUCCEED();
+ else
+ FAIL();
+
+ if (!emptyView)
+ FAIL();
+ else
+ SUCCEED();
+
+ StringView viewWithCharacters(String("hello"));
+ EXPECT_FALSE(viewWithCharacters.isNull());
+ EXPECT_FALSE(viewWithCharacters.isEmpty());
+
+ // Test in a boolean context to test operator bool().
+ if (viewWithCharacters)
+ SUCCEED();
+ else
+ FAIL();
+
+ if (!viewWithCharacters)
+ FAIL();
+ else
+ SUCCEED();
+}
+
+bool compareLoopIterations(StringView::CodePoints codePoints, std::vector<UChar32> expected)
+{
+ std::vector<UChar32> actual;
+ for (auto codePoint : codePoints)
+ actual.push_back(codePoint);
+ return actual == expected;
+}
+
+static bool compareLoopIterations(StringView::CodeUnits codeUnits, std::vector<UChar> expected)
+{
+ std::vector<UChar> actual;
+ for (auto codeUnit : codeUnits)
+ actual.push_back(codeUnit);
+ return actual == expected;
+}
+
+static void build(StringBuilder& builder, std::vector<UChar> input)
+{
+ builder.clear();
+ for (auto codeUnit : input)
+ builder.append(codeUnit);
+}
+
+TEST(WTF, StringViewIterators)
+{
+ compareLoopIterations(StringView().codePoints(), { });
+ compareLoopIterations(StringView().codeUnits(), { });
+
+ compareLoopIterations(StringView::empty().codePoints(), { });
+ compareLoopIterations(StringView::empty().codeUnits(), { });
+
+ compareLoopIterations(StringView(String("hello")).codePoints(), {'h', 'e', 'l', 'l', 'o'});
+ compareLoopIterations(StringView(String("hello")).codeUnits(), {'h', 'e', 'l', 'l', 'o'});
+
+ StringBuilder b;
+ build(b, {0xD800, 0xDD55}); // Surrogates for unicode code point U+10155
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codePoints(), {0x10155}));
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codeUnits(), {0xD800, 0xDD55}));
+
+ build(b, {0xD800}); // Leading surrogate only
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codePoints(), {0xD800}));
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codeUnits(), {0xD800}));
+
+ build(b, {0xD800, 0xD801}); // Two leading surrogates
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codePoints(), {0xD800, 0xD801}));
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codeUnits(), {0xD800, 0xD801}));
+
+ build(b, {0xDD55}); // Trailing surrogate only
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codePoints(), {0xDD55}));
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codeUnits(), {0xDD55}));
+
+ build(b, {0xD800, 'h'}); // Leading surrogate followed by non-surrogate
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codePoints(), {0xD800, 'h'}));
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codeUnits(), {0xD800, 'h'}));
+
+ build(b, {0x0306}); // "COMBINING BREVE"
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codePoints(), {0x0306}));
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codeUnits(), {0x0306}));
+
+ build(b, {0x0306, 0xD800, 0xDD55, 'h', 'e', 'l', 'o'}); // Mix of single code unit and multi code unit code points
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codePoints(), {0x0306, 0x10155, 'h', 'e', 'l', 'o'}));
+ EXPECT_TRUE(compareLoopIterations(StringView(b.toString()).codeUnits(), {0x0306, 0xD800, 0xDD55, 'h', 'e', 'l', 'o'}));
+}
+
+TEST(WTF, StringViewEqualIgnoringASCIICaseBasic)
+{
+ RefPtr<StringImpl> a = StringImpl::createFromLiteral("aBcDeFG");
+ RefPtr<StringImpl> b = StringImpl::createFromLiteral("ABCDEFG");
+ RefPtr<StringImpl> c = StringImpl::createFromLiteral("abcdefg");
+ const char d[] = "aBcDeFG";
+ RefPtr<StringImpl> empty = StringImpl::create(reinterpret_cast<const LChar*>(""));
+ RefPtr<StringImpl> shorter = StringImpl::createFromLiteral("abcdef");
+ RefPtr<StringImpl> different = StringImpl::createFromLiteral("abcrefg");
+
+ StringView stringViewA(*a.get());
+ StringView stringViewB(*b.get());
+ StringView stringViewC(*c.get());
+ StringView emptyStringView(*empty.get());
+ StringView shorterStringView(*shorter.get());
+ StringView differentStringView(*different.get());
+
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewA, stringViewB));
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewB, stringViewC));
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewB, stringViewC));
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewA, d));
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewB, d));
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewC, d));
+
+ // Identity.
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewA, stringViewA));
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewB, stringViewB));
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewC, stringViewC));
+
+ // Transitivity.
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewA, stringViewB));
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewB, stringViewC));
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewA, stringViewC));
+
+ // Negative cases.
+ ASSERT_FALSE(equalIgnoringASCIICase(stringViewA, emptyStringView));
+ ASSERT_FALSE(equalIgnoringASCIICase(stringViewB, emptyStringView));
+ ASSERT_FALSE(equalIgnoringASCIICase(stringViewC, emptyStringView));
+ ASSERT_FALSE(equalIgnoringASCIICase(stringViewA, shorterStringView));
+ ASSERT_FALSE(equalIgnoringASCIICase(stringViewB, shorterStringView));
+ ASSERT_FALSE(equalIgnoringASCIICase(stringViewC, shorterStringView));
+ ASSERT_FALSE(equalIgnoringASCIICase(stringViewA, differentStringView));
+ ASSERT_FALSE(equalIgnoringASCIICase(stringViewB, differentStringView));
+ ASSERT_FALSE(equalIgnoringASCIICase(stringViewC, differentStringView));
+ ASSERT_FALSE(equalIgnoringASCIICase(emptyStringView, d));
+ ASSERT_FALSE(equalIgnoringASCIICase(shorterStringView, d));
+ ASSERT_FALSE(equalIgnoringASCIICase(differentStringView, d));
+}
+
+TEST(WTF, StringViewEqualIgnoringASCIICaseWithEmpty)
+{
+ RefPtr<StringImpl> a = StringImpl::create(reinterpret_cast<const LChar*>(""));
+ RefPtr<StringImpl> b = StringImpl::create(reinterpret_cast<const LChar*>(""));
+ StringView stringViewA(*a.get());
+ StringView stringViewB(*b.get());
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewA, stringViewB));
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewB, stringViewA));
+}
+
+TEST(WTF, StringViewEqualIgnoringASCIICaseWithLatin1Characters)
+{
+ RefPtr<StringImpl> a = StringImpl::create(reinterpret_cast<const LChar*>("aBcéeFG"));
+ RefPtr<StringImpl> b = StringImpl::create(reinterpret_cast<const LChar*>("ABCÉEFG"));
+ RefPtr<StringImpl> c = StringImpl::create(reinterpret_cast<const LChar*>("ABCéEFG"));
+ RefPtr<StringImpl> d = StringImpl::create(reinterpret_cast<const LChar*>("abcéefg"));
+ const char e[] = "aBcéeFG";
+ StringView stringViewA(*a.get());
+ StringView stringViewB(*b.get());
+ StringView stringViewC(*c.get());
+ StringView stringViewD(*d.get());
+
+ // Identity.
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewA, stringViewA));
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewB, stringViewB));
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewC, stringViewC));
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewD, stringViewD));
+
+ // All combination.
+ ASSERT_FALSE(equalIgnoringASCIICase(stringViewA, stringViewB));
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewA, stringViewC));
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewA, stringViewD));
+ ASSERT_FALSE(equalIgnoringASCIICase(stringViewB, stringViewC));
+ ASSERT_FALSE(equalIgnoringASCIICase(stringViewB, stringViewD));
+ ASSERT_TRUE(equalIgnoringASCIICase(stringViewC, stringViewD));
+ ASSERT_FALSE(equalIgnoringASCIICase(stringViewA, e));
+ ASSERT_FALSE(equalIgnoringASCIICase(stringViewB, e));
+ ASSERT_FALSE(equalIgnoringASCIICase(stringViewC, e));
+ ASSERT_FALSE(equalIgnoringASCIICase(stringViewD, e));
+}
+
+StringView stringViewFromLiteral(const char* characters)
+{
+ return StringView(reinterpret_cast<const LChar*>(characters), strlen(characters));
+}
+
+StringView stringViewFromUTF8(String &ref, const char* characters)
+{
+ ref = String::fromUTF8(characters);
+ return ref;
+}
+
+TEST(WTF, StringViewFindIgnoringASCIICaseBasic)
+{
+ String referenceAHolder;
+ StringView referenceA = stringViewFromUTF8(referenceAHolder, "aBcéeFG");
+ String referenceBHolder;
+ StringView referenceB = stringViewFromUTF8(referenceBHolder, "ABCÉEFG");
+
+ // Search the exact string.
+ EXPECT_EQ(static_cast<size_t>(0), referenceA.findIgnoringASCIICase(referenceA));
+ EXPECT_EQ(static_cast<size_t>(0), referenceB.findIgnoringASCIICase(referenceB));
+
+ // A and B are distinct by the non-ascii character é/É.
+ EXPECT_EQ(static_cast<size_t>(notFound), referenceA.findIgnoringASCIICase(referenceB));
+ EXPECT_EQ(static_cast<size_t>(notFound), referenceB.findIgnoringASCIICase(referenceA));
+
+ String tempStringHolder;
+ // Find the prefix.
+ EXPECT_EQ(static_cast<size_t>(0), referenceA.findIgnoringASCIICase(stringViewFromLiteral("a")));
+ EXPECT_EQ(static_cast<size_t>(0), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "abcé")));
+ EXPECT_EQ(static_cast<size_t>(0), referenceA.findIgnoringASCIICase(stringViewFromLiteral("A")));
+ EXPECT_EQ(static_cast<size_t>(0), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABCé")));
+ EXPECT_EQ(static_cast<size_t>(0), referenceB.findIgnoringASCIICase(stringViewFromLiteral("a")));
+ EXPECT_EQ(static_cast<size_t>(0), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "abcÉ")));
+ EXPECT_EQ(static_cast<size_t>(0), referenceB.findIgnoringASCIICase(stringViewFromLiteral("A")));
+ EXPECT_EQ(static_cast<size_t>(0), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABCÉ")));
+
+ // Not a prefix.
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromLiteral("x")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "accé")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "abcÉ")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromLiteral("X")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABDé")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABCÉ")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromLiteral("y")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "accÉ")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "abcé")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromLiteral("Y")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABdÉ")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABCé")));
+
+ // Find the infix.
+ EXPECT_EQ(static_cast<size_t>(2), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "cée")));
+ EXPECT_EQ(static_cast<size_t>(3), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ée")));
+ EXPECT_EQ(static_cast<size_t>(2), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "cé")));
+ EXPECT_EQ(static_cast<size_t>(2), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "c")));
+ EXPECT_EQ(static_cast<size_t>(3), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "é")));
+ EXPECT_EQ(static_cast<size_t>(2), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "Cée")));
+ EXPECT_EQ(static_cast<size_t>(3), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "éE")));
+ EXPECT_EQ(static_cast<size_t>(2), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "Cé")));
+ EXPECT_EQ(static_cast<size_t>(2), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "C")));
+
+ EXPECT_EQ(static_cast<size_t>(2), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "cÉe")));
+ EXPECT_EQ(static_cast<size_t>(3), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "Ée")));
+ EXPECT_EQ(static_cast<size_t>(2), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "cÉ")));
+ EXPECT_EQ(static_cast<size_t>(2), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "c")));
+ EXPECT_EQ(static_cast<size_t>(3), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "É")));
+ EXPECT_EQ(static_cast<size_t>(2), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "CÉe")));
+ EXPECT_EQ(static_cast<size_t>(3), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ÉE")));
+ EXPECT_EQ(static_cast<size_t>(2), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "CÉ")));
+ EXPECT_EQ(static_cast<size_t>(2), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "C")));
+
+ // Not an infix.
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "céd")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "Ée")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "bé")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "x")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "É")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "CÉe")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "éd")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "CÉ")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "Y")));
+
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "cée")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "Éc")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "cé")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "W")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "é")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "bÉe")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "éE")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "BÉ")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "z")));
+
+ // Find the suffix.
+ EXPECT_EQ(static_cast<size_t>(6), referenceA.findIgnoringASCIICase(stringViewFromLiteral("g")));
+ EXPECT_EQ(static_cast<size_t>(4), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "efg")));
+ EXPECT_EQ(static_cast<size_t>(3), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "éefg")));
+ EXPECT_EQ(static_cast<size_t>(6), referenceA.findIgnoringASCIICase(stringViewFromLiteral("G")));
+ EXPECT_EQ(static_cast<size_t>(4), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "EFG")));
+ EXPECT_EQ(static_cast<size_t>(3), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "éEFG")));
+
+ EXPECT_EQ(static_cast<size_t>(6), referenceB.findIgnoringASCIICase(stringViewFromLiteral("g")));
+ EXPECT_EQ(static_cast<size_t>(4), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "efg")));
+ EXPECT_EQ(static_cast<size_t>(3), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "Éefg")));
+ EXPECT_EQ(static_cast<size_t>(6), referenceB.findIgnoringASCIICase(stringViewFromLiteral("G")));
+ EXPECT_EQ(static_cast<size_t>(4), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "EFG")));
+ EXPECT_EQ(static_cast<size_t>(3), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ÉEFG")));
+
+ // Not a suffix.
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromLiteral("X")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "edg")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "Éefg")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromLiteral("w")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "dFG")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceA.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ÉEFG")));
+
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromLiteral("Z")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ffg")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "éefg")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromLiteral("r")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "EgG")));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), referenceB.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "éEFG")));
+}
+
+TEST(WTF, StringViewFindIgnoringASCIICaseWithValidOffset)
+{
+ String referenceHolder;
+ StringView reference = stringViewFromUTF8(referenceHolder, "ABCÉEFGaBcéeFG");
+ String tempStringHolder;
+
+ EXPECT_EQ(static_cast<size_t>(0), reference.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABC"), 0));
+ EXPECT_EQ(static_cast<size_t>(7), reference.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABC"), 1));
+ EXPECT_EQ(static_cast<size_t>(0), reference.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABCÉ"), 0));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABCÉ"), 1));
+ EXPECT_EQ(static_cast<size_t>(7), reference.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABCé"), 0));
+ EXPECT_EQ(static_cast<size_t>(7), reference.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABCé"), 1));
+}
+
+TEST(WTF, StringViewFindIgnoringASCIICaseWithInvalidOffset)
+{
+ String referenceHolder;
+ StringView reference = stringViewFromUTF8(referenceHolder, "ABCÉEFGaBcéeFG");
+ String tempStringHolder;
+
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABC"), 15));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABC"), 16));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABCÉ"), 17));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABCÉ"), 42));
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference.findIgnoringASCIICase(stringViewFromUTF8(tempStringHolder, "ABCÉ"), std::numeric_limits<unsigned>::max()));
+}
+
+TEST(WTF, StringViewFindIgnoringASCIICaseOnEmpty)
+{
+ String referenceHolder;
+ StringView reference = stringViewFromUTF8(referenceHolder, "ABCÉEFG");
+ StringView empty = stringViewFromLiteral("");
+ EXPECT_EQ(static_cast<size_t>(0), reference.findIgnoringASCIICase(empty));
+ EXPECT_EQ(static_cast<size_t>(0), reference.findIgnoringASCIICase(empty, 0));
+ EXPECT_EQ(static_cast<size_t>(3), reference.findIgnoringASCIICase(empty, 3));
+ EXPECT_EQ(static_cast<size_t>(7), reference.findIgnoringASCIICase(empty, 7));
+ EXPECT_EQ(static_cast<size_t>(7), reference.findIgnoringASCIICase(empty, 8));
+ EXPECT_EQ(static_cast<size_t>(7), reference.findIgnoringASCIICase(empty, 42));
+ EXPECT_EQ(static_cast<size_t>(7), reference.findIgnoringASCIICase(empty, std::numeric_limits<unsigned>::max()));
+}
+
+TEST(WTF, StringViewFindIgnoringASCIICaseWithPatternLongerThanReference)
+{
+ String referenceHolder;
+ StringView reference = stringViewFromUTF8(referenceHolder, "ABCÉEFG");
+ String patternHolder;
+ StringView pattern = stringViewFromUTF8(patternHolder, "ABCÉEFGA");
+
+ EXPECT_EQ(static_cast<size_t>(WTF::notFound), reference.findIgnoringASCIICase(pattern));
+ EXPECT_EQ(static_cast<size_t>(0), pattern.findIgnoringASCIICase(reference));
+}
+
+TEST(WTF, StringViewStartsWithBasic)
+{
+ StringView reference = stringViewFromLiteral("abcdefg");
+ String referenceUTF8Ref;
+ StringView referenceUTF8 = stringViewFromUTF8(referenceUTF8Ref, "àîûèô");
+
+ StringView oneLetterPrefix = stringViewFromLiteral("a");
+ StringView shortPrefix = stringViewFromLiteral("abc");
+ StringView longPrefix = stringViewFromLiteral("abcdef");
+ StringView upperCasePrefix = stringViewFromLiteral("ABC");
+ StringView empty = stringViewFromLiteral("");
+ StringView notPrefix = stringViewFromLiteral("bc");
+
+ String oneLetterPrefixUTF8Ref;
+ StringView oneLetterPrefixUTF8 = stringViewFromUTF8(oneLetterPrefixUTF8Ref, "à");
+ String shortPrefixUTF8Ref;
+ StringView shortPrefixUTF8 = stringViewFromUTF8(shortPrefixUTF8Ref, "àî");
+ String longPrefixUTF8Ref;
+ StringView longPrefixUTF8 = stringViewFromUTF8(longPrefixUTF8Ref, "àîûè");
+ String upperCasePrefixUTF8Ref;
+ StringView upperCasePrefixUTF8 = stringViewFromUTF8(upperCasePrefixUTF8Ref, "ÀÎ");
+ String notPrefixUTF8Ref;
+ StringView notPrefixUTF8 = stringViewFromUTF8(notPrefixUTF8Ref, "îû");
+
+ EXPECT_TRUE(reference.startsWith(reference));
+ EXPECT_TRUE(reference.startsWith(oneLetterPrefix));
+ EXPECT_TRUE(reference.startsWith(shortPrefix));
+ EXPECT_TRUE(reference.startsWith(longPrefix));
+ EXPECT_TRUE(reference.startsWith(empty));
+
+ EXPECT_TRUE(referenceUTF8.startsWith(referenceUTF8));
+ EXPECT_TRUE(referenceUTF8.startsWith(oneLetterPrefixUTF8));
+ EXPECT_TRUE(referenceUTF8.startsWith(shortPrefixUTF8));
+ EXPECT_TRUE(referenceUTF8.startsWith(longPrefixUTF8));
+ EXPECT_TRUE(referenceUTF8.startsWith(empty));
+
+ EXPECT_FALSE(reference.startsWith(notPrefix));
+ EXPECT_FALSE(reference.startsWith(upperCasePrefix));
+ EXPECT_FALSE(reference.startsWith(notPrefixUTF8));
+ EXPECT_FALSE(reference.startsWith(upperCasePrefixUTF8));
+ EXPECT_FALSE(referenceUTF8.startsWith(notPrefix));
+ EXPECT_FALSE(referenceUTF8.startsWith(upperCasePrefix));
+ EXPECT_FALSE(referenceUTF8.startsWith(notPrefixUTF8));
+ EXPECT_FALSE(referenceUTF8.startsWith(upperCasePrefixUTF8));
+}
+
+TEST(WTF, StringViewStartsWithEmpty)
+{
+ StringView a = stringViewFromLiteral("");
+ String refB;
+ StringView b = stringViewFromUTF8(refB, "");
+
+ EXPECT_TRUE(a.startsWith(a));
+ EXPECT_TRUE(a.startsWith(b));
+ EXPECT_TRUE(b.startsWith(a));
+ EXPECT_TRUE(b.startsWith(b));
+}
+
+TEST(WTF, StringViewStartsWithIgnoringASCIICaseBasic)
+{
+ StringView reference = stringViewFromLiteral("abcdefg");
+
+ String referenceUTF8Ref;
+ StringView referenceUTF8 = stringViewFromUTF8(referenceUTF8Ref, "àîûèô");
+
+ StringView oneLetterPrefix = stringViewFromLiteral("a");
+ StringView shortPrefix = stringViewFromLiteral("abc");
+ StringView longPrefix = stringViewFromLiteral("abcdef");
+ StringView upperCasePrefix = stringViewFromLiteral("ABC");
+ StringView mixedCasePrefix = stringViewFromLiteral("aBcDe");
+ StringView empty = stringViewFromLiteral("");
+ StringView notPrefix = stringViewFromLiteral("bc");
+
+ String oneLetterPrefixUTF8Ref;
+ StringView oneLetterPrefixUTF8 = stringViewFromUTF8(oneLetterPrefixUTF8Ref, "à");
+ String shortPrefixUTF8Ref;
+ StringView shortPrefixUTF8 = stringViewFromUTF8(shortPrefixUTF8Ref, "àî");
+ String longPrefixUTF8Ref;
+ StringView longPrefixUTF8 = stringViewFromUTF8(longPrefixUTF8Ref, "àîûè");
+ String upperCasePrefixUTF8Ref;
+ StringView upperCasePrefixUTF8 = stringViewFromUTF8(upperCasePrefixUTF8Ref, "ÀÎ");
+ String notPrefixUTF8Ref;
+ StringView notPrefixUTF8 = stringViewFromUTF8(notPrefixUTF8Ref, "îû");
+
+ EXPECT_TRUE(reference.startsWithIgnoringASCIICase(reference));
+ EXPECT_TRUE(reference.startsWithIgnoringASCIICase(oneLetterPrefix));
+ EXPECT_TRUE(reference.startsWithIgnoringASCIICase(shortPrefix));
+ EXPECT_TRUE(reference.startsWithIgnoringASCIICase(longPrefix));
+ EXPECT_TRUE(reference.startsWithIgnoringASCIICase(empty));
+ EXPECT_TRUE(reference.startsWithIgnoringASCIICase(upperCasePrefix));
+ EXPECT_TRUE(reference.startsWithIgnoringASCIICase(mixedCasePrefix));
+
+ EXPECT_TRUE(referenceUTF8.startsWithIgnoringASCIICase(referenceUTF8));
+ EXPECT_TRUE(referenceUTF8.startsWithIgnoringASCIICase(oneLetterPrefixUTF8));
+ EXPECT_TRUE(referenceUTF8.startsWithIgnoringASCIICase(shortPrefixUTF8));
+ EXPECT_TRUE(referenceUTF8.startsWithIgnoringASCIICase(longPrefixUTF8));
+ EXPECT_TRUE(referenceUTF8.startsWithIgnoringASCIICase(empty));
+
+ EXPECT_FALSE(reference.startsWithIgnoringASCIICase(notPrefix));
+ EXPECT_FALSE(reference.startsWithIgnoringASCIICase(notPrefixUTF8));
+ EXPECT_FALSE(reference.startsWithIgnoringASCIICase(upperCasePrefixUTF8));
+ EXPECT_FALSE(referenceUTF8.startsWithIgnoringASCIICase(notPrefix));
+ EXPECT_FALSE(referenceUTF8.startsWithIgnoringASCIICase(notPrefixUTF8));
+ EXPECT_FALSE(referenceUTF8.startsWithIgnoringASCIICase(upperCasePrefix));
+ EXPECT_FALSE(referenceUTF8.startsWithIgnoringASCIICase(upperCasePrefixUTF8));
+}
+
+
+TEST(WTF, StringViewStartsWithIgnoringASCIICaseEmpty)
+{
+ StringView a = stringViewFromLiteral("");
+ String refB;
+ StringView b = stringViewFromUTF8(refB, "");
+
+ EXPECT_TRUE(a.startsWithIgnoringASCIICase(a));
+ EXPECT_TRUE(a.startsWithIgnoringASCIICase(b));
+ EXPECT_TRUE(b.startsWithIgnoringASCIICase(a));
+ EXPECT_TRUE(b.startsWithIgnoringASCIICase(b));
+}
+
+TEST(WTF, StringViewStartsWithIgnoringASCIICaseWithLatin1Characters)
+{
+ StringView reference = stringViewFromLiteral("aBcéeFG");
+ String referenceUTF8Ref;
+ StringView referenceUTF8 = stringViewFromUTF8(referenceUTF8Ref, "aBcéeFG");
+
+ StringView a = stringViewFromLiteral("aBcéeF");
+ StringView b = stringViewFromLiteral("ABCéEF");
+ StringView c = stringViewFromLiteral("abcéef");
+ StringView d = stringViewFromLiteral("Abcéef");
+
+ String refE;
+ StringView e = stringViewFromUTF8(refE, "aBcéeF");
+ String refF;
+ StringView f = stringViewFromUTF8(refF, "ABCéEF");
+ String refG;
+ StringView g = stringViewFromUTF8(refG, "abcéef");
+ String refH;
+ StringView h = stringViewFromUTF8(refH, "Abcéef");
+
+ EXPECT_TRUE(reference.startsWithIgnoringASCIICase(a));
+ EXPECT_TRUE(reference.startsWithIgnoringASCIICase(b));
+ EXPECT_TRUE(reference.startsWithIgnoringASCIICase(c));
+ EXPECT_TRUE(reference.startsWithIgnoringASCIICase(d));
+
+ EXPECT_TRUE(referenceUTF8.startsWithIgnoringASCIICase(e));
+ EXPECT_TRUE(referenceUTF8.startsWithIgnoringASCIICase(f));
+ EXPECT_TRUE(referenceUTF8.startsWithIgnoringASCIICase(g));
+ EXPECT_TRUE(referenceUTF8.startsWithIgnoringASCIICase(h));
+
+ EXPECT_FALSE(reference.endsWithIgnoringASCIICase(referenceUTF8));
+ EXPECT_FALSE(referenceUTF8.endsWithIgnoringASCIICase(reference));
+}
+
+TEST(WTF, StringViewEndsWithBasic)
+{
+ StringView reference = stringViewFromLiteral("abcdefg");
+ String referenceUTF8Ref;
+ StringView referenceUTF8 = stringViewFromUTF8(referenceUTF8Ref, "àîûèô");
+
+ StringView oneLetterSuffix = stringViewFromLiteral("g");
+ StringView shortSuffix = stringViewFromLiteral("efg");
+ StringView longSuffix = stringViewFromLiteral("cdefg");
+ StringView upperCaseSuffix = stringViewFromLiteral("EFG");
+ StringView empty = stringViewFromLiteral("");
+ StringView notSuffix = stringViewFromLiteral("bc");
+
+ String oneLetterSuffixUTF8Ref;
+ StringView oneLetterSuffixUTF8 = stringViewFromUTF8(oneLetterSuffixUTF8Ref, "ô");
+ String shortSuffixUTF8Ref;
+ StringView shortSuffixUTF8 = stringViewFromUTF8(shortSuffixUTF8Ref, "èô");
+ String longSuffixUTF8Ref;
+ StringView longSuffixUTF8 = stringViewFromUTF8(longSuffixUTF8Ref, "îûèô");
+ String upperCaseSuffixUTF8Ref;
+ StringView upperCaseSuffixUTF8 = stringViewFromUTF8(upperCaseSuffixUTF8Ref, "ÈÔ");
+ String notSuffixUTF8Ref;
+ StringView notSuffixUTF8 = stringViewFromUTF8(notSuffixUTF8Ref, "îû");
+
+ EXPECT_TRUE(reference.endsWith(reference));
+ EXPECT_TRUE(reference.endsWith(oneLetterSuffix));
+ EXPECT_TRUE(reference.endsWith(shortSuffix));
+ EXPECT_TRUE(reference.endsWith(longSuffix));
+ EXPECT_TRUE(reference.endsWith(empty));
+
+ EXPECT_TRUE(referenceUTF8.endsWith(referenceUTF8));
+ EXPECT_TRUE(referenceUTF8.endsWith(oneLetterSuffixUTF8));
+ EXPECT_TRUE(referenceUTF8.endsWith(shortSuffixUTF8));
+ EXPECT_TRUE(referenceUTF8.endsWith(longSuffixUTF8));
+ EXPECT_TRUE(referenceUTF8.endsWith(empty));
+
+ EXPECT_FALSE(reference.endsWith(notSuffix));
+ EXPECT_FALSE(reference.endsWith(upperCaseSuffix));
+ EXPECT_FALSE(reference.endsWith(notSuffixUTF8));
+ EXPECT_FALSE(reference.endsWith(upperCaseSuffixUTF8));
+ EXPECT_FALSE(referenceUTF8.endsWith(notSuffix));
+ EXPECT_FALSE(referenceUTF8.endsWith(upperCaseSuffix));
+ EXPECT_FALSE(referenceUTF8.endsWith(notSuffixUTF8));
+ EXPECT_FALSE(referenceUTF8.endsWith(upperCaseSuffixUTF8));
+}
+
+TEST(WTF, StringViewEndsWithEmpty)
+{
+ StringView a = stringViewFromLiteral("");
+ String refB;
+ StringView b = stringViewFromUTF8(refB, "");
+
+ EXPECT_TRUE(a.endsWith(a));
+ EXPECT_TRUE(a.endsWith(b));
+ EXPECT_TRUE(b.endsWith(a));
+ EXPECT_TRUE(b.endsWith(b));
+}
+
+TEST(WTF, StringViewEndsWithIgnoringASCIICaseBasic)
+{
+ StringView reference = stringViewFromLiteral("abcdefg");
+ String referenceUTF8Ref;
+ StringView referenceUTF8 = stringViewFromUTF8(referenceUTF8Ref, "àîûèô");
+
+ StringView oneLetterSuffix = stringViewFromLiteral("g");
+ StringView shortSuffix = stringViewFromLiteral("efg");
+ StringView longSuffix = stringViewFromLiteral("bcdefg");
+ StringView upperCaseSuffix = stringViewFromLiteral("EFG");
+ StringView mixedCaseSuffix = stringViewFromLiteral("bCdeFg");
+ StringView empty = stringViewFromLiteral("");
+ StringView notSuffix = stringViewFromLiteral("bc");
+
+ String oneLetterSuffixUTF8Ref;
+ StringView oneLetterSuffixUTF8 = stringViewFromUTF8(oneLetterSuffixUTF8Ref, "ô");
+ String shortSuffixUTF8Ref;
+ StringView shortSuffixUTF8 = stringViewFromUTF8(shortSuffixUTF8Ref, "èô");
+ String longSuffixUTF8Ref;
+ StringView longSuffixUTF8 = stringViewFromUTF8(longSuffixUTF8Ref, "îûèô");
+ String upperCaseSuffixUTF8Ref;
+ StringView upperCaseSuffixUTF8 = stringViewFromUTF8(upperCaseSuffixUTF8Ref, "ÈÔ");
+ String notSuffixUTF8Ref;
+ StringView notSuffixUTF8 = stringViewFromUTF8(notSuffixUTF8Ref, "îû");
+
+ EXPECT_TRUE(reference.endsWithIgnoringASCIICase(reference));
+ EXPECT_TRUE(reference.endsWithIgnoringASCIICase(oneLetterSuffix));
+ EXPECT_TRUE(reference.endsWithIgnoringASCIICase(shortSuffix));
+ EXPECT_TRUE(reference.endsWithIgnoringASCIICase(longSuffix));
+ EXPECT_TRUE(reference.endsWithIgnoringASCIICase(empty));
+ EXPECT_TRUE(reference.endsWithIgnoringASCIICase(upperCaseSuffix));
+ EXPECT_TRUE(reference.endsWithIgnoringASCIICase(mixedCaseSuffix));
+
+ EXPECT_TRUE(referenceUTF8.endsWithIgnoringASCIICase(referenceUTF8));
+ EXPECT_TRUE(referenceUTF8.endsWithIgnoringASCIICase(oneLetterSuffixUTF8));
+ EXPECT_TRUE(referenceUTF8.endsWithIgnoringASCIICase(shortSuffixUTF8));
+ EXPECT_TRUE(referenceUTF8.endsWithIgnoringASCIICase(longSuffixUTF8));
+ EXPECT_TRUE(referenceUTF8.endsWithIgnoringASCIICase(empty));
+
+ EXPECT_FALSE(reference.endsWithIgnoringASCIICase(notSuffix));
+ EXPECT_FALSE(reference.endsWithIgnoringASCIICase(notSuffixUTF8));
+ EXPECT_FALSE(reference.endsWithIgnoringASCIICase(upperCaseSuffixUTF8));
+ EXPECT_FALSE(referenceUTF8.endsWithIgnoringASCIICase(notSuffix));
+ EXPECT_FALSE(referenceUTF8.endsWithIgnoringASCIICase(notSuffixUTF8));
+ EXPECT_FALSE(referenceUTF8.endsWithIgnoringASCIICase(upperCaseSuffix));
+ EXPECT_FALSE(referenceUTF8.endsWithIgnoringASCIICase(upperCaseSuffixUTF8));
+}
+
+TEST(WTF, StringViewEndsWithIgnoringASCIICaseEmpty)
+{
+ StringView a = stringViewFromLiteral("");
+ String refB;
+ StringView b = stringViewFromUTF8(refB, "");
+
+ EXPECT_TRUE(a.endsWithIgnoringASCIICase(a));
+ EXPECT_TRUE(a.endsWithIgnoringASCIICase(b));
+ EXPECT_TRUE(b.endsWithIgnoringASCIICase(a));
+ EXPECT_TRUE(b.endsWithIgnoringASCIICase(b));
+}
+
+TEST(WTF, StringViewEndsWithIgnoringASCIICaseWithLatin1Characters)
+{
+ StringView reference = stringViewFromLiteral("aBcéeFG");
+ String referenceUTF8Ref;
+ StringView referenceUTF8 = stringViewFromUTF8(referenceUTF8Ref, "aBcéeFG");
+
+ StringView a = stringViewFromLiteral("BcéeFG");
+ StringView b = stringViewFromLiteral("BCéEFG");
+ StringView c = stringViewFromLiteral("bcéefG");
+ StringView d = stringViewFromLiteral("bcéefg");
+
+ String refE;
+ StringView e = stringViewFromUTF8(refE, "bcéefG");
+ String refF;
+ StringView f = stringViewFromUTF8(refF, "BCéEFG");
+ String refG;
+ StringView g = stringViewFromUTF8(refG, "bcéefG");
+ String refH;
+ StringView h = stringViewFromUTF8(refH, "bcéefg");
+
+ EXPECT_TRUE(reference.endsWithIgnoringASCIICase(a));
+ EXPECT_TRUE(reference.endsWithIgnoringASCIICase(b));
+ EXPECT_TRUE(reference.endsWithIgnoringASCIICase(c));
+ EXPECT_TRUE(reference.endsWithIgnoringASCIICase(d));
+
+ EXPECT_TRUE(referenceUTF8.endsWithIgnoringASCIICase(e));
+ EXPECT_TRUE(referenceUTF8.endsWithIgnoringASCIICase(f));
+ EXPECT_TRUE(referenceUTF8.endsWithIgnoringASCIICase(g));
+ EXPECT_TRUE(referenceUTF8.endsWithIgnoringASCIICase(h));
+
+ EXPECT_FALSE(reference.endsWithIgnoringASCIICase(referenceUTF8));
+ EXPECT_FALSE(referenceUTF8.endsWithIgnoringASCIICase(reference));
+}
+
+TEST(WTF, StringView8Bit)
+{
+ StringView nullView;
+ StringView emptyView = StringView::empty();
+ EXPECT_TRUE(StringView().is8Bit());
+ EXPECT_TRUE(StringView::empty().is8Bit());
+
+ LChar* lcharPtr = nullptr;
+ UChar* ucharPtr = nullptr;
+ EXPECT_TRUE(StringView(lcharPtr, 0).is8Bit());
+ EXPECT_FALSE(StringView(ucharPtr, 0).is8Bit());
+
+ EXPECT_TRUE(StringView(String(lcharPtr, 0)).is8Bit());
+ EXPECT_TRUE(StringView(String(ucharPtr, 0)).is8Bit());
+
+ EXPECT_TRUE(StringView(String().impl()).is8Bit());
+ EXPECT_TRUE(StringView(emptyString().impl()).is8Bit());
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/TemporaryChange.cpp b/Tools/TestWebKitAPI/Tests/WTF/TemporaryChange.cpp
new file mode 100644
index 000000000..3ba0f15bd
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/TemporaryChange.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2011 Google 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 <wtf/TemporaryChange.h>
+
+namespace TestWebKitAPI {
+
+TEST(WTF, TemporaryChangeNested)
+{
+ bool originallyFalse = false;
+ {
+ TemporaryChange<bool> change1OriginallyFalse(originallyFalse, true);
+ EXPECT_TRUE(originallyFalse);
+ {
+ TemporaryChange<bool> change2OriginallyFalse(originallyFalse, false);
+ EXPECT_FALSE(originallyFalse);
+ }
+ EXPECT_TRUE(originallyFalse);
+ }
+ EXPECT_FALSE(originallyFalse);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/Vector.cpp b/Tools/TestWebKitAPI/Tests/WTF/Vector.cpp
new file mode 100644
index 000000000..bec224141
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/Vector.cpp
@@ -0,0 +1,617 @@
+/*
+ * Copyright (C) 2011 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 "MoveOnly.h"
+#include <wtf/Vector.h>
+#include <wtf/text/CString.h>
+
+namespace TestWebKitAPI {
+
+TEST(WTF_Vector, Basic)
+{
+ Vector<int> intVector;
+ EXPECT_TRUE(intVector.isEmpty());
+ EXPECT_EQ(0U, intVector.size());
+ EXPECT_EQ(0U, intVector.capacity());
+}
+
+TEST(WTF_Vector, Iterator)
+{
+ Vector<int> intVector;
+ intVector.append(10);
+ intVector.append(11);
+ intVector.append(12);
+ intVector.append(13);
+
+ Vector<int>::iterator it = intVector.begin();
+ Vector<int>::iterator end = intVector.end();
+ EXPECT_TRUE(end != it);
+
+ EXPECT_EQ(10, *it);
+ ++it;
+ EXPECT_EQ(11, *it);
+ ++it;
+ EXPECT_EQ(12, *it);
+ ++it;
+ EXPECT_EQ(13, *it);
+ ++it;
+
+ EXPECT_TRUE(end == it);
+}
+
+TEST(WTF_Vector, OverloadedOperatorAmpersand)
+{
+ struct Test {
+ private:
+ Test* operator&();
+ };
+
+ Vector<Test> vector;
+ vector.append(Test());
+}
+
+TEST(WTF_Vector, AppendLast)
+{
+ Vector<unsigned> vector;
+ vector.append(0);
+
+ // FIXME: This test needs to be run with GuardMalloc to show the bug.
+ for (size_t i = 0; i < 100; ++i)
+ vector.append(const_cast<const unsigned&>(vector.last()));
+}
+
+TEST(WTF_Vector, InitializerList)
+{
+ Vector<int> vector = { 1, 2, 3, 4 };
+ EXPECT_EQ(4U, vector.size());
+
+ EXPECT_EQ(1, vector[0]);
+ EXPECT_EQ(2, vector[1]);
+ EXPECT_EQ(3, vector[2]);
+ EXPECT_EQ(4, vector[3]);
+}
+
+TEST(WTF_Vector, InitializeFromOtherInitialCapacity)
+{
+ Vector<int, 3> vector = { 1, 3, 2, 4 };
+ Vector<int, 5> vectorCopy(vector);
+ EXPECT_EQ(4U, vector.size());
+ EXPECT_EQ(4U, vectorCopy.size());
+ EXPECT_EQ(5U, vectorCopy.capacity());
+
+ EXPECT_EQ(1, vectorCopy[0]);
+ EXPECT_EQ(3, vectorCopy[1]);
+ EXPECT_EQ(2, vectorCopy[2]);
+ EXPECT_EQ(4, vectorCopy[3]);
+}
+
+TEST(WTF_Vector, CopyFromOtherInitialCapacity)
+{
+ Vector<int, 3> vector = { 1, 3, 2, 4 };
+ Vector<int, 5> vectorCopy { 0 };
+ EXPECT_EQ(4U, vector.size());
+ EXPECT_EQ(1U, vectorCopy.size());
+
+ vectorCopy = vector;
+
+ EXPECT_EQ(4U, vector.size());
+ EXPECT_EQ(4U, vectorCopy.size());
+ EXPECT_EQ(5U, vectorCopy.capacity());
+
+ EXPECT_EQ(1, vectorCopy[0]);
+ EXPECT_EQ(3, vectorCopy[1]);
+ EXPECT_EQ(2, vectorCopy[2]);
+ EXPECT_EQ(4, vectorCopy[3]);
+}
+
+TEST(WTF_Vector, InitializeFromOtherOverflowBehavior)
+{
+ Vector<int, 7, WTF::CrashOnOverflow> vector = { 4, 3, 2, 1 };
+ Vector<int, 7, UnsafeVectorOverflow> vectorCopy(vector);
+ EXPECT_EQ(4U, vector.size());
+ EXPECT_EQ(4U, vectorCopy.size());
+
+ EXPECT_EQ(4, vectorCopy[0]);
+ EXPECT_EQ(3, vectorCopy[1]);
+ EXPECT_EQ(2, vectorCopy[2]);
+ EXPECT_EQ(1, vectorCopy[3]);
+}
+
+TEST(WTF_Vector, CopyFromOtherOverflowBehavior)
+{
+ Vector<int, 7, WTF::CrashOnOverflow> vector = { 4, 3, 2, 1 };
+ Vector<int, 7, UnsafeVectorOverflow> vectorCopy = { 0, 0, 0 };
+
+ EXPECT_EQ(4U, vector.size());
+ EXPECT_EQ(3U, vectorCopy.size());
+
+ vectorCopy = vector;
+
+ EXPECT_EQ(4U, vector.size());
+ EXPECT_EQ(4U, vectorCopy.size());
+
+ EXPECT_EQ(4, vectorCopy[0]);
+ EXPECT_EQ(3, vectorCopy[1]);
+ EXPECT_EQ(2, vectorCopy[2]);
+ EXPECT_EQ(1, vectorCopy[3]);
+}
+
+TEST(WTF_Vector, InitializeFromOtherMinCapacity)
+{
+ Vector<int, 7, WTF::CrashOnOverflow, 1> vector = { 3, 4, 2, 1 };
+ Vector<int, 7, WTF::CrashOnOverflow, 50> vectorCopy(vector);
+ EXPECT_EQ(4U, vector.size());
+ EXPECT_EQ(4U, vectorCopy.size());
+
+ EXPECT_EQ(3, vectorCopy[0]);
+ EXPECT_EQ(4, vectorCopy[1]);
+ EXPECT_EQ(2, vectorCopy[2]);
+ EXPECT_EQ(1, vectorCopy[3]);
+}
+
+TEST(WTF_Vector, CopyFromOtherMinCapacity)
+{
+ Vector<int, 7, WTF::CrashOnOverflow, 1> vector = { 3, 4, 2, 1 };
+ Vector<int, 7, WTF::CrashOnOverflow, 50> vectorCopy;
+
+ EXPECT_EQ(4U, vector.size());
+ EXPECT_EQ(0U, vectorCopy.size());
+
+ vectorCopy = vector;
+
+ EXPECT_EQ(4U, vector.size());
+ EXPECT_EQ(4U, vectorCopy.size());
+
+ EXPECT_EQ(3, vectorCopy[0]);
+ EXPECT_EQ(4, vectorCopy[1]);
+ EXPECT_EQ(2, vectorCopy[2]);
+ EXPECT_EQ(1, vectorCopy[3]);
+}
+
+TEST(WTF_Vector, Reverse)
+{
+ Vector<int> intVector;
+ intVector.append(10);
+ intVector.append(11);
+ intVector.append(12);
+ intVector.append(13);
+ intVector.reverse();
+
+ EXPECT_EQ(13, intVector[0]);
+ EXPECT_EQ(12, intVector[1]);
+ EXPECT_EQ(11, intVector[2]);
+ EXPECT_EQ(10, intVector[3]);
+
+ intVector.append(9);
+ intVector.reverse();
+
+ EXPECT_EQ(9, intVector[0]);
+ EXPECT_EQ(10, intVector[1]);
+ EXPECT_EQ(11, intVector[2]);
+ EXPECT_EQ(12, intVector[3]);
+ EXPECT_EQ(13, intVector[4]);
+}
+
+TEST(WTF_Vector, ReverseIterator)
+{
+ Vector<int> intVector;
+ intVector.append(10);
+ intVector.append(11);
+ intVector.append(12);
+ intVector.append(13);
+
+ Vector<int>::reverse_iterator it = intVector.rbegin();
+ Vector<int>::reverse_iterator end = intVector.rend();
+ EXPECT_TRUE(end != it);
+
+ EXPECT_EQ(13, *it);
+ ++it;
+ EXPECT_EQ(12, *it);
+ ++it;
+ EXPECT_EQ(11, *it);
+ ++it;
+ EXPECT_EQ(10, *it);
+ ++it;
+
+ EXPECT_TRUE(end == it);
+}
+
+TEST(WTF_Vector, MoveOnly_UncheckedAppend)
+{
+ Vector<MoveOnly> vector;
+
+ vector.reserveInitialCapacity(100);
+ for (size_t i = 0; i < 100; ++i) {
+ MoveOnly moveOnly(i);
+ vector.uncheckedAppend(WTF::move(moveOnly));
+ EXPECT_EQ(0U, moveOnly.value());
+ }
+
+ for (size_t i = 0; i < 100; ++i)
+ EXPECT_EQ(i, vector[i].value());
+}
+
+TEST(WTF_Vector, MoveOnly_Append)
+{
+ Vector<MoveOnly> vector;
+
+ for (size_t i = 0; i < 100; ++i) {
+ MoveOnly moveOnly(i);
+ vector.append(WTF::move(moveOnly));
+ EXPECT_EQ(0U, moveOnly.value());
+ }
+
+ for (size_t i = 0; i < 100; ++i)
+ EXPECT_EQ(i, vector[i].value());
+
+ for (size_t i = 0; i < 16; ++i) {
+ Vector<MoveOnly> vector;
+
+ vector.append(i);
+
+ for (size_t j = 0; j < i; ++j)
+ vector.append(j);
+ vector.append(WTF::move(vector[0]));
+
+ EXPECT_EQ(0U, vector[0].value());
+
+ for (size_t j = 0; j < i; ++j)
+ EXPECT_EQ(j, vector[j + 1].value());
+ EXPECT_EQ(i, vector.last().value());
+ }
+}
+
+TEST(WTF_Vector, MoveOnly_Insert)
+{
+ Vector<MoveOnly> vector;
+
+ for (size_t i = 0; i < 100; ++i) {
+ MoveOnly moveOnly(i);
+ vector.insert(0, WTF::move(moveOnly));
+ EXPECT_EQ(0U, moveOnly.value());
+ }
+
+ EXPECT_EQ(vector.size(), 100U);
+ for (size_t i = 0; i < 100; ++i)
+ EXPECT_EQ(99 - i, vector[i].value());
+
+ for (size_t i = 0; i < 200; i += 2) {
+ MoveOnly moveOnly(1000 + i);
+ vector.insert(i, WTF::move(moveOnly));
+ EXPECT_EQ(0U, moveOnly.value());
+ }
+
+ EXPECT_EQ(200U, vector.size());
+ for (size_t i = 0; i < 200; ++i) {
+ if (i % 2)
+ EXPECT_EQ(99 - i / 2, vector[i].value());
+ else
+ EXPECT_EQ(1000 + i, vector[i].value());
+ }
+}
+
+TEST(WTF_Vector, MoveOnly_TakeLast)
+{
+ Vector<MoveOnly> vector;
+
+ for (size_t i = 0; i < 100; ++i) {
+ MoveOnly moveOnly(i);
+ vector.append(WTF::move(moveOnly));
+ EXPECT_EQ(0U, moveOnly.value());
+ }
+
+ EXPECT_EQ(100U, vector.size());
+ for (size_t i = 0; i < 100; ++i)
+ EXPECT_EQ(99 - i, vector.takeLast().value());
+
+ EXPECT_EQ(0U, vector.size());
+}
+
+TEST(WTF_Vector, VectorOfVectorsOfVectorsInlineCapacitySwap)
+{
+ Vector<Vector<Vector<int, 1>, 1>, 1> a;
+ Vector<Vector<Vector<int, 1>, 1>, 1> b;
+ Vector<Vector<Vector<int, 1>, 1>, 1> c;
+
+ EXPECT_EQ(0U, a.size());
+ EXPECT_EQ(0U, b.size());
+ EXPECT_EQ(0U, c.size());
+
+ Vector<int, 1> x;
+ x.append(42);
+
+ EXPECT_EQ(1U, x.size());
+ EXPECT_EQ(42, x[0]);
+
+ Vector<Vector<int, 1>, 1> y;
+ y.append(x);
+
+ EXPECT_EQ(1U, x.size());
+ EXPECT_EQ(42, x[0]);
+ EXPECT_EQ(1U, y.size());
+ EXPECT_EQ(1U, y[0].size());
+ EXPECT_EQ(42, y[0][0]);
+
+ a.append(y);
+
+ EXPECT_EQ(1U, x.size());
+ EXPECT_EQ(42, x[0]);
+ EXPECT_EQ(1U, y.size());
+ EXPECT_EQ(1U, y[0].size());
+ EXPECT_EQ(42, y[0][0]);
+ EXPECT_EQ(1U, a.size());
+ EXPECT_EQ(1U, a[0].size());
+ EXPECT_EQ(1U, a[0][0].size());
+ EXPECT_EQ(42, a[0][0][0]);
+
+ a.swap(b);
+
+ EXPECT_EQ(0U, a.size());
+ EXPECT_EQ(1U, x.size());
+ EXPECT_EQ(42, x[0]);
+ EXPECT_EQ(1U, y.size());
+ EXPECT_EQ(1U, y[0].size());
+ EXPECT_EQ(42, y[0][0]);
+ EXPECT_EQ(1U, b.size());
+ EXPECT_EQ(1U, b[0].size());
+ EXPECT_EQ(1U, b[0][0].size());
+ EXPECT_EQ(42, b[0][0][0]);
+
+ b.swap(c);
+
+ EXPECT_EQ(0U, a.size());
+ EXPECT_EQ(0U, b.size());
+ EXPECT_EQ(1U, x.size());
+ EXPECT_EQ(42, x[0]);
+ EXPECT_EQ(1U, y.size());
+ EXPECT_EQ(1U, y[0].size());
+ EXPECT_EQ(42, y[0][0]);
+ EXPECT_EQ(1U, c.size());
+ EXPECT_EQ(1U, c[0].size());
+ EXPECT_EQ(1U, c[0][0].size());
+ EXPECT_EQ(42, c[0][0][0]);
+
+ y[0][0] = 24;
+
+ EXPECT_EQ(1U, x.size());
+ EXPECT_EQ(42, x[0]);
+ EXPECT_EQ(1U, y.size());
+ EXPECT_EQ(1U, y[0].size());
+ EXPECT_EQ(24, y[0][0]);
+
+ a.append(y);
+
+ EXPECT_EQ(1U, x.size());
+ EXPECT_EQ(42, x[0]);
+ EXPECT_EQ(1U, y.size());
+ EXPECT_EQ(1U, y[0].size());
+ EXPECT_EQ(24, y[0][0]);
+ EXPECT_EQ(1U, a.size());
+ EXPECT_EQ(1U, a[0].size());
+ EXPECT_EQ(1U, a[0][0].size());
+ EXPECT_EQ(24, a[0][0][0]);
+ EXPECT_EQ(1U, c.size());
+ EXPECT_EQ(1U, c[0].size());
+ EXPECT_EQ(1U, c[0][0].size());
+ EXPECT_EQ(42, c[0][0][0]);
+ EXPECT_EQ(0U, b.size());
+}
+
+TEST(WTF_Vector, RemoveFirst)
+{
+ Vector<int> v;
+ EXPECT_TRUE(v.isEmpty());
+ EXPECT_FALSE(v.removeFirst(1));
+ EXPECT_FALSE(v.removeFirst(-1));
+ EXPECT_TRUE(v.isEmpty());
+
+ v.fill(2, 10);
+ EXPECT_EQ(10U, v.size());
+ EXPECT_FALSE(v.removeFirst(1));
+ EXPECT_EQ(10U, v.size());
+ v.clear();
+
+ v.fill(1, 10);
+ EXPECT_EQ(10U, v.size());
+ EXPECT_TRUE(v.removeFirst(1));
+ EXPECT_TRUE(v == Vector<int>({1, 1, 1, 1, 1, 1, 1, 1, 1}));
+ EXPECT_EQ(9U, v.size());
+ EXPECT_FALSE(v.removeFirst(2));
+ EXPECT_EQ(9U, v.size());
+ EXPECT_TRUE(v == Vector<int>({1, 1, 1, 1, 1, 1, 1, 1, 1}));
+
+ unsigned removed = 0;
+ while (v.removeFirst(1))
+ ++removed;
+ EXPECT_EQ(9U, removed);
+ EXPECT_TRUE(v.isEmpty());
+
+ v.resize(1);
+ EXPECT_EQ(1U, v.size());
+ EXPECT_TRUE(v.removeFirst(1));
+ EXPECT_EQ(0U, v.size());
+ EXPECT_TRUE(v.isEmpty());
+}
+
+TEST(WTF_Vector, RemoveAll)
+{
+ // Using a memcpy-able type.
+ static_assert(VectorTraits<int>::canMoveWithMemcpy, "Should use a memcpy-able type");
+ Vector<int> v;
+ EXPECT_TRUE(v.isEmpty());
+ EXPECT_FALSE(v.removeAll(1));
+ EXPECT_FALSE(v.removeAll(-1));
+ EXPECT_TRUE(v.isEmpty());
+
+ v.fill(1, 10);
+ EXPECT_EQ(10U, v.size());
+ EXPECT_EQ(10U, v.removeAll(1));
+ EXPECT_TRUE(v.isEmpty());
+
+ v.fill(2, 10);
+ EXPECT_EQ(10U, v.size());
+ EXPECT_EQ(0U, v.removeAll(1));
+ EXPECT_EQ(10U, v.size());
+
+ v = {1, 2, 1, 2, 1, 2, 2, 1, 1, 1};
+ EXPECT_EQ(10U, v.size());
+ EXPECT_EQ(6U, v.removeAll(1));
+ EXPECT_EQ(4U, v.size());
+ EXPECT_TRUE(v == Vector<int>({2, 2, 2, 2}));
+ EXPECT_TRUE(v.find(1) == notFound);
+ EXPECT_EQ(4U, v.removeAll(2));
+ EXPECT_TRUE(v.isEmpty());
+
+ v = {3, 1, 2, 1, 2, 1, 2, 2, 1, 1, 1, 3};
+ EXPECT_EQ(12U, v.size());
+ EXPECT_EQ(6U, v.removeAll(1));
+ EXPECT_EQ(6U, v.size());
+ EXPECT_TRUE(v.find(1) == notFound);
+ EXPECT_TRUE(v == Vector<int>({3, 2, 2, 2, 2, 3}));
+
+ EXPECT_EQ(4U, v.removeAll(2));
+ EXPECT_EQ(2U, v.size());
+ EXPECT_TRUE(v.find(2) == notFound);
+ EXPECT_TRUE(v == Vector<int>({3, 3}));
+
+ EXPECT_EQ(2U, v.removeAll(3));
+ EXPECT_TRUE(v.isEmpty());
+
+ v = {1, 1, 1, 3, 2, 4, 2, 2, 2, 4, 4, 3};
+ EXPECT_EQ(12U, v.size());
+ EXPECT_EQ(3U, v.removeAll(1));
+ EXPECT_EQ(9U, v.size());
+ EXPECT_TRUE(v.find(1) == notFound);
+ EXPECT_TRUE(v == Vector<int>({3, 2, 4, 2, 2, 2, 4, 4, 3}));
+
+ // Using a non memcpy-able type.
+ static_assert(!VectorTraits<CString>::canMoveWithMemcpy, "Should use a non memcpy-able type");
+ Vector<CString> vExpected;
+ Vector<CString> v2;
+ EXPECT_TRUE(v2.isEmpty());
+ EXPECT_FALSE(v2.removeAll("1"));
+ EXPECT_TRUE(v2.isEmpty());
+
+ v2.fill("1", 10);
+ EXPECT_EQ(10U, v2.size());
+ EXPECT_EQ(10U, v2.removeAll("1"));
+ EXPECT_TRUE(v2.isEmpty());
+
+ v2.fill("2", 10);
+ EXPECT_EQ(10U, v2.size());
+ EXPECT_EQ(0U, v2.removeAll("1"));
+ EXPECT_EQ(10U, v2.size());
+
+ v2 = {"1", "2", "1", "2", "1", "2", "2", "1", "1", "1"};
+ EXPECT_EQ(10U, v2.size());
+ EXPECT_EQ(6U, v2.removeAll("1"));
+ EXPECT_EQ(4U, v2.size());
+ EXPECT_TRUE(v2.find("1") == notFound);
+ EXPECT_EQ(4U, v2.removeAll("2"));
+ EXPECT_TRUE(v2.isEmpty());
+
+ v2 = {"3", "1", "2", "1", "2", "1", "2", "2", "1", "1", "1", "3"};
+ EXPECT_EQ(12U, v2.size());
+ EXPECT_EQ(6U, v2.removeAll("1"));
+ EXPECT_EQ(6U, v2.size());
+ EXPECT_TRUE(v2.find("1") == notFound);
+ vExpected = {"3", "2", "2", "2", "2", "3"};
+ EXPECT_TRUE(v2 == vExpected);
+
+ EXPECT_EQ(4U, v2.removeAll("2"));
+ EXPECT_EQ(2U, v2.size());
+ EXPECT_TRUE(v2.find("2") == notFound);
+ vExpected = {"3", "3"};
+ EXPECT_TRUE(v2 == vExpected);
+
+ EXPECT_EQ(2U, v2.removeAll("3"));
+ EXPECT_TRUE(v2.isEmpty());
+
+ v2 = {"1", "1", "1", "3", "2", "4", "2", "2", "2", "4", "4", "3"};
+ EXPECT_EQ(12U, v2.size());
+ EXPECT_EQ(3U, v2.removeAll("1"));
+ EXPECT_EQ(9U, v2.size());
+ EXPECT_TRUE(v2.find("1") == notFound);
+ vExpected = {"3", "2", "4", "2", "2", "2", "4", "4", "3"};
+ EXPECT_TRUE(v2 == vExpected);
+}
+
+TEST(WTF_Vector, RemoveFirstMatching)
+{
+ Vector<int> v;
+ EXPECT_TRUE(v.isEmpty());
+ EXPECT_FALSE(v.removeFirstMatching([] (int value) { return value > 0; }));
+ EXPECT_FALSE(v.removeFirstMatching([] (int) { return true; }));
+ EXPECT_FALSE(v.removeFirstMatching([] (int) { return false; }));
+
+ v = {3, 1, 2, 1, 2, 1, 2, 2, 1, 1, 1, 3};
+ EXPECT_EQ(12U, v.size());
+ EXPECT_FALSE(v.removeFirstMatching([] (int) { return false; }));
+ EXPECT_EQ(12U, v.size());
+ EXPECT_FALSE(v.removeFirstMatching([] (int value) { return value < 0; }));
+ EXPECT_EQ(12U, v.size());
+ EXPECT_TRUE(v.removeFirstMatching([] (int value) { return value < 3; }));
+ EXPECT_EQ(11U, v.size());
+ EXPECT_TRUE(v == Vector<int>({3, 2, 1, 2, 1, 2, 2, 1, 1, 1, 3}));
+ EXPECT_TRUE(v.removeFirstMatching([] (int value) { return value > 2; }));
+ EXPECT_EQ(10U, v.size());
+ EXPECT_TRUE(v == Vector<int>({2, 1, 2, 1, 2, 2, 1, 1, 1, 3}));
+ EXPECT_TRUE(v.removeFirstMatching([] (int value) { return value > 2; }));
+ EXPECT_EQ(9U, v.size());
+ EXPECT_TRUE(v == Vector<int>({2, 1, 2, 1, 2, 2, 1, 1, 1}));
+}
+
+TEST(WTF_Vector, RemoveAllMatching)
+{
+ Vector<int> v;
+ EXPECT_TRUE(v.isEmpty());
+ EXPECT_FALSE(v.removeAllMatching([] (int value) { return value > 0; }));
+ EXPECT_FALSE(v.removeAllMatching([] (int) { return true; }));
+ EXPECT_FALSE(v.removeAllMatching([] (int) { return false; }));
+
+ v = {3, 1, 2, 1, 2, 1, 2, 2, 1, 1, 1, 3};
+ EXPECT_EQ(12U, v.size());
+ EXPECT_EQ(0U, v.removeAllMatching([] (int) { return false; }));
+ EXPECT_EQ(12U, v.size());
+ EXPECT_EQ(0U, v.removeAllMatching([] (int value) { return value < 0; }));
+ EXPECT_EQ(12U, v.size());
+ EXPECT_EQ(12U, v.removeAllMatching([] (int value) { return value > 0; }));
+ EXPECT_TRUE(v.isEmpty());
+
+ v = {3, 1, 2, 1, 2, 1, 3, 2, 2, 1, 1, 1, 3};
+ EXPECT_EQ(13U, v.size());
+ EXPECT_EQ(3U, v.removeAllMatching([] (int value) { return value > 2; }));
+ EXPECT_EQ(10U, v.size());
+ EXPECT_TRUE(v == Vector<int>({1, 2, 1, 2, 1, 2, 2, 1, 1, 1}));
+ EXPECT_EQ(6U, v.removeAllMatching([] (int value) { return value != 2; }));
+ EXPECT_EQ(4U, v.size());
+ EXPECT_TRUE(v == Vector<int>({2, 2, 2, 2}));
+ EXPECT_EQ(4U, v.removeAllMatching([] (int value) { return value == 2; }));
+ EXPECT_TRUE(v.isEmpty());
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/WTFString.cpp b/Tools/TestWebKitAPI/Tests/WTF/WTFString.cpp
new file mode 100644
index 000000000..a13ca0aa0
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/WTFString.cpp
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2012 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 <limits>
+#include <wtf/MathExtras.h>
+#include <wtf/text/CString.h>
+#include <wtf/text/WTFString.h>
+
+namespace TestWebKitAPI {
+
+TEST(WTF, StringCreationFromLiteral)
+{
+ String stringFromLiteral(ASCIILiteral("Explicit construction syntax"));
+ ASSERT_EQ(strlen("Explicit construction syntax"), stringFromLiteral.length());
+ ASSERT_TRUE(stringFromLiteral == "Explicit construction syntax");
+ ASSERT_TRUE(stringFromLiteral.is8Bit());
+ ASSERT_TRUE(String("Explicit construction syntax") == stringFromLiteral);
+
+ String stringWithTemplate("Template Literal", String::ConstructFromLiteral);
+ ASSERT_EQ(strlen("Template Literal"), stringWithTemplate.length());
+ ASSERT_TRUE(stringWithTemplate == "Template Literal");
+ ASSERT_TRUE(stringWithTemplate.is8Bit());
+ ASSERT_TRUE(String("Template Literal") == stringWithTemplate);
+}
+
+TEST(WTF, StringASCII)
+{
+ CString output;
+
+ // Null String.
+ output = String().ascii();
+ ASSERT_STREQ("", output.data());
+
+ // Empty String.
+ output = emptyString().ascii();
+ ASSERT_STREQ("", output.data());
+
+ // Regular String.
+ output = String(ASCIILiteral("foobar")).ascii();
+ ASSERT_STREQ("foobar", output.data());
+}
+
+static void testNumberToStringECMAScript(double number, const char* reference)
+{
+ CString numberString = String::numberToStringECMAScript(number).latin1();
+ ASSERT_STREQ(reference, numberString.data());
+}
+
+TEST(WTF, StringNumberToStringECMAScriptBoundaries)
+{
+ typedef std::numeric_limits<double> Limits;
+
+ // Infinity.
+ testNumberToStringECMAScript(Limits::infinity(), "Infinity");
+ testNumberToStringECMAScript(-Limits::infinity(), "-Infinity");
+
+ // NaN.
+ testNumberToStringECMAScript(-Limits::quiet_NaN(), "NaN");
+
+ // Zeros.
+ testNumberToStringECMAScript(0, "0");
+ testNumberToStringECMAScript(-0, "0");
+
+ // Min-Max.
+ testNumberToStringECMAScript(Limits::min(), "2.2250738585072014e-308");
+ testNumberToStringECMAScript(Limits::max(), "1.7976931348623157e+308");
+}
+
+TEST(WTF, StringNumberToStringECMAScriptRegularNumbers)
+{
+ // Pi.
+ testNumberToStringECMAScript(piDouble, "3.141592653589793");
+ testNumberToStringECMAScript(piFloat, "3.1415927410125732");
+ testNumberToStringECMAScript(piOverTwoDouble, "1.5707963267948966");
+ testNumberToStringECMAScript(piOverTwoFloat, "1.5707963705062866");
+ testNumberToStringECMAScript(piOverFourDouble, "0.7853981633974483");
+ testNumberToStringECMAScript(piOverFourFloat, "0.7853981852531433");
+
+ // e.
+ const double e = 2.71828182845904523536028747135266249775724709369995;
+ testNumberToStringECMAScript(e, "2.718281828459045");
+
+ // c, speed of light in m/s.
+ const double c = 299792458;
+ testNumberToStringECMAScript(c, "299792458");
+
+ // Golen ratio.
+ const double phi = 1.6180339887498948482;
+ testNumberToStringECMAScript(phi, "1.618033988749895");
+}
+
+TEST(WTF, StringReplaceWithLiteral)
+{
+ // Cases for 8Bit source.
+ String testString = "1224";
+ ASSERT_TRUE(testString.is8Bit());
+ testString.replaceWithLiteral('2', "");
+ ASSERT_STREQ("14", testString.utf8().data());
+
+ testString = "1224";
+ ASSERT_TRUE(testString.is8Bit());
+ testString.replaceWithLiteral('2', "3");
+ ASSERT_STREQ("1334", testString.utf8().data());
+
+ testString = "1224";
+ ASSERT_TRUE(testString.is8Bit());
+ testString.replaceWithLiteral('2', "555");
+ ASSERT_STREQ("15555554", testString.utf8().data());
+
+ testString = "1224";
+ ASSERT_TRUE(testString.is8Bit());
+ testString.replaceWithLiteral('3', "NotFound");
+ ASSERT_STREQ("1224", testString.utf8().data());
+
+ // Cases for 16Bit source.
+ testString = String::fromUTF8("résumé");
+ ASSERT_FALSE(testString.is8Bit());
+ testString.replaceWithLiteral(UChar(0x00E9 /*U+00E9 is 'é'*/), "e");
+ ASSERT_STREQ("resume", testString.utf8().data());
+
+ testString = String::fromUTF8("résumé");
+ ASSERT_FALSE(testString.is8Bit());
+ testString.replaceWithLiteral(UChar(0x00E9 /*U+00E9 is 'é'*/), "");
+ ASSERT_STREQ("rsum", testString.utf8().data());
+
+ testString = String::fromUTF8("résumé");
+ ASSERT_FALSE(testString.is8Bit());
+ testString.replaceWithLiteral('3', "NotFound");
+ ASSERT_STREQ("résumé", testString.utf8().data());
+}
+
+TEST(WTF, StringIsolatedCopy)
+{
+ String original = "1234";
+ auto copy = WTF::move(original).isolatedCopy();
+ ASSERT_FALSE(original.impl() == copy.impl());
+}
+
+TEST(WTF, StringToInt)
+{
+ bool ok;
+
+ EXPECT_EQ(0, String().toInt());
+ EXPECT_EQ(0, String().toInt(&ok));
+ EXPECT_FALSE(ok);
+
+ EXPECT_EQ(0, emptyString().toInt());
+ EXPECT_EQ(0, emptyString().toInt(&ok));
+ EXPECT_FALSE(ok);
+
+ EXPECT_EQ(0, String("0").toInt());
+ EXPECT_EQ(0, String("0").toInt(&ok));
+ EXPECT_TRUE(ok);
+
+ EXPECT_EQ(1, String("1").toInt());
+ EXPECT_EQ(1, String("1").toInt(&ok));
+ EXPECT_TRUE(ok);
+
+ EXPECT_EQ(2147483647, String("2147483647").toInt());
+ EXPECT_EQ(2147483647, String("2147483647").toInt(&ok));
+ EXPECT_TRUE(ok);
+
+ EXPECT_EQ(0, String("2147483648").toInt());
+ EXPECT_EQ(0, String("2147483648").toInt(&ok));
+ EXPECT_FALSE(ok);
+
+ EXPECT_EQ(-2147483648, String("-2147483648").toInt());
+ EXPECT_EQ(-2147483648, String("-2147483648").toInt(&ok));
+ EXPECT_TRUE(ok);
+
+ EXPECT_EQ(0, String("-2147483649").toInt());
+ EXPECT_EQ(0, String("-2147483649").toInt(&ok));
+ EXPECT_FALSE(ok);
+
+ // fail if we see leading junk
+ EXPECT_EQ(0, String("x1").toInt());
+ EXPECT_EQ(0, String("x1").toInt(&ok));
+ EXPECT_FALSE(ok);
+
+ // succeed if we see leading spaces
+ EXPECT_EQ(1, String(" 1").toInt());
+ EXPECT_EQ(1, String(" 1").toInt(&ok));
+ EXPECT_TRUE(ok);
+
+ // silently ignore trailing junk
+ EXPECT_EQ(1, String("1x").toInt());
+ EXPECT_EQ(1, String("1x").toInt(&ok));
+ EXPECT_TRUE(ok);
+}
+
+TEST(WTF, StringToDouble)
+{
+ bool ok;
+
+ 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").toDouble());
+ EXPECT_EQ(0.0, String("0").toDouble(&ok));
+ EXPECT_TRUE(ok);
+
+ EXPECT_EQ(1.0, String("1").toDouble());
+ EXPECT_EQ(1.0, String("1").toDouble(&ok));
+ EXPECT_TRUE(ok);
+
+ // fail if we see leading junk
+ EXPECT_EQ(0.0, String("x1").toDouble());
+ EXPECT_EQ(0.0, String("x1").toDouble(&ok));
+ EXPECT_FALSE(ok);
+
+ // succeed if we see leading spaces
+ EXPECT_EQ(1.0, String(" 1").toDouble());
+ EXPECT_EQ(1.0, String(" 1").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").toDouble());
+ EXPECT_EQ(1.0, String("1x").toDouble(&ok));
+ EXPECT_FALSE(ok);
+
+ // parse only numbers, not special values such as "infinity"
+ EXPECT_EQ(0.0, String("infinity").toDouble());
+ EXPECT_EQ(0.0, String("infinity").toDouble(&ok));
+ EXPECT_FALSE(ok);
+
+ // parse only numbers, not special values such as "nan"
+ EXPECT_EQ(0.0, String("nan").toDouble());
+ EXPECT_EQ(0.0, String("nan").toDouble(&ok));
+ EXPECT_FALSE(ok);
+}
+
+TEST(WTF, StringhasInfixStartingAt)
+{
+ EXPECT_TRUE(String("Test").is8Bit());
+ EXPECT_TRUE(String("Te").is8Bit());
+ EXPECT_TRUE(String("st").is8Bit());
+ EXPECT_TRUE(String("Test").hasInfixStartingAt(String("Te"), 0));
+ EXPECT_FALSE(String("Test").hasInfixStartingAt(String("Te"), 2));
+ EXPECT_TRUE(String("Test").hasInfixStartingAt(String("st"), 2));
+ EXPECT_FALSE(String("Test").hasInfixStartingAt(String("ST"), 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(String("Te"), 0));
+ EXPECT_FALSE(String("Test").hasInfixStartingAt(String::fromUTF8("中"), 2));
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/WeakPtr.cpp b/Tools/TestWebKitAPI/Tests/WTF/WeakPtr.cpp
new file mode 100644
index 000000000..5b900007a
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/WeakPtr.cpp
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2015 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 "test.h"
+
+#include <wtf/WeakPtr.h>
+
+namespace TestWebKitAPI {
+
+TEST(WTF_WeakPtr, Basic)
+{
+ int dummy = 5;
+ WeakPtrFactory<int>* factory = new WeakPtrFactory<int>(&dummy);
+ WeakPtr<int> weakPtr1 = factory->createWeakPtr();
+ WeakPtr<int> weakPtr2 = factory->createWeakPtr();
+ WeakPtr<int> weakPtr3 = factory->createWeakPtr();
+ EXPECT_EQ(weakPtr1.get(), &dummy);
+ EXPECT_EQ(weakPtr2.get(), &dummy);
+ EXPECT_EQ(weakPtr3.get(), &dummy);
+ EXPECT_TRUE(weakPtr1);
+ EXPECT_TRUE(weakPtr2);
+ EXPECT_TRUE(weakPtr3);
+ delete factory;
+ EXPECT_NULL(weakPtr1.get());
+ EXPECT_NULL(weakPtr2.get());
+ EXPECT_NULL(weakPtr3.get());
+ EXPECT_FALSE(weakPtr1);
+ EXPECT_FALSE(weakPtr2);
+ EXPECT_FALSE(weakPtr3);
+}
+
+TEST(WTF_WeakPtr, Assignment)
+{
+ int dummy = 5;
+ WeakPtr<int> weakPtr;
+ {
+ WeakPtrFactory<int> factory(&dummy);
+ EXPECT_NULL(weakPtr.get());
+ weakPtr = factory.createWeakPtr();
+ EXPECT_EQ(weakPtr.get(), &dummy);
+ }
+ EXPECT_NULL(weakPtr.get());
+}
+
+TEST(WTF_WeakPtr, MultipleFactories)
+{
+ int dummy1 = 5;
+ int dummy2 = 7;
+ WeakPtrFactory<int>* factory1 = new WeakPtrFactory<int>(&dummy1);
+ WeakPtrFactory<int>* factory2 = new WeakPtrFactory<int>(&dummy2);
+ WeakPtr<int> weakPtr1 = factory1->createWeakPtr();
+ WeakPtr<int> weakPtr2 = factory2->createWeakPtr();
+ EXPECT_EQ(weakPtr1.get(), &dummy1);
+ EXPECT_EQ(weakPtr2.get(), &dummy2);
+ delete factory1;
+ EXPECT_NULL(weakPtr1.get());
+ EXPECT_EQ(weakPtr2.get(), &dummy2);
+ delete factory2;
+ EXPECT_NULL(weakPtr2.get());
+}
+
+TEST(WTF_WeakPtr, RevokeAll)
+{
+ int dummy = 5;
+ WeakPtrFactory<int> factory(&dummy);
+ WeakPtr<int> weakPtr1 = factory.createWeakPtr();
+ WeakPtr<int> weakPtr2 = factory.createWeakPtr();
+ WeakPtr<int> weakPtr3 = factory.createWeakPtr();
+ EXPECT_EQ(weakPtr1.get(), &dummy);
+ EXPECT_EQ(weakPtr2.get(), &dummy);
+ EXPECT_EQ(weakPtr3.get(), &dummy);
+ factory.revokeAll();
+ EXPECT_NULL(weakPtr1.get());
+ EXPECT_NULL(weakPtr2.get());
+ EXPECT_NULL(weakPtr3.get());
+}
+
+TEST(WTF_WeakPtr, NullFactory)
+{
+ WeakPtrFactory<int> factory(nullptr);
+ WeakPtr<int> weakPtr = factory.createWeakPtr();
+ EXPECT_NULL(weakPtr.get());
+ factory.revokeAll();
+ EXPECT_NULL(weakPtr.get());
+}
+
+struct Foo {
+ void bar() { };
+};
+
+TEST(WTF_WeakPtr, Dereference)
+{
+ Foo f;
+ WeakPtrFactory<Foo> factory(&f);
+ WeakPtr<Foo> weakPtr = factory.createWeakPtr();
+ weakPtr->bar();
+}
+
+TEST(WTF_WeakPtr, Forget)
+{
+ int dummy = 5;
+ int dummy2 = 7;
+
+ WeakPtrFactory<int> outerFactory(&dummy2);
+ WeakPtr<int> weakPtr1, weakPtr2, weakPtr3, weakPtr4;
+ {
+ WeakPtrFactory<int> innerFactory(&dummy);
+ weakPtr1 = innerFactory.createWeakPtr();
+ weakPtr2 = innerFactory.createWeakPtr();
+ weakPtr3 = innerFactory.createWeakPtr();
+ EXPECT_EQ(weakPtr1.get(), &dummy);
+ EXPECT_EQ(weakPtr2.get(), &dummy);
+ EXPECT_EQ(weakPtr3.get(), &dummy);
+ weakPtr1.clear();
+ weakPtr3 = nullptr;
+ EXPECT_NULL(weakPtr1.get());
+ EXPECT_EQ(weakPtr2.get(), &dummy);
+ EXPECT_NULL(weakPtr3.get());
+ weakPtr1.clear();
+ weakPtr3.clear();
+ EXPECT_NULL(weakPtr1.get());
+ EXPECT_EQ(weakPtr2.get(), &dummy);
+ EXPECT_NULL(weakPtr3.get());
+ weakPtr3 = nullptr;
+ EXPECT_NULL(weakPtr1.get());
+ EXPECT_EQ(weakPtr2.get(), &dummy);
+ EXPECT_NULL(weakPtr3.get());
+
+ weakPtr4 = weakPtr2;
+ EXPECT_EQ(weakPtr2.get(), &dummy);
+ EXPECT_EQ(weakPtr4.get(), &dummy);
+
+ WeakPtr<int> weakPtr5 = weakPtr2;
+ EXPECT_EQ(weakPtr2.get(), &dummy);
+ EXPECT_EQ(weakPtr5.get(), &dummy);
+ weakPtr5.clear();
+ EXPECT_NULL(weakPtr5.get());
+ EXPECT_EQ(weakPtr2.get(), &dummy);
+
+ weakPtr4 = outerFactory.createWeakPtr();
+ EXPECT_EQ(weakPtr2.get(), &dummy);
+ EXPECT_EQ(weakPtr4.get(), &dummy2);
+ }
+
+ EXPECT_NULL(weakPtr1.get());
+ EXPECT_NULL(weakPtr2.get());
+ EXPECT_EQ(weakPtr4.get(), &dummy2);
+
+ WeakPtr<int> weakPtr5 = weakPtr4;
+ EXPECT_EQ(weakPtr4.get(), &dummy2);
+ EXPECT_EQ(weakPtr5.get(), &dummy2);
+ weakPtr5.clear();
+ EXPECT_NULL(weakPtr5.get());
+ WeakPtr<int> weakPtr6 = weakPtr5;
+ EXPECT_NULL(weakPtr6.get());
+ EXPECT_EQ(weakPtr5.get(), weakPtr6.get());
+
+ WeakPtr<int> weakPtr7 = outerFactory.createWeakPtr();
+ EXPECT_EQ(weakPtr7.get(), &dummy2);
+ weakPtr7 = nullptr;
+ EXPECT_NULL(weakPtr7.get());
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/WorkQueue.cpp b/Tools/TestWebKitAPI/Tests/WTF/WorkQueue.cpp
new file mode 100644
index 000000000..74f5dc294
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/WorkQueue.cpp
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2015 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 "Test.h"
+#include <wtf/Condition.h>
+#include <wtf/Lock.h>
+#include <wtf/Vector.h>
+#include <wtf/WorkQueue.h>
+#include <string>
+#include <thread>
+
+namespace TestWebKitAPI {
+
+static const char* simpleTestLabel = "simpleTest";
+static const char* longTestLabel = "longTest";
+static const char* thirdTestLabel = "thirdTest";
+static const char* dispatchAfterLabel = "dispatchAfter";
+
+TEST(WTF_WorkQueue, Simple)
+{
+ Lock m_lock;
+ Condition m_testCompleted;
+ Vector<std::string> m_functionCallOrder;
+
+ bool calledSimpleTest = false;
+ bool calledLongTest = false;
+ bool calledThirdTest = false;
+
+ static const char* simpleTestLabel = "simpleTest";
+ static const char* longTestLabel = "longTest";
+ static const char* thirdTestLabel = "thirdTest";
+
+ auto queue = WorkQueue::create("com.apple.WebKit.Test.simple");
+ int initialRefCount = queue->refCount();
+ EXPECT_EQ(1, initialRefCount);
+
+ LockHolder locker(m_lock);
+ queue->dispatch([&](void) {
+ m_functionCallOrder.append(simpleTestLabel);
+ calledSimpleTest = true;
+ });
+
+ queue->dispatch([&](void) {
+ m_functionCallOrder.append(longTestLabel);
+ std::this_thread::sleep_for(std::chrono::nanoseconds(100));
+ calledLongTest = true;
+ });
+
+ queue->dispatch([&](void) {
+ LockHolder locker(m_lock);
+ m_functionCallOrder.append(thirdTestLabel);
+ calledThirdTest = true;
+
+ EXPECT_TRUE(calledSimpleTest);
+ EXPECT_TRUE(calledLongTest);
+ EXPECT_TRUE(calledThirdTest);
+
+ m_testCompleted.notifyOne();
+ });
+
+ EXPECT_GT(queue->refCount(), 1);
+
+ m_testCompleted.wait(m_lock);
+
+ EXPECT_TRUE(calledSimpleTest);
+ EXPECT_TRUE(calledLongTest);
+ EXPECT_TRUE(calledThirdTest);
+
+ EXPECT_EQ(static_cast<size_t>(3), m_functionCallOrder.size());
+ EXPECT_STREQ(simpleTestLabel, m_functionCallOrder[0].c_str());
+ EXPECT_STREQ(longTestLabel, m_functionCallOrder[1].c_str());
+ EXPECT_STREQ(thirdTestLabel, m_functionCallOrder[2].c_str());
+}
+
+TEST(WTF_WorkQueue, TwoQueues)
+{
+ Lock m_lock;
+ Condition m_testQueue1Completed, m_testQueue2Completed;
+ Vector<std::string> m_functionCallOrder;
+
+ bool calledSimpleTest = false;
+ bool calledLongTest = false;
+ bool calledThirdTest = false;
+
+ auto queue1 = WorkQueue::create("com.apple.WebKit.Test.twoQueues1");
+ auto queue2 = WorkQueue::create("com.apple.WebKit.Test.twoQueues2");
+
+ EXPECT_EQ(1, queue1->refCount());
+ EXPECT_EQ(1, queue2->refCount());
+
+ LockHolder locker(m_lock);
+
+ queue1->dispatch([&](void) {
+ m_functionCallOrder.append(simpleTestLabel);
+ calledSimpleTest = true;
+ });
+
+ queue2->dispatch([&](void) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(50));
+
+ LockHolder locker(m_lock);
+
+ // Will fail if queue2 took the mutex before queue1.
+ EXPECT_TRUE(calledThirdTest);
+
+ m_functionCallOrder.append(longTestLabel);
+ calledLongTest = true;
+ m_testQueue2Completed.notifyOne();
+ });
+
+ queue1->dispatch([&](void) {
+ LockHolder locker(m_lock);
+ m_functionCallOrder.append(thirdTestLabel);
+ calledThirdTest = true;
+
+ m_testQueue1Completed.notifyOne();
+ });
+
+ m_testQueue1Completed.wait(m_lock);
+
+ EXPECT_TRUE(calledSimpleTest);
+ EXPECT_FALSE(calledLongTest);
+ EXPECT_TRUE(calledThirdTest);
+
+ m_testQueue2Completed.wait(m_lock);
+
+ EXPECT_TRUE(calledSimpleTest);
+ EXPECT_TRUE(calledLongTest);
+ EXPECT_TRUE(calledThirdTest);
+
+ EXPECT_EQ(static_cast<size_t>(3), m_functionCallOrder.size());
+ EXPECT_STREQ(simpleTestLabel, m_functionCallOrder[0].c_str());
+ EXPECT_STREQ(thirdTestLabel, m_functionCallOrder[1].c_str());
+ EXPECT_STREQ(longTestLabel, m_functionCallOrder[2].c_str());
+}
+
+TEST(WTF_WorkQueue, DispatchAfter)
+{
+ Lock m_lock;
+ Condition m_testCompleted, m_dispatchAfterTestCompleted;
+ Vector<std::string> m_functionCallOrder;
+
+ bool calledSimpleTest = false;
+ bool calledDispatchAfterTest = false;
+
+ auto queue = WorkQueue::create("com.apple.WebKit.Test.dispatchAfter");
+
+ LockHolder locker(m_lock);
+
+ queue->dispatch([&](void) {
+ LockHolder locker(m_lock);
+ m_functionCallOrder.append(simpleTestLabel);
+ calledSimpleTest = true;
+ m_testCompleted.notifyOne();
+ });
+
+ queue->dispatchAfter(std::chrono::milliseconds(500), [&](void) {
+ LockHolder locker(m_lock);
+ m_functionCallOrder.append(dispatchAfterLabel);
+ calledDispatchAfterTest = true;
+ m_dispatchAfterTestCompleted.notifyOne();
+ });
+
+ m_testCompleted.wait(m_lock);
+
+ EXPECT_TRUE(calledSimpleTest);
+ EXPECT_FALSE(calledDispatchAfterTest);
+
+ m_dispatchAfterTestCompleted.wait(m_lock);
+
+ EXPECT_TRUE(calledSimpleTest);
+ EXPECT_TRUE(calledDispatchAfterTest);
+
+ EXPECT_EQ(static_cast<size_t>(2), m_functionCallOrder.size());
+ EXPECT_STREQ(simpleTestLabel, m_functionCallOrder[0].c_str());
+ EXPECT_STREQ(dispatchAfterLabel, m_functionCallOrder[1].c_str());
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/darwin/OSObjectPtr.cpp b/Tools/TestWebKitAPI/Tests/WTF/darwin/OSObjectPtr.cpp
new file mode 100644
index 000000000..5389dcbc8
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/darwin/OSObjectPtr.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2014 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 <wtf/OSObjectPtr.h>
+
+#include <dispatch/dispatch.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+namespace TestWebKitAPI {
+
+TEST(OSObjectPtr, AdoptOSObject)
+{
+ OSObjectPtr<dispatch_queue_t> foo = adoptOSObject(dispatch_queue_create(0, DISPATCH_QUEUE_SERIAL));
+
+ EXPECT_EQ(1, CFGetRetainCount(foo.get()));
+}
+
+TEST(OSObjectPtr, RetainRelease)
+{
+ dispatch_queue_t foo = dispatch_queue_create(0, DISPATCH_QUEUE_SERIAL);
+ EXPECT_EQ(1, CFGetRetainCount(foo));
+
+ WTF::retainOSObject(foo);
+ EXPECT_EQ(2, CFGetRetainCount(foo));
+
+ WTF::releaseOSObject(foo);
+ EXPECT_EQ(1, CFGetRetainCount(foo));
+}
+
+TEST(OSObjectPtr, LeakRef)
+{
+ OSObjectPtr<dispatch_queue_t> foo = adoptOSObject(dispatch_queue_create(0, DISPATCH_QUEUE_SERIAL));
+ EXPECT_EQ(1, CFGetRetainCount(foo.get()));
+
+ dispatch_queue_t queue = foo.leakRef();
+ EXPECT_EQ(nullptr, foo.get());
+ EXPECT_EQ(1, CFGetRetainCount(queue));
+
+ WTF::releaseOSObject(queue);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/glib/GMainLoopSource.cpp b/Tools/TestWebKitAPI/Tests/WTF/glib/GMainLoopSource.cpp
new file mode 100644
index 000000000..54991eeeb
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/glib/GMainLoopSource.cpp
@@ -0,0 +1,547 @@
+/*
+ * Copyright (C) 2014 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include <wtf/glib/GThreadSafeMainLoopSource.h>
+#include <stdio.h>
+
+namespace TestWebKitAPI {
+
+template <typename T>
+class GMainLoopSourceTest {
+public:
+ GMainLoopSourceTest()
+ : m_mainLoop(g_main_loop_new(nullptr, TRUE))
+ {
+ }
+
+ ~GMainLoopSourceTest()
+ {
+ g_main_loop_unref(m_mainLoop);
+ }
+
+ void runLoop()
+ {
+ g_main_loop_run(m_mainLoop);
+ }
+
+ void delayedFinish()
+ {
+ g_timeout_add(250,
+ [](gpointer data) {
+ GMainLoopSourceTest& test = *static_cast<GMainLoopSourceTest*>(data);
+ test.finish();
+ return G_SOURCE_REMOVE;
+ }, this);
+ }
+
+ void finish()
+ {
+ g_main_loop_quit(m_mainLoop);
+ }
+
+ T& source() { return m_source; }
+
+private:
+ GMainLoop* m_mainLoop;
+ T m_source;
+};
+
+template <typename T>
+static void basicRescheduling(T& context)
+{
+ EXPECT_TRUE(!context.test.source().isActive());
+
+ context.test.source().schedule("[Test] FirstTask", [&] {
+ // This should never be called. That's why we assert
+ // that the variable is false a few lines later.
+ context.finishedFirstTask = true;
+ });
+ EXPECT_TRUE(context.test.source().isScheduled());
+
+ context.test.source().schedule("[Test] SecondTask", [&] {
+ EXPECT_TRUE(context.test.source().isActive() && !context.test.source().isScheduled());
+ context.finishedSecondTask = true;
+ context.test.finish();
+ });
+ EXPECT_TRUE(context.test.source().isScheduled());
+
+ context.test.runLoop();
+
+ EXPECT_TRUE(!context.test.source().isActive());
+ EXPECT_FALSE(context.finishedFirstTask);
+ EXPECT_TRUE(context.finishedSecondTask);
+}
+
+TEST(WTF_GMainLoopSource, BasicRescheduling)
+{
+ struct TestingContext {
+ GMainLoopSourceTest<GMainLoopSource> test;
+ bool finishedFirstTask = false;
+ bool finishedSecondTask = false;
+ } context;
+ basicRescheduling<TestingContext>(context);
+
+ struct ThreadSafeTestingContext {
+ GMainLoopSourceTest<GThreadSafeMainLoopSource> test;
+ bool finishedFirstTask = false;
+ bool finishedSecondTask = false;
+ } threadSafeContext;
+ basicRescheduling<ThreadSafeTestingContext>(threadSafeContext);
+}
+
+template <typename T>
+static void reentrantRescheduling(T& context)
+{
+ EXPECT_TRUE(!context.test.source().isActive());
+
+ context.test.source().schedule("[Test] FirstTask", [&] {
+ EXPECT_TRUE(context.test.source().isActive() && !context.test.source().isScheduled());
+
+ context.test.source().schedule("[Test] SecondTask", [&] {
+ EXPECT_TRUE(context.test.source().isActive() && !context.test.source().isScheduled());
+ EXPECT_TRUE(context.finishedFirstTask);
+
+ context.finishedSecondTask = true;
+ context.test.finish();
+ });
+ EXPECT_TRUE(context.test.source().isScheduled());
+
+ context.finishedFirstTask = true;
+ });
+ EXPECT_TRUE(context.test.source().isScheduled());
+
+ context.test.runLoop();
+
+ EXPECT_TRUE(!context.test.source().isActive());
+ EXPECT_TRUE(context.finishedFirstTask);
+ EXPECT_TRUE(context.finishedSecondTask);
+}
+
+TEST(WTF_GMainLoopSource, ReentrantRescheduling)
+{
+ struct TestingContext {
+ GMainLoopSourceTest<GMainLoopSource> test;
+ bool finishedFirstTask = false;
+ bool finishedSecondTask = false;
+ } context;
+ reentrantRescheduling<TestingContext>(context);
+
+ struct ThreadSafeTestingContext {
+ GMainLoopSourceTest<GThreadSafeMainLoopSource> test;
+ bool finishedFirstTask = false;
+ bool finishedSecondTask = false;
+ } threadSafeContext;
+ reentrantRescheduling<ThreadSafeTestingContext>(threadSafeContext);
+}
+
+TEST(WTF_GMainLoopSource, ReschedulingFromDifferentThread)
+{
+ struct TestingContext {
+ GMainLoopSourceTest<GThreadSafeMainLoopSource> test;
+ bool finishedFirstTask;
+ bool finishedSecondTask;
+ } context;
+
+ EXPECT_TRUE(!context.test.source().isActive());
+
+ context.test.source().schedule("[Test] FirstTask", [&] {
+ EXPECT_TRUE(context.test.source().isActive() && !context.test.source().isScheduled());
+
+ g_usleep(1 * G_USEC_PER_SEC);
+ context.finishedFirstTask = true;
+ });
+ EXPECT_TRUE(context.test.source().isScheduled());
+
+ GThread* helperThread = g_thread_new(nullptr, [](gpointer data) -> gpointer {
+ g_usleep(0.25 * G_USEC_PER_SEC);
+
+ TestingContext& context = *static_cast<TestingContext*>(data);
+ EXPECT_TRUE(context.test.source().isActive() && !context.test.source().isScheduled());
+ EXPECT_FALSE(context.finishedFirstTask);
+
+ context.test.source().schedule("[Test] SecondTask", [&] {
+ EXPECT_TRUE(context.finishedFirstTask);
+
+ context.finishedSecondTask = true;
+ context.test.finish();
+ });
+ EXPECT_TRUE(context.test.source().isScheduled());
+
+ g_thread_exit(nullptr);
+ return nullptr;
+ }, &context);
+
+ context.test.runLoop();
+ g_thread_unref(helperThread);
+
+ EXPECT_TRUE(!context.test.source().isActive());
+ EXPECT_TRUE(context.finishedFirstTask);
+ EXPECT_TRUE(context.finishedSecondTask);
+}
+
+TEST(WTF_GMainLoopSource, DestructionDuringDispatch)
+{
+ // This is just a raw test that ensures deleting the GMainLoopSource object during
+ // dispatch does not cause problems. This test succeeds if it doesn't crash.
+
+ GMainLoopSource* source;
+ GMainLoop* loop = g_main_loop_new(nullptr, TRUE);
+
+ source = new GMainLoopSource;
+ source->schedule("[Test] DestroySourceTask", [&] {
+ delete source;
+ g_main_loop_quit(loop);
+ });
+ g_main_loop_run(loop);
+
+ source = new GMainLoopSource;
+ source->schedule("[Test] DestroySourceTask", std::function<bool ()>([&] {
+ delete source;
+ g_main_loop_quit(loop);
+ return false;
+ }));
+ g_main_loop_run(loop);
+
+ g_main_loop_unref(loop);
+}
+
+template <typename T>
+static void cancelRepeatingSourceDuringDispatch(T& context)
+{
+ EXPECT_TRUE(!context.test.source().isActive());
+
+ context.test.source().schedule("[Test] RepeatingTask",
+ std::function<bool ()>([&] {
+ EXPECT_TRUE(context.test.source().isActive() && !context.test.source().isScheduled());
+
+ context.callCount++;
+ if (context.callCount == 3)
+ context.test.source().cancel();
+ return true;
+ }));
+ EXPECT_TRUE(context.test.source().isScheduled());
+
+ context.test.delayedFinish();
+ context.test.runLoop();
+
+ EXPECT_TRUE(!context.test.source().isActive());
+ EXPECT_EQ(3, context.callCount);
+}
+
+TEST(WTF_GMainLoopSource, CancelRepeatingSourceDuringDispatch)
+{
+ struct TestingContext {
+ GMainLoopSourceTest<GMainLoopSource> test;
+ unsigned callCount = 0;
+ } context;
+ cancelRepeatingSourceDuringDispatch<TestingContext>(context);
+
+ struct ThreadSafeTestingContext {
+ GMainLoopSourceTest<GThreadSafeMainLoopSource> test;
+ unsigned callCount = 0;
+ } threadSafeContext;
+ cancelRepeatingSourceDuringDispatch<ThreadSafeTestingContext>(threadSafeContext);
+}
+
+template <typename T>
+static void basicDestroyCallbacks()
+{
+ {
+ T context;
+ EXPECT_TRUE(!context.test.source().isActive());
+ context.test.source().schedule("[Test] DestroyCallback",
+ [&] {
+ EXPECT_TRUE(context.test.source().isActive() && !context.test.source().isScheduled());
+ context.callbackCalled = true;
+ }, G_PRIORITY_DEFAULT,
+ [&] {
+ EXPECT_TRUE(!context.test.source().isActive());
+ context.destroyCallbackCalled = true;
+ context.test.finish();
+ });
+ EXPECT_TRUE(context.test.source().isScheduled());
+
+ context.test.runLoop();
+
+ EXPECT_TRUE(!context.test.source().isActive());
+ EXPECT_TRUE(context.callbackCalled);
+ EXPECT_TRUE(context.destroyCallbackCalled);
+ }
+
+ {
+ T context;
+ EXPECT_TRUE(!context.test.source().isActive());
+ context.test.source().schedule("[Test] DestroyCallback",
+ std::function<bool ()>([&] {
+ EXPECT_TRUE(context.test.source().isActive() && !context.test.source().isScheduled());
+ context.callbackCalled = true;
+ return false;
+ }), G_PRIORITY_DEFAULT,
+ [&] {
+ EXPECT_TRUE(!context.test.source().isActive());
+ context.destroyCallbackCalled = true;
+ context.test.finish();
+ });
+ EXPECT_TRUE(context.test.source().isScheduled());
+
+ context.test.runLoop();
+
+ EXPECT_TRUE(!context.test.source().isActive());
+ EXPECT_TRUE(context.callbackCalled);
+ EXPECT_TRUE(context.destroyCallbackCalled);
+ }
+}
+
+TEST(WTF_GMainLoopSource, BasicDestroyCallbacks)
+{
+ struct TestingContext {
+ GMainLoopSourceTest<GMainLoopSource> test;
+ bool callbackCalled = false;
+ bool destroyCallbackCalled = false;
+ };
+ basicDestroyCallbacks<TestingContext>();
+
+ struct ThreadSafeTestingContext {
+ GMainLoopSourceTest<GThreadSafeMainLoopSource> test;
+ bool callbackCalled = false;
+ bool destroyCallbackCalled = false;
+ };
+ basicDestroyCallbacks<ThreadSafeTestingContext>();
+}
+
+template <typename T>
+static void destroyCallbacksAfterCancellingDuringDispatch()
+{
+ {
+ T context;
+ EXPECT_TRUE(!context.test.source().isActive());
+ context.test.source().schedule("[Test] DestroyCallback",
+ [&] {
+ EXPECT_TRUE(context.test.source().isActive() && !context.test.source().isScheduled());
+ context.callbackCallCount++;
+ context.test.source().cancel();
+ }, G_PRIORITY_DEFAULT,
+ [&] {
+ EXPECT_TRUE(!context.test.source().isActive());
+ context.destroyCallbackCalled = true;
+ context.test.finish();
+ });
+ EXPECT_TRUE(context.test.source().isScheduled());
+
+ context.test.delayedFinish();
+ context.test.runLoop();
+
+ EXPECT_TRUE(!context.test.source().isActive());
+ EXPECT_EQ(1, context.callbackCallCount);
+ EXPECT_TRUE(context.destroyCallbackCalled);
+ }
+
+ {
+ T context;
+ EXPECT_TRUE(!context.test.source().isActive());
+ context.test.source().schedule("[Test] DestroyCallback",
+ std::function<bool ()>([&] {
+ EXPECT_TRUE(context.test.source().isActive() && !context.test.source().isScheduled());
+ context.callbackCallCount++;
+ if (context.callbackCallCount == 3)
+ context.test.source().cancel();
+ return true;
+ }), G_PRIORITY_DEFAULT,
+ [&] {
+ EXPECT_TRUE(!context.test.source().isActive());
+ context.destroyCallbackCalled = true;
+ });
+ EXPECT_TRUE(context.test.source().isScheduled());
+
+ context.test.delayedFinish();
+ context.test.runLoop();
+
+ EXPECT_TRUE(!context.test.source().isActive());
+ EXPECT_EQ(3, context.callbackCallCount);
+ EXPECT_TRUE(context.destroyCallbackCalled);
+ }
+}
+
+TEST(WTF_GMainLoopSource, DestroyCallbacksAfterCancellingDuringDispatch)
+{
+ struct TestingContext {
+ GMainLoopSourceTest<GMainLoopSource> test;
+ unsigned callbackCallCount= 0;
+ bool destroyCallbackCalled = false;
+ };
+ destroyCallbacksAfterCancellingDuringDispatch<TestingContext>();
+
+ struct ThreadSafeTestingContext {
+ GMainLoopSourceTest<GThreadSafeMainLoopSource> test;
+ unsigned callbackCallCount= 0;
+ bool destroyCallbackCalled = false;
+ };
+ destroyCallbacksAfterCancellingDuringDispatch<ThreadSafeTestingContext>();
+}
+
+template <typename T>
+static void destroyCallbacksAfterReschedulingDuringDispatch()
+{
+ {
+ T context;
+ EXPECT_TRUE(!context.test.source().isActive());
+ context.test.source().schedule("[Test] BaseCallback",
+ [&] {
+ EXPECT_TRUE(context.test.source().isActive() && !context.test.source().isScheduled());
+ context.firstCallbackCallCount++;
+ context.test.source().schedule("[Test] ReschedulingCallback",
+ [&] {
+ EXPECT_TRUE(context.test.source().isActive() && !context.test.source().isScheduled());
+ context.secondCallbackCallCount++;
+ }, G_PRIORITY_DEFAULT,
+ [&] {
+ EXPECT_TRUE(!context.test.source().isActive());
+ context.secondDestroyCallbackCalled = true;
+ });
+ EXPECT_TRUE(context.test.source().isScheduled());
+ }, G_PRIORITY_DEFAULT,
+ [&] {
+ // At this point the GMainLoopSource has been rescheduled, ergo the Scheduled status.
+ EXPECT_TRUE(context.test.source().isScheduled());
+ context.firstDestroyCallbackCalled = true;
+ });
+ EXPECT_TRUE(context.test.source().isScheduled());
+
+ context.test.delayedFinish();
+ context.test.runLoop();
+
+ EXPECT_TRUE(!context.test.source().isActive());
+ EXPECT_EQ(1, context.firstCallbackCallCount);
+ EXPECT_TRUE(context.firstDestroyCallbackCalled);
+ EXPECT_EQ(1, context.secondCallbackCallCount);
+ EXPECT_TRUE(context.secondDestroyCallbackCalled);
+ }
+
+ {
+ T context;
+ EXPECT_TRUE(!context.test.source().isActive());
+ context.test.source().schedule("[Test] BaseCallback",
+ std::function<bool ()>([&] {
+ EXPECT_TRUE(context.test.source().isActive() && !context.test.source().isScheduled());
+ context.firstCallbackCallCount++;
+ context.test.source().schedule("[Test] ReschedulingCallback",
+ std::function<bool ()>([&] {
+ EXPECT_TRUE(context.test.source().isActive() && !context.test.source().isScheduled());
+ context.secondCallbackCallCount++;
+ return context.secondCallbackCallCount != 3;
+ }), G_PRIORITY_DEFAULT,
+ [&] {
+ EXPECT_TRUE(!context.test.source().isActive());
+ context.secondDestroyCallbackCalled = true;
+ });
+ EXPECT_TRUE(context.test.source().isScheduled());
+ return true;
+ }), G_PRIORITY_DEFAULT,
+ [&] {
+ // At this point the GMainLoopSource has been rescheduled, ergo the Scheduled status.
+ EXPECT_TRUE(context.test.source().isScheduled());
+ context.firstDestroyCallbackCalled = true;
+ });
+ EXPECT_TRUE(context.test.source().isScheduled());
+
+ context.test.delayedFinish();
+ context.test.runLoop();
+
+ EXPECT_TRUE(!context.test.source().isActive());
+ EXPECT_EQ(1, context.firstCallbackCallCount);
+ EXPECT_TRUE(context.firstDestroyCallbackCalled);
+ EXPECT_EQ(3, context.secondCallbackCallCount);
+ EXPECT_TRUE(context.secondDestroyCallbackCalled);
+ }
+}
+
+TEST(WTF_GMainLoopSource, DestroyCallbacksAfterReschedulingDuringDispatch)
+{
+ struct TestingContext {
+ GMainLoopSourceTest<GMainLoopSource> test;
+ unsigned firstCallbackCallCount = 0;
+ bool firstDestroyCallbackCalled = false;
+ unsigned secondCallbackCallCount = 0;
+ bool secondDestroyCallbackCalled = false;
+ };
+ destroyCallbacksAfterReschedulingDuringDispatch<TestingContext>();
+
+ struct ThreadSafeTestingContext {
+ GMainLoopSourceTest<GThreadSafeMainLoopSource> test;
+ unsigned firstCallbackCallCount = 0;
+ bool firstDestroyCallbackCalled = false;
+ unsigned secondCallbackCallCount = 0;
+ bool secondDestroyCallbackCalled = false;
+ };
+ destroyCallbacksAfterReschedulingDuringDispatch<ThreadSafeTestingContext>();
+}
+
+TEST(WTF_GMainLoopSource, DeleteOnDestroySources)
+{
+ // Testing the delete-on-destroy sources is very limited. There's no good way
+ // of testing that the GMainLoopSource objects are deleted when their GSource
+ // is destroyed.
+
+ struct TestingContext {
+ GMainLoopSourceTest<GMainLoopSource> test;
+ unsigned callbackCallCount = 0;
+ bool destroyCallbackCalled = false;
+ } context;
+
+ {
+ TestingContext context;
+
+ GMainLoopSource::scheduleAndDeleteOnDestroy("[Test] DeleteOnDestroy",
+ [&] {
+ context.callbackCallCount++;
+ }, G_PRIORITY_DEFAULT,
+ [&] {
+ EXPECT_FALSE(context.destroyCallbackCalled);
+ context.destroyCallbackCalled = true;
+ });
+
+ context.test.delayedFinish();
+ context.test.runLoop();
+ EXPECT_EQ(1, context.callbackCallCount);
+ EXPECT_TRUE(context.destroyCallbackCalled);
+ }
+
+ {
+ TestingContext context;
+
+ GMainLoopSource::scheduleAndDeleteOnDestroy("[Test] DeleteOnDestroy",
+ std::function<bool ()>([&] {
+ context.callbackCallCount++;
+ return context.callbackCallCount != 3;
+ }), G_PRIORITY_DEFAULT,
+ [&] {
+ EXPECT_FALSE(context.destroyCallbackCalled);
+ context.destroyCallbackCalled = true;
+ });
+
+ context.test.delayedFinish();
+ context.test.runLoop();
+ EXPECT_EQ(3, context.callbackCallCount);
+ EXPECT_TRUE(context.destroyCallbackCalled);
+ }
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/glib/GUniquePtr.cpp b/Tools/TestWebKitAPI/Tests/WTF/glib/GUniquePtr.cpp
new file mode 100644
index 000000000..11f02c7b0
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/glib/GUniquePtr.cpp
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2014 Igalia S.L.
+ *
+ * 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 <gio/gio.h>
+
+inline std::ostringstream& log()
+{
+ static std::ostringstream log;
+ return log;
+}
+
+inline std::string takeLogStr()
+{
+ std::string string = log().str();
+ log().str("");
+ return string;
+}
+
+static void (* _g_free)(void*) = g_free;
+#define g_free(x) \
+ log() << "g_free(" << ptr << ");"; \
+ _g_free(x);
+
+static void (* _g_error_free)(GError*) = g_error_free;
+#define g_error_free(x) \
+ log() << "g_error_free(" << ptr << ");"; \
+ _g_error_free(x);
+
+static void (* _g_list_free)(GList*) = g_list_free;
+#define g_list_free(x) \
+ log() << "g_list_free(" << ptr << ");"; \
+ _g_list_free(x);
+
+static void (* _g_slist_free)(GSList*) = g_slist_free;
+#define g_slist_free(x) \
+ log() << "g_slist_free(" << ptr << ");"; \
+ _g_slist_free(x);
+
+static void (* _g_pattern_spec_free)(GPatternSpec*) = g_pattern_spec_free;
+#define g_pattern_spec_free(x) \
+ log() << "g_pattern_spec_free(" << ptr << ");"; \
+ _g_pattern_spec_free(x);
+
+static void (* _g_dir_close)(GDir*) = g_dir_close;
+#define g_dir_close(x) \
+ log() << "g_dir_close(" << ptr << ");"; \
+ _g_dir_close(x);
+
+static void (* _g_timer_destroy)(GTimer*) = g_timer_destroy;
+#define g_timer_destroy(x) \
+ log() << "g_timer_destroy(" << ptr << ");"; \
+ _g_timer_destroy(x);
+
+static void (* _g_key_file_free)(GKeyFile*) = g_key_file_free;
+#define g_key_file_free(x) \
+ log() << "g_key_file_free(" << ptr << ");"; \
+ _g_key_file_free(x);
+
+#include <wtf/glib/GUniquePtr.h>
+
+namespace TestWebKitAPI {
+
+TEST(WTF_GUniquePtr, Basic)
+{
+ std::ostringstream actual;
+
+ {
+ GUniquePtr<char> a(g_strdup("a"));
+ actual << "g_free(" << a.get() << ");";
+ }
+ ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str());
+ actual.str("");
+
+ {
+ GUniquePtr<GError> a(g_error_new_literal(G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "a"));
+ actual << "g_error_free(" << a.get() << ");";
+ }
+ ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str());
+ actual.str("");
+
+ {
+ GUniquePtr<GList> a(g_list_prepend(nullptr, g_strdup("a")));
+ actual << "g_list_free(" << a.get() << ");";
+ }
+ ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str());
+ actual.str("");
+
+ {
+ GUniquePtr<GSList> a(g_slist_prepend(nullptr, g_strdup("a")));
+ actual << "g_slist_free(" << a.get() << ");";
+ }
+ ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str());
+ actual.str("");
+
+ {
+ GUniquePtr<GPatternSpec> a(g_pattern_spec_new("a"));
+ actual << "g_pattern_spec_free(" << a.get() << ");";
+ }
+ ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str());
+ actual.str("");
+
+ {
+ GUniquePtr<GDir> a(g_dir_open("/tmp", 0, nullptr));
+ actual << "g_dir_close(" << a.get() << ");";
+ }
+ ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str());
+ actual.str("");
+
+ {
+ GUniquePtr<GTimer> a(g_timer_new());
+ actual << "g_timer_destroy(" << a.get() << ");";
+ }
+ ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str());
+ actual.str("");
+
+ {
+ GUniquePtr<GKeyFile> a(g_key_file_new());
+ actual << "g_key_file_free(" << a.get() << ");";
+ }
+ ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str());
+ actual.str("");
+}
+
+static void returnOutChar(char** outChar)
+{
+ *outChar = g_strdup("a");
+}
+
+TEST(WTF_GUniquePtr, OutPtr)
+{
+ std::ostringstream actual;
+
+ {
+ GUniqueOutPtr<char> a;
+ ASSERT_EQ(nullptr, a.get());
+ }
+ ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str());
+ actual.str("");
+
+ {
+ GUniqueOutPtr<char> a;
+ returnOutChar(&a.outPtr());
+ actual << "g_free(" << a.get() << ");";
+ }
+ ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str());
+ actual.str("");
+
+ {
+ GUniqueOutPtr<char> a;
+ returnOutChar(&a.outPtr());
+ actual << "g_free(" << a.get() << ");";
+ returnOutChar(&a.outPtr());
+ ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str());
+ actual.str("");
+ actual << "g_free(" << a.get() << ");";
+ }
+ ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str());
+ actual.str("");
+
+ {
+ GUniqueOutPtr<char> a;
+ returnOutChar(&a.outPtr());
+ GUniquePtr<char> b = a.release();
+ ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str());
+ actual << "g_free(" << b.get() << ");";
+ }
+ ASSERT_STREQ(actual.str().c_str(), takeLogStr().c_str());
+ actual.str("");
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WTF/glib/WorkQueueGLib.cpp b/Tools/TestWebKitAPI/Tests/WTF/glib/WorkQueueGLib.cpp
new file mode 100644
index 000000000..9923d6580
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/glib/WorkQueueGLib.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2015 Igalia S.L.
+ *
+ * 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 "Test.h"
+#include <gio/gio.h>
+#include <thread>
+#include <wtf/Condition.h>
+#include <wtf/Lock.h>
+#include <wtf/WorkQueue.h>
+#include <wtf/glib/GRefPtr.h>
+#include <wtf/glib/GUniquePtr.h>
+
+namespace TestWebKitAPI {
+
+TEST(WTF_WorkQueue, AsyncIO)
+{
+ struct TestingContext {
+ Lock m_lock;
+ Condition m_testCompleted;
+ GMainContext* m_mainContext;
+ } context;
+
+ auto queue = WorkQueue::create("com.apple.WebKit.Test.AsyncIO");
+ context.m_mainContext = g_main_context_default();
+ EXPECT_FALSE(g_main_context_get_thread_default());
+
+ GUniquePtr<char> currentDirectory(g_get_current_dir());
+ GRefPtr<GFile> file = adoptGRef(g_file_new_for_path(currentDirectory.get()));
+
+ LockHolder locker(context.m_lock);
+ queue->dispatch([&](void) {
+ EXPECT_TRUE(g_main_context_get_thread_default());
+ EXPECT_TRUE(g_main_context_get_thread_default() != context.m_mainContext);
+ context.m_mainContext = g_main_context_get_thread_default();
+ g_file_query_info_async(file.get(), G_FILE_ATTRIBUTE_STANDARD_SIZE, G_FILE_QUERY_INFO_NONE, G_PRIORITY_DEFAULT, nullptr,
+ [](GObject*, GAsyncResult*, gpointer userData) {
+ TestingContext* context = static_cast<TestingContext*>(userData);
+ LockHolder locker(context->m_lock);
+ EXPECT_EQ(g_main_context_get_thread_default(), context->m_mainContext);
+ context->m_testCompleted.notifyOne();
+ }, &context);
+ });
+
+ context.m_testCompleted.wait(context.m_lock);
+}
+
+} // namespace TestWebKitAPI