tests.h 72.5 KB
Newer Older
lucapegolotti committed
1 2 3 4
/**
/* Internal tests for the linearizability checker
*/

5
#include <linearizability_tester.h>
6
#include <sequential_data_structures.h>
7 8 9 10 11

using namespace lt;

static void test_lru_cache()
{
lucapegolotti committed
12 13 14 15 16 17 18 19 20 21
  LruCache<char> lru_cache{ 3 };
  assert(lru_cache.insert('\1'));
  assert(!lru_cache.insert('\1'));

  assert(lru_cache.insert('\2'));
  assert(lru_cache.insert('\3'));
  assert(lru_cache.insert('\1'));
  assert(!lru_cache.insert('\3'));
  assert(lru_cache.insert('\4'));
  assert(lru_cache.insert('\1'));
22 23 24 25
}

static void test_atomic_op()
{
lucapegolotti committed
26 27
  bool ok;
  state::Atomic atomic, new_atomic;
28

lucapegolotti committed
29
  OpPtr<state::Atomic> read_call_op_ptr;
30

lucapegolotti committed
31 32 33
  OpPtr<state::Atomic> read_0_ret_op_ptr, read_0_pending_op_ptr;
  OpPtr<state::Atomic> read_1_ret_op_ptr;
  OpPtr<state::Atomic> read_2_ret_op_ptr;
34

lucapegolotti committed
35 36 37
  OpPtr<state::Atomic> write_1_call_op_ptr, write_1_ret_op_ptr, write_1_pending_op_ptr;
  OpPtr<state::Atomic> cas_2_succeeded_call_op_ptr, cas_2_succeeded_ret_op_ptr, cas_2_pending_op_ptr;
  OpPtr<state::Atomic> cas_2_failed_call_op_ptr, cas_2_failed_ret_op_ptr;
38

lucapegolotti committed
39
  read_call_op_ptr = state::Atomic::make_read_call();
40

lucapegolotti committed
41 42 43 44
  read_0_ret_op_ptr = state::Atomic::make_read_ret('\0');
  read_0_pending_op_ptr = state::Atomic::make_read_pending();
  read_1_ret_op_ptr = state::Atomic::make_read_ret('\1');
  read_2_ret_op_ptr = state::Atomic::make_read_ret('\2');
45

lucapegolotti committed
46 47 48
  write_1_call_op_ptr = state::Atomic::make_write_call('\1');
  write_1_ret_op_ptr = state::Atomic::make_write_ret();
  write_1_pending_op_ptr = state::Atomic::make_write_pending();
49

lucapegolotti committed
50 51 52
  cas_2_succeeded_call_op_ptr = state::Atomic::make_cas_call('\1', '\2');
  cas_2_succeeded_ret_op_ptr = state::Atomic::make_cas_ret(true);
  cas_2_pending_op_ptr = state::Atomic::make_cas_pending();
53

lucapegolotti committed
54 55
  cas_2_failed_call_op_ptr = state::Atomic::make_cas_call('\2', '\1');
  cas_2_failed_ret_op_ptr = state::Atomic::make_cas_ret(false);
56

lucapegolotti committed
57
  Op<state::Atomic>& read_call_op = *read_call_op_ptr;
58

lucapegolotti committed
59 60 61 62
  Op<state::Atomic>& read_0_ret_op = *read_0_ret_op_ptr;
  Op<state::Atomic>& read_0_pending_op = *read_0_pending_op_ptr;
  Op<state::Atomic>& read_1_ret_op = *read_1_ret_op_ptr;
  Op<state::Atomic>& read_2_ret_op = *read_2_ret_op_ptr;
63

lucapegolotti committed
64 65 66
  Op<state::Atomic>& write_1_call_op = *write_1_call_op_ptr;
  Op<state::Atomic>& write_1_ret_op = *write_1_ret_op_ptr;
  Op<state::Atomic>& write_1_pending_op = *write_1_pending_op_ptr;
67

lucapegolotti committed
68 69 70
  Op<state::Atomic>& cas_2_succeeded_call_op = *cas_2_succeeded_call_op_ptr;
  Op<state::Atomic>& cas_2_succeeded_ret_op = *cas_2_succeeded_ret_op_ptr;
  Op<state::Atomic>& cas_2_pending_op = *cas_2_pending_op_ptr;
71

lucapegolotti committed
72 73
  Op<state::Atomic>& cas_2_failed_call_op = *cas_2_failed_call_op_ptr;
  Op<state::Atomic>& cas_2_failed_ret_op = *cas_2_failed_ret_op_ptr;
74

lucapegolotti committed
75 76 77 78 79
  assert(!read_call_op.is_partitionable());
  assert(!read_0_ret_op.is_partitionable());
  assert(!read_0_pending_op.is_partitionable());
  assert(!read_1_ret_op.is_partitionable());
  assert(!read_2_ret_op.is_partitionable());
80

lucapegolotti committed
81 82 83
  assert(!write_1_call_op.is_partitionable());
  assert(!write_1_ret_op.is_partitionable());
  assert(!write_1_pending_op.is_partitionable());
84

lucapegolotti committed
85 86 87 88 89
  assert(!cas_2_succeeded_call_op.is_partitionable());
  assert(!cas_2_succeeded_ret_op.is_partitionable());
  assert(!cas_2_pending_op.is_partitionable());
  assert(!cas_2_failed_call_op.is_partitionable());
  assert(!cas_2_failed_ret_op.is_partitionable());
90

lucapegolotti committed
91 92 93
  std::tie(ok, new_atomic) = read_call_op.apply(atomic, read_0_ret_op);
  assert(atomic == new_atomic);
  assert(!ok);
94

lucapegolotti committed
95 96 97
  std::tie(ok, new_atomic) = read_call_op.apply(atomic, read_1_ret_op);
  assert(atomic == new_atomic);
  assert(!ok);
98

lucapegolotti committed
99 100 101
  std::tie(ok, new_atomic) = read_call_op.apply(atomic, read_0_pending_op);
  assert(atomic == new_atomic);
  assert(ok);
102

lucapegolotti committed
103 104 105
  std::tie(ok, new_atomic) = read_call_op.apply(atomic, read_1_ret_op);
  assert(atomic == new_atomic);
  assert(!ok);
106

lucapegolotti committed
107 108 109
  std::tie(ok, new_atomic) = write_1_call_op.apply(atomic, write_1_pending_op);
  assert(atomic != new_atomic);
  assert(ok);
110

lucapegolotti committed
111 112 113
  std::tie(ok, new_atomic) = write_1_call_op.apply(atomic, write_1_ret_op);
  assert(atomic != new_atomic);
  assert(ok);
114

lucapegolotti committed
115
  atomic = new_atomic;
116

lucapegolotti committed
117 118 119
  std::tie(ok, new_atomic) = read_call_op.apply(atomic, read_1_ret_op);
  assert(atomic == new_atomic);
  assert(ok);
120

lucapegolotti committed
121 122 123
  std::tie(ok, new_atomic) = read_call_op.apply(atomic, read_2_ret_op);
  assert(atomic == new_atomic);
  assert(!ok);
124

lucapegolotti committed
125 126 127
  std::tie(ok, new_atomic) = cas_2_failed_call_op.apply(atomic, cas_2_failed_ret_op);
  assert(atomic == new_atomic);
  assert(ok);
128

lucapegolotti committed
129 130 131
  std::tie(ok, new_atomic) = cas_2_failed_call_op.apply(atomic, cas_2_succeeded_ret_op);
  assert(atomic == new_atomic);
  assert(!ok);
132

lucapegolotti committed
133 134 135
  std::tie(ok, new_atomic) = cas_2_succeeded_call_op.apply(atomic, cas_2_pending_op);
  assert(atomic != new_atomic);
  assert(ok);
136

lucapegolotti committed
137 138 139
  std::tie(ok, new_atomic) = cas_2_succeeded_call_op.apply(atomic, cas_2_succeeded_ret_op);
  assert(atomic != new_atomic);
  assert(ok);
140

lucapegolotti committed
141
  atomic = new_atomic;
142

lucapegolotti committed
143 144 145
  std::tie(ok, new_atomic) = read_call_op.apply(atomic, read_2_ret_op);
  assert(atomic == new_atomic);
  assert(ok);
146 147 148 149 150
}

/// a few sanity checks
static void test_stack()
{
lucapegolotti committed
151 152 153 154
  Entry<state::Set> ret, call;
  call.set_op(state::Set::make_contains_call('\1'));
  ret.set_op(state::Set::make_ret(true));
  call.set_match(&ret);
155

lucapegolotti committed
156
  EntryPtr<state::Set> A{ &call }, B{ &call }, C{ &call };
157

lucapegolotti committed
158
  Stack<state::Set> stack{ 3 };
159

lucapegolotti committed
160 161 162
  assert(stack.is_empty());
  assert(!stack.is_full());
  assert(stack.size() == 0U);
163

lucapegolotti committed
164
  stack.push(A, state::Set());
165

lucapegolotti committed
166 167 168 169
  assert(std::get<0>(stack.top()) == A);
  assert(!stack.is_empty());
  assert(!stack.is_full());
  assert(stack.size() == 1U);
170

lucapegolotti committed
171
  stack.push(B, state::Set());
172

lucapegolotti committed
173 174 175 176
  assert(std::get<0>(stack.top()) == B);
  assert(!stack.is_empty());
  assert(!stack.is_full());
  assert(stack.size() == 2U);
177

lucapegolotti committed
178
  stack.push(C, state::Set());
179

lucapegolotti committed
180 181 182 183
  assert(std::get<0>(stack.top()) == C);
  assert(!stack.is_empty());
  assert(stack.is_full());
  assert(stack.size() == 3U);
184

lucapegolotti committed
185
  stack.pop();
186

lucapegolotti committed
187 188 189 190
  assert(std::get<0>(stack.top()) == B);
  assert(!stack.is_empty());
  assert(!stack.is_full());
  assert(stack.size() == 2U);
191

lucapegolotti committed
192
  stack.push(C, state::Set());
193

lucapegolotti committed
194 195 196 197
  assert(std::get<0>(stack.top()) == C);
  assert(!stack.is_empty());
  assert(stack.is_full());
  assert(stack.size() == 3U);
198

lucapegolotti committed
199 200
  // pop multiple entries at once
  stack.pop(2);
201

lucapegolotti committed
202 203 204
  assert(!stack.is_empty());
  assert(!stack.is_full());
  assert(stack.size() == 1U);
205

lucapegolotti committed
206
  stack.pop();
207

lucapegolotti committed
208 209 210
  assert(stack.is_empty());
  assert(!stack.is_full());
  assert(stack.size() == 0U);
211 212 213 214
}

static void test_bitset()
{
lucapegolotti committed
215 216
  constexpr unsigned bits_per_block = static_cast<unsigned>(sizeof(unsigned long) * CHAR_BIT);
  constexpr unsigned N = bits_per_block + 7;
217

lucapegolotti committed
218
  FlexibleBitset bitset;
219

lucapegolotti committed
220 221
  for (unsigned k{ 0U }; k < N; ++k)
    assert(!bitset.is_set(k));
222

lucapegolotti committed
223
  assert(bitset.is_empty());
224

lucapegolotti committed
225 226 227
  bitset.set(0);
  assert(bitset.is_set(0));
  assert(!bitset.is_empty());
228

lucapegolotti committed
229 230
  for (unsigned k{ 1U }; k < N; ++k)
    assert(!bitset.is_set(k));
231

lucapegolotti committed
232 233 234
  bitset.reset(0);
  assert(!bitset.is_set(0));
  assert(bitset.is_empty());
235

lucapegolotti committed
236 237 238 239
  bitset.set(1);
  assert(!bitset.is_set(0));
  assert(bitset.is_set(1));
  assert(!bitset.is_empty());
240

lucapegolotti committed
241 242
  for (unsigned k{ 2U }; k < N; ++k)
    assert(!bitset.is_set(k));
243

lucapegolotti committed
244 245 246
  bitset.set(N-1);
  assert(bitset.is_set(N-1));
  assert(!bitset.is_empty());
247

lucapegolotti committed
248 249
  for (unsigned k{ 2U }; k < N - 1U; ++k)
    assert(!bitset.is_set(k));
250

lucapegolotti committed
251 252 253 254 255
  FlexibleBitset another_bitset;
  another_bitset.set(1);
  another_bitset.set(N-1);
  
  FlexibleBitset yet_another_bitset(another_bitset);
256

lucapegolotti committed
257 258
  assert(bitset == another_bitset);
  assert(bitset == yet_another_bitset);
259

lucapegolotti committed
260 261 262
  assert(!bitset.is_set(bits_per_block - 1U));
  assert(bitset.set(bits_per_block - 1U));
  assert(bitset.is_set(bits_per_block - 1U));
263

lucapegolotti committed
264 265 266
  assert(!bitset.is_set(bits_per_block));
  assert(bitset.set(bits_per_block));
  assert(bitset.is_set(bits_per_block));
267

lucapegolotti committed
268 269 270
  assert(!bitset.is_set(bits_per_block + 1U));
  assert(bitset.set(bits_per_block + 1U));
  assert(bitset.is_set(bits_per_block + 1U));
271

lucapegolotti committed
272 273 274
  assert(!bitset.is_set(2U * bits_per_block - 1U));
  assert(bitset.set(2U * bits_per_block - 1U));
  assert(bitset.is_set(2U * bits_per_block - 1U));
275

lucapegolotti committed
276 277 278
  assert(!bitset.is_set(2U * bits_per_block));
  assert(bitset.set(2U * bits_per_block));
  assert(bitset.is_set(2U * bits_per_block));
279

lucapegolotti committed
280 281 282
  assert(!bitset.is_set(2U * bits_per_block + 1U));
  assert(bitset.set(2U * bits_per_block + 1U));
  assert(bitset.is_set(2U * bits_per_block + 1U));
283

lucapegolotti committed
284
  bitset = another_bitset;
285

lucapegolotti committed
286 287 288
  assert(bitset.set(2U * bits_per_block - 1U));
  assert(bitset.reset(2U * bits_per_block - 1U));
  assert(bitset == another_bitset);
289

lucapegolotti committed
290 291 292 293
  assert(bitset.set(2U * bits_per_block));
  assert(bitset.reset(2U * bits_per_block));
  // different number of blocks
  assert(bitset != another_bitset);
294

lucapegolotti committed
295 296
  assert(bitset.set(2U * bits_per_block + 1U));
  assert(bitset.reset(2U * bits_per_block + 1U));
297

lucapegolotti committed
298 299
  // different number of blocks
  assert(bitset != another_bitset);
300 301 302 303
}

