| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| #include <gtest/gtest.h> |
| |
| #include "lib/MapCache.h" |
| |
| using namespace pulsar; |
| |
| struct MoveOnlyInt { |
| int x = 0; |
| |
| MoveOnlyInt() = default; |
| MoveOnlyInt(int xx) : x(xx) {} |
| MoveOnlyInt(const MoveOnlyInt&) = delete; |
| MoveOnlyInt(MoveOnlyInt&& rhs) noexcept : x(rhs.x) {} |
| |
| bool operator=(const MoveOnlyInt& rhs) const { return x == rhs.x; } |
| }; |
| |
| TEST(MapCacheTest, testPutIfAbsent) { |
| MapCache<int, MoveOnlyInt> cache; |
| |
| ASSERT_NE(cache.putIfAbsent(1, {100}), cache.end()); |
| ASSERT_EQ(cache.putIfAbsent(1, {200}), cache.end()); |
| auto it = cache.find(1); |
| ASSERT_NE(it, cache.end()); |
| ASSERT_EQ(it->second.x, 100); |
| |
| cache.remove(1); |
| ASSERT_EQ(cache.find(1), cache.end()); |
| } |
| |
| TEST(MapCacheTest, testRemoveOldestValues) { |
| MapCache<int, MoveOnlyInt> cache; |
| cache.putIfAbsent(1, {200}); |
| cache.putIfAbsent(2, {210}); |
| cache.putIfAbsent(3, {220}); |
| ASSERT_EQ(cache.getKeys(), (std::vector<int>{1, 2, 3})); |
| |
| std::vector<int> removedValues; |
| cache.removeOldestValues(2, [&removedValues](const int& key, const MoveOnlyInt& value) { |
| removedValues.emplace_back(value.x); |
| }); |
| ASSERT_EQ(removedValues, (std::vector<int>{200, 210})); |
| |
| ASSERT_EQ(cache.getKeys(), (std::vector<int>{3})); |
| ASSERT_EQ(cache.size(), 1); |
| auto it = cache.find(3); |
| ASSERT_NE(it, cache.end()); |
| ASSERT_EQ(it->second.x, 220); |
| } |
| |
| TEST(MapCacheTest, testRemoveAllValues) { |
| MapCache<int, MoveOnlyInt> cache; |
| cache.putIfAbsent(1, {300}); |
| cache.putIfAbsent(2, {310}); |
| cache.putIfAbsent(3, {320}); |
| |
| // removeOldestValues works well even if the argument is greater than the size of keys |
| cache.removeOldestValues(10000, nullptr); |
| ASSERT_TRUE(cache.getKeys().empty()); |
| ASSERT_EQ(cache.size(), 0); |
| } |
| |
| TEST(MapCacheTest, testRemoveOldestValuesIf) { |
| MapCache<int, MoveOnlyInt> cache; |
| cache.putIfAbsent(1, {100}); |
| cache.putIfAbsent(2, {200}); |
| cache.putIfAbsent(3, {300}); |
| int expireTime = 100; |
| |
| auto checkCondition = [&expireTime](const int& key, const MoveOnlyInt& value) -> bool { |
| return expireTime > value.x; |
| }; |
| |
| cache.removeOldestValuesIf(nullptr); |
| ASSERT_EQ(cache.size(), 3); |
| |
| cache.removeOldestValuesIf(checkCondition); |
| ASSERT_EQ(cache.size(), 3); |
| |
| expireTime = 200; |
| cache.removeOldestValuesIf(checkCondition); |
| |
| auto keys = cache.getKeys(); |
| ASSERT_EQ(cache.size(), 2); |
| ASSERT_EQ(cache.find(2)->second.x, 200); |
| ASSERT_EQ(cache.find(3)->second.x, 300); |
| |
| expireTime = 400; |
| cache.removeOldestValuesIf(checkCondition); |
| ASSERT_EQ(cache.size(), 0); |
| } |