1#include <userver/multi-index-lru/container.hpp>
2#include <userver/utest/utest.hpp>
6#include <boost/multi_index/hashed_index.hpp>
7#include <boost/multi_index/identity.hpp>
8#include <boost/multi_index/member.hpp>
9#include <boost/multi_index/ordered_index.hpp>
11USERVER_NAMESPACE_BEGIN
15class LRUUsersTest :
public ::testing::Test {
17 void SetUp()
override {}
28 bool operator==(
const User& other)
const {
29 return id == other.id && email == other.email && name == other.name;
33 using UserCache = multi_index_lru::
Container<
35 boost::multi_index::indexed_by<
36 boost::multi_index::ordered_unique<
37 boost::multi_index::tag<IdTag>,
38 boost::multi_index::member<User,
int, &User::id>>,
39 boost::multi_index::ordered_unique<
40 boost::multi_index::tag<EmailTag>,
41 boost::multi_index::member<User, std::string, &User::email>>,
42 boost::multi_index::ordered_non_unique<
43 boost::multi_index::tag<NameTag>,
44 boost::multi_index::member<User, std::string, &User::name>>>>;
47UTEST_F(LRUUsersTest, BasicOperations) {
51 cache.emplace(User{1,
"alice@test.com",
"Alice"});
52 cache.emplace(User{2,
"bob@test.com",
"Bob"});
53 cache.emplace(User{3,
"charlie@test.com",
"Charlie"});
55 EXPECT_EQ(cache.size(), 3);
58 auto by_id = cache.find<IdTag,
int>(1);
59 EXPECT_NE(by_id, cache.end<IdTag>());
60 EXPECT_EQ(by_id->name,
"Alice");
63 auto by_email = cache.find<EmailTag, std::string>(
"bob@test.com");
64 EXPECT_NE(by_email, cache.end<EmailTag>());
65 EXPECT_EQ(by_email->id, 2);
68 auto by_name = cache.find<NameTag, std::string>(
"Charlie");
69 EXPECT_NE(by_name, cache.end<NameTag>());
70 EXPECT_EQ(by_name->email,
"charlie@test.com");
72 auto it = cache.find<EmailTag, std::string>(
"alice@test.com");
73 EXPECT_NE(it, cache.end<EmailTag>());
76UTEST_F(LRUUsersTest, LRUEviction) {
79 cache.emplace(User{1,
"alice@test.com",
"Alice"});
80 cache.emplace(User{2,
"bob@test.com",
"Bob"});
81 cache.emplace(User{3,
"charlie@test.com",
"Charlie"});
88 cache.emplace(User{4,
"david@test.com",
"David"});
90 EXPECT_FALSE((cache.contains<IdTag>(2)));
91 EXPECT_TRUE((cache.contains<IdTag>(1)));
92 EXPECT_TRUE((cache.contains<IdTag>(3)));
93 EXPECT_TRUE((cache.contains<IdTag>(4)));
96UTEST_F(LRUUsersTest, GetNoUpdateDoesNotChangeLru) {
99 cache.emplace(User{1,
"alice@test.com",
"Alice"});
100 cache.emplace(User{2,
"bob@test.com",
"Bob"});
101 cache.emplace(User{3,
"charlie@test.com",
"Charlie"});
103 auto it = cache.find_no_update<IdTag>(1);
104 EXPECT_NE(it, cache.end<IdTag>());
105 EXPECT_EQ(it->name,
"Alice");
107 cache.emplace(User{4,
"david@test.com",
"David"});
109 EXPECT_FALSE((cache.contains<IdTag>(1)));
110 EXPECT_TRUE((cache.contains<IdTag>(2)));
111 EXPECT_TRUE((cache.contains<IdTag>(3)));
112 EXPECT_TRUE((cache.contains<IdTag>(4)));
115UTEST_F(LRUUsersTest, EqualRangeUpdatesLruForAllMatches) {
118 cache.emplace(User{1,
"john1@test.com",
"John"});
119 cache.emplace(User{2,
"john2@test.com",
"John"});
120 cache.emplace(User{3,
"alice@test.com",
"Alice"});
121 cache.emplace(User{4,
"bob@test.com",
"Bob"});
123 auto [begin, end] = cache.equal_range<NameTag, std::string>(
"John");
125 for (
auto it = begin; it != end; ++it) {
130 cache.emplace(User{5,
"eve@test.com",
"Eve"});
132 EXPECT_TRUE((cache.contains<IdTag>(1)));
133 EXPECT_TRUE((cache.contains<IdTag>(2)));
134 EXPECT_FALSE((cache.contains<IdTag>(3)));
135 EXPECT_TRUE((cache.contains<IdTag>(4)));
136 EXPECT_TRUE((cache.contains<IdTag>(5)));
139UTEST_F(LRUUsersTest, EqualRangeNoUpdateDoesNotChangeLru) {
142 cache.emplace(User{1,
"john1@test.com",
"John"});
143 cache.emplace(User{2,
"john2@test.com",
"John"});
144 cache.emplace(User{3,
"alice@test.com",
"Alice"});
145 cache.emplace(User{4,
"bob@test.com",
"Bob"});
147 auto [begin, end] = cache.equal_range_no_update<NameTag, std::string>(
"John");
149 for (
auto it = begin; it != end; ++it) {
154 cache.emplace(User{5,
"eve@test.com",
"Eve"});
156 EXPECT_FALSE((cache.contains<IdTag>(1)));
157 EXPECT_TRUE((cache.contains<IdTag>(2)));
158 EXPECT_TRUE((cache.contains<IdTag>(3)));
159 EXPECT_TRUE((cache.contains<IdTag>(4)));
160 EXPECT_TRUE((cache.contains<IdTag>(5)));
163UTEST_F(LRUUsersTest, EqualRangeWorksWithEmptyRange) {
165 cache.emplace(User{1,
"alice@test.com",
"Alice"});
167 auto [begin, end] = cache.equal_range<NameTag, std::string>(
"Nonexistent");
168 EXPECT_EQ(begin, end);
171UTEST_F(LRUUsersTest, EqualRangeNoUpdateWorksWithEmptyRange) {
173 cache.emplace(User{1,
"alice@test.com",
"Alice"});
175 auto [begin, end] = cache.equal_range_no_update<NameTag, std::string>(
"Nonexistent");
176 EXPECT_EQ(begin, end);
179class ProductsTest :
public ::testing::Test {
189 bool operator==(
const Product& other)
const {
190 return sku == other.sku && name == other.name && price == other.price;
194 using ProductCache = multi_index_lru::
Container<
196 boost::multi_index::indexed_by<
197 boost::multi_index::ordered_unique<
198 boost::multi_index::tag<SkuTag>,
199 boost::multi_index::member<Product, std::string, &Product::sku>>,
200 boost::multi_index::ordered_unique<
201 boost::multi_index::tag<NameTag>,
202 boost::multi_index::member<Product, std::string, &Product::name>>>>;
205UTEST_F(ProductsTest, BasicProductOperations) {
206 ProductCache cache(2);
208 cache.emplace(Product{
"A1",
"Laptop", 999.99});
209 cache.emplace(Product{
"A2",
"Mouse", 29.99});
211 auto laptop = cache.find<SkuTag, std::string>(
"A1");
212 EXPECT_NE(laptop, cache.end<SkuTag>());
213 EXPECT_EQ(laptop->name,
"Laptop");
216UTEST_F(ProductsTest, ProductEviction) {
217 ProductCache cache(2);
219 cache.emplace(Product{
"A1",
"Laptop", 999.99});
220 cache.emplace(Product{
"A2",
"Mouse", 29.99});
223 cache.find<SkuTag>(
"A1");
224 cache.emplace(Product{
"A3",
"Keyboard", 79.99});
226 EXPECT_TRUE((cache.contains<SkuTag, std::string>(
"A1")));
227 EXPECT_TRUE((cache.contains<SkuTag, std::string>(
"A3")));
228 EXPECT_FALSE((cache.contains<SkuTag, std::string>(
"A2")));
230 EXPECT_NE(cache.find<NameTag>(
"Keyboard"), cache.end<NameTag>());
231 EXPECT_EQ(cache.find<NameTag>(
"Mouse"), cache.end<NameTag>());
234TEST(Snippet, SimpleUsage) {
242 MyValueT my_value{
"some_key", 1};
244 using MyLruCache = multi_index_lru::
Container<
246 boost::multi_index::indexed_by<boost::multi_index::hashed_unique<
247 boost::multi_index::tag<MyTag>,
248 boost::multi_index::member<MyValueT, std::string, &MyValueT::key>>>>;
250 MyLruCache cache(1000);
251 cache.insert(my_value);
252 auto it = cache.find<MyTag>(
"some_key");
253 EXPECT_NE(it, cache.end<MyTag>());