static void test_state_set()
{
lucapegolotti committed
304 305
  bool ok;
  state::Set set;
306

lucapegolotti committed
307
  assert(!set.contains('\1'));
308

lucapegolotti committed
309 310
  std::tie(ok, set) = set.insert('\1');
  assert(ok);
311

lucapegolotti committed
312
  assert(set.contains('\1'));
313

lucapegolotti committed
314 315 316 317
  // item is already in the set
  std::tie(ok, set) = set.insert('\1');
  assert(!ok);
  assert(set.contains('\1'));
318

lucapegolotti committed
319 320 321
  std::tie(ok, set) = set.erase('\1');
  assert(ok);
  assert(!set.contains('\1'));
322

lucapegolotti committed
323 324 325 326
  // item has been already erased from the set
  std::tie(ok, set) = set.erase('\1');
  assert(!ok);
  assert(!set.contains('\1'));
327 328 329 330
}

static void test_state_set_op()
{
lucapegolotti committed
331 332
  bool ok;
  state::Set set, new_set;
333

lucapegolotti committed
334 335 336 337
  OpPtr<state::Set> empty_op_ptr;
  OpPtr<state::Set> contains_op_ptr;
  OpPtr<state::Set> insert_op_ptr;
  OpPtr<state::Set> erase_op_ptr;
338

lucapegolotti committed
339 340
  OpPtr<state::Set> true_ret_op_ptr{ state::Set::make_ret(true) };
  OpPtr<state::Set> false_ret_op_ptr{ state::Set::make_ret(false) };
341

lucapegolotti committed
342 343
  const Op<state::Set>& true_ret_op = *true_ret_op_ptr;
  const Op<state::Set>& false_ret_op = *false_ret_op_ptr;
344

lucapegolotti committed
345 346 347 348
  empty_op_ptr = state::Set::make_empty_call();
  contains_op_ptr = state::Set::make_contains_call('\1');
  insert_op_ptr = state::Set::make_insert_call('\1');
  erase_op_ptr = state::Set::make_erase_call('\1');
349

lucapegolotti committed
350 351 352 353
  Op<state::Set>& empty_op = *empty_op_ptr;
  Op<state::Set>& contains_op = *contains_op_ptr;
  Op<state::Set>& insert_op = *insert_op_ptr;
  Op<state::Set>& erase_op = *erase_op_ptr;
354

lucapegolotti committed
355 356 357
  std::tie(ok, new_set) = empty_op.apply(set, true_ret_op);
  assert(set == new_set);
  assert(ok);
358

lucapegolotti committed
359 360 361
  std::tie(ok, new_set) = contains_op.apply(set, false_ret_op);
  assert(set == new_set);
  assert(ok);
362

lucapegolotti committed
363 364 365
  std::tie(ok, new_set) = insert_op.apply(set, true_ret_op);
  assert(set != new_set);
  assert(ok);
366

lucapegolotti committed
367
  set = new_set;
368

lucapegolotti committed
369 370 371
  std::tie(ok, new_set) = empty_op.apply(set, false_ret_op);
  assert(set == new_set);
  assert(ok);
372

lucapegolotti committed
373 374 375
  std::tie(ok, new_set) = contains_op.apply(set, true_ret_op);
  assert(set == new_set);
  assert(ok);
376

lucapegolotti committed
377 378 379 380
  // item is already in the set, so insertion is unsuccessful
  std::tie(ok, new_set) = insert_op.apply(set, false_ret_op);
  assert(set == new_set);
  assert(ok);
381

lucapegolotti committed
382 383 384
  std::tie(ok, new_set) = contains_op.apply(set, true_ret_op);
  assert(set == new_set);
  assert(ok);
385

lucapegolotti committed
386 387 388
  std::tie(ok, new_set) = erase_op.apply(set, true_ret_op);
  assert(set != new_set);
  assert(ok);
389

lucapegolotti committed
390 391
  assert(std::get<0>(contains_op.apply(set, true_ret_op)));
  assert(!std::get<0>(contains_op.apply(set, false_ret_op)));
392

lucapegolotti committed
393 394
  assert(!std::get<0>(contains_op.apply(new_set, true_ret_op)));
  assert(std::get<0>(contains_op.apply(new_set, false_ret_op)));
395 396 397 398
}

static void test_state_stack()
{
lucapegolotti committed
399
  constexpr unsigned N = 2;
400

lucapegolotti committed
401 402 403
  state::Stack<N> stack;
  state::Stack<N> new_stack;
  state::Stack<N> stack_1, stack_2;
404

lucapegolotti committed
405 406
  assert(stack.is_empty());
  assert(!stack.is_full());
407

lucapegolotti committed
408
  new_stack = stack.push('\1');
409

lucapegolotti committed
410 411
  assert(stack != new_stack);
  stack = stack_1 = new_stack;
412

lucapegolotti committed
413 414
  assert(!stack.is_empty());
  assert(!stack.is_full());
415

lucapegolotti committed
416
  assert(stack.top() == '\1');
417

lucapegolotti committed
418
  new_stack = stack.push('\2');
419

lucapegolotti committed
420 421
  assert(stack != new_stack);
  stack = stack_2 = new_stack;
422

lucapegolotti committed
423
  assert(stack_1 != stack_2);
424

lucapegolotti committed
425 426
  assert(!stack.is_empty());
  assert(stack.is_full());
427

lucapegolotti committed
428
  assert(stack.top() == '\2');
429

lucapegolotti committed
430 431
  new_stack = stack.pop();
  assert(new_stack == stack_1);
432

lucapegolotti committed
433
  stack = new_stack;
434

lucapegolotti committed
435 436
  assert(!stack.is_empty());
  assert(!stack.is_full());
437

lucapegolotti committed
438
  assert(stack.top() == '\1');
439

lucapegolotti committed
440
  new_stack = stack.push('\2');
441

lucapegolotti committed
442 443
  assert(stack != new_stack);
  assert(new_stack == stack_2);
444

lucapegolotti committed
445
  stack = new_stack;
446

lucapegolotti committed
447 448
  assert(!stack.is_empty());
  assert(stack.is_full());
449

lucapegolotti committed
450
  assert(stack.top() == '\2');
451

lucapegolotti committed
452 453
  new_stack = stack.pop();
  assert(new_stack == stack_1);
454

lucapegolotti committed
455
  stack = new_stack;
456

lucapegolotti committed
457 458
  assert(!stack.is_empty());
  assert(!stack.is_full());
459

lucapegolotti committed
460
  assert(stack.top() == '\1');
461

lucapegolotti committed
462
  new_stack = stack.push('\3');
463

lucapegolotti committed
464 465 466
  assert(stack != new_stack);
  assert(new_stack != stack_1);
  assert(new_stack != stack_2);
467

lucapegolotti committed
468
  stack = new_stack;
469

lucapegolotti committed
470 471
  assert(!stack.is_empty());
  assert(stack.is_full());
472

lucapegolotti committed
473
  assert(stack.top() == '\3');
474 475 476 477
}

static void test_state_queue()
{
lucapegolotti committed
478
  constexpr unsigned N = 2;
479

lucapegolotti committed
480
  state::Queue<N> queue;
481

lucapegolotti committed
482 483
  state::Queue<N> new_queue;
  state::Queue<N> queue_1, queue_2;
484

lucapegolotti committed
485 486 487 488 489
  assert(queue.is_empty());
  assert(!queue.is_full());
  
  queue.enqueue('\1');
  new_queue = queue.enqueue('\1');
490

lucapegolotti committed
491 492
  assert(queue != new_queue);
  queue = queue_1 = new_queue;
493

lucapegolotti committed
494 495
  assert(!queue.is_empty());
  assert(!queue.is_full());
496

lucapegolotti committed
497
  assert(queue.get_value() == '\1');
498

lucapegolotti committed
499
  new_queue = queue.enqueue('\2');
500

lucapegolotti committed
501 502
  assert(queue != new_queue);
  queue = queue_2 = new_queue;
503

lucapegolotti committed
504
  assert(queue_1 != queue_2);
505

lucapegolotti committed
506 507
  assert(!queue.is_empty());
  assert(queue.is_full());
508

lucapegolotti committed
509
  assert(queue.get_value() == '\1');
510

lucapegolotti committed
511 512
  new_queue = queue.dequeue();
  assert(new_queue != queue_1);
513

lucapegolotti committed
514 515 516 517
  queue = new_queue;
  
  assert(!queue.is_empty());
  assert(!queue.is_full());
518

lucapegolotti committed
519
  assert(queue.get_value() == '\2');
520

lucapegolotti committed
521
  new_queue = queue.enqueue('\1');
522

lucapegolotti committed
523 524
  assert(queue != new_queue);
  assert(new_queue != queue_2);
525

lucapegolotti committed
526
  queue = new_queue;
527

lucapegolotti committed
528 529
  assert(!queue.is_empty());
  assert(queue.is_full());
530

lucapegolotti committed
531
  assert(queue.get_value() == '\2');
532

lucapegolotti committed
533 534 535
  new_queue = queue.dequeue();
  assert(new_queue != queue_1);
  queue = new_queue;
536

lucapegolotti committed
537 538
  assert(!queue.is_empty());
  assert(!queue.is_full());
539

lucapegolotti committed
540
  assert(queue.get_value() == '\1');
541

lucapegolotti committed
542
  new_queue = queue.enqueue('\3');
543

lucapegolotti committed
544 545 546
  assert(queue != new_queue);
  assert(new_queue != queue_1);
  assert(new_queue != queue_2);
547

lucapegolotti committed
548
  queue = new_queue;
549

lucapegolotti committed
550 551
  assert(!queue.is_empty());
  assert(queue.is_full());
552

lucapegolotti committed
553 554
  assert(queue.get_value() == '\1');
  
555 556 557 558
}

static void test_state_stack_op()
{
lucapegolotti committed
559
  constexpr unsigned N = 1;
560

lucapegolotti committed
561 562
  bool ok;
  state::Stack<N> stack, new_stack;
563

lucapegolotti committed
564 565
  OpPtr<state::Stack<N>> try_push_1_op_ptr, try_push_2_op_ptr;
  OpPtr<state::Stack<N>> try_pop_op_ptr;
566

lucapegolotti committed
567 568
  OpPtr<state::Stack<N>> true_try_push_ret_op_ptr{ state::Stack<N>::make_try_push_ret(true) };
  OpPtr<state::Stack<N>> false_try_push_ret_op_ptr{ state::Stack<N>::make_try_push_ret(false) };
569

lucapegolotti committed
570 571
  const Op<state::Stack<N>>& true_try_push_ret_op = *true_try_push_ret_op_ptr;
  const Op<state::Stack<N>>& false_try_push_ret_op = *false_try_push_ret_op_ptr;
572

lucapegolotti committed
573 574 575
  OpPtr<state::Stack<N>> true_1_try_pop_ret_op_ptr{ state::Stack<N>::make_try_pop_ret(true, '\1') };
  OpPtr<state::Stack<N>> true_2_try_pop_ret_op_ptr{ state::Stack<N>::make_try_pop_ret(true, '\2') };
  OpPtr<state::Stack<N>> false_try_pop_ret_op_ptr{ state::Stack<N>::make_try_pop_ret(false, '\0') };
576

lucapegolotti committed
577 578 579
  const Op<state::Stack<N>>& true_1_try_pop_ret_op = *true_1_try_pop_ret_op_ptr;
  const Op<state::Stack<N>>& true_2_try_pop_ret_op = *true_2_try_pop_ret_op_ptr;
  const Op<state::Stack<N>>& false_try_pop_ret_op = *false_try_pop_ret_op_ptr;
580

lucapegolotti committed
581 582 583 584 585 586
  try_pop_op_ptr = state::Stack<N>::make_try_pop_call();
  Op<state::Stack<N>>& try_pop_op = *try_pop_op_ptr;
  
  std::tie(ok, new_stack) = try_pop_op.apply(stack, false_try_pop_ret_op);
  assert(stack == new_stack);
  assert(ok);
587

lucapegolotti committed
588 589 590
  std::tie(ok, new_stack) = try_pop_op.apply(stack, true_1_try_pop_ret_op);
  assert(stack == new_stack);
  assert(!ok);
591

lucapegolotti committed
592 593 594
  std::tie(ok, new_stack) = try_pop_op.apply(stack, true_2_try_pop_ret_op);
  assert(stack == new_stack);
  assert(!ok);
595

lucapegolotti committed
596 597
  try_push_2_op_ptr = state::Stack<N>::make_try_push_call('\2');
  Op<state::Stack<N>>& try_push_2_op = *try_push_2_op_ptr;
598

lucapegolotti committed
599 600 601 602 603 604 605
  std::tie(ok, new_stack) = try_push_2_op.apply(stack, false_try_push_ret_op);
  assert(stack != new_stack);
  assert(!ok);
  
  std::tie(ok, new_stack) = try_push_2_op.apply(stack, true_try_push_ret_op);
  assert(stack != new_stack);
  assert(ok);
606

lucapegolotti committed
607
  stack = new_stack;
608

lucapegolotti committed
609 610
  try_push_1_op_ptr = state::Stack<N>::make_try_push_call('\1');
  Op<state::Stack<N>>& try_push_1_op = *try_push_1_op_ptr;
611

lucapegolotti committed
612 613 614 615
  // stack is full
  std::tie(ok, new_stack) = try_push_1_op.apply(stack, false_try_push_ret_op);
  assert(stack == new_stack);
  assert(ok);
616

lucapegolotti committed
617 618 619
  std::tie(ok, new_stack) = try_push_1_op.apply(stack, true_try_push_ret_op);
  assert(stack == new_stack);
  assert(!ok);
620

lucapegolotti committed
621 622 623
  std::tie(ok, new_stack) = try_pop_op.apply(stack, false_try_pop_ret_op);
  assert(stack != new_stack);
  assert(!ok);
624

lucapegolotti committed
625 626 627
  std::tie(ok, new_stack) = try_pop_op.apply(stack, true_1_try_pop_ret_op);
  assert(stack != new_stack);
  assert(!ok);
628

lucapegolotti committed
629 630 631
  std::tie(ok, new_stack) = try_pop_op.apply(stack, true_2_try_pop_ret_op);
  assert(stack != new_stack);
  assert(ok);
632 633 634 635
}

