/* -*- 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 { 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 { 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 { 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 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::IsNotEmpty(test)); test = 42; EXPECT_TRUE(EmptyChecker::IsNotEmpty(test)); } { const char* test = "abc"; EXPECT_TRUE(EmptyChecker::IsNotEmpty(test)); test = nullptr; EXPECT_FALSE(EmptyChecker::IsNotEmpty(test)); } { int foo = 42; int* test = &foo; EXPECT_TRUE(EmptyChecker::IsNotEmpty(test)); test = nullptr; EXPECT_FALSE(EmptyChecker::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 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 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); }