/**
* Copyright (C) 2016 MongoDB Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the GNU Affero General Public License in all respects
* for all of the code used other than as permitted herein. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you do not
* wish to do so, delete this exception statement from your version. If you
* delete this exception statement from all source files in the program,
* then also delete it in the license file.
*/
#include "mongo/base/clonable_ptr.h"
#include "mongo/stdx/functional.h"
#include "mongo/stdx/memory.h"
#include "mongo/unittest/unittest.h"
#include
namespace {
namespace stdx = mongo::stdx;
template
void runSyntaxTest(Test&& t) {
if (false)
t();
}
// These testing helper classes model various kinds of class which should be compatible with
// `mongo::clonable_ptr`. The basic use cases satisfied by each class are described in each class's
// documentation.
// This class models the `Clonable` concept, and is used to test the simple case of `clonable_ptr`.
class ClonableTest {
private:
std::string data =
"This is the string data which is stored to make Functor Clonable need a complicated copy "
"ctor.";
public:
std::unique_ptr clone() const {
return mongo::stdx::make_unique();
}
};
// This class provides a member structure which models `CloneFactory`. The member
// structure is available under the expected member name of `clone_factory_type`. The
// `CloneFactory` is stateless.
class AltClonableTest {
private:
std::string data =
"This is the string data which is stored to make Functor Clonable need a complicated copy "
"ctor.";
public:
struct clone_factory_type {
std::unique_ptr operator()(const AltClonableTest&) const {
return mongo::stdx::make_unique();
}
};
};
// This class requires a companion cloning function models `CloneFactory`. There
// is an attendant specialization of the `mongo::clonable_traits` metafunction to provide the clone
// factory for this type. That `CloneFactory` is stateless.
class Alt2ClonableTest {
private:
std::string data =
"This is the string data which is stored to make Functor Clonable need a complicated copy "
"ctor.";
};
} // namespace
namespace mongo {
// This specialization of the `mongo::clonable_traits` metafunction provides a model of a stateless
// `CloneFactory`
template <>
struct clonable_traits<::Alt2ClonableTest> {
struct clone_factory_type {
std::unique_ptr operator()(const Alt2ClonableTest&) const {
return mongo::stdx::make_unique();
}
};
};
} // namespace mongo
namespace {
// This class uses a stateful cloning function provided by the `getCloningFunction` static member.
// This stateful `CloneFactory` must be passed to constructors of the
// `cloning_ptr`.
class FunctorClonable {
private:
std::string data =
"This is the string data which is stored to make Functor Clonable need a complicated copy "
"ctor.";
public:
using CloningFunctionType =
mongo::stdx::function(const FunctorClonable&)>;
static CloningFunctionType getCloningFunction() {
return
[](const FunctorClonable& c) { return mongo::stdx::make_unique(c); };
}
};
// This class uses a stateful cloning function provided by the `getCloningFunction` static member.
// This stateful `CloneFactory` must be passed to constructors of
// the `cloning_ptr`. The `CloneFactory` for this type dynamically updates its internal state.
// This is used to test cloning of objects that have dynamically changing clone factories.
class FunctorWithDynamicStateClonable {
private:
std::string data =
"This is the string data which is stored to make Functor Clonable need a complicated copy "
"ctor.";
public:
FunctorWithDynamicStateClonable(const FunctorWithDynamicStateClonable&) = delete;
FunctorWithDynamicStateClonable() = default;
FunctorWithDynamicStateClonable(const std::string& s) : data(s) {}
using CloningFunctionType = stdx::function(
const FunctorWithDynamicStateClonable&)>;
static CloningFunctionType getCloningFunction() {
return [calls = 0](const FunctorWithDynamicStateClonable& c) mutable {
return mongo::stdx::make_unique(
c.data + boost::lexical_cast(++calls));
};
}
};
// This class models `Clonable`, with a return from clone which is
// `Constructible>` but isn't
// `std::unique_ptr`. This is used to test that the `clonable_ptr` class does
// not expect `RawPointerClonable::clone() const` to return a model of
// `UniquePtr`
class RawPointerClonable {
public:
RawPointerClonable* clone() const {
return new RawPointerClonable;
}
};
// This class models `Clonable`, with a return from clone which is
// `Constructible>` because it is
// `std::unique_ptr`. This is used to test that the `clonable_ptr` class can
// use a `UniquePtrClonable::clone() const` that returns a model of
// `UniquePtr`
class UniquePtrClonable {
public:
std::unique_ptr clone() const {
return mongo::stdx::make_unique();
}
};
TEST(ClonablePtrTest, syntax_smoke_test) {
// TODO: Either add a compressed pair type for optimization, or wait for MSVC to get this feature by
// default. MSVC doesn't make its tuple compressed, which causes this test to fail on MSVC.
#ifndef _MSC_VER
{
mongo::clonable_ptr p;
p = mongo::stdx::make_unique();
mongo::clonable_ptr p2 = p;
ASSERT_TRUE(p != p2);
static_assert(sizeof(p) == sizeof(ClonableTest*),
"`mongo::clonable_ptr< T >` should be `sizeof` a pointer when there is no "
"CloneFactory");
}
#endif
{
mongo::clonable_ptr p;
p = mongo::stdx::make_unique();
mongo::clonable_ptr p2 = p;
ASSERT_TRUE(p != p2);
}
{
mongo::clonable_ptr p;
p = mongo::stdx::make_unique();
mongo::clonable_ptr p2 = p;
ASSERT_TRUE(p != p2);
}
{
mongo::clonable_ptr p{
FunctorClonable::getCloningFunction()};
p = mongo::stdx::make_unique();
mongo::clonable_ptr p2 = p;
ASSERT_TRUE(p != p2);
mongo::clonable_ptr p3{
FunctorClonable::getCloningFunction()};
auto tmp = mongo::stdx::make_unique();
p3 = std::move(tmp);
ASSERT_TRUE(p != p2);
ASSERT_TRUE(p2 != p3);
ASSERT_TRUE(p != p3);
}
}
// These tests check that all expected valid syntactic forms of use for the
// `mongo::clonable_ptr` are valid. These tests assert nothing but provide a single
// unified place to check the syntax of this component. Build failures in these parts indicate that
// a change to the component has broken an expected valid syntactic usage. Any expected valid usage
// which is not in this list should be added.
namespace SyntaxTests {
template
void construction() {
// Test default construction
{ mongo::clonable_ptr{}; }
// Test construction from a nullptr
{ mongo::clonable_ptr{nullptr}; }
// Test construction from a Clonable pointer.
{
Clonable* const local = nullptr;
mongo::clonable_ptr{local};
}
// Test move construction.
{ mongo::clonable_ptr{mongo::clonable_ptr{}}; }
// Test copy construction.
{
mongo::clonable_ptr a;
mongo::clonable_ptr b{a};
}
// Test move assignment.
{
mongo::clonable_ptr a;
a = mongo::clonable_ptr{};
}
// Test copy assignment.
{
mongo::clonable_ptr a;
mongo::clonable_ptr b;
b = a;
}
// Test unique pointer construction
{ mongo::clonable_ptr{mongo::stdx::make_unique()}; }
// Test unique pointer construction (conversion)
{
auto acceptor = [](const mongo::clonable_ptr&) {};
acceptor(mongo::stdx::make_unique());
}
// Test non-conversion pointer construction
{ static_assert(!std::is_convertible>::value, ""); }
// Test conversion unique pointer construction
{
static_assert(
std::is_convertible, mongo::clonable_ptr>::value,
"");
}
}
// Tests that syntactic forms that require augmented construction are proper
template
void augmentedConstruction() {
// Test default construction
{
static_assert(
!std::is_default_constructible>::value, "");
}
// Test Clone Factory construction
{ mongo::clonable_ptr{Clonable::getCloningFunction()}; }
// TODO: Revist this when MSVC's enable-if and deletion on ctors works.
#ifndef _MSC_VER
// Test non-construction from a nullptr
{
static_assert(!std::is_constructible,
std::nullptr_t>::value,
"");
}
#endif
// Test construction from a nullptr with factory
{ mongo::clonable_ptr{nullptr, Clonable::getCloningFunction()}; }
// TODO: Revist this when MSVC's enable-if and deletion on ctors works.
#ifndef _MSC_VER
// Test construction from a raw Clonable pointer.
{
static_assert(
!std::is_constructible, Clonable*>::value,
"");
}
#endif
// Test initialization of a raw Clonable pointer with factory, using reset.
{
Clonable* const local = nullptr;
mongo::clonable_ptr p{Clonable::getCloningFunction()};
p.reset(local);
}
// Test move construction.
{
mongo::clonable_ptr{
mongo::clonable_ptr{Clonable::getCloningFunction()}};
}
// Test copy construction.
{
mongo::clonable_ptr a{Clonable::getCloningFunction()};
mongo::clonable_ptr b{a};
}
// Test augmented copy construction.
{
mongo::clonable_ptr a{Clonable::getCloningFunction()};
mongo::clonable_ptr b{a, Clonable::getCloningFunction()};
}
// Test move assignment.
{
mongo::clonable_ptr a{Clonable::getCloningFunction()};
a = mongo::clonable_ptr{Clonable::getCloningFunction()};
}
// Test copy assignment.
{
mongo::clonable_ptr a{Clonable::getCloningFunction()};
mongo::clonable_ptr b{Clonable::getCloningFunction()};
b = a;
}
// Test unique pointer construction
{
mongo::clonable_ptr{mongo::stdx::make_unique(),
Clonable::getCloningFunction()};
}
// Test augmented unique pointer construction
{
mongo::clonable_ptr{mongo::stdx::make_unique(),
Clonable::getCloningFunction()};
}
// Test non-conversion pointer construction
{
static_assert(
!std::is_convertible, Clonable*>::value,
"");
}
// Test non-conversion from factory
{
static_assert(
!std::is_convertible, CloneFactory>::value,
"");
}
// Test conversion unique pointer construction
{
static_assert(!std::is_convertible,
mongo::clonable_ptr>::value,
"");
}
}
template
void pointerOperations() {
mongo::clonable_ptr a;
// Test `.get()` functionality:
{
Clonable* p = a.get();
(void)p;
}
// Test `->` functionality
{
// We don't actually want to call the dtor, but we want the compiler to check that we
// have.
if (false) {
a->~Clonable();
}
}
// Test `*` functionality
Clonable& r = *a;
(void)r;
// Test reset functionality
{
a.reset();
a.reset(nullptr);
a.reset(new Clonable);
}
}
template
void equalityOperations() {
mongo::clonable_ptr a;
mongo::clonable_ptr b;
std::unique_ptr ua;
// Test equality expressions
{
(void)(a == a);
(void)(a == b);
(void)(b == a);
(void)(a == ua);
(void)(ua == a);
(void)(nullptr == a);
(void)(a == nullptr);
}
// Test inequality expressions
{
(void)(a != a);
(void)(a != b);
(void)(b != a);
(void)(a != ua);
(void)(ua != a);
(void)(nullptr == a);
(void)(a == nullptr);
}
}
} // namespace SyntaxTests
TEST(ClonablePtrSyntaxTests, construction) {
runSyntaxTest(SyntaxTests::construction);
runSyntaxTest(SyntaxTests::construction);
runSyntaxTest(SyntaxTests::construction);
runSyntaxTest(SyntaxTests::construction);
runSyntaxTest(SyntaxTests::construction);
}
TEST(ClonablePtrSyntaxTests, augmentedConstruction) {
runSyntaxTest(
SyntaxTests::augmentedConstruction);
runSyntaxTest(
SyntaxTests::augmentedConstruction);
}
TEST(ClonablePtrSyntaxTests, pointerOperations) {
runSyntaxTest(SyntaxTests::pointerOperations);
runSyntaxTest(SyntaxTests::pointerOperations);
runSyntaxTest(SyntaxTests::pointerOperations);
runSyntaxTest(SyntaxTests::pointerOperations);
runSyntaxTest(SyntaxTests::pointerOperations);
}
TEST(ClonablePtrSyntaxTests, equalityOperations) {
runSyntaxTest(SyntaxTests::equalityOperations);
runSyntaxTest(SyntaxTests::equalityOperations);
runSyntaxTest(SyntaxTests::equalityOperations);
runSyntaxTest(SyntaxTests::equalityOperations);
runSyntaxTest(SyntaxTests::equalityOperations);
}
namespace BehaviorTests {
class DetectDestruction {
public:
static int activeCount;
static void resetCount() {
activeCount = 0;
}
~DetectDestruction() {
--activeCount;
}
DetectDestruction(const DetectDestruction&) {
++activeCount;
}
DetectDestruction& operator=(const DetectDestruction&) = delete;
DetectDestruction(DetectDestruction&&) = delete;
DetectDestruction& operator=(DetectDestruction&&) = delete;
DetectDestruction() {
++activeCount;
}
std::unique_ptr clone() const {
return mongo::stdx::make_unique(*this);
}
};
int DetectDestruction::activeCount = 0;
struct DestructionGuard {
DestructionGuard(const DestructionGuard&) = delete;
DestructionGuard& operator=(const DestructionGuard&) = delete;
DestructionGuard() {
DetectDestruction::resetCount();
}
~DestructionGuard() {
ASSERT_EQ(DetectDestruction::activeCount, 0);
}
};
TEST(ClonablePtrTest, basic_construction_test) {
// Do not default construct the object
{
DestructionGuard check;
mongo::clonable_ptr p;
ASSERT_EQ(DetectDestruction::activeCount, 0);
}
// Do not make unnecessary copies of the object from ptr
{
DestructionGuard check;
mongo::clonable_ptr p{new DetectDestruction};
ASSERT_EQ(DetectDestruction::activeCount, 1);
}
// Do not make unnecessary copies of the object from unique_ptr
{
DestructionGuard check;
mongo::clonable_ptr p{mongo::stdx::make_unique()};
ASSERT_EQ(DetectDestruction::activeCount, 1);
}
{
DestructionGuard check;
mongo::clonable_ptr p = mongo::stdx::make_unique();
ASSERT_EQ(DetectDestruction::activeCount, 1);
}
// Two separate constructions are unlinked
{
DestructionGuard check;
mongo::clonable_ptr p1{mongo::stdx::make_unique()};
ASSERT_EQ(DetectDestruction::activeCount, 1);
{
mongo::clonable_ptr p2{
mongo::stdx::make_unique()};
ASSERT_EQ(DetectDestruction::activeCount, 2);
}
ASSERT_EQ(DetectDestruction::activeCount, 1);
}
// Two separate constructions can have opposite order and be unlinked
{
DestructionGuard check;
auto p1 = mongo::stdx::make_unique>(
mongo::stdx::make_unique());
ASSERT_EQ(DetectDestruction::activeCount, 1);
auto p2 = mongo::stdx::make_unique>(
mongo::stdx::make_unique());
ASSERT_EQ(DetectDestruction::activeCount, 2);
p1.reset();
ASSERT_EQ(DetectDestruction::activeCount, 1);
p2.reset();
ASSERT_EQ(DetectDestruction::activeCount, 0);
}
}
// TODO: Bring in an "equivalence class for equality predicate testing" framework.
// Equals and Not Equals need to be tested independently -- It is not valid to assume that equals
// and not equals are correctly implemented as complimentary predicates. Equality must be
// reflexive, symmetric and transitive. This requres several instances that all have the same
// value. Simply testing "2 == 2" and "3 != 2" is insufficient. Every combination of position and
// equality must be tested to come out as expected.
//
// Consider that with equality it is important to make sure that `a == b` has the same meaning as `b
// == a`. It is also necessary to check that `a == b` and `b == c` and `a == c` is true, when all
// three are equal, and to do so in reverse: `b == a` and `c == b` and `c == a`. Further, the
// relationships above have to hold for multiple cases. Similar cases need to be tested for
// inequality.
//
// Further, equality is an incredibly important operation to test completely and thoroughly --
// besides being a critical element in code using any value modeling type, it also is the keystone
// in any testing schedule for a copyable and movable value type. Almost all testing of behavior
// relies upon being able to detect fundamental differences in value. In order to provide this
// correctly, we provide a full battery of tests for equality in all mathematically relevant
// situations. For this equality testing schedule to be correct, we require a mechanism to
// initialize objects (and references to those objects) which have predictable value. These
// predictable values are then used to test known equality expressions for the correct evaluation.
//
// All other tests can then just use equality to verify that an object is in the desired state.
// This greatly simplifies testing and also makes tests more precise.
TEST(ClonablePtrTest, basicEqualityTest) {
DestructionGuard check;
mongo::clonable_ptr n1;
mongo::clonable_ptr n2;
mongo::clonable_ptr n3;
mongo::clonable_ptr a = mongo::stdx::make_unique();
mongo::clonable_ptr b = mongo::stdx::make_unique();
mongo::clonable_ptr c = mongo::stdx::make_unique();
const mongo::clonable_ptr& ap = a;
const mongo::clonable_ptr& bp = b;
const mongo::clonable_ptr& cp = c;
const mongo::clonable_ptr& ap2 = a;
const mongo::clonable_ptr& bp2 = b;
const mongo::clonable_ptr& cp2 = c;
// Equals operator
// Identity checks
ASSERT(n1 == n1);
ASSERT(n2 == n2);
ASSERT(n3 == n3);
ASSERT(a == a);
ASSERT(b == b);
ASSERT(c == c);
// Same value checks. (Because unique pointers should never be the same value, we have to use
// references.)
ASSERT(n1 == n2);
ASSERT(n1 == n3);
ASSERT(n2 == n1);
ASSERT(n2 == n3);
ASSERT(n3 == n1);
ASSERT(n3 == n2);
ASSERT(a == ap);
ASSERT(a == ap2);
ASSERT(ap == a);
ASSERT(ap == ap2);
ASSERT(ap2 == a);
ASSERT(ap2 == ap);
ASSERT(b == bp);
ASSERT(b == bp2);
ASSERT(bp == b);
ASSERT(bp == bp2);
ASSERT(bp2 == b);
ASSERT(bp2 == bp);
ASSERT(c == cp);
ASSERT(c == cp2);
ASSERT(cp == c);
ASSERT(cp == cp2);
ASSERT(cp2 == c);
ASSERT(cp2 == cp);
// Different value checks:
ASSERT(!(a == n1));
ASSERT(!(b == n1));
ASSERT(!(c == n1));
ASSERT(!(a == n2));
ASSERT(!(b == n2));
ASSERT(!(c == n2));
ASSERT(!(n1 == a));
ASSERT(!(n1 == b));
ASSERT(!(n1 == c));
ASSERT(!(n2 == a));
ASSERT(!(n2 == b));
ASSERT(!(n2 == c));
ASSERT(!(a == b));
ASSERT(!(a == c));
ASSERT(!(b == a));
ASSERT(!(b == c));
ASSERT(!(c == a));
ASSERT(!(c == b));
// Not Equals operator
// Identity checks
ASSERT(!(n1 != n1));
ASSERT(!(n2 != n2));
ASSERT(!(n3 != n3));
ASSERT(!(a != a));
ASSERT(!(b != b));
ASSERT(!(c != c));
// Same value checks. (Because unique pointers should never be the same value, we have to use
// references.)
ASSERT(!(n1 != n2));
ASSERT(!(n1 != n3));
ASSERT(!(n2 != n1));
ASSERT(!(n2 != n3));
ASSERT(!(n3 != n1));
ASSERT(!(n3 != n2));
ASSERT(!(a != ap));
ASSERT(!(a != ap2));
ASSERT(!(ap != a));
ASSERT(!(ap != ap2));
ASSERT(!(ap2 != a));
ASSERT(!(ap2 != ap));
ASSERT(!(b != bp));
ASSERT(!(b != bp2));
ASSERT(!(bp != b));
ASSERT(!(bp != bp2));
ASSERT(!(bp2 != b));
ASSERT(!(bp2 != bp));
ASSERT(!(c != cp));
ASSERT(!(c != cp2));
ASSERT(!(cp != c));
ASSERT(!(cp != cp2));
ASSERT(!(cp2 != c));
ASSERT(!(cp2 != cp));
// Different value checks:
ASSERT(a != n1);
ASSERT(b != n1);
ASSERT(c != n1);
ASSERT(a != n2);
ASSERT(b != n2);
ASSERT(c != n2);
ASSERT(n1 != a);
ASSERT(n1 != b);
ASSERT(n1 != c);
ASSERT(n2 != a);
ASSERT(n2 != b);
ASSERT(n2 != c);
ASSERT(a != b);
ASSERT(a != c);
ASSERT(b != a);
ASSERT(b != c);
ASSERT(c != a);
ASSERT(c != b);
}
// TODO: all other forms of equality with other types (`std::nullptr_t` and `std::unique_ptr< T >`)
// need testing still.
TEST(ClonablePtrTest, ownershipStabilityTest) {
{
DestructionGuard check;
auto ptr_init = mongo::stdx::make_unique();
const auto* rp = ptr_init.get();
mongo::clonable_ptr cp = std::move(ptr_init);
ASSERT(rp == cp.get());
mongo::clonable_ptr cp2 = std::move(cp);
ASSERT(rp == cp2.get());
mongo::clonable_ptr cp3;
ASSERT(nullptr == cp3);
cp3 = std::move(cp2);
ASSERT(rp == cp3.get());
}
{
auto ptr_init = mongo::stdx::make_unique();
const auto* rp = ptr_init.get();
mongo::clonable_ptr cp{ptr_init.release()};
ASSERT(rp == cp.get());
mongo::clonable_ptr cp2 = std::move(cp);
ASSERT(rp == cp2.get());
mongo::clonable_ptr cp3;
ASSERT(nullptr == cp3.get());
cp3 = std::move(cp2);
ASSERT(rp == cp3.get());
}
}
class ClonableObject {
private:
int value = 0;
public:
// ClonableObject( const ClonableObject & ) { abort(); }
ClonableObject() = default;
explicit ClonableObject(const int v) : value(v) {}
std::unique_ptr clone() const {
return mongo::stdx::make_unique(*this);
}
auto make_equality_lens() const -> decltype(std::tie(this->value)) {
return std::tie(value);
}
};
bool operator==(const ClonableObject& lhs, const ClonableObject& rhs) {
return lhs.make_equality_lens() == rhs.make_equality_lens();
}
bool operator!=(const ClonableObject& lhs, const ClonableObject& rhs) {
return !(lhs == rhs);
}
TEST(ClonablePtrTest, noObjectCopySemanticTest) {
mongo::clonable_ptr p;
mongo::clonable_ptr p2 = p;
ASSERT(p == p2);
mongo::clonable_ptr p3;
p3 = p;
ASSERT(p == p3);
}
TEST(ClonablePtrTest, objectCopySemanticTest) {
mongo::clonable_ptr p = mongo::stdx::make_unique(1);
mongo::clonable_ptr q = mongo::stdx::make_unique(2);
ASSERT(p != q);
ASSERT(*p != *q);
mongo::clonable_ptr p2 = p;
ASSERT(p != p2);
ASSERT(*p == *p2);
mongo::clonable_ptr q2 = q;
ASSERT(q2 != q);
ASSERT(q2 != p);
ASSERT(q2 != p2);
ASSERT(*q2 == *q);
q2 = p2;
ASSERT(q2 != q);
ASSERT(q2 != p);
ASSERT(q2 != p2);
ASSERT(*q2 == *p2);
}
class Interface {
public:
virtual ~Interface() = default;
virtual void consumeText(const std::string& message) = 0;
virtual std::string produceText() = 0;
std::unique_ptr clone() const {
return std::unique_ptr{this->clone_impl()};
}
private:
virtual Interface* clone_impl() const = 0;
};
class GeneratorImplementation : public Interface {
private:
const std::string root;
int generation = 0;
GeneratorImplementation* clone_impl() const {
return new GeneratorImplementation{*this};
}
public:
explicit GeneratorImplementation(const std::string& m) : root(m) {}
void consumeText(const std::string&) override {}
std::string produceText() override {
return root + boost::lexical_cast(++generation);
}
};
class StorageImplementation : public Interface {
private:
std::string store;
StorageImplementation* clone_impl() const {
return new StorageImplementation{*this};
}
public:
void consumeText(const std::string& m) override {
store = m;
}
std::string produceText() override {
return store;
}
};
TEST(ClonablePtrSimpleTest, simpleUsageExample) {
mongo::clonable_ptr source;
mongo::clonable_ptr sink;
mongo::clonable_ptr instance = stdx::make_unique();
sink = instance;
ASSERT(instance.get() != sink.get());
instance = stdx::make_unique("base message");
source = std::move(instance);
sink->consumeText(source->produceText());
}
} // namespace BehaviorTests
} // namespace