static void test_state_queue_op()
{
lucapegolotti committed
636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709
  constexpr unsigned N = 1;

  bool ok;
  state::Queue<N> queue, new_queue;

  OpPtr<state::Queue<N>> try_enqueue_1_op_ptr, try_enqueue_2_op_ptr;
  OpPtr<state::Queue<N>> try_dequeue_op_ptr;

  OpPtr<state::Queue<N>> true_try_enqueue_ret_op_ptr{ state::Queue<N>::make_try_enqueue_ret(true) };
  OpPtr<state::Queue<N>> false_try_enqueue_ret_op_ptr{ state::Queue<N>::make_try_enqueue_ret(false) };

  const Op<state::Queue<N>>& true_try_enqueue_ret_op = *true_try_enqueue_ret_op_ptr;
  const Op<state::Queue<N>>& false_try_enqueue_ret_op = *false_try_enqueue_ret_op_ptr;

  OpPtr<state::Queue<N>> true_1_try_dequeue_ret_op_ptr{ state::Queue<N>::make_try_dequeue_ret(true, '\1') };
  OpPtr<state::Queue<N>> true_2_try_dequeue_ret_op_ptr{ state::Queue<N>::make_try_dequeue_ret(true, '\2') };
  OpPtr<state::Queue<N>> false_try_dequeue_ret_op_ptr{ state::Queue<N>::make_try_dequeue_ret(false, '\0') };

  const Op<state::Queue<N>>& true_1_try_dequeue_ret_op = *true_1_try_dequeue_ret_op_ptr;
  const Op<state::Queue<N>>& true_2_try_dequeue_ret_op = *true_2_try_dequeue_ret_op_ptr;
  const Op<state::Queue<N>>& false_try_dequeue_ret_op = *false_try_dequeue_ret_op_ptr;

  try_dequeue_op_ptr = state::Queue<N>::make_try_dequeue_call();
  Op<state::Queue<N>>& try_dequeue_op = *try_dequeue_op_ptr;
  
  std::tie(ok, new_queue) = try_dequeue_op.apply(queue, false_try_dequeue_ret_op);
  assert(queue == new_queue);
  assert(ok);
  
  std::tie(ok, new_queue) = try_dequeue_op.apply(queue, true_1_try_dequeue_ret_op);
  assert(queue == new_queue);
  assert(!ok);

  std::tie(ok, new_queue) = try_dequeue_op.apply(queue, true_2_try_dequeue_ret_op);
  assert(queue == new_queue);
  assert(!ok);
  

  try_enqueue_2_op_ptr = state::Queue<N>::make_try_enqueue_call('\2');
  Op<state::Queue<N>>& try_enqueue_2_op = *try_enqueue_2_op_ptr;

  std::tie(ok, new_queue) = try_enqueue_2_op.apply(queue, false_try_enqueue_ret_op);
  assert(queue != new_queue);
  assert(!ok);
  
  std::tie(ok, new_queue) = try_enqueue_2_op.apply(queue, true_try_enqueue_ret_op);
  assert(queue != new_queue);
  assert(ok);

  queue = new_queue;

  try_enqueue_1_op_ptr = state::Queue<N>::make_try_enqueue_call('\1');
  Op<state::Queue<N>>& try_enqueue_1_op = *try_enqueue_1_op_ptr;

  // queue is full
  std::tie(ok, new_queue) = try_enqueue_1_op.apply(queue, false_try_enqueue_ret_op);
  assert(queue == new_queue);
  assert(ok);

  std::tie(ok, new_queue) = try_enqueue_1_op.apply(queue, true_try_enqueue_ret_op);
  assert(queue == new_queue);
  assert(!ok);

  std::tie(ok, new_queue) = try_dequeue_op.apply(queue, false_try_dequeue_ret_op);
  assert(queue != new_queue);
  assert(!ok);

  std::tie(ok, new_queue) = try_dequeue_op.apply(queue, true_1_try_dequeue_ret_op);
  assert(queue != new_queue);
  assert(!ok);

  std::tie(ok, new_queue) = try_dequeue_op.apply(queue, true_2_try_dequeue_ret_op);
  assert(queue != new_queue);
  assert(ok);
710 711 712 713
}
/// The empty log is trivially linearizable.
static void test_linearizability_empty_log()
{
lucapegolotti committed
714 715 716 717 718
  std::size_t number_of_entries{ 0U };
  LogInfo<state::Set> log_info;
  LinearizabilityTester<state::Set> t{ log_info };
  assert(log_info.is_empty());
  assert(t.check());
719 720 721 722 723
}

/// a few sanity checks on the raw entry data structure
static void test_raw_single_contains_is_linearizable()
{
lucapegolotti committed
724
  Entry<state::Set> contains_call, contains_ret;
725

lucapegolotti committed
726 727
  contains_ret.set_op(state::Set::make_ret(false));
  contains_ret.prev = &contains_call;
728

lucapegolotti committed
729 730 731
  contains_call.set_op(state::Set::make_contains_call('\1'));
  contains_call.next = &contains_ret;
  contains_call.set_match(&contains_ret);
732

lucapegolotti committed
733 734 735 736
  std::size_t number_of_entries{ 2U };
  LogInfo<state::Set> log_info{ &contains_call, number_of_entries };
  LinearizabilityTester<state::Set> t{ log_info };
  assert(t.check());
737 738 739 740
}

static void test_raw_single_contains_is_not_linearizable()
{
lucapegolotti committed
741
  Entry<state::Set> contains_call, contains_ret;
742

lucapegolotti committed
743 744
  contains_ret.set_op(state::Set::make_ret(true));
  contains_ret.prev = &contains_call;
745

lucapegolotti committed
746 747 748
  contains_call.set_op(state::Set::make_contains_call('\1'));
  contains_call.next = &contains_ret;
  contains_call.set_match(&contains_ret);
749

lucapegolotti committed
750 751 752 753
  std::size_t number_of_entries{ 2U };
  LogInfo<state::Set> log_info{ &contains_call, number_of_entries };
  LinearizabilityTester<state::Set> t{ log_info };
  assert(!t.check());
754 755 756 757
}

static void test_single_contains(bool ret)
{
lucapegolotti committed
758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791
  Log<state::Set> log{ 4U };
  EntryPtr<state::Set> contains_call_entry_ptr, contains_ret_entry_ptr;

  contains_call_entry_ptr = log.add_call(state::Set::make_contains_call('\1'));
  contains_ret_entry_ptr = log.add_ret(contains_call_entry_ptr, state::Set::make_ret(ret));

  assert(log.log_head_ptr() == contains_call_entry_ptr);
  assert(log.number_of_entries() == 2U);

  assert(log.log_head_ptr() == contains_call_entry_ptr);
  assert(contains_call_entry_ptr->prev == nullptr);
  assert(contains_call_entry_ptr->next == contains_ret_entry_ptr);
  assert(contains_call_entry_ptr->match() == contains_ret_entry_ptr);

  assert(contains_ret_entry_ptr->match() == contains_call_entry_ptr);
  assert(contains_ret_entry_ptr->prev == contains_call_entry_ptr);
  assert(contains_ret_entry_ptr->next == nullptr);

  LinearizabilityTester<state::Set> t{ log.info() };
  assert(t.check() == (!ret));

  if (ret)
  {
    // If log cannot be linearized, then all pointers
    // (except the first one) are still the same.
    assert(log.log_head_ptr() == contains_call_entry_ptr);
    assert(contains_call_entry_ptr->prev != nullptr);
    assert(contains_call_entry_ptr->next == contains_ret_entry_ptr);
    assert(contains_call_entry_ptr->match() == contains_ret_entry_ptr);

    assert(contains_ret_entry_ptr->match() == contains_call_entry_ptr);
    assert(contains_ret_entry_ptr->prev == contains_call_entry_ptr);
    assert(contains_ret_entry_ptr->next == nullptr);
  }
792 793 794 795
}

static void test_log_copy()
{
lucapegolotti committed
796
  constexpr bool ret = true;
797

lucapegolotti committed
798 799
  Log<state::Set> log{ 4U };
  EntryPtr<state::Set> contains_call_entry_ptr, contains_ret_entry_ptr;
800

lucapegolotti committed
801 802
  contains_call_entry_ptr = log.add_call(state::Set::make_contains_call('\1'));
  contains_ret_entry_ptr = log.add_ret(contains_call_entry_ptr, state::Set::make_ret(ret));
803

lucapegolotti committed
804 805
  assert(log.log_head_ptr() == contains_call_entry_ptr);
  assert(log.number_of_entries() == 2U);
806

lucapegolotti committed
807 808 809 810
  assert(log.log_head_ptr() == contains_call_entry_ptr);
  assert(contains_call_entry_ptr->prev == nullptr);
  assert(contains_call_entry_ptr->next == contains_ret_entry_ptr);
  assert(contains_call_entry_ptr->match() == contains_ret_entry_ptr);
811

lucapegolotti committed
812 813 814
  assert(contains_ret_entry_ptr->match() == contains_call_entry_ptr);
  assert(contains_ret_entry_ptr->prev == contains_call_entry_ptr);
  assert(contains_ret_entry_ptr->next == nullptr);
815

lucapegolotti committed
816
  Log<state::Set> log_copy{ log.info() };
817

lucapegolotti committed
818 819 820 821 822 823 824
  assert(log_copy.log_head_ptr() != contains_call_entry_ptr);
  assert(log_copy.log_head_ptr() != contains_call_entry_ptr);
  assert(log_copy.log_head_ptr()->entry_id() == 0U);
  assert(&log_copy.log_head_ptr()->op() == &contains_call_entry_ptr->op());
  assert(log_copy.log_head_ptr() == log_copy.log_head_ptr()->match()->match());
  assert(log_copy.log_head_ptr()->prev == nullptr);
  assert(log_copy.number_of_entries() == 2U);
825 826 827 828 829 830 831 832 833
}

//   contains(x) : contains_ret
// |---------------------------|
//
//         insert(x) : insert_ret
//     |---------------------------|
static void test_000(bool insert_ret, bool contains_ret)
{
lucapegolotti committed
834
  constexpr char x = '\1';
835

lucapegolotti committed
836 837
  constexpr unsigned contains_entry_id{ 0U };
  constexpr unsigned insert_entry_id{ 1U };
838

lucapegolotti committed
839 840 841
  Log<state::Set> log{ 4U };
  EntryPtr<state::Set> contains_call_entry_ptr, contains_ret_entry_ptr;
  EntryPtr<state::Set> insert_call_entry_ptr, insert_ret_entry_ptr;
842

lucapegolotti committed
843 844 845 846
  contains_call_entry_ptr = log.add_call(state::Set::make_contains_call(x));
  insert_call_entry_ptr = log.add_call(state::Set::make_insert_call(x));
  contains_ret_entry_ptr = log.add_ret(contains_call_entry_ptr, state::Set::make_ret(contains_ret));
  insert_ret_entry_ptr = log.add_ret(insert_call_entry_ptr, state::Set::make_ret(insert_ret));
847

lucapegolotti committed
848 849
  assert(insert_call_entry_ptr->entry_id() == insert_entry_id);
  assert(insert_ret_entry_ptr->entry_id() == insert_entry_id);
850

lucapegolotti committed
851 852
  assert(contains_call_entry_ptr->entry_id() == contains_entry_id);
  assert(contains_ret_entry_ptr->entry_id() == contains_entry_id);
853

lucapegolotti committed
854 855
  LinearizabilityTester<state::Set> t{ log.info() };
  assert(t.check() == insert_ret);
856 857 858 859 860 861 862 863 864
}

