summaryrefslogtreecommitdiffstats
path: root/xpcom/tests/gtest/TestMruCache.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xpcom/tests/gtest/TestMruCache.cpp')
-rw-r--r--xpcom/tests/gtest/TestMruCache.cpp395
1 files changed, 395 insertions, 0 deletions
diff --git a/xpcom/tests/gtest/TestMruCache.cpp b/xpcom/tests/gtest/TestMruCache.cpp
new file mode 100644
index 0000000000..8cf97408d1
--- /dev/null
+++ b/xpcom/tests/gtest/TestMruCache.cpp
@@ -0,0 +1,395 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gtest/gtest.h"
+
+#include "mozilla/MruCache.h"
+#include "nsString.h"
+
+using namespace mozilla;
+
+// A few MruCache implementations to use during testing.
+struct IntMap : public MruCache<int, int, IntMap> {
+ static HashNumber Hash(const KeyType& aKey) { return aKey - 1; }
+ static bool Match(const KeyType& aKey, const ValueType& aVal) {
+ return aKey == aVal;
+ }
+};
+
+struct UintPtrMap : public MruCache<uintptr_t, int*, UintPtrMap> {
+ static HashNumber Hash(const KeyType& aKey) { return aKey - 1; }
+ static bool Match(const KeyType& aKey, const ValueType& aVal) {
+ return aKey == (KeyType)aVal;
+ }
+};
+
+struct StringStruct {
+ nsCString mKey;
+ nsCString mOther;
+};
+
+struct StringStructMap
+ : public MruCache<nsCString, StringStruct, StringStructMap> {
+ static HashNumber Hash(const KeyType& aKey) {
+ return *aKey.BeginReading() - 1;
+ }
+ static bool Match(const KeyType& aKey, const ValueType& aVal) {
+ return aKey == aVal.mKey;
+ }
+};
+
+// Helper for emulating convertable holders such as RefPtr.
+template <typename T>
+struct Convertable {
+ T mItem;
+ operator T() const { return mItem; }
+};
+
+// Helper to create a StringStructMap key.
+static nsCString MakeStringKey(char aKey) {
+ nsCString key;
+ key.Append(aKey);
+ return key;
+}
+
+TEST(MruCache, TestNullChecker)
+{
+ using mozilla::detail::EmptyChecker;
+
+ {
+ int test = 0;
+ EXPECT_TRUE(EmptyChecker<decltype(test)>::IsNotEmpty(test));
+
+ test = 42;
+ EXPECT_TRUE(EmptyChecker<decltype(test)>::IsNotEmpty(test));
+ }
+
+ {
+ const char* test = "abc";
+ EXPECT_TRUE(EmptyChecker<decltype(test)>::IsNotEmpty(test));
+
+ test = nullptr;
+ EXPECT_FALSE(EmptyChecker<decltype(test)>::IsNotEmpty(test));
+ }
+
+ {
+ int foo = 42;
+ int* test = &foo;
+ EXPECT_TRUE(EmptyChecker<decltype(test)>::IsNotEmpty(test));
+
+ test = nullptr;
+ EXPECT_FALSE(EmptyChecker<decltype(test)>::IsNotEmpty(test));
+ }
+}
+
+TEST(MruCache, TestEmptyCache)
+{
+ {
+ // Test a basic empty cache.
+ IntMap mru;
+
+ // Make sure the default values are set.
+ for (int i = 1; i < 32; i++) {
+ auto p = mru.Lookup(i);
+
+ // Shouldn't be found.
+ EXPECT_FALSE(p);
+ }
+ }
+
+ {
+ // Test an empty cache with pointer values.
+ UintPtrMap mru;
+
+ // Make sure the default values are set.
+ for (uintptr_t i = 1; i < 32; i++) {
+ auto p = mru.Lookup(i);
+
+ // Shouldn't be found.
+ EXPECT_FALSE(p);
+ }
+ }
+
+ {
+ // Test an empty cache with more complex structure.
+ StringStructMap mru;
+
+ // Make sure the default values are set.
+ for (char i = 1; i < 32; i++) {
+ const nsCString key = MakeStringKey(i);
+ auto p = mru.Lookup(key);
+
+ // Shouldn't be found.
+ EXPECT_FALSE(p);
+ }
+ }
+}
+
+TEST(MruCache, TestPut)
+{
+ IntMap mru;
+
+ // Fill it up.
+ for (int i = 1; i < 32; i++) {
+ mru.Put(i, i);
+ }
+
+ // Now check each value.
+ for (int i = 1; i < 32; i++) {
+ auto p = mru.Lookup(i);
+
+ // Should be found.
+ EXPECT_TRUE(p);
+ EXPECT_EQ(p.Data(), i);
+ }
+}
+
+TEST(MruCache, TestPutConvertable)
+{
+ UintPtrMap mru;
+
+ // Fill it up.
+ for (uintptr_t i = 1; i < 32; i++) {
+ Convertable<int*> val{(int*)i};
+ mru.Put(i, val);
+ }
+
+ // Now check each value.
+ for (uintptr_t i = 1; i < 32; i++) {
+ auto p = mru.Lookup(i);
+
+ // Should be found.
+ EXPECT_TRUE(p);
+ EXPECT_EQ(p.Data(), (int*)i);
+ }
+}
+
+TEST(MruCache, TestOverwriting)
+{
+ // Test overwrting
+ IntMap mru;
+
+ // 1-31 should be overwritten by 32-63
+ for (int i = 1; i < 63; i++) {
+ mru.Put(i, i);
+ }
+
+ // Look them up.
+ for (int i = 32; i < 63; i++) {
+ auto p = mru.Lookup(i);
+
+ // Should be found.
+ EXPECT_TRUE(p);
+ EXPECT_EQ(p.Data(), i);
+ }
+}
+
+TEST(MruCache, TestRemove)
+{
+ {
+ IntMap mru;
+
+ // Fill it up.
+ for (int i = 1; i < 32; i++) {
+ mru.Put(i, i);
+ }
+
+ // Now remove each value.
+ for (int i = 1; i < 32; i++) {
+ // Should be present.
+ auto p = mru.Lookup(i);
+ EXPECT_TRUE(p);
+
+ mru.Remove(i);
+
+ // Should no longer match.
+ p = mru.Lookup(i);
+ EXPECT_FALSE(p);
+ }
+ }
+
+ {
+ UintPtrMap mru;
+
+ // Fill it up.
+ for (uintptr_t i = 1; i < 32; i++) {
+ mru.Put(i, (int*)i);
+ }
+
+ // Now remove each value.
+ for (uintptr_t i = 1; i < 32; i++) {
+ // Should be present.
+ auto p = mru.Lookup(i);
+ EXPECT_TRUE(p);
+
+ mru.Remove(i);
+
+ // Should no longer match.
+ p = mru.Lookup(i);
+ EXPECT_FALSE(p);
+ }
+ }
+
+ {
+ StringStructMap mru;
+
+ // Fill it up.
+ for (char i = 1; i < 32; i++) {
+ const nsCString key = MakeStringKey(i);
+ mru.Put(key, StringStruct{key, "foo"_ns});
+ }
+
+ // Now remove each value.
+ for (char i = 1; i < 32; i++) {
+ const nsCString key = MakeStringKey(i);
+
+ // Should be present.
+ auto p = mru.Lookup(key);
+ EXPECT_TRUE(p);
+
+ mru.Remove(key);
+
+ // Should no longer match.
+ p = mru.Lookup(key);
+ EXPECT_FALSE(p);
+ }
+ }
+}
+
+TEST(MruCache, TestClear)
+{
+ IntMap mru;
+
+ // Fill it up.
+ for (int i = 1; i < 32; i++) {
+ mru.Put(i, i);
+ }
+
+ // Empty it.
+ mru.Clear();
+
+ // Now check each value.
+ for (int i = 1; i < 32; i++) {
+ auto p = mru.Lookup(i);
+
+ // Should not be found.
+ EXPECT_FALSE(p);
+ }
+}
+
+TEST(MruCache, TestLookupMissingAndSet)
+{
+ IntMap mru;
+
+ // Value not found.
+ auto p = mru.Lookup(1);
+ EXPECT_FALSE(p);
+
+ // Set it.
+ p.Set(1);
+ EXPECT_TRUE(p);
+ EXPECT_EQ(p.Data(), 1);
+
+ // Look it up again.
+ p = mru.Lookup(1);
+ EXPECT_TRUE(p);
+ EXPECT_EQ(p.Data(), 1);
+
+ // Test w/ a convertable value.
+ p = mru.Lookup(2);
+ EXPECT_FALSE(p);
+
+ // Set it.
+ Convertable<int> val{2};
+ p.Set(val);
+ EXPECT_TRUE(p);
+ EXPECT_EQ(p.Data(), 2);
+
+ // Look it up again.
+ p = mru.Lookup(2);
+ EXPECT_TRUE(p);
+ EXPECT_EQ(p.Data(), 2);
+}
+
+TEST(MruCache, TestLookupAndOverwrite)
+{
+ IntMap mru;
+
+ // Set 1.
+ mru.Put(1, 1);
+
+ // Lookup a key that maps the 1's entry.
+ auto p = mru.Lookup(32);
+ EXPECT_FALSE(p); // not a match
+
+ // Now overwrite the entry.
+ p.Set(32);
+ EXPECT_TRUE(p);
+ EXPECT_EQ(p.Data(), 32);
+
+ // 1 should be gone now.
+ p = mru.Lookup(1);
+ EXPECT_FALSE(p);
+
+ // 32 should be found.
+ p = mru.Lookup(32);
+ EXPECT_TRUE(p);
+ EXPECT_EQ(p.Data(), 32);
+}
+
+TEST(MruCache, TestLookupAndRemove)
+{
+ IntMap mru;
+
+ // Set 1.
+ mru.Put(1, 1);
+
+ auto p = mru.Lookup(1);
+ EXPECT_TRUE(p);
+ EXPECT_EQ(p.Data(), 1);
+
+ // Now remove it.
+ p.Remove();
+ EXPECT_FALSE(p);
+
+ p = mru.Lookup(1);
+ EXPECT_FALSE(p);
+}
+
+TEST(MruCache, TestLookupNotMatchedAndRemove)
+{
+ IntMap mru;
+
+ // Set 1.
+ mru.Put(1, 1);
+
+ // Lookup a key that matches 1's entry.
+ auto p = mru.Lookup(32);
+ EXPECT_FALSE(p);
+
+ // Now attempt to remove it.
+ p.Remove();
+
+ // Make sure 1 is still there.
+ p = mru.Lookup(1);
+ EXPECT_TRUE(p);
+ EXPECT_EQ(p.Data(), 1);
+}
+
+TEST(MruCache, TestLookupAndSetWithMove)
+{
+ StringStructMap mru;
+
+ const nsCString key = MakeStringKey((char)1);
+ StringStruct val{key, "foo"_ns};
+
+ auto p = mru.Lookup(key);
+ EXPECT_FALSE(p);
+ p.Set(std::move(val));
+
+ EXPECT_TRUE(p.Data().mKey == key);
+ EXPECT_TRUE(p.Data().mOther == "foo"_ns);
+}