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