Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
undo_index.cpp
Go to the documentation of this file.
2
3#include <boost/multi_index/member.hpp>
4#include <boost/multi_index/ordered_index.hpp>
5
6#include <boost/test/unit_test.hpp>
7#include <boost/test/data/monomorphic.hpp>
8#include <boost/test/data/test_case.hpp>
9
10
11namespace {
12int exception_counter = 0;
13int throw_at = -1;
14struct test_exception_base {};
15template<typename E>
16struct test_exception : E, test_exception_base {
17 template<typename... A>
18 test_exception(A&&... a) : E{static_cast<E&&>(a)...} {}
19};
20template<typename E, typename... A>
21void throw_point(A&&... a) {
22 if(throw_at != -1 && exception_counter++ >= throw_at) {
23 throw test_exception<E>{static_cast<A&&>(a)...};
24 }
25}
26template<typename F>
27void test_exceptions(F&& f) {
28 for(throw_at = 0; ; ++throw_at) {
29 exception_counter = 0;
30 try {
31 f();
32 break;
33 } catch(test_exception_base&) {}
34 }
35 throw_at = -1;
36 exception_counter = 0;
37}
38
39struct throwing_copy {
40 throwing_copy() { throw_point<std::bad_alloc>(); }
41 throwing_copy(const throwing_copy&) { throw_point<std::bad_alloc>(); }
42 throwing_copy(throwing_copy&&) noexcept = default;
43 throwing_copy& operator=(const throwing_copy&) { throw_point<std::bad_alloc>(); return *this; }
44 throwing_copy& operator=(throwing_copy&&) noexcept = default;
45};
46
47template<typename T>
48struct test_allocator : std::allocator<T> {
49 test_allocator() = default;
50 template<typename U>
51 test_allocator(const test_allocator<U>&) {}
52 template<typename U>
53 struct rebind { using other = test_allocator<U>; };
54 T* allocate(std::size_t count) {
55 throw_point<std::bad_alloc>();
56 return std::allocator<T>::allocate(count);
57 }
58};
59
60template<typename F>
61struct scope_fail {
62 scope_fail(F&& f) : _f{static_cast<F&&>(f)}, _exception_count{std::uncaught_exceptions()} {}
63 ~scope_fail() {
64 if(_exception_count != std::uncaught_exceptions()) _f();
65 }
66 F _f;
67 int _exception_count;
68};
69
70struct basic_element_t {
71 template<typename C, typename A>
72 basic_element_t(C&& c, const std::allocator<A>&) { c(*this); }
74 throwing_copy dummy;
75};
76
77// TODO: Replace with boost::multi_index::key once we bump our minimum Boost version to at least 1.69
78template<typename T>
79struct key_impl;
80template<typename C, typename T>
81struct key_impl<T C::*> { template<auto F> using fn = boost::multi_index::member<C, T, F>; };
82
83template<auto Fn>
84using key = typename key_impl<decltype(Fn)>::template fn<Fn>;
85
86}
87
88BOOST_AUTO_TEST_SUITE(undo_index_tests)
89
90#define EXCEPTION_TEST_CASE(name) \
91 void name##impl(); \
92 BOOST_AUTO_TEST_CASE(name) { test_exceptions(&name##impl); } \
93 void name##impl ()
94
95EXCEPTION_TEST_CASE(test_simple) {
96 chainbase::undo_index<basic_element_t, test_allocator<basic_element_t>, boost::multi_index::ordered_unique<key<&basic_element_t::id>>> i0;
97 i0.emplace([](basic_element_t& elem) {});
98 const basic_element_t* element = i0.find(0);
99 BOOST_TEST((element != nullptr && element->id == 0));
100 const basic_element_t* e1 = i0.find(1);
101 BOOST_TEST(e1 == nullptr);
102 i0.emplace([](basic_element_t& elem) {});
103 const basic_element_t* e2 = i0.find(1);
104 BOOST_TEST((e2 != nullptr && e2->id == 1));
105
106 i0.modify(*element, [](basic_element_t& elem) {});
107 i0.remove(*element);
108 element = i0.find(0);
109 BOOST_TEST(element == nullptr);
110}
111
113 template<typename C, typename A>
114 test_element_t(C&& c, const std::allocator<A>&) { c(*this); }
117 throwing_copy dummy;
118};
119
120// If an exception is thrown while an undo session is active, undo will restore the state.
121template<typename C>
122auto capture_state(const C& index) {
123 std::vector<std::pair<test_element_t, const test_element_t*>> vec;
124 for(const auto& elem : index) {
125 vec.emplace_back(elem, &elem);
126 }
127 return scope_fail{[vec = std::move(vec), &index]{
128 BOOST_TEST(index.size() == vec.size());
129 for(const auto& [elem, ptr] : vec) {
130 auto * actual0 = index.find(elem.id);
131 BOOST_TEST(actual0 == ptr); // reference stability is guaranteed
132 if (actual0 != nullptr) {
133 BOOST_TEST(actual0->id == elem.id);
134 BOOST_TEST(actual0->secondary == elem.secondary);
135 }
136 auto actual1iter = index.template get<1>().find(elem.secondary);
137 BOOST_TEST((actual1iter != index.template get<1>().end() && &*actual1iter == actual0));
138 }
139 }};
140}
141
142EXCEPTION_TEST_CASE(test_insert_undo) {
144 boost::multi_index::ordered_unique<key<&test_element_t::id>>,
145 boost::multi_index::ordered_unique<key<&test_element_t::secondary> > > i0;
146 i0.emplace([](test_element_t& elem) { elem.secondary = 42; });
147 BOOST_TEST(i0.find(0)->secondary == 42);
148 {
149 auto undo_checker = capture_state(i0);
150 auto session = i0.start_undo_session(true);
151 i0.emplace([](test_element_t& elem) { elem.secondary = 12; });
152 BOOST_TEST(i0.find(1)->secondary == 12);
153 }
154 BOOST_TEST(i0.find(0)->secondary == 42);
155 BOOST_TEST(i0.find(1) == nullptr);
156}
157
158EXCEPTION_TEST_CASE(test_insert_squash) {
160 boost::multi_index::ordered_unique<key<&test_element_t::id>>,
161 boost::multi_index::ordered_unique<key<&test_element_t::secondary> > > i0;
162 i0.emplace([](test_element_t& elem) { elem.secondary = 42; });
163 BOOST_TEST(i0.find(0)->secondary == 42);
164 {
165 auto undo_checker = capture_state(i0);
166 auto session0 = i0.start_undo_session(true);
167 auto session1 = i0.start_undo_session(true);
168 i0.emplace([](test_element_t& elem) { elem.secondary = 12; });
169 BOOST_TEST(i0.find(1)->secondary == 12);
170 session1.squash();
171 BOOST_TEST(i0.find(1)->secondary == 12);
172 }
173 BOOST_TEST(i0.find(0)->secondary == 42);
174 BOOST_TEST(i0.find(1) == nullptr);
175}
176
177EXCEPTION_TEST_CASE(test_insert_push) {
179 boost::multi_index::ordered_unique<key<&test_element_t::id>>,
180 boost::multi_index::ordered_unique<key<&test_element_t::secondary> > > i0;
181 i0.emplace([](test_element_t& elem) { elem.secondary = 42; });
182 BOOST_TEST(i0.find(0)->secondary == 42);
183 {
184 auto undo_checker = capture_state(i0);
185 auto session = i0.start_undo_session(true);
186 i0.emplace([](test_element_t& elem) { elem.secondary = 12; });
187 BOOST_TEST(i0.find(1)->secondary == 12);
188 session.push();
189 i0.commit(i0.revision());
190 }
191 BOOST_TEST(!i0.has_undo_session());
192 BOOST_TEST(i0.find(0)->secondary == 42);
193 BOOST_TEST(i0.find(1)->secondary == 12);
194}
195
196EXCEPTION_TEST_CASE(test_modify_undo) {
198 boost::multi_index::ordered_unique<key<&test_element_t::id>>,
199 boost::multi_index::ordered_unique<key<&test_element_t::secondary>>> i0;
200 i0.emplace([](test_element_t& elem) { elem.secondary = 42; });
201 BOOST_TEST(i0.find(0)->secondary == 42);
202 {
203 auto undo_checker = capture_state(i0);
204 auto session = i0.start_undo_session(true);
205 i0.modify(*i0.find(0), [](test_element_t& elem) { elem.secondary = 18; });
206 BOOST_TEST(i0.find(0)->secondary == 18);
207 }
208 BOOST_TEST(i0.find(0)->secondary == 42);
209}
210
211EXCEPTION_TEST_CASE(test_modify_squash) {
213 boost::multi_index::ordered_unique<key<&test_element_t::id>>,
214 boost::multi_index::ordered_unique<key<&test_element_t::secondary>>> i0;
215 i0.emplace([](test_element_t& elem) { elem.secondary = 42; });
216 BOOST_TEST(i0.find(0)->secondary == 42);
217 {
218 auto undo_checker = capture_state(i0);
219 auto session0 = i0.start_undo_session(true);
220 auto session1 = i0.start_undo_session(true);
221 i0.modify(*i0.find(0), [](test_element_t& elem) { elem.secondary = 18; });
222 BOOST_TEST(i0.find(0)->secondary == 18);
223 session1.squash();
224 BOOST_TEST(i0.find(0)->secondary == 18);
225 }
226 BOOST_TEST(i0.find(0)->secondary == 42);
227}
228
229EXCEPTION_TEST_CASE(test_modify_push) {
231 boost::multi_index::ordered_unique<key<&test_element_t::id>>,
232 boost::multi_index::ordered_unique<key<&test_element_t::secondary>>> i0;
233 i0.emplace([](test_element_t& elem) { elem.secondary = 42; });
234 BOOST_TEST(i0.find(0)->secondary == 42);
235 {
236 auto undo_checker = capture_state(i0);
237 auto session = i0.start_undo_session(true);
238 i0.modify(*i0.find(0), [](test_element_t& elem) { elem.secondary = 18; });
239 BOOST_TEST(i0.find(0)->secondary == 18);
240 session.push();
241 i0.commit(i0.revision());
242 }
243 BOOST_TEST(!i0.has_undo_session());
244 BOOST_TEST(i0.find(0)->secondary == 18);
245}
246
247EXCEPTION_TEST_CASE(test_remove_undo) {
249 boost::multi_index::ordered_unique<key<&test_element_t::id>>,
250 boost::multi_index::ordered_unique<key<&test_element_t::secondary>>> i0;
251 i0.emplace([](test_element_t& elem) { elem.secondary = 42; });
252 BOOST_TEST(i0.find(0)->secondary == 42);
253 {
254 auto undo_checker = capture_state(i0);
255 auto session = i0.start_undo_session(true);
256 i0.remove(*i0.find(0));
257 BOOST_TEST(i0.find(0) == nullptr);
258 }
259 BOOST_TEST(i0.find(0)->secondary == 42);
260}
261
262EXCEPTION_TEST_CASE(test_remove_squash) {
264 boost::multi_index::ordered_unique<key<&test_element_t::id>>,
265 boost::multi_index::ordered_unique<key<&test_element_t::secondary>>> i0;
266 i0.emplace([](test_element_t& elem) { elem.secondary = 42; });
267 BOOST_TEST(i0.find(0)->secondary == 42);
268 {
269 auto undo_checker = capture_state(i0);
270 auto session0 = i0.start_undo_session(true);
271 auto session1 = i0.start_undo_session(true);
272 i0.remove(*i0.find(0));
273 BOOST_TEST(i0.find(0) == nullptr);
274 session1.squash();
275 BOOST_TEST(i0.find(0) == nullptr);
276 }
277 BOOST_TEST(i0.find(0)->secondary == 42);
278}
279
280EXCEPTION_TEST_CASE(test_remove_push) {
282 boost::multi_index::ordered_unique<key<&test_element_t::id>>,
283 boost::multi_index::ordered_unique<key<&test_element_t::secondary>>> i0;
284 i0.emplace([](test_element_t& elem) { elem.secondary = 42; });
285 BOOST_TEST(i0.find(0)->secondary == 42);
286 {
287 auto undo_checker = capture_state(i0);
288 auto session = i0.start_undo_session(true);
289 i0.remove(*i0.find(0));
290 BOOST_TEST(i0.find(0) == nullptr);
291 session.push();
292 i0.commit(i0.revision());
293 }
294 BOOST_TEST(!i0.has_undo_session());
295 BOOST_TEST(i0.find(0) == nullptr);
296}
297
298EXCEPTION_TEST_CASE(test_insert_modify) {
300 boost::multi_index::ordered_unique<key<&test_element_t::id>>,
301 boost::multi_index::ordered_unique<key<&test_element_t::secondary>>> i0;
302 i0.emplace([](test_element_t& elem) { elem.secondary = 42; });
303 BOOST_TEST(i0.find(0)->secondary == 42);
304 i0.emplace([](test_element_t& elem) { elem.secondary = 12; });
305 BOOST_TEST(i0.find(1)->secondary == 12);
306 i0.modify(*i0.find(1), [](test_element_t& elem) { elem.secondary = 24; });
307 BOOST_TEST(i0.find(1)->secondary == 24);
308}
309
310EXCEPTION_TEST_CASE(test_insert_modify_undo) {
312 boost::multi_index::ordered_unique<key<&test_element_t::id>>,
313 boost::multi_index::ordered_unique<key<&test_element_t::secondary>>> i0;
314 i0.emplace([](test_element_t& elem) { elem.secondary = 42; });
315 BOOST_TEST(i0.find(0)->secondary == 42);
316 {
317 auto undo_checker = capture_state(i0);
318 auto session = i0.start_undo_session(true);
319 i0.emplace([](test_element_t& elem) { elem.secondary = 12; });
320 BOOST_TEST(i0.find(1)->secondary == 12);
321 i0.modify(*i0.find(1), [](test_element_t& elem) { elem.secondary = 24; });
322 BOOST_TEST(i0.find(1)->secondary == 24);
323 }
324 BOOST_TEST(i0.find(0)->secondary == 42);
325 BOOST_TEST(i0.find(1) == nullptr);
326}
327
328
329EXCEPTION_TEST_CASE(test_insert_modify_squash) {
331 boost::multi_index::ordered_unique<key<&test_element_t::id>>,
332 boost::multi_index::ordered_unique<key<&test_element_t::secondary>>> i0;
333 i0.emplace([](test_element_t& elem) { elem.secondary = 42; });
334 BOOST_TEST(i0.find(0)->secondary == 42);
335 {
336 auto undo_checker = capture_state(i0);
337 auto session1 = i0.start_undo_session(true);
338 i0.emplace([](test_element_t& elem) { elem.secondary = 12; });
339 BOOST_TEST(i0.find(1)->secondary == 12);
340 auto session2 = i0.start_undo_session(true);
341 i0.modify(*i0.find(1), [](test_element_t& elem) { elem.secondary = 24; });
342 BOOST_TEST(i0.find(1)->secondary == 24);
343 session2.squash();
344 }
345 BOOST_TEST(i0.find(0)->secondary == 42);
346 BOOST_TEST(i0.find(1) == nullptr);
347}
348
349EXCEPTION_TEST_CASE(test_insert_remove_undo) {
351 boost::multi_index::ordered_unique<key<&test_element_t::id>>,
352 boost::multi_index::ordered_unique<key<&test_element_t::secondary>>> i0;
353 i0.emplace([](test_element_t& elem) { elem.secondary = 42; });
354 BOOST_TEST(i0.find(0)->secondary == 42);
355 {
356 auto undo_checker = capture_state(i0);
357 auto session = i0.start_undo_session(true);
358 i0.emplace([](test_element_t& elem) { elem.secondary = 12; });
359 BOOST_TEST(i0.find(1)->secondary == 12);
360 i0.remove(*i0.find(1));
361 BOOST_TEST(i0.find(1) == nullptr);
362 }
363 BOOST_TEST(i0.find(0)->secondary == 42);
364 BOOST_TEST(i0.find(1) == nullptr);
365}
366
367EXCEPTION_TEST_CASE(test_insert_remove_squash) {
369 boost::multi_index::ordered_unique<key<&test_element_t::id>>,
370 boost::multi_index::ordered_unique<key<&test_element_t::secondary>>> i0;
371 i0.emplace([](test_element_t& elem) { elem.secondary = 42; });
372 BOOST_TEST(i0.find(0)->secondary == 42);
373 {
374 auto undo_checker = capture_state(i0);
375 auto session1 = i0.start_undo_session(true);
376 i0.emplace([](test_element_t& elem) { elem.secondary = 12; });
377 BOOST_TEST(i0.find(1)->secondary == 12);
378 auto session2 = i0.start_undo_session(true);
379 i0.remove(*i0.find(1));
380 BOOST_TEST(i0.find(1) == nullptr);
381 session2.squash();
382 }
383 BOOST_TEST(i0.find(0)->secondary == 42);
384 BOOST_TEST(i0.find(1) == nullptr);
385}
386
387EXCEPTION_TEST_CASE(test_modify_modify_undo) {
389 boost::multi_index::ordered_unique<key<&test_element_t::id>>,
390 boost::multi_index::ordered_unique<key<&test_element_t::secondary>>> i0;
391 i0.emplace([](test_element_t& elem) { elem.secondary = 42; });
392 BOOST_TEST(i0.find(0)->secondary == 42);
393 {
394 auto undo_checker = capture_state(i0);
395 auto session = i0.start_undo_session(true);
396 i0.modify(*i0.find(0), [](test_element_t& elem) { elem.secondary = 18; });
397 BOOST_TEST(i0.find(0)->secondary == 18);
398 i0.modify(*i0.find(0), [](test_element_t& elem) { elem.secondary = 24; });
399 BOOST_TEST(i0.find(0)->secondary == 24);
400 }
401 BOOST_TEST(i0.find(0)->secondary == 42);
402}
403
404EXCEPTION_TEST_CASE(test_modify_modify_squash) {
406 boost::multi_index::ordered_unique<key<&test_element_t::id>>,
407 boost::multi_index::ordered_unique<key<&test_element_t::secondary>>> i0;
408 i0.emplace([](test_element_t& elem) { elem.secondary = 42; });
409 BOOST_TEST(i0.find(0)->secondary == 42);
410 {
411 auto undo_checker = capture_state(i0);
412 auto session1 = i0.start_undo_session(true);
413 i0.modify(*i0.find(0), [](test_element_t& elem) { elem.secondary = 18; });
414 BOOST_TEST(i0.find(0)->secondary == 18);
415 auto session2 = i0.start_undo_session(true);
416 i0.modify(*i0.find(0), [](test_element_t& elem) { elem.secondary = 24; });
417 BOOST_TEST(i0.find(0)->secondary == 24);
418 session2.squash();
419 }
420 BOOST_TEST(i0.find(0)->secondary == 42);
421}
422
423EXCEPTION_TEST_CASE(test_modify_remove_undo) {
425 boost::multi_index::ordered_unique<key<&test_element_t::id>>,
426 boost::multi_index::ordered_unique<key<&test_element_t::secondary>>> i0;
427 i0.emplace([](test_element_t& elem) { elem.secondary = 42; });
428 BOOST_TEST(i0.find(0)->secondary == 42);
429 {
430 auto undo_checker = capture_state(i0);
431 auto session = i0.start_undo_session(true);
432 i0.modify(*i0.find(0), [](test_element_t& elem) { elem.secondary = 18; });
433 BOOST_TEST(i0.find(0)->secondary == 18);
434 i0.remove(*i0.find(0));
435 BOOST_TEST(i0.find(0) == nullptr);
436 }
437 BOOST_TEST(i0.find(0)->secondary == 42);
438}
439
440EXCEPTION_TEST_CASE(test_modify_remove_squash) {
442 boost::multi_index::ordered_unique<key<&test_element_t::id>>,
443 boost::multi_index::ordered_unique<key<&test_element_t::secondary>>> i0;
444 i0.emplace([](test_element_t& elem) { elem.secondary = 42; });
445 BOOST_TEST(i0.find(0)->secondary == 42);
446 {
447 auto undo_checker = capture_state(i0);
448 auto session1 = i0.start_undo_session(true);
449 i0.modify(*i0.find(0), [](test_element_t& elem) { elem.secondary = 18; });
450 BOOST_TEST(i0.find(0)->secondary == 18);
451 auto session2 = i0.start_undo_session(true);
452 i0.remove(*i0.find(0));
453 BOOST_TEST(i0.find(0) == nullptr);
454 session2.squash();
455 }
456 BOOST_TEST(i0.find(0)->secondary == 42);
457}
458
459EXCEPTION_TEST_CASE(test_squash_one) {
461 boost::multi_index::ordered_unique<key<&test_element_t::id>>,
462 boost::multi_index::ordered_unique<key<&test_element_t::secondary>>> i0;
463 i0.emplace([](test_element_t& elem) { elem.secondary = 42; });
464 BOOST_TEST(i0.find(0)->secondary == 42);
465 {
466 i0.modify(*i0.find(0), [](test_element_t& elem) { elem.secondary = 18; });
467 BOOST_TEST(i0.find(0)->secondary == 18);
468 auto session2 = i0.start_undo_session(true);
469 i0.remove(*i0.find(0));
470 BOOST_TEST(i0.find(0) == nullptr);
471 session2.squash();
472 }
473}
474
475EXCEPTION_TEST_CASE(test_insert_non_unique) {
477 boost::multi_index::ordered_unique<key<&test_element_t::id>>,
478 boost::multi_index::ordered_unique<key<&test_element_t::secondary>>> i0;
479 i0.emplace([](test_element_t& elem) { elem.secondary = 42; });
480 BOOST_TEST(i0.find(0)->secondary == 42);
481 BOOST_CHECK_THROW(i0.emplace([](test_element_t& elem) { elem.secondary = 42; }), std::exception);
482 BOOST_TEST(i0.find(0)->secondary == 42);
483}
484
486 template<typename C, typename A>
487 conflict_element_t(C&& c, const test_allocator<A>&) { c(*this); }
489 int x0;
490 int x1;
491 int x2;
492 throwing_copy dummy;
493};
494
495EXCEPTION_TEST_CASE(test_modify_conflict) {
497 boost::multi_index::ordered_unique<key<&conflict_element_t::id>>,
498 boost::multi_index::ordered_unique<key<&conflict_element_t::x0>>,
499 boost::multi_index::ordered_unique<key<&conflict_element_t::x1>>,
500 boost::multi_index::ordered_unique<key<&conflict_element_t::x2>>> i0;
501 // insert 3 elements
502 i0.emplace([](conflict_element_t& elem) { elem.x0 = 0; elem.x1 = 10; elem.x2 = 10; });
503 i0.emplace([](conflict_element_t& elem) { elem.x0 = 11; elem.x1 = 1; elem.x2 = 11; });
504 i0.emplace([](conflict_element_t& elem) { elem.x0 = 12; elem.x1 = 12; elem.x2 = 2; });
505 {
506 auto session = i0.start_undo_session(true);
507 // set them to a different value
508 i0.modify(*i0.find(0), [](conflict_element_t& elem) { elem.x0 = 10; elem.x1 = 10; elem.x2 = 10; });
509 i0.modify(*i0.find(1), [](conflict_element_t& elem) { elem.x0 = 11; elem.x1 = 11; elem.x2 = 11; });
510 i0.modify(*i0.find(2), [](conflict_element_t& elem) { elem.x0 = 12; elem.x1 = 12; elem.x2 = 12; });
511 // create a circular conflict with the original values
512 i0.modify(*i0.find(0), [](conflict_element_t& elem) { elem.x0 = 10; elem.x1 = 1; elem.x2 = 10; });
513 i0.modify(*i0.find(1), [](conflict_element_t& elem) { elem.x0 = 11; elem.x1 = 11; elem.x2 = 2; });
514 i0.modify(*i0.find(2), [](conflict_element_t& elem) { elem.x0 = 0; elem.x1 = 12; elem.x2 = 12; });
515 }
516 BOOST_TEST(i0.find(0)->x0 == 0);
517 BOOST_TEST(i0.find(1)->x1 == 1);
518 BOOST_TEST(i0.find(2)->x2 == 2);
519 // Check lookup in the other indices
520 BOOST_TEST(i0.get<1>().find(0)->x0 == 0);
521 BOOST_TEST(i0.get<1>().find(11)->x0 == 11);
522 BOOST_TEST(i0.get<1>().find(12)->x0 == 12);
523 BOOST_TEST(i0.get<2>().find(10)->x1 == 10);
524 BOOST_TEST(i0.get<2>().find(1)->x1 == 1);
525 BOOST_TEST(i0.get<2>().find(12)->x1 == 12);
526 BOOST_TEST(i0.get<3>().find(10)->x2 == 10);
527 BOOST_TEST(i0.get<3>().find(11)->x2 == 11);
528 BOOST_TEST(i0.get<3>().find(2)->x2 == 2);
529}
530
531BOOST_DATA_TEST_CASE(test_insert_fail, boost::unit_test::data::make({true, false}), use_undo) {
533 boost::multi_index::ordered_unique<key<&conflict_element_t::id>>,
534 boost::multi_index::ordered_unique<key<&conflict_element_t::x0>>,
535 boost::multi_index::ordered_unique<key<&conflict_element_t::x1>>,
536 boost::multi_index::ordered_unique<key<&conflict_element_t::x2>>> i0;
537 // insert 3 elements
538 i0.emplace([](conflict_element_t& elem) { elem.x0 = 10; elem.x1 = 10; elem.x2 = 10; });
539 i0.emplace([](conflict_element_t& elem) { elem.x0 = 11; elem.x1 = 11; elem.x2 = 11; });
540 i0.emplace([](conflict_element_t& elem) { elem.x0 = 12; elem.x1 = 12; elem.x2 = 12; });
541 {
542 auto session = i0.start_undo_session(true);
543 // Insert a value with a duplicate
544 BOOST_CHECK_THROW(i0.emplace([](conflict_element_t& elem) { elem.x0 = 81; elem.x1 = 11; elem.x2 = 91; }), std::logic_error);
545 }
546 BOOST_TEST(i0.find(0)->x0 == 10);
547 BOOST_TEST(i0.find(1)->x1 == 11);
548 BOOST_TEST(i0.find(2)->x2 == 12);
549 // Check lookup in the other indices
550 BOOST_TEST(i0.get<1>().find(10)->x0 == 10);
551 BOOST_TEST(i0.get<1>().find(11)->x0 == 11);
552 BOOST_TEST(i0.get<1>().find(12)->x0 == 12);
553 BOOST_TEST(i0.get<2>().find(10)->x1 == 10);
554 BOOST_TEST(i0.get<2>().find(11)->x1 == 11);
555 BOOST_TEST(i0.get<2>().find(12)->x1 == 12);
556 BOOST_TEST(i0.get<3>().find(10)->x2 == 10);
557 BOOST_TEST(i0.get<3>().find(11)->x2 == 11);
558 BOOST_TEST(i0.get<3>().find(12)->x2 == 12);
559}
560
561EXCEPTION_TEST_CASE(test_modify_fail) {
563 boost::multi_index::ordered_unique<key<&conflict_element_t::id>>,
564 boost::multi_index::ordered_unique<key<&conflict_element_t::x0>>,
565 boost::multi_index::ordered_unique<key<&conflict_element_t::x1>>,
566 boost::multi_index::ordered_unique<key<&conflict_element_t::x2>>> i0;
567 // insert 3 elements
568 i0.emplace([](conflict_element_t& elem) { elem.x0 = 10; elem.x1 = 10; elem.x2 = 10; });
569 i0.emplace([](conflict_element_t& elem) { elem.x0 = 11; elem.x1 = 11; elem.x2 = 11; });
570 i0.emplace([](conflict_element_t& elem) { elem.x0 = 12; elem.x1 = 12; elem.x2 = 12; });
571 {
572 auto session = i0.start_undo_session(true);
573 // Insert a value with a duplicate
574 i0.emplace([](conflict_element_t& elem) { elem.x0 = 71; elem.x1 = 81; elem.x2 = 91; });
575 BOOST_CHECK_THROW(i0.modify(i0.get(3), [](conflict_element_t& elem) { elem.x0 = 71; elem.x1 = 10; elem.x2 = 91; }), std::logic_error);
576 }
577 BOOST_TEST(i0.get<0>().size() == 3);
578 BOOST_TEST(i0.get<1>().size() == 3);
579 BOOST_TEST(i0.get<2>().size() == 3);
580 BOOST_TEST(i0.get<3>().size() == 3);
581 BOOST_TEST(i0.find(0)->x0 == 10);
582 BOOST_TEST(i0.find(1)->x1 == 11);
583 BOOST_TEST(i0.find(2)->x2 == 12);
584 // Check lookup in the other indices
585 BOOST_TEST(i0.get<1>().find(10)->x0 == 10);
586 BOOST_TEST(i0.get<1>().find(11)->x0 == 11);
587 BOOST_TEST(i0.get<1>().find(12)->x0 == 12);
588 BOOST_TEST(i0.get<2>().find(10)->x1 == 10);
589 BOOST_TEST(i0.get<2>().find(11)->x1 == 11);
590 BOOST_TEST(i0.get<2>().find(12)->x1 == 12);
591 BOOST_TEST(i0.get<3>().find(10)->x2 == 10);
592 BOOST_TEST(i0.get<3>().find(11)->x2 == 11);
593 BOOST_TEST(i0.get<3>().find(12)->x2 == 12);
594}
595
596struct by_secondary {};
597
598BOOST_AUTO_TEST_CASE(test_project) {
600 boost::multi_index::ordered_unique<key<&test_element_t::id>>,
601 boost::multi_index::ordered_unique<boost::multi_index::tag<by_secondary>, key<&test_element_t::secondary>>> i0;
602 i0.emplace([](test_element_t& elem) { elem.secondary = 42; });
603 BOOST_TEST(i0.project<by_secondary>(i0.begin()) == i0.get<by_secondary>().begin());
604 BOOST_TEST(i0.project<by_secondary>(i0.end()) == i0.get<by_secondary>().end());
605 BOOST_TEST(i0.project<1>(i0.begin()) == i0.get<by_secondary>().begin());
606 BOOST_TEST(i0.project<1>(i0.end()) == i0.get<by_secondary>().end());
607}
608
609
610EXCEPTION_TEST_CASE(test_remove_tracking_session) {
612 boost::multi_index::ordered_unique<key<&test_element_t::id>>,
613 boost::multi_index::ordered_unique<key<&test_element_t::secondary>>> i0;
614 i0.emplace([](test_element_t& elem) { elem.secondary = 20; });
615 auto session = i0.start_undo_session(true);
616 auto tracker = i0.track_removed();
617 i0.emplace([](test_element_t& elem) { elem.secondary = 21; });
618 const test_element_t& elem0 = *i0.find(0);
619 const test_element_t& elem1 = *i0.find(1);
620 BOOST_CHECK(!tracker.is_removed(elem0));
621 BOOST_CHECK(!tracker.is_removed(elem1));
622 tracker.remove(elem0);
623 tracker.remove(elem1);
624 BOOST_CHECK(tracker.is_removed(elem0));
625 BOOST_CHECK(tracker.is_removed(elem1));
626}
627
628
629EXCEPTION_TEST_CASE(test_remove_tracking_no_session) {
631 boost::multi_index::ordered_unique<key<&test_element_t::id>>,
632 boost::multi_index::ordered_unique<key<&test_element_t::secondary>>> i0;
633 i0.emplace([](test_element_t& elem) { elem.secondary = 20; });
634 auto tracker = i0.track_removed();
635 i0.emplace([](test_element_t& elem) { elem.secondary = 21; });
636 const test_element_t& elem0 = *i0.find(0);
637 const test_element_t& elem1 = *i0.find(1);
638 BOOST_CHECK(!tracker.is_removed(elem0));
639 BOOST_CHECK(!tracker.is_removed(elem1));
640 tracker.remove(elem0);
641 tracker.remove(elem1);
642 BOOST_CHECK(tracker.is_removed(elem0));
643 BOOST_CHECK(tracker.is_removed(elem1));
644}
645
646BOOST_AUTO_TEST_SUITE_END()
void modify(const value_type &obj, Modifier &&m)
int64_t revision() const
const value_type & get(CompatibleKey &&key) const
bool has_undo_session() const
auto project(Iter iter) const
session start_undo_session(bool enabled)
void commit(int64_t revision) noexcept
const value_type * find(CompatibleKey &&key) const
const value_type & emplace(Constructor &&c)
void remove(const value_type &obj) noexcept
uint64_t id
Definition code_cache.cpp:0
CK_SESSION_HANDLE session
int * count
constexpr enabler dummy
An instance to use in EnableIf.
Definition CLI11.hpp:856
Definition name.hpp:106
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition pointer.h:1181
#define T(meth, val, expected)
unsigned __int64 uint64_t
Definition stdint.h:136
conflict_element_t(C &&c, const test_allocator< A > &)
throwing_copy dummy
throwing_copy dummy
test_element_t(C &&c, const std::allocator< A > &)
#define EXCEPTION_TEST_CASE(name)
auto capture_state(const C &index)
BOOST_DATA_TEST_CASE(test_insert_fail, boost::unit_test::data::make({true, false}), use_undo)
BOOST_AUTO_TEST_CASE(test_project)
yubihsm_pkcs11_object_template template