1
2 /**
3 * Copyright (C) 2018-present MongoDB, Inc.
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the Server Side Public License, version 1,
7 * as published by MongoDB, Inc.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * Server Side Public License for more details.
13 *
14 * You should have received a copy of the Server Side Public License
15 * along with this program. If not, see
16 * <http://www.mongodb.com/licensing/server-side-public-license>.
17 *
18 * As a special exception, the copyright holders give permission to link the
19 * code of portions of this program with the OpenSSL library under certain
20 * conditions as described in each individual source file and distribute
21 * linked combinations including the program with the OpenSSL library. You
22 * must comply with the Server Side Public License in all respects for
23 * all of the code used other than as permitted herein. If you modify file(s)
24 * with this exception, you may extend this exception to your version of the
25 * file(s), but you are not obligated to do so. If you do not wish to do so,
26 * delete this exception statement from your version. If you delete this
27 * exception statement from all source files in the program, then also delete
28 * it in the license file.
29 */
30
31 #include "mongo/base/clonable_ptr.h"
32
33 #include <functional>
34 #include <memory>
35
36 #include "mongo/unittest/unittest.h"
37
38 #include <boost/lexical_cast.hpp>
39
40 namespace {
41
42 template <typename Test>
runSyntaxTest(Test && t)43 void runSyntaxTest(Test&& t) {
44 if (false)
45 t();
46 }
47
48 // These testing helper classes model various kinds of class which should be compatible with
49 // `mongo::clonable_ptr`. The basic use cases satisfied by each class are described in each class's
50 // documentation.
51
52 // This class models the `Clonable` concept, and is used to test the simple case of `clonable_ptr`.
53 class ClonableTest {
54 private:
55 std::string data =
56 "This is the string data which is stored to make Functor Clonable need a complicated copy "
57 "ctor.";
58
59 public:
clone() const60 std::unique_ptr<ClonableTest> clone() const {
61 return std::make_unique<ClonableTest>();
62 }
63 };
64
65 // This class provides a member structure which models `CloneFactory<AltClonableTest>`. The member
66 // structure is available under the expected member name of `clone_factory_type`. The
67 // `CloneFactory` is stateless.
68 class AltClonableTest {
69 private:
70 std::string data =
71 "This is the string data which is stored to make Functor Clonable need a complicated copy "
72 "ctor.";
73
74 public:
75 struct clone_factory_type {
operator ()__anon0e50d3670111::AltClonableTest::clone_factory_type76 std::unique_ptr<AltClonableTest> operator()(const AltClonableTest&) const {
77 return std::make_unique<AltClonableTest>();
78 }
79 };
80 };
81
82 // This class requires a companion cloning function models `CloneFactory<Alt2ClonableTest>`. There
83 // is an attendant specialization of the `mongo::clonable_traits` metafunction to provide the clone
84 // factory for this type. That `CloneFactory` is stateless.
85 class Alt2ClonableTest {
86 private:
87 std::string data =
88 "This is the string data which is stored to make Functor Clonable need a complicated copy "
89 "ctor.";
90 };
91 } // namespace
92
93 namespace mongo {
94 // This specialization of the `mongo::clonable_traits` metafunction provides a model of a stateless
95 // `CloneFactory<Alt2ClonableTest>`
96 template <>
97 struct clonable_traits<::Alt2ClonableTest> {
98 struct clone_factory_type {
operator ()mongo::clonable_traits::clone_factory_type99 std::unique_ptr<Alt2ClonableTest> operator()(const Alt2ClonableTest&) const {
100 return std::make_unique<Alt2ClonableTest>();
101 }
102 };
103 };
104 } // namespace mongo
105
106 namespace {
107 // This class uses a stateful cloning function provided by the `getCloningFunction` static member.
108 // This stateful `CloneFactory<FunctorClonable>` must be passed to constructors of the
109 // `cloning_ptr`.
110 class FunctorClonable {
111 private:
112 std::string data =
113 "This is the string data which is stored to make Functor Clonable need a complicated copy "
114 "ctor.";
115
116 public:
117 using CloningFunctionType =
118 std::function<std::unique_ptr<FunctorClonable>(const FunctorClonable&)>;
119
getCloningFunction()120 static CloningFunctionType getCloningFunction() {
121 return [](const FunctorClonable& c) { return std::make_unique<FunctorClonable>(c); };
122 }
123 };
124
125
126 // This class uses a stateful cloning function provided by the `getCloningFunction` static member.
127 // This stateful `CloneFactory<FunctorWithDynamicStateClonable>` must be passed to constructors of
128 // the `cloning_ptr`. The `CloneFactory` for this type dynamically updates its internal state.
129 // This is used to test cloning of objects that have dynamically changing clone factories.
130 class FunctorWithDynamicStateClonable {
131 private:
132 std::string data =
133 "This is the string data which is stored to make Functor Clonable need a complicated copy "
134 "ctor.";
135
136 public:
137 FunctorWithDynamicStateClonable(const FunctorWithDynamicStateClonable&) = delete;
138 FunctorWithDynamicStateClonable() = default;
139
FunctorWithDynamicStateClonable(const std::string & s)140 FunctorWithDynamicStateClonable(const std::string& s) : data(s) {}
141
142 using CloningFunctionType = std::function<std::unique_ptr<FunctorWithDynamicStateClonable>(
143 const FunctorWithDynamicStateClonable&)>;
144
getCloningFunction()145 static CloningFunctionType getCloningFunction() {
146 return [calls = 0](const FunctorWithDynamicStateClonable& c) mutable {
147 return std::make_unique<FunctorWithDynamicStateClonable>(
148 c.data + boost::lexical_cast<std::string>(++calls));
149 };
150 }
151 };
152
153 // This class models `Clonable`, with a return from clone which is
154 // `Constructible<std::unique_ptr<RawPointerClonable>>` but isn't
155 // `std::unique_ptr<RawPointerClonable>`. This is used to test that the `clonable_ptr` class does
156 // not expect `RawPointerClonable::clone() const` to return a model of
157 // `UniquePtr<RawPointerClonable>`
158 class RawPointerClonable {
159 public:
clone() const160 RawPointerClonable* clone() const {
161 return new RawPointerClonable;
162 }
163 };
164
165 // This class models `Clonable`, with a return from clone which is
166 // `Constructible<std::unique_ptr<UniquePtrClonable>>` because it is
167 // `std::unique_ptr<UniquePtrClonable>`. This is used to test that the `clonable_ptr` class can
168 // use a `UniquePtrClonable::clone() const` that returns a model of
169 // `UniquePtr<UniquePtrClonable>`
170 class UniquePtrClonable {
171 public:
clone() const172 std::unique_ptr<UniquePtrClonable> clone() const {
173 return std::make_unique<UniquePtrClonable>();
174 }
175 };
176
TEST(ClonablePtrTest,syntax_smoke_test)177 TEST(ClonablePtrTest, syntax_smoke_test) {
178 // TODO: Either add a compressed pair type for optimization, or wait for MSVC to get this feature by
179 // default. MSVC doesn't make its tuple compressed, which causes this test to fail on MSVC.
180 #ifndef _MSC_VER
181 {
182 mongo::clonable_ptr<ClonableTest> p;
183
184 p = std::make_unique<ClonableTest>();
185
186 mongo::clonable_ptr<ClonableTest> p2 = p;
187
188 ASSERT_TRUE(p != p2);
189
190 static_assert(sizeof(p) == sizeof(ClonableTest*),
191 "`mongo::clonable_ptr< T >` should be `sizeof` a pointer when there is no "
192 "CloneFactory");
193 }
194 #endif
195
196 {
197 mongo::clonable_ptr<AltClonableTest> p;
198
199 p = std::make_unique<AltClonableTest>();
200
201 mongo::clonable_ptr<AltClonableTest> p2 = p;
202
203 ASSERT_TRUE(p != p2);
204 }
205
206 {
207 mongo::clonable_ptr<Alt2ClonableTest> p;
208
209 p = std::make_unique<Alt2ClonableTest>();
210
211 mongo::clonable_ptr<Alt2ClonableTest> p2 = p;
212
213 ASSERT_TRUE(p != p2);
214 }
215
216 {
217 mongo::clonable_ptr<FunctorClonable, FunctorClonable::CloningFunctionType> p{
218 FunctorClonable::getCloningFunction()};
219
220 p = std::make_unique<FunctorClonable>();
221
222 mongo::clonable_ptr<FunctorClonable, FunctorClonable::CloningFunctionType> p2 = p;
223
224 ASSERT_TRUE(p != p2);
225
226 mongo::clonable_ptr<FunctorClonable, FunctorClonable::CloningFunctionType> p3{
227 FunctorClonable::getCloningFunction()};
228
229 auto tmp = std::make_unique<FunctorClonable>();
230 p3 = std::move(tmp);
231
232 ASSERT_TRUE(p != p2);
233 ASSERT_TRUE(p2 != p3);
234 ASSERT_TRUE(p != p3);
235 }
236 }
237
238 // These tests check that all expected valid syntactic forms of use for the
239 // `mongo::clonable_ptr<Clonable>` are valid. These tests assert nothing but provide a single
240 // unified place to check the syntax of this component. Build failures in these parts indicate that
241 // a change to the component has broken an expected valid syntactic usage. Any expected valid usage
242 // which is not in this list should be added.
243 namespace SyntaxTests {
244 template <typename Clonable>
construction()245 void construction() {
246 // Test default construction
247 { mongo::clonable_ptr<Clonable>{}; }
248
249 // Test construction from a nullptr
250 { mongo::clonable_ptr<Clonable>{nullptr}; }
251
252 // Test construction from a Clonable pointer.
253 {
254 Clonable* const local = nullptr;
255 mongo::clonable_ptr<Clonable>{local};
256 }
257
258 // Test move construction.
259 { mongo::clonable_ptr<Clonable>{mongo::clonable_ptr<Clonable>{}}; }
260
261 // Test copy construction.
262 {
263 mongo::clonable_ptr<Clonable> a;
264 mongo::clonable_ptr<Clonable> b{a};
265 }
266
267 // Test move assignment.
268 {
269 mongo::clonable_ptr<Clonable> a;
270 a = mongo::clonable_ptr<Clonable>{};
271 }
272
273 // Test copy assignment.
274 {
275 mongo::clonable_ptr<Clonable> a;
276 mongo::clonable_ptr<Clonable> b;
277 b = a;
278 }
279
280 // Test unique pointer construction
281 { mongo::clonable_ptr<Clonable>{std::make_unique<Clonable>()}; }
282
283 // Test unique pointer construction (conversion)
284 {
285 auto acceptor = [](const mongo::clonable_ptr<Clonable>&) {};
286 acceptor(std::make_unique<Clonable>());
287 }
288
289 // Test non-conversion pointer construction
290 { static_assert(!std::is_convertible<Clonable*, mongo::clonable_ptr<Clonable>>::value, ""); }
291
292 // Test conversion unique pointer construction
293 {
294 static_assert(
295 std::is_convertible<std::unique_ptr<Clonable>, mongo::clonable_ptr<Clonable>>::value,
296 "");
297 }
298 }
299
300 // Tests that syntactic forms that require augmented construction are proper
301 template <typename Clonable, typename CloneFactory>
augmentedConstruction()302 void augmentedConstruction() {
303 // Test default construction
304 {
305 static_assert(
306 !std::is_default_constructible<mongo::clonable_ptr<Clonable, CloneFactory>>::value, "");
307 }
308
309 // Test Clone Factory construction
310 { mongo::clonable_ptr<Clonable, CloneFactory>{Clonable::getCloningFunction()}; }
311
312 // TODO: Revist this when MSVC's enable-if and deletion on ctors works.
313 #ifndef _MSC_VER
314 // Test non-construction from a nullptr
315 {
316 static_assert(!std::is_constructible<mongo::clonable_ptr<Clonable, CloneFactory>,
317 std::nullptr_t>::value,
318 "");
319 }
320 #endif
321
322 // Test construction from a nullptr with factory
323 { mongo::clonable_ptr<Clonable, CloneFactory>{nullptr, Clonable::getCloningFunction()}; }
324
325 // TODO: Revist this when MSVC's enable-if and deletion on ctors works.
326 #ifndef _MSC_VER
327 // Test construction from a raw Clonable pointer.
328 {
329 static_assert(
330 !std::is_constructible<mongo::clonable_ptr<Clonable, CloneFactory>, Clonable*>::value,
331 "");
332 }
333 #endif
334
335
336 // Test initialization of a raw Clonable pointer with factory, using reset.
337 {
338 Clonable* const local = nullptr;
339 mongo::clonable_ptr<Clonable, CloneFactory> p{Clonable::getCloningFunction()};
340 p.reset(local);
341 }
342
343 // Test move construction.
344 {
345 mongo::clonable_ptr<Clonable, CloneFactory>{
346 mongo::clonable_ptr<Clonable, CloneFactory>{Clonable::getCloningFunction()}};
347 }
348
349 // Test copy construction.
350 {
351 mongo::clonable_ptr<Clonable, CloneFactory> a{Clonable::getCloningFunction()};
352 mongo::clonable_ptr<Clonable, CloneFactory> b{a};
353 }
354
355 // Test augmented copy construction.
356 {
357 mongo::clonable_ptr<Clonable, CloneFactory> a{Clonable::getCloningFunction()};
358 mongo::clonable_ptr<Clonable, CloneFactory> b{a, Clonable::getCloningFunction()};
359 }
360
361
362 // Test move assignment.
363 {
364 mongo::clonable_ptr<Clonable, CloneFactory> a{Clonable::getCloningFunction()};
365 a = mongo::clonable_ptr<Clonable, CloneFactory>{Clonable::getCloningFunction()};
366 }
367
368 // Test copy assignment.
369 {
370 mongo::clonable_ptr<Clonable, CloneFactory> a{Clonable::getCloningFunction()};
371 mongo::clonable_ptr<Clonable, CloneFactory> b{Clonable::getCloningFunction()};
372 b = a;
373 }
374
375 // Test unique pointer construction
376 {
377 mongo::clonable_ptr<Clonable, CloneFactory>{std::make_unique<Clonable>(),
378 Clonable::getCloningFunction()};
379 }
380
381 // Test augmented unique pointer construction
382 {
383 mongo::clonable_ptr<Clonable, CloneFactory>{std::make_unique<Clonable>(),
384 Clonable::getCloningFunction()};
385 }
386
387 // Test non-conversion pointer construction
388 {
389 static_assert(
390 !std::is_convertible<mongo::clonable_ptr<Clonable, CloneFactory>, Clonable*>::value,
391 "");
392 }
393
394 // Test non-conversion from factory
395 {
396 static_assert(
397 !std::is_convertible<mongo::clonable_ptr<Clonable, CloneFactory>, CloneFactory>::value,
398 "");
399 }
400
401 // Test conversion unique pointer construction
402 {
403 static_assert(!std::is_convertible<std::unique_ptr<Clonable>,
404 mongo::clonable_ptr<Clonable, CloneFactory>>::value,
405 "");
406 }
407 }
408
409 template <typename Clonable>
pointerOperations()410 void pointerOperations() {
411 mongo::clonable_ptr<Clonable> a;
412
413 // Test `.get()` functionality:
414 {
415 Clonable* p = a.get();
416 (void)p;
417 }
418
419 // Test `->` functionality
420 {
421 // We don't actually want to call the dtor, but we want the compiler to check that we
422 // have.
423 if (false) {
424 a->~Clonable();
425 }
426 }
427
428 // Test `*` functionality
429 Clonable& r = *a;
430 (void)r;
431
432 // Test reset functionality
433 {
434 a.reset();
435 a.reset(nullptr);
436 a.reset(new Clonable);
437 }
438 }
439
440 template <typename Clonable>
equalityOperations()441 void equalityOperations() {
442 mongo::clonable_ptr<Clonable> a;
443 mongo::clonable_ptr<Clonable> b;
444
445 std::unique_ptr<Clonable> ua;
446
447 // Test equality expressions
448 {
449 (void)(a == a);
450 (void)(a == b);
451 (void)(b == a);
452
453 (void)(a == ua);
454 (void)(ua == a);
455
456 (void)(nullptr == a);
457 (void)(a == nullptr);
458 }
459
460 // Test inequality expressions
461 {
462 (void)(a != a);
463 (void)(a != b);
464 (void)(b != a);
465
466 (void)(a != ua);
467 (void)(ua != a);
468
469 (void)(nullptr == a);
470 (void)(a == nullptr);
471 }
472 }
473 } // namespace SyntaxTests
474
TEST(ClonablePtrSyntaxTests,construction)475 TEST(ClonablePtrSyntaxTests, construction) {
476 runSyntaxTest(SyntaxTests::construction<ClonableTest>);
477 runSyntaxTest(SyntaxTests::construction<AltClonableTest>);
478 runSyntaxTest(SyntaxTests::construction<Alt2ClonableTest>);
479 runSyntaxTest(SyntaxTests::construction<RawPointerClonable>);
480 runSyntaxTest(SyntaxTests::construction<UniquePtrClonable>);
481 }
482
TEST(ClonablePtrSyntaxTests,augmentedConstruction)483 TEST(ClonablePtrSyntaxTests, augmentedConstruction) {
484 runSyntaxTest(
485 SyntaxTests::augmentedConstruction<FunctorClonable, FunctorClonable::CloningFunctionType>);
486 runSyntaxTest(
487 SyntaxTests::augmentedConstruction<FunctorWithDynamicStateClonable,
488 FunctorWithDynamicStateClonable::CloningFunctionType>);
489 }
490
TEST(ClonablePtrSyntaxTests,pointerOperations)491 TEST(ClonablePtrSyntaxTests, pointerOperations) {
492 runSyntaxTest(SyntaxTests::pointerOperations<ClonableTest>);
493 runSyntaxTest(SyntaxTests::pointerOperations<AltClonableTest>);
494 runSyntaxTest(SyntaxTests::pointerOperations<Alt2ClonableTest>);
495 runSyntaxTest(SyntaxTests::pointerOperations<RawPointerClonable>);
496 runSyntaxTest(SyntaxTests::pointerOperations<UniquePtrClonable>);
497 }
498
TEST(ClonablePtrSyntaxTests,equalityOperations)499 TEST(ClonablePtrSyntaxTests, equalityOperations) {
500 runSyntaxTest(SyntaxTests::equalityOperations<ClonableTest>);
501 runSyntaxTest(SyntaxTests::equalityOperations<AltClonableTest>);
502 runSyntaxTest(SyntaxTests::equalityOperations<Alt2ClonableTest>);
503 runSyntaxTest(SyntaxTests::equalityOperations<RawPointerClonable>);
504 runSyntaxTest(SyntaxTests::equalityOperations<UniquePtrClonable>);
505 }
506
507 namespace BehaviorTests {
508 class DetectDestruction {
509 public:
510 static int activeCount;
511
resetCount()512 static void resetCount() {
513 activeCount = 0;
514 }
515
~DetectDestruction()516 ~DetectDestruction() {
517 --activeCount;
518 }
519
DetectDestruction(const DetectDestruction &)520 DetectDestruction(const DetectDestruction&) {
521 ++activeCount;
522 }
523
524 DetectDestruction& operator=(const DetectDestruction&) = delete;
525
526 DetectDestruction(DetectDestruction&&) = delete;
527 DetectDestruction& operator=(DetectDestruction&&) = delete;
528
DetectDestruction()529 DetectDestruction() {
530 ++activeCount;
531 }
532
clone() const533 std::unique_ptr<DetectDestruction> clone() const {
534 return std::make_unique<DetectDestruction>(*this);
535 }
536 };
537
538 int DetectDestruction::activeCount = 0;
539
540 struct DestructionGuard {
541 DestructionGuard(const DestructionGuard&) = delete;
542 DestructionGuard& operator=(const DestructionGuard&) = delete;
543
DestructionGuard__anon0e50d3670211::BehaviorTests::DestructionGuard544 DestructionGuard() {
545 DetectDestruction::resetCount();
546 }
547
~DestructionGuard__anon0e50d3670211::BehaviorTests::DestructionGuard548 ~DestructionGuard() {
549 ASSERT_EQ(DetectDestruction::activeCount, 0);
550 }
551 };
552
TEST(ClonablePtrTest,basic_construction_test)553 TEST(ClonablePtrTest, basic_construction_test) {
554 // Do not default construct the object
555 {
556 DestructionGuard check;
557 mongo::clonable_ptr<DetectDestruction> p;
558 ASSERT_EQ(DetectDestruction::activeCount, 0);
559 }
560
561 // Do not make unnecessary copies of the object from ptr
562 {
563 DestructionGuard check;
564 mongo::clonable_ptr<DetectDestruction> p{new DetectDestruction};
565 ASSERT_EQ(DetectDestruction::activeCount, 1);
566 }
567
568 // Do not make unnecessary copies of the object from unique_ptr
569 {
570 DestructionGuard check;
571 mongo::clonable_ptr<DetectDestruction> p{std::make_unique<DetectDestruction>()};
572 ASSERT_EQ(DetectDestruction::activeCount, 1);
573 }
574 {
575 DestructionGuard check;
576 mongo::clonable_ptr<DetectDestruction> p = std::make_unique<DetectDestruction>();
577 ASSERT_EQ(DetectDestruction::activeCount, 1);
578 }
579
580 // Two separate constructions are unlinked
581 {
582 DestructionGuard check;
583
584 mongo::clonable_ptr<DetectDestruction> p1{std::make_unique<DetectDestruction>()};
585 ASSERT_EQ(DetectDestruction::activeCount, 1);
586
587 {
588 mongo::clonable_ptr<DetectDestruction> p2{std::make_unique<DetectDestruction>()};
589 ASSERT_EQ(DetectDestruction::activeCount, 2);
590 }
591 ASSERT_EQ(DetectDestruction::activeCount, 1);
592 }
593
594 // Two separate constructions can have opposite order and be unlinked
595 {
596 DestructionGuard check;
597
598 auto p1 = std::make_unique<mongo::clonable_ptr<DetectDestruction>>(
599 std::make_unique<DetectDestruction>());
600 ASSERT_EQ(DetectDestruction::activeCount, 1);
601
602 auto p2 = std::make_unique<mongo::clonable_ptr<DetectDestruction>>(
603 std::make_unique<DetectDestruction>());
604 ASSERT_EQ(DetectDestruction::activeCount, 2);
605
606 p1.reset();
607 ASSERT_EQ(DetectDestruction::activeCount, 1);
608
609 p2.reset();
610 ASSERT_EQ(DetectDestruction::activeCount, 0);
611 }
612 }
613
614 // TODO: Bring in an "equivalence class for equality predicate testing" framework.
615 // Equals and Not Equals need to be tested independently -- It is not valid to assume that equals
616 // and not equals are correctly implemented as complimentary predicates. Equality must be
617 // reflexive, symmetric and transitive. This requres several instances that all have the same
618 // value. Simply testing "2 == 2" and "3 != 2" is insufficient. Every combination of position and
619 // equality must be tested to come out as expected.
620 //
621 // Consider that with equality it is important to make sure that `a == b` has the same meaning as `b
622 // == a`. It is also necessary to check that `a == b` and `b == c` and `a == c` is true, when all
623 // three are equal, and to do so in reverse: `b == a` and `c == b` and `c == a`. Further, the
624 // relationships above have to hold for multiple cases. Similar cases need to be tested for
625 // inequality.
626 //
627 // Further, equality is an incredibly important operation to test completely and thoroughly --
628 // besides being a critical element in code using any value modeling type, it also is the keystone
629 // in any testing schedule for a copyable and movable value type. Almost all testing of behavior
630 // relies upon being able to detect fundamental differences in value. In order to provide this
631 // correctly, we provide a full battery of tests for equality in all mathematically relevant
632 // situations. For this equality testing schedule to be correct, we require a mechanism to
633 // initialize objects (and references to those objects) which have predictable value. These
634 // predictable values are then used to test known equality expressions for the correct evaluation.
635 //
636 // All other tests can then just use equality to verify that an object is in the desired state.
637 // This greatly simplifies testing and also makes tests more precise.
TEST(ClonablePtrTest,basicEqualityTest)638 TEST(ClonablePtrTest, basicEqualityTest) {
639 DestructionGuard check;
640
641 mongo::clonable_ptr<DetectDestruction> n1;
642 mongo::clonable_ptr<DetectDestruction> n2;
643 mongo::clonable_ptr<DetectDestruction> n3;
644
645 mongo::clonable_ptr<DetectDestruction> a = std::make_unique<DetectDestruction>();
646 mongo::clonable_ptr<DetectDestruction> b = std::make_unique<DetectDestruction>();
647 mongo::clonable_ptr<DetectDestruction> c = std::make_unique<DetectDestruction>();
648
649 const mongo::clonable_ptr<DetectDestruction>& ap = a;
650 const mongo::clonable_ptr<DetectDestruction>& bp = b;
651 const mongo::clonable_ptr<DetectDestruction>& cp = c;
652 const mongo::clonable_ptr<DetectDestruction>& ap2 = a;
653 const mongo::clonable_ptr<DetectDestruction>& bp2 = b;
654 const mongo::clonable_ptr<DetectDestruction>& cp2 = c;
655
656 // Equals operator
657
658 // Identity checks
659
660 ASSERT(n1 == n1);
661 ASSERT(n2 == n2);
662 ASSERT(n3 == n3);
663
664 ASSERT(a == a);
665 ASSERT(b == b);
666 ASSERT(c == c);
667
668 // Same value checks. (Because unique pointers should never be the same value, we have to use
669 // references.)
670
671 ASSERT(n1 == n2);
672 ASSERT(n1 == n3);
673
674 ASSERT(n2 == n1);
675 ASSERT(n2 == n3);
676
677 ASSERT(n3 == n1);
678 ASSERT(n3 == n2);
679
680 ASSERT(a == ap);
681 ASSERT(a == ap2);
682 ASSERT(ap == a);
683 ASSERT(ap == ap2);
684 ASSERT(ap2 == a);
685 ASSERT(ap2 == ap);
686
687 ASSERT(b == bp);
688 ASSERT(b == bp2);
689 ASSERT(bp == b);
690 ASSERT(bp == bp2);
691 ASSERT(bp2 == b);
692 ASSERT(bp2 == bp);
693
694 ASSERT(c == cp);
695 ASSERT(c == cp2);
696 ASSERT(cp == c);
697 ASSERT(cp == cp2);
698 ASSERT(cp2 == c);
699 ASSERT(cp2 == cp);
700
701 // Different value checks:
702
703 ASSERT(!(a == n1));
704 ASSERT(!(b == n1));
705 ASSERT(!(c == n1));
706 ASSERT(!(a == n2));
707 ASSERT(!(b == n2));
708 ASSERT(!(c == n2));
709
710 ASSERT(!(n1 == a));
711 ASSERT(!(n1 == b));
712 ASSERT(!(n1 == c));
713 ASSERT(!(n2 == a));
714 ASSERT(!(n2 == b));
715 ASSERT(!(n2 == c));
716
717 ASSERT(!(a == b));
718 ASSERT(!(a == c));
719
720 ASSERT(!(b == a));
721 ASSERT(!(b == c));
722
723 ASSERT(!(c == a));
724 ASSERT(!(c == b));
725
726 // Not Equals operator
727
728 // Identity checks
729
730 ASSERT(!(n1 != n1));
731 ASSERT(!(n2 != n2));
732 ASSERT(!(n3 != n3));
733
734 ASSERT(!(a != a));
735 ASSERT(!(b != b));
736 ASSERT(!(c != c));
737
738 // Same value checks. (Because unique pointers should never be the same value, we have to use
739 // references.)
740
741 ASSERT(!(n1 != n2));
742 ASSERT(!(n1 != n3));
743
744 ASSERT(!(n2 != n1));
745 ASSERT(!(n2 != n3));
746
747 ASSERT(!(n3 != n1));
748 ASSERT(!(n3 != n2));
749
750 ASSERT(!(a != ap));
751 ASSERT(!(a != ap2));
752 ASSERT(!(ap != a));
753 ASSERT(!(ap != ap2));
754 ASSERT(!(ap2 != a));
755 ASSERT(!(ap2 != ap));
756
757 ASSERT(!(b != bp));
758 ASSERT(!(b != bp2));
759 ASSERT(!(bp != b));
760 ASSERT(!(bp != bp2));
761 ASSERT(!(bp2 != b));
762 ASSERT(!(bp2 != bp));
763
764 ASSERT(!(c != cp));
765 ASSERT(!(c != cp2));
766 ASSERT(!(cp != c));
767 ASSERT(!(cp != cp2));
768 ASSERT(!(cp2 != c));
769 ASSERT(!(cp2 != cp));
770
771 // Different value checks:
772
773 ASSERT(a != n1);
774 ASSERT(b != n1);
775 ASSERT(c != n1);
776 ASSERT(a != n2);
777 ASSERT(b != n2);
778 ASSERT(c != n2);
779
780 ASSERT(n1 != a);
781 ASSERT(n1 != b);
782 ASSERT(n1 != c);
783 ASSERT(n2 != a);
784 ASSERT(n2 != b);
785 ASSERT(n2 != c);
786
787 ASSERT(a != b);
788 ASSERT(a != c);
789
790 ASSERT(b != a);
791 ASSERT(b != c);
792
793 ASSERT(c != a);
794 ASSERT(c != b);
795 }
796
797 // TODO: all other forms of equality with other types (`std::nullptr_t` and `std::unique_ptr< T >`)
798 // need testing still.
799
TEST(ClonablePtrTest,ownershipStabilityTest)800 TEST(ClonablePtrTest, ownershipStabilityTest) {
801 {
802 DestructionGuard check;
803
804 auto ptr_init = std::make_unique<DetectDestruction>();
805 const auto* rp = ptr_init.get();
806
807 mongo::clonable_ptr<DetectDestruction> cp = std::move(ptr_init);
808
809 ASSERT(rp == cp.get());
810
811 mongo::clonable_ptr<DetectDestruction> cp2 = std::move(cp);
812
813 ASSERT(rp == cp2.get());
814
815 mongo::clonable_ptr<DetectDestruction> cp3;
816
817 ASSERT(nullptr == cp3);
818
819 cp3 = std::move(cp2);
820
821 ASSERT(rp == cp3.get());
822 }
823
824 {
825 auto ptr_init = std::make_unique<DetectDestruction>();
826 const auto* rp = ptr_init.get();
827
828 mongo::clonable_ptr<DetectDestruction> cp{ptr_init.release()};
829
830 ASSERT(rp == cp.get());
831
832 mongo::clonable_ptr<DetectDestruction> cp2 = std::move(cp);
833
834 ASSERT(rp == cp2.get());
835
836 mongo::clonable_ptr<DetectDestruction> cp3;
837
838 ASSERT(nullptr == cp3.get());
839
840 cp3 = std::move(cp2);
841
842 ASSERT(rp == cp3.get());
843 }
844 }
845
846 class ClonableObject {
847 private:
848 int value = 0;
849
850 public:
851 // ClonableObject( const ClonableObject & ) { abort(); }
852 ClonableObject() = default;
ClonableObject(const int v)853 explicit ClonableObject(const int v) : value(v) {}
854
clone() const855 std::unique_ptr<ClonableObject> clone() const {
856 return std::make_unique<ClonableObject>(*this);
857 }
858
make_equality_lens() const859 auto make_equality_lens() const -> decltype(std::tie(this->value)) {
860 return std::tie(value);
861 }
862 };
863
operator ==(const ClonableObject & lhs,const ClonableObject & rhs)864 bool operator==(const ClonableObject& lhs, const ClonableObject& rhs) {
865 return lhs.make_equality_lens() == rhs.make_equality_lens();
866 }
867
operator !=(const ClonableObject & lhs,const ClonableObject & rhs)868 bool operator!=(const ClonableObject& lhs, const ClonableObject& rhs) {
869 return !(lhs == rhs);
870 }
871
TEST(ClonablePtrTest,noObjectCopySemanticTest)872 TEST(ClonablePtrTest, noObjectCopySemanticTest) {
873 mongo::clonable_ptr<ClonableObject> p;
874
875 mongo::clonable_ptr<ClonableObject> p2 = p;
876 ASSERT(p == p2);
877
878 mongo::clonable_ptr<ClonableObject> p3;
879
880 p3 = p;
881 ASSERT(p == p3);
882 }
883
TEST(ClonablePtrTest,objectCopySemanticTest)884 TEST(ClonablePtrTest, objectCopySemanticTest) {
885 mongo::clonable_ptr<ClonableObject> p = std::make_unique<ClonableObject>(1);
886 mongo::clonable_ptr<ClonableObject> q = std::make_unique<ClonableObject>(2);
887 ASSERT(p != q);
888 ASSERT(*p != *q);
889
890 mongo::clonable_ptr<ClonableObject> p2 = p;
891 ASSERT(p != p2);
892 ASSERT(*p == *p2);
893
894 mongo::clonable_ptr<ClonableObject> q2 = q;
895 ASSERT(q2 != q);
896 ASSERT(q2 != p);
897 ASSERT(q2 != p2);
898 ASSERT(*q2 == *q);
899
900 q2 = p2;
901 ASSERT(q2 != q);
902 ASSERT(q2 != p);
903 ASSERT(q2 != p2);
904 ASSERT(*q2 == *p2);
905 }
906
907 class Interface {
908 public:
909 virtual ~Interface() = default;
910 virtual void consumeText(const std::string& message) = 0;
911 virtual std::string produceText() = 0;
912
clone() const913 std::unique_ptr<Interface> clone() const {
914 return std::unique_ptr<Interface>{this->clone_impl()};
915 }
916
917 private:
918 virtual Interface* clone_impl() const = 0;
919 };
920
921 class GeneratorImplementation : public Interface {
922 private:
923 const std::string root;
924 int generation = 0;
925
clone_impl() const926 GeneratorImplementation* clone_impl() const {
927 return new GeneratorImplementation{*this};
928 }
929
930 public:
GeneratorImplementation(const std::string & m)931 explicit GeneratorImplementation(const std::string& m) : root(m) {}
932
consumeText(const std::string &)933 void consumeText(const std::string&) override {}
934
produceText()935 std::string produceText() override {
936 return root + boost::lexical_cast<std::string>(++generation);
937 }
938 };
939
940 class StorageImplementation : public Interface {
941 private:
942 std::string store;
943
clone_impl() const944 StorageImplementation* clone_impl() const {
945 return new StorageImplementation{*this};
946 }
947
948 public:
consumeText(const std::string & m)949 void consumeText(const std::string& m) override {
950 store = m;
951 }
produceText()952 std::string produceText() override {
953 return store;
954 }
955 };
956
957
TEST(ClonablePtrSimpleTest,simpleUsageExample)958 TEST(ClonablePtrSimpleTest, simpleUsageExample) {
959 mongo::clonable_ptr<Interface> source;
960 mongo::clonable_ptr<Interface> sink;
961
962 mongo::clonable_ptr<Interface> instance = std::make_unique<StorageImplementation>();
963
964 sink = instance;
965
966 ASSERT(instance.get() != sink.get());
967
968 instance = std::make_unique<GeneratorImplementation>("base message");
969
970
971 source = std::move(instance);
972
973
974 sink->consumeText(source->produceText());
975 }
976
977 } // namespace BehaviorTests
978 } // namespace
979