xrpld
Loading...
Searching...
No Matches
Mutex.cpp
1#include <xrpl/basics/Mutex.hpp>
2
3#include <gtest/gtest.h>
4
5#include <memory>
6#include <mutex>
7#include <shared_mutex>
8#include <string>
9#include <type_traits>
10#include <utility>
11#include <vector>
12
13using namespace xrpl;
14
15struct MutexMakeTest : ::testing::Test
16{
17};
18
19TEST_F(MutexMakeTest, default_constructor)
20{
21 auto m = Mutex<int>::make();
22 auto lock = m.lock();
23 EXPECT_EQ(*lock, 0);
24}
25
26TEST_F(MutexMakeTest, single_argument)
27{
28 auto m = Mutex<int>::make(42);
29 auto lock = m.lock();
30 EXPECT_EQ(*lock, 42);
31}
32
33TEST_F(MutexMakeTest, string_argument)
34{
35 auto m = Mutex<std::string>::make("test");
36 auto lock = m.lock();
37 EXPECT_EQ(*lock, "test");
38}
39
40TEST_F(MutexMakeTest, move_only_type)
41{
42 auto m = Mutex<std::unique_ptr<int>>::make(std::make_unique<int>(100));
43 auto lock = m.lock();
44 EXPECT_NE(lock->get(), nullptr);
45 EXPECT_EQ(**lock, 100);
46}
47
48struct MutexDirectConstructionTest : ::testing::Test
49{
50};
51
52TEST_F(MutexDirectConstructionTest, default_constructor)
53{
54 // Test default construction with a type that has a non-trivial
55 // default constructor
56 Mutex<std::string> m;
57 auto lock = m.lock();
58 EXPECT_TRUE(lock->empty());
59}
60
61TEST_F(MutexDirectConstructionTest, default_initialization)
62{
63 Mutex<int> m;
64 auto lock = m.lock();
65 EXPECT_EQ(*lock, 0);
66}
67
68TEST_F(MutexDirectConstructionTest, constructor_with_value)
69{
70 Mutex<int> m(42);
71 auto lock = m.lock();
72 EXPECT_EQ(*lock, 42);
73}
74
75TEST_F(MutexDirectConstructionTest, constructor_with_string)
76{
77 Mutex<std::string> m(std::string("hello"));
78 auto lock = m.lock();
79 EXPECT_EQ(*lock, "hello");
80}
81
82struct MutexLockNonConstTest : ::testing::Test
83{
84};
85
86TEST_F(MutexLockNonConstTest, operator_star)
87{
88 Mutex<int> m(10);
89 {
90 auto lock = m.lock();
91 EXPECT_EQ(*lock, 10);
92 *lock = 20;
93 }
94 auto lock = m.lock();
95 EXPECT_EQ(*lock, 20);
96}
97
98TEST_F(MutexLockNonConstTest, get_method)
99{
100 Mutex<int> m(10);
101 {
102 auto lock = m.lock();
103 EXPECT_EQ(lock.get(), 10);
104 lock.get() = 30;
105 }
106 auto lock = m.lock();
107 EXPECT_EQ(lock.get(), 30);
108}
109
110TEST_F(MutexLockNonConstTest, operator_arrow)
111{
112 Mutex<std::string> m(std::string("test"));
113 {
114 auto lock = m.lock();
115 EXPECT_EQ(lock->size(), 4);
116 lock->append(" string");
117 }
118 auto lock = m.lock();
119 EXPECT_EQ(*lock, "test string");
120}
121
122TEST_F(MutexLockNonConstTest, multiple_modifications)
123{
124 Mutex<int> m(10);
125 {
126 auto lock = m.lock();
127 *lock = 20;
128 }
129 {
130 auto lock = m.lock();
131 EXPECT_EQ(lock.get(), 20);
132 lock.get() = 30;
133 }
134 {
135 auto lock = m.lock();
136 EXPECT_EQ(*lock, 30);
137 }
138}
139
140struct MutexLockConstTest : ::testing::Test
141{
142};
143
144TEST_F(MutexLockConstTest, operator_star)
145{
146 Mutex<int> const m(42);
147 auto lock = m.lock();
148 static_assert(std::is_const_v<std::remove_reference_t<decltype(*lock)>>);
149 EXPECT_EQ(*lock, 42);
150}
151
152TEST_F(MutexLockConstTest, get_method)
153{
154 Mutex<int> const m(42);
155 auto lock = m.lock();
156 static_assert(std::is_const_v<std::remove_reference_t<decltype(lock.get())>>);
157 EXPECT_EQ(lock.get(), 42);
158}
159
160TEST_F(MutexLockConstTest, operator_arrow)
161{
162 Mutex<std::string> const m(std::string("test"));
163 auto lock = m.lock();
164 static_assert(std::is_const_v<std::remove_reference_t<decltype(*lock)>>);
165 EXPECT_EQ(lock->size(), 4);
166 EXPECT_EQ(lock->at(0), 't');
167}
168
169struct MutexConstCorrectnessTest : ::testing::Test
170{
171};
172
173TEST_F(MutexConstCorrectnessTest, non_const_allows_modification)
174{
175 Mutex<std::vector<int>> m({1, 2, 3, 4, 5});
176 {
177 auto lock = m.lock();
178 EXPECT_EQ(lock->size(), 5);
179 lock->push_back(6);
180 }
181 auto lock = m.lock();
182 EXPECT_EQ(lock->size(), 6);
183 EXPECT_EQ(lock->back(), 6);
184}
185
186TEST_F(MutexConstCorrectnessTest, const_reference_provides_const_access)
187{
188 Mutex<std::vector<int>> const m({1, 2, 3, 4, 5, 6});
189 Mutex<std::vector<int>> const& constRef = m;
190 auto lock = constRef.lock();
191 static_assert(std::is_const_v<std::remove_reference_t<decltype(*lock)>>);
192 EXPECT_EQ(lock->size(), 6);
193 EXPECT_EQ(lock->at(5), 6);
194}
195
196struct MutexDifferentLockTypesTest : ::testing::Test
197{
198};
199
200TEST_F(MutexDifferentLockTypesTest, scoped_lock)
201{
202 Mutex<int> m(0);
203 {
204 auto lock = m.lock();
205 *lock = 1;
206 }
207 auto lock = m.lock();
208 EXPECT_EQ(*lock, 1);
209}
210
211TEST_F(MutexDifferentLockTypesTest, unique_lock)
212{
213 Mutex<int> m(0);
214 auto lock = m.lock<std::unique_lock>();
215 EXPECT_EQ(*lock, 0);
216 *lock = 2;
217
219 ul.unlock();
220 ul.lock();
221 EXPECT_EQ(*lock, 2);
222}
223
224struct MutexSharedMutexTest : ::testing::Test
225{
226};
227
228TEST_F(MutexSharedMutexTest, shared_lock_for_const_access)
229{
230 Mutex<int, std::shared_mutex> const m(100);
231 Mutex<int, std::shared_mutex> const& constRef = m;
232 auto lock = constRef.lock<std::shared_lock>();
233 EXPECT_EQ(*lock, 100);
234}
235
236TEST_F(MutexSharedMutexTest, unique_lock_for_mutable_access)
237{
238 Mutex<int, std::shared_mutex> m(100);
239 {
240 auto lock = m.lock<std::unique_lock>();
241 *lock = 200;
242 }
243 auto lock = m.lock<std::shared_lock>();
244 EXPECT_EQ(*lock, 200);
245}
246
247struct MutexComplexTypeTest : ::testing::Test
248{
249 struct Data
250 {
251 int x;
253
254 Data(int x, std::string y) : x(x), y(std::move(y))
255 {
256 }
257 };
258};
259
260TEST_F(MutexComplexTypeTest, construct_and_access)
261{
262 auto m = Mutex<Data>::make(42, "hello");
263 auto lock = m.lock();
264 EXPECT_EQ(lock->x, 42);
265 EXPECT_EQ(lock->y, "hello");
266}
267
268TEST_F(MutexComplexTypeTest, modify_fields)
269{
270 auto m = Mutex<Data>::make(42, "hello");
271 {
272 auto lock = m.lock();
273 lock->x = 100;
274 lock->y = "world";
275 }
276 {
277 auto lock = m.lock();
278 EXPECT_EQ(lock->x, 100);
279 EXPECT_EQ(lock->y, "world");
280 }
281}
282
283TEST_F(MutexComplexTypeTest, const_access_to_fields)
284{
285 auto const m = Mutex<Data>::make(42, "hello");
286 auto lock = m.lock();
287 static_assert(std::is_const_v<std::remove_reference_t<decltype(*lock)>>);
288 EXPECT_EQ(lock->x, 42);
289 EXPECT_EQ(lock->y, "hello");
290}
T is_const_v
T lock(T... args)
T make_unique(T... args)
STL namespace.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
Data(int x, std::string y)
Definition Mutex.cpp:254
T unlock(T... args)