//        contains(x) : contains_ret
//      |----------------------------|
//
//    insert(x) : insert_ret
// |-------------------------|
static void test_001(bool insert_ret, bool contains_ret)
{
lucapegolotti committed
865
  constexpr char x = '\1';
866

lucapegolotti committed
867 868
  constexpr unsigned insert_entry_id{ 0U };
  constexpr unsigned contains_entry_id{ 1U };
869

lucapegolotti committed
870 871 872
  Log<state::Set> log{ 4U };
  EntryPtr<state::Set> contains_call_entry_ptr, contains_ret_entry_ptr;
  EntryPtr<state::Set> insert_call_entry_ptr, insert_ret_entry_ptr;
873

lucapegolotti committed
874 875 876 877
  insert_call_entry_ptr = log.add_call(state::Set::make_insert_call(x));
  contains_call_entry_ptr = log.add_call(state::Set::make_contains_call(x));
  insert_ret_entry_ptr = log.add_ret(insert_call_entry_ptr, state::Set::make_ret(insert_ret));
  contains_ret_entry_ptr = log.add_ret(contains_call_entry_ptr, state::Set::make_ret(contains_ret));
878

lucapegolotti committed
879 880
  assert(insert_call_entry_ptr->entry_id() == insert_entry_id);
  assert(insert_ret_entry_ptr->entry_id() == insert_entry_id);
881

lucapegolotti committed
882 883
  assert(contains_call_entry_ptr->entry_id() == contains_entry_id);
  assert(contains_ret_entry_ptr->entry_id() == contains_entry_id);
884

lucapegolotti committed
885 886
  LinearizabilityTester<state::Set> t{ log.info() };
  assert(t.check() == insert_ret);
887 888 889 890 891 892 893 894 895
}

//      contains(x) : contains_ret
//    |----------------------------|
//
//       insert(x) : insert_ret
// |----------------------------------|
static void test_002(bool insert_ret, bool contains_ret)
{
lucapegolotti committed
896
  constexpr char x = '\1';
897

lucapegolotti committed
898 899
  constexpr unsigned insert_entry_id{ 0U };
  constexpr unsigned contains_entry_id{ 1U };
900

lucapegolotti committed
901 902 903
  Log<state::Set> log{ 4U };
  EntryPtr<state::Set> contains_call_entry_ptr, contains_ret_entry_ptr;
  EntryPtr<state::Set> insert_call_entry_ptr, insert_ret_entry_ptr;
904

lucapegolotti committed
905 906 907 908
  insert_call_entry_ptr = log.add_call(state::Set::make_insert_call(x));
  contains_call_entry_ptr = log.add_call(state::Set::make_contains_call(x));
  contains_ret_entry_ptr = log.add_ret(contains_call_entry_ptr, state::Set::make_ret(contains_ret));
  insert_ret_entry_ptr = log.add_ret(insert_call_entry_ptr, state::Set::make_ret(insert_ret));
909

lucapegolotti committed
910 911
  assert(insert_call_entry_ptr->entry_id() == insert_entry_id);
  assert(insert_ret_entry_ptr->entry_id() == insert_entry_id);
912

lucapegolotti committed
913 914
  assert(contains_call_entry_ptr->entry_id() == contains_entry_id);
  assert(contains_ret_entry_ptr->entry_id() == contains_entry_id);
915

lucapegolotti committed
916 917
  LinearizabilityTester<state::Set> t{ log.info() };
  assert(t.check() == insert_ret);
918 919 920 921 922 923 924 925 926
}

//     contains(x) : contains_ret
// |----------------------------------|
//
//       insert(x) : insert_ret
//    |---------------------------|
static void test_003(bool insert_ret, bool contains_ret)
{
lucapegolotti committed
927
  constexpr char x = '\1';
928

lucapegolotti committed
929 930
  constexpr unsigned contains_entry_id{ 0U };
  constexpr unsigned insert_entry_id{ 1U };
931

lucapegolotti committed
932 933 934
  Log<state::Set> log{ 4U };
  EntryPtr<state::Set> contains_call_entry_ptr, contains_ret_entry_ptr;
  EntryPtr<state::Set> insert_call_entry_ptr, insert_ret_entry_ptr;
935

lucapegolotti committed
936 937 938 939
  contains_call_entry_ptr = log.add_call(state::Set::make_contains_call(x));
  insert_call_entry_ptr = log.add_call(state::Set::make_insert_call(x));
  insert_ret_entry_ptr = log.add_ret(insert_call_entry_ptr, state::Set::make_ret(insert_ret));
  contains_ret_entry_ptr = log.add_ret(contains_call_entry_ptr, state::Set::make_ret(contains_ret));
940

lucapegolotti committed
941 942
  assert(insert_call_entry_ptr->entry_id() == insert_entry_id);
  assert(insert_ret_entry_ptr->entry_id() == insert_entry_id);
943

lucapegolotti committed
944 945
  assert(contains_call_entry_ptr->entry_id() == contains_entry_id);
  assert(contains_ret_entry_ptr->entry_id() == contains_entry_id);
946

lucapegolotti committed
947 948
  LinearizabilityTester<state::Set> t{ log.info() };
  assert(t.check() == insert_ret);
949 950 951 952 953 954
}

//   insert(x) : insert_ret     contains(x) : contains_ret
// |------------------------| |---------------------------|
static void test_004(bool insert_ret, bool contains_ret)
{
lucapegolotti committed
955
  constexpr char x = '\1';
956

lucapegolotti committed
957 958
  constexpr unsigned insert_entry_id{ 0U };
  constexpr unsigned contains_entry_id{ 1U };
959

lucapegolotti committed
960 961 962
  Log<state::Set> log{ 4U };
  EntryPtr<state::Set> contains_call_entry_ptr, contains_ret_entry_ptr;
  EntryPtr<state::Set> insert_call_entry_ptr, insert_ret_entry_ptr;
963

lucapegolotti committed
964 965 966 967
  insert_call_entry_ptr = log.add_call(state::Set::make_insert_call(x));
  insert_ret_entry_ptr = log.add_ret(insert_call_entry_ptr, state::Set::make_ret(insert_ret));
  contains_call_entry_ptr = log.add_call(state::Set::make_contains_call(x));
  contains_ret_entry_ptr = log.add_ret(contains_call_entry_ptr, state::Set::make_ret(contains_ret));
968

lucapegolotti committed
969 970
  assert(insert_call_entry_ptr->entry_id() == insert_entry_id);
  assert(insert_ret_entry_ptr->entry_id() == insert_entry_id);
971

lucapegolotti committed
972 973
  assert(contains_call_entry_ptr->entry_id() == contains_entry_id);
  assert(contains_ret_entry_ptr->entry_id() == contains_entry_id);
974

lucapegolotti committed
975 976
  LinearizabilityTester<state::Set> t{ log.info() };
  assert(t.check() == (insert_ret && contains_ret));
977 978 979 980 981 982
}

//   contains(x) : contains_ret    insert(x) : insert_ret
// |---------------------------| |------------------------| 
static void test_005(bool insert_ret, bool contains_ret)
{
lucapegolotti committed
983
  constexpr char x = '\1';
984

lucapegolotti committed
985 986
  constexpr unsigned contains_entry_id{ 0U };
  constexpr unsigned insert_entry_id{ 1U };
987

lucapegolotti committed
988 989 990
  Log<state::Set> log{ 4U };
  EntryPtr<state::Set> contains_call_entry_ptr, contains_ret_entry_ptr;
  EntryPtr<state::Set> insert_call_entry_ptr, insert_ret_entry_ptr;
991

lucapegolotti committed
992 993 994 995
  contains_call_entry_ptr = log.add_call(state::Set::make_contains_call(x));
  contains_ret_entry_ptr = log.add_ret(contains_call_entry_ptr, state::Set::make_ret(contains_ret));
  insert_call_entry_ptr = log.add_call(state::Set::make_insert_call(x));
  insert_ret_entry_ptr = log.add_ret(insert_call_entry_ptr, state::Set::make_ret(insert_ret));
996

lucapegolotti committed
997 998
  assert(insert_call_entry_ptr->entry_id() == insert_entry_id);
  assert(insert_ret_entry_ptr->entry_id() == insert_entry_id);
999

lucapegolotti committed
1000 1001
  assert(contains_call_entry_ptr->entry_id() == contains_entry_id);
  assert(contains_ret_entry_ptr->entry_id() == contains_entry_id);
1002

lucapegolotti committed
1003 1004
  LinearizabilityTester<state::Set> t{ log.info() };
  assert(t.check() == (insert_ret && !contains_ret));
1005 1006 1007 1008 1009 1010 1011 1012 1013
}

//   insert(x) : insert_ret_0
// |--------------------------|
//
//       insert(x) : insert_ret_1
//     |--------------------------|
static void test_006(bool insert_ret_0, bool insert_ret_1)
{
lucapegolotti committed
1014
  constexpr char x = '\1';
1015

lucapegolotti committed
1016 1017
  constexpr unsigned insert_0_entry_id{ 0U };
  constexpr unsigned insert_1_entry_id{ 1U };
1018

lucapegolotti committed
1019 1020
  EntryPtr<state::Set> insert_call_0_entry_ptr, insert_ret_0_entry_ptr;
  EntryPtr<state::Set> insert_call_1_entry_ptr, insert_ret_1_entry_ptr;
1021

lucapegolotti committed
1022
  Log<state::Set> log{ 4U };
1023

lucapegolotti committed
1024 1025 1026 1027
  insert_call_0_entry_ptr = log.add_call(state::Set::make_insert_call(x));
  insert_call_1_entry_ptr = log.add_call(state::Set::make_insert_call(x));
  insert_ret_0_entry_ptr = log.add_ret(insert_call_0_entry_ptr, state::Set::make_ret(insert_ret_0));
  insert_ret_1_entry_ptr = log.add_ret(insert_call_1_entry_ptr, state::Set::make_ret(insert_ret_1));
1028

lucapegolotti committed
1029 1030
  assert(insert_call_0_entry_ptr->entry_id() == insert_0_entry_id);
  assert(insert_ret_0_entry_ptr->entry_id() == insert_0_entry_id);
1031

lucapegolotti committed
1032 1033
  assert(insert_call_1_entry_ptr->entry_id() == insert_1_entry_id);
  assert(insert_ret_1_entry_ptr->entry_id() == insert_1_entry_id);
1034

lucapegolotti committed
1035 1036
  LinearizabilityTester<state::Set> t{ log.info() };
  assert(t.check() == (!(insert_ret_0 == insert_ret_1)));
1037 1038 1039 1040 1041 1042
}

//   insert(x) : insert_ret_0     insert(x) : insert_ret_1
// |--------------------------| |--------------------------|
static void test_007(bool insert_ret_0, bool insert_ret_1)
{
lucapegolotti committed
1043
  constexpr char x = '\1';
1044

lucapegolotti committed
1045 1046
  constexpr unsigned insert_0_entry_id{ 0U };
  constexpr unsigned insert_1_entry_id{ 1U };
1047

lucapegolotti committed
1048 1049
  EntryPtr<state::Set> insert_call_0_entry_ptr, insert_ret_0_entry_ptr;
  EntryPtr<state::Set> insert_call_1_entry_ptr, insert_ret_1_entry_ptr;
1050

lucapegolotti committed
1051
  Log<state::Set> log{ 4U };
1052

lucapegolotti committed
1053 1054 1055 1056
  insert_call_0_entry_ptr = log.add_call(state::Set::make_insert_call(x));
  insert_ret_0_entry_ptr = log.add_ret(insert_call_0_entry_ptr, state::Set::make_ret(insert_ret_0));
  insert_call_1_entry_ptr = log.add_call(state::Set::make_insert_call(x));
  insert_ret_1_entry_ptr = log.add_ret(insert_call_1_entry_ptr, state::Set::make_ret(insert_ret_1));
1057

lucapegolotti committed
1058 1059
  assert(insert_call_0_entry_ptr->entry_id() == insert_0_entry_id);
  assert(insert_ret_0_entry_ptr->entry_id() == insert_0_entry_id);
1060

lucapegolotti committed
1061 1062
  assert(insert_call_1_entry_ptr->entry_id() == insert_1_entry_id);
  assert(insert_ret_1_entry_ptr->entry_id() == insert_1_entry_id);
1063

lucapegolotti committed
1064 1065
  LinearizabilityTester<state::Set> t{ log.info() };
  assert(t.check() == (insert_ret_0 && !insert_ret_1));
1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078
}

