| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #include <chrono> |
| | #include <string> |
| | #include <thread> |
| |
|
| | #include "gtest/gtest.h" |
| | #include "lru/lru.hpp" |
| |
|
| | using namespace LRU; |
| | using namespace std::chrono_literals; |
| |
|
| | struct IteratorTest : public ::testing::Test { |
| | using CacheType = Cache<std::string, int>; |
| | using UnorderedIterator = typename CacheType::UnorderedIterator; |
| | using UnorderedConstIterator = typename CacheType::UnorderedConstIterator; |
| | using OrderedIterator = typename CacheType::OrderedIterator; |
| | using OrderedConstIterator = typename CacheType::OrderedConstIterator; |
| |
|
| | CacheType cache; |
| | }; |
| |
|
| | TEST_F(IteratorTest, UnorderedIteratorsAreCompatibleAsExpected) { |
| | cache.emplace("one", 1); |
| |
|
| | |
| | UnorderedIterator first(cache.unordered_begin()); |
| |
|
| | |
| | UnorderedIterator second(first); |
| |
|
| | |
| | UnorderedIterator third; |
| | third = second; |
| |
|
| | |
| | UnorderedConstIterator first_const(std::move(first)); |
| |
|
| | |
| | UnorderedConstIterator second_const(second); |
| |
|
| | |
| | UnorderedConstIterator third_const; |
| | third_const = third; |
| | } |
| |
|
| | TEST_F(IteratorTest, OrderedIteratorsAreCompatibleAsExpected) { |
| | cache.emplace("one", 1); |
| |
|
| | |
| | OrderedIterator first(cache.ordered_begin()); |
| |
|
| | |
| | OrderedIterator second(first); |
| |
|
| | |
| | OrderedIterator third; |
| | third = second; |
| |
|
| | |
| | OrderedConstIterator first_const(std::move(first)); |
| |
|
| | |
| | OrderedConstIterator second_const(second); |
| |
|
| | |
| | OrderedConstIterator third_const; |
| | third_const = third; |
| | } |
| |
|
| | TEST_F(IteratorTest, OrderedAndUnorderedAreComparable) { |
| | cache.emplace("one", 1); |
| |
|
| | |
| | ASSERT_EQ(cache.unordered_begin(), cache.unordered_begin()); |
| | ASSERT_EQ(cache.ordered_begin(), cache.ordered_begin()); |
| | ASSERT_EQ(cache.unordered_end(), cache.unordered_end()); |
| | ASSERT_EQ(cache.ordered_end(), cache.ordered_end()); |
| |
|
| | EXPECT_EQ(cache.unordered_begin(), cache.ordered_begin()); |
| |
|
| | |
| | EXPECT_EQ(cache.ordered_begin(), cache.unordered_begin()); |
| |
|
| | |
| | EXPECT_EQ(cache.unordered_end(), cache.ordered_end()); |
| | EXPECT_EQ(cache.ordered_end(), cache.unordered_end()); |
| |
|
| | |
| | |
| | |
| | EXPECT_EQ(cache.ordered_begin(), cache.unordered_begin()); |
| | EXPECT_EQ(cache.unordered_begin(), cache.ordered_begin()); |
| |
|
| | cache.emplace("two", 1); |
| |
|
| | |
| | EXPECT_NE(cache.ordered_begin(), cache.find("two")); |
| | EXPECT_NE(cache.find("two"), cache.ordered_begin()); |
| | } |
| |
|
| | TEST_F(IteratorTest, TestConversionFromUnorderedToOrdered) { |
| | cache.emplace("one", 1); |
| | cache.emplace("two", 2); |
| | cache.emplace("three", 3); |
| |
|
| | |
| | UnorderedIterator unordered = cache.find("one"); |
| |
|
| | ASSERT_EQ(unordered.key(), "one"); |
| | ASSERT_EQ(unordered.value(), 1); |
| |
|
| | OrderedIterator ordered(unordered); |
| | ordered = OrderedIterator(unordered); |
| |
|
| | EXPECT_EQ(ordered.key(), "one"); |
| | EXPECT_EQ(ordered.value(), 1); |
| |
|
| | |
| | --ordered; |
| | EXPECT_EQ(ordered.key(), "three"); |
| | EXPECT_EQ(ordered.value(), 3); |
| |
|
| | UnorderedConstIterator const_unordered = unordered; |
| | const_unordered = unordered; |
| |
|
| | OrderedConstIterator const_ordered(std::move(const_unordered)); |
| | const_ordered = OrderedConstIterator(std::move(const_unordered)); |
| |
|
| | |
| | const_ordered = --ordered; |
| | const_ordered = OrderedConstIterator(unordered); |
| |
|
| | EXPECT_EQ(ordered.key(), "two"); |
| | EXPECT_EQ(ordered.value(), 2); |
| | } |
| |
|
| | TEST_F(IteratorTest, OrdereredIteratorsAreOrdered) { |
| | for (std::size_t i = 0; i < 100; ++i) { |
| | cache.emplace(std::to_string(i), i); |
| | } |
| |
|
| | auto iterator = cache.ordered_begin(); |
| | for (std::size_t i = 0; i < 100; ++i, ++iterator) { |
| | ASSERT_EQ(iterator.value(), i); |
| | } |
| | } |
| |
|
| | TEST_F(IteratorTest, OrderedIteratorsDoNotChangeTheOrderOfElements) { |
| | cache.capacity(2); |
| | cache.insert({{"one", 1}}); |
| |
|
| | auto begin = cache.ordered_begin(); |
| |
|
| | cache.emplace("two", 2); |
| |
|
| | |
| | |
| | ASSERT_EQ(begin->key(), "one"); |
| | ASSERT_EQ((++begin)->key(), "two"); |
| | ASSERT_EQ((--begin)->key(), "one"); |
| | cache.emplace("three", 3); |
| |
|
| | EXPECT_FALSE(cache.contains("one")); |
| | EXPECT_TRUE(cache.contains("two")); |
| | EXPECT_TRUE(cache.contains("three")); |
| | } |
| |
|
| | TEST_F(IteratorTest, UnorderedIteratorsDoNotChangeTheOrderOfElements) { |
| | cache.capacity(2); |
| | cache.insert({{"one", 1}}); |
| |
|
| | auto begin = cache.unordered_begin(); |
| |
|
| | cache.emplace("two", 2); |
| |
|
| | ASSERT_EQ(begin->key(), "one"); |
| | cache.emplace("three", 3); |
| |
|
| | EXPECT_FALSE(cache.contains("one")); |
| | EXPECT_TRUE(cache.contains("two")); |
| | EXPECT_TRUE(cache.contains("three")); |
| |
|
| | ASSERT_EQ(cache.back(), "two"); |
| | ASSERT_EQ(cache.front(), "three"); |
| | } |
| |
|
| |
|
| | TEST_F(IteratorTest, OrderedIteratorsThrowWhenAccessingExpiredElements) { |
| | TimedCache<int, int> timed_cache(0ms); |
| |
|
| | timed_cache.emplace(1, 1); |
| |
|
| | auto iterator = timed_cache.ordered_begin(); |
| |
|
| | EXPECT_THROW(iterator.entry(), LRU::Error::KeyExpired); |
| | } |
| |
|
| | TEST_F(IteratorTest, UnorderedIteratorsThrowWhenAccessingExpiredElements) { |
| | TimedCache<int, int> timed_cache(0ms); |
| |
|
| | timed_cache.emplace(1, 1); |
| |
|
| | auto iterator = timed_cache.unordered_begin(); |
| |
|
| | EXPECT_THROW(iterator.entry(), LRU::Error::KeyExpired); |
| | } |
| |
|
| | TEST_F(IteratorTest, IsValidReturnsTrueForValidIterators) { |
| | cache.emplace("one", 1); |
| | cache.emplace("two", 1); |
| |
|
| | auto ordered_iterator = cache.ordered_begin(); |
| | EXPECT_TRUE(cache.is_valid(ordered_iterator)); |
| | EXPECT_TRUE(cache.is_valid(++ordered_iterator)); |
| |
|
| | auto unordered_iterator = cache.unordered_begin(); |
| | EXPECT_TRUE(cache.is_valid(unordered_iterator)); |
| | EXPECT_TRUE(cache.is_valid(++unordered_iterator)); |
| | } |
| |
|
| | TEST_F(IteratorTest, IsValidReturnsFalseForInvalidIterators) { |
| | TimedCache<int, int> timed_cache(0ms); |
| |
|
| | EXPECT_FALSE(cache.is_valid(cache.ordered_begin())); |
| | EXPECT_FALSE(cache.is_valid(cache.ordered_end())); |
| | EXPECT_FALSE(cache.is_valid(cache.unordered_begin())); |
| | EXPECT_FALSE(cache.is_valid(cache.unordered_end())); |
| |
|
| | timed_cache.emplace(1, 1); |
| |
|
| | EXPECT_FALSE(cache.is_valid(cache.ordered_begin())); |
| | EXPECT_FALSE(cache.is_valid(cache.unordered_begin())); |
| | } |
| |
|
| | TEST_F(IteratorTest, ThrowIfInvalidThrowsAsExpected) { |
| | EXPECT_THROW(cache.throw_if_invalid(cache.ordered_begin()), |
| | LRU::Error::InvalidIterator); |
| | EXPECT_THROW(cache.throw_if_invalid(cache.ordered_end()), |
| | LRU::Error::InvalidIterator); |
| | EXPECT_THROW(cache.throw_if_invalid(cache.unordered_begin()), |
| | LRU::Error::InvalidIterator); |
| | EXPECT_THROW(cache.throw_if_invalid(cache.unordered_end()), |
| | LRU::Error::InvalidIterator); |
| |
|
| | TimedCache<int, int> timed_cache(0s, {{1, 1}}); |
| |
|
| | ASSERT_EQ(timed_cache.size(), 1); |
| |
|
| | EXPECT_THROW(timed_cache.throw_if_invalid(timed_cache.ordered_begin()), |
| | LRU::Error::KeyExpired); |
| | EXPECT_THROW(timed_cache.throw_if_invalid(timed_cache.unordered_begin()), |
| | LRU::Error::KeyExpired); |
| | } |
| |
|
| | TEST_F(IteratorTest, DereferencingNeverThrows) { |
| | TimedCache<int, int> timed_cache(1ms, {{1, 1}}); |
| |
|
| | |
| | EXPECT_EQ(timed_cache.ordered_begin()->key(), 1); |
| | EXPECT_EQ(timed_cache.unordered_begin()->key(), 1); |
| |
|
| | std::this_thread::sleep_for(1ms); |
| |
|
| | |
| | *timed_cache.ordered_begin(); |
| | *timed_cache.unordered_begin(); |
| | timed_cache.ordered_begin()->key(); |
| | timed_cache.unordered_begin()->key(); |
| | timed_cache.ordered_begin()->value(); |
| | timed_cache.unordered_begin()->value(); |
| | } |
| |
|
| | TEST_F(IteratorTest, CallingAccessThrowsForInvalidIterators) { |
| | TimedCache<int, int> timed_cache(1ms, {{1, 1}}); |
| |
|
| | |
| | ASSERT_EQ(timed_cache.ordered_begin()->key(), 1); |
| | ASSERT_EQ(timed_cache.unordered_begin()->key(), 1); |
| |
|
| | std::this_thread::sleep_for(1ms); |
| |
|
| | |
| | EXPECT_THROW(timed_cache.ordered_begin().key(), LRU::Error::KeyExpired); |
| | EXPECT_THROW(timed_cache.unordered_begin().key(), LRU::Error::KeyExpired); |
| | EXPECT_THROW(timed_cache.ordered_begin().value(), LRU::Error::KeyExpired); |
| | EXPECT_THROW(timed_cache.unordered_begin().value(), LRU::Error::KeyExpired); |
| | EXPECT_THROW(timed_cache.ordered_end().key(), LRU::Error::InvalidIterator); |
| | EXPECT_THROW(timed_cache.unordered_end().key(), LRU::Error::InvalidIterator); |
| | EXPECT_THROW(timed_cache.ordered_end().value(), LRU::Error::InvalidIterator); |
| | EXPECT_THROW(timed_cache.unordered_end().value(), |
| | LRU::Error::InvalidIterator); |
| | } |
| |
|