Something went wrong. Try again.
OpenMW is an open implementation of the Morrowind engine
Something went wrong. Try again.
16 kB · 417 lines
C++
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418#include <components/resource/objectcache.hpp>
#include <gmock/gmock.h>#include <gtest/gtest.h>
#include <memory>
#include <osg/Object>
namespace Resource{ namespace { using namespace ::testing;
using ObjectCache = GenericObjectCache<int, osg::ref_ptr<osg::Object>>; using StringObjectCache = GenericObjectCache<std::string, osg::ref_ptr<osg::Object>>;
// The point of the value type parameter: a type that derives from nothing at all // is cacheable, and expiry still knows whether anything outside holds it. using SharedCache = GenericObjectCache<int, std::shared_ptr<const std::string>>;
TEST(ResourceGenericObjectCacheTest, getRefFromObjectCacheShouldReturnNullptrByDefault) { ObjectCache cache; EXPECT_EQ(cache.getRefFromObjectCache(42), nullptr); }
TEST(ResourceGenericObjectCacheTest, getRefFromObjectCacheOrNoneShouldReturnNulloptByDefault) { ObjectCache cache; EXPECT_EQ(cache.getRefFromObjectCacheOrNone(42), std::nullopt); }
struct Object : osg::Object { Object() = default;
Object(const Object& other, const osg::CopyOp& copyOp = osg::CopyOp()) : osg::Object(other, copyOp) { }
META_Object(ResourceTest, Object) };
TEST(ResourceGenericObjectCacheTest, shouldStoreValuesThatAreNotOsgObjects) { SharedCache cache; const auto value = std::make_shared<const std::string>("value"); cache.addEntryToObjectCache(42, value); EXPECT_EQ(cache.getRefFromObjectCache(42), value); }
TEST(ResourceGenericObjectCacheTest, updateShouldNotDereferenceNullValues) { ObjectCache cache; cache.addEntryToObjectCache(42, nullptr); cache.update(1000, 1); EXPECT_THAT(cache.getRefFromObjectCacheOrNone(42), Optional(nullptr)); }
TEST(ResourceGenericObjectCacheTest, updateShouldKeepSharedPtrValuesHeldElsewhere) { SharedCache cache; const auto held = std::make_shared<const std::string>("held"); cache.addEntryToObjectCache(1, held); cache.addEntryToObjectCache(2, std::make_shared<const std::string>("dropped"));
const double referenceTime = 1000; cache.update(referenceTime, 1); cache.update(referenceTime + 10, 1);
EXPECT_THAT(cache.getRefFromObjectCacheOrNone(1), Optional(held)); EXPECT_EQ(cache.getRefFromObjectCacheOrNone(2), std::nullopt); }
TEST(ResourceGenericObjectCacheTest, shouldStoreValues) { ObjectCache cache; const int key = 42; osg::ref_ptr<Object> value(new Object); cache.addEntryToObjectCache(key, value); EXPECT_EQ(cache.getRefFromObjectCache(key), value); }
TEST(ResourceGenericObjectCacheTest, shouldStoreNullptrValues) { ObjectCache cache; const int key = 42; cache.addEntryToObjectCache(key, nullptr); EXPECT_THAT(cache.getRefFromObjectCacheOrNone(key), Optional(nullptr)); }
TEST(ResourceGenericObjectCacheTest, updateShouldExtendLifetimeForItemsWithZeroTimestamp) { ObjectCache cache;
const int key = 42; osg::ref_ptr<Object> value(new Object); cache.addEntryToObjectCache(key, value, 0); value = nullptr;
const double referenceTime = 1000; const double expiryDelay = 1; cache.update(referenceTime, expiryDelay); EXPECT_THAT(cache.getRefFromObjectCacheOrNone(key), Optional(_)); }
TEST(ResourceGenericObjectCacheTest, addEntryToObjectCacheShouldReplaceExistingItemByKey) { ObjectCache cache;
const int key = 42; osg::ref_ptr<Object> value1(new Object); osg::ref_ptr<Object> value2(new Object); cache.addEntryToObjectCache(key, value1); ASSERT_EQ(cache.getRefFromObjectCache(key), value1); cache.addEntryToObjectCache(key, value2); EXPECT_EQ(cache.getRefFromObjectCache(key), value2); }
TEST(ResourceGenericObjectCacheTest, addEntryToObjectCacheShouldMarkLifetime) { ObjectCache cache;
const double referenceTime = 1; const double expiryDelay = 2;
const int key = 42; cache.addEntryToObjectCache(key, nullptr, referenceTime + expiryDelay);
cache.update(referenceTime, expiryDelay); ASSERT_THAT(cache.getRefFromObjectCacheOrNone(key), Optional(_));
cache.update(referenceTime + expiryDelay, expiryDelay); ASSERT_THAT(cache.getRefFromObjectCacheOrNone(key), Optional(_));
cache.update(referenceTime + 2 * expiryDelay, expiryDelay); EXPECT_EQ(cache.getRefFromObjectCacheOrNone(key), std::nullopt); }
TEST(ResourceGenericObjectCacheTest, updateShouldRemoveExpiredItems) { ObjectCache cache;
const double referenceTime = 1; const double expiryDelay = 1;
const int key = 42; osg::ref_ptr<Object> value(new Object); cache.addEntryToObjectCache(key, value); value = nullptr;
cache.update(referenceTime, expiryDelay); ASSERT_THAT(cache.getRefFromObjectCacheOrNone(key), Optional(_)); ASSERT_EQ(cache.getStats().mExpired, 0);
cache.update(referenceTime + expiryDelay, expiryDelay); EXPECT_EQ(cache.getRefFromObjectCacheOrNone(key), std::nullopt); ASSERT_EQ(cache.getStats().mExpired, 1); }
TEST(ResourceGenericObjectCacheTest, updateShouldKeepExternallyReferencedItems) { ObjectCache cache;
const double referenceTime = 1; const double expiryDelay = 1;
const int key = 42; osg::ref_ptr<Object> value(new Object); cache.addEntryToObjectCache(key, value);
cache.update(referenceTime, expiryDelay); ASSERT_THAT(cache.getRefFromObjectCacheOrNone(key), Optional(_));
cache.update(referenceTime + expiryDelay, expiryDelay); EXPECT_THAT(cache.getRefFromObjectCacheOrNone(key), Optional(value)); }
TEST(ResourceGenericObjectCacheTest, updateShouldKeepNotExpiredItems) { ObjectCache cache;
const double referenceTime = 1; const double expiryDelay = 2;
const int key = 42; osg::ref_ptr<Object> value(new Object); cache.addEntryToObjectCache(key, value); value = nullptr;
cache.update(referenceTime + expiryDelay, expiryDelay); ASSERT_THAT(cache.getRefFromObjectCacheOrNone(key), Optional(_));
cache.update(referenceTime + expiryDelay / 2, expiryDelay); EXPECT_THAT(cache.getRefFromObjectCacheOrNone(key), Optional(_)); }
TEST(ResourceGenericObjectCacheTest, updateShouldKeepNotExpiredNullptrItems) { ObjectCache cache;
const double referenceTime = 1; const double expiryDelay = 2;
const int key = 42; cache.addEntryToObjectCache(key, nullptr);
cache.update(referenceTime + expiryDelay, expiryDelay); ASSERT_THAT(cache.getRefFromObjectCacheOrNone(key), Optional(_));
cache.update(referenceTime + expiryDelay / 2, expiryDelay); EXPECT_THAT(cache.getRefFromObjectCacheOrNone(key), Optional(_)); }
TEST(ResourceGenericObjectCacheTest, getRefFromObjectCacheOrNoneShouldNotExtendItemLifetime) { ObjectCache cache;
const double referenceTime = 1; const double expiryDelay = 2;
const int key = 42; cache.addEntryToObjectCache(key, nullptr);
cache.update(referenceTime, expiryDelay); ASSERT_THAT(cache.getRefFromObjectCacheOrNone(key), Optional(_));
cache.update(referenceTime + expiryDelay / 2, expiryDelay); ASSERT_THAT(cache.getRefFromObjectCacheOrNone(key), Optional(_));
cache.update(referenceTime + expiryDelay, expiryDelay); EXPECT_EQ(cache.getRefFromObjectCacheOrNone(key), std::nullopt); }
TEST(ResourceGenericObjectCacheTest, lowerBoundShouldSupportHeterogeneousLookup) { StringObjectCache cache; cache.addEntryToObjectCache("a", nullptr); cache.addEntryToObjectCache("c", nullptr); EXPECT_THAT(cache.lowerBound(std::string_view("b")), Optional(Pair("c", _))); }
TEST(ResourceGenericObjectCacheTest, shouldSupportRemovingItems) { ObjectCache cache; const int key = 42; osg::ref_ptr<Object> value(new Object); cache.addEntryToObjectCache(key, value); ASSERT_EQ(cache.getRefFromObjectCache(key), value); cache.removeFromObjectCache(key); EXPECT_EQ(cache.getRefFromObjectCacheOrNone(key), std::nullopt); }
TEST(ResourceGenericObjectCacheTest, clearShouldRemoveAllItems) { ObjectCache cache;
const int key1 = 42; const int key2 = 13; osg::ref_ptr<Object> value1(new Object); osg::ref_ptr<Object> value2(new Object); cache.addEntryToObjectCache(key1, value1); cache.addEntryToObjectCache(key2, value2);
ASSERT_EQ(cache.getRefFromObjectCache(key1), value1); ASSERT_EQ(cache.getRefFromObjectCache(key2), value2);
cache.clear();
EXPECT_EQ(cache.getRefFromObjectCacheOrNone(key1), std::nullopt); EXPECT_EQ(cache.getRefFromObjectCacheOrNone(key2), std::nullopt); }
TEST(ResourceGenericObjectCacheTest, callShouldIterateOverAllItems) { ObjectCache cache;
osg::ref_ptr<Object> value1(new Object); osg::ref_ptr<Object> value2(new Object); osg::ref_ptr<Object> value3(new Object); cache.addEntryToObjectCache(1, value1); cache.addEntryToObjectCache(2, value2); cache.addEntryToObjectCache(3, value3);
std::vector<std::pair<int, osg::Object*>> actual; cache.call([&](int key, osg::Object* value) { actual.emplace_back(key, value); });
EXPECT_THAT(actual, ElementsAre(Pair(1, value1.get()), Pair(2, value2.get()), Pair(3, value3.get()))); }
TEST(ResourceGenericObjectCacheTest, getStatsShouldReturnNumberOrAddedItems) { ObjectCache cache;
osg::ref_ptr<Object> value1(new Object); osg::ref_ptr<Object> value2(new Object); cache.addEntryToObjectCache(13, value1); cache.addEntryToObjectCache(42, value2);
const CacheStats stats = cache.getStats();
EXPECT_EQ(stats.mSize, 2); }
TEST(ResourceGenericObjectCacheTest, getStatsShouldReturnNumberOrGetsAndHits) { ObjectCache cache;
{ const CacheStats stats = cache.getStats();
EXPECT_EQ(stats.mGet, 0); EXPECT_EQ(stats.mHit, 0); }
osg::ref_ptr<Object> value(new Object); cache.addEntryToObjectCache(13, value); cache.getRefFromObjectCache(13); cache.getRefFromObjectCache(42);
{ const CacheStats stats = cache.getStats();
EXPECT_EQ(stats.mGet, 2); EXPECT_EQ(stats.mHit, 1); } }
TEST(ResourceGenericObjectCacheTest, lowerBoundShouldReturnFirstNotLessThatGivenKey) { ObjectCache cache;
osg::ref_ptr<Object> value1(new Object); osg::ref_ptr<Object> value2(new Object); osg::ref_ptr<Object> value3(new Object); cache.addEntryToObjectCache(1, value1); cache.addEntryToObjectCache(2, value2); cache.addEntryToObjectCache(4, value3);
EXPECT_THAT(cache.lowerBound(3), Optional(Pair(4, value3))); }
TEST(ResourceGenericObjectCacheTest, lowerBoundShouldReturnNulloptWhenKeyIsGreaterThanAnyOther) { ObjectCache cache;
osg::ref_ptr<Object> value1(new Object); osg::ref_ptr<Object> value2(new Object); osg::ref_ptr<Object> value3(new Object); cache.addEntryToObjectCache(1, value1); cache.addEntryToObjectCache(2, value2); cache.addEntryToObjectCache(3, value3);
EXPECT_EQ(cache.lowerBound(4), std::nullopt); }
TEST(ResourceGenericObjectCacheTest, addEntryToObjectCacheShouldSupportHeterogeneousLookup) { StringObjectCache cache; const std::string key = "key"; osg::ref_ptr<Object> value(new Object); cache.addEntryToObjectCache(std::string_view("key"), value); EXPECT_EQ(cache.getRefFromObjectCache(key), value); }
TEST(ResourceGenericObjectCacheTest, addEntryToObjectCacheShouldKeyMoving) { StringObjectCache cache; std::string key(128, 'a'); osg::ref_ptr<Object> value(new Object); cache.addEntryToObjectCache(std::move(key), value); EXPECT_EQ(key, ""); EXPECT_EQ(cache.getRefFromObjectCache(std::string(128, 'a')), value); }
TEST(ResourceGenericObjectCacheTest, removeFromObjectCacheShouldSupportHeterogeneousLookup) { StringObjectCache cache; const std::string key = "key"; osg::ref_ptr<Object> value(new Object); cache.addEntryToObjectCache(key, value); ASSERT_EQ(cache.getRefFromObjectCache(key), value); cache.removeFromObjectCache(std::string_view("key")); EXPECT_EQ(cache.getRefFromObjectCacheOrNone(key), std::nullopt); }
TEST(ResourceGenericObjectCacheTest, getRefFromObjectCacheShouldSupportHeterogeneousLookup) { StringObjectCache cache; const std::string key = "key"; osg::ref_ptr<Object> value(new Object); cache.addEntryToObjectCache(key, value); EXPECT_EQ(cache.getRefFromObjectCache(std::string_view("key")), value); }
TEST(ResourceGenericObjectCacheTest, getRefFromObjectCacheOrNoneShouldSupportHeterogeneousLookup) { StringObjectCache cache; const std::string key = "key"; osg::ref_ptr<Object> value(new Object); cache.addEntryToObjectCache(key, value); EXPECT_THAT(cache.getRefFromObjectCacheOrNone(std::string_view("key")), Optional(value)); }
TEST(ResourceGenericObjectCacheTest, checkInObjectCacheShouldSupportHeterogeneousLookup) { StringObjectCache cache; const std::string key = "key"; osg::ref_ptr<Object> value(new Object); cache.addEntryToObjectCache(key, value); EXPECT_TRUE(cache.checkInObjectCache(std::string_view("key"), 0)); } }}