//           insert(x) : insert_ret
// |------------------------------------------|
//
//           insert(x) : insert_ret
//   |-------------------------------------|
//
//         contains(x) : contains_ret
//       |----------------------------|
//
static void test_008(bool insert_ret, bool contains_ret)
{
lucapegolotti committed
1079
  constexpr char x = '\1';
1080

lucapegolotti committed
1081 1082 1083
  constexpr unsigned insert_0_entry_id{ 0U };
  constexpr unsigned insert_1_entry_id{ 1U };
  constexpr unsigned contains_entry_id{ 2U };
1084

lucapegolotti committed
1085 1086 1087 1088
  Log<state::Set> log{ 8U };
  EntryPtr<state::Set> contains_call_entry_ptr, contains_ret_entry_ptr;
  EntryPtr<state::Set> insert_0_call_entry_ptr, insert_0_ret_entry_ptr;
  EntryPtr<state::Set> insert_1_call_entry_ptr, insert_1_ret_entry_ptr;
1089

lucapegolotti committed
1090 1091 1092 1093 1094 1095
  insert_0_call_entry_ptr = log.add_call(state::Set::make_insert_call(x));
  insert_1_call_entry_ptr = log.add_call(state::Set::make_insert_call(x));
  contains_call_entry_ptr = log.add_call(state::Set::make_contains_call(x));
  contains_ret_entry_ptr = log.add_ret(contains_call_entry_ptr, state::Set::make_ret(contains_ret));
  insert_1_ret_entry_ptr = log.add_ret(insert_1_call_entry_ptr, state::Set::make_ret(insert_ret));
  insert_0_ret_entry_ptr = log.add_ret(insert_0_call_entry_ptr, state::Set::make_ret(insert_ret));
1096

lucapegolotti committed
1097 1098
  assert(insert_0_call_entry_ptr->entry_id() == insert_0_entry_id);
  assert(insert_0_ret_entry_ptr->entry_id() == insert_0_entry_id);
1099

lucapegolotti committed
1100 1101
  assert(insert_1_call_entry_ptr->entry_id() == insert_1_entry_id);
  assert(insert_1_ret_entry_ptr->entry_id() == insert_1_entry_id);
1102

lucapegolotti committed
1103 1104
  assert(contains_call_entry_ptr->entry_id() == contains_entry_id);
  assert(contains_ret_entry_ptr->entry_id() == contains_entry_id);
1105

lucapegolotti committed
1106 1107
  LinearizabilityTester<state::Set> t{ log.info() };
  assert(!t.check());
1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123
}

// !linearizable:
//
// Let x && y be distinct values.
//
//   contains(x) : false 
// |---------------------|
//
//      contains(y) : false
//    |---------------------|
//
//          insert(x) : false
//        |---------------------|
static void test_009()
{
lucapegolotti committed
1124 1125
  constexpr char x = '\1';
  constexpr char y = '\2';
1126

lucapegolotti committed
1127 1128 1129
  constexpr unsigned contains_x_entry_id{ 0U };
  constexpr unsigned contains_y_entry_id{ 1U };
  constexpr unsigned insert_x_entry_id{ 2U };
1130

lucapegolotti committed
1131
  Log<state::Set> log{ 6U };
1132

lucapegolotti committed
1133 1134 1135
  EntryPtr<state::Set> contains_x_call_entry_ptr, contains_x_ret_entry_ptr;
  EntryPtr<state::Set> contains_y_call_entry_ptr, contains_y_ret_entry_ptr;
  EntryPtr<state::Set> insert_x_call_entry_ptr, insert_x_ret_entry_ptr;
1136

lucapegolotti committed
1137 1138 1139
  contains_x_call_entry_ptr = log.add_call(state::Set::make_contains_call(x));
  contains_y_call_entry_ptr = log.add_call(state::Set::make_contains_call(y));
  insert_x_call_entry_ptr = log.add_call(state::Set::make_insert_call(x));
1140

lucapegolotti committed
1141 1142 1143
  contains_x_ret_entry_ptr = log.add_ret(contains_x_call_entry_ptr, state::Set::make_ret(false));
  contains_y_ret_entry_ptr = log.add_ret(contains_y_call_entry_ptr, state::Set::make_ret(false));
  insert_x_ret_entry_ptr = log.add_ret(insert_x_call_entry_ptr, state::Set::make_ret(false));
1144

lucapegolotti committed
1145 1146
  assert(contains_x_call_entry_ptr->entry_id() == contains_x_entry_id);
  assert(contains_x_ret_entry_ptr->entry_id() == contains_x_entry_id);
1147

lucapegolotti committed
1148 1149
  assert(contains_y_call_entry_ptr->entry_id() == contains_y_entry_id);
  assert(contains_y_ret_entry_ptr->entry_id() == contains_y_entry_id);
1150

lucapegolotti committed
1151 1152
  assert(insert_x_call_entry_ptr->entry_id() == insert_x_entry_id);
  assert(insert_x_ret_entry_ptr->entry_id() == insert_x_entry_id);
1153

lucapegolotti committed
1154 1155
  LinearizabilityTester<state::Set> t{ log.info() };
  assert(!t.check());
1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171
}

// !linearizable:
//
// Let x && y be distinct values.
//
//   contains(x) : false 
// |---------------------|
//
//       insert(x) : false
//    |---------------------|
//
//          contains(y) : false
//        |---------------------|
static void test_010()
{
lucapegolotti committed
1172 1173
  constexpr char x = '\1';
  constexpr char y = '\2';
1174

lucapegolotti committed
1175 1176 1177
  constexpr unsigned contains_x_entry_id{ 0U };
  constexpr unsigned insert_x_entry_id{ 1U };
  constexpr unsigned contains_y_entry_id{ 2U };
1178

lucapegolotti committed
1179
  Log<state::Set> log{ 6U };
1180

lucapegolotti committed
1181 1182 1183
  EntryPtr<state::Set> contains_x_call_entry_ptr, contains_x_ret_entry_ptr;
  EntryPtr<state::Set> contains_y_call_entry_ptr, contains_y_ret_entry_ptr;
  EntryPtr<state::Set> insert_x_call_entry_ptr, insert_x_ret_entry_ptr;
1184

lucapegolotti committed
1185 1186 1187
  contains_x_call_entry_ptr = log.add_call(state::Set::make_contains_call(x));
  insert_x_call_entry_ptr = log.add_call(state::Set::make_insert_call(x));
  contains_y_call_entry_ptr = log.add_call(state::Set::make_contains_call(y));
1188

lucapegolotti committed
1189 1190 1191
  contains_x_ret_entry_ptr = log.add_ret(contains_x_call_entry_ptr, state::Set::make_ret(false));
  insert_x_ret_entry_ptr = log.add_ret(insert_x_call_entry_ptr, state::Set::make_ret(false));
  contains_y_ret_entry_ptr = log.add_ret(contains_y_call_entry_ptr, state::Set::make_ret(false));
1192

lucapegolotti committed
1193 1194
  assert(contains_x_call_entry_ptr->entry_id() == contains_x_entry_id);
  assert(contains_x_ret_entry_ptr->entry_id() == contains_x_entry_id);
1195

lucapegolotti committed
1196 1197
  assert(insert_x_call_entry_ptr->entry_id() == insert_x_entry_id);
  assert(insert_x_ret_entry_ptr->entry_id() == insert_x_entry_id);
1198

lucapegolotti committed
1199 1200
  assert(contains_y_call_entry_ptr->entry_id() == contains_y_entry_id);
  assert(contains_y_ret_entry_ptr->entry_id() == contains_y_entry_id);
1201

lucapegolotti committed
1202 1203
  LinearizabilityTester<state::Set> t{ log.info() };
  assert(!t.check());
1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219
}

// Linearizable:
//
// Let x && y be distinct values.
//
//   insert(x) : true
// |------------------|
//
//      contains(y) : false
//    |---------------------|
//
//         contains(x) : false
//       |---------------------|
static void test_011()
{
lucapegolotti committed
1220 1221
  constexpr char x = '\1';
  constexpr char y = '\2';
1222

lucapegolotti committed
1223 1224 1225
  constexpr unsigned insert_x_entry_id{ 0U };
  constexpr unsigned contains_y_entry_id{ 1U };
  constexpr unsigned contains_x_entry_id{ 2U };
1226

lucapegolotti committed
1227
  Log<state::Set> log{ 6U };
1228

lucapegolotti committed
1229 1230 1231
  EntryPtr<state::Set> insert_x_call_entry_ptr, insert_x_ret_entry_ptr;
  EntryPtr<state::Set> contains_y_call_entry_ptr, contains_y_ret_entry_ptr;
  EntryPtr<state::Set> contains_x_call_entry_ptr, contains_x_ret_entry_ptr;
1232

lucapegolotti committed
1233 1234 1235
  insert_x_call_entry_ptr = log.add_call(state::Set::make_insert_call(x));
  contains_y_call_entry_ptr = log.add_call(state::Set::make_contains_call(y));
  contains_x_call_entry_ptr = log.add_call(state::Set::make_contains_call(x));
1236

lucapegolotti committed
1237 1238 1239
  insert_x_ret_entry_ptr = log.add_ret(insert_x_call_entry_ptr, state::Set::make_ret(true));
  contains_y_ret_entry_ptr = log.add_ret(contains_y_call_entry_ptr, state::Set::make_ret(false));
  contains_x_ret_entry_ptr = log.add_ret(contains_x_call_entry_ptr, state::Set::make_ret(false));
1240

lucapegolotti committed
1241 1242
  assert(insert_x_call_entry_ptr->entry_id() == insert_x_entry_id);
  assert(insert_x_ret_entry_ptr->entry_id() == insert_x_entry_id);
1243

lucapegolotti committed
1244 1245
  assert(contains_y_call_entry_ptr->entry_id() == contains_y_entry_id);
  assert(contains_y_ret_entry_ptr->entry_id() == contains_y_entry_id);
1246

lucapegolotti committed
1247 1248
  assert(contains_x_call_entry_ptr->entry_id() == contains_x_entry_id);
  assert(contains_x_ret_entry_ptr->entry_id() == contains_x_entry_id);
1249

lucapegolotti committed
1250 1251
  LinearizabilityTester<state::Set> t{ log.info() };
  assert(t.check());
1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267
}

// Linearizable:
//
// Let x && y be distinct values.
//
//   erase(x) : false     insert(y) : true
// |------------------| |------------------|
//
//                                               contains(x) : true
//                                 |------------------------------------------------|
//
//                                      contains(y) : false     insert(x) : true
//                                    |---------------------| |------------------|
static void test_012()
{
lucapegolotti committed
1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291
  constexpr char x = '\1';
  constexpr char y = '\2';

  Log<state::Set> log{ 10U };

  EntryPtr<state::Set> erase_x_call_entry_ptr, erase_x_ret_entry_ptr;
  EntryPtr<state::Set> insert_x_call_entry_ptr, insert_x_ret_entry_ptr;
  EntryPtr<state::Set> contains_x_call_entry_ptr, contains_x_ret_entry_ptr;
  EntryPtr<state::Set> insert_y_call_entry_ptr, insert_y_ret_entry_ptr;
  EntryPtr<state::Set> contains_y_call_entry_ptr, contains_y_ret_entry_ptr;

  erase_x_call_entry_ptr = log.add_call(state::Set::make_erase_call(x));
  erase_x_ret_entry_ptr = log.add_ret(erase_x_call_entry_ptr, state::Set::make_ret(false));
  insert_y_call_entry_ptr = log.add_call(state::Set::make_insert_call(y));
  contains_x_call_entry_ptr = log.add_call(state::Set::make_contains_call(x));
  contains_y_call_entry_ptr = log.add_call(state::Set::make_contains_call(y));
  insert_y_ret_entry_ptr = log.add_ret(insert_y_call_entry_ptr, state::Set::make_ret(true));
  contains_y_ret_entry_ptr = log.add_ret(contains_y_call_entry_ptr, state::Set::make_ret(false));
  insert_x_call_entry_ptr = log.add_call(state::Set::make_insert_call(x));
  insert_x_ret_entry_ptr = log.add_ret(insert_x_call_entry_ptr, state::Set::make_ret(true));
  contains_x_ret_entry_ptr = log.add_ret(contains_x_call_entry_ptr, state::Set::make_ret(true));

  LinearizabilityTester<state::Set> t{ log.info() };
  assert(t.check());
1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307
}

// entry id: X0, call: contains(x)
// entry id: X1, call: insert(x)
// entry id: X0, return: ret: 0
// entry id: X2, call: contains(x)
// entry id: X2, return: ret: 0
// entry id: X3, call: insert(x)
// entry id: X3, return: ret: 1
// entry id: X4, call: contains(x)
// entry id: X4, return: ret: 1
// entry id: X1, return: ret: 0
// entry id: X5, call: contains(x)
// entry id: X5, return: ret: 1
static void test_013()
{
lucapegolotti committed
1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333
  constexpr char x = '\1';

  Log<state::Set> log{ 12U };

  EntryPtr<state::Set> call_x0_entry_ptr, ret_x0_entry_ptr;
  EntryPtr<state::Set> call_x1_entry_ptr, ret_x1_entry_ptr;
  EntryPtr<state::Set> call_x2_entry_ptr, ret_x2_entry_ptr;
  EntryPtr<state::Set> call_x3_entry_ptr, ret_x3_entry_ptr;
  EntryPtr<state::Set> call_x4_entry_ptr, ret_x4_entry_ptr;
  EntryPtr<state::Set> call_x5_entry_ptr, ret_x5_entry_ptr;

  call_x0_entry_ptr = log.add_call(state::Set::make_contains_call(x));
  call_x1_entry_ptr = log.add_call(state::Set::make_insert_call(x));
  ret_x0_entry_ptr = log.add_ret(call_x0_entry_ptr, state::Set::make_ret(false));
  call_x2_entry_ptr = log.add_call(state::Set::make_contains_call(x));
  ret_x2_entry_ptr = log.add_ret(call_x2_entry_ptr, state::Set::make_ret(false));
  call_x3_entry_ptr = log.add_call(state::Set::make_insert_call(x));
  ret_x3_entry_ptr = log.add_ret(call_x3_entry_ptr, state::Set::make_ret(true));
  call_x4_entry_ptr = log.add_call(state::Set::make_contains_call(x));
  ret_x4_entry_ptr = log.add_ret(call_x4_entry_ptr, state::Set::make_ret(true));
  ret_x1_entry_ptr = log.add_ret(call_x1_entry_ptr, state::Set::make_ret(false));
  call_x5_entry_ptr = log.add_call(state::Set::make_contains_call(x));
  ret_x5_entry_ptr = log.add_ret(call_x5_entry_ptr, state::Set::make_ret(true));

  LinearizabilityTester<state::Set> t{ log.info() };
  assert(t.check());
1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353
}

