* Copyright (c) 2026 Huawei Technologies Co., Ltd.
* openUBMC is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#include <gtest/gtest.h>
#include <mc/algorithm/lru_cache.h>
#include <string>
#include <vector>
using namespace mc::algorithm;
TEST(lru_cache_test, basic_put_and_get)
{
lru_cache<int, std::string> cache(3);
cache.put(1, "one");
cache.put(2, "two");
cache.put(3, "three");
EXPECT_EQ(cache.size(), 3);
auto val1 = cache.get(1);
ASSERT_TRUE(val1.has_value());
EXPECT_EQ(val1->get(), "one");
auto val2 = cache.get(2);
ASSERT_TRUE(val2.has_value());
EXPECT_EQ(val2->get(), "two");
auto val_not_exist = cache.get(999);
EXPECT_FALSE(val_not_exist.has_value());
}
TEST(lru_cache_test, lru_eviction)
{
lru_cache<int, std::string> cache(3);
cache.put(1, "one");
cache.put(2, "two");
cache.put(3, "three");
EXPECT_EQ(cache.size(), 3);
cache.put(4, "four");
EXPECT_EQ(cache.size(), 3);
EXPECT_FALSE(cache.get(1).has_value());
EXPECT_TRUE(cache.get(2).has_value());
EXPECT_TRUE(cache.get(3).has_value());
EXPECT_TRUE(cache.get(4).has_value());
}
TEST(lru_cache_test, access_updates_order)
{
lru_cache<int, std::string> cache(3);
cache.put(1, "one");
cache.put(2, "two");
cache.put(3, "three");
cache.get(1);
cache.put(4, "four");
EXPECT_TRUE(cache.get(1).has_value());
EXPECT_FALSE(cache.get(2).has_value());
EXPECT_TRUE(cache.get(3).has_value());
EXPECT_TRUE(cache.get(4).has_value());
}
TEST(lru_cache_test, update_existing_key)
{
lru_cache<int, std::string> cache(3);
cache.put(1, "one");
cache.put(2, "two");
cache.put(3, "three");
cache.put(1, "ONE");
auto val = cache.get(1);
ASSERT_TRUE(val.has_value());
EXPECT_EQ(val->get(), "ONE");
cache.put(4, "four");
EXPECT_TRUE(cache.get(1).has_value());
EXPECT_FALSE(cache.get(2).has_value());
EXPECT_TRUE(cache.get(3).has_value());
EXPECT_TRUE(cache.get(4).has_value());
}
TEST(lru_cache_test, clear_cache)
{
lru_cache<int, std::string> cache(3);
cache.put(1, "one");
cache.put(2, "two");
cache.put(3, "three");
EXPECT_EQ(cache.size(), 3);
cache.clear();
EXPECT_EQ(cache.size(), 0);
EXPECT_TRUE(cache.empty());
EXPECT_FALSE(cache.get(1).has_value());
}
TEST(lru_cache_test, erase_key)
{
lru_cache<int, std::string> cache(3);
cache.put(1, "one");
cache.put(2, "two");
cache.put(3, "three");
EXPECT_TRUE(cache.erase(2));
EXPECT_EQ(cache.size(), 2);
EXPECT_FALSE(cache.get(2).has_value());
EXPECT_FALSE(cache.erase(999));
}
TEST(lru_cache_test, contains_key)
{
lru_cache<int, std::string> cache(3);
cache.put(1, "one");
cache.put(2, "two");
EXPECT_TRUE(cache.contains(1));
EXPECT_TRUE(cache.contains(2));
EXPECT_FALSE(cache.contains(3));
}
TEST(lru_cache_test, set_max_size)
{
lru_cache<int, std::string> cache(5);
cache.put(1, "one");
cache.put(2, "two");
cache.put(3, "three");
cache.put(4, "four");
cache.put(5, "five");
EXPECT_EQ(cache.size(), 5);
cache.set_max_size(3);
EXPECT_EQ(cache.size(), 3);
EXPECT_FALSE(cache.get(1).has_value());
EXPECT_FALSE(cache.get(2).has_value());
EXPECT_TRUE(cache.get(3).has_value());
EXPECT_TRUE(cache.get(4).has_value());
EXPECT_TRUE(cache.get(5).has_value());
}
TEST(lru_cache_test, unlimited_size)
{
lru_cache<int, std::string> cache(0);
for (int i = 0; i < 1000; i++) {
cache.put(i, std::to_string(i));
}
EXPECT_EQ(cache.size(), 1000);
for (int i = 0; i < 1000; i++) {
EXPECT_TRUE(cache.get(i).has_value());
}
}
TEST(lru_cache_test, eviction_callback)
{
std::vector<int> evicted_keys;
auto callback = [&evicted_keys](const int& key, std::string&& value) {
evicted_keys.push_back(key);
};
lru_cache<int, std::string> cache(3, callback);
cache.put(1, "one");
cache.put(2, "two");
cache.put(3, "three");
EXPECT_EQ(evicted_keys.size(), 0);
cache.put(4, "four");
EXPECT_EQ(evicted_keys.size(), 1);
EXPECT_EQ(evicted_keys[0], 1);
cache.put(5, "five");
EXPECT_EQ(evicted_keys.size(), 2);
EXPECT_EQ(evicted_keys[1], 2);
}
TEST(lru_cache_test, for_each_iteration)
{
lru_cache<int, std::string> cache(5);
cache.put(1, "one");
cache.put(2, "two");
cache.put(3, "three");
std::vector<int> keys;
cache.for_each([&keys](const int& key, const std::string& value) {
keys.push_back(key);
});
EXPECT_EQ(keys.size(), 3);
EXPECT_EQ(keys[0], 3);
EXPECT_EQ(keys[1], 2);
EXPECT_EQ(keys[2], 1);
}
TEST(lru_cache_test, string_key)
{
lru_cache<std::string, int> cache(3);
cache.put("one", 1);
cache.put("two", 2);
cache.put("three", 3);
auto val = cache.get("two");
ASSERT_TRUE(val.has_value());
EXPECT_EQ(val->get(), 2);
cache.put("four", 4);
EXPECT_FALSE(cache.get("one").has_value());
EXPECT_TRUE(cache.get("two").has_value());
}
TEST(lru_cache_test, complex_value_type)
{
struct data {
std::string name;
int value;
std::vector<int> numbers;
};
lru_cache<int, data> cache(2);
cache.put(1, {"first", 100, {1, 2, 3}});
cache.put(2, {"second", 200, {4, 5, 6}});
auto val = cache.get(1);
ASSERT_TRUE(val.has_value());
EXPECT_EQ(val->get().name, "first");
EXPECT_EQ(val->get().value, 100);
EXPECT_EQ(val->get().numbers.size(), 3);
}
TEST(lru_cache_test, empty_cache)
{
lru_cache<int, std::string> cache(3);
EXPECT_TRUE(cache.empty());
EXPECT_EQ(cache.size(), 0);
EXPECT_FALSE(cache.get(1).has_value());
EXPECT_FALSE(cache.erase(1));
EXPECT_FALSE(cache.contains(1));
}
TEST(lru_cache_test, modify_via_get_reference)
{
lru_cache<int, std::string> cache(3);
cache.put(1, "one");
auto val = cache.get(1);
ASSERT_TRUE(val.has_value());
val->get() = "ONE";
auto val2 = cache.get(1);
ASSERT_TRUE(val2.has_value());
EXPECT_EQ(val2->get(), "ONE");
}