Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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);
}