// Let x && y be distinct.
//
// entry id: X0, call: contains(x)
// entry id: X1, call: insert(x)
// entry id: X0, return: ret: 0
// entry id: Y0, call: contains(y) <- !linearizable
// entry id: Y0, return: ret: 1
// entry id: X2, call: contains(x)
// entry id: X2, return: ret: 0
// entry id: X3, call: insert(x)
// entry id: X3, return: ret: 1
// entry id: X4, call: contains(x)
// entry id: X4, return: ret: 1
// entry id: X1, return: ret: 0
// entry id: X5, call: contains(x)
// entry id: X5, return: ret: 1
static void test_014()
{
lucapegolotti committed
1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388
  constexpr char x = '\1';
  constexpr char y = '\2';

  constexpr unsigned not_linearizable_entry_id = 2U;

  Log<state::Set> log{ 14U };

  EntryPtr<state::Set> call_x0_entry_ptr, ret_x0_entry_ptr;
  EntryPtr<state::Set> call_x1_entry_ptr, ret_x1_entry_ptr;
  EntryPtr<state::Set> call_x2_entry_ptr, ret_x2_entry_ptr;
  EntryPtr<state::Set> call_x3_entry_ptr, ret_x3_entry_ptr;
  EntryPtr<state::Set> call_x4_entry_ptr, ret_x4_entry_ptr;
  EntryPtr<state::Set> call_x5_entry_ptr, ret_x5_entry_ptr;

  EntryPtr<state::Set> call_y0_entry_ptr, ret_y0_entry_ptr;

  call_x0_entry_ptr = log.add_call(state::Set::make_contains_call(x));
  call_x1_entry_ptr = log.add_call(state::Set::make_insert_call(x));
  ret_x0_entry_ptr = log.add_ret(call_x0_entry_ptr, state::Set::make_ret(false));
  call_y0_entry_ptr = log.add_call(state::Set::make_contains_call(y));
  ret_y0_entry_ptr = log.add_ret(call_y0_entry_ptr, state::Set::make_ret(true));
  call_x2_entry_ptr = log.add_call(state::Set::make_contains_call(x));
  ret_x2_entry_ptr = log.add_ret(call_x2_entry_ptr, state::Set::make_ret(false));
  call_x3_entry_ptr = log.add_call(state::Set::make_insert_call(x));
  ret_x3_entry_ptr = log.add_ret(call_x3_entry_ptr, state::Set::make_ret(true));
  call_x4_entry_ptr = log.add_call(state::Set::make_contains_call(x));
  ret_x4_entry_ptr = log.add_ret(call_x4_entry_ptr, state::Set::make_ret(true));
  ret_x1_entry_ptr = log.add_ret(call_x1_entry_ptr, state::Set::make_ret(false));
  call_x5_entry_ptr = log.add_call(state::Set::make_contains_call(x));
  ret_x5_entry_ptr = log.add_ret(call_x5_entry_ptr, state::Set::make_ret(true));

  assert(call_y0_entry_ptr->entry_id() == not_linearizable_entry_id);

  LinearizabilityTester<state::Set> t{ log.info() };
  assert(!t.check());
1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401
}

// !linearizable:
//
// Let x && y be distinct values.
//
//   contains(x) : false     contains(y) : true
// |---------------------| |--------------------|
//
//                          insert(x) : true
//                    |----------------------------|
static void test_015()
{
lucapegolotti committed
1402 1403
  constexpr char x = '\1';
  constexpr char y = '\2';
1404

lucapegolotti committed
1405 1406 1407
  constexpr unsigned contains_x_entry_id{ 0U };
  constexpr unsigned insert_x_entry_id{ 1U };
  constexpr unsigned contains_y_entry_id{ 2U };
1408

lucapegolotti committed
1409
  Log<state::Set> log{ 6U };
1410

lucapegolotti committed
1411 1412 1413
  EntryPtr<state::Set> contains_x_call_entry_ptr, contains_x_ret_entry_ptr;
  EntryPtr<state::Set> insert_x_call_entry_ptr, insert_x_ret_entry_ptr;
  EntryPtr<state::Set> contains_y_call_entry_ptr, contains_y_ret_entry_ptr;
1414

lucapegolotti committed
1415 1416 1417 1418 1419 1420
  contains_x_call_entry_ptr = log.add_call(state::Set::make_contains_call(x));
  insert_x_call_entry_ptr = log.add_call(state::Set::make_insert_call(x));
  contains_x_ret_entry_ptr = log.add_ret(contains_x_call_entry_ptr, state::Set::make_ret(false));
  contains_y_call_entry_ptr = log.add_call(state::Set::make_contains_call(y));
  contains_y_ret_entry_ptr = log.add_ret(contains_y_call_entry_ptr, state::Set::make_ret(true));
  insert_x_ret_entry_ptr = log.add_ret(insert_x_call_entry_ptr, state::Set::make_ret(true));
1421

lucapegolotti committed
1422 1423
  assert(contains_x_call_entry_ptr->entry_id() == contains_x_entry_id);
  assert(contains_x_ret_entry_ptr->entry_id() == contains_x_entry_id);
1424

lucapegolotti committed
1425 1426
  assert(insert_x_call_entry_ptr->entry_id() == insert_x_entry_id);
  assert(insert_x_ret_entry_ptr->entry_id() == insert_x_entry_id);
1427

lucapegolotti committed
1428 1429
  assert(contains_y_call_entry_ptr->entry_id() == contains_y_entry_id);
  assert(contains_y_ret_entry_ptr->entry_id() == contains_y_entry_id);
1430

lucapegolotti committed
1431 1432
  LinearizabilityTester<state::Set> t{ log.info() };
  assert(!t.check());
1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445
}

// !linearizable:
//
// Let x && y be distinct values.
//
//   contains(x) : false     contains(y) : true     contains(x) : false
// |---------------------| |--------------------| |---------------------|
//
//                             insert(x) : true
//                    |------------------------------|
static void test_016()
{
lucapegolotti committed
1446 1447
  constexpr char x = '\1';
  constexpr char y = '\2';
1448

lucapegolotti committed
1449
  constexpr unsigned not_linearizable_entry_id = 2U;
1450

lucapegolotti committed
1451
  Log<state::Set> log{ 8U };
1452

lucapegolotti committed
1453 1454 1455 1456
  EntryPtr<state::Set> call_x0_entry_ptr, ret_x0_entry_ptr;
  EntryPtr<state::Set> call_x1_entry_ptr, ret_x1_entry_ptr;
  EntryPtr<state::Set> call_x2_entry_ptr, ret_x2_entry_ptr;
  EntryPtr<state::Set> call_y0_entry_ptr, ret_y0_entry_ptr;
1457

lucapegolotti committed
1458 1459 1460 1461 1462 1463 1464 1465
  call_x0_entry_ptr = log.add_call(state::Set::make_contains_call(x));
  call_x1_entry_ptr = log.add_call(state::Set::make_insert_call(x));
  ret_x0_entry_ptr = log.add_ret(call_x0_entry_ptr, state::Set::make_ret(false));
  call_y0_entry_ptr = log.add_call(state::Set::make_contains_call(y));
  ret_y0_entry_ptr = log.add_ret(call_y0_entry_ptr, state::Set::make_ret(true));
  call_x2_entry_ptr = log.add_call(state::Set::make_contains_call(x));
  ret_x1_entry_ptr = log.add_ret(call_x1_entry_ptr, state::Set::make_ret(true));
  ret_x2_entry_ptr = log.add_ret(call_x2_entry_ptr, state::Set::make_ret(false));
1466

lucapegolotti committed
1467
  assert(call_y0_entry_ptr->entry_id() == not_linearizable_entry_id);
1468

lucapegolotti committed
1469 1470
  LinearizabilityTester<state::Set> t{ log.info() };
  assert(!t.check());
1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483
}

// !linearizable:
//
// Let x && y be distinct values.
//
//   contains(x) : false     contains(y) : true     contains(x) : false
// |---------------------| |--------------------| |---------------------|
//
//                                      insert(x) : true
//                    |-----------------------------------------------------|
static void test_017()
{
lucapegolotti committed
1484 1485
  constexpr char x = '\1';
  constexpr char y = '\2';
1486

lucapegolotti committed
1487
  constexpr unsigned not_linearizable_entry_id = 2U;
1488

lucapegolotti committed
1489
  Log<state::Set> log{ 8U };
1490

lucapegolotti committed
1491 1492 1493 1494
  EntryPtr<state::Set> call_x0_entry_ptr, ret_x0_entry_ptr;
  EntryPtr<state::Set> call_x1_entry_ptr, ret_x1_entry_ptr;
  EntryPtr<state::Set> call_x2_entry_ptr, ret_x2_entry_ptr;
  EntryPtr<state::Set> call_y0_entry_ptr, ret_y0_entry_ptr;
1495

lucapegolotti committed
1496 1497 1498 1499 1500 1501 1502 1503
  call_x0_entry_ptr = log.add_call(state::Set::make_contains_call(x));
  call_x1_entry_ptr = log.add_call(state::Set::make_insert_call(x));
  ret_x0_entry_ptr = log.add_ret(call_x0_entry_ptr, state::Set::make_ret(false));
  call_y0_entry_ptr = log.add_call(state::Set::make_contains_call(y));
  ret_y0_entry_ptr = log.add_ret(call_y0_entry_ptr, state::Set::make_ret(true));
  call_x2_entry_ptr = log.add_call(state::Set::make_contains_call(x));
  ret_x2_entry_ptr = log.add_ret(call_x2_entry_ptr, state::Set::make_ret(false));
  ret_x1_entry_ptr = log.add_ret(call_x1_entry_ptr, state::Set::make_ret(true));
1504

lucapegolotti committed
1505
  assert(call_y0_entry_ptr->entry_id() == not_linearizable_entry_id);
1506

lucapegolotti committed
1507 1508
  LinearizabilityTester<state::Set> t{ log.info() };
  assert(!t.check());
1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521
}

// !linearizable:
//
// Let x && y be distinct values.
//
//      contains(y) : true     insert(x) : true
//    |--------------------| |------------------|
//
//                insert(x) : false
// |------------------------------------------------|
static void test_018()
{
lucapegolotti committed
1522 1523
  constexpr char x = '\1';
  constexpr char y = '\2';
1524

lucapegolotti committed
1525
  constexpr unsigned not_linearizable_entry_id = 1U;
1526

lucapegolotti committed
1527
  Log<state::Set> log{ 8U };
1528

lucapegolotti committed
1529 1530 1531
  EntryPtr<state::Set> call_x0_entry_ptr, ret_x0_entry_ptr;
  EntryPtr<state::Set> call_x1_entry_ptr, ret_x1_entry_ptr;
  EntryPtr<state::Set> call_y0_entry_ptr, ret_y0_entry_ptr;
1532

lucapegolotti committed
1533 1534 1535 1536 1537 1538
  call_x0_entry_ptr = log.add_call(state::Set::make_insert_call(x));
  call_y0_entry_ptr = log.add_call(state::Set::make_contains_call(y));
  ret_y0_entry_ptr = log.add_ret(call_y0_entry_ptr, state::Set::make_ret(true));
  call_x1_entry_ptr = log.add_call(state::Set::make_insert_call(x));
  ret_x1_entry_ptr = log.add_ret(call_x1_entry_ptr, state::Set::make_ret(true));
  ret_x0_entry_ptr = log.add_ret(call_x1_entry_ptr, state::Set::make_ret(false));
1539

lucapegolotti committed
1540
  assert(call_y0_entry_ptr->entry_id() == not_linearizable_entry_id);
1541

lucapegolotti committed
1542 1543
  LinearizabilityTester<state::Set> t{ log.info() };
  assert(!t.check());
1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557
}

// Linearizable:
//
//   insert(x) : insert_ret
// |------------------------|
//
//               contains(x) : contains_ret
//            |-----------------------------|
//
//                 empty() : empty_ret 
//             |------------------------|
static void test_019(bool insert_ret, bool contains_ret, bool empty_ret)
{
lucapegolotti committed
1558
  constexpr char x = '\1';
1559

lucapegolotti committed
1560
  Log<state::Set> log{ 8U };
1561

lucapegolotti committed
1562 1563 1564
  EntryPtr<state::Set> call_insert_entry_ptr, ret_insert_entry_ptr;
  EntryPtr<state::Set> call_contains_entry_ptr, ret_contains_entry_ptr;
  EntryPtr<state::Set> call_empty_entry_ptr, ret_empty_entry_ptr;
1565

lucapegolotti committed
1566 1567 1568 1569 1570 1571
  call_insert_entry_ptr = log.add_call(state::Set::make_insert_call(x));
  call_contains_entry_ptr = log.add_call(state::Set::make_contains_call(x));
  call_empty_entry_ptr = log.add_call(state::Set::make_empty_call());
  ret_insert_entry_ptr = log.add_ret(call_insert_entry_ptr, state::Set::make_ret(insert_ret));
  ret_empty_entry_ptr = log.add_ret(call_empty_entry_ptr, state::Set::make_ret(empty_ret));
  ret_contains_entry_ptr = log.add_ret(call_contains_entry_ptr, state::Set::make_ret(contains_ret));
1572

lucapegolotti committed
1573 1574
  LinearizabilityTester<state::Set> t{ log.info() };
  assert(t.check() == insert_ret);
1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586
}

