#include #include #include #include class Foo { public: virtual ~Foo() = default; virtual void set_foo(int) = 0; virtual int get_foo() const = 0; }; class Bar: public Foo { int m_i = 0; public: virtual void set_foo(int i) { m_i = i; } virtual int get_foo() const { return m_i; }; }; class BarPlus: public Foo { int m_i = 0; public: virtual void set_foo(int i) { m_i = i + 1; } virtual int get_foo() const { return m_i; }; }; TEST_CASE("Testing AnyPtr", "[anyptr]") { using Slic3r::AnyPtr; SECTION("Construction with various valid arguments using operator=") { auto args = std::make_tuple(nullptr, AnyPtr{nullptr}, AnyPtr{static_cast(nullptr)}, AnyPtr{static_cast(nullptr)}, AnyPtr{static_cast(nullptr)}, AnyPtr{}, AnyPtr{}, AnyPtr{}, static_cast(nullptr), static_cast(nullptr), static_cast(nullptr)); auto check_ptr = [](auto &ptr) { REQUIRE(!ptr); REQUIRE(!ptr.is_owned()); auto shp = ptr.get_shared_cpy(); REQUIRE(!shp); }; SECTION("operator =") { Slic3r::for_each_in_tuple([&check_ptr](auto &arg){ AnyPtr ptr = std::move(arg); check_ptr(ptr); }, args); } SECTION("move construction") { Slic3r::for_each_in_tuple([&check_ptr](auto &arg){ AnyPtr ptr{std::move(arg)}; check_ptr(ptr); }, args); } } GIVEN("A polymorphic base class type Foo") { WHEN("Creating a subclass on the stack") { Bar bar; auto val = random_value(-100, 100); bar.set_foo(val); THEN("Storing a raw pointer in an AnyPtr should be valid " "until the object is not destroyed") { AnyPtr ptr = &bar; auto val2 = random_value(-100, 100); ptr->set_foo(val2); REQUIRE(ptr->get_foo() == val2); } THEN("Storing a raw pointer in an AnyPtr should be " "valid until the object is not destroyed") { AnyPtr ptr{&bar}; REQUIRE(ptr->get_foo() == val); } } } GIVEN("An empty AnyPtr of type Foo") { AnyPtr ptr; WHEN("Re-assigning a new unique_ptr of object of type Bar to ptr") { auto bar = std::make_unique(); auto val = random_value(-100, 100); bar->set_foo(val); ptr = std::move(bar); THEN("the ptr should contain the new object and should own it") { REQUIRE(ptr->get_foo() == val); REQUIRE(ptr.is_owned()); } } WHEN("Re-assigning a new unique_ptr of object of type BarPlus to ptr") { auto barplus = std::make_unique(); auto val = random_value(-100, 100); barplus->set_foo(val); ptr = std::move(barplus); THEN("the ptr should contain the new object and should own it") { REQUIRE(ptr->get_foo() == val + 1); REQUIRE(ptr.is_owned()); } THEN("copying the stored object into a shared_ptr should be invalid") { std::shared_ptr shptr = ptr.get_shared_cpy(); REQUIRE(!shptr); } THEN("copying the stored object into a shared_ptr after calling " "convert_unique_to_shared should be valid") { ptr.convert_unique_to_shared(); std::shared_ptr shptr = ptr.get_shared_cpy(); REQUIRE(shptr); REQUIRE(shptr->get_foo() == val + 1); } } } GIVEN("A vector of AnyPtr pointer to random Bar or BarPlus objects") { std::vector> ptrs; auto N = random_value(size_t(1), size_t(10)); INFO("N = " << N); std::generate_n(std::back_inserter(ptrs), N, []{ auto v = random_value(0, 1); std::unique_ptr ret; if (v) ret = std::make_unique(); else ret = std::make_unique(); return ret; }); WHEN("moving the whole array into a vector of AnyPtr") { THEN("the move should be valid") { std::vector> constptrs; std::vector vals; std::transform(ptrs.begin(), ptrs.end(), std::back_inserter(vals), [](auto &p) { return p->get_foo(); }); std::move(ptrs.begin(), ptrs.end(), std::back_inserter(constptrs)); REQUIRE(constptrs.size() == N); REQUIRE(ptrs.size() == N); REQUIRE(std::all_of(ptrs.begin(), ptrs.end(), [](auto &p) { return !p; })); for (size_t i = 0; i < N; ++i) { REQUIRE(vals[i] == constptrs[i]->get_foo()); } } } } }