1// Originally taken from
2// https://raw.githubusercontent.com/cryfs/cryfs/14ad22570ddacef22d5ff139cdff68a54fc8234d/test/cpp-utils/either_test.cpp
3
4#include <c10/macros/Macros.h>
5#include <c10/util/either.h>
6#include <gmock/gmock.h>
7#include <gtest/gtest.h>
8#include <sstream>
9#include <vector>
10
11using c10::either;
12using c10::make_left;
13using c10::make_right;
14using std::ostringstream;
15using std::pair;
16using std::string;
17using std::tuple;
18using std::vector;
19
20namespace {
21class MovableOnly final {
22 public:
23 explicit MovableOnly(int value) : _value(value) {}
24 MovableOnly(const MovableOnly&) = delete;
25 MovableOnly& operator=(const MovableOnly&) = delete;
26
27 MovableOnly(MovableOnly&& rhs) : _value(rhs._value) {
28 rhs._value = 0;
29 }
30
31 MovableOnly& operator=(MovableOnly&& rhs) {
32 _value = rhs._value;
33 rhs._value = 0;
34 return *this;
35 }
36
37 int value() const {
38 return _value;
39 }
40
41 private:
42 int _value;
43};
44
45bool operator==(const MovableOnly& lhs, const MovableOnly& rhs) {
46 return lhs.value() == rhs.value();
47}
48
49template <class T>
50void test_with_matrix(
51 std::vector<std::function<void(std::function<void(T&)>)>> setups,
52 std::vector<std::function<void(T&)>> expectations) {
53 for (const auto& setup : setups) {
54 for (const auto& expectation : expectations) {
55 setup(expectation);
56 }
57 }
58}
59
60template <class Left, class Right>
61std::vector<std::function<void(either<Left, Right>&)>> EXPECT_IS_LEFT(
62 const Left& expected) {
63 return {
64 [&](either<Left, Right>& obj) { EXPECT_TRUE(obj.is_left()); },
65 [&](either<Left, Right>& obj) { EXPECT_FALSE(obj.is_right()); },
66 [&](either<Left, Right>& obj) { EXPECT_EQ(expected, obj.left()); },
67 [&](either<Left, Right>& obj) {
68 EXPECT_EQ(expected, std::move(obj).left());
69 },
70 [&](either<Left, Right>& obj) {
71 // NOLINTNEXTLINE(hicpp-avoid-goto,cppcoreguidelines-avoid-goto)
72 EXPECT_ANY_THROW(obj.right());
73 },
74 [&](either<Left, Right>& obj) {
75 // NOLINTNEXTLINE(hicpp-avoid-goto,cppcoreguidelines-avoid-goto)
76 EXPECT_ANY_THROW(std::move(obj).right());
77 }};
78}
79
80template <class Left, class Right>
81std::vector<std::function<void(either<Left, Right>&)>> EXPECT_IS_RIGHT(
82 const Right& expected) {
83 return {
84 [&](either<Left, Right>& obj) { EXPECT_FALSE(obj.is_left()); },
85 [&](either<Left, Right>& obj) { EXPECT_TRUE(obj.is_right()); },
86 [&](either<Left, Right>& obj) { EXPECT_EQ(expected, obj.right()); },
87 [&](either<Left, Right>& obj) {
88 EXPECT_EQ(expected, std::move(obj).right());
89 },
90 [&](either<Left, Right>& obj) {
91 // NOLINTNEXTLINE(hicpp-avoid-goto,cppcoreguidelines-avoid-goto)
92 EXPECT_ANY_THROW(obj.left());
93 },
94 [&](either<Left, Right>& obj) {
95 // NOLINTNEXTLINE(hicpp-avoid-goto,cppcoreguidelines-avoid-goto)
96 EXPECT_ANY_THROW(std::move(obj).left());
97 }};
98}
99
100template <class Value>
101std::vector<std::function<void(Value&)>> EXPECT_IS(const Value& v) {
102 return {[&](Value& obj) { return obj == v; }};
103}
104
105template <typename T>
106struct StoreWith1ByteFlag {
107 T val;
108 char flag;
109};
110
111template <typename Left, typename Right>
112void TestSpaceUsage() {
113 EXPECT_EQ(
114 std::max(
115 sizeof(StoreWith1ByteFlag<Left>), sizeof(StoreWith1ByteFlag<Right>)),
116 sizeof(either<Left, Right>));
117}
118} // namespace
119
120TEST(EitherTest, SpaceUsage) {
121 TestSpaceUsage<char, int>();
122 TestSpaceUsage<int, short>();
123 TestSpaceUsage<char, short>();
124 TestSpaceUsage<int, string>();
125 TestSpaceUsage<string, vector<string>>();
126}
127
128TEST(EitherTest, givenLeft) {
129 test_with_matrix(
130 {
131 [](std::function<void(either<int, string>&)> test) {
132 either<int, string> a(4);
133 test(a);
134 },
135 [](std::function<void(either<int, string>&)> test) {
136 either<int, string> a = 4;
137 test(a);
138 },
139 },
140 EXPECT_IS_LEFT<int, string>(4));
141}
142
143TEST(EitherTest, givenRight) {
144 test_with_matrix(
145 {[](std::function<void(either<int, string>&)> test) {
146 either<int, string> a("4");
147 test(a);
148 },
149 [](std::function<void(either<int, string>&)> test) {
150 either<int, string> a = string("4");
151 test(a);
152 }},
153 EXPECT_IS_RIGHT<int, string>("4"));
154}
155
156TEST(EitherTest, givenMakeLeft) {
157 test_with_matrix(
158 {
159 [](std::function<void(either<int, string>&)> test) {
160 either<int, string> a = make_left<int, string>(4);
161 test(a);
162 },
163 [](std::function<void(either<int, string>&)> test) {
164 auto a = make_left<int, string>(4);
165 test(a);
166 },
167 },
168 EXPECT_IS_LEFT<int, string>(4));
169}
170
171TEST(EitherTest, givenMakeLeftWithSameType) {
172 test_with_matrix(
173 {
174 [](std::function<void(either<int, int>&)> test) {
175 either<int, int> a = make_left<int, int>(4);
176 test(a);
177 },
178 [](std::function<void(either<int, int>&)> test) {
179 auto a = make_left<int, int>(4);
180 test(a);
181 },
182 },
183 EXPECT_IS_LEFT<int, int>(4));
184}
185
186TEST(EitherTest, givenMakeRight) {
187 test_with_matrix(
188 {[](std::function<void(either<int, string>&)> test) {
189 either<int, string> a = make_right<int, string>("4");
190 test(a);
191 },
192 [](std::function<void(either<int, string>&)> test) {
193 auto a = make_right<int, string>("4");
194 test(a);
195 }},
196 EXPECT_IS_RIGHT<int, string>("4"));
197}
198
199TEST(EitherTest, givenMakeRightWithSameType) {
200 test_with_matrix(
201 {[](std::function<void(either<string, string>&)> test) {
202 either<string, string> a = make_right<string, string>("4");
203 test(a);
204 },
205 [](std::function<void(either<string, string>&)> test) {
206 auto a = make_right<string, string>("4");
207 test(a);
208 }},
209 EXPECT_IS_RIGHT<string, string>("4"));
210}
211
212TEST(EitherTest, givenMovableOnlyMakeLeft) {
213 test_with_matrix(
214 {
215 [](std::function<void(either<MovableOnly, string>&)> test) {
216 either<MovableOnly, string> a = make_left<MovableOnly, string>(3);
217 test(a);
218 },
219 [](std::function<void(either<MovableOnly, string>&)> test) {
220 auto a = make_left<MovableOnly, string>(3);
221 test(a);
222 },
223 },
224 EXPECT_IS_LEFT<MovableOnly, string>(MovableOnly(3)));
225}
226
227TEST(EitherTest, givenMovableOnlyMakeRight) {
228 test_with_matrix(
229 {[](std::function<void(either<int, MovableOnly>&)> test) {
230 either<int, MovableOnly> a = make_right<int, MovableOnly>(3);
231 test(a);
232 },
233 [](std::function<void(either<int, MovableOnly>&)> test) {
234 auto a = make_right<int, MovableOnly>(3);
235 test(a);
236 }},
237 EXPECT_IS_RIGHT<int, MovableOnly>(MovableOnly(3)));
238}
239
240TEST(EitherTest, givenMultiParamMakeLeft) {
241 test_with_matrix(
242 {
243 [](std::function<void(either<pair<int, int>, string>&)> test) {
244 either<pair<int, int>, string> a =
245 make_left<pair<int, int>, string>(5, 6);
246 test(a);
247 },
248 [](std::function<void(either<pair<int, int>, string>&)> test) {
249 auto a = make_left<pair<int, int>, string>(5, 6);
250 test(a);
251 },
252 },
253 EXPECT_IS_LEFT<pair<int, int>, string>(pair<int, int>(5, 6)));
254}
255
256TEST(EitherTest, givenMultiParamMakeRight) {
257 test_with_matrix(
258 {[](std::function<void(either<int, pair<int, int>>&)> test) {
259 either<int, pair<int, int>> a = make_right<int, pair<int, int>>(5, 6);
260 test(a);
261 },
262 [](std::function<void(either<int, pair<int, int>>&)> test) {
263 auto a = make_right<int, pair<int, int>>(5, 6);
264 test(a);
265 }},
266 EXPECT_IS_RIGHT<int, pair<int, int>>(pair<int, int>(5, 6)));
267}
268
269TEST(EitherTest, givenLeftCopyConstructedFromValue_thenNewIsCorrect) {
270 test_with_matrix(
271 {[](std::function<void(either<string, int>&)> test) {
272 string a = "4";
273 either<string, int> b(a);
274 test(b);
275 }},
276 EXPECT_IS_LEFT<string, int>("4"));
277}
278
279TEST(EitherTest, givenLeftCopyConstructedFromValue_thenOldIsCorrect) {
280 test_with_matrix(
281 {[](std::function<void(string&)> test) {
282 string a = "4";
283 either<string, int> b(a);
284 test(a);
285 }},
286 EXPECT_IS<string>("4"));
287}
288
289TEST(EitherTest, givenRightCopyConstructedFromValue_thenNewIsCorrect) {
290 test_with_matrix(
291 {[](std::function<void(either<int, string>&)> test) {
292 string a = "4";
293 either<int, string> b(a);
294 test(b);
295 }},
296 EXPECT_IS_RIGHT<int, string>("4"));
297}
298
299TEST(EitherTest, givenRightCopyConstructedFromValue_thenOldIsCorrect) {
300 test_with_matrix(
301 {[](std::function<void(string&)> test) {
302 string a = "4";
303 either<int, string> b(a);
304 test(a);
305 }},
306 EXPECT_IS<string>("4"));
307}
308
309TEST(EitherTest, givenLeftMoveConstructedFromValue_thenNewIsCorrect) {
310 test_with_matrix(
311 {[](std::function<void(either<MovableOnly, int>&)> test) {
312 MovableOnly a(3);
313 either<MovableOnly, int> b(std::move(a));
314 test(b);
315 }},
316 EXPECT_IS_LEFT<MovableOnly, int>(MovableOnly(3)));
317}
318
319TEST(EitherTest, givenLeftMoveConstructedFromValue_thenOldIsCorrect) {
320 test_with_matrix(
321 {[](std::function<void(MovableOnly&)> test) {
322 MovableOnly a(3);
323 either<MovableOnly, int> b(std::move(a));
324 test(a); // NOLINT(bugprone-use-after-move)
325 }},
326 EXPECT_IS<MovableOnly>(MovableOnly(0)) // 0 is moved-from value
327 );
328}
329
330TEST(EitherTest, givenRightMoveConstructedFromValue_thenNewIsCorrect) {
331 test_with_matrix(
332 {[](std::function<void(either<int, MovableOnly>&)> test) {
333 MovableOnly a(3);
334 either<int, MovableOnly> b(std::move(a));
335 test(b);
336 }},
337 EXPECT_IS_RIGHT<int, MovableOnly>(MovableOnly(3)));
338}
339
340TEST(EitherTest, givenRightMoveConstructedFromValue_thenOldIsCorrect) {
341 test_with_matrix(
342 {[](std::function<void(MovableOnly&)> test) {
343 MovableOnly a(3);
344 either<int, MovableOnly> b(std::move(a));
345 test(a); // NOLINT(bugprone-use-after-move)
346 }},
347 EXPECT_IS<MovableOnly>(MovableOnly(0)) // 0 is moved-from value
348 );
349}
350
351TEST(EitherTest, givenLeftCopyAssignedFromValue_thenNewIsCorrect) {
352 test_with_matrix(
353 {[](std::function<void(either<string, int>&)> test) {
354 string a = "4";
355 either<string, int> b(2);
356 b = a;
357 test(b);
358 },
359 [](std::function<void(either<string, int>&)> test) {
360 string a = "4";
361 either<string, int> b("2");
362 b = a;
363 test(b);
364 }},
365 EXPECT_IS_LEFT<string, int>("4"));
366}
367
368TEST(EitherTest, givenLeftCopyAssignedFromValue_thenOldIsCorrect) {
369 test_with_matrix(
370 {[](std::function<void(string&)> test) {
371 string a = "4";
372 either<string, int> b(2);
373 b = a;
374 test(a);
375 },
376 [](std::function<void(string&)> test) {
377 string a = "4";
378 either<string, int> b("2");
379 b = a;
380 test(a);
381 }},
382 EXPECT_IS<string>("4"));
383}
384
385TEST(EitherTest, givenRightCopyAssignedFromValue_thenNewIsCorrect) {
386 test_with_matrix(
387 {[](std::function<void(either<int, string>&)> test) {
388 string a = "4";
389 either<int, string> b(2);
390 b = a;
391 test(b);
392 },
393 [](std::function<void(either<int, string>&)> test) {
394 string a = "4";
395 either<int, string> b("2");
396 b = a;
397 test(b);
398 }},
399 EXPECT_IS_RIGHT<int, string>("4"));
400}
401
402TEST(EitherTest, givenRightCopyAssignedFromValue_thenOldIsCorrect) {
403 test_with_matrix(
404 {[](std::function<void(string&)> test) {
405 string a = "4";
406 either<int, string> b(2);
407 b = a;
408 test(a);
409 },
410 [](std::function<void(string&)> test) {
411 string a = "4";
412 either<int, string> b("2");
413 b = a;
414 test(a);
415 }},
416 EXPECT_IS<string>("4"));
417}
418
419TEST(EitherTest, givenLeftMoveAssignedFromValue_thenNewIsCorrect) {
420 test_with_matrix(
421 {[](std::function<void(either<MovableOnly, string>&)> test) {
422 MovableOnly a(3);
423 either<MovableOnly, string> b(2);
424 b = std::move(a);
425 test(b);
426 },
427 [](std::function<void(either<MovableOnly, string>&)> test) {
428 MovableOnly a(3);
429 either<MovableOnly, string> b(MovableOnly(2));
430 b = std::move(a);
431 test(b);
432 }},
433 EXPECT_IS_LEFT<MovableOnly, string>(MovableOnly(3)));
434}
435
436TEST(EitherTest, givenLeftMoveAssignedFromValue_thenOldIsCorrect) {
437 test_with_matrix(
438 {[](std::function<void(MovableOnly&)> test) {
439 MovableOnly a(3);
440 either<MovableOnly, string> b("2");
441 b = std::move(a);
442 test(a); // NOLINT(bugprone-use-after-move)
443 },
444 [](std::function<void(MovableOnly&)> test) {
445 MovableOnly a(3);
446 either<MovableOnly, string> b(MovableOnly(0));
447 b = std::move(a);
448 test(a); // NOLINT(bugprone-use-after-move)
449 }},
450 EXPECT_IS<MovableOnly>(MovableOnly(0)));
451}
452
453TEST(EitherTest, givenRightMoveAssignedFromValue_thenNewIsCorrect) {
454 test_with_matrix(
455 {[](std::function<void(either<string, MovableOnly>&)> test) {
456 MovableOnly a(3);
457 either<string, MovableOnly> b("2");
458 b = std::move(a);
459 test(b);
460 },
461 [](std::function<void(either<string, MovableOnly>&)> test) {
462 MovableOnly a(3);
463 either<string, MovableOnly> b(MovableOnly(2));
464 b = std::move(a);
465 test(b);
466 }},
467 EXPECT_IS_RIGHT<string, MovableOnly>(MovableOnly(3)));
468}
469
470TEST(EitherTest, givenRightMoveAssignedFromValue_thenOldIsCorrect) {
471 test_with_matrix(
472 {[](std::function<void(MovableOnly&)> test) {
473 MovableOnly a(3);
474 either<string, MovableOnly> b("2");
475 b = std::move(a);
476 test(a); // NOLINT(bugprone-use-after-move)
477 },
478 [](std::function<void(MovableOnly&)> test) {
479 MovableOnly a(3);
480 either<string, MovableOnly> b(MovableOnly(2));
481 b = std::move(a);
482 test(a); // NOLINT(bugprone-use-after-move)
483 }},
484 EXPECT_IS<MovableOnly>(MovableOnly(0)) // 0 is moved-from value
485 );
486}
487
488TEST(EitherTest, givenLeftCopyConstructed_thenNewIsCorrect) {
489 test_with_matrix(
490 {[](std::function<void(either<string, int>&)> test) {
491 either<string, int> a("4");
492 // NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
493 either<string, int> b(a);
494 test(b);
495 }},
496 EXPECT_IS_LEFT<string, int>("4"));
497}
498
499TEST(EitherTest, givenLeftCopyConstructed_thenOldIsCorrect) {
500 test_with_matrix(
501 {[](std::function<void(either<string, int>&)> test) {
502 either<string, int> a("4");
503 // NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
504 either<string, int> b(a);
505 test(a);
506 }},
507 EXPECT_IS_LEFT<string, int>("4"));
508}
509
510TEST(EitherTest, givenLeftCopyConstructed_withSameType_thenNewIsCorrect) {
511 test_with_matrix(
512 {[](std::function<void(either<string, string>&)> test) {
513 either<string, string> a = make_left<string, string>("4");
514 // NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
515 either<string, string> b(a);
516 test(b);
517 }},
518 EXPECT_IS_LEFT<string, string>("4"));
519}
520
521TEST(EitherTest, givenLeftCopyConstructed_withSameType_thenOldIsCorrect) {
522 test_with_matrix(
523 {[](std::function<void(either<string, string>&)> test) {
524 either<string, string> a = make_left<string, string>("4");
525 // NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
526 either<string, string> b(a);
527 test(a);
528 }},
529 EXPECT_IS_LEFT<string, string>("4"));
530}
531
532TEST(EitherTest, givenRightCopyConstructed_thenNewIsCorrect) {
533 test_with_matrix(
534 {[](std::function<void(either<int, string>&)> test) {
535 either<int, string> a("4");
536 // NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
537 either<int, string> b(a);
538 test(b);
539 }},
540 EXPECT_IS_RIGHT<int, string>("4"));
541}
542
543TEST(EitherTest, givenRightCopyConstructed_thenOldIsCorrect) {
544 test_with_matrix(
545 {[](std::function<void(either<int, string>&)> test) {
546 either<int, string> a("4");
547 // NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
548 either<int, string> b(a);
549 test(a);
550 }},
551 EXPECT_IS_RIGHT<int, string>("4"));
552}
553
554TEST(EitherTest, givenRightCopyConstructed_withSameType_thenNewIsCorrect) {
555 test_with_matrix(
556 {[](std::function<void(either<string, string>&)> test) {
557 either<string, string> a = make_right<string, string>("4");
558 // NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
559 either<string, string> b(a);
560 test(b);
561 }},
562 EXPECT_IS_RIGHT<string, string>("4"));
563}
564
565TEST(EitherTest, givenRightCopyConstructed_withSameType_thenOldIsCorrect) {
566 test_with_matrix(
567 {[](std::function<void(either<string, string>&)> test) {
568 either<string, string> a = make_right<string, string>("4");
569 // NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
570 either<string, string> b(a);
571 test(a);
572 }},
573 EXPECT_IS_RIGHT<string, string>("4"));
574}
575
576TEST(EitherTest, givenLeftMoveConstructed_thenNewIsCorrect) {
577 test_with_matrix(
578 {[](std::function<void(either<MovableOnly, int>&)> test) {
579 either<MovableOnly, int> a(MovableOnly(3));
580 either<MovableOnly, int> b(std::move(a));
581 test(b);
582 }},
583 EXPECT_IS_LEFT<MovableOnly, int>(MovableOnly(3)));
584}
585
586TEST(EitherTest, givenLeftMoveConstructed_thenOldIsCorrect) {
587 test_with_matrix(
588 {[](std::function<void(either<MovableOnly, int>&)> test) {
589 either<MovableOnly, int> a(MovableOnly(3));
590 either<MovableOnly, int> b(std::move(a));
591 test(a); // NOLINT(bugprone-use-after-move)
592 }},
593 EXPECT_IS_LEFT<MovableOnly, int>(MovableOnly(0)) // 0 is moved-from value
594 );
595}
596
597TEST(EitherTest, givenLeftMoveConstructed_withSameType_thenNewIsCorrect) {
598 test_with_matrix(
599 {[](std::function<void(either<MovableOnly, MovableOnly>&)> test) {
600 either<MovableOnly, MovableOnly> a =
601 make_left<MovableOnly, MovableOnly>(MovableOnly(3));
602 either<MovableOnly, MovableOnly> b(std::move(a));
603 test(b);
604 }},
605 EXPECT_IS_LEFT<MovableOnly, MovableOnly>(MovableOnly(3)));
606}
607
608TEST(EitherTest, givenLeftMoveConstructed_withSameType_thenOldIsCorrect) {
609 test_with_matrix(
610 {[](std::function<void(either<MovableOnly, MovableOnly>&)> test) {
611 either<MovableOnly, MovableOnly> a =
612 make_left<MovableOnly, MovableOnly>(MovableOnly(3));
613 either<MovableOnly, MovableOnly> b(std::move(a));
614 test(a); // NOLINT(bugprone-use-after-move)
615 }},
616 EXPECT_IS_LEFT<MovableOnly, MovableOnly>(
617 MovableOnly(0)) // 0 is moved-from value
618 );
619}
620
621TEST(EitherTest, givenRightMoveConstructed_thenNewIsCorrect) {
622 test_with_matrix(
623 {[](std::function<void(either<int, MovableOnly>&)> test) {
624 either<int, MovableOnly> a(MovableOnly(3));
625 either<int, MovableOnly> b(std::move(a));
626 test(b);
627 }},
628 EXPECT_IS_RIGHT<int, MovableOnly>(MovableOnly(3)));
629}
630
631TEST(EitherTest, givenRightMoveConstructed_thenOldIsCorrect) {
632 test_with_matrix(
633 {[](std::function<void(either<int, MovableOnly>&)> test) {
634 either<int, MovableOnly> a(MovableOnly(3));
635 either<int, MovableOnly> b(std::move(a));
636 test(a); // NOLINT(bugprone-use-after-move)
637 }},
638 EXPECT_IS_RIGHT<int, MovableOnly>(MovableOnly(0)) // 0 is moved-from value
639 );
640}
641
642TEST(EitherTest, givenRightMoveConstructed_withSameType_thenNewIsCorrect) {
643 test_with_matrix(
644 {[](std::function<void(either<MovableOnly, MovableOnly>&)> test) {
645 either<MovableOnly, MovableOnly> a =
646 make_right<MovableOnly, MovableOnly>(MovableOnly(3));
647 either<MovableOnly, MovableOnly> b(std::move(a));
648 test(b);
649 }},
650 EXPECT_IS_RIGHT<MovableOnly, MovableOnly>(MovableOnly(3)));
651}
652
653TEST(EitherTest, givenRightMoveConstructed_withSameType_thenOldIsCorrect) {
654 test_with_matrix(
655 {[](std::function<void(either<MovableOnly, MovableOnly>&)> test) {
656 either<MovableOnly, MovableOnly> a =
657 make_right<MovableOnly, MovableOnly>(MovableOnly(3));
658 either<MovableOnly, MovableOnly> b(std::move(a));
659 test(a); // NOLINT(bugprone-use-after-move)
660 }},
661 EXPECT_IS_RIGHT<MovableOnly, MovableOnly>(
662 MovableOnly(0)) // 0 is moved-from value
663 );
664}
665
666TEST(EitherTest, givenLeftCopyAssigned_thenNewIsCorrect) {
667 test_with_matrix(
668 {[](std::function<void(either<string, int>&)> test) {
669 either<string, int> a("4");
670 either<string, int> b(2);
671 b = a;
672 test(b);
673 },
674 [](std::function<void(either<string, int>&)> test) {
675 either<string, int> a("4");
676 either<string, int> b("2");
677 b = a;
678 test(b);
679 }},
680 EXPECT_IS_LEFT<string, int>("4"));
681}
682
683TEST(EitherTest, givenLeftCopyAssigned_thenOldIsCorrect) {
684 test_with_matrix(
685 {[](std::function<void(either<string, int>&)> test) {
686 either<string, int> a("4");
687 either<string, int> b(2);
688 b = a;
689 test(a);
690 },
691 [](std::function<void(either<string, int>&)> test) {
692 either<string, int> a("4");
693 either<string, int> b("2");
694 b = a;
695 test(a);
696 }},
697 EXPECT_IS_LEFT<string, int>("4"));
698}
699
700TEST(EitherTest, givenLeftCopyAssigned_withSameType_thenNewIsCorrect) {
701 test_with_matrix(
702 {[](std::function<void(either<string, string>&)> test) {
703 either<string, string> a = make_left<string, string>("4");
704 either<string, string> b = make_right<string, string>("2");
705 b = a;
706 test(b);
707 },
708 [](std::function<void(either<string, string>&)> test) {
709 either<string, string> a = make_left<string, string>("4");
710 either<string, string> b = make_left<string, string>("2");
711 b = a;
712 test(b);
713 }},
714 EXPECT_IS_LEFT<string, string>("4"));
715}
716
717TEST(EitherTest, givenLeftCopyAssigned_withSameType_thenOldIsCorrect) {
718 test_with_matrix(
719 {[](std::function<void(either<string, string>&)> test) {
720 either<string, string> a = make_left<string, string>("4");
721 either<string, string> b = make_right<string, string>("2");
722 b = a;
723 test(a);
724 },
725 [](std::function<void(either<string, string>&)> test) {
726 either<string, string> a = make_left<string, string>("4");
727 either<string, string> b = make_left<string, string>("2");
728 b = a;
729 test(a);
730 }},
731 EXPECT_IS_LEFT<string, string>("4"));
732}
733
734TEST(EitherTest, givenRightCopyAssigned_thenNewIsCorrect) {
735 test_with_matrix(
736 {[](std::function<void(either<int, string>&)> test) {
737 either<int, string> a("4");
738 either<int, string> b(2);
739 b = a;
740 test(b);
741 },
742 [](std::function<void(either<int, string>&)> test) {
743 either<int, string> a("4");
744 either<int, string> b("2");
745 b = a;
746 test(b);
747 }},
748 EXPECT_IS_RIGHT<int, string>("4"));
749}
750
751TEST(EitherTest, givenRightCopyAssigned_thenOldIsCorrect) {
752 test_with_matrix(
753 {[](std::function<void(either<int, string>&)> test) {
754 either<int, string> a("4");
755 either<int, string> b(2);
756 b = a;
757 test(a);
758 },
759 [](std::function<void(either<int, string>&)> test) {
760 either<int, string> a("4");
761 either<int, string> b("2");
762 b = a;
763 test(a);
764 }},
765 EXPECT_IS_RIGHT<int, string>("4"));
766}
767
768TEST(EitherTest, givenRightCopyAssigned_withSameType_thenNewIsCorrect) {
769 test_with_matrix(
770 {[](std::function<void(either<string, string>&)> test) {
771 either<string, string> a = make_right<string, string>("4");
772 either<string, string> b = make_left<string, string>("2");
773 b = a;
774 test(b);
775 },
776 [](std::function<void(either<string, string>&)> test) {
777 either<string, string> a = make_right<string, string>("4");
778 either<string, string> b = make_right<string, string>("2");
779 b = a;
780 test(b);
781 }},
782 EXPECT_IS_RIGHT<string, string>("4"));
783}
784
785TEST(EitherTest, givenRightCopyAssigned_withSameType_thenOldIsCorrect) {
786 test_with_matrix(
787 {[](std::function<void(either<string, string>&)> test) {
788 either<string, string> a = make_right<string, string>("4");
789 either<string, string> b = make_left<string, string>("2");
790 b = a;
791 test(a);
792 },
793 [](std::function<void(either<string, string>&)> test) {
794 either<string, string> a = make_right<string, string>("4");
795 either<string, string> b = make_right<string, string>("2");
796 b = a;
797 test(a);
798 }},
799 EXPECT_IS_RIGHT<string, string>("4"));
800}
801
802TEST(EitherTest, givenLeftMoveAssigned_thenNewIsCorrect) {
803 test_with_matrix(
804 {[](std::function<void(either<MovableOnly, string>&)> test) {
805 either<MovableOnly, string> a(MovableOnly(3));
806 either<MovableOnly, string> b(2);
807 b = std::move(a);
808 test(b);
809 },
810 [](std::function<void(either<MovableOnly, string>&)> test) {
811 either<MovableOnly, string> a(MovableOnly(3));
812 either<MovableOnly, string> b(MovableOnly(2));
813 b = std::move(a);
814 test(b);
815 }},
816 EXPECT_IS_LEFT<MovableOnly, string>(MovableOnly(3)));
817}
818
819TEST(EitherTest, givenLeftMoveAssigned_thenOldIsCorrect) {
820 test_with_matrix(
821 {[](std::function<void(either<MovableOnly, string>&)> test) {
822 either<MovableOnly, string> a(MovableOnly(3));
823 either<MovableOnly, string> b(2);
824 b = std::move(a);
825 test(a); // NOLINT(bugprone-use-after-move)
826 },
827 [](std::function<void(either<MovableOnly, string>&)> test) {
828 either<MovableOnly, string> a(MovableOnly(3));
829 either<MovableOnly, string> b(MovableOnly(2));
830 b = std::move(a);
831 test(a); // NOLINT(bugprone-use-after-move)
832 }},
833 EXPECT_IS_LEFT<MovableOnly, string>(
834 MovableOnly(0)) // 0 is moved-from value
835 );
836}
837
838TEST(EitherTest, givenLeftMoveAssigned_withSameType_thenNewIsCorrect) {
839 test_with_matrix(
840 {[](std::function<void(either<MovableOnly, MovableOnly>&)> test) {
841 either<MovableOnly, MovableOnly> a =
842 make_left<MovableOnly, MovableOnly>(3);
843 either<MovableOnly, MovableOnly> b =
844 make_right<MovableOnly, MovableOnly>(2);
845 b = std::move(a);
846 test(b);
847 },
848 [](std::function<void(either<MovableOnly, MovableOnly>&)> test) {
849 either<MovableOnly, MovableOnly> a =
850 make_left<MovableOnly, MovableOnly>(3);
851 either<MovableOnly, MovableOnly> b =
852 make_left<MovableOnly, MovableOnly>(2);
853 b = std::move(a);
854 test(b);
855 }},
856 EXPECT_IS_LEFT<MovableOnly, MovableOnly>(MovableOnly(3)));
857}
858
859TEST(EitherTest, givenLeftMoveAssigned_withSameType_thenOldIsCorrect) {
860 test_with_matrix(
861 {[](std::function<void(either<MovableOnly, MovableOnly>&)> test) {
862 either<MovableOnly, MovableOnly> a =
863 make_left<MovableOnly, MovableOnly>(3);
864 either<MovableOnly, MovableOnly> b =
865 make_right<MovableOnly, MovableOnly>(2);
866 b = std::move(a);
867 test(a); // NOLINT(bugprone-use-after-move)
868 },
869 [](std::function<void(either<MovableOnly, MovableOnly>&)> test) {
870 either<MovableOnly, MovableOnly> a =
871 make_left<MovableOnly, MovableOnly>(3);
872 either<MovableOnly, MovableOnly> b =
873 make_left<MovableOnly, MovableOnly>(2);
874 b = std::move(a);
875 test(a); // NOLINT(bugprone-use-after-move)
876 }},
877 EXPECT_IS_LEFT<MovableOnly, MovableOnly>(
878 MovableOnly(0)) // 0 is moved-from value
879 );
880}
881
882TEST(EitherTest, givenRightMoveAssigned_thenNewIsCorrect) {
883 test_with_matrix(
884 {[](std::function<void(either<string, MovableOnly>&)> test) {
885 either<string, MovableOnly> a(MovableOnly(3));
886 either<string, MovableOnly> b("2");
887 b = std::move(a);
888 test(b);
889 },
890 [](std::function<void(either<string, MovableOnly>&)> test) {
891 either<string, MovableOnly> a(MovableOnly(3));
892 either<string, MovableOnly> b(MovableOnly(2));
893 b = std::move(a);
894 test(b);
895 }},
896 EXPECT_IS_RIGHT<string, MovableOnly>(MovableOnly(3)));
897}
898
899TEST(EitherTest, givenRightMoveAssigned_thenOldIsCorrect) {
900 test_with_matrix(
901 {[](std::function<void(either<string, MovableOnly>&)> test) {
902 either<string, MovableOnly> a(MovableOnly(3));
903 either<string, MovableOnly> b("2");
904 b = std::move(a);
905 test(a); // NOLINT(bugprone-use-after-move)
906 },
907 [](std::function<void(either<string, MovableOnly>&)> test) {
908 either<string, MovableOnly> a(MovableOnly(3));
909 either<string, MovableOnly> b(MovableOnly(2));
910 b = std::move(a);
911 test(a); // NOLINT(bugprone-use-after-move)
912 }},
913 EXPECT_IS_RIGHT<string, MovableOnly>(
914 MovableOnly(0)) // 0 is moved-from value
915 );
916}
917
918TEST(EitherTest, givenRightMoveAssigned_withSameType_thenNewIsCorrect) {
919 test_with_matrix(
920 {[](std::function<void(either<MovableOnly, MovableOnly>&)> test) {
921 either<MovableOnly, MovableOnly> a =
922 make_right<MovableOnly, MovableOnly>(3);
923 either<MovableOnly, MovableOnly> b =
924 make_left<MovableOnly, MovableOnly>(2);
925 b = std::move(a);
926 test(b);
927 },
928 [](std::function<void(either<MovableOnly, MovableOnly>&)> test) {
929 either<MovableOnly, MovableOnly> a =
930 make_right<MovableOnly, MovableOnly>(3);
931 either<MovableOnly, MovableOnly> b =
932 make_right<MovableOnly, MovableOnly>(2);
933 b = std::move(a);
934 test(b);
935 }},
936 EXPECT_IS_RIGHT<MovableOnly, MovableOnly>(MovableOnly(3)));
937}
938
939TEST(EitherTest, givenRightMoveAssigned_withSameType_thenOldIsCorrect) {
940 test_with_matrix(
941 {[](std::function<void(either<MovableOnly, MovableOnly>&)> test) {
942 either<MovableOnly, MovableOnly> a =
943 make_right<MovableOnly, MovableOnly>(3);
944 either<MovableOnly, MovableOnly> b =
945 make_left<MovableOnly, MovableOnly>(2);
946 b = std::move(a);
947 test(a); // NOLINT(bugprone-use-after-move)
948 },
949 [](std::function<void(either<MovableOnly, MovableOnly>&)> test) {
950 either<MovableOnly, MovableOnly> a =
951 make_right<MovableOnly, MovableOnly>(3);
952 either<MovableOnly, MovableOnly> b =
953 make_right<MovableOnly, MovableOnly>(2);
954 b = std::move(a);
955 test(a); // NOLINT(bugprone-use-after-move)
956 }},
957 EXPECT_IS_RIGHT<MovableOnly, MovableOnly>(
958 MovableOnly(0)) // 0 is moved-from value
959 );
960}
961
962TEST(EitherTest, givenLeft_whenModified_thenValueIsChanged) {
963 test_with_matrix(
964 {[](std::function<void(either<int, string>&)> test) {
965 either<int, string> a(4);
966 a.left() = 5;
967 test(a);
968 },
969 [](std::function<void(either<int, string>&)> test) {
970 either<int, string> a(4);
971 a.left() = 5;
972 test(a);
973 }},
974 EXPECT_IS_LEFT<int, string>(5));
975}
976
977TEST(EitherTest, givenRight_whenModified_thenValueIsChanged) {
978 test_with_matrix(
979 {[](std::function<void(either<int, string>&)> test) {
980 either<int, string> a("4");
981 a.right() = "5";
982 test(a);
983 },
984 [](std::function<void(either<int, string>&)> test) {
985 either<int, string> a("4");
986 a.right() = "5";
987 test(a);
988 }},
989 EXPECT_IS_RIGHT<int, string>("5"));
990}
991
992TEST(EitherTest, canEmplaceConstructLeft) {
993 test_with_matrix(
994 {[](std::function<void(either<tuple<int, int>, tuple<int, string, int>>&)>
995 test) {
996 either<tuple<int, int>, tuple<int, string, int>> a(2, 3);
997 test(a);
998 }},
999 EXPECT_IS_LEFT<tuple<int, int>, tuple<int, string, int>>(
1000 tuple<int, int>(2, 3)));
1001}
1002
1003TEST(EitherTest, canEmplaceConstructRight) {
1004 test_with_matrix(
1005 {[](std::function<void(either<tuple<int, int>, tuple<int, string, int>>&)>
1006 test) {
1007 either<tuple<int, int>, tuple<int, string, int>> a(2, "3", 4);
1008 test(a);
1009 }},
1010 EXPECT_IS_RIGHT<tuple<int, int>, tuple<int, string, int>>(
1011 tuple<int, string, int>(2, "3", 4)));
1012}
1013
1014TEST(EitherTest, givenEqualLefts_thenAreEqual) {
1015 either<string, int> a("3");
1016 either<string, int> b("3");
1017 EXPECT_TRUE(a == b);
1018}
1019
1020TEST(EitherTest, givenEqualLefts_thenAreNotUnequal) {
1021 either<string, int> a("3");
1022 either<string, int> b("3");
1023 EXPECT_FALSE(a != b);
1024}
1025
1026TEST(EitherTest, givenEqualRights_thenAreEqual) {
1027 either<string, int> a(3);
1028 either<string, int> b(3);
1029 EXPECT_TRUE(a == b);
1030}
1031
1032TEST(EitherTest, givenEqualRights_thenAreNotUnequal) {
1033 either<string, int> a(3);
1034 either<string, int> b(3);
1035 EXPECT_FALSE(a != b);
1036}
1037
1038TEST(EitherTest, givenLeftAndRight_thenAreNotEqual) {
1039 either<string, int> a("3");
1040 either<string, int> b(3);
1041 EXPECT_FALSE(a == b);
1042 EXPECT_FALSE(b == a);
1043}
1044
1045TEST(EitherTest, givenLeftAndRight_thenAreUnequal) {
1046 either<string, int> a("3");
1047 either<string, int> b(3);
1048 EXPECT_TRUE(a != b);
1049 EXPECT_TRUE(b != a);
1050}
1051
1052TEST(EitherTest, OutputLeft) {
1053 ostringstream str;
1054 str << either<string, int>("mystring");
1055 EXPECT_EQ("Left(mystring)", str.str());
1056}
1057
1058TEST(EitherTest, OutputRight) {
1059 ostringstream str;
1060 str << either<int, string>("mystring");
1061 EXPECT_EQ("Right(mystring)", str.str());
1062}
1063
1064TEST(EitherTest, givenLeftAndRightWithSameType_thenAreNotEqual) {
1065 either<string, string> a = make_left<string, string>("3");
1066 either<string, string> b = make_right<string, string>("3");
1067 EXPECT_FALSE(a == b);
1068 EXPECT_FALSE(b == a);
1069}
1070
1071TEST(EitherTest, givenLeftAndRightWithSameType_thenAreUnequal) {
1072 either<string, string> a = make_left<string, string>("3");
1073 either<string, string> b = make_right<string, string>("3");
1074 EXPECT_TRUE(a != b);
1075 EXPECT_TRUE(b != a);
1076}
1077
1078namespace {
1079class DestructorCallback {
1080 public:
1081 MOCK_CONST_METHOD0(call, void());
1082
1083 void EXPECT_CALLED(int times = 1) {
1084 EXPECT_CALL(*this, call()).Times(times);
1085 }
1086};
1087class ClassWithDestructorCallback {
1088 public:
1089 ClassWithDestructorCallback(const DestructorCallback* destructorCallback)
1090 : _destructorCallback(destructorCallback) {}
1091
1092 ~ClassWithDestructorCallback() {
1093 _destructorCallback->call();
1094 }
1095
1096 ClassWithDestructorCallback& operator=(
1097 const ClassWithDestructorCallback& rhs) = delete;
1098
1099 private:
1100 const DestructorCallback* _destructorCallback;
1101};
1102class OnlyMoveableClassWithDestructorCallback {
1103 public:
1104 OnlyMoveableClassWithDestructorCallback(
1105 const DestructorCallback* destructorCallback)
1106 : _destructorCallback(destructorCallback) {}
1107 OnlyMoveableClassWithDestructorCallback(
1108 OnlyMoveableClassWithDestructorCallback&& source)
1109 : _destructorCallback(source._destructorCallback) {}
1110
1111 ~OnlyMoveableClassWithDestructorCallback() {
1112 _destructorCallback->call();
1113 }
1114
1115 private:
1116 C10_DISABLE_COPY_AND_ASSIGN(OnlyMoveableClassWithDestructorCallback);
1117 const DestructorCallback* _destructorCallback;
1118};
1119
1120} // namespace
1121
1122TEST(EitherTest_Destructor, LeftDestructorIsCalled) {
1123 DestructorCallback destructorCallback;
1124 destructorCallback.EXPECT_CALLED(
1125 2); // Once for the temp object, once when the either class destructs
1126
1127 ClassWithDestructorCallback temp(&destructorCallback);
1128 either<ClassWithDestructorCallback, string> var = temp;
1129}
1130
1131TEST(EitherTest_Destructor, RightDestructorIsCalled) {
1132 DestructorCallback destructorCallback;
1133 destructorCallback.EXPECT_CALLED(
1134 2); // Once for the temp object, once when the either class destructs
1135
1136 ClassWithDestructorCallback temp(&destructorCallback);
1137 either<string, ClassWithDestructorCallback> var = temp;
1138}
1139
1140TEST(EitherTest_Destructor, LeftDestructorIsCalledAfterCopying) {
1141 DestructorCallback destructorCallback;
1142 destructorCallback.EXPECT_CALLED(
1143 3); // Once for the temp object, once for var1 and once for var2
1144
1145 ClassWithDestructorCallback temp(&destructorCallback);
1146 either<ClassWithDestructorCallback, string> var1 = temp;
1147 // NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
1148 either<ClassWithDestructorCallback, string> var2 = var1;
1149}
1150
1151TEST(EitherTest_Destructor, RightDestructorIsCalledAfterCopying) {
1152 DestructorCallback destructorCallback;
1153 destructorCallback.EXPECT_CALLED(
1154 3); // Once for the temp object, once for var1 and once for var2
1155
1156 ClassWithDestructorCallback temp(&destructorCallback);
1157 either<string, ClassWithDestructorCallback> var1 = temp;
1158 // NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
1159 either<string, ClassWithDestructorCallback> var2 = var1;
1160}
1161
1162TEST(EitherTest_Destructor, LeftDestructorIsCalledAfterMoving) {
1163 DestructorCallback destructorCallback;
1164 destructorCallback.EXPECT_CALLED(
1165 3); // Once for the temp object, once for var1 and once for var2
1166
1167 OnlyMoveableClassWithDestructorCallback temp(&destructorCallback);
1168 either<OnlyMoveableClassWithDestructorCallback, string> var1 =
1169 std::move(temp);
1170 either<OnlyMoveableClassWithDestructorCallback, string> var2 =
1171 std::move(var1);
1172}
1173
1174TEST(EitherTest_Destructor, RightDestructorIsCalledAfterMoving) {
1175 DestructorCallback destructorCallback;
1176 destructorCallback.EXPECT_CALLED(
1177 3); // Once for the temp object, once for var1 and once for var2
1178
1179 OnlyMoveableClassWithDestructorCallback temp(&destructorCallback);
1180 either<string, OnlyMoveableClassWithDestructorCallback> var1 =
1181 std::move(temp);
1182 either<string, OnlyMoveableClassWithDestructorCallback> var2 =
1183 std::move(var1);
1184}
1185
1186TEST(EitherTest_Destructor, LeftDestructorIsCalledAfterAssignment) {
1187 DestructorCallback destructorCallback1;
1188 DestructorCallback destructorCallback2;
1189 destructorCallback1.EXPECT_CALLED(
1190 2); // Once for the temp1 object, once at the assignment
1191 destructorCallback2.EXPECT_CALLED(
1192 3); // Once for the temp2 object, once in destructor of var2, once in
1193 // destructor of var1
1194
1195 ClassWithDestructorCallback temp1(&destructorCallback1);
1196 either<ClassWithDestructorCallback, string> var1 = temp1;
1197 ClassWithDestructorCallback temp2(&destructorCallback2);
1198 either<ClassWithDestructorCallback, string> var2 = temp2;
1199 var1 = var2;
1200}
1201
1202TEST(EitherTest_Destructor, RightDestructorIsCalledAfterAssignment) {
1203 DestructorCallback destructorCallback1;
1204 DestructorCallback destructorCallback2;
1205 destructorCallback1.EXPECT_CALLED(
1206 2); // Once for the temp1 object, once at the assignment
1207 destructorCallback2.EXPECT_CALLED(
1208 3); // Once for the temp2 object, once in destructor of var2, once in
1209 // destructor of var1
1210
1211 ClassWithDestructorCallback temp1(&destructorCallback1);
1212 either<string, ClassWithDestructorCallback> var1 = temp1;
1213 ClassWithDestructorCallback temp2(&destructorCallback2);
1214 either<string, ClassWithDestructorCallback> var2 = temp2;
1215 var1 = var2;
1216}
1217
1218TEST(EitherTest_Destructor, LeftDestructorIsCalledAfterMoveAssignment) {
1219 DestructorCallback destructorCallback1;
1220 DestructorCallback destructorCallback2;
1221 destructorCallback1.EXPECT_CALLED(
1222 2); // Once for the temp1 object, once at the assignment
1223 destructorCallback2.EXPECT_CALLED(
1224 3); // Once for the temp2 object, once in destructor of var2, once in
1225 // destructor of var1
1226
1227 OnlyMoveableClassWithDestructorCallback temp1(&destructorCallback1);
1228 either<OnlyMoveableClassWithDestructorCallback, string> var1 =
1229 std::move(temp1);
1230 OnlyMoveableClassWithDestructorCallback temp2(&destructorCallback2);
1231 either<OnlyMoveableClassWithDestructorCallback, string> var2 =
1232 std::move(temp2);
1233 var1 = std::move(var2);
1234}
1235
1236TEST(EitherTest_Destructor, RightDestructorIsCalledAfterMoveAssignment) {
1237 DestructorCallback destructorCallback1;
1238 DestructorCallback destructorCallback2;
1239 destructorCallback1.EXPECT_CALLED(
1240 2); // Once for the temp1 object, once at the assignment
1241 destructorCallback2.EXPECT_CALLED(
1242 3); // Once for the temp2 object, once in destructor of var2, once in
1243 // destructor of var1
1244
1245 OnlyMoveableClassWithDestructorCallback temp1(&destructorCallback1);
1246 either<string, OnlyMoveableClassWithDestructorCallback> var1 =
1247 std::move(temp1);
1248 OnlyMoveableClassWithDestructorCallback temp2(&destructorCallback2);
1249 either<string, OnlyMoveableClassWithDestructorCallback> var2 =
1250 std::move(temp2);
1251 var1 = std::move(var2);
1252}
1253