//                                                          insert(x) : insert_ret
//                                                        |------------------------|
//
//   contains(x) :  contains_ret    contains(x) : contains_ret
// |----------------------------| |----------------------------|
//
//                                                     empty() : empty_ret
//                                                   |----------------------|
static void test_020(bool insert_ret, bool contains_ret, bool empty_ret)
{
lucapegolotti committed
1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606
  constexpr char x = '\1';

  Log<state::Set> log{ 8U };

  EntryPtr<state::Set> call_contains_0_entry_ptr, ret_contains_0_entry_ptr;
  EntryPtr<state::Set> call_contains_1_entry_ptr, ret_contains_1_entry_ptr;
  EntryPtr<state::Set> call_insert_entry_ptr, ret_insert_entry_ptr;
  EntryPtr<state::Set> call_empty_entry_ptr, ret_empty_entry_ptr;

  call_contains_0_entry_ptr = log.add_call(state::Set::make_contains_call(x));
  ret_contains_0_entry_ptr = log.add_ret(call_contains_0_entry_ptr, state::Set::make_ret(contains_ret));
  call_contains_1_entry_ptr = log.add_call(state::Set::make_contains_call(x));
  call_empty_entry_ptr = log.add_call(state::Set::make_empty_call());
  call_insert_entry_ptr = log.add_call(state::Set::make_insert_call(x));
  ret_contains_1_entry_ptr = log.add_ret(call_contains_1_entry_ptr, state::Set::make_ret(contains_ret));
  ret_empty_entry_ptr = log.add_ret(call_empty_entry_ptr, state::Set::make_ret(empty_ret));
  ret_insert_entry_ptr = log.add_ret(call_insert_entry_ptr, state::Set::make_ret(insert_ret));

  LinearizabilityTester<state::Set> t{ log.info() };
  assert(t.check() == (insert_ret && !contains_ret));
1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622
}

// Linearizable:
//
// Let x && y be distinct values.
//
//   contains(x) : false
// |---------------------|
//
//              insert(y) : true
//           |-----------------------------------------------------------|
//
//                            contains(x) : false      empty() : true
//                          |---------------------|  |----------------|
static void test_021()
{
lucapegolotti committed
1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643
  constexpr char x = '\1';
  constexpr char y = '\2';

  Log<state::Set> log{ 8U };

  EntryPtr<state::Set> call_contains_0_entry_ptr, ret_contains_0_entry_ptr;
  EntryPtr<state::Set> call_contains_1_entry_ptr, ret_contains_1_entry_ptr;
  EntryPtr<state::Set> call_insert_entry_ptr, ret_insert_entry_ptr;
  EntryPtr<state::Set> call_empty_entry_ptr, ret_empty_entry_ptr;

  call_contains_0_entry_ptr = log.add_call(state::Set::make_contains_call(x));
  call_insert_entry_ptr = log.add_call(state::Set::make_insert_call(y));
  ret_contains_0_entry_ptr = log.add_ret(call_contains_0_entry_ptr, state::Set::make_ret(false));
  call_contains_1_entry_ptr = log.add_call(state::Set::make_contains_call(x));
  ret_contains_1_entry_ptr = log.add_ret(call_contains_1_entry_ptr, state::Set::make_ret(false));
  call_empty_entry_ptr = log.add_call(state::Set::make_empty_call());
  ret_empty_entry_ptr = log.add_ret(call_empty_entry_ptr, state::Set::make_ret(true));
  ret_insert_entry_ptr = log.add_ret(call_insert_entry_ptr, state::Set::make_ret(1));

  LinearizabilityTester<state::Set> t{ log.info() };
  assert(t.check());
1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657
}

// Linearizable:
//
//        push(x) : true
// |------------------------|
//
//        push(y) : true
//   |--------------------|
//
//      pop() : (true, x)
//    |------------------|
static void test_stack_history_000()
{
lucapegolotti committed
1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683
  constexpr char x = '\1';
  constexpr char y = '\2';
  constexpr std::size_t N = 5;

  Log<state::Stack<N>> log{ 6U };
  EntryPtr<state::Stack<N>> try_push_x_call_entry_ptr, try_push_x_ret_entry_ptr;
  EntryPtr<state::Stack<N>> try_push_y_call_entry_ptr, try_push_y_ret_entry_ptr;
  EntryPtr<state::Stack<N>> try_pop_x_call_entry_ptr, try_pop_x_ret_entry_ptr;

  try_push_x_call_entry_ptr = log.add_call(state::Stack<N>::make_try_push_call(x));
  try_push_y_call_entry_ptr = log.add_call(state::Stack<N>::make_try_push_call(y));
  try_pop_x_call_entry_ptr = log.add_call(state::Stack<N>::make_try_pop_call());
  try_push_x_ret_entry_ptr = log.add_ret(try_push_x_call_entry_ptr, state::Stack<N>::make_try_push_ret(true));
  try_push_y_ret_entry_ptr = log.add_ret(try_push_y_call_entry_ptr, state::Stack<N>::make_try_push_ret(true));
  try_pop_x_ret_entry_ptr = log.add_ret(try_pop_x_call_entry_ptr, state::Stack<N>::make_try_pop_ret(true, x));

  assert(!try_push_x_call_entry_ptr->is_partitionable());
  assert(!try_push_y_call_entry_ptr->is_partitionable());
  assert(!try_pop_x_call_entry_ptr->is_partitionable());

  assert(!try_push_x_ret_entry_ptr->is_partitionable());
  assert(!try_push_y_ret_entry_ptr->is_partitionable());
  assert(!try_pop_x_ret_entry_ptr->is_partitionable());

  LinearizabilityTester<state::Stack<N>> t{ log.info() };
  assert(t.check());
1684 1685 1686 1687 1688
}

// push(x):true; push(y):true; pop():x
static void test_stack_history_001()
{
lucapegolotti committed
1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714
  constexpr char x = '\1';
  constexpr char y = '\2';
  constexpr std::size_t N = 5;

  Log<state::Stack<N>> log{ 6U };
  EntryPtr<state::Stack<N>> try_push_x_call_entry_ptr, try_push_x_ret_entry_ptr;
  EntryPtr<state::Stack<N>> try_push_y_call_entry_ptr, try_push_y_ret_entry_ptr;
  EntryPtr<state::Stack<N>> try_pop_x_call_entry_ptr, try_pop_x_ret_entry_ptr;

  try_push_x_call_entry_ptr = log.add_call(state::Stack<N>::make_try_push_call(x));
  try_push_x_ret_entry_ptr = log.add_ret(try_push_x_call_entry_ptr, state::Stack<N>::make_try_push_ret(true));
  try_push_y_call_entry_ptr = log.add_call(state::Stack<N>::make_try_push_call(y));
  try_push_y_ret_entry_ptr = log.add_ret(try_push_y_call_entry_ptr, state::Stack<N>::make_try_push_ret(true));
  try_pop_x_call_entry_ptr = log.add_call(state::Stack<N>::make_try_pop_call());
  try_pop_x_ret_entry_ptr = log.add_ret(try_pop_x_call_entry_ptr, state::Stack<N>::make_try_pop_ret(true, x));

  assert(!try_push_x_call_entry_ptr->is_partitionable());
  assert(!try_push_y_call_entry_ptr->is_partitionable());
  assert(!try_pop_x_call_entry_ptr->is_partitionable());

  assert(!try_push_x_ret_entry_ptr->is_partitionable());
  assert(!try_push_y_ret_entry_ptr->is_partitionable());
  assert(!try_pop_x_ret_entry_ptr->is_partitionable());

  LinearizabilityTester<state::Stack<N>> t{ log.info() };
  assert(!t.check());
1715 1716 1717 1718 1719 1720 1721 1722 1723 1724
}

// entry id: 0, thread id: 0x2, call: try_push(x)
// entry id: 0, thread id: 0x2, return: ret: 1
// entry id: 1, thread id: 0x3, call: try_push(y)
// entry id: 2, thread id: 0x4, call: try_pop()
// entry id: 2, thread id: 0x4, return: ret: [ok: 1, value: x]
// entry id: 1, thread id: 0x3, return: ret: 1
static void test_stack_history_002()
{
lucapegolotti committed
1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750
  constexpr char x = '\1';
  constexpr char y = '\2';
  constexpr std::size_t N = 5;

  Log<state::Stack<N>> log{ 8U };
  EntryPtr<state::Stack<N>> try_push_x_call_entry_ptr, try_push_x_ret_entry_ptr;
  EntryPtr<state::Stack<N>> try_push_y_call_entry_ptr, try_push_y_ret_entry_ptr;
  EntryPtr<state::Stack<N>> try_pop_x_call_entry_ptr, try_pop_x_ret_entry_ptr;

  try_push_x_call_entry_ptr = log.add_call(state::Stack<N>::make_try_push_call(x));
  try_push_x_ret_entry_ptr = log.add_ret(try_push_x_call_entry_ptr, state::Stack<N>::make_try_push_ret(true));
  try_push_y_call_entry_ptr = log.add_call(state::Stack<N>::make_try_push_call(y));
  try_pop_x_call_entry_ptr = log.add_call(state::Stack<N>::make_try_pop_call());
  try_pop_x_ret_entry_ptr = log.add_ret(try_pop_x_call_entry_ptr, state::Stack<N>::make_try_pop_ret(true, x));
  try_push_y_ret_entry_ptr = log.add_ret(try_push_y_call_entry_ptr, state::Stack<N>::make_try_push_ret(true));

  assert(!try_push_x_call_entry_ptr->is_partitionable());
  assert(!try_push_y_call_entry_ptr->is_partitionable());
  assert(!try_pop_x_call_entry_ptr->is_partitionable());

  assert(!try_push_x_ret_entry_ptr->is_partitionable());
  assert(!try_push_y_ret_entry_ptr->is_partitionable());
  assert(!try_pop_x_ret_entry_ptr->is_partitionable());

  LinearizabilityTester<state::Stack<N>> t{ log.info() };
  assert(t.check());
1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764
}

// Linearizable:
//
//   push(x) : true       pop() : (true, y)
// |----------------|   |------------------|
//
//     push(y) : true                           push(z) : true
//   |----------------|                |---------------------------------|
//
//                                                  pop() : (true, x)     pop() : (true, z)
//                                               |-------------------| |-------------------|
static void test_stack_history_003()
{
lucapegolotti committed
1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792
  constexpr char x = '\1';
  constexpr char y = '\2';
  constexpr char z = '\3';
  constexpr std::size_t N = 5;

  Log<state::Stack<N>> log{ 12U };
  EntryPtr<state::Stack<N>> try_push_x_call_entry_ptr, try_push_x_ret_entry_ptr;
  EntryPtr<state::Stack<N>> try_push_y_call_entry_ptr, try_push_y_ret_entry_ptr;
  EntryPtr<state::Stack<N>> try_push_z_call_entry_ptr, try_push_z_ret_entry_ptr;
  EntryPtr<state::Stack<N>> try_pop_x_call_entry_ptr, try_pop_x_ret_entry_ptr;
  EntryPtr<state::Stack<N>> try_pop_y_call_entry_ptr, try_pop_y_ret_entry_ptr;
  EntryPtr<state::Stack<N>> try_pop_z_call_entry_ptr, try_pop_z_ret_entry_ptr;

  try_push_x_call_entry_ptr = log.add_call(state::Stack<N>::make_try_push_call(x));
  try_push_y_call_entry_ptr = log.add_call(state::Stack<N>::make_try_push_call(y));
  try_push_x_ret_entry_ptr = log.add_ret(try_push_x_call_entry_ptr, state::Stack<N>::make_try_push_ret(true));
  try_push_y_ret_entry_ptr = log.add_ret(try_push_y_call_entry_ptr, state::Stack<N>::make_try_push_ret(true));
  try_pop_y_call_entry_ptr = log.add_call(state::Stack<N>::make_try_pop_call());
  try_push_z_call_entry_ptr = log.add_call(state::Stack<N>::make_try_push_call(z));
  try_pop_y_ret_entry_ptr = log.add_ret(try_pop_y_call_entry_ptr, state::Stack<N>::make_try_pop_ret(true, y));
  try_pop_x_call_entry_ptr = log.add_call(state::Stack<N>::make_try_pop_call());
  try_pop_x_ret_entry_ptr = log.add_ret(try_pop_x_call_entry_ptr, state::Stack<N>::make_try_pop_ret(true, x));
  try_pop_z_call_entry_ptr = log.add_call(state::Stack<N>::make_try_pop_call());
  try_push_z_ret_entry_ptr = log.add_ret(try_push_z_call_entry_ptr, state::Stack<N>::make_try_push_ret(true));
  try_pop_z_ret_entry_ptr = log.add_ret(try_pop_z_call_entry_ptr, state::Stack<N>::make_try_pop_ret(true, z));

  LinearizabilityTester<state::Stack<N>> t{ log.info() };
  assert(t.check());
1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807
}


// Let x = '\0' && y = '\1'.
//
//   erase(x) : false     insert(y) : true
// |------------------| |------------------|
//
//                                               contains(x) : true
//                                 |------------------------------------------------|
//
//                                      contains(y) : false     insert(x) : true
//                                    |---------------------| |------------------|
static void test_slice_000()
{
lucapegolotti committed
1808 1809
  constexpr char x = '\0';
  constexpr char y = '\1';
1810

lucapegolotti committed
1811
  Log<state::Set> log{ 10U };
1812

lucapegolotti committed
1813 1814 1815 1816 1817
  EntryPtr<state::Set> erase_x_call_entry_ptr, erase_x_ret_entry_ptr;
  EntryPtr<state::Set> insert_x_call_entry_ptr, insert_x_ret_entry_ptr;
  EntryPtr<state::Set> contains_x_call_entry_ptr, contains_x_ret_entry_ptr;
  EntryPtr<state::Set> insert_y_call_entry_ptr, insert_y_ret_entry_ptr;
  EntryPtr<state::Set> contains_y_call_entry_ptr, contains_y_ret_entry_ptr;
1818

lucapegolotti committed
1819 1820 1821 1822 1823 1824 1825 1826 1827 1828
  erase_x_call_entry_ptr = log.add_call(state::Set::make_erase_call(x));
  erase_x_ret_entry_ptr = log.add_ret(erase_x_call_entry_ptr, state::Set::make_ret(false));
  insert_y_call_entry_ptr = log.add_call(state::Set::make_insert_call(y));
  contains_x_call_entry_ptr = log.add_call(state::Set::make_contains_call(x));
  contains_y_call_entry_ptr = log.add_call(state::Set::make_contains_call(y));
  insert_y_ret_entry_ptr = log.add_ret(insert_y_call_entry_ptr, state::Set::make_ret(true));
  contains_y_ret_entry_ptr = log.add_ret(contains_y_call_entry_ptr, state::Set::make_ret(false));
  insert_x_call_entry_ptr = log.add_call(state::Set::make_insert_call(x));
  insert_x_ret_entry_ptr = log.add_ret(insert_x_call_entry_ptr, state::Set::make_ret(true));
  contains_x_ret_entry_ptr = log.add_ret(contains_x_call_entry_ptr, state::Set::make_ret(true));
1829

lucapegolotti committed
1830
  Slicer<state::Set> slicer{ log.info(), 2U };
1831

lucapegolotti committed
1832 1833
  assert(slicer.sublog_info(x).log_head_ptr() == erase_x_call_entry_ptr);
  assert(slicer.sublog_info(y).log_head_ptr() == insert_y_call_entry_ptr);
1834

lucapegolotti committed
1835 1836
  assert(slicer.sublog_info(x).number_of_entries() == 6U);
  assert(slicer.sublog_info(y).number_of_entries() == 4U);
1837

lucapegolotti committed
1838 1839
  LinearizabilityTester<state::Set> tester_0{ slicer.sublog_info(x) };
  assert(tester_0.check());
1840

lucapegolotti committed
1841 1842
  LinearizabilityTester<state::Set> tester_1{ slicer.sublog_info(y) };
  assert(tester_1.check());
1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856
}

// Let x = '\0' && y = '\1'.
//
//   contains(x) : false 
// |---------------------|
//
//      contains(y) : false
//    |---------------------|
//
//          insert(x) : false
//        |---------------------|
static void test_slice_001()
{
lucapegolotti committed
1857 1858
  constexpr char x = '\0';
  constexpr char y = '\1';
1859

lucapegolotti committed
1860 1861 1862 1863
  Log<state::Set> log{ 6U };
  EntryPtr<state::Set> contains_x_call_entry_ptr, contains_x_ret_entry_ptr;
  EntryPtr<state::Set> contains_y_call_entry_ptr, contains_y_ret_entry_ptr;
  EntryPtr<state::Set> insert_x_call_entry_ptr, insert_x_ret_entry_ptr;
1864

lucapegolotti committed
1865 1866 1867
  contains_x_call_entry_ptr = log.add_call(state::Set::make_contains_call(x));
  contains_y_call_entry_ptr = log.add_call(state::Set::make_contains_call(y));
  insert_x_call_entry_ptr = log.add_call(state::Set::make_insert_call(x));
1868

lucapegolotti committed
1869 1870 1871
  contains_x_ret_entry_ptr = log.add_ret(contains_x_call_entry_ptr, state::Set::make_ret(false));
  contains_y_ret_entry_ptr = log.add_ret(contains_y_call_entry_ptr, state::Set::make_ret(false));
  insert_x_ret_entry_ptr = log.add_ret(insert_x_call_entry_ptr, state::Set::make_ret(false));
1872

lucapegolotti committed
1873
  Slicer<state::Set> slicer{ log.info(), 2U };
1874

lucapegolotti committed
1875 1876
  assert(slicer.sublog_info(x).log_head_ptr() == contains_x_call_entry_ptr);
  assert(slicer.sublog_info(y).log_head_ptr() == contains_y_call_entry_ptr);
1877

lucapegolotti committed
1878 1879
  assert(slicer.sublog_info(x).number_of_entries() == 4U);
  assert(slicer.sublog_info(y).number_of_entries() == 2U);
1880

lucapegolotti committed
1881 1882
  LinearizabilityTester<state::Set> tester_0{ slicer.sublog_info(x) };
  assert(!tester_0.check());
1883

lucapegolotti committed
1884 1885
  LinearizabilityTester<state::Set> tester_1{ slicer.sublog_info(y) };
  assert(tester_1.check());
1886 1887 1888 1889
}

static void debug()
{
lucapegolotti committed
1890
  constexpr char x = '\1';
1891

lucapegolotti committed
1892
  Log<state::Set> log{ 2U };
1893

lucapegolotti committed
1894 1895 1896
  EntryPtr<state::Set> contains_call_entry_ptr, contains_ret_entry_ptr;
  contains_call_entry_ptr = log.add_call(state::Set::make_contains_call(x));
  contains_ret_entry_ptr = log.add_ret(contains_call_entry_ptr, state::Set::make_ret(true));
1897

lucapegolotti committed
1898 1899
  LinearizabilityTester<state::Set> t{ log.info() };
  Result<state::Set> result;
1900

lucapegolotti committed
1901 1902
  t.check(result);
  assert(!result.is_linearizable());
1903

lucapegolotti committed
1904 1905
  std::stringstream os;
  result.debug(os);
1906

lucapegolotti committed
1907 1908 1909 1910 1911
  assert(os.str() == "Linearizable: No\n"
    "entry id: 0, thread id: 0, call: contains(1)\n"
    "^ previous entries cannot be linearized\n"
    "entry id: 0, thread id: 0, return: ret: 1\n"
    "^ previous entries cannot be linearized\n");
1912 1913 1914 1915 1916
}


static void concurrent_log()
{
lucapegolotti committed
1917
  constexpr unsigned number_of_partitions = 1U;
1918

lucapegolotti committed
1919
  constexpr char x = '\0';
1920

lucapegolotti committed
1921
  ConcurrentLog<state::Set> log{ 6U };
1922

lucapegolotti committed
1923 1924
  EntryPtr<state::Set> contains_x_call_entry_ptr, contains_x_ret_entry_ptr;
  EntryPtr<state::Set> insert_x_call_entry_ptr, insert_x_ret_entry_ptr;
1925

lucapegolotti committed
1926 1927 1928 1929
  contains_x_call_entry_ptr = log.push_back(state::Set::make_contains_call(x));
  insert_x_call_entry_ptr = log.push_back(state::Set::make_insert_call(x));
  contains_x_ret_entry_ptr = log.push_back(contains_x_call_entry_ptr, state::Set::make_ret(false));
  insert_x_ret_entry_ptr = log.push_back(insert_x_call_entry_ptr, state::Set::make_ret(false));
1930

lucapegolotti committed
1931
  EntryPtr<state::Set> entry_ptr, log_head_ptr{ log.log_head_ptr() };
1932

lucapegolotti committed
1933 1934 1935 1936
  assert(log_head_ptr == contains_x_call_entry_ptr);
  assert(log_head_ptr->prev == nullptr);
  assert(log_head_ptr->next == insert_x_call_entry_ptr);
  assert(log_head_ptr->match() == contains_x_ret_entry_ptr);
1937

lucapegolotti committed
1938 1939 1940 1941 1942
  entry_ptr = log_head_ptr->next;
  assert(entry_ptr == insert_x_call_entry_ptr);
  assert(entry_ptr->prev == contains_x_call_entry_ptr);
  assert(entry_ptr->next == contains_x_ret_entry_ptr);
  assert(entry_ptr->match() == insert_x_ret_entry_ptr);
1943

lucapegolotti committed
1944 1945 1946 1947 1948
  entry_ptr = entry_ptr->next;
  assert(entry_ptr == contains_x_ret_entry_ptr);
  assert(entry_ptr->prev == insert_x_call_entry_ptr);
  assert(entry_ptr->next == insert_x_ret_entry_ptr);
  assert(entry_ptr->match() == contains_x_call_entry_ptr);
1949

lucapegolotti committed
1950 1951 1952 1953 1954
  entry_ptr = entry_ptr->next;
  assert(entry_ptr == insert_x_ret_entry_ptr);
  assert(entry_ptr->prev == contains_x_ret_entry_ptr);
  assert(entry_ptr->next == nullptr);
  assert(entry_ptr->match() == insert_x_call_entry_ptr);
1955

lucapegolotti committed
1956 1957
  LinearizabilityTester<state::Set> t{ log.info() };
  assert(!t.check());
1958 1959 1960 1961
}

struct WorkerConfiguration
{
lucapegolotti committed
1962 1963
  const char max_value;
  const unsigned number_of_ops;
1964 1965 1966
};

static void returns_always_false_worker(
lucapegolotti committed
1967 1968
  const WorkerConfiguration& worker_configuration,
  ConcurrentLog<state::Set>& concurrent_log)
1969
{
lucapegolotti committed
1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000
  std::random_device rd;
  std::mt19937 gen(rd());
  std::uniform_int_distribution<> value_dist('\0', worker_configuration.max_value);
  std::uniform_int_distribution<> percentage_dist(0, 100);

  // each operation returns false
  constexpr bool ret = false;

  char value;
  EntryPtr<state::Set> call_entry_ptr;
  for (unsigned number_of_ops{ 0U };
  number_of_ops < worker_configuration.number_of_ops;
    ++number_of_ops)
  {
    value = value_dist(rd);
    if (percentage_dist(rd) < 30)
    {
      call_entry_ptr = concurrent_log.push_back(state::Set::make_insert_call(value));
      concurrent_log.push_back(call_entry_ptr, state::Set::make_ret(ret));
    }
    else if (percentage_dist(rd) < 50)
    {
      call_entry_ptr = concurrent_log.push_back(state::Set::make_erase_call(value));
      concurrent_log.push_back(call_entry_ptr, state::Set::make_ret(ret));
    }
    else
    {
      call_entry_ptr = concurrent_log.push_back(state::Set::make_contains_call(value));
      concurrent_log.push_back(call_entry_ptr, state::Set::make_ret(ret));
    }
  }
2001 2002 2003 2004 2005
}

template<class F, class ...Args>
void start_threads(unsigned number_of_threads, F&& f, Args&&... args)
{
lucapegolotti committed
2006
  std::vector<Thread> threads(number_of_threads);
2007

lucapegolotti committed
2008 2009
  for (Thread& thread : threads)
    thread = Thread(std::forward<F>(f), std::forward<Args>(args)...);
2010

lucapegolotti committed
2011 2012
  for (Thread& thread : threads)
    thread.join();
2013 2014 2015 2016 2017
}

/// The first "insert" operation should be always marked as non-linearizable.
static void fuzzy_functional_test()
{
lucapegolotti committed
2018 2019 2020
  constexpr unsigned number_of_threads = 4U;
  constexpr WorkerConfiguration worker_configuration = { '\7', 12U };
  constexpr unsigned log_size = number_of_threads * worker_configuration.number_of_ops;
2021

lucapegolotti committed
2022
  ConcurrentLog<state::Set> concurrent_log{ 2U * log_size };
2023

lucapegolotti committed
2024 2025 2026
  // create history
  start_threads(number_of_threads, returns_always_false_worker,
    std::cref(worker_configuration), std::ref(concurrent_log));
2027

lucapegolotti committed
2028
  LinearizabilityTester<state::Set> tester{ concurrent_log.info() };
2029

lucapegolotti committed
2030
  assert(!tester.check());
2031 2032 2033
}

void run_tests(){
lucapegolotti committed
2034
  test_lru_cache();
2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107
  test_atomic_op();
  test_stack();
  test_state_set();
  test_bitset();
  test_state_set_op();
  test_state_stack();
  test_state_stack_op();
  test_state_queue();
  test_state_queue_op();
  
  test_linearizability_empty_log();
  test_raw_single_contains_is_linearizable();
  test_raw_single_contains_is_not_linearizable();
  test_log_copy();
  test_single_contains(true);
  test_single_contains(false);

  // Consider a sequential insert(x) && contains(x) operation
  // && their return values on an initially empty set:

  for (bool a : {true, false})
  for (bool b : {true, false})
  {
  test_000(a, b);
  test_001(a, b);
  test_002(a, b);
  test_003(a, b);
  test_004(a, b);
  test_005(a, b);
  test_006(a, b);
  test_007(a, b);
  test_008(a, b);
  }

  // semantically deeper tests

  test_009();
  test_010();
  test_011();
  test_012();
  test_013();
  test_014();
  test_015();
  test_016();
  test_017();
  test_018();

  for (bool a : {true, false})
  for (bool b : {true, false})
  for (bool c : {true, false})
  {
  test_019(a, b, c);
  test_020(a, b, c);
  }

  test_021();

  test_stack_history_000();
  test_stack_history_001();
  test_stack_history_002();
  test_stack_history_003();

  test_slice_000();
  test_slice_001();

  #ifdef _LT_DEBUG_
    debug();
  #endif

  concurrent_log();
  fuzzy_functional_test();

}