From 32d5037a6247772739fedaa851078a30d281706d Mon Sep 17 00:00:00 2001 From: Corentin Schreiber Date: Sat, 24 Sep 2022 10:25:35 +0100 Subject: [PATCH 01/81] Fix public `this_control_block` --- include/oup/observable_unique_ptr.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/oup/observable_unique_ptr.hpp b/include/oup/observable_unique_ptr.hpp index ffab836..4dc5e44 100644 --- a/include/oup/observable_unique_ptr.hpp +++ b/include/oup/observable_unique_ptr.hpp @@ -260,8 +260,6 @@ struct enable_observer_from_this_base { /// Policy query helper using queries = policy_queries; - mutable control_block_type* this_control_block = nullptr; - enable_observer_from_this_base() noexcept(!queries::eoft_constructor_allocates()) { if constexpr (queries::eoft_constructor_allocates()) { this_control_block = new control_block_type; @@ -285,6 +283,8 @@ struct enable_observer_from_this_base { } private: + mutable control_block_type* this_control_block = nullptr; + void set_control_block_(control_block_type* b) noexcept { this_control_block = b; this_control_block->push_ref(); @@ -301,6 +301,8 @@ struct enable_observer_from_this_base { friend auto oup::make_observable(Args&&... args); template friend class oup::basic_observable_ptr; + template + friend class oup::basic_enable_observer_from_this; }; } // namespace details From bcdaa1082e1ad365e8dc05afabba0c95ab6ad531 Mon Sep 17 00:00:00 2001 From: Corentin Schreiber Date: Sat, 24 Sep 2022 10:26:22 +0100 Subject: [PATCH 02/81] Clarify error message and comments around over aligned types --- include/oup/observable_unique_ptr.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/oup/observable_unique_ptr.hpp b/include/oup/observable_unique_ptr.hpp index 4dc5e44..56064e6 100644 --- a/include/oup/observable_unique_ptr.hpp +++ b/include/oup/observable_unique_ptr.hpp @@ -890,20 +890,20 @@ auto make_observable(Args&&... args) { // See comment below on alignment static_assert( block_align <= __STDCPP_DEFAULT_NEW_ALIGNMENT__, - "control block is over-aligned, this would require a custom allocator"); + "control block is over-aligned, this is not supported for sealed pointers"); static_assert( obj_align <= __STDCPP_DEFAULT_NEW_ALIGNMENT__, - "object is over-aligned, this would require a custom allocator"); + "object is over-aligned, this is not supported for sealed pointers"); // NB: The correct thing to do here would be to use aligned-new, with an alignment // of max(block_align, obj_align). This would require using aligned-delete in the // control block, which in turn would either require the control block to always use // aligned-delete and aligned-new, which could be wasteful, or to know somehow whether - // it has been allocated here or individually. + // it has been allocated here or individually (which is what the libstdc++ implementation + // of shared_ptr does, with polymorphic control blocks). // Most types will have an alignment <= __STDCPP_DEFAULT_NEW_ALIGNMENT__, which is // the alignment guaranteed by the classic operator new, therefore we can safely use - // it and warn the user with a static asset if we can't. - // Going beyond this would require support for custom allocators. + // it and warn the user with a static assert if we can't. std::byte* buffer = reinterpret_cast(operator new(obj_offset + obj_size)); From 9a1dfdd50951c27162a0c1dd918eaad96f3deba1 Mon Sep 17 00:00:00 2001 From: Corentin Schreiber Date: Sun, 25 Sep 2022 16:09:48 +0100 Subject: [PATCH 03/81] Better encapsulation of pointer_and_deleter --- include/oup/observable_unique_ptr.hpp | 123 ++++++++++++++++---------- 1 file changed, 75 insertions(+), 48 deletions(-) diff --git a/include/oup/observable_unique_ptr.hpp b/include/oup/observable_unique_ptr.hpp index 56064e6..0c9bf55 100644 --- a/include/oup/observable_unique_ptr.hpp +++ b/include/oup/observable_unique_ptr.hpp @@ -35,8 +35,33 @@ namespace details { // on empty base class optimization. In C++20, this could be simplified // by [[no_unique_address]]. template -struct ptr_and_deleter : Deleter { +class ptr_and_deleter : private Deleter { T* data = nullptr; + +public: + explicit ptr_and_deleter(Deleter d, T* ptr) : Deleter(std::move(d)), data(ptr) {} + + ptr_and_deleter() = default; + ptr_and_deleter(const ptr_and_deleter&) = default; + ptr_and_deleter(ptr_and_deleter&&) = default; + ptr_and_deleter& operator=(const ptr_and_deleter&) = default; + ptr_and_deleter& operator=(ptr_and_deleter&&) = default; + + T*& pointer() { + return data; + } + + T* const& pointer() const { + return data; + } + + Deleter& deleter() { + return *static_cast(this); + } + + const Deleter& deleter() const { + return *static_cast(this); + } }; // Struct providing an unsigned integer with at least `Bits` bits. @@ -405,14 +430,14 @@ class basic_observable_ptr final { } void delete_object_() noexcept { - delete_object_(block, ptr_deleter.data, ptr_deleter); + delete_object_(block, ptr_deleter.pointer(), ptr_deleter.deleter()); } void delete_object_if_exists_() noexcept { - if (ptr_deleter.data) { + if (ptr_deleter.pointer()) { delete_object_(); - block = nullptr; - ptr_deleter.data = nullptr; + block = nullptr; + ptr_deleter.pointer() = nullptr; } } @@ -500,9 +525,10 @@ class basic_observable_ptr final { * is moved. */ basic_observable_ptr(basic_observable_ptr&& value) noexcept : - basic_observable_ptr(value.block, value.ptr_deleter.data, std::move(value.ptr_deleter)) { - value.block = nullptr; - value.ptr_deleter.data = nullptr; + basic_observable_ptr( + value.block, value.ptr_deleter.pointer(), std::move(value.ptr_deleter.deleter())) { + value.block = nullptr; + value.ptr_deleter.pointer() = nullptr; } /** @@ -519,9 +545,10 @@ class basic_observable_ptr final { typename enable = std::enable_if_t && std::is_convertible_v>> basic_observable_ptr(basic_observable_ptr&& value) noexcept : - basic_observable_ptr(value.block, value.ptr_deleter.data, std::move(value.ptr_deleter)) { - value.block = nullptr; - value.ptr_deleter.data = nullptr; + basic_observable_ptr( + value.block, value.ptr_deleter.pointer(), std::move(value.ptr_deleter.deleter())) { + value.block = nullptr; + value.ptr_deleter.pointer() = nullptr; } /** @@ -544,8 +571,8 @@ class basic_observable_ptr final { manager.delete_object_if_exists_(); } - manager.block = nullptr; - manager.ptr_deleter.data = nullptr; + manager.block = nullptr; + manager.ptr_deleter.pointer() = nullptr; } /** @@ -569,8 +596,8 @@ class basic_observable_ptr final { manager.delete_object_if_exists_(); } - manager.block = nullptr; - manager.ptr_deleter.data = nullptr; + manager.block = nullptr; + manager.ptr_deleter.pointer() = nullptr; } /** @@ -625,11 +652,11 @@ class basic_observable_ptr final { basic_observable_ptr& operator=(basic_observable_ptr&& value) noexcept { delete_object_if_exists_(); - block = value.block; - value.block = nullptr; - ptr_deleter.data = value.ptr_deleter.data; - value.ptr_deleter.data = nullptr; - static_cast(ptr_deleter) = std::move(static_cast(value.ptr_deleter)); + block = value.block; + value.block = nullptr; + ptr_deleter.pointer() = value.ptr_deleter.pointer(); + value.ptr_deleter.pointer() = nullptr; + ptr_deleter.deleter() = std::move(value.ptr_deleter.deleter()); return *this; } @@ -650,11 +677,11 @@ class basic_observable_ptr final { basic_observable_ptr& operator=(basic_observable_ptr&& value) noexcept { delete_object_if_exists_(); - block = value.block; - value.block = nullptr; - ptr_deleter.data = value.ptr_deleter.data; - value.ptr_deleter.data = nullptr; - static_cast(ptr_deleter) = std::move(static_cast(ptr_deleter)); + block = value.block; + value.block = nullptr; + ptr_deleter.pointer() = value.ptr_deleter.pointer(); + value.ptr_deleter.pointer() = nullptr; + ptr_deleter.deleter() = std::move(value.ptr_deleter.deleter()); return *this; } @@ -668,7 +695,7 @@ class basic_observable_ptr final { * \return The deleter */ Deleter& get_deleter() noexcept { - return ptr_deleter; + return ptr_deleter.deleter(); } /** @@ -676,7 +703,7 @@ class basic_observable_ptr final { * \return The deleter */ const Deleter& get_deleter() const noexcept { - return ptr_deleter; + return ptr_deleter.deleter(); } /** @@ -707,21 +734,21 @@ class basic_observable_ptr final { void reset(U* ptr) noexcept( queries::eoft_always_has_block() && has_enable_observer_from_this) { // Copy old pointer - T* old_ptr = ptr_deleter.data; + T* old_ptr = ptr_deleter.pointer(); control_block_type* old_block = block; // Assign the new one if constexpr (noexcept(get_or_create_block_from_object_(ptr))) { // There is always a control block available for us, so this cannot fail - block = get_or_create_block_from_object_(ptr); - ptr_deleter.data = ptr; + block = get_or_create_block_from_object_(ptr); + ptr_deleter.pointer() = ptr; } else { try { - block = get_or_create_block_from_object_(ptr); - ptr_deleter.data = ptr; + block = get_or_create_block_from_object_(ptr); + ptr_deleter.pointer() = ptr; } catch (...) { // Allocation of control block failed, delete input pointer and rethrow - ptr_deleter(ptr); + ptr_deleter.deleter()(ptr); throw; } } @@ -729,7 +756,7 @@ class basic_observable_ptr final { // Delete the old pointer // (this follows `std::unique_ptr` specs) if (old_ptr) { - delete_object_(old_block, old_ptr, ptr_deleter); + delete_object_(old_block, old_ptr, ptr_deleter.deleter()); } } @@ -741,17 +768,17 @@ class basic_observable_ptr final { static_cast(ptr); // silence "unused variable" warnings // Copy old pointer - T* old_ptr = ptr_deleter.data; + T* old_ptr = ptr_deleter.pointer(); control_block_type* old_block = block; // Assign the new one - block = nullptr; - ptr_deleter.data = nullptr; + block = nullptr; + ptr_deleter.pointer() = nullptr; // Delete the old pointer // (this follows `std::unique_ptr` specs) if (old_ptr) { - delete_object_(old_block, old_ptr, ptr_deleter); + delete_object_(old_block, old_ptr, ptr_deleter.deleter()); } } @@ -770,15 +797,15 @@ class basic_observable_ptr final { typename U = T, typename enable = std::enable_if_t && queries::owner_allow_release()>> T* release() noexcept { - T* old_ptr = ptr_deleter.data; - if (ptr_deleter.data) { + T* old_ptr = ptr_deleter.pointer(); + if (ptr_deleter.pointer()) { if (!has_enable_observer_from_this) { block->set_expired(); } block->pop_ref(); - block = nullptr; - ptr_deleter.data = nullptr; + block = nullptr; + ptr_deleter.pointer() = nullptr; } return old_ptr; @@ -793,7 +820,7 @@ class basic_observable_ptr final { * you are done using the raw pointer. */ T* get() const noexcept { - return ptr_deleter.data; + return ptr_deleter.pointer(); } /** @@ -806,7 +833,7 @@ class basic_observable_ptr final { * you are done using the raw pointer. */ T& operator*() const noexcept { - return *ptr_deleter.data; + return *ptr_deleter.pointer(); } /** @@ -818,7 +845,7 @@ class basic_observable_ptr final { * you are done using the raw pointer. */ T* operator->() const noexcept { - return ptr_deleter.data; + return ptr_deleter.pointer(); } /** @@ -826,7 +853,7 @@ class basic_observable_ptr final { * \return `true` if an object is owned, 'false' otherwise */ explicit operator bool() const noexcept { - return ptr_deleter.data != nullptr; + return ptr_deleter.pointer() != nullptr; } template @@ -1057,7 +1084,7 @@ class basic_observer_ptr final { typename enable = std::enable_if_t< std::is_convertible_v && std::is_same_v>> basic_observer_ptr(const basic_observable_ptr& owner) noexcept : - block(owner.block), data(owner.ptr_deleter.data) { + block(owner.block), data(owner.ptr_deleter.pointer()) { if (block) { block->push_ref(); } @@ -1178,7 +1205,7 @@ class basic_observer_ptr final { typename D, typename enable = std::enable_if_t>> basic_observer_ptr& operator=(const basic_observable_ptr& owner) noexcept { - set_data_(owner.block, owner.ptr_deleter.data); + set_data_(owner.block, owner.ptr_deleter.pointer()); if (block) { block->push_ref(); From 75ef95ee0374cfdf687fb98d363ffb9cbf9f4715 Mon Sep 17 00:00:00 2001 From: Corentin Schreiber Date: Sun, 25 Sep 2022 16:10:24 +0100 Subject: [PATCH 04/81] Fix deleter not moved in explicit conversion contructor --- include/oup/observable_unique_ptr.hpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/include/oup/observable_unique_ptr.hpp b/include/oup/observable_unique_ptr.hpp index 0c9bf55..0f6e5f6 100644 --- a/include/oup/observable_unique_ptr.hpp +++ b/include/oup/observable_unique_ptr.hpp @@ -556,8 +556,8 @@ class basic_observable_ptr final { * \param manager The smart pointer to take ownership from * \param value The casted pointer value to take ownership of * \note After this smart pointer is created, the source - * pointer is set to null and looses ownership. The deleter - * is default constructed. + * pointer is set to null and looses ownership. Its deleter + * is moved into the new pointer. */ template< typename U, @@ -565,10 +565,14 @@ class basic_observable_ptr final { typename V, typename enable = std::enable_if_t>> basic_observable_ptr(basic_observable_ptr&& manager, V* value) noexcept : - basic_observable_ptr(value != nullptr ? manager.block : nullptr, value) { + basic_observable_ptr( + value != nullptr ? manager.block : nullptr, + value, + std::move(manager.ptr_deleter.deleter())) { - if (value == nullptr) { - manager.delete_object_if_exists_(); + if (value == nullptr && manager.ptr_deleter.pointer() != nullptr) { + manager.delete_object_( + manager.block, manager.ptr_deleter.pointer(), ptr_deleter.deleter()); } manager.block = nullptr; @@ -594,10 +598,10 @@ class basic_observable_ptr final { if (value == nullptr) { manager.delete_object_if_exists_(); + } else { + manager.block = nullptr; + manager.ptr_deleter.pointer() = nullptr; } - - manager.block = nullptr; - manager.ptr_deleter.pointer() = nullptr; } /** From b561cddef8f4b0e3149ae108678d748a274239b5 Mon Sep 17 00:00:00 2001 From: Corentin Schreiber Date: Mon, 26 Sep 2022 21:37:10 +0100 Subject: [PATCH 05/81] Start refactor of tests --- oup.sublime-project | 88 +- tests/CMakeLists.txt | 33 +- tests/catch2_and_overrides.hpp | 17 + tests/memory_tracker.cpp | 120 + tests/memory_tracker.hpp | 142 +- tests/runtime_tests.cpp | 4335 ++++++++--------- tests/runtime_tests_lifetime.cpp | 101 + tests/runtime_tests_make_observable.cpp | 103 + tests/runtime_tests_observer_assignment.cpp | 317 ++ tests/runtime_tests_observer_comparison.cpp | 111 + tests/runtime_tests_observer_construction.cpp | 221 + tests/runtime_tests_observer_misc.cpp | 7 + tests/runtime_tests_owner_assignment.cpp | 317 ++ tests/runtime_tests_owner_comparison.cpp | 111 + tests/runtime_tests_owner_construction.cpp | 409 ++ tests/runtime_tests_owner_misc.cpp | 407 ++ tests/size_benchmark.cpp | 1 - tests/tests_common2.cpp | 7 + tests/tests_common2.hpp | 466 ++ 19 files changed, 4971 insertions(+), 2342 deletions(-) create mode 100644 tests/catch2_and_overrides.hpp create mode 100644 tests/memory_tracker.cpp create mode 100644 tests/runtime_tests_lifetime.cpp create mode 100644 tests/runtime_tests_make_observable.cpp create mode 100644 tests/runtime_tests_observer_assignment.cpp create mode 100644 tests/runtime_tests_observer_comparison.cpp create mode 100644 tests/runtime_tests_observer_construction.cpp create mode 100644 tests/runtime_tests_observer_misc.cpp create mode 100644 tests/runtime_tests_owner_assignment.cpp create mode 100644 tests/runtime_tests_owner_comparison.cpp create mode 100644 tests/runtime_tests_owner_construction.cpp create mode 100644 tests/runtime_tests_owner_misc.cpp create mode 100644 tests/tests_common2.cpp create mode 100644 tests/tests_common2.hpp diff --git a/oup.sublime-project b/oup.sublime-project index ca50315..601f2e9 100644 --- a/oup.sublime-project +++ b/oup.sublime-project @@ -27,166 +27,170 @@ [ { "name": "clean", - "shell_cmd": "make -j12 clean" + "shell_cmd": "make -j12 clean", }, { "name": "install", - "shell_cmd": "make -j12 install" + "shell_cmd": "make -j12 install", }, { "name": "install/local", - "shell_cmd": "make -j12 install/local" + "shell_cmd": "make -j12 install/local", }, { "name": "install/strip", - "shell_cmd": "make -j12 install/strip" + "shell_cmd": "make -j12 install/strip", }, { "name": "list_install_components", - "shell_cmd": "make -j12 list_install_components" + "shell_cmd": "make -j12 list_install_components", }, { "name": "rebuild_cache", - "shell_cmd": "make -j12 rebuild_cache" + "shell_cmd": "make -j12 rebuild_cache", }, { "name": "test", - "shell_cmd": "make -j12 test" + "shell_cmd": "make -j12 test", }, { "name": "Continuous", - "shell_cmd": "make -j12 Continuous" + "shell_cmd": "make -j12 Continuous", }, { "name": "ContinuousBuild", - "shell_cmd": "make -j12 ContinuousBuild" + "shell_cmd": "make -j12 ContinuousBuild", }, { "name": "ContinuousConfigure", - "shell_cmd": "make -j12 ContinuousConfigure" + "shell_cmd": "make -j12 ContinuousConfigure", }, { "name": "ContinuousCoverage", - "shell_cmd": "make -j12 ContinuousCoverage" + "shell_cmd": "make -j12 ContinuousCoverage", }, { "name": "ContinuousMemCheck", - "shell_cmd": "make -j12 ContinuousMemCheck" + "shell_cmd": "make -j12 ContinuousMemCheck", }, { "name": "ContinuousStart", - "shell_cmd": "make -j12 ContinuousStart" + "shell_cmd": "make -j12 ContinuousStart", }, { "name": "ContinuousSubmit", - "shell_cmd": "make -j12 ContinuousSubmit" + "shell_cmd": "make -j12 ContinuousSubmit", }, { "name": "ContinuousTest", - "shell_cmd": "make -j12 ContinuousTest" + "shell_cmd": "make -j12 ContinuousTest", }, { "name": "ContinuousUpdate", - "shell_cmd": "make -j12 ContinuousUpdate" + "shell_cmd": "make -j12 ContinuousUpdate", }, { "name": "Experimental", - "shell_cmd": "make -j12 Experimental" + "shell_cmd": "make -j12 Experimental", }, { "name": "ExperimentalBuild", - "shell_cmd": "make -j12 ExperimentalBuild" + "shell_cmd": "make -j12 ExperimentalBuild", }, { "name": "ExperimentalConfigure", - "shell_cmd": "make -j12 ExperimentalConfigure" + "shell_cmd": "make -j12 ExperimentalConfigure", }, { "name": "ExperimentalCoverage", - "shell_cmd": "make -j12 ExperimentalCoverage" + "shell_cmd": "make -j12 ExperimentalCoverage", }, { "name": "ExperimentalMemCheck", - "shell_cmd": "make -j12 ExperimentalMemCheck" + "shell_cmd": "make -j12 ExperimentalMemCheck", }, { "name": "ExperimentalStart", - "shell_cmd": "make -j12 ExperimentalStart" + "shell_cmd": "make -j12 ExperimentalStart", }, { "name": "ExperimentalSubmit", - "shell_cmd": "make -j12 ExperimentalSubmit" + "shell_cmd": "make -j12 ExperimentalSubmit", }, { "name": "ExperimentalTest", - "shell_cmd": "make -j12 ExperimentalTest" + "shell_cmd": "make -j12 ExperimentalTest", }, { "name": "ExperimentalUpdate", - "shell_cmd": "make -j12 ExperimentalUpdate" + "shell_cmd": "make -j12 ExperimentalUpdate", }, { "name": "Nightly", - "shell_cmd": "make -j12 Nightly" + "shell_cmd": "make -j12 Nightly", }, { "name": "NightlyBuild", - "shell_cmd": "make -j12 NightlyBuild" + "shell_cmd": "make -j12 NightlyBuild", }, { "name": "NightlyConfigure", - "shell_cmd": "make -j12 NightlyConfigure" + "shell_cmd": "make -j12 NightlyConfigure", }, { "name": "NightlyCoverage", - "shell_cmd": "make -j12 NightlyCoverage" + "shell_cmd": "make -j12 NightlyCoverage", }, { "name": "NightlyMemCheck", - "shell_cmd": "make -j12 NightlyMemCheck" + "shell_cmd": "make -j12 NightlyMemCheck", }, { "name": "NightlyMemoryCheck", - "shell_cmd": "make -j12 NightlyMemoryCheck" + "shell_cmd": "make -j12 NightlyMemoryCheck", }, { "name": "NightlyStart", - "shell_cmd": "make -j12 NightlyStart" + "shell_cmd": "make -j12 NightlyStart", }, { "name": "NightlySubmit", - "shell_cmd": "make -j12 NightlySubmit" + "shell_cmd": "make -j12 NightlySubmit", }, { "name": "NightlyTest", - "shell_cmd": "make -j12 NightlyTest" + "shell_cmd": "make -j12 NightlyTest", }, { "name": "NightlyUpdate", - "shell_cmd": "make -j12 NightlyUpdate" + "shell_cmd": "make -j12 NightlyUpdate", }, { "name": "Catch2", - "shell_cmd": "make -j12 Catch2" + "shell_cmd": "make -j12 Catch2", }, { "name": "Catch2WithMain", - "shell_cmd": "make -j12 Catch2WithMain" + "shell_cmd": "make -j12 Catch2WithMain", }, { "name": "oup_size_benchmark", - "shell_cmd": "make -j12 oup_size_benchmark" + "shell_cmd": "make -j12 oup_size_benchmark", }, { "name": "oup_speed_benchmark", - "shell_cmd": "make -j12 oup_speed_benchmark" + "shell_cmd": "make -j12 oup_speed_benchmark", }, { "name": "oup_tests", - "shell_cmd": "make -j12 oup_tests" - } + "shell_cmd": "make -j12 oup_tests", + }, + { + "name": "oup_tests2", + "shell_cmd": "make -j12 oup_tests2" + }, ], - "working_dir": "$folder/build" + "working_dir": "$folder/build", } ], } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 74826fc..872731f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -18,23 +18,42 @@ include(FetchContent) FetchContent_Declare( Catch2 - GIT_REPOSITORY https://github.com/catchorg/Catch2.git - GIT_TAG 912df7df354fd6c814b5d7c45ac44f494a5fb5fe + GIT_REPOSITORY https://github.com/cschreib/Catch2.git + GIT_TAG 911eb82cf37f4017cb7f3260485e9d7351e18a4f ) FetchContent_MakeAvailable(Catch2) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${Catch2_SOURCE_DIR}/extras") -add_executable(oup_tests ${PROJECT_SOURCE_DIR}/tests/runtime_tests.cpp) +add_executable(oup_tests + ${PROJECT_SOURCE_DIR}/tests/memory_tracker.cpp + ${PROJECT_SOURCE_DIR}/tests/runtime_tests.cpp) target_link_libraries(oup_tests PRIVATE Catch2::Catch2WithMain) target_link_libraries(oup_tests PRIVATE oup::oup) add_platform_definitions(oup_tests) +add_executable(oup_tests2 + ${PROJECT_SOURCE_DIR}/tests/tests_common2.cpp + ${PROJECT_SOURCE_DIR}/tests/memory_tracker.cpp + ${PROJECT_SOURCE_DIR}/tests/runtime_tests_owner_misc.cpp + ${PROJECT_SOURCE_DIR}/tests/runtime_tests_owner_construction.cpp + ${PROJECT_SOURCE_DIR}/tests/runtime_tests_owner_assignment.cpp + ${PROJECT_SOURCE_DIR}/tests/runtime_tests_owner_comparison.cpp + ${PROJECT_SOURCE_DIR}/tests/runtime_tests_lifetime.cpp + ${PROJECT_SOURCE_DIR}/tests/runtime_tests_make_observable.cpp + ${PROJECT_SOURCE_DIR}/tests/runtime_tests_observer_misc.cpp + ${PROJECT_SOURCE_DIR}/tests/runtime_tests_observer_construction.cpp + ${PROJECT_SOURCE_DIR}/tests/runtime_tests_observer_assignment.cpp + ${PROJECT_SOURCE_DIR}/tests/runtime_tests_observer_comparison.cpp) +target_link_libraries(oup_tests2 PRIVATE Catch2::Catch2WithMain) +target_link_libraries(oup_tests2 PRIVATE oup::oup) +add_platform_definitions(oup_tests2) + include(CTest) include(Catch) -catch_discover_tests(oup_tests) +catch_discover_tests(oup_tests2) # Compile-time error tests set(CMAKE_TRY_COMPILE_TARGET_TYPE EXECUTABLE) @@ -55,7 +74,7 @@ function(run_compile_test TEST_NAME TEST_FILE EXPECTED) endif() endfunction() -run_compile_test("does_compilation_works" compile_test_good.cpp TRUE) +run_compile_test("does_compilation_work" compile_test_good.cpp TRUE) run_compile_test("is_copy_constructor_allowed" compile_test_copy_const.cpp FALSE) run_compile_test("is_copy_assignment_allowed" compile_test_copy_assign.cpp FALSE) run_compile_test("is_implicit_constructor_base_to_derived_allowed_acquire" compile_test_implicit_const_base_to_derived1.cpp FALSE) @@ -72,7 +91,9 @@ message(STATUS "Running compile-time tests ended.") # Benchmarks -add_executable(oup_size_benchmark ${PROJECT_SOURCE_DIR}/tests/size_benchmark.cpp) +add_executable(oup_size_benchmark + ${PROJECT_SOURCE_DIR}/tests/memory_tracker.cpp + ${PROJECT_SOURCE_DIR}/tests/size_benchmark.cpp) target_link_libraries(oup_size_benchmark PRIVATE oup::oup) add_platform_definitions(oup_size_benchmark) diff --git a/tests/catch2_and_overrides.hpp b/tests/catch2_and_overrides.hpp new file mode 100644 index 0000000..5a879aa --- /dev/null +++ b/tests/catch2_and_overrides.hpp @@ -0,0 +1,17 @@ +#include + +// Replace Catch2's REQUIRE_THROWS_AS, which allocates on Windows; +// this confuses our memory leak checks. +#undef REQUIRE_THROWS_AS +#define REQUIRE_THROWS_AS(EXPRESSION, EXCEPTION) \ + do { \ + try { \ + EXPRESSION; \ + FAIL("no exception thrown"); \ + } catch (const EXCEPTION&) { \ + } catch (const std::exception& e) { \ + FAIL(e.what()); \ + } catch (...) { \ + FAIL("unexpected exception thrown"); \ + } \ + } while (0) diff --git a/tests/memory_tracker.cpp b/tests/memory_tracker.cpp new file mode 100644 index 0000000..1d7aba1 --- /dev/null +++ b/tests/memory_tracker.cpp @@ -0,0 +1,120 @@ +#include "memory_tracker.hpp" + +void* allocations[max_allocations]; +void* allocations_array[max_allocations]; +std::size_t allocations_bytes[max_allocations]; +std::size_t num_allocations = 0u; +std::size_t size_allocations = 0u; +std::size_t double_delete = 0u; +bool memory_tracking = false; +bool force_next_allocation_failure = false; + +void* allocate(std::size_t size, bool array, std::align_val_t align) { + if (memory_tracking && num_allocations == max_allocations) { + throw std::bad_alloc(); + } + + if (force_next_allocation_failure) { + force_next_allocation_failure = false; + throw std::bad_alloc(); + } + + void* p = nullptr; + if (align == std::align_val_t{0}) { + p = std::malloc(size); + } else { +#if defined(OUP_COMPILER_MSVC) + p = _aligned_malloc(size, static_cast(align)); +#elif defined(OUP_COMPILER_EMSCRIPTEN) + p = aligned_alloc(static_cast(align), size); +#else + p = std::aligned_alloc(static_cast(align), size); +#endif + } + + if (!p) { + throw std::bad_alloc(); + } + + if (memory_tracking) { + if (array) { + allocations_array[num_allocations] = p; + } else { + allocations[num_allocations] = p; + } + + allocations_bytes[num_allocations] = size; + + ++num_allocations; + size_allocations += size; + } + + return p; +} + +void deallocate(void* p, bool array, std::align_val_t align [[maybe_unused]]) { + if (p == nullptr) { + return; + } + + if (memory_tracking) { + bool found = false; + void** allocations_type = array ? allocations_array : allocations; + for (std::size_t i = 0; i < num_allocations; ++i) { + if (allocations_type[i] == p) { + std::swap(allocations_type[i], allocations_type[num_allocations - 1]); + std::swap(allocations_bytes[i], allocations_bytes[num_allocations - 1]); + --num_allocations; + size_allocations -= allocations_bytes[num_allocations - 1]; + found = true; + break; + } + } + + if (!found) { + ++double_delete; + } + } + + if (align == std::align_val_t{0}) { + std::free(p); + } else { +#if defined(OUP_COMPILER_MSVC) + _aligned_free(p); +#else + std::free(p); +#endif + } +} + +void* operator new(std::size_t size) { + return allocate(size, false, std::align_val_t{0}); +} + +void* operator new[](size_t size) { + return allocate(size, true, std::align_val_t{0}); +} + +void* operator new(std::size_t size, std::align_val_t al) { + return allocate(size, false, al); +} + +void* operator new[](size_t size, std::align_val_t al) { + return allocate(size, true, al); +} + +void operator delete(void* p) noexcept { + deallocate(p, false, std::align_val_t{0}); +} + +void operator delete[](void* p) noexcept { + deallocate(p, true, std::align_val_t{0}); +} + +void operator delete(void* p, std::align_val_t al) noexcept { + deallocate(p, false, al); +} + +void operator delete[](void* p, std::align_val_t al) noexcept { + deallocate(p, true, al); +} diff --git a/tests/memory_tracker.hpp b/tests/memory_tracker.hpp index 84c9904..2f30d93 100644 --- a/tests/memory_tracker.hpp +++ b/tests/memory_tracker.hpp @@ -3,145 +3,49 @@ // Allocation tracker, to catch memory leaks and double delete constexpr std::size_t max_allocations = 20'000; -void* allocations[max_allocations]; -void* allocations_array[max_allocations]; -std::size_t allocations_bytes[max_allocations]; -std::size_t num_allocations = 0u; -std::size_t size_allocations = 0u; -std::size_t double_delete = 0u; -bool memory_tracking = false; -bool force_next_allocation_failure = false; +extern void* allocations[max_allocations]; +extern void* allocations_array[max_allocations]; +extern std::size_t allocations_bytes[max_allocations]; +extern std::size_t num_allocations; +extern std::size_t size_allocations; +extern std::size_t double_delete; +extern bool memory_tracking; +extern bool force_next_allocation_failure; -#if defined(CHECK_MEMORY_LEAKS) -void* allocate(std::size_t size, bool array, std::align_val_t align) { - if (memory_tracking && num_allocations == max_allocations) { - throw std::bad_alloc(); - } - - if (force_next_allocation_failure) { - force_next_allocation_failure = false; - throw std::bad_alloc(); - } - - void* p = nullptr; - if (align == std::align_val_t{0}) { - p = std::malloc(size); - } else { -# if defined(OUP_COMPILER_MSVC) - p = _aligned_malloc(size, static_cast(align)); -# elif defined(OUP_COMPILER_EMSCRIPTEN) - p = aligned_alloc(static_cast(align), size); -# else - p = std::aligned_alloc(static_cast(align), size); -# endif - } - - if (!p) { - throw std::bad_alloc(); - } - - if (memory_tracking) { - if (array) { - allocations_array[num_allocations] = p; - } else { - allocations[num_allocations] = p; - } - - allocations_bytes[num_allocations] = size; - - ++num_allocations; - size_allocations += size; - } - - return p; -} - -void deallocate(void* p, bool array, std::align_val_t align [[maybe_unused]]) { - if (p == nullptr) { - return; - } - - if (memory_tracking) { - bool found = false; - void** allocations_type = array ? allocations_array : allocations; - for (std::size_t i = 0; i < num_allocations; ++i) { - if (allocations_type[i] == p) { - std::swap(allocations_type[i], allocations_type[num_allocations - 1]); - std::swap(allocations_bytes[i], allocations_bytes[num_allocations - 1]); - --num_allocations; - size_allocations -= allocations_bytes[num_allocations - 1]; - found = true; - break; - } - } - - if (!found) { - ++double_delete; - } - } - - if (align == std::align_val_t{0}) { - std::free(p); - } else { -# if defined(OUP_COMPILER_MSVC) - _aligned_free(p); -# else - std::free(p); -# endif - } -} - -void* operator new(std::size_t size) { - return allocate(size, false, std::align_val_t{0}); -} +void* operator new(std::size_t size); -void* operator new[](size_t size) { - return allocate(size, true, std::align_val_t{0}); -} +void* operator new[](size_t size); -void* operator new(std::size_t size, std::align_val_t al) { - return allocate(size, false, al); -} +void* operator new(std::size_t size, std::align_val_t al); -void* operator new[](size_t size, std::align_val_t al) { - return allocate(size, true, al); -} +void* operator new[](size_t size, std::align_val_t al); -void operator delete(void* p) noexcept { - deallocate(p, false, std::align_val_t{0}); -} +void operator delete(void* p) noexcept; -void operator delete[](void* p) noexcept { - deallocate(p, true, std::align_val_t{0}); -} +void operator delete[](void* p) noexcept; -void operator delete(void* p, std::align_val_t al) noexcept { - deallocate(p, false, al); -} +void operator delete(void* p, std::align_val_t al) noexcept; -void operator delete[](void* p, std::align_val_t al) noexcept { - deallocate(p, true, al); -} -#endif +void operator delete[](void* p, std::align_val_t al) noexcept; struct memory_tracker { std::size_t initial_allocations; std::size_t initial_double_delete; memory_tracker() noexcept : - initial_allocations(num_allocations), initial_double_delete(double_delete) { - memory_tracking = true; + initial_allocations(::num_allocations), initial_double_delete(::double_delete) { + ::memory_tracking = true; } ~memory_tracker() noexcept { - memory_tracking = false; + ::memory_tracking = false; } - std::size_t leaks() const { - return num_allocations - initial_allocations; + std::size_t allocated() const { + return ::num_allocations - initial_allocations; } - std::size_t double_del() const { - return double_delete - initial_double_delete; + std::size_t double_delete() const { + return ::double_delete - initial_double_delete; } }; diff --git a/tests/runtime_tests.cpp b/tests/runtime_tests.cpp index 4cb6c30..a8def7c 100644 --- a/tests/runtime_tests.cpp +++ b/tests/runtime_tests.cpp @@ -1,1925 +1,1912 @@ -#include "tests_common.hpp" -#define CHECK_MEMORY_LEAKS +#include "catch2_and_overrides.hpp" #include "memory_tracker.hpp" +#include "tests_common.hpp" -#include -#include - -// Replace Catch2's REQUIRE_THROWS_AS, which allocates on Windows; -// this confuses our memory leak checks. -#undef REQUIRE_THROWS_AS -#define REQUIRE_THROWS_AS(EXPRESSION, EXCEPTION) \ - do { \ - try { \ - EXPRESSION; \ - FAIL("no exception thrown"); \ - } catch (const EXCEPTION&) { \ - } catch (const std::exception& e) { \ - FAIL(e.what()); \ - } catch (...) { \ - FAIL("unexpected exception thrown"); \ - } \ - } while (0) - -TEST_CASE("owner size", "[owner_size]") { - REQUIRE(sizeof(test_ptr) == 2 * sizeof(void*)); -} - -TEST_CASE("owner size sealed", "[owner_size]") { - REQUIRE(sizeof(test_sptr) == 2 * sizeof(void*)); -} - -TEST_CASE("owner default constructor", "[owner_construction]") { - memory_tracker mem_track; - - { - test_ptr ptr; - REQUIRE(instances == 0); - REQUIRE(ptr.get() == nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner default constructor sealed", "[owner_construction]") { - memory_tracker mem_track; - - { - test_sptr ptr; - REQUIRE(instances == 0); - REQUIRE(ptr.get() == nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner default constructor with deleter", "[owner_construction]") { - memory_tracker mem_track; - - { - test_ptr_with_deleter ptr; - REQUIRE(instances == 0); - REQUIRE(instances_deleter == 1); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr.get_deleter().state_ == 0); - } - - REQUIRE(instances == 0); - REQUIRE(instances_deleter == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner nullptr constructor", "[owner_construction]") { - memory_tracker mem_track; - - { - test_ptr ptr{nullptr}; - REQUIRE(instances == 0); - REQUIRE(ptr.get() == nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner nullptr constructor sealed", "[owner_construction]") { - memory_tracker mem_track; - - { - test_sptr ptr{nullptr}; - REQUIRE(instances == 0); - REQUIRE(ptr.get() == nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner nullptr constructor with deleter", "[owner_construction]") { - memory_tracker mem_track; - - { - test_ptr_with_deleter ptr{nullptr, test_deleter{42}}; - REQUIRE(instances == 0); - REQUIRE(instances_deleter == 1); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr.get_deleter().state_ == 42); - } - - REQUIRE(instances == 0); - REQUIRE(instances_deleter == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner move constructor", "[owner_construction]") { - memory_tracker mem_track; - - { - test_ptr ptr_orig(new test_object); - { - test_ptr ptr(std::move(ptr_orig)); - REQUIRE(instances == 1); - REQUIRE(ptr.get() != nullptr); - } - - REQUIRE(instances == 0); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner move constructor sealed", "[owner_construction]") { - memory_tracker mem_track; - - { - test_sptr ptr_orig = oup::make_observable_sealed(); - { - test_sptr ptr(std::move(ptr_orig)); - REQUIRE(instances == 1); - REQUIRE(ptr.get() != nullptr); - } - - REQUIRE(instances == 0); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner move constructor with deleter", "[owner_construction]") { - memory_tracker mem_track; - - { - test_ptr_with_deleter ptr_orig(new test_object, test_deleter{42}); - { - test_ptr_with_deleter ptr(std::move(ptr_orig)); - REQUIRE(instances == 1); - REQUIRE(instances_deleter == 2); - REQUIRE(ptr.get() != nullptr); - REQUIRE(ptr.get_deleter().state_ == 42); - } - - REQUIRE(instances == 0); - REQUIRE(instances_deleter == 1); - } - - REQUIRE(instances == 0); - REQUIRE(instances_deleter == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner acquiring constructor", "[owner_construction]") { - memory_tracker mem_track; - - { - test_ptr ptr{new test_object}; - REQUIRE(instances == 1); - REQUIRE(ptr.get() != nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner acquiring constructor bad alloc", "[owner_construction]") { - memory_tracker mem_track; - - { - test_object* raw_ptr = new test_object; - try { - force_next_allocation_failure = true; - test_ptr{raw_ptr}; - } catch (...) { - } - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner acquiring constructor with deleter", "[owner_construction]") { - memory_tracker mem_track; - - { - test_ptr_with_deleter ptr{new test_object, test_deleter{42}}; - REQUIRE(instances == 1); - REQUIRE(instances_deleter == 1); - REQUIRE(ptr.get() != nullptr); - REQUIRE(ptr.get_deleter().state_ == 42); - } - - REQUIRE(instances == 0); - REQUIRE(instances_deleter == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner acquiring constructor with deleter bad alloc", "[owner_construction]") { - memory_tracker mem_track; - - { - test_object* raw_ptr = new test_object; - try { - force_next_allocation_failure = true; - test_ptr_with_deleter{raw_ptr, test_deleter{42}}; - } catch (...) { - } - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner acquiring constructor null", "[owner_construction]") { - memory_tracker mem_track; - - { - test_ptr ptr{static_cast(nullptr)}; - REQUIRE(instances == 0); - REQUIRE(ptr.get() == nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner acquiring constructor null with deleter", "[owner_construction]") { - memory_tracker mem_track; - - { - test_ptr_with_deleter ptr{static_cast(nullptr), test_deleter{42}}; - REQUIRE(instances == 0); - REQUIRE(instances_deleter == 1); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr.get_deleter().state_ == 42); - } - - REQUIRE(instances == 0); - REQUIRE(instances_deleter == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner implicit conversion constructor", "[owner_construction]") { - memory_tracker mem_track; - - { - test_ptr_derived ptr_orig{new test_object_derived}; - { - test_ptr ptr(std::move(ptr_orig)); - REQUIRE(instances == 1); - REQUIRE(instances_derived == 1); - REQUIRE(ptr.get() != nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(instances_derived == 0); - } - - REQUIRE(instances == 0); - REQUIRE(instances_derived == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner implicit conversion constructor sealed", "[owner_construction]") { - memory_tracker mem_track; - - { - test_sptr_derived ptr_orig = oup::make_observable_sealed(); - { - test_sptr ptr(std::move(ptr_orig)); - REQUIRE(instances == 1); - REQUIRE(instances_derived == 1); - REQUIRE(ptr.get() != nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(instances_derived == 0); - } - - REQUIRE(instances == 0); - REQUIRE(instances_derived == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner implicit conversion constructor with deleter", "[owner_construction]") { - memory_tracker mem_track; - - { - test_ptr_derived_with_deleter ptr_orig{new test_object_derived, test_deleter{42}}; - { - test_ptr_with_deleter ptr(std::move(ptr_orig)); - REQUIRE(instances == 1); - REQUIRE(instances_derived == 1); - REQUIRE(instances_deleter == 2); - REQUIRE(ptr.get() != nullptr); - REQUIRE(ptr.get_deleter().state_ == 42); - } - - REQUIRE(instances == 0); - REQUIRE(instances_derived == 0); - REQUIRE(instances_deleter == 1); - } - - REQUIRE(instances == 0); - REQUIRE(instances_derived == 0); - REQUIRE(instances_deleter == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner explicit conversion constructor", "[owner_construction]") { - memory_tracker mem_track; - - { - test_ptr ptr_orig{new test_object_derived}; - { - test_ptr_derived ptr( - std::move(ptr_orig), dynamic_cast(ptr_orig.get())); - REQUIRE(instances == 1); - REQUIRE(instances_derived == 1); - REQUIRE(ptr.get() != nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(instances_derived == 0); - } - - REQUIRE(instances == 0); - REQUIRE(instances_derived == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner explicit conversion constructor sealed", "[owner_construction]") { - memory_tracker mem_track; - - { - test_sptr ptr_orig = oup::make_observable_sealed(); - { - test_sptr_derived ptr( - std::move(ptr_orig), dynamic_cast(ptr_orig.get())); - REQUIRE(instances == 1); - REQUIRE(instances_derived == 1); - REQUIRE(ptr.get() != nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(instances_derived == 0); - } - - REQUIRE(instances == 0); - REQUIRE(instances_derived == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner explicit conversion constructor with default deleter", "[owner_construction]") { - memory_tracker mem_track; - - { - test_ptr_with_deleter ptr_orig{new test_object_derived, test_deleter{42}}; - { - test_ptr_derived_with_deleter ptr( - std::move(ptr_orig), dynamic_cast(ptr_orig.get())); - REQUIRE(instances == 1); - REQUIRE(instances_derived == 1); - REQUIRE(instances_deleter == 2); - REQUIRE(ptr.get() != nullptr); - REQUIRE(ptr.get_deleter().state_ == 0); - } - - REQUIRE(instances == 0); - REQUIRE(instances_derived == 0); - REQUIRE(instances_deleter == 1); - } - - REQUIRE(instances == 0); - REQUIRE(instances_derived == 0); - REQUIRE(instances_deleter == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner explicit conversion constructor with custom deleter", "[owner_construction]") { - memory_tracker mem_track; - - { - test_ptr_with_deleter ptr_orig{new test_object_derived, test_deleter{42}}; - { - test_ptr_derived_with_deleter ptr( - std::move(ptr_orig), dynamic_cast(ptr_orig.get()), - test_deleter{43}); - REQUIRE(instances == 1); - REQUIRE(instances_derived == 1); - REQUIRE(instances_deleter == 2); - REQUIRE(ptr.get() != nullptr); - REQUIRE(ptr.get_deleter().state_ == 43); - } - - REQUIRE(instances == 0); - REQUIRE(instances_derived == 0); - REQUIRE(instances_deleter == 1); - } - - REQUIRE(instances == 0); - REQUIRE(instances_derived == 0); - REQUIRE(instances_deleter == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner explicit conversion constructor with nullptr", "[owner_construction]") { - memory_tracker mem_track; - - { - test_ptr ptr_orig{new test_object_derived}; - { - test_ptr_derived ptr(std::move(ptr_orig), static_cast(nullptr)); - REQUIRE(instances == 0); - REQUIRE(instances_derived == 0); - REQUIRE(ptr.get() == nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(instances_derived == 0); - } - - REQUIRE(instances == 0); - REQUIRE(instances_derived == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner explicit conversion constructor with nullptr sealed", "[owner_construction]") { - memory_tracker mem_track; - - { - test_sptr ptr_orig = oup::make_observable_sealed(); - { - test_sptr_derived ptr(std::move(ptr_orig), static_cast(nullptr)); - REQUIRE(instances == 0); - REQUIRE(instances_derived == 0); - REQUIRE(ptr.get() == nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(instances_derived == 0); - } - - REQUIRE(instances == 0); - REQUIRE(instances_derived == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE( - "owner explicit conversion constructor with nullptr with custom deleter", - "[owner_construction]") { - memory_tracker mem_track; - - { - test_ptr_with_deleter ptr_orig{new test_object_derived, test_deleter{42}}; - { - test_ptr_derived_with_deleter ptr( - std::move(ptr_orig), static_cast(nullptr), test_deleter{43}); - REQUIRE(instances == 0); - REQUIRE(instances_derived == 0); - REQUIRE(instances_deleter == 2); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr.get_deleter().state_ == 43); - } - - REQUIRE(instances == 0); - REQUIRE(instances_derived == 0); - REQUIRE(instances_deleter == 1); - } - - REQUIRE(instances == 0); - REQUIRE(instances_derived == 0); - REQUIRE(instances_deleter == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner move assignment operator valid to empty", "[owner_assignment]") { - memory_tracker mem_track; - - { - test_ptr ptr_orig(new test_object); - { - test_ptr ptr; - ptr = std::move(ptr_orig); - REQUIRE(instances == 1); - REQUIRE(ptr.get() != nullptr); - } - - REQUIRE(instances == 0); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner move assignment operator valid to empty sealed", "[owner_assignment]") { - memory_tracker mem_track; - - { - test_sptr ptr_orig = oup::make_observable_sealed(); - { - test_sptr ptr; - ptr = std::move(ptr_orig); - REQUIRE(instances == 1); - REQUIRE(ptr.get() != nullptr); - } - - REQUIRE(instances == 0); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner move assignment operator valid to empty with deleter", "[owner_assignment]") { - memory_tracker mem_track; - - { - test_ptr_with_deleter ptr_orig(new test_object, test_deleter{42}); - { - test_ptr_with_deleter ptr; - ptr = std::move(ptr_orig); - REQUIRE(instances == 1); - REQUIRE(instances_deleter == 2); - REQUIRE(ptr.get() != nullptr); - REQUIRE(ptr.get_deleter().state_ == 42); - } - - REQUIRE(instances == 0); - REQUIRE(instances_deleter == 1); - } - - REQUIRE(instances == 0); - REQUIRE(instances_deleter == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner move assignment operator empty to valid", "[owner_assignment]") { - memory_tracker mem_track; - - { - test_ptr ptr_orig; - { - test_ptr ptr(new test_object); - ptr = std::move(ptr_orig); - REQUIRE(instances == 0); - REQUIRE(ptr.get() == nullptr); - } - - REQUIRE(instances == 0); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner move assignment operator empty to valid sealed", "[owner_assignment]") { - memory_tracker mem_track; - - { - test_sptr ptr_orig; - { - test_sptr ptr = oup::make_observable_sealed(); - ptr = std::move(ptr_orig); - REQUIRE(instances == 0); - REQUIRE(ptr.get() == nullptr); - } - - REQUIRE(instances == 0); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner move assignment operator empty to valid with deleter", "[owner_assignment]") { - memory_tracker mem_track; - - { - test_ptr_with_deleter ptr_orig; - { - test_ptr_with_deleter ptr(new test_object, test_deleter{42}); - ptr = std::move(ptr_orig); - REQUIRE(instances == 0); - REQUIRE(instances_deleter == 2); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr.get_deleter().state_ == 0); - } - - REQUIRE(instances == 0); - REQUIRE(instances_deleter == 1); - } - - REQUIRE(instances == 0); - REQUIRE(instances_deleter == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner move assignment operator empty to empty", "[owner_assignment]") { - memory_tracker mem_track; - - { - test_ptr ptr_orig; - { - test_ptr ptr; - ptr = std::move(ptr_orig); - REQUIRE(instances == 0); - REQUIRE(ptr.get() == nullptr); - } - - REQUIRE(instances == 0); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner move assignment operator empty to empty sealed", "[owner_assignment]") { - memory_tracker mem_track; - - { - test_sptr ptr_orig; - { - test_sptr ptr; - ptr = std::move(ptr_orig); - REQUIRE(instances == 0); - REQUIRE(ptr.get() == nullptr); - } - - REQUIRE(instances == 0); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner move assignment operator empty to empty with deleter", "[owner_assignment]") { - memory_tracker mem_track; - - { - test_ptr_with_deleter ptr_orig; - { - test_ptr_with_deleter ptr; - ptr = std::move(ptr_orig); - REQUIRE(instances == 0); - REQUIRE(instances_deleter == 2); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr.get_deleter().state_ == 0); - } - - REQUIRE(instances == 0); - REQUIRE(instances_deleter == 1); - } - - REQUIRE(instances == 0); - REQUIRE(instances_deleter == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner move assignment operator valid to valid", "[owner_assignment]") { - memory_tracker mem_track; - - { - test_ptr ptr_orig(new test_object); - { - test_ptr ptr(new test_object); - ptr = std::move(ptr_orig); - REQUIRE(instances == 1); - REQUIRE(ptr.get() != nullptr); - } - - REQUIRE(instances == 0); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner move assignment operator valid to valid sealed", "[owner_assignment]") { - memory_tracker mem_track; - - { - test_sptr ptr_orig = oup::make_observable_sealed(); - { - test_sptr ptr = oup::make_observable_sealed(); - ptr = std::move(ptr_orig); - REQUIRE(instances == 1); - REQUIRE(ptr.get() != nullptr); - } - - REQUIRE(instances == 0); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner move assignment operator valid to valid with deleter", "[owner_assignment]") { - memory_tracker mem_track; - - { - test_ptr_with_deleter ptr_orig(new test_object, test_deleter{42}); - { - test_ptr_with_deleter ptr(new test_object, test_deleter{43}); - ptr = std::move(ptr_orig); - REQUIRE(instances == 1); - REQUIRE(instances_deleter == 2); - REQUIRE(ptr.get() != nullptr); - REQUIRE(ptr.get_deleter().state_ == 42); - } - - REQUIRE(instances == 0); - REQUIRE(instances_deleter == 1); - } - - REQUIRE(instances == 0); - REQUIRE(instances_deleter == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner move assignment operator self to self", "[owner_assignment]") { - memory_tracker mem_track; - - { - test_ptr ptr(new test_object); - ptr = std::move(ptr); - REQUIRE(instances == 0); - REQUIRE(ptr.get() == nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner move assignment operator self to self sealed", "[owner_assignment]") { - memory_tracker mem_track; - - { - test_sptr ptr = oup::make_observable_sealed(); - ptr = std::move(ptr); - REQUIRE(instances == 0); - REQUIRE(ptr.get() == nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner move assignment operator self to self with deleter", "[owner_assignment]") { - memory_tracker mem_track; - - { - test_ptr_with_deleter ptr(new test_object, test_deleter{42}); - ptr = std::move(ptr); - REQUIRE(instances == 0); - REQUIRE(ptr.get() == nullptr); - REQUIRE(instances_deleter == 1); - REQUIRE(ptr.get_deleter().state_ == 0); - } - - REQUIRE(instances == 0); - REQUIRE(instances_deleter == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner move assignment operator self to self empty", "[owner_assignment]") { - memory_tracker mem_track; - - { - test_ptr ptr; - ptr = std::move(ptr); - REQUIRE(instances == 0); - REQUIRE(ptr.get() == nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner move assignment operator self to self empty sealed", "[owner_assignment]") { - memory_tracker mem_track; - - { - test_sptr ptr; - ptr = std::move(ptr); - REQUIRE(instances == 0); - REQUIRE(ptr.get() == nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner move assignment operator self to self empty with deleter", "[owner_assignment]") { - memory_tracker mem_track; - - { - test_ptr_with_deleter ptr; - ptr = std::move(ptr); - REQUIRE(instances == 0); - REQUIRE(ptr.get() == nullptr); - REQUIRE(instances_deleter == 1); - REQUIRE(ptr.get_deleter().state_ == 0); - } - - REQUIRE(instances == 0); - REQUIRE(instances_deleter == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner comparison valid ptr vs nullptr", "[owner_comparison]") { - memory_tracker mem_track; - - { - test_ptr ptr(new test_object); - REQUIRE(ptr != nullptr); - REQUIRE(!(ptr == nullptr)); - REQUIRE(nullptr != ptr); - REQUIRE(!(nullptr == ptr)); - } - - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner comparison valid ptr vs nullptr sealed", "[owner_comparison]") { - memory_tracker mem_track; - - { - test_sptr ptr = oup::make_observable_sealed(); - REQUIRE(ptr != nullptr); - REQUIRE(!(ptr == nullptr)); - REQUIRE(nullptr != ptr); - REQUIRE(!(nullptr == ptr)); - } - - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner comparison valid ptr vs nullptr with deleter", "[owner_comparison]") { - memory_tracker mem_track; - - { - test_ptr_with_deleter ptr(new test_object, test_deleter{42}); - REQUIRE(ptr != nullptr); - REQUIRE(!(ptr == nullptr)); - REQUIRE(nullptr != ptr); - REQUIRE(!(nullptr == ptr)); - } - - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner comparison invalid ptr vs nullptr", "[owner_comparison]") { - memory_tracker mem_track; - - { - test_ptr ptr; - REQUIRE(ptr == nullptr); - REQUIRE(!(ptr != nullptr)); - REQUIRE(nullptr == ptr); - REQUIRE(!(nullptr != ptr)); - } - - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner comparison invalid ptr vs nullptr sealed", "[owner_comparison]") { - memory_tracker mem_track; - - { - test_sptr ptr; - REQUIRE(ptr == nullptr); - REQUIRE(!(ptr != nullptr)); - REQUIRE(nullptr == ptr); - REQUIRE(!(nullptr != ptr)); - } - - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner comparison invalid ptr vs nullptr with deleter", "[owner_comparison]") { - memory_tracker mem_track; - - { - test_ptr_with_deleter ptr; - REQUIRE(ptr == nullptr); - REQUIRE(!(ptr != nullptr)); - REQUIRE(nullptr == ptr); - REQUIRE(!(nullptr != ptr)); - } - - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner comparison invalid ptr vs nullptr with deleter explicit", "[owner_comparison]") { - memory_tracker mem_track; - - { - test_ptr_with_deleter ptr(nullptr, test_deleter{42}); - REQUIRE(ptr == nullptr); - REQUIRE(!(ptr != nullptr)); - REQUIRE(nullptr == ptr); - REQUIRE(!(nullptr != ptr)); - } - - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner comparison invalid ptr vs invalid ptr", "[owner_comparison]") { - memory_tracker mem_track; - - { - test_ptr ptr1; - test_ptr ptr2; - REQUIRE(ptr1 == ptr2); - REQUIRE(!(ptr1 != ptr2)); - } - - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner comparison invalid ptr vs invalid ptr sealed", "[owner_comparison]") { - memory_tracker mem_track; - - { - test_sptr ptr1; - test_sptr ptr2; - REQUIRE(ptr1 == ptr2); - REQUIRE(!(ptr1 != ptr2)); - } - - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner comparison invalid ptr vs invalid ptr with deleter", "[owner_comparison]") { - memory_tracker mem_track; - - { - test_ptr_with_deleter ptr1; - test_ptr_with_deleter ptr2; - REQUIRE(ptr1 == ptr2); - REQUIRE(!(ptr1 != ptr2)); - } - - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE( - "owner comparison invalid ptr vs invalid ptr with deleter explicit", "[owner_comparison]") { - memory_tracker mem_track; - - { - test_ptr_with_deleter ptr1; - test_ptr_with_deleter ptr2(nullptr, test_deleter{42}); - REQUIRE(ptr1 == ptr2); - REQUIRE(ptr2 == ptr1); - REQUIRE(!(ptr2 != ptr1)); - REQUIRE(!(ptr2 != ptr1)); - } - - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE( - "owner comparison invalid ptr vs invalid ptr with both deleter explicit", - "[owner_comparison]") { - memory_tracker mem_track; - - { - test_ptr_with_deleter ptr1(nullptr, test_deleter{43}); - test_ptr_with_deleter ptr2(nullptr, test_deleter{42}); - REQUIRE(ptr1 == ptr2); - REQUIRE(ptr2 == ptr1); - REQUIRE(!(ptr2 != ptr1)); - REQUIRE(!(ptr2 != ptr1)); - } - - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner comparison invalid ptr vs valid ptr", "[owner_comparison]") { - memory_tracker mem_track; - - { - test_ptr ptr1; - test_ptr ptr2(new test_object); - REQUIRE(ptr1 != ptr2); - REQUIRE(!(ptr1 == ptr2)); - REQUIRE(ptr2 != ptr1); - REQUIRE(!(ptr2 == ptr1)); - } - - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner comparison invalid ptr vs valid ptr sealed", "[owner_comparison]") { - memory_tracker mem_track; - - { - test_sptr ptr1; - test_sptr ptr2 = oup::make_observable_sealed(); - REQUIRE(ptr1 != ptr2); - REQUIRE(!(ptr1 == ptr2)); - REQUIRE(ptr2 != ptr1); - REQUIRE(!(ptr2 == ptr1)); - } - - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner comparison invalid ptr vs valid ptr with deleter", "[owner_comparison]") { - memory_tracker mem_track; - - { - test_ptr_with_deleter ptr1; - test_ptr_with_deleter ptr2(new test_object, test_deleter{42}); - REQUIRE(ptr1 != ptr2); - REQUIRE(!(ptr1 == ptr2)); - REQUIRE(ptr2 != ptr1); - REQUIRE(!(ptr2 == ptr1)); - } - - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner comparison invalid ptr vs valid ptr with deleter explicit", "[owner_comparison]") { - memory_tracker mem_track; - - { - test_ptr_with_deleter ptr1(nullptr, test_deleter{43}); - test_ptr_with_deleter ptr2(new test_object, test_deleter{42}); - REQUIRE(ptr1 != ptr2); - REQUIRE(!(ptr1 == ptr2)); - REQUIRE(ptr2 != ptr1); - REQUIRE(!(ptr2 == ptr1)); - } - - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner comparison valid ptr vs valid ptr", "[owner_comparison]") { - memory_tracker mem_track; - - { - test_ptr ptr1(new test_object); - test_ptr ptr2(new test_object); - REQUIRE(ptr1 != ptr2); - REQUIRE(!(ptr1 == ptr2)); - REQUIRE(ptr2 != ptr1); - REQUIRE(!(ptr2 == ptr1)); - } - - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner comparison valid ptr vs valid ptr sealed", "[owner_comparison]") { - memory_tracker mem_track; - - { - test_sptr ptr1 = oup::make_observable_sealed(); - test_sptr ptr2 = oup::make_observable_sealed(); - REQUIRE(ptr1 != ptr2); - REQUIRE(!(ptr1 == ptr2)); - REQUIRE(ptr2 != ptr1); - REQUIRE(!(ptr2 == ptr1)); - } - - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner comparison valid ptr vs valid ptr with deleter", "[owner_comparison]") { - memory_tracker mem_track; - - { - test_ptr_with_deleter ptr1(new test_object, test_deleter{43}); - test_ptr_with_deleter ptr2(new test_object, test_deleter{42}); - REQUIRE(ptr1 != ptr2); - REQUIRE(!(ptr1 == ptr2)); - REQUIRE(ptr2 != ptr1); - REQUIRE(!(ptr2 == ptr1)); - } - - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner reset to null", "[owner_utility]") { - memory_tracker mem_track; - - { - test_ptr ptr(new test_object); - ptr.reset(); - REQUIRE(instances == 0); - REQUIRE(ptr.get() == nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner reset to null sealed", "[owner_utility]") { - memory_tracker mem_track; - - { - test_sptr ptr = oup::make_observable_sealed(); - ptr.reset(); - REQUIRE(instances == 0); - REQUIRE(ptr.get() == nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner reset to null with deleter", "[owner_utility]") { - memory_tracker mem_track; - - { - test_ptr_with_deleter ptr(new test_object, test_deleter{42}); - ptr.reset(); - REQUIRE(instances == 0); - REQUIRE(instances_deleter == 1); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr.get_deleter().state_ == 42); - } - - REQUIRE(instances == 0); - REQUIRE(instances_deleter == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner reset to new", "[owner_utility]") { - memory_tracker mem_track; - - { - test_ptr ptr(new test_object); - ptr.reset(new test_object); - REQUIRE(instances == 1); - REQUIRE(ptr.get() != nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner reset to new bad alloc", "[owner_utility]") { - memory_tracker mem_track; - - { - test_object* raw_ptr1 = new test_object; - test_object* raw_ptr2 = new test_object; - test_ptr ptr(raw_ptr1); - try { - force_next_allocation_failure = true; - ptr.reset(raw_ptr2); - } catch (...) { - } - REQUIRE(instances == 1); - REQUIRE(ptr.get() == raw_ptr1); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner reset to new with deleter", "[owner_utility]") { - memory_tracker mem_track; - - { - test_ptr_with_deleter ptr(new test_object, test_deleter{42}); - ptr.reset(new test_object); - REQUIRE(instances == 1); - REQUIRE(instances_deleter == 1); - REQUIRE(ptr.get() != nullptr); - REQUIRE(ptr.get_deleter().state_ == 42); - } - - REQUIRE(instances == 0); - REQUIRE(instances_deleter == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner swap no instance", "[owner_utility]") { - memory_tracker mem_track; - - { - test_ptr ptr_orig; - test_ptr ptr; - ptr.swap(ptr_orig); - REQUIRE(instances == 0); - REQUIRE(ptr_orig.get() == nullptr); - REQUIRE(ptr.get() == nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner swap no instance sealed", "[owner_utility]") { - memory_tracker mem_track; - - { - test_sptr ptr_orig; - test_sptr ptr; - ptr.swap(ptr_orig); - REQUIRE(instances == 0); - REQUIRE(ptr_orig.get() == nullptr); - REQUIRE(ptr.get() == nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner swap no instance with deleter", "[owner_utility]") { - memory_tracker mem_track; - - { - test_ptr_with_deleter ptr_orig(nullptr, test_deleter{42}); - test_ptr_with_deleter ptr(nullptr, test_deleter{43}); - ptr.swap(ptr_orig); - REQUIRE(instances == 0); - REQUIRE(instances_deleter == 2); - REQUIRE(ptr_orig.get() == nullptr); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr.get_deleter().state_ == 42); - REQUIRE(ptr_orig.get_deleter().state_ == 43); - } - - REQUIRE(instances == 0); - REQUIRE(instances_deleter == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner swap one instance", "[owner_utility]") { - memory_tracker mem_track; - - { - test_ptr ptr_orig(new test_object); - test_ptr ptr; - ptr.swap(ptr_orig); - REQUIRE(instances == 1); - REQUIRE(ptr_orig.get() == nullptr); - REQUIRE(ptr.get() != nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner swap one instance sealed", "[owner_utility]") { - memory_tracker mem_track; - - { - test_sptr ptr_orig = oup::make_observable_sealed(); - test_sptr ptr; - ptr.swap(ptr_orig); - REQUIRE(instances == 1); - REQUIRE(ptr_orig.get() == nullptr); - REQUIRE(ptr.get() != nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner swap one instance with deleter", "[owner_utility]") { - memory_tracker mem_track; - - { - test_ptr_with_deleter ptr_orig(new test_object, test_deleter{42}); - test_ptr_with_deleter ptr(nullptr, test_deleter{43}); - ptr.swap(ptr_orig); - REQUIRE(instances == 1); - REQUIRE(instances_deleter == 2); - REQUIRE(ptr_orig.get() == nullptr); - REQUIRE(ptr.get() != nullptr); - REQUIRE(ptr.get_deleter().state_ == 42); - REQUIRE(ptr_orig.get_deleter().state_ == 43); - } - - REQUIRE(instances == 0); - REQUIRE(instances_deleter == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner swap two instances", "[owner_utility]") { - memory_tracker mem_track; - - { - test_ptr ptr_orig(new test_object); - test_object* ptr_orig_raw = ptr_orig.get(); - test_ptr ptr(new test_object); - test_object* ptr_raw = ptr.get(); - ptr.swap(ptr_orig); - REQUIRE(instances == 2); - REQUIRE(ptr_orig.get() == ptr_raw); - REQUIRE(ptr.get() == ptr_orig_raw); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner swap two instances sealed", "[owner_utility]") { - memory_tracker mem_track; - - { - test_sptr ptr_orig = oup::make_observable_sealed(); - test_object* ptr_orig_raw = ptr_orig.get(); - test_sptr ptr = oup::make_observable_sealed(); - test_object* ptr_raw = ptr.get(); - ptr.swap(ptr_orig); - REQUIRE(instances == 2); - REQUIRE(ptr_orig.get() == ptr_raw); - REQUIRE(ptr.get() == ptr_orig_raw); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner swap two instances with deleter", "[owner_utility]") { - memory_tracker mem_track; - - { - test_ptr_with_deleter ptr_orig(new test_object, test_deleter{42}); - test_object* ptr_orig_raw = ptr_orig.get(); - test_ptr_with_deleter ptr(new test_object, test_deleter{43}); - test_object* ptr_raw = ptr.get(); - ptr.swap(ptr_orig); - REQUIRE(instances == 2); - REQUIRE(instances_deleter == 2); - REQUIRE(ptr_orig.get() == ptr_raw); - REQUIRE(ptr.get() == ptr_orig_raw); - REQUIRE(ptr.get_deleter().state_ == 42); - REQUIRE(ptr_orig.get_deleter().state_ == 43); - } - - REQUIRE(instances == 0); - REQUIRE(instances_deleter == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner swap self", "[owner_utility]") { - memory_tracker mem_track; - - { - test_ptr ptr(new test_object); - ptr.swap(ptr); - REQUIRE(instances == 1); - REQUIRE(ptr.get() != nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner swap self sealed", "[owner_utility]") { - memory_tracker mem_track; - - { - test_sptr ptr = oup::make_observable_sealed(); - ptr.swap(ptr); - REQUIRE(instances == 1); - REQUIRE(ptr.get() != nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner swap self with deleter", "[owner_utility]") { - memory_tracker mem_track; - - { - test_ptr_with_deleter ptr(new test_object, test_deleter{43}); - ptr.swap(ptr); - REQUIRE(instances == 1); - REQUIRE(ptr.get() != nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(instances_deleter == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner dereference", "[owner_utility]") { - memory_tracker mem_track; - - { - test_ptr ptr(new test_object); - REQUIRE(ptr->state_ == 1337); - REQUIRE((*ptr).state_ == 1337); - } - - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner dereference sealed", "[owner_utility]") { - memory_tracker mem_track; - - { - test_sptr ptr = oup::make_observable_sealed(); - REQUIRE(ptr->state_ == 1337); - REQUIRE((*ptr).state_ == 1337); - } - - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner operator bool valid", "[owner_utility]") { - memory_tracker mem_track; - - { - test_ptr ptr(new test_object); - if (ptr) { - } else - FAIL("if (ptr) should have been true"); - } - - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner operator bool valid sealed", "[owner_utility]") { - memory_tracker mem_track; - - { - test_sptr ptr = oup::make_observable_sealed(); - if (ptr) { - } else - FAIL("if (ptr) should have been true"); - } - - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner operator bool invalid", "[owner_utility]") { - memory_tracker mem_track; - - { - test_ptr ptr; - if (ptr) - FAIL("if (ptr) should not have been true"); - } - - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner operator bool invalid sealed", "[owner_utility]") { - memory_tracker mem_track; - - { - test_sptr ptr; - if (ptr) - FAIL("if (ptr) should not have been true"); - } - - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner release valid", "[owner_utility]") { - memory_tracker mem_track; - - { - test_ptr ptr(new test_object); - test_object* ptr_raw = ptr.release(); - REQUIRE(ptr_raw != nullptr); - REQUIRE(ptr.get() == nullptr); - REQUIRE(instances == 1); - delete ptr_raw; - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner release valid with observer", "[owner_utility]") { - memory_tracker mem_track; - - { - test_optr optr; - { - test_ptr ptr(new test_object); - optr = ptr; - test_object* ptr_raw = ptr.release(); - REQUIRE(ptr_raw != nullptr); - REQUIRE(ptr.get() == nullptr); - REQUIRE(instances == 1); - delete ptr_raw; - } - - REQUIRE(optr.expired()); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner release valid from make_observable_unique", "[owner_utility]") { - memory_tracker mem_track; - - { - test_ptr ptr = oup::make_observable_unique(); - test_object* ptr_raw = ptr.release(); - REQUIRE(ptr_raw != nullptr); - REQUIRE(ptr.get() == nullptr); - REQUIRE(instances == 1); - delete ptr_raw; - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner release valid from make_observable_unique with observer", "[owner_utility]") { - memory_tracker mem_track; - - { - test_optr optr; - { - test_ptr ptr = oup::make_observable_unique(); - optr = ptr; - test_object* ptr_raw = ptr.release(); - REQUIRE(ptr_raw != nullptr); - REQUIRE(ptr.get() == nullptr); - REQUIRE(instances == 1); - delete ptr_raw; - } - - REQUIRE(optr.expired()); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner release valid with deleter", "[owner_utility]") { - memory_tracker mem_track; - - { - test_ptr_with_deleter ptr(new test_object, test_deleter{42}); - test_object* ptr_raw = ptr.release(); - REQUIRE(ptr_raw != nullptr); - REQUIRE(ptr.get() == nullptr); - REQUIRE(instances == 1); - REQUIRE(instances_deleter == 1); - REQUIRE(ptr.get_deleter().state_ == 42); - delete ptr_raw; - } - - REQUIRE(instances == 0); - REQUIRE(instances_deleter == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner release valid with deleter with observer", "[owner_utility]") { - memory_tracker mem_track; - - { - test_optr optr; - { - test_ptr_with_deleter ptr(new test_object, test_deleter{42}); - optr = ptr; - test_object* ptr_raw = ptr.release(); - REQUIRE(ptr_raw != nullptr); - REQUIRE(ptr.get() == nullptr); - REQUIRE(instances == 1); - REQUIRE(instances_deleter == 1); - REQUIRE(ptr.get_deleter().state_ == 42); - delete ptr_raw; - } - - REQUIRE(optr.expired()); - } - - REQUIRE(instances == 0); - REQUIRE(instances_deleter == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner release invalid", "[owner_utility]") { - memory_tracker mem_track; - - { - test_ptr ptr; - REQUIRE(ptr.release() == nullptr); - REQUIRE(instances == 0); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("owner release invalid with deleter", "[owner_utility]") { - memory_tracker mem_track; - - { - test_ptr_with_deleter ptr; - REQUIRE(ptr.release() == nullptr); - REQUIRE(instances == 0); - REQUIRE(instances_deleter == 1); - } - - REQUIRE(instances == 0); - REQUIRE(instances_deleter == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("make observable unique", "[make_observable_unique]") { - memory_tracker mem_track; - - { - test_ptr ptr = oup::make_observable_unique(); - REQUIRE(instances == 1); - REQUIRE(ptr.get() != nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("make observable unique throw in constructor", "[make_observable_unique]") { - memory_tracker mem_track; - - REQUIRE_THROWS_AS(oup::make_observable_unique(), throw_constructor); - - REQUIRE(instances_thrower == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("make observable non virtual unique throw in constructor", "[make_observable_unique]") { - memory_tracker mem_track; - - REQUIRE_THROWS_AS( - (oup::make_observable< - test_object_thrower_observer_from_this_non_virtual_unique, - unique_non_virtual_policy>()), - throw_constructor); - - REQUIRE(instances_thrower == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("make observable sealed", "[make_observable_sealed]") { - memory_tracker mem_track; - - { - test_sptr ptr = oup::make_observable_sealed(); - REQUIRE(instances == 1); - REQUIRE(ptr.get() != nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("make observable sealed throw in constructor", "[make_observable_sealed]") { - memory_tracker mem_track; - - REQUIRE_THROWS_AS(oup::make_observable_sealed(), throw_constructor); - - REQUIRE(instances_thrower == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("observer size", "[observer_size]") { - REQUIRE(sizeof(test_optr) == 2 * sizeof(void*)); -} - -TEST_CASE("observer default constructor", "[observer_construction]") { - memory_tracker mem_track; - - { - test_optr ptr; - REQUIRE(instances == 0); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr.expired() == true); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("observer nullptr constructor", "[observer_construction]") { - memory_tracker mem_track; - - { - test_optr ptr{nullptr}; - REQUIRE(instances == 0); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr.expired() == true); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("observer copy constructor", "[observer_construction]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner{new test_object}; - test_optr ptr_orig{ptr_owner}; - { - test_optr ptr(ptr_orig); - REQUIRE(instances == 1); - REQUIRE(ptr.get() != nullptr); - REQUIRE(ptr.expired() == false); - REQUIRE(ptr_orig.get() != nullptr); - REQUIRE(ptr_orig.expired() == false); - - ptr_owner.reset(); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr.expired() == true); - } - - REQUIRE(instances == 0); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("observer explicit conversion copy constructor ", "[observer_construction]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner{new test_object_derived}; - test_optr ptr_orig{ptr_owner}; - { - test_optr ptr{ptr_orig, static_cast(ptr_orig.get())}; - REQUIRE(instances == 1); - REQUIRE(ptr.get() == static_cast(ptr_owner.get())); - REQUIRE(ptr.expired() == false); - REQUIRE(ptr_orig.get() == ptr_owner.get()); - REQUIRE(ptr_orig.expired() == false); - - ptr_owner.reset(); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr.expired() == true); - } - - REQUIRE(instances == 0); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("observer explicit conversion copy constructor null pointer", "[observer_construction]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner{new test_object_derived}; - test_optr ptr_orig{ptr_owner}; - { - test_optr ptr{ptr_orig, static_cast(nullptr)}; - REQUIRE(instances == 1); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr.expired() == true); - REQUIRE(ptr_orig.get() == ptr_owner.get()); - REQUIRE(ptr_orig.expired() == false); - } - - REQUIRE(instances == 1); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} - -TEST_CASE("observer explicit conversion copy constructor subobject", "[observer_construction]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner{new test_object_derived}; - test_optr ptr_orig{ptr_owner}; - { - int_optr ptr{ptr_orig, &ptr_owner->state_}; - REQUIRE(instances == 1); - REQUIRE(ptr.get() == &ptr_owner->state_); - REQUIRE(ptr.expired() == false); - REQUIRE(ptr_orig.get() == ptr_owner.get()); - REQUIRE(ptr_orig.expired() == false); - - ptr_owner.reset(); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr.expired() == true); - } - - REQUIRE(instances == 0); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); -} +// TEST_CASE("owner size", "[owner_size]") { +// REQUIRE(sizeof(test_ptr) == 2 * sizeof(void*)); +// } + +// TEST_CASE("owner size sealed", "[owner_size]") { +// REQUIRE(sizeof(test_sptr) == 2 * sizeof(void*)); +// } + +// TEST_CASE("owner default constructor", "[owner_construction]") { +// memory_tracker mem_track; + +// { +// test_ptr ptr; +// REQUIRE(instances == 0); +// REQUIRE(ptr.get() == nullptr); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner default constructor sealed", "[owner_construction]") { +// memory_tracker mem_track; + +// { +// test_sptr ptr; +// REQUIRE(instances == 0); +// REQUIRE(ptr.get() == nullptr); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner default constructor with deleter", "[owner_construction]") { +// memory_tracker mem_track; + +// { +// test_ptr_with_deleter ptr; +// REQUIRE(instances == 0); +// REQUIRE(instances_deleter == 1); +// REQUIRE(ptr.get() == nullptr); +// REQUIRE(ptr.get_deleter().state_ == 0); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_deleter == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner nullptr constructor", "[owner_construction]") { +// memory_tracker mem_track; + +// { +// test_ptr ptr{nullptr}; +// REQUIRE(instances == 0); +// REQUIRE(ptr.get() == nullptr); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner nullptr constructor sealed", "[owner_construction]") { +// memory_tracker mem_track; + +// { +// test_sptr ptr{nullptr}; +// REQUIRE(instances == 0); +// REQUIRE(ptr.get() == nullptr); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner nullptr constructor with deleter", "[owner_construction]") { +// memory_tracker mem_track; + +// { +// test_ptr_with_deleter ptr{nullptr, test_deleter{42}}; +// REQUIRE(instances == 0); +// REQUIRE(instances_deleter == 1); +// REQUIRE(ptr.get() == nullptr); +// REQUIRE(ptr.get_deleter().state_ == 42); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_deleter == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner move constructor", "[owner_construction]") { +// memory_tracker mem_track; + +// { +// test_ptr ptr_orig(new test_object); +// { +// test_ptr ptr(std::move(ptr_orig)); +// REQUIRE(instances == 1); +// REQUIRE(ptr.get() != nullptr); +// } + +// REQUIRE(instances == 0); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner move constructor sealed", "[owner_construction]") { +// memory_tracker mem_track; + +// { +// test_sptr ptr_orig = oup::make_observable_sealed(); +// { +// test_sptr ptr(std::move(ptr_orig)); +// REQUIRE(instances == 1); +// REQUIRE(ptr.get() != nullptr); +// } + +// REQUIRE(instances == 0); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner move constructor with deleter", "[owner_construction]") { +// memory_tracker mem_track; + +// { +// test_ptr_with_deleter ptr_orig(new test_object, test_deleter{42}); +// { +// test_ptr_with_deleter ptr(std::move(ptr_orig)); +// REQUIRE(instances == 1); +// REQUIRE(instances_deleter == 2); +// REQUIRE(ptr.get() != nullptr); +// REQUIRE(ptr.get_deleter().state_ == 42); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_deleter == 1); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_deleter == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner acquiring constructor", "[owner_construction]") { +// memory_tracker mem_track; + +// { +// test_ptr ptr{new test_object}; +// REQUIRE(instances == 1); +// REQUIRE(ptr.get() != nullptr); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner acquiring constructor bad alloc", "[owner_construction]") { +// memory_tracker mem_track; + +// { +// test_object* raw_ptr = new test_object; +// try { +// force_next_allocation_failure = true; +// test_ptr{raw_ptr}; +// } catch (...) { +// } +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner acquiring constructor with deleter", "[owner_construction]") { +// memory_tracker mem_track; + +// { +// test_ptr_with_deleter ptr{new test_object, test_deleter{42}}; +// REQUIRE(instances == 1); +// REQUIRE(instances_deleter == 1); +// REQUIRE(ptr.get() != nullptr); +// REQUIRE(ptr.get_deleter().state_ == 42); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_deleter == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner acquiring constructor with deleter bad alloc", "[owner_construction]") { +// memory_tracker mem_track; + +// { +// test_object* raw_ptr = new test_object; +// try { +// force_next_allocation_failure = true; +// test_ptr_with_deleter{raw_ptr, test_deleter{42}}; +// } catch (...) { +// } +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner acquiring constructor null", "[owner_construction]") { +// memory_tracker mem_track; + +// { +// test_ptr ptr{static_cast(nullptr)}; +// REQUIRE(instances == 0); +// REQUIRE(ptr.get() == nullptr); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner acquiring constructor null with deleter", "[owner_construction]") { +// memory_tracker mem_track; + +// { +// test_ptr_with_deleter ptr{static_cast(nullptr), test_deleter{42}}; +// REQUIRE(instances == 0); +// REQUIRE(instances_deleter == 1); +// REQUIRE(ptr.get() == nullptr); +// REQUIRE(ptr.get_deleter().state_ == 42); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_deleter == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner implicit conversion constructor", "[owner_construction]") { +// memory_tracker mem_track; + +// { +// test_ptr_derived ptr_orig{new test_object_derived}; +// { +// test_ptr ptr(std::move(ptr_orig)); +// REQUIRE(instances == 1); +// REQUIRE(instances_derived == 1); +// REQUIRE(ptr.get() != nullptr); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_derived == 0); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_derived == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner implicit conversion constructor sealed", "[owner_construction]") { +// memory_tracker mem_track; + +// { +// test_sptr_derived ptr_orig = oup::make_observable_sealed(); +// { +// test_sptr ptr(std::move(ptr_orig)); +// REQUIRE(instances == 1); +// REQUIRE(instances_derived == 1); +// REQUIRE(ptr.get() != nullptr); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_derived == 0); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_derived == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner implicit conversion constructor with deleter", "[owner_construction]") { +// memory_tracker mem_track; + +// { +// test_ptr_derived_with_deleter ptr_orig{new test_object_derived, test_deleter{42}}; +// { +// test_ptr_with_deleter ptr(std::move(ptr_orig)); +// REQUIRE(instances == 1); +// REQUIRE(instances_derived == 1); +// REQUIRE(instances_deleter == 2); +// REQUIRE(ptr.get() != nullptr); +// REQUIRE(ptr.get_deleter().state_ == 42); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_derived == 0); +// REQUIRE(instances_deleter == 1); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_derived == 0); +// REQUIRE(instances_deleter == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner explicit conversion constructor", "[owner_construction]") { +// memory_tracker mem_track; + +// { +// test_ptr ptr_orig{new test_object_derived}; +// { +// test_ptr_derived ptr( +// std::move(ptr_orig), dynamic_cast(ptr_orig.get())); +// REQUIRE(instances == 1); +// REQUIRE(instances_derived == 1); +// REQUIRE(ptr.get() != nullptr); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_derived == 0); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_derived == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner explicit conversion constructor sealed", "[owner_construction]") { +// memory_tracker mem_track; + +// { +// test_sptr ptr_orig = oup::make_observable_sealed(); +// { +// test_sptr_derived ptr( +// std::move(ptr_orig), dynamic_cast(ptr_orig.get())); +// REQUIRE(instances == 1); +// REQUIRE(instances_derived == 1); +// REQUIRE(ptr.get() != nullptr); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_derived == 0); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_derived == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner explicit conversion constructor with default deleter", "[owner_construction]") { +// memory_tracker mem_track; + +// { +// test_ptr_with_deleter ptr_orig{new test_object_derived, test_deleter{42}}; +// { +// test_ptr_derived_with_deleter ptr( +// std::move(ptr_orig), dynamic_cast(ptr_orig.get())); +// REQUIRE(instances == 1); +// REQUIRE(instances_derived == 1); +// REQUIRE(instances_deleter == 2); +// REQUIRE(ptr.get() != nullptr); +// REQUIRE(ptr.get_deleter().state_ == 42); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_derived == 0); +// REQUIRE(instances_deleter == 1); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_derived == 0); +// REQUIRE(instances_deleter == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner explicit conversion constructor with custom deleter", "[owner_construction]") { +// memory_tracker mem_track; + +// { +// test_ptr_with_deleter ptr_orig{new test_object_derived, test_deleter{42}}; +// { +// test_ptr_derived_with_deleter ptr( +// std::move(ptr_orig), dynamic_cast(ptr_orig.get()), +// test_deleter{43}); +// REQUIRE(instances == 1); +// REQUIRE(instances_derived == 1); +// REQUIRE(instances_deleter == 2); +// REQUIRE(ptr.get() != nullptr); +// REQUIRE(ptr.get_deleter().state_ == 43); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_derived == 0); +// REQUIRE(instances_deleter == 1); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_derived == 0); +// REQUIRE(instances_deleter == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner explicit conversion constructor with nullptr", "[owner_construction]") { +// memory_tracker mem_track; + +// { +// test_ptr ptr_orig{new test_object_derived}; +// { +// test_ptr_derived ptr(std::move(ptr_orig), +// static_cast(nullptr)); REQUIRE(instances == 0); +// REQUIRE(instances_derived == 0); +// REQUIRE(ptr.get() == nullptr); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_derived == 0); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_derived == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner explicit conversion constructor with nullptr sealed", "[owner_construction]") { +// memory_tracker mem_track; + +// { +// test_sptr ptr_orig = oup::make_observable_sealed(); +// { +// test_sptr_derived ptr(std::move(ptr_orig), +// static_cast(nullptr)); REQUIRE(instances == 0); +// REQUIRE(instances_derived == 0); +// REQUIRE(ptr.get() == nullptr); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_derived == 0); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_derived == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE( +// "owner explicit conversion constructor with nullptr with custom deleter", +// "[owner_construction]") { +// memory_tracker mem_track; + +// { +// test_ptr_with_deleter ptr_orig{new test_object_derived, test_deleter{42}}; +// { +// test_ptr_derived_with_deleter ptr( +// std::move(ptr_orig), static_cast(nullptr), +// test_deleter{43}); +// REQUIRE(instances == 0); +// REQUIRE(instances_derived == 0); +// REQUIRE(instances_deleter == 2); +// REQUIRE(ptr.get() == nullptr); +// REQUIRE(ptr.get_deleter().state_ == 43); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_derived == 0); +// REQUIRE(instances_deleter == 1); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_derived == 0); +// REQUIRE(instances_deleter == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner move assignment operator valid to empty", "[owner_assignment]") { +// memory_tracker mem_track; + +// { +// test_ptr ptr_orig(new test_object); +// { +// test_ptr ptr; +// ptr = std::move(ptr_orig); +// REQUIRE(instances == 1); +// REQUIRE(ptr.get() != nullptr); +// } + +// REQUIRE(instances == 0); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner move assignment operator valid to empty sealed", "[owner_assignment]") { +// memory_tracker mem_track; + +// { +// test_sptr ptr_orig = oup::make_observable_sealed(); +// { +// test_sptr ptr; +// ptr = std::move(ptr_orig); +// REQUIRE(instances == 1); +// REQUIRE(ptr.get() != nullptr); +// } + +// REQUIRE(instances == 0); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner move assignment operator valid to empty with deleter", "[owner_assignment]") { +// memory_tracker mem_track; + +// { +// test_ptr_with_deleter ptr_orig(new test_object, test_deleter{42}); +// { +// test_ptr_with_deleter ptr; +// ptr = std::move(ptr_orig); +// REQUIRE(instances == 1); +// REQUIRE(instances_deleter == 2); +// REQUIRE(ptr.get() != nullptr); +// REQUIRE(ptr.get_deleter().state_ == 42); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_deleter == 1); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_deleter == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner move assignment operator empty to valid", "[owner_assignment]") { +// memory_tracker mem_track; + +// { +// test_ptr ptr_orig; +// { +// test_ptr ptr(new test_object); +// ptr = std::move(ptr_orig); +// REQUIRE(instances == 0); +// REQUIRE(ptr.get() == nullptr); +// } + +// REQUIRE(instances == 0); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner move assignment operator empty to valid sealed", "[owner_assignment]") { +// memory_tracker mem_track; + +// { +// test_sptr ptr_orig; +// { +// test_sptr ptr = oup::make_observable_sealed(); +// ptr = std::move(ptr_orig); +// REQUIRE(instances == 0); +// REQUIRE(ptr.get() == nullptr); +// } + +// REQUIRE(instances == 0); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner move assignment operator empty to valid with deleter", "[owner_assignment]") { +// memory_tracker mem_track; + +// { +// test_ptr_with_deleter ptr_orig; +// { +// test_ptr_with_deleter ptr(new test_object, test_deleter{42}); +// ptr = std::move(ptr_orig); +// REQUIRE(instances == 0); +// REQUIRE(instances_deleter == 2); +// REQUIRE(ptr.get() == nullptr); +// REQUIRE(ptr.get_deleter().state_ == 0); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_deleter == 1); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_deleter == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner move assignment operator empty to empty", "[owner_assignment]") { +// memory_tracker mem_track; + +// { +// test_ptr ptr_orig; +// { +// test_ptr ptr; +// ptr = std::move(ptr_orig); +// REQUIRE(instances == 0); +// REQUIRE(ptr.get() == nullptr); +// } + +// REQUIRE(instances == 0); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner move assignment operator empty to empty sealed", "[owner_assignment]") { +// memory_tracker mem_track; + +// { +// test_sptr ptr_orig; +// { +// test_sptr ptr; +// ptr = std::move(ptr_orig); +// REQUIRE(instances == 0); +// REQUIRE(ptr.get() == nullptr); +// } + +// REQUIRE(instances == 0); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner move assignment operator empty to empty with deleter", "[owner_assignment]") { +// memory_tracker mem_track; + +// { +// test_ptr_with_deleter ptr_orig; +// { +// test_ptr_with_deleter ptr; +// ptr = std::move(ptr_orig); +// REQUIRE(instances == 0); +// REQUIRE(instances_deleter == 2); +// REQUIRE(ptr.get() == nullptr); +// REQUIRE(ptr.get_deleter().state_ == 0); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_deleter == 1); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_deleter == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner move assignment operator valid to valid", "[owner_assignment]") { +// memory_tracker mem_track; + +// { +// test_ptr ptr_orig(new test_object); +// { +// test_ptr ptr(new test_object); +// ptr = std::move(ptr_orig); +// REQUIRE(instances == 1); +// REQUIRE(ptr.get() != nullptr); +// } + +// REQUIRE(instances == 0); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner move assignment operator valid to valid sealed", "[owner_assignment]") { +// memory_tracker mem_track; + +// { +// test_sptr ptr_orig = oup::make_observable_sealed(); +// { +// test_sptr ptr = oup::make_observable_sealed(); +// ptr = std::move(ptr_orig); +// REQUIRE(instances == 1); +// REQUIRE(ptr.get() != nullptr); +// } + +// REQUIRE(instances == 0); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner move assignment operator valid to valid with deleter", "[owner_assignment]") { +// memory_tracker mem_track; + +// { +// test_ptr_with_deleter ptr_orig(new test_object, test_deleter{42}); +// { +// test_ptr_with_deleter ptr(new test_object, test_deleter{43}); +// ptr = std::move(ptr_orig); +// REQUIRE(instances == 1); +// REQUIRE(instances_deleter == 2); +// REQUIRE(ptr.get() != nullptr); +// REQUIRE(ptr.get_deleter().state_ == 42); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_deleter == 1); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_deleter == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner move assignment operator self to self", "[owner_assignment]") { +// memory_tracker mem_track; + +// { +// test_ptr ptr(new test_object); +// ptr = std::move(ptr); +// REQUIRE(instances == 0); +// REQUIRE(ptr.get() == nullptr); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner move assignment operator self to self sealed", "[owner_assignment]") { +// memory_tracker mem_track; + +// { +// test_sptr ptr = oup::make_observable_sealed(); +// ptr = std::move(ptr); +// REQUIRE(instances == 0); +// REQUIRE(ptr.get() == nullptr); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner move assignment operator self to self with deleter", "[owner_assignment]") { +// memory_tracker mem_track; + +// { +// test_ptr_with_deleter ptr(new test_object, test_deleter{42}); +// ptr = std::move(ptr); +// REQUIRE(instances == 0); +// REQUIRE(ptr.get() == nullptr); +// REQUIRE(instances_deleter == 1); +// REQUIRE(ptr.get_deleter().state_ == 0); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_deleter == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner move assignment operator self to self empty", "[owner_assignment]") { +// memory_tracker mem_track; + +// { +// test_ptr ptr; +// ptr = std::move(ptr); +// REQUIRE(instances == 0); +// REQUIRE(ptr.get() == nullptr); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner move assignment operator self to self empty sealed", "[owner_assignment]") { +// memory_tracker mem_track; + +// { +// test_sptr ptr; +// ptr = std::move(ptr); +// REQUIRE(instances == 0); +// REQUIRE(ptr.get() == nullptr); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner move assignment operator self to self empty with deleter", "[owner_assignment]") +// { +// memory_tracker mem_track; + +// { +// test_ptr_with_deleter ptr; +// ptr = std::move(ptr); +// REQUIRE(instances == 0); +// REQUIRE(ptr.get() == nullptr); +// REQUIRE(instances_deleter == 1); +// REQUIRE(ptr.get_deleter().state_ == 0); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_deleter == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner comparison valid ptr vs nullptr", "[owner_comparison]") { +// memory_tracker mem_track; + +// { +// test_ptr ptr(new test_object); +// REQUIRE(ptr != nullptr); +// REQUIRE(!(ptr == nullptr)); +// REQUIRE(nullptr != ptr); +// REQUIRE(!(nullptr == ptr)); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner comparison valid ptr vs nullptr sealed", "[owner_comparison]") { +// memory_tracker mem_track; + +// { +// test_sptr ptr = oup::make_observable_sealed(); +// REQUIRE(ptr != nullptr); +// REQUIRE(!(ptr == nullptr)); +// REQUIRE(nullptr != ptr); +// REQUIRE(!(nullptr == ptr)); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner comparison valid ptr vs nullptr with deleter", "[owner_comparison]") { +// memory_tracker mem_track; + +// { +// test_ptr_with_deleter ptr(new test_object, test_deleter{42}); +// REQUIRE(ptr != nullptr); +// REQUIRE(!(ptr == nullptr)); +// REQUIRE(nullptr != ptr); +// REQUIRE(!(nullptr == ptr)); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner comparison invalid ptr vs nullptr", "[owner_comparison]") { +// memory_tracker mem_track; + +// { +// test_ptr ptr; +// REQUIRE(ptr == nullptr); +// REQUIRE(!(ptr != nullptr)); +// REQUIRE(nullptr == ptr); +// REQUIRE(!(nullptr != ptr)); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner comparison invalid ptr vs nullptr sealed", "[owner_comparison]") { +// memory_tracker mem_track; + +// { +// test_sptr ptr; +// REQUIRE(ptr == nullptr); +// REQUIRE(!(ptr != nullptr)); +// REQUIRE(nullptr == ptr); +// REQUIRE(!(nullptr != ptr)); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner comparison invalid ptr vs nullptr with deleter", "[owner_comparison]") { +// memory_tracker mem_track; + +// { +// test_ptr_with_deleter ptr; +// REQUIRE(ptr == nullptr); +// REQUIRE(!(ptr != nullptr)); +// REQUIRE(nullptr == ptr); +// REQUIRE(!(nullptr != ptr)); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner comparison invalid ptr vs nullptr with deleter explicit", "[owner_comparison]") +// { +// memory_tracker mem_track; + +// { +// test_ptr_with_deleter ptr(nullptr, test_deleter{42}); +// REQUIRE(ptr == nullptr); +// REQUIRE(!(ptr != nullptr)); +// REQUIRE(nullptr == ptr); +// REQUIRE(!(nullptr != ptr)); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner comparison invalid ptr vs invalid ptr", "[owner_comparison]") { +// memory_tracker mem_track; + +// { +// test_ptr ptr1; +// test_ptr ptr2; +// REQUIRE(ptr1 == ptr2); +// REQUIRE(!(ptr1 != ptr2)); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner comparison invalid ptr vs invalid ptr sealed", "[owner_comparison]") { +// memory_tracker mem_track; + +// { +// test_sptr ptr1; +// test_sptr ptr2; +// REQUIRE(ptr1 == ptr2); +// REQUIRE(!(ptr1 != ptr2)); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner comparison invalid ptr vs invalid ptr with deleter", "[owner_comparison]") { +// memory_tracker mem_track; + +// { +// test_ptr_with_deleter ptr1; +// test_ptr_with_deleter ptr2; +// REQUIRE(ptr1 == ptr2); +// REQUIRE(!(ptr1 != ptr2)); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE( +// "owner comparison invalid ptr vs invalid ptr with deleter explicit", "[owner_comparison]") { +// memory_tracker mem_track; + +// { +// test_ptr_with_deleter ptr1; +// test_ptr_with_deleter ptr2(nullptr, test_deleter{42}); +// REQUIRE(ptr1 == ptr2); +// REQUIRE(ptr2 == ptr1); +// REQUIRE(!(ptr2 != ptr1)); +// REQUIRE(!(ptr2 != ptr1)); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE( +// "owner comparison invalid ptr vs invalid ptr with both deleter explicit", +// "[owner_comparison]") { +// memory_tracker mem_track; + +// { +// test_ptr_with_deleter ptr1(nullptr, test_deleter{43}); +// test_ptr_with_deleter ptr2(nullptr, test_deleter{42}); +// REQUIRE(ptr1 == ptr2); +// REQUIRE(ptr2 == ptr1); +// REQUIRE(!(ptr2 != ptr1)); +// REQUIRE(!(ptr2 != ptr1)); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner comparison invalid ptr vs valid ptr", "[owner_comparison]") { +// memory_tracker mem_track; + +// { +// test_ptr ptr1; +// test_ptr ptr2(new test_object); +// REQUIRE(ptr1 != ptr2); +// REQUIRE(!(ptr1 == ptr2)); +// REQUIRE(ptr2 != ptr1); +// REQUIRE(!(ptr2 == ptr1)); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner comparison invalid ptr vs valid ptr sealed", "[owner_comparison]") { +// memory_tracker mem_track; + +// { +// test_sptr ptr1; +// test_sptr ptr2 = oup::make_observable_sealed(); +// REQUIRE(ptr1 != ptr2); +// REQUIRE(!(ptr1 == ptr2)); +// REQUIRE(ptr2 != ptr1); +// REQUIRE(!(ptr2 == ptr1)); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner comparison invalid ptr vs valid ptr with deleter", "[owner_comparison]") { +// memory_tracker mem_track; + +// { +// test_ptr_with_deleter ptr1; +// test_ptr_with_deleter ptr2(new test_object, test_deleter{42}); +// REQUIRE(ptr1 != ptr2); +// REQUIRE(!(ptr1 == ptr2)); +// REQUIRE(ptr2 != ptr1); +// REQUIRE(!(ptr2 == ptr1)); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner comparison invalid ptr vs valid ptr with deleter explicit", +// "[owner_comparison]") { +// memory_tracker mem_track; + +// { +// test_ptr_with_deleter ptr1(nullptr, test_deleter{43}); +// test_ptr_with_deleter ptr2(new test_object, test_deleter{42}); +// REQUIRE(ptr1 != ptr2); +// REQUIRE(!(ptr1 == ptr2)); +// REQUIRE(ptr2 != ptr1); +// REQUIRE(!(ptr2 == ptr1)); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner comparison valid ptr vs valid ptr", "[owner_comparison]") { +// memory_tracker mem_track; + +// { +// test_ptr ptr1(new test_object); +// test_ptr ptr2(new test_object); +// REQUIRE(ptr1 != ptr2); +// REQUIRE(!(ptr1 == ptr2)); +// REQUIRE(ptr2 != ptr1); +// REQUIRE(!(ptr2 == ptr1)); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner comparison valid ptr vs valid ptr sealed", "[owner_comparison]") { +// memory_tracker mem_track; + +// { +// test_sptr ptr1 = oup::make_observable_sealed(); +// test_sptr ptr2 = oup::make_observable_sealed(); +// REQUIRE(ptr1 != ptr2); +// REQUIRE(!(ptr1 == ptr2)); +// REQUIRE(ptr2 != ptr1); +// REQUIRE(!(ptr2 == ptr1)); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner comparison valid ptr vs valid ptr with deleter", "[owner_comparison]") { +// memory_tracker mem_track; + +// { +// test_ptr_with_deleter ptr1(new test_object, test_deleter{43}); +// test_ptr_with_deleter ptr2(new test_object, test_deleter{42}); +// REQUIRE(ptr1 != ptr2); +// REQUIRE(!(ptr1 == ptr2)); +// REQUIRE(ptr2 != ptr1); +// REQUIRE(!(ptr2 == ptr1)); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner reset to null", "[owner_utility]") { +// memory_tracker mem_track; + +// { +// test_ptr ptr(new test_object); +// ptr.reset(); +// REQUIRE(instances == 0); +// REQUIRE(ptr.get() == nullptr); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner reset to null sealed", "[owner_utility]") { +// memory_tracker mem_track; + +// { +// test_sptr ptr = oup::make_observable_sealed(); +// ptr.reset(); +// REQUIRE(instances == 0); +// REQUIRE(ptr.get() == nullptr); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner reset to null with deleter", "[owner_utility]") { +// memory_tracker mem_track; + +// { +// test_ptr_with_deleter ptr(new test_object, test_deleter{42}); +// ptr.reset(); +// REQUIRE(instances == 0); +// REQUIRE(instances_deleter == 1); +// REQUIRE(ptr.get() == nullptr); +// REQUIRE(ptr.get_deleter().state_ == 42); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_deleter == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner reset to new", "[owner_utility]") { +// memory_tracker mem_track; + +// { +// test_ptr ptr(new test_object); +// ptr.reset(new test_object); +// REQUIRE(instances == 1); +// REQUIRE(ptr.get() != nullptr); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner reset to new bad alloc", "[owner_utility]") { +// memory_tracker mem_track; + +// { +// test_object* raw_ptr1 = new test_object; +// test_object* raw_ptr2 = new test_object; +// test_ptr ptr(raw_ptr1); +// try { +// force_next_allocation_failure = true; +// ptr.reset(raw_ptr2); +// } catch (...) { +// } +// REQUIRE(instances == 1); +// REQUIRE(ptr.get() == raw_ptr1); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner reset to new with deleter", "[owner_utility]") { +// memory_tracker mem_track; + +// { +// test_ptr_with_deleter ptr(new test_object, test_deleter{42}); +// ptr.reset(new test_object); +// REQUIRE(instances == 1); +// REQUIRE(instances_deleter == 1); +// REQUIRE(ptr.get() != nullptr); +// REQUIRE(ptr.get_deleter().state_ == 42); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_deleter == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner swap no instance", "[owner_utility]") { +// memory_tracker mem_track; + +// { +// test_ptr ptr_orig; +// test_ptr ptr; +// ptr.swap(ptr_orig); +// REQUIRE(instances == 0); +// REQUIRE(ptr_orig.get() == nullptr); +// REQUIRE(ptr.get() == nullptr); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner swap no instance sealed", "[owner_utility]") { +// memory_tracker mem_track; + +// { +// test_sptr ptr_orig; +// test_sptr ptr; +// ptr.swap(ptr_orig); +// REQUIRE(instances == 0); +// REQUIRE(ptr_orig.get() == nullptr); +// REQUIRE(ptr.get() == nullptr); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner swap no instance with deleter", "[owner_utility]") { +// memory_tracker mem_track; + +// { +// test_ptr_with_deleter ptr_orig(nullptr, test_deleter{42}); +// test_ptr_with_deleter ptr(nullptr, test_deleter{43}); +// ptr.swap(ptr_orig); +// REQUIRE(instances == 0); +// REQUIRE(instances_deleter == 2); +// REQUIRE(ptr_orig.get() == nullptr); +// REQUIRE(ptr.get() == nullptr); +// REQUIRE(ptr.get_deleter().state_ == 42); +// REQUIRE(ptr_orig.get_deleter().state_ == 43); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_deleter == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner swap one instance", "[owner_utility]") { +// memory_tracker mem_track; + +// { +// test_ptr ptr_orig(new test_object); +// test_ptr ptr; +// ptr.swap(ptr_orig); +// REQUIRE(instances == 1); +// REQUIRE(ptr_orig.get() == nullptr); +// REQUIRE(ptr.get() != nullptr); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner swap one instance sealed", "[owner_utility]") { +// memory_tracker mem_track; + +// { +// test_sptr ptr_orig = oup::make_observable_sealed(); +// test_sptr ptr; +// ptr.swap(ptr_orig); +// REQUIRE(instances == 1); +// REQUIRE(ptr_orig.get() == nullptr); +// REQUIRE(ptr.get() != nullptr); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner swap one instance with deleter", "[owner_utility]") { +// memory_tracker mem_track; + +// { +// test_ptr_with_deleter ptr_orig(new test_object, test_deleter{42}); +// test_ptr_with_deleter ptr(nullptr, test_deleter{43}); +// ptr.swap(ptr_orig); +// REQUIRE(instances == 1); +// REQUIRE(instances_deleter == 2); +// REQUIRE(ptr_orig.get() == nullptr); +// REQUIRE(ptr.get() != nullptr); +// REQUIRE(ptr.get_deleter().state_ == 42); +// REQUIRE(ptr_orig.get_deleter().state_ == 43); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_deleter == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner swap two instances", "[owner_utility]") { +// memory_tracker mem_track; + +// { +// test_ptr ptr_orig(new test_object); +// test_object* ptr_orig_raw = ptr_orig.get(); +// test_ptr ptr(new test_object); +// test_object* ptr_raw = ptr.get(); +// ptr.swap(ptr_orig); +// REQUIRE(instances == 2); +// REQUIRE(ptr_orig.get() == ptr_raw); +// REQUIRE(ptr.get() == ptr_orig_raw); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner swap two instances sealed", "[owner_utility]") { +// memory_tracker mem_track; + +// { +// test_sptr ptr_orig = oup::make_observable_sealed(); +// test_object* ptr_orig_raw = ptr_orig.get(); +// test_sptr ptr = oup::make_observable_sealed(); +// test_object* ptr_raw = ptr.get(); +// ptr.swap(ptr_orig); +// REQUIRE(instances == 2); +// REQUIRE(ptr_orig.get() == ptr_raw); +// REQUIRE(ptr.get() == ptr_orig_raw); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner swap two instances with deleter", "[owner_utility]") { +// memory_tracker mem_track; + +// { +// test_ptr_with_deleter ptr_orig(new test_object, test_deleter{42}); +// test_object* ptr_orig_raw = ptr_orig.get(); +// test_ptr_with_deleter ptr(new test_object, test_deleter{43}); +// test_object* ptr_raw = ptr.get(); +// ptr.swap(ptr_orig); +// REQUIRE(instances == 2); +// REQUIRE(instances_deleter == 2); +// REQUIRE(ptr_orig.get() == ptr_raw); +// REQUIRE(ptr.get() == ptr_orig_raw); +// REQUIRE(ptr.get_deleter().state_ == 42); +// REQUIRE(ptr_orig.get_deleter().state_ == 43); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_deleter == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner swap self", "[owner_utility]") { +// memory_tracker mem_track; + +// { +// test_ptr ptr(new test_object); +// ptr.swap(ptr); +// REQUIRE(instances == 1); +// REQUIRE(ptr.get() != nullptr); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner swap self sealed", "[owner_utility]") { +// memory_tracker mem_track; + +// { +// test_sptr ptr = oup::make_observable_sealed(); +// ptr.swap(ptr); +// REQUIRE(instances == 1); +// REQUIRE(ptr.get() != nullptr); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner swap self with deleter", "[owner_utility]") { +// memory_tracker mem_track; + +// { +// test_ptr_with_deleter ptr(new test_object, test_deleter{43}); +// ptr.swap(ptr); +// REQUIRE(instances == 1); +// REQUIRE(ptr.get() != nullptr); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_deleter == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner dereference", "[owner_utility]") { +// memory_tracker mem_track; + +// { +// test_ptr ptr(new test_object); +// REQUIRE(ptr->state_ == 1337); +// REQUIRE((*ptr).state_ == 1337); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner dereference sealed", "[owner_utility]") { +// memory_tracker mem_track; + +// { +// test_sptr ptr = oup::make_observable_sealed(); +// REQUIRE(ptr->state_ == 1337); +// REQUIRE((*ptr).state_ == 1337); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner operator bool valid", "[owner_utility]") { +// memory_tracker mem_track; + +// { +// test_ptr ptr(new test_object); +// if (ptr) { +// } else +// FAIL("if (ptr) should have been true"); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner operator bool valid sealed", "[owner_utility]") { +// memory_tracker mem_track; + +// { +// test_sptr ptr = oup::make_observable_sealed(); +// if (ptr) { +// } else +// FAIL("if (ptr) should have been true"); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner operator bool invalid", "[owner_utility]") { +// memory_tracker mem_track; + +// { +// test_ptr ptr; +// if (ptr) +// FAIL("if (ptr) should not have been true"); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner operator bool invalid sealed", "[owner_utility]") { +// memory_tracker mem_track; + +// { +// test_sptr ptr; +// if (ptr) +// FAIL("if (ptr) should not have been true"); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner release valid", "[owner_utility]") { +// memory_tracker mem_track; + +// { +// test_ptr ptr(new test_object); +// test_object* ptr_raw = ptr.release(); +// REQUIRE(ptr_raw != nullptr); +// REQUIRE(ptr.get() == nullptr); +// REQUIRE(instances == 1); +// delete ptr_raw; +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner release valid with observer", "[owner_utility]") { +// memory_tracker mem_track; + +// { +// test_optr optr; +// { +// test_ptr ptr(new test_object); +// optr = ptr; +// test_object* ptr_raw = ptr.release(); +// REQUIRE(ptr_raw != nullptr); +// REQUIRE(ptr.get() == nullptr); +// REQUIRE(instances == 1); +// delete ptr_raw; +// } + +// REQUIRE(optr.expired()); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner release valid from make_observable_unique", "[owner_utility]") { +// memory_tracker mem_track; + +// { +// test_ptr ptr = oup::make_observable_unique(); +// test_object* ptr_raw = ptr.release(); +// REQUIRE(ptr_raw != nullptr); +// REQUIRE(ptr.get() == nullptr); +// REQUIRE(instances == 1); +// delete ptr_raw; +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner release valid from make_observable_unique with observer", "[owner_utility]") { +// memory_tracker mem_track; + +// { +// test_optr optr; +// { +// test_ptr ptr = oup::make_observable_unique(); +// optr = ptr; +// test_object* ptr_raw = ptr.release(); +// REQUIRE(ptr_raw != nullptr); +// REQUIRE(ptr.get() == nullptr); +// REQUIRE(instances == 1); +// delete ptr_raw; +// } + +// REQUIRE(optr.expired()); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner release valid with deleter", "[owner_utility]") { +// memory_tracker mem_track; + +// { +// test_ptr_with_deleter ptr(new test_object, test_deleter{42}); +// test_object* ptr_raw = ptr.release(); +// REQUIRE(ptr_raw != nullptr); +// REQUIRE(ptr.get() == nullptr); +// REQUIRE(instances == 1); +// REQUIRE(instances_deleter == 1); +// REQUIRE(ptr.get_deleter().state_ == 42); +// delete ptr_raw; +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_deleter == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner release valid with deleter with observer", "[owner_utility]") { +// memory_tracker mem_track; + +// { +// test_optr optr; +// { +// test_ptr_with_deleter ptr(new test_object, test_deleter{42}); +// optr = ptr; +// test_object* ptr_raw = ptr.release(); +// REQUIRE(ptr_raw != nullptr); +// REQUIRE(ptr.get() == nullptr); +// REQUIRE(instances == 1); +// REQUIRE(instances_deleter == 1); +// REQUIRE(ptr.get_deleter().state_ == 42); +// delete ptr_raw; +// } + +// REQUIRE(optr.expired()); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_deleter == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner release invalid", "[owner_utility]") { +// memory_tracker mem_track; + +// { +// test_ptr ptr; +// REQUIRE(ptr.release() == nullptr); +// REQUIRE(instances == 0); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("owner release invalid with deleter", "[owner_utility]") { +// memory_tracker mem_track; + +// { +// test_ptr_with_deleter ptr; +// REQUIRE(ptr.release() == nullptr); +// REQUIRE(instances == 0); +// REQUIRE(instances_deleter == 1); +// } + +// REQUIRE(instances == 0); +// REQUIRE(instances_deleter == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("make observable unique", "[make_observable_unique]") { +// memory_tracker mem_track; + +// { +// test_ptr ptr = oup::make_observable_unique(); +// REQUIRE(instances == 1); +// REQUIRE(ptr.get() != nullptr); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("make observable unique throw in constructor", "[make_observable_unique]") { +// memory_tracker mem_track; + +// REQUIRE_THROWS_AS(oup::make_observable_unique(), throw_constructor); + +// REQUIRE(instances_thrower == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("make observable non virtual unique throw in constructor", "[make_observable_unique]") +// { +// memory_tracker mem_track; + +// REQUIRE_THROWS_AS( +// (oup::make_observable< +// test_object_thrower_observer_from_this_non_virtual_unique, +// unique_non_virtual_policy>()), +// throw_constructor); + +// REQUIRE(instances_thrower == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("make observable sealed", "[make_observable_sealed]") { +// memory_tracker mem_track; + +// { +// test_sptr ptr = oup::make_observable_sealed(); +// REQUIRE(instances == 1); +// REQUIRE(ptr.get() != nullptr); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("make observable sealed throw in constructor", "[make_observable_sealed]") { +// memory_tracker mem_track; + +// REQUIRE_THROWS_AS(oup::make_observable_sealed(), throw_constructor); + +// REQUIRE(instances_thrower == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("observer size", "[observer_size]") { +// REQUIRE(sizeof(test_optr) == 2 * sizeof(void*)); +// } + +// TEST_CASE("observer default constructor", "[observer_construction]") { +// memory_tracker mem_track; + +// { +// test_optr ptr; +// REQUIRE(instances == 0); +// REQUIRE(ptr.get() == nullptr); +// REQUIRE(ptr.expired() == true); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("observer nullptr constructor", "[observer_construction]") { +// memory_tracker mem_track; + +// { +// test_optr ptr{nullptr}; +// REQUIRE(instances == 0); +// REQUIRE(ptr.get() == nullptr); +// REQUIRE(ptr.expired() == true); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("observer copy constructor", "[observer_construction]") { +// memory_tracker mem_track; + +// { +// test_ptr ptr_owner{new test_object}; +// test_optr ptr_orig{ptr_owner}; +// { +// test_optr ptr(ptr_orig); +// REQUIRE(instances == 1); +// REQUIRE(ptr.get() != nullptr); +// REQUIRE(ptr.expired() == false); +// REQUIRE(ptr_orig.get() != nullptr); +// REQUIRE(ptr_orig.expired() == false); + +// ptr_owner.reset(); +// REQUIRE(ptr.get() == nullptr); +// REQUIRE(ptr.expired() == true); +// } + +// REQUIRE(instances == 0); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("observer explicit conversion copy constructor ", "[observer_construction]") { +// memory_tracker mem_track; + +// { +// test_ptr ptr_owner{new test_object_derived}; +// test_optr ptr_orig{ptr_owner}; +// { +// test_optr ptr{ptr_orig, static_cast(ptr_orig.get())}; +// REQUIRE(instances == 1); +// REQUIRE(ptr.get() == static_cast(ptr_owner.get())); +// REQUIRE(ptr.expired() == false); +// REQUIRE(ptr_orig.get() == ptr_owner.get()); +// REQUIRE(ptr_orig.expired() == false); + +// ptr_owner.reset(); +// REQUIRE(ptr.get() == nullptr); +// REQUIRE(ptr.expired() == true); +// } + +// REQUIRE(instances == 0); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("observer explicit conversion copy constructor null pointer", +// "[observer_construction]") { +// memory_tracker mem_track; + +// { +// test_ptr ptr_owner{new test_object_derived}; +// test_optr ptr_orig{ptr_owner}; +// { +// test_optr ptr{ptr_orig, static_cast(nullptr)}; +// REQUIRE(instances == 1); +// REQUIRE(ptr.get() == nullptr); +// REQUIRE(ptr.expired() == true); +// REQUIRE(ptr_orig.get() == ptr_owner.get()); +// REQUIRE(ptr_orig.expired() == false); +// } + +// REQUIRE(instances == 1); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEST_CASE("observer explicit conversion copy constructor subobject", "[observer_construction]") { +// memory_tracker mem_track; + +// { +// test_ptr ptr_owner{new test_object_derived}; +// test_optr ptr_orig{ptr_owner}; +// { +// int_optr ptr{ptr_orig, &ptr_owner->state_}; +// REQUIRE(instances == 1); +// REQUIRE(ptr.get() == &ptr_owner->state_); +// REQUIRE(ptr.expired() == false); +// REQUIRE(ptr_orig.get() == ptr_owner.get()); +// REQUIRE(ptr_orig.expired() == false); + +// ptr_owner.reset(); +// REQUIRE(ptr.get() == nullptr); +// REQUIRE(ptr.expired() == true); +// } + +// REQUIRE(instances == 0); +// } + +// REQUIRE(instances == 0); +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } TEST_CASE("observer from null owner constructor", "[observer_construction]") { memory_tracker mem_track; @@ -1937,8 +1924,8 @@ TEST_CASE("observer from null owner constructor", "[observer_construction]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer from owner constructor", "[observer_construction]") { @@ -1961,8 +1948,8 @@ TEST_CASE("observer from owner constructor", "[observer_construction]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer from null owner casting constructor", "[observer_construction]") { @@ -1981,8 +1968,8 @@ TEST_CASE("observer from null owner casting constructor", "[observer_constructio } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer from owner casting constructor", "[observer_construction]") { @@ -2005,8 +1992,8 @@ TEST_CASE("observer from owner casting constructor", "[observer_construction]") } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer move constructor", "[observer_construction]") { @@ -2032,8 +2019,8 @@ TEST_CASE("observer move constructor", "[observer_construction]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer explicit conversion move constructor ", "[observer_construction]") { @@ -2059,8 +2046,8 @@ TEST_CASE("observer explicit conversion move constructor ", "[observer_construct } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer explicit conversion move constructor null pointer", "[observer_construction]") { @@ -2082,8 +2069,8 @@ TEST_CASE("observer explicit conversion move constructor null pointer", "[observ } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer explicit conversion move constructor subobject", "[observer_construction]") { @@ -2109,8 +2096,8 @@ TEST_CASE("observer explicit conversion move constructor subobject", "[observer_ } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer acquiring constructor", "[observer_construction]") { @@ -2125,8 +2112,8 @@ TEST_CASE("observer acquiring constructor", "[observer_construction]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer acquiring constructor sealed", "[observer_construction]") { @@ -2141,8 +2128,8 @@ TEST_CASE("observer acquiring constructor sealed", "[observer_construction]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer acquiring constructor derived", "[observer_construction]") { @@ -2157,8 +2144,8 @@ TEST_CASE("observer acquiring constructor derived", "[observer_construction]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer acquiring constructor derived sealed", "[observer_construction]") { @@ -2173,8 +2160,8 @@ TEST_CASE("observer acquiring constructor derived sealed", "[observer_constructi } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer acquiring constructor with deleter", "[observer_construction]") { @@ -2189,8 +2176,8 @@ TEST_CASE("observer acquiring constructor with deleter", "[observer_construction } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer implicit copy conversion constructor", "[observer_construction]") { @@ -2215,8 +2202,8 @@ TEST_CASE("observer implicit copy conversion constructor", "[observer_constructi REQUIRE(instances == 0); REQUIRE(instances_derived == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer implicit move conversion constructor", "[observer_construction]") { @@ -2241,8 +2228,8 @@ TEST_CASE("observer implicit move conversion constructor", "[observer_constructi REQUIRE(instances == 0); REQUIRE(instances_derived == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer expiring", "[observer_utility]") { @@ -2264,8 +2251,8 @@ TEST_CASE("observer expiring", "[observer_utility]") { REQUIRE(ptr.expired() == true); } - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer expiring sealed", "[observer_utility]") { @@ -2287,8 +2274,8 @@ TEST_CASE("observer expiring sealed", "[observer_utility]") { REQUIRE(ptr.expired() == true); } - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer expiring reset", "[observer_utility]") { @@ -2302,8 +2289,8 @@ TEST_CASE("observer expiring reset", "[observer_utility]") { REQUIRE(ptr.expired()); } - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer expiring reset sealed", "[observer_utility]") { @@ -2317,8 +2304,8 @@ TEST_CASE("observer expiring reset sealed", "[observer_utility]") { REQUIRE(ptr.expired()); } - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer not expiring when owner moved", "[observer_utility]") { @@ -2332,8 +2319,8 @@ TEST_CASE("observer not expiring when owner moved", "[observer_utility]") { REQUIRE(!ptr.expired()); } - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer not expiring when owner moved sealed", "[observer_utility]") { @@ -2347,8 +2334,8 @@ TEST_CASE("observer not expiring when owner moved sealed", "[observer_utility]") REQUIRE(!ptr.expired()); } - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer reset to null", "[observer_utility]") { @@ -2381,8 +2368,8 @@ TEST_CASE("observer swap no instance", "[observer_utility]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer swap one instance", "[observer_utility]") { @@ -2401,8 +2388,8 @@ TEST_CASE("observer swap one instance", "[observer_utility]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer swap two same instance", "[observer_utility]") { @@ -2421,8 +2408,8 @@ TEST_CASE("observer swap two same instance", "[observer_utility]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer swap two different instances", "[observer_utility]") { @@ -2442,8 +2429,8 @@ TEST_CASE("observer swap two different instances", "[observer_utility]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer swap self", "[observer_utility]") { @@ -2459,8 +2446,8 @@ TEST_CASE("observer swap self", "[observer_utility]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer dereference", "[observer_utility]") { @@ -2473,8 +2460,8 @@ TEST_CASE("observer dereference", "[observer_utility]") { REQUIRE((*ptr).state_ == 1337); } - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer operator bool valid", "[observer_utility]") { @@ -2488,8 +2475,8 @@ TEST_CASE("observer operator bool valid", "[observer_utility]") { FAIL("if (ptr) should have been true"); } - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer operator bool invalid", "[observer_utility]") { @@ -2501,8 +2488,8 @@ TEST_CASE("observer operator bool invalid", "[observer_utility]") { FAIL("if (ptr) should not have been true"); } - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer get and raw get", "[observer_utility]") { @@ -2522,8 +2509,8 @@ TEST_CASE("observer get and raw get", "[observer_utility]") { REQUIRE(ptr.get() == nullptr); } - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer copy assignment operator valid to empty", "[observer_assignment]") { @@ -2546,8 +2533,8 @@ TEST_CASE("observer copy assignment operator valid to empty", "[observer_assignm } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer copy assignment operator valid to valid", "[observer_assignment]") { @@ -2571,8 +2558,8 @@ TEST_CASE("observer copy assignment operator valid to valid", "[observer_assignm } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer copy assignment operator empty to empty", "[observer_assignment]") { @@ -2594,8 +2581,8 @@ TEST_CASE("observer copy assignment operator empty to empty", "[observer_assignm } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer copy assignment operator self to self", "[observer_assignment]") { @@ -2611,8 +2598,8 @@ TEST_CASE("observer copy assignment operator self to self", "[observer_assignmen } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer copy assignment operator self to self expired", "[observer_assignment]") { @@ -2631,8 +2618,8 @@ TEST_CASE("observer copy assignment operator self to self expired", "[observer_a } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer copy assignment operator self to self empty", "[observer_assignment]") { @@ -2647,8 +2634,8 @@ TEST_CASE("observer copy assignment operator self to self empty", "[observer_ass } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer move assignment operator valid to empty", "[observer_assignment]") { @@ -2671,8 +2658,8 @@ TEST_CASE("observer move assignment operator valid to empty", "[observer_assignm } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer move assignment operator valid to valid", "[observer_assignment]") { @@ -2696,8 +2683,8 @@ TEST_CASE("observer move assignment operator valid to valid", "[observer_assignm } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer move assignment operator empty to empty", "[observer_assignment]") { @@ -2719,8 +2706,8 @@ TEST_CASE("observer move assignment operator empty to empty", "[observer_assignm } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer move assignment operator self to self", "[observer_assignment]") { @@ -2736,8 +2723,8 @@ TEST_CASE("observer move assignment operator self to self", "[observer_assignmen } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer move assignment operator self to self expired", "[observer_assignment]") { @@ -2756,8 +2743,8 @@ TEST_CASE("observer move assignment operator self to self expired", "[observer_a } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer move assignment operator self to self empty", "[observer_assignment]") { @@ -2772,8 +2759,8 @@ TEST_CASE("observer move assignment operator self to self empty", "[observer_ass } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer acquiring assignment operator valid to empty", "[observer_assignment]") { @@ -2790,8 +2777,8 @@ TEST_CASE("observer acquiring assignment operator valid to empty", "[observer_as } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer acquiring assignment operator valid to valid", "[observer_assignment]") { @@ -2809,8 +2796,8 @@ TEST_CASE("observer acquiring assignment operator valid to valid", "[observer_as } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer acquiring assignment operator empty to valid", "[observer_assignment]") { @@ -2828,8 +2815,8 @@ TEST_CASE("observer acquiring assignment operator empty to valid", "[observer_as } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer acquiring assignment operator empty to empty", "[observer_assignment]") { @@ -2846,8 +2833,8 @@ TEST_CASE("observer acquiring assignment operator empty to empty", "[observer_as } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer acquiring assignment operator valid to empty sealed", "[observer_assignment]") { @@ -2864,8 +2851,8 @@ TEST_CASE("observer acquiring assignment operator valid to empty sealed", "[obse } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer acquiring assignment operator valid to valid sealed", "[observer_assignment]") { @@ -2883,8 +2870,8 @@ TEST_CASE("observer acquiring assignment operator valid to valid sealed", "[obse } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer acquiring assignment operator empty to valid sealed", "[observer_assignment]") { @@ -2902,8 +2889,8 @@ TEST_CASE("observer acquiring assignment operator empty to valid sealed", "[obse } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer acquiring assignment operator empty to empty sealed", "[observer_assignment]") { @@ -2920,8 +2907,8 @@ TEST_CASE("observer acquiring assignment operator empty to empty sealed", "[obse } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE( @@ -2939,8 +2926,8 @@ TEST_CASE( } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE( @@ -2959,8 +2946,8 @@ TEST_CASE( } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE( @@ -2979,8 +2966,8 @@ TEST_CASE( } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE( @@ -2998,8 +2985,8 @@ TEST_CASE( } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer comparison valid ptr vs nullptr", "[observer_comparison]") { @@ -3014,8 +3001,8 @@ TEST_CASE("observer comparison valid ptr vs nullptr", "[observer_comparison]") { REQUIRE(!(nullptr == ptr)); } - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer comparison invalid ptr vs nullptr", "[observer_comparison]") { @@ -3029,8 +3016,8 @@ TEST_CASE("observer comparison invalid ptr vs nullptr", "[observer_comparison]") REQUIRE(!(nullptr != ptr)); } - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer comparison invalid ptr vs invalid ptr", "[observer_comparison]") { @@ -3043,8 +3030,8 @@ TEST_CASE("observer comparison invalid ptr vs invalid ptr", "[observer_compariso REQUIRE(!(ptr1 != ptr2)); } - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer comparison invalid ptr vs valid ptr", "[observer_comparison]") { @@ -3060,8 +3047,8 @@ TEST_CASE("observer comparison invalid ptr vs valid ptr", "[observer_comparison] REQUIRE(!(ptr2 == ptr1)); } - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer comparison valid ptr vs valid ptr same owner", "[observer_comparison]") { @@ -3077,8 +3064,8 @@ TEST_CASE("observer comparison valid ptr vs valid ptr same owner", "[observer_co REQUIRE(!(ptr2 != ptr1)); } - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer comparison valid ptr vs valid ptr different owner", "[observer_comparison]") { @@ -3095,8 +3082,8 @@ TEST_CASE("observer comparison valid ptr vs valid ptr different owner", "[observ REQUIRE(!(ptr2 == ptr1)); } - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE( @@ -3113,8 +3100,8 @@ TEST_CASE( REQUIRE(!(ptr2 != ptr1)); } - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE( @@ -3132,8 +3119,8 @@ TEST_CASE( REQUIRE(!(ptr2 == ptr1)); } - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } struct observer_owner { @@ -3148,8 +3135,8 @@ TEST_CASE("object owning observer pointer to itself", "[system_tests]") { ptr->obs = ptr; } - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("object owning observer pointer to other", "[system_tests]") { @@ -3162,8 +3149,8 @@ TEST_CASE("object owning observer pointer to other", "[system_tests]") { ptr2->obs = ptr1; } - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("object owning observer pointer open chain", "[system_tests]") { @@ -3177,8 +3164,8 @@ TEST_CASE("object owning observer pointer open chain", "[system_tests]") { ptr2->obs = ptr3; } - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("object owning observer pointer open chain reversed", "[system_tests]") { @@ -3192,8 +3179,8 @@ TEST_CASE("object owning observer pointer open chain reversed", "[system_tests]" ptr2->obs = ptr1; } - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("object owning observer pointer closed chain interleaved", "[system_tests]") { @@ -3210,8 +3197,8 @@ TEST_CASE("object owning observer pointer closed chain interleaved", "[system_te ptr4->obs = ptr3; } - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("pointers in vector", "[system_tests]") { @@ -3254,8 +3241,8 @@ TEST_CASE("pointers in vector", "[system_tests]") { }) == true); } - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer from this unique", "[observer_from_this]") { @@ -3276,8 +3263,8 @@ TEST_CASE("observer from this unique", "[observer_from_this]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer from this sealed", "[observer_from_this]") { @@ -3299,8 +3286,8 @@ TEST_CASE("observer from this sealed", "[observer_from_this]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer from this non virtual unique", "[observer_from_this]") { @@ -3323,8 +3310,8 @@ TEST_CASE("observer from this non virtual unique", "[observer_from_this]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer from this maybe no block unique", "[observer_from_this]") { @@ -3347,8 +3334,8 @@ TEST_CASE("observer from this maybe no block unique", "[observer_from_this]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer from this maybe no block acquire", "[observer_from_this]") { @@ -3371,8 +3358,8 @@ TEST_CASE("observer from this maybe no block acquire", "[observer_from_this]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer from this maybe no block reset to new", "[observer_from_this]") { @@ -3401,8 +3388,8 @@ TEST_CASE("observer from this maybe no block reset to new", "[observer_from_this } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer from this maybe no block reset to new after release", "[observer_from_this]") { @@ -3444,8 +3431,8 @@ TEST_CASE("observer from this maybe no block reset to new after release", "[obse } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer from this maybe no block reset to new bad alloc", "[observer_from_this]") { @@ -3468,8 +3455,8 @@ TEST_CASE("observer from this maybe no block reset to new bad alloc", "[observer } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer from this virtual sealed", "[observer_from_this]") { @@ -3491,8 +3478,8 @@ TEST_CASE("observer from this virtual sealed", "[observer_from_this]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer from this derived", "[observer_from_this]") { @@ -3513,8 +3500,8 @@ TEST_CASE("observer from this derived", "[observer_from_this]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer from this derived into base", "[observer_from_this]") { @@ -3532,8 +3519,8 @@ TEST_CASE("observer from this derived into base", "[observer_from_this]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer from this derived into base after cast", "[observer_from_this]") { @@ -3556,8 +3543,8 @@ TEST_CASE("observer from this derived into base after cast", "[observer_from_thi } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer from this const", "[observer_from_this]") { @@ -3573,8 +3560,8 @@ TEST_CASE("observer from this const", "[observer_from_this]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer from this const sealed", "[observer_from_this]") { @@ -3591,8 +3578,8 @@ TEST_CASE("observer from this const sealed", "[observer_from_this]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer from this after move", "[observer_from_this]") { @@ -3614,8 +3601,8 @@ TEST_CASE("observer from this after move", "[observer_from_this]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer from this after move sealed", "[observer_from_this]") { @@ -3638,8 +3625,8 @@ TEST_CASE("observer from this after move sealed", "[observer_from_this]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer from this after move assignment", "[observer_from_this]") { @@ -3662,8 +3649,8 @@ TEST_CASE("observer from this after move assignment", "[observer_from_this]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer from this after move assignment sealed", "[observer_from_this]") { @@ -3687,8 +3674,8 @@ TEST_CASE("observer from this after move assignment sealed", "[observer_from_thi } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer from this after release", "[observer_from_this]") { @@ -3716,8 +3703,8 @@ TEST_CASE("observer from this after release", "[observer_from_this]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer from this after release and reset", "[observer_from_this]") { @@ -3742,8 +3729,8 @@ TEST_CASE("observer from this after release and reset", "[observer_from_this]") } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer from this stack", "[observer_from_this]") { @@ -3764,8 +3751,8 @@ TEST_CASE("observer from this stack", "[observer_from_this]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer from this heap", "[observer_from_this]") { @@ -3788,8 +3775,8 @@ TEST_CASE("observer from this heap", "[observer_from_this]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer from this stack virtual sealed", "[observer_from_this]") { @@ -3807,8 +3794,8 @@ TEST_CASE("observer from this stack virtual sealed", "[observer_from_this]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer from this heap virtual sealed", "[observer_from_this]") { @@ -3829,8 +3816,8 @@ TEST_CASE("observer from this heap virtual sealed", "[observer_from_this]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer from this multiple inheritance", "[observer_from_this]") { @@ -3858,8 +3845,8 @@ TEST_CASE("observer from this multiple inheritance", "[observer_from_this]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer from this in constructor", "[observer_from_this]") { @@ -3875,8 +3862,8 @@ TEST_CASE("observer from this in constructor", "[observer_from_this]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer from this in constructor sealed", "[observer_from_this]") { @@ -3892,8 +3879,8 @@ TEST_CASE("observer from this in constructor sealed", "[observer_from_this]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer from this in constructor multiple inheritance", "[observer_from_this]") { @@ -3909,8 +3896,8 @@ TEST_CASE("observer from this in constructor multiple inheritance", "[observer_f } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer from this in constructor multiple inheritance sealed", "[observer_from_this]") { @@ -3926,8 +3913,8 @@ TEST_CASE("observer from this in constructor multiple inheritance sealed", "[obs } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("observer from this in constructor sealed virtual throws", "[observer_from_this]") { @@ -3943,8 +3930,8 @@ TEST_CASE("observer from this in constructor sealed virtual throws", "[observer_ } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("bad_observer_from_this", "[observer_from_this]") { @@ -3954,8 +3941,8 @@ TEST_CASE("bad_observer_from_this", "[observer_from_this]") { REQUIRE(e.what() != nullptr); REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("static pointer cast unique from valid", "[pointer_cast]") { @@ -3972,8 +3959,8 @@ TEST_CASE("static pointer cast unique from valid", "[pointer_cast]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("static pointer cast unique from null", "[pointer_cast]") { @@ -3989,8 +3976,8 @@ TEST_CASE("static pointer cast unique from null", "[pointer_cast]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("static pointer cast sealed from valid", "[pointer_cast]") { @@ -4008,8 +3995,8 @@ TEST_CASE("static pointer cast sealed from valid", "[pointer_cast]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("static pointer cast sealed from null", "[pointer_cast]") { @@ -4025,8 +4012,8 @@ TEST_CASE("static pointer cast sealed from null", "[pointer_cast]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("static pointer cast observer copy from valid", "[pointer_cast]") { @@ -4044,8 +4031,8 @@ TEST_CASE("static pointer cast observer copy from valid", "[pointer_cast]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("static pointer cast observer copy from null", "[pointer_cast]") { @@ -4061,8 +4048,8 @@ TEST_CASE("static pointer cast observer copy from null", "[pointer_cast]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("static pointer cast observer move from valid", "[pointer_cast]") { @@ -4080,8 +4067,8 @@ TEST_CASE("static pointer cast observer move from valid", "[pointer_cast]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("static pointer cast observer move from null", "[pointer_cast]") { @@ -4097,8 +4084,8 @@ TEST_CASE("static pointer cast observer move from null", "[pointer_cast]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("const pointer cast unique from valid", "[pointer_cast]") { @@ -4115,8 +4102,8 @@ TEST_CASE("const pointer cast unique from valid", "[pointer_cast]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("const pointer cast unique from null", "[pointer_cast]") { @@ -4132,8 +4119,8 @@ TEST_CASE("const pointer cast unique from null", "[pointer_cast]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("const pointer cast sealed from valid", "[pointer_cast]") { @@ -4151,8 +4138,8 @@ TEST_CASE("const pointer cast sealed from valid", "[pointer_cast]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("const pointer cast sealed from null", "[pointer_cast]") { @@ -4168,8 +4155,8 @@ TEST_CASE("const pointer cast sealed from null", "[pointer_cast]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("const pointer cast observer copy from valid", "[pointer_cast]") { @@ -4187,8 +4174,8 @@ TEST_CASE("const pointer cast observer copy from valid", "[pointer_cast]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("const pointer cast observer copy from null", "[pointer_cast]") { @@ -4204,8 +4191,8 @@ TEST_CASE("const pointer cast observer copy from null", "[pointer_cast]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("const pointer cast observer move from valid", "[pointer_cast]") { @@ -4223,8 +4210,8 @@ TEST_CASE("const pointer cast observer move from valid", "[pointer_cast]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("const pointer cast observer move from null", "[pointer_cast]") { @@ -4240,8 +4227,8 @@ TEST_CASE("const pointer cast observer move from null", "[pointer_cast]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("dynamic pointer cast unique from valid", "[pointer_cast]") { @@ -4258,8 +4245,8 @@ TEST_CASE("dynamic pointer cast unique from valid", "[pointer_cast]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("dynamic pointer cast unique from invalid", "[pointer_cast]") { @@ -4276,8 +4263,8 @@ TEST_CASE("dynamic pointer cast unique from invalid", "[pointer_cast]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("dynamic pointer cast unique from null", "[pointer_cast]") { @@ -4293,8 +4280,8 @@ TEST_CASE("dynamic pointer cast unique from null", "[pointer_cast]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("dynamic pointer cast sealed from valid", "[pointer_cast]") { @@ -4312,8 +4299,8 @@ TEST_CASE("dynamic pointer cast sealed from valid", "[pointer_cast]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("dynamic pointer cast sealed from invalid", "[pointer_cast]") { @@ -4330,8 +4317,8 @@ TEST_CASE("dynamic pointer cast sealed from invalid", "[pointer_cast]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("dynamic pointer cast sealed from null", "[pointer_cast]") { @@ -4347,8 +4334,8 @@ TEST_CASE("dynamic pointer cast sealed from null", "[pointer_cast]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("dynamic pointer cast observer copy from valid", "[pointer_cast]") { @@ -4366,8 +4353,8 @@ TEST_CASE("dynamic pointer cast observer copy from valid", "[pointer_cast]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("dynamic pointer cast observer copy from invalid", "[pointer_cast]") { @@ -4385,8 +4372,8 @@ TEST_CASE("dynamic pointer cast observer copy from invalid", "[pointer_cast]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("dynamic pointer cast observer copy from null", "[pointer_cast]") { @@ -4402,8 +4389,8 @@ TEST_CASE("dynamic pointer cast observer copy from null", "[pointer_cast]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("dynamic pointer cast observer move from valid", "[pointer_cast]") { @@ -4421,8 +4408,8 @@ TEST_CASE("dynamic pointer cast observer move from valid", "[pointer_cast]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("dynamic pointer cast observer move from invalid", "[pointer_cast]") { @@ -4440,8 +4427,8 @@ TEST_CASE("dynamic pointer cast observer move from invalid", "[pointer_cast]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } TEST_CASE("dynamic pointer cast observer move from null", "[pointer_cast]") { @@ -4457,6 +4444,6 @@ TEST_CASE("dynamic pointer cast observer move from null", "[pointer_cast]") { } REQUIRE(instances == 0); - REQUIRE(mem_track.leaks() == 0u); - REQUIRE(mem_track.double_del() == 0u); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); } diff --git a/tests/runtime_tests_lifetime.cpp b/tests/runtime_tests_lifetime.cpp new file mode 100644 index 0000000..801dcd1 --- /dev/null +++ b/tests/runtime_tests_lifetime.cpp @@ -0,0 +1,101 @@ +#include "catch2_and_overrides.hpp" +#include "memory_tracker.hpp" +#include "tests_common2.hpp" + +TEMPLATE_LIST_TEST_CASE( + "release valid owner with observer", "[lifetime],[release],[owner],[observer]", owner_types) { + if constexpr (!is_sealed) { + memory_tracker mem_track; + + { + observer_ptr optr; + { + TestType ptr = make_pointer_deleter_1(); + auto* ptr_raw = ptr.get(); + + optr = ptr; + REQUIRE(optr.get() == ptr_raw); + REQUIRE(!optr.expired()); + + auto* ptr_released = ptr.release(); + REQUIRE(ptr_released == ptr_raw); + REQUIRE(ptr.get() == nullptr); + REQUIRE(optr.get() != nullptr); + REQUIRE(!optr.expired()); + + REQUIRE(instances == 1); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + REQUIRE(ptr.get_deleter().state_ == test_deleter::state::special_init_1); + } + + delete ptr_released; + } + + REQUIRE(optr.get() == nullptr); + REQUIRE(optr.expired()); + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); + } +} + +TEMPLATE_LIST_TEST_CASE( + "release valid owner with observer subobject", + "[lifetime],[release],[owner],[observer]", + owner_types) { + if constexpr (!is_sealed) { + memory_tracker mem_track; + + { + state_observer_ptr optr; + { + TestType ptr = make_pointer_deleter_1(); + auto* ptr_raw = ptr.get(); + + optr = state_observer_ptr{ptr, &ptr->state_}; + REQUIRE(optr.get() == &ptr_raw->state_); + REQUIRE(!optr.expired()); + + auto* ptr_released = ptr.release(); + REQUIRE(ptr_released == ptr_raw); + REQUIRE(ptr.get() == nullptr); + REQUIRE(optr.get() != nullptr); + REQUIRE(!optr.expired()); + + REQUIRE(instances == 1); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + REQUIRE(ptr.get_deleter().state_ == test_deleter::state::special_init_1); + } + + delete ptr_released; + } + + REQUIRE(optr.get() == nullptr); + REQUIRE(optr.expired()); + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); + } +} diff --git a/tests/runtime_tests_make_observable.cpp b/tests/runtime_tests_make_observable.cpp new file mode 100644 index 0000000..6c510fb --- /dev/null +++ b/tests/runtime_tests_make_observable.cpp @@ -0,0 +1,103 @@ +#include "catch2_and_overrides.hpp" +#include "memory_tracker.hpp" +#include "tests_common2.hpp" + +TEMPLATE_LIST_TEST_CASE("make observable", "[make_observable],[owner]", owner_types) { + if constexpr (can_use_make_observable) { + memory_tracker mem_track; + + { + TestType ptr = oup::make_observable, get_policy>(); + if constexpr (is_sealed) { + REQUIRE(mem_track.allocated() == 1u); + } else { + REQUIRE(mem_track.allocated() == 2u); + } + REQUIRE(instances == 1); + REQUIRE(ptr->state_ == test_object::state::default_init); + REQUIRE(ptr.get() != nullptr); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + REQUIRE(ptr.get_deleter().state_ == test_deleter::state::default_init); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); + } +} + +TEMPLATE_LIST_TEST_CASE( + "make observable with arguments", "[make_observable],[owner]", owner_types) { + if constexpr (can_use_make_observable) { + memory_tracker mem_track; + + { + TestType ptr = oup::make_observable, get_policy>( + test_object::state::special_init); + if constexpr (is_sealed) { + REQUIRE(mem_track.allocated() == 1u); + } else { + REQUIRE(mem_track.allocated() == 2u); + } + REQUIRE(instances == 1); + REQUIRE(ptr->state_ == test_object::state::special_init); + REQUIRE(ptr.get() != nullptr); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + REQUIRE(ptr.get_deleter().state_ == test_deleter::state::default_init); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); + } +} + +TEMPLATE_LIST_TEST_CASE( + "make observable throw in constructor", "[make_observable],[owner]", owner_types) { + if constexpr (can_use_make_observable) { + memory_tracker mem_track; + + next_test_object_constructor_throws = true; + REQUIRE_THROWS_AS( + (oup::make_observable, get_policy>()), + throw_constructor); + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); + } +} + +TEMPLATE_LIST_TEST_CASE("make observable bad alloc", "[make_observable],[owner]", owner_types) { + if constexpr (can_use_make_observable) { + memory_tracker mem_track; + + force_next_allocation_failure = true; + REQUIRE_THROWS_AS( + (oup::make_observable, get_policy>()), std::bad_alloc); + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); + } +} diff --git a/tests/runtime_tests_observer_assignment.cpp b/tests/runtime_tests_observer_assignment.cpp new file mode 100644 index 0000000..bb226f9 --- /dev/null +++ b/tests/runtime_tests_observer_assignment.cpp @@ -0,0 +1,317 @@ +#include "catch2_and_overrides.hpp" +#include "memory_tracker.hpp" +#include "tests_common2.hpp" + +// TEMPLATE_LIST_TEST_CASE( +// "owner move assignment operator valid to empty", "[assignment],[owner]", owner_types) { +// memory_tracker mem_track; + +// { +// TestType ptr_orig = make_pointer_deleter_1(); +// { +// TestType ptr = make_empty_pointer_deleter_2(); +// ptr = std::move(ptr_orig); +// REQUIRE(instances == 1); +// REQUIRE(ptr.get() != nullptr); +// if constexpr (has_stateful_deleter) { +// REQUIRE(instances_deleter == 2); +// REQUIRE(ptr.get_deleter().state_ == test_deleter::state::special_init_1); +// } +// } + +// REQUIRE(instances == 0); +// if constexpr (has_stateful_deleter) { +// REQUIRE(instances_deleter == 1); +// } +// } + +// REQUIRE(instances == 0); +// if constexpr (has_stateful_deleter) { +// REQUIRE(instances_deleter == 0); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEMPLATE_LIST_TEST_CASE( +// "owner move assignment operator empty to valid", "[assignment],[owner]", owner_types) { +// memory_tracker mem_track; + +// { +// TestType ptr_orig = make_empty_pointer_deleter_1(); +// { +// TestType ptr = make_pointer_deleter_2(); +// ptr = std::move(ptr_orig); +// REQUIRE(instances == 0); +// REQUIRE(ptr.get() == nullptr); +// if constexpr (has_stateful_deleter) { +// REQUIRE(instances_deleter == 2); +// REQUIRE(ptr.get_deleter().state_ == test_deleter::state::special_init_1); +// } +// } + +// REQUIRE(instances == 0); +// if constexpr (has_stateful_deleter) { +// REQUIRE(instances_deleter == 1); +// } +// } + +// REQUIRE(instances == 0); +// if constexpr (has_stateful_deleter) { +// REQUIRE(instances_deleter == 0); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEMPLATE_LIST_TEST_CASE( +// "owner move assignment operator empty to empty", "[assignment],[owner]", owner_types) { +// memory_tracker mem_track; + +// { +// TestType ptr_orig = make_empty_pointer_deleter_1(); +// { +// TestType ptr = make_empty_pointer_deleter_2(); +// ptr = std::move(ptr_orig); +// REQUIRE(instances == 0); +// REQUIRE(ptr.get() == nullptr); +// if constexpr (has_stateful_deleter) { +// REQUIRE(instances_deleter == 2); +// REQUIRE(ptr.get_deleter().state_ == test_deleter::state::special_init_1); +// } +// } + +// REQUIRE(instances == 0); +// if constexpr (has_stateful_deleter) { +// REQUIRE(instances_deleter == 1); +// } +// } + +// REQUIRE(instances == 0); +// if constexpr (has_stateful_deleter) { +// REQUIRE(instances_deleter == 0); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEMPLATE_LIST_TEST_CASE( +// "owner move assignment operator valid to valid", "[assignment],[owner]", owner_types) { +// memory_tracker mem_track; + +// { +// TestType ptr_orig = make_pointer_deleter_1(); +// auto* raw_ptr_orig = ptr_orig.get(); +// { +// TestType ptr = make_pointer_deleter_1(); +// ptr = std::move(ptr_orig); +// REQUIRE(instances == 1); +// REQUIRE(ptr.get() == raw_ptr_orig); +// if constexpr (has_stateful_deleter) { +// REQUIRE(instances_deleter == 2); +// REQUIRE(ptr.get_deleter().state_ == test_deleter::state::special_init_1); +// } +// } + +// REQUIRE(instances == 0); +// if constexpr (has_stateful_deleter) { +// REQUIRE(instances_deleter == 1); +// } +// } + +// REQUIRE(instances == 0); +// if constexpr (has_stateful_deleter) { +// REQUIRE(instances_deleter == 0); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEMPLATE_LIST_TEST_CASE( +// "owner move assignment converting operator valid to empty", +// "[assignment],[owner]", +// owner_types) { +// memory_tracker mem_track; + +// { +// TestType ptr_orig = make_pointer_deleter_1(); +// { +// base_ptr ptr = make_empty_pointer_deleter_2>(); +// ptr = std::move(ptr_orig); +// REQUIRE(instances == 1); +// REQUIRE(ptr.get() != nullptr); +// if constexpr (has_stateful_deleter) { +// REQUIRE(instances_deleter == 2); +// REQUIRE(ptr.get_deleter().state_ == test_deleter::state::special_init_1); +// } +// } + +// REQUIRE(instances == 0); +// if constexpr (has_stateful_deleter) { +// REQUIRE(instances_deleter == 1); +// } +// } + +// REQUIRE(instances == 0); +// if constexpr (has_stateful_deleter) { +// REQUIRE(instances_deleter == 0); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEMPLATE_LIST_TEST_CASE( +// "owner move assignment converting operator empty to valid", +// "[assignment],[owner]", +// owner_types) { +// memory_tracker mem_track; + +// { +// TestType ptr_orig = make_empty_pointer_deleter_1(); +// { +// base_ptr ptr = make_pointer_deleter_2>(); +// ptr = std::move(ptr_orig); +// REQUIRE(instances == 0); +// REQUIRE(ptr.get() == nullptr); +// if constexpr (has_stateful_deleter) { +// REQUIRE(instances_deleter == 2); +// REQUIRE(ptr.get_deleter().state_ == test_deleter::state::special_init_1); +// } +// } + +// REQUIRE(instances == 0); +// if constexpr (has_stateful_deleter) { +// REQUIRE(instances_deleter == 1); +// } +// } + +// REQUIRE(instances == 0); +// if constexpr (has_stateful_deleter) { +// REQUIRE(instances_deleter == 0); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEMPLATE_LIST_TEST_CASE( +// "owner move assignment converting operator empty to empty", +// "[assignment],[owner]", +// owner_types) { +// memory_tracker mem_track; + +// { +// TestType ptr_orig = make_empty_pointer_deleter_1(); +// { +// base_ptr ptr = make_empty_pointer_deleter_2>(); +// ptr = std::move(ptr_orig); +// REQUIRE(instances == 0); +// REQUIRE(ptr.get() == nullptr); +// if constexpr (has_stateful_deleter) { +// REQUIRE(instances_deleter == 2); +// REQUIRE(ptr.get_deleter().state_ == test_deleter::state::special_init_1); +// } +// } + +// REQUIRE(instances == 0); +// if constexpr (has_stateful_deleter) { +// REQUIRE(instances_deleter == 1); +// } +// } + +// REQUIRE(instances == 0); +// if constexpr (has_stateful_deleter) { +// REQUIRE(instances_deleter == 0); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEMPLATE_LIST_TEST_CASE( +// "owner move assignment converting operator valid to valid", +// "[assignment],[owner]", +// owner_types) { +// memory_tracker mem_track; + +// { +// TestType ptr_orig = make_pointer_deleter_1(); +// auto* raw_ptr_orig = ptr_orig.get(); +// { +// base_ptr ptr = make_pointer_deleter_1>(); +// ptr = std::move(ptr_orig); +// REQUIRE(instances == 1); +// REQUIRE(ptr.get() == raw_ptr_orig); +// if constexpr (has_stateful_deleter) { +// REQUIRE(instances_deleter == 2); +// REQUIRE(ptr.get_deleter().state_ == test_deleter::state::special_init_1); +// } +// } + +// REQUIRE(instances == 0); +// if constexpr (has_stateful_deleter) { +// REQUIRE(instances_deleter == 1); +// } +// } + +// REQUIRE(instances == 0); +// if constexpr (has_stateful_deleter) { +// REQUIRE(instances_deleter == 0); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEMPLATE_LIST_TEST_CASE( +// "owner move assignment operator self to self valid", "[assignment],[owner]", owner_types) { +// memory_tracker mem_track; + +// { +// TestType ptr = make_pointer_deleter_1(); +// ptr = std::move(ptr); +// REQUIRE(instances == 0); +// REQUIRE(ptr.get() == nullptr); +// if constexpr (has_stateful_deleter) { +// REQUIRE(instances_deleter == 1); +// REQUIRE(ptr.get_deleter().state_ == test_deleter::state::empty); +// } +// } + +// REQUIRE(instances == 0); +// if constexpr (has_stateful_deleter) { +// REQUIRE(instances_deleter == 0); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEMPLATE_LIST_TEST_CASE( +// "owner move assignment operator self to self empty", "[assignment],[owner]", owner_types) { +// memory_tracker mem_track; + +// { +// TestType ptr = make_empty_pointer_deleter_1(); +// ptr = std::move(ptr); +// REQUIRE(instances == 0); +// REQUIRE(ptr.get() == nullptr); +// if constexpr (has_stateful_deleter) { +// REQUIRE(instances_deleter == 1); +// REQUIRE(ptr.get_deleter().state_ == test_deleter::state::empty); +// } +// } + +// REQUIRE(instances == 0); +// if constexpr (has_stateful_deleter) { +// REQUIRE(instances_deleter == 0); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } diff --git a/tests/runtime_tests_observer_comparison.cpp b/tests/runtime_tests_observer_comparison.cpp new file mode 100644 index 0000000..dc07c7b --- /dev/null +++ b/tests/runtime_tests_observer_comparison.cpp @@ -0,0 +1,111 @@ +#include "catch2_and_overrides.hpp" +#include "memory_tracker.hpp" +#include "tests_common2.hpp" + +// TEMPLATE_LIST_TEST_CASE( +// "owner comparison valid ptr vs nullptr", "[comparison],[owner]", owner_types) { +// memory_tracker mem_track; + +// { +// TestType ptr = make_pointer_deleter_1(); +// REQUIRE(ptr != nullptr); +// REQUIRE(!(ptr == nullptr)); +// REQUIRE(nullptr != ptr); +// REQUIRE(!(nullptr == ptr)); +// } + +// REQUIRE(instances == 0); +// if constexpr (has_stateful_deleter) { +// REQUIRE(instances_deleter == 0); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEMPLATE_LIST_TEST_CASE( +// "owner comparison empty ptr vs nullptr", "[comparison],[owner]", owner_types) { +// memory_tracker mem_track; + +// { +// TestType ptr = make_empty_pointer_deleter_1(); +// REQUIRE(ptr == nullptr); +// REQUIRE(!(ptr != nullptr)); +// REQUIRE(nullptr == ptr); +// REQUIRE(!(nullptr != ptr)); +// } + +// REQUIRE(instances == 0); +// if constexpr (has_stateful_deleter) { +// REQUIRE(instances_deleter == 0); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEMPLATE_LIST_TEST_CASE( +// "owner comparison empty ptr vs empty ptr", "[comparison],[owner]", owner_types) { +// memory_tracker mem_track; + +// { +// TestType ptr1 = make_empty_pointer_deleter_1(); +// TestType ptr2 = make_empty_pointer_deleter_2(); +// REQUIRE(ptr1 == ptr2); +// REQUIRE(ptr2 == ptr1); +// REQUIRE(!(ptr1 != ptr2)); +// REQUIRE(!(ptr2 != ptr1)); +// } + +// REQUIRE(instances == 0); +// if constexpr (has_stateful_deleter) { +// REQUIRE(instances_deleter == 0); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEMPLATE_LIST_TEST_CASE( +// "owner comparison empty ptr vs valid ptr", "[comparison],[owner]", owner_types) { +// memory_tracker mem_track; + +// { +// TestType ptr1 = make_empty_pointer_deleter_1(); +// TestType ptr2 = make_pointer_deleter_2(); +// REQUIRE(ptr1 != ptr2); +// REQUIRE(ptr2 != ptr1); +// REQUIRE(!(ptr1 == ptr2)); +// REQUIRE(!(ptr2 == ptr1)); +// } + +// REQUIRE(instances == 0); +// if constexpr (has_stateful_deleter) { +// REQUIRE(instances_deleter == 0); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } + +// TEMPLATE_LIST_TEST_CASE( +// "owner comparison valid ptr vs valid ptr", "[comparison],[owner]", owner_types) { +// memory_tracker mem_track; + +// { +// TestType ptr1 = make_pointer_deleter_1(); +// TestType ptr2 = make_pointer_deleter_2(); +// REQUIRE(ptr1 != ptr2); +// REQUIRE(ptr2 != ptr1); +// REQUIRE(!(ptr1 == ptr2)); +// REQUIRE(!(ptr2 == ptr1)); +// } + +// REQUIRE(instances == 0); +// if constexpr (has_stateful_deleter) { +// REQUIRE(instances_deleter == 0); +// } + +// REQUIRE(mem_track.allocated() == 0u); +// REQUIRE(mem_track.double_delete() == 0u); +// } diff --git a/tests/runtime_tests_observer_construction.cpp b/tests/runtime_tests_observer_construction.cpp new file mode 100644 index 0000000..cab1398 --- /dev/null +++ b/tests/runtime_tests_observer_construction.cpp @@ -0,0 +1,221 @@ +#include "catch2_and_overrides.hpp" +#include "memory_tracker.hpp" +#include "tests_common2.hpp" + +TEMPLATE_LIST_TEST_CASE("observer default constructor", "[construction],[observer]", owner_types) { + memory_tracker mem_track; + + { + observer_ptr ptr; + REQUIRE(instances == 0); + REQUIRE(ptr.get() == nullptr); + REQUIRE(ptr.expired() == true); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); +} + +TEMPLATE_LIST_TEST_CASE("observer nullptr constructor", "[construction],[observer]", owner_types) { + memory_tracker mem_track; + + { + observer_ptr ptr(nullptr); + REQUIRE(instances == 0); + REQUIRE(ptr.get() == nullptr); + REQUIRE(ptr.expired() == true); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); +} + +TEMPLATE_LIST_TEST_CASE( + "observer copy constructor valid", "[construction],[observer]", owner_types) { + memory_tracker mem_track; + + { + TestType ptr_owner = make_pointer_deleter_1(); + observer_ptr ptr_orig{ptr_owner}; + { + observer_ptr ptr(ptr_orig); + REQUIRE(ptr.get() != nullptr); + REQUIRE(ptr.expired() == false); + REQUIRE(ptr_orig.get() != nullptr); + REQUIRE(ptr_orig.expired() == false); + REQUIRE(instances == 1); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + } + } + + REQUIRE(instances == 1); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); +} + +TEMPLATE_LIST_TEST_CASE( + "observer copy constructor empty", "[construction],[observer]", owner_types) { + memory_tracker mem_track; + + { + observer_ptr ptr_orig; + { + observer_ptr ptr(ptr_orig); + REQUIRE(ptr.get() == nullptr); + REQUIRE(ptr.expired() == true); + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); +} + +TEMPLATE_LIST_TEST_CASE( + "observer explicit conversion copy constructor", "[construction],[observer]", owner_types) { + if constexpr (has_base) { + memory_tracker mem_track; + + { + base_ptr ptr_owner = make_pointer_deleter_1(); + base_observer_ptr ptr_orig{ptr_owner}; + { + observer_ptr ptr{ + ptr_orig, static_cast*>(ptr_orig.get())}; + REQUIRE(ptr.get() == static_cast*>(ptr_owner.get())); + REQUIRE(ptr.expired() == false); + REQUIRE(ptr_orig.get() == ptr_owner.get()); + REQUIRE(ptr_orig.expired() == false); + REQUIRE(instances == 1); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + } + } + + REQUIRE(instances == 1); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); + } +} + +TEMPLATE_LIST_TEST_CASE( + "observer explicit conversion copy constructor null pointer", + "[construction],[observer]", + owner_types) { + memory_tracker mem_track; + + { + TestType ptr_owner = make_pointer_deleter_1(); + observer_ptr ptr_orig{ptr_owner}; + { + observer_ptr ptr{ptr_orig, static_cast*>(nullptr)}; + REQUIRE(ptr.get() == nullptr); + REQUIRE(ptr.expired() == true); + REQUIRE(ptr_orig.get() == ptr_owner.get()); + REQUIRE(ptr_orig.expired() == false); + REQUIRE(instances == 1); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + } + } + + REQUIRE(instances == 1); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); +} + +TEMPLATE_LIST_TEST_CASE( + "observer explicit conversion copy constructor subobject", + "[construction],[observer]", + owner_types) { + memory_tracker mem_track; + + { + TestType ptr_owner = make_pointer_deleter_1(); + observer_ptr ptr_orig{ptr_owner}; + { + state_observer_ptr ptr{ptr_orig, &ptr_owner->state_}; + REQUIRE(ptr.get() == &ptr_owner->state_); + REQUIRE(ptr.expired() == false); + REQUIRE(ptr_orig.get() == ptr_owner.get()); + REQUIRE(ptr_orig.expired() == false); + REQUIRE(instances == 1); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + } + } + + REQUIRE(instances == 1); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); +} diff --git a/tests/runtime_tests_observer_misc.cpp b/tests/runtime_tests_observer_misc.cpp new file mode 100644 index 0000000..bcb59b9 --- /dev/null +++ b/tests/runtime_tests_observer_misc.cpp @@ -0,0 +1,7 @@ +#include "catch2_and_overrides.hpp" +#include "memory_tracker.hpp" +#include "tests_common2.hpp" + +TEMPLATE_LIST_TEST_CASE("observer size", "[size],[observer]", owner_types) { + REQUIRE(sizeof(observer_ptr) == 2 * sizeof(void*)); +} diff --git a/tests/runtime_tests_owner_assignment.cpp b/tests/runtime_tests_owner_assignment.cpp new file mode 100644 index 0000000..cec0706 --- /dev/null +++ b/tests/runtime_tests_owner_assignment.cpp @@ -0,0 +1,317 @@ +#include "catch2_and_overrides.hpp" +#include "memory_tracker.hpp" +#include "tests_common2.hpp" + +TEMPLATE_LIST_TEST_CASE( + "owner move assignment operator valid to empty", "[assignment],[owner]", owner_types) { + memory_tracker mem_track; + + { + TestType ptr_orig = make_pointer_deleter_1(); + { + TestType ptr = make_empty_pointer_deleter_2(); + ptr = std::move(ptr_orig); + REQUIRE(instances == 1); + REQUIRE(ptr.get() != nullptr); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 2); + REQUIRE(ptr.get_deleter().state_ == test_deleter::state::special_init_1); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); +} + +TEMPLATE_LIST_TEST_CASE( + "owner move assignment operator empty to valid", "[assignment],[owner]", owner_types) { + memory_tracker mem_track; + + { + TestType ptr_orig = make_empty_pointer_deleter_1(); + { + TestType ptr = make_pointer_deleter_2(); + ptr = std::move(ptr_orig); + REQUIRE(instances == 0); + REQUIRE(ptr.get() == nullptr); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 2); + REQUIRE(ptr.get_deleter().state_ == test_deleter::state::special_init_1); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); +} + +TEMPLATE_LIST_TEST_CASE( + "owner move assignment operator empty to empty", "[assignment],[owner]", owner_types) { + memory_tracker mem_track; + + { + TestType ptr_orig = make_empty_pointer_deleter_1(); + { + TestType ptr = make_empty_pointer_deleter_2(); + ptr = std::move(ptr_orig); + REQUIRE(instances == 0); + REQUIRE(ptr.get() == nullptr); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 2); + REQUIRE(ptr.get_deleter().state_ == test_deleter::state::special_init_1); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); +} + +TEMPLATE_LIST_TEST_CASE( + "owner move assignment operator valid to valid", "[assignment],[owner]", owner_types) { + memory_tracker mem_track; + + { + TestType ptr_orig = make_pointer_deleter_1(); + auto* raw_ptr_orig = ptr_orig.get(); + { + TestType ptr = make_pointer_deleter_1(); + ptr = std::move(ptr_orig); + REQUIRE(instances == 1); + REQUIRE(ptr.get() == raw_ptr_orig); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 2); + REQUIRE(ptr.get_deleter().state_ == test_deleter::state::special_init_1); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); +} + +TEMPLATE_LIST_TEST_CASE( + "owner move assignment converting operator valid to empty", + "[assignment],[owner]", + owner_types) { + memory_tracker mem_track; + + { + TestType ptr_orig = make_pointer_deleter_1(); + { + base_ptr ptr = make_empty_pointer_deleter_2>(); + ptr = std::move(ptr_orig); + REQUIRE(instances == 1); + REQUIRE(ptr.get() != nullptr); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 2); + REQUIRE(ptr.get_deleter().state_ == test_deleter::state::special_init_1); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); +} + +TEMPLATE_LIST_TEST_CASE( + "owner move assignment converting operator empty to valid", + "[assignment],[owner]", + owner_types) { + memory_tracker mem_track; + + { + TestType ptr_orig = make_empty_pointer_deleter_1(); + { + base_ptr ptr = make_pointer_deleter_2>(); + ptr = std::move(ptr_orig); + REQUIRE(instances == 0); + REQUIRE(ptr.get() == nullptr); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 2); + REQUIRE(ptr.get_deleter().state_ == test_deleter::state::special_init_1); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); +} + +TEMPLATE_LIST_TEST_CASE( + "owner move assignment converting operator empty to empty", + "[assignment],[owner]", + owner_types) { + memory_tracker mem_track; + + { + TestType ptr_orig = make_empty_pointer_deleter_1(); + { + base_ptr ptr = make_empty_pointer_deleter_2>(); + ptr = std::move(ptr_orig); + REQUIRE(instances == 0); + REQUIRE(ptr.get() == nullptr); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 2); + REQUIRE(ptr.get_deleter().state_ == test_deleter::state::special_init_1); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); +} + +TEMPLATE_LIST_TEST_CASE( + "owner move assignment converting operator valid to valid", + "[assignment],[owner]", + owner_types) { + memory_tracker mem_track; + + { + TestType ptr_orig = make_pointer_deleter_1(); + auto* raw_ptr_orig = ptr_orig.get(); + { + base_ptr ptr = make_pointer_deleter_1>(); + ptr = std::move(ptr_orig); + REQUIRE(instances == 1); + REQUIRE(ptr.get() == raw_ptr_orig); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 2); + REQUIRE(ptr.get_deleter().state_ == test_deleter::state::special_init_1); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); +} + +TEMPLATE_LIST_TEST_CASE( + "owner move assignment operator self to self valid", "[assignment],[owner]", owner_types) { + memory_tracker mem_track; + + { + TestType ptr = make_pointer_deleter_1(); + ptr = std::move(ptr); + REQUIRE(instances == 0); + REQUIRE(ptr.get() == nullptr); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + REQUIRE(ptr.get_deleter().state_ == test_deleter::state::empty); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); +} + +TEMPLATE_LIST_TEST_CASE( + "owner move assignment operator self to self empty", "[assignment],[owner]", owner_types) { + memory_tracker mem_track; + + { + TestType ptr = make_empty_pointer_deleter_1(); + ptr = std::move(ptr); + REQUIRE(instances == 0); + REQUIRE(ptr.get() == nullptr); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + REQUIRE(ptr.get_deleter().state_ == test_deleter::state::empty); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); +} diff --git a/tests/runtime_tests_owner_comparison.cpp b/tests/runtime_tests_owner_comparison.cpp new file mode 100644 index 0000000..0bd6cc1 --- /dev/null +++ b/tests/runtime_tests_owner_comparison.cpp @@ -0,0 +1,111 @@ +#include "catch2_and_overrides.hpp" +#include "memory_tracker.hpp" +#include "tests_common2.hpp" + +TEMPLATE_LIST_TEST_CASE( + "owner comparison valid ptr vs nullptr", "[comparison],[owner]", owner_types) { + memory_tracker mem_track; + + { + TestType ptr = make_pointer_deleter_1(); + REQUIRE(ptr != nullptr); + REQUIRE(!(ptr == nullptr)); + REQUIRE(nullptr != ptr); + REQUIRE(!(nullptr == ptr)); + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); +} + +TEMPLATE_LIST_TEST_CASE( + "owner comparison empty ptr vs nullptr", "[comparison],[owner]", owner_types) { + memory_tracker mem_track; + + { + TestType ptr = make_empty_pointer_deleter_1(); + REQUIRE(ptr == nullptr); + REQUIRE(!(ptr != nullptr)); + REQUIRE(nullptr == ptr); + REQUIRE(!(nullptr != ptr)); + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); +} + +TEMPLATE_LIST_TEST_CASE( + "owner comparison empty ptr vs empty ptr", "[comparison],[owner]", owner_types) { + memory_tracker mem_track; + + { + TestType ptr1 = make_empty_pointer_deleter_1(); + TestType ptr2 = make_empty_pointer_deleter_2(); + REQUIRE(ptr1 == ptr2); + REQUIRE(ptr2 == ptr1); + REQUIRE(!(ptr1 != ptr2)); + REQUIRE(!(ptr2 != ptr1)); + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); +} + +TEMPLATE_LIST_TEST_CASE( + "owner comparison empty ptr vs valid ptr", "[comparison],[owner]", owner_types) { + memory_tracker mem_track; + + { + TestType ptr1 = make_empty_pointer_deleter_1(); + TestType ptr2 = make_pointer_deleter_2(); + REQUIRE(ptr1 != ptr2); + REQUIRE(ptr2 != ptr1); + REQUIRE(!(ptr1 == ptr2)); + REQUIRE(!(ptr2 == ptr1)); + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); +} + +TEMPLATE_LIST_TEST_CASE( + "owner comparison valid ptr vs valid ptr", "[comparison],[owner]", owner_types) { + memory_tracker mem_track; + + { + TestType ptr1 = make_pointer_deleter_1(); + TestType ptr2 = make_pointer_deleter_2(); + REQUIRE(ptr1 != ptr2); + REQUIRE(ptr2 != ptr1); + REQUIRE(!(ptr1 == ptr2)); + REQUIRE(!(ptr2 == ptr1)); + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); +} diff --git a/tests/runtime_tests_owner_construction.cpp b/tests/runtime_tests_owner_construction.cpp new file mode 100644 index 0000000..2d025f0 --- /dev/null +++ b/tests/runtime_tests_owner_construction.cpp @@ -0,0 +1,409 @@ +#include "catch2_and_overrides.hpp" +#include "memory_tracker.hpp" +#include "tests_common2.hpp" + +TEMPLATE_LIST_TEST_CASE("owner default constructor", "[construction],[owner]", owner_types) { + memory_tracker mem_track; + + { + TestType ptr; + REQUIRE(instances == 0); + REQUIRE(ptr.get() == nullptr); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + REQUIRE(ptr.get_deleter().state_ == test_deleter::state::default_init); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); +} + +TEMPLATE_LIST_TEST_CASE("owner nullptr constructor", "[construction],[owner]", owner_types) { + memory_tracker mem_track; + + { + TestType ptr(nullptr); + REQUIRE(instances == 0); + REQUIRE(ptr.get() == nullptr); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + REQUIRE(ptr.get_deleter().state_ == test_deleter::state::default_init); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); +} + +TEMPLATE_LIST_TEST_CASE("owner move constructor", "[construction],[owner]", owner_types) { + memory_tracker mem_track; + + { + TestType ptr_orig = make_pointer_deleter_1(); + { + TestType ptr(std::move(ptr_orig)); + REQUIRE(instances == 1); + REQUIRE(ptr.get() != nullptr); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 2); + REQUIRE(ptr.get_deleter().state_ == test_deleter::state::special_init_1); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); +} + +TEMPLATE_LIST_TEST_CASE("owner acquiring constructor", "[construction],[owner]", owner_types) { + if constexpr (!must_use_make_observable) { + memory_tracker mem_track; + + { + TestType ptr(make_instance()); + REQUIRE(instances == 1); + REQUIRE(ptr.get() != nullptr); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + REQUIRE(ptr.get_deleter().state_ == test_deleter::state::default_init); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); + } +} + +TEMPLATE_LIST_TEST_CASE( + "owner acquiring constructor with deleter", "[construction],[owner]", owner_types) { + if constexpr (!must_use_make_observable && has_stateful_deleter) { + memory_tracker mem_track; + + { + TestType ptr(make_instance(), make_deleter_instance_1()); + REQUIRE(instances == 1); + REQUIRE(ptr.get() != nullptr); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + REQUIRE(ptr.get_deleter().state_ == test_deleter::state::special_init_1); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); + } +} + +TEMPLATE_LIST_TEST_CASE( + "owner acquiring constructor bad alloc", "[construction],[owner]", owner_types) { + if constexpr (!must_use_make_observable) { + memory_tracker mem_track; + + { + auto* raw_ptr = make_instance(); + bool has_thrown = false; + try { + force_next_allocation_failure = true; + TestType{raw_ptr}; + force_next_allocation_failure = false; + } catch (const std::bad_alloc&) { + has_thrown = true; + } + + if constexpr (eoft_allocates) { + REQUIRE(!has_thrown); + } else { + REQUIRE(has_thrown); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); + } +} + +TEMPLATE_LIST_TEST_CASE( + "owner acquiring constructor bad alloc with deleter", "[construction],[owner]", owner_types) { + if constexpr ( + !must_use_make_observable && !eoft_allocates && + has_stateful_deleter) { + memory_tracker mem_track; + + { + auto* raw_ptr = make_instance(); + auto deleter = make_deleter_instance_1(); + bool has_thrown = false; + try { + force_next_allocation_failure = true; + TestType{raw_ptr, deleter}; + force_next_allocation_failure = false; + } catch (const std::bad_alloc&) { + has_thrown = true; + } + + REQUIRE(has_thrown); + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); + } +} + +TEMPLATE_LIST_TEST_CASE("owner acquiring constructor null", "[construction],[owner]", owner_types) { + if constexpr (!must_use_make_observable) { + memory_tracker mem_track; + + { + TestType ptr(static_cast*>(nullptr)); + REQUIRE(instances == 0); + REQUIRE(ptr.get() == nullptr); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + REQUIRE(ptr.get_deleter().state_ == test_deleter::state::default_init); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); + } +} + +TEMPLATE_LIST_TEST_CASE( + "owner implicit conversion constructor", "[construction],[owner]", owner_types) { + if constexpr (has_base) { + memory_tracker mem_track; + + { + TestType ptr_orig = make_pointer_deleter_1(); + { + base_ptr ptr(std::move(ptr_orig)); + REQUIRE(instances == 1); + REQUIRE(instances_derived == 1); + REQUIRE(ptr.get() != nullptr); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 2); + REQUIRE(ptr.get_deleter().state_ == test_deleter::state::special_init_1); + } + } + + REQUIRE(instances == 0); + REQUIRE(instances_derived == 0); + REQUIRE(ptr_orig.get() == nullptr); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + } + } + + REQUIRE(instances == 0); + REQUIRE(instances_derived == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); + } +} + +TEMPLATE_LIST_TEST_CASE( + "owner explicit conversion constructor", "[construction],[owner]", owner_types) { + if constexpr (has_base) { + memory_tracker mem_track; + + { + base_ptr ptr_orig = make_pointer_deleter_1(); + { + TestType ptr( + std::move(ptr_orig), dynamic_cast*>(ptr_orig.get())); + REQUIRE(instances == 1); + REQUIRE(instances_derived == 1); + REQUIRE(ptr.get() != nullptr); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 2); + REQUIRE(ptr.get_deleter().state_ == test_deleter::state::special_init_1); + } + } + + REQUIRE(instances == 0); + REQUIRE(instances_derived == 0); + REQUIRE(ptr_orig.get() == nullptr); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + } + } + + REQUIRE(instances == 0); + REQUIRE(instances_derived == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); + } +} + +TEMPLATE_LIST_TEST_CASE( + "owner explicit conversion constructor with custom deleter", + "[construction],[owner]", + owner_types) { + if constexpr (has_base && has_stateful_deleter) { + memory_tracker mem_track; + + { + base_ptr ptr_orig = make_pointer_deleter_1(); + { + TestType ptr( + std::move(ptr_orig), dynamic_cast*>(ptr_orig.get()), + make_deleter_instance_2()); + REQUIRE(instances == 1); + REQUIRE(instances_derived == 1); + REQUIRE(ptr.get() != nullptr); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 2); + REQUIRE(ptr.get_deleter().state_ == test_deleter::state::special_init_2); + } + } + + REQUIRE(instances == 0); + REQUIRE(instances_derived == 0); + REQUIRE(ptr_orig.get() == nullptr); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + } + } + + REQUIRE(instances == 0); + REQUIRE(instances_derived == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); + } +} + +TEMPLATE_LIST_TEST_CASE( + "owner explicit conversion constructor with null", "[construction],[owner]", owner_types) { + if constexpr (has_base) { + memory_tracker mem_track; + + { + base_ptr ptr_orig = make_pointer_deleter_1(); + { + TestType ptr(std::move(ptr_orig), static_cast*>(nullptr)); + REQUIRE(instances == 0); + REQUIRE(instances_derived == 0); + REQUIRE(ptr.get() == nullptr); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 2); + REQUIRE(ptr.get_deleter().state_ == test_deleter::state::special_init_1); + } + } + + REQUIRE(instances == 0); + REQUIRE(instances_derived == 0); + REQUIRE(ptr_orig.get() == nullptr); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + } + } + + REQUIRE(instances == 0); + REQUIRE(instances_derived == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); + } +} + +TEMPLATE_LIST_TEST_CASE( + "owner explicit conversion constructor with custom deleter with null", + "[construction],[owner]", + owner_types) { + if constexpr (has_base && has_stateful_deleter) { + memory_tracker mem_track; + + { + base_ptr ptr_orig = make_pointer_deleter_1(); + { + TestType ptr( + std::move(ptr_orig), static_cast*>(nullptr), + make_deleter_instance_2()); + REQUIRE(instances == 0); + REQUIRE(instances_derived == 0); + REQUIRE(ptr.get() == nullptr); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 2); + REQUIRE(ptr.get_deleter().state_ == test_deleter::state::special_init_2); + } + } + + REQUIRE(instances == 0); + REQUIRE(instances_derived == 0); + REQUIRE(ptr_orig.get() == nullptr); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + } + } + + REQUIRE(instances == 0); + REQUIRE(instances_derived == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); + } +} diff --git a/tests/runtime_tests_owner_misc.cpp b/tests/runtime_tests_owner_misc.cpp new file mode 100644 index 0000000..d6173a1 --- /dev/null +++ b/tests/runtime_tests_owner_misc.cpp @@ -0,0 +1,407 @@ +#include "catch2_and_overrides.hpp" +#include "memory_tracker.hpp" +#include "tests_common2.hpp" + +TEMPLATE_LIST_TEST_CASE("owner size", "[size],[owner]", owner_types) { + using deleter_type = get_deleter; + + constexpr auto round_up = [](std::size_t i, std::size_t m) { + return i % m == 0 ? i : i + m - i % m; + }; + + // The deleter should have no overhead when stateless. + // Otherwise, the overhead should be exactly the size of the deleter, modulo alignment. + constexpr std::size_t deleter_overhead = + std::is_empty_v + ? 0 + : round_up(sizeof(deleter_type), std::max(alignof(deleter_type), alignof(void*))); + + REQUIRE(sizeof(TestType) == 2 * sizeof(void*) + deleter_overhead); +} + +TEMPLATE_LIST_TEST_CASE("owner reset to null", "[reset],[owner]", owner_types) { + memory_tracker mem_track; + + { + TestType ptr = make_pointer_deleter_1(); + ptr.reset(); + REQUIRE(instances == 0); + REQUIRE(ptr.get() == nullptr); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + REQUIRE(ptr.get_deleter().state_ == test_deleter::state::special_init_1); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); +} + +TEMPLATE_LIST_TEST_CASE("owner reset to new", "[reset],[owner]", owner_types) { + if constexpr (!must_use_make_observable) { + memory_tracker mem_track; + + { + TestType ptr = make_pointer_deleter_1(); + auto* raw_ptr_orig = ptr.get(); + ptr.reset(make_instance()); + REQUIRE(instances == 1); + REQUIRE(ptr.get() != nullptr); + REQUIRE(ptr.get() != raw_ptr_orig); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + REQUIRE(ptr.get_deleter().state_ == test_deleter::state::special_init_1); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); + } +} + +TEMPLATE_LIST_TEST_CASE("owner reset to new bad alloc", "[reset],[owner]", owner_types) { + if constexpr (!must_use_make_observable) { + memory_tracker mem_track; + + { + auto* raw_ptr1 = make_instance(); + auto* raw_ptr2 = make_instance(); + TestType ptr(raw_ptr1); + bool has_thrown = false; + try { + force_next_allocation_failure = true; + ptr.reset(raw_ptr2); + force_next_allocation_failure = false; + } catch (const std::bad_alloc&) { + has_thrown = true; + } + + if constexpr (eoft_allocates) { + REQUIRE(!has_thrown); + } else { + REQUIRE(has_thrown); + } + + REQUIRE(instances == 1); + if (has_thrown) { + REQUIRE(ptr.get() != raw_ptr2); + REQUIRE(ptr.get() == raw_ptr1); + } else { + REQUIRE(ptr.get() != raw_ptr1); + REQUIRE(ptr.get() == raw_ptr2); + } + } + + REQUIRE(instances == 0); + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); + } +} + +TEMPLATE_LIST_TEST_CASE("owner swap empty vs empty", "[swap],[owner]", owner_types) { + memory_tracker mem_track; + + { + TestType ptr1 = make_empty_pointer_deleter_1(); + TestType ptr2 = make_empty_pointer_deleter_2(); + ptr2.swap(ptr1); + REQUIRE(instances == 0); + REQUIRE(ptr1.get() == nullptr); + REQUIRE(ptr2.get() == nullptr); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 2); + REQUIRE(ptr1.get_deleter().state_ == test_deleter::state::special_init_2); + REQUIRE(ptr2.get_deleter().state_ == test_deleter::state::special_init_1); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); +} + +TEMPLATE_LIST_TEST_CASE("owner swap valid vs empty", "[swap],[owner]", owner_types) { + memory_tracker mem_track; + + { + TestType ptr1 = make_pointer_deleter_1(); + TestType ptr2 = make_empty_pointer_deleter_2(); + ptr2.swap(ptr1); + REQUIRE(instances == 1); + REQUIRE(ptr1.get() == nullptr); + REQUIRE(ptr2.get() != nullptr); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 2); + REQUIRE(ptr1.get_deleter().state_ == test_deleter::state::special_init_2); + REQUIRE(ptr2.get_deleter().state_ == test_deleter::state::special_init_1); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); +} + +TEMPLATE_LIST_TEST_CASE("owner swap empty vs valid", "[swap],[owner]", owner_types) { + memory_tracker mem_track; + + { + TestType ptr1 = make_empty_pointer_deleter_1(); + TestType ptr2 = make_pointer_deleter_2(); + ptr2.swap(ptr1); + REQUIRE(instances == 1); + REQUIRE(ptr1.get() != nullptr); + REQUIRE(ptr2.get() == nullptr); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 2); + REQUIRE(ptr1.get_deleter().state_ == test_deleter::state::special_init_2); + REQUIRE(ptr2.get_deleter().state_ == test_deleter::state::special_init_1); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); +} + +TEMPLATE_LIST_TEST_CASE("owner swap valid vs valid", "[swap],[owner]", owner_types) { + memory_tracker mem_track; + + { + TestType ptr1 = make_pointer_deleter_1(); + TestType ptr2 = make_pointer_deleter_2(); + auto* raw_ptr1 = ptr1.get(); + auto* raw_ptr2 = ptr2.get(); + ptr2.swap(ptr1); + REQUIRE(instances == 2); + REQUIRE(ptr1.get() != raw_ptr1); + REQUIRE(ptr1.get() == raw_ptr2); + REQUIRE(ptr2.get() != raw_ptr2); + REQUIRE(ptr2.get() == raw_ptr1); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 2); + REQUIRE(ptr1.get_deleter().state_ == test_deleter::state::special_init_2); + REQUIRE(ptr2.get_deleter().state_ == test_deleter::state::special_init_1); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); +} + +TEMPLATE_LIST_TEST_CASE("owner swap self vs self empty", "[swap],[owner]", owner_types) { + memory_tracker mem_track; + + { + TestType ptr = make_empty_pointer_deleter_1(); + ptr.swap(ptr); + REQUIRE(instances == 0); + REQUIRE(ptr.get() == nullptr); + if constexpr (has_stateful_deleter) { + REQUIRE(ptr.get_deleter().state_ == test_deleter::state::special_init_1); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); +} + +TEMPLATE_LIST_TEST_CASE("owner swap self vs self valid", "[swap],[owner]", owner_types) { + memory_tracker mem_track; + + { + TestType ptr = make_pointer_deleter_1(); + ptr.swap(ptr); + REQUIRE(instances == 1); + REQUIRE(ptr.get() != nullptr); + if constexpr (has_stateful_deleter) { + REQUIRE(ptr.get_deleter().state_ == test_deleter::state::special_init_1); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); +} + +TEMPLATE_LIST_TEST_CASE("owner dereference", "[dereference],[owner]", owner_types) { + memory_tracker mem_track; + + { + TestType ptr = make_pointer_deleter_1(); + REQUIRE(ptr->state_ == test_object::state::default_init); + REQUIRE((*ptr).state_ == test_object::state::default_init); + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); +} + +TEMPLATE_LIST_TEST_CASE("owner get valid", "[get],[owner]", owner_types) { + memory_tracker mem_track; + + { + TestType ptr = make_pointer_deleter_1(); + REQUIRE(ptr.get() != nullptr); + REQUIRE(ptr.get()->state_ == test_object::state::default_init); + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); +} + +TEMPLATE_LIST_TEST_CASE("owner get empty", "[get],[owner]", owner_types) { + memory_tracker mem_track; + + { + TestType ptr = make_empty_pointer_deleter_1(); + REQUIRE(ptr.get() == nullptr); + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); +} + +TEMPLATE_LIST_TEST_CASE("owner operator bool valid", "[bool],[owner]", owner_types) { + memory_tracker mem_track; + + { + TestType ptr = make_pointer_deleter_1(); + if (ptr) { + } else { + FAIL("if (ptr) should have been true"); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); +} + +TEMPLATE_LIST_TEST_CASE("owner operator bool empty", "[bool],[owner]", owner_types) { + memory_tracker mem_track; + + { + TestType ptr = make_empty_pointer_deleter_1(); + if (ptr) { + FAIL("if (ptr) should have been true"); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); +} + +TEMPLATE_LIST_TEST_CASE("owner release valid", "[release],[owner]", owner_types) { + if constexpr (!is_sealed) { + memory_tracker mem_track; + + { + TestType ptr = make_pointer_deleter_1(); + auto* ptr_raw = ptr.get(); + auto* ptr_released = ptr.release(); + REQUIRE(ptr_released == ptr_raw); + REQUIRE(ptr.get() == nullptr); + REQUIRE(instances == 1); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + REQUIRE(ptr.get_deleter().state_ == test_deleter::state::special_init_1); + } + delete ptr_released; + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); + } +} + +TEMPLATE_LIST_TEST_CASE("owner release empty", "[release],[owner]", owner_types) { + if constexpr (!is_sealed) { + memory_tracker mem_track; + + { + TestType ptr = make_empty_pointer_deleter_1(); + auto* ptr_released = ptr.release(); + REQUIRE(ptr_released == nullptr); + REQUIRE(ptr.get() == nullptr); + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 1); + REQUIRE(ptr.get_deleter().state_ == test_deleter::state::special_init_1); + } + } + + REQUIRE(instances == 0); + if constexpr (has_stateful_deleter) { + REQUIRE(instances_deleter == 0); + } + + REQUIRE(mem_track.allocated() == 0u); + REQUIRE(mem_track.double_delete() == 0u); + } +} diff --git a/tests/size_benchmark.cpp b/tests/size_benchmark.cpp index c75db73..0687284 100644 --- a/tests/size_benchmark.cpp +++ b/tests/size_benchmark.cpp @@ -1,4 +1,3 @@ -#define CHECK_MEMORY_LEAKS #include "memory_tracker.hpp" #include diff --git a/tests/tests_common2.cpp b/tests/tests_common2.cpp new file mode 100644 index 0000000..ee981a8 --- /dev/null +++ b/tests/tests_common2.cpp @@ -0,0 +1,7 @@ +#include "tests_common2.hpp" + +int instances = 0; +int instances_derived = 0; +int instances_deleter = 0; + +bool next_test_object_constructor_throws = false; diff --git a/tests/tests_common2.hpp b/tests/tests_common2.hpp new file mode 100644 index 0000000..455dc51 --- /dev/null +++ b/tests/tests_common2.hpp @@ -0,0 +1,466 @@ +#include "oup/observable_unique_ptr.hpp" + +#include + +extern int instances; +extern int instances_derived; +extern int instances_deleter; + +extern bool next_test_object_constructor_throws; + +struct throw_constructor : std::exception {}; + +struct test_object { + enum class state { default_init = 1337, special_init = 42 } state_ = state::default_init; + + test_object() { + if (next_test_object_constructor_throws) { + next_test_object_constructor_throws = false; + throw throw_constructor{}; + } + ++instances; + } + + explicit test_object(state s) : state_(s) { + if (next_test_object_constructor_throws) { + next_test_object_constructor_throws = false; + throw throw_constructor{}; + } + ++instances; + } + + virtual ~test_object() noexcept { + --instances; + } + + test_object(const test_object&) = delete; + test_object(test_object&&) = delete; + + test_object& operator=(const test_object&) = delete; + test_object& operator=(test_object&&) = delete; +}; + +struct test_object_derived : test_object { + test_object_derived() { + ++instances_derived; + } + + explicit test_object_derived(state s) : test_object(s) { + ++instances_derived; + } + + virtual ~test_object_derived() noexcept { + --instances_derived; + } +}; + +struct test_object_observer_from_this_unique : + public test_object, + public oup::enable_observer_from_this_unique { + test_object_observer_from_this_unique() = default; + test_object_observer_from_this_unique(state s) : test_object(s) {} +}; + +struct test_object_observer_from_this_sealed : + public test_object, + public oup::enable_observer_from_this_sealed { + + explicit test_object_observer_from_this_sealed(control_block_type& block) : + oup::enable_observer_from_this_sealed(block) {} + + explicit test_object_observer_from_this_sealed(control_block_type& block, state s) : + test_object(s), + oup::enable_observer_from_this_sealed(block) {} +}; + +struct sealed_virtual_policy { + static constexpr bool is_sealed = true; + static constexpr bool allow_eoft_in_constructor = false; + static constexpr bool allow_eoft_multiple_inheritance = true; + static constexpr bool eoft_constructor_takes_control_block = false; + using observer_policy = oup::default_observer_policy; +}; + +struct unique_non_virtual_policy { + static constexpr bool is_sealed = false; + static constexpr bool allow_eoft_in_constructor = true; + static constexpr bool allow_eoft_multiple_inheritance = true; + static constexpr bool eoft_constructor_takes_control_block = true; + using observer_policy = oup::default_observer_policy; +}; + +struct unique_maybe_no_block_policy { + static constexpr bool is_sealed = false; + static constexpr bool allow_eoft_in_constructor = false; + static constexpr bool allow_eoft_multiple_inheritance = true; + static constexpr bool eoft_constructor_takes_control_block = false; + using observer_policy = oup::default_observer_policy; +}; + +struct test_object_observer_from_this_virtual_sealed : + public test_object, + public oup::basic_enable_observer_from_this< + test_object_observer_from_this_virtual_sealed, + sealed_virtual_policy> { + test_object_observer_from_this_virtual_sealed() = default; + test_object_observer_from_this_virtual_sealed(state s) : test_object(s) {} +}; + +struct test_object_observer_from_this_non_virtual_unique : + public test_object, + public oup::basic_enable_observer_from_this< + test_object_observer_from_this_non_virtual_unique, + unique_non_virtual_policy> { + + explicit test_object_observer_from_this_non_virtual_unique(control_block_type& block) : + oup::basic_enable_observer_from_this< + test_object_observer_from_this_non_virtual_unique, + unique_non_virtual_policy>(block) {} + + explicit test_object_observer_from_this_non_virtual_unique(control_block_type& block, state s) : + test_object(s), + oup::basic_enable_observer_from_this< + test_object_observer_from_this_non_virtual_unique, + unique_non_virtual_policy>(block) {} +}; + +struct test_object_observer_from_this_maybe_no_block_unique : + public test_object, + public oup::basic_enable_observer_from_this< + test_object_observer_from_this_maybe_no_block_unique, + unique_maybe_no_block_policy> { + test_object_observer_from_this_maybe_no_block_unique() = default; + test_object_observer_from_this_maybe_no_block_unique(state s) : test_object(s) {} +}; + +struct test_object_observer_from_this_derived_unique : + public test_object_observer_from_this_unique { + test_object_observer_from_this_derived_unique() = default; + test_object_observer_from_this_derived_unique(state s) : + test_object_observer_from_this_unique(s) {} +}; + +struct test_object_observer_from_this_derived_sealed : + public test_object_observer_from_this_sealed { + + explicit test_object_observer_from_this_derived_sealed(control_block_type& block) : + test_object_observer_from_this_sealed(block) {} + + explicit test_object_observer_from_this_derived_sealed(control_block_type& block, state s) : + test_object_observer_from_this_sealed(block, s) {} +}; + +struct test_object_observer_from_this_multi_unique : + public test_object_observer_from_this_unique, + public oup::enable_observer_from_this_unique { + test_object_observer_from_this_multi_unique() = default; + test_object_observer_from_this_multi_unique(state s) : + test_object_observer_from_this_unique(s) {} +}; + +struct test_object_observer_from_this_multi_sealed : + public test_object_observer_from_this_sealed, + public oup::enable_observer_from_this_sealed { + + using control_block_type = oup::enable_observer_from_this_sealed< + test_object_observer_from_this_multi_sealed>::control_block_type; + + explicit test_object_observer_from_this_multi_sealed(control_block_type& block) : + test_object_observer_from_this_sealed(block), + oup::enable_observer_from_this_sealed(block) {} + + explicit test_object_observer_from_this_multi_sealed(control_block_type& block, state s) : + test_object_observer_from_this_sealed(block, s), + oup::enable_observer_from_this_sealed(block) {} +}; + +struct test_object_observer_from_this_constructor_unique : + public test_object, + public oup::enable_observer_from_this_unique< + test_object_observer_from_this_constructor_unique> { + + oup::observer_ptr ptr; + + test_object_observer_from_this_constructor_unique() { + ptr = observer_from_this(); + } + + explicit test_object_observer_from_this_constructor_unique(state s) : test_object(s) { + ptr = observer_from_this(); + } +}; + +struct test_object_observer_from_this_constructor_sealed : + public test_object, + public oup::enable_observer_from_this_sealed< + test_object_observer_from_this_constructor_sealed> { + + oup::observer_ptr ptr; + + explicit test_object_observer_from_this_constructor_sealed(control_block_type& block) : + oup::enable_observer_from_this_sealed( + block) { + ptr = observer_from_this(); + } + + explicit test_object_observer_from_this_constructor_sealed(control_block_type& block, state s) : + test_object(s), + oup::enable_observer_from_this_sealed( + block) { + ptr = observer_from_this(); + } +}; + +struct test_object_observer_from_this_constructor_bad : + public test_object, + public oup::basic_enable_observer_from_this< + test_object_observer_from_this_constructor_bad, + sealed_virtual_policy> { + + oup::observer_ptr ptr; + + explicit test_object_observer_from_this_constructor_bad() { + ptr = observer_from_this(); + } + + explicit test_object_observer_from_this_constructor_bad(state s) : test_object(s) { + ptr = observer_from_this(); + } +}; + +struct test_object_observer_from_this_constructor_multi_unique : + public test_object_observer_from_this_constructor_unique, + public oup::enable_observer_from_this_unique< + test_object_observer_from_this_constructor_multi_unique> { + + oup::observer_ptr ptr; + + test_object_observer_from_this_constructor_multi_unique() { + ptr = oup::enable_observer_from_this_unique< + test_object_observer_from_this_constructor_multi_unique>::observer_from_this(); + } + + test_object_observer_from_this_constructor_multi_unique(state s) : + test_object_observer_from_this_constructor_unique(s) { + ptr = oup::enable_observer_from_this_unique< + test_object_observer_from_this_constructor_multi_unique>::observer_from_this(); + } +}; + +struct test_object_observer_from_this_constructor_multi_sealed : + public test_object_observer_from_this_constructor_sealed, + public oup::enable_observer_from_this_sealed< + test_object_observer_from_this_constructor_multi_sealed> { + + using control_block_type = oup::enable_observer_from_this_sealed< + test_object_observer_from_this_constructor_multi_sealed>::control_block_type; + + oup::observer_ptr ptr; + + explicit test_object_observer_from_this_constructor_multi_sealed(control_block_type& block) : + test_object_observer_from_this_constructor_sealed(block), + oup::enable_observer_from_this_sealed< + test_object_observer_from_this_constructor_multi_sealed>(block) { + ptr = oup::enable_observer_from_this_sealed< + test_object_observer_from_this_constructor_multi_sealed>::observer_from_this(); + } + + explicit test_object_observer_from_this_constructor_multi_sealed( + control_block_type& block, state s) : + test_object_observer_from_this_constructor_sealed(block, s), + oup::enable_observer_from_this_sealed< + test_object_observer_from_this_constructor_multi_sealed>(block) { + ptr = oup::enable_observer_from_this_sealed< + test_object_observer_from_this_constructor_multi_sealed>::observer_from_this(); + } +}; + +struct test_deleter { + enum class state { + default_init = 1334, + special_init_1 = 59846, + special_init_2 = 221, + empty = 0 + } state_ = state::default_init; + + test_deleter() noexcept { + ++instances_deleter; + } + + explicit test_deleter(state s) noexcept : state_(s) { + ++instances_deleter; + } + + test_deleter(const test_deleter& source) noexcept : state_(source.state_) { + ++instances_deleter; + } + + test_deleter(test_deleter&& source) noexcept : state_(source.state_) { + source.state_ = state::empty; + ++instances_deleter; + } + + ~test_deleter() noexcept { + --instances_deleter; + } + + test_deleter& operator=(const test_deleter&) = default; + + test_deleter& operator=(test_deleter&& source) noexcept { + state_ = source.state_; + source.state_ = state::empty; + return *this; + } + + void operator()(test_object* ptr) noexcept { + delete ptr; + } + + void operator()(std::nullptr_t) noexcept {} +}; + +template +using get_object = typename T::element_type; + +template +using get_deleter = typename T::deleter_type; + +template +using get_policy = typename T::policy; + +template +using get_observer_policy = typename T::observer_policy; + +template +using observer_ptr = typename T::observer_type; + +template +constexpr bool is_sealed = get_policy::is_sealed; + +template +constexpr bool has_stateful_deleter = !std::is_empty_v>; + +template +constexpr bool has_eoft = oup::has_enable_observer_from_this, get_policy>; + +template +constexpr bool eoft_constructor_takes_control_block = + has_eoft&& get_policy::eoft_constructor_takes_control_block; + +template +constexpr bool eoft_allocates = has_eoft&& + oup::policy_queries>::eoft_constructor_allocates(); + +template +constexpr bool must_use_make_observable = is_sealed || eoft_constructor_takes_control_block; + +template +constexpr bool can_use_make_observable = (is_sealed && + std::is_same_v, oup::placement_delete>) || + std::is_same_v, oup::default_delete>; + +template +constexpr bool has_base = std::is_base_of_v>; + +template +using base_ptr = oup::basic_observable_ptr< + std::conditional_t>, const test_object, test_object>, + get_deleter, + get_policy>; + +template +using base_observer_ptr = typename base_ptr::observer_type; + +template +using get_state = std:: + conditional_t>, const test_object::state, test_object::state>; + +template +using state_observer_ptr = oup::basic_observer_ptr, get_observer_policy>; + +template +get_object* make_instance() { + return new std::remove_cv_t>; +} + +template +get_deleter make_deleter_instance_1() { + return get_deleter(test_deleter::state::special_init_1); +} + +template +get_deleter make_deleter_instance_2() { + return get_deleter(test_deleter::state::special_init_2); +} + +template +T make_pointer_deleter_1() { + if constexpr (must_use_make_observable) { + return oup::make_observable, get_policy>(); + } else { + if constexpr (has_stateful_deleter) { + return T(make_instance(), make_deleter_instance_1()); + } else { + return T(make_instance()); + } + } +} + +template +T make_pointer_deleter_2() { + if constexpr (must_use_make_observable) { + return oup::make_observable, get_policy>(); + } else { + if constexpr (has_stateful_deleter) { + return T(make_instance(), make_deleter_instance_2()); + } else { + return T(make_instance()); + } + } +} + +template +T make_empty_pointer_deleter_1() { + if constexpr (has_stateful_deleter) { + return T(nullptr, make_deleter_instance_1()); + } else { + return T{}; + } +} + +template +T make_empty_pointer_deleter_2() { + if constexpr (has_stateful_deleter) { + return T(nullptr, make_deleter_instance_2()); + } else { + return T{}; + } +} + +// clang-format off +using owner_types = std::tuple< + oup::observable_unique_ptr, + oup::observable_sealed_ptr, + oup::observable_unique_ptr, + oup::observable_sealed_ptr, + oup::observable_unique_ptr, + oup::observable_sealed_ptr, + oup::observable_unique_ptr, + oup::observable_unique_ptr, + oup::observable_unique_ptr, + oup::observable_sealed_ptr, + oup::basic_observable_ptr, + oup::basic_observable_ptr, + oup::basic_observable_ptr, + oup::observable_unique_ptr, + oup::observable_sealed_ptr, + oup::observable_unique_ptr, + oup::observable_sealed_ptr, + oup::observable_unique_ptr, + oup::observable_sealed_ptr, + oup::observable_unique_ptr, + oup::observable_sealed_ptr, + oup::observable_unique_ptr, + oup::observable_sealed_ptr + >; +// clang-format on From d43045f3a42719ae9c2dabab184feb58a7cb11e5 Mon Sep 17 00:00:00 2001 From: Corentin Schreiber Date: Mon, 26 Sep 2022 21:43:28 +0100 Subject: [PATCH 06/81] Remove old tests --- oup.sublime-project | 6 +- tests/CMakeLists.txt | 24 +- tests/compile_test_copy_assign.cpp | 4 +- tests/compile_test_copy_const.cpp | 4 +- tests/compile_test_good.cpp | 2 +- ...e_test_implicit_const_base_to_derived1.cpp | 2 +- ...e_test_implicit_const_base_to_derived2.cpp | 4 +- ...e_test_implicit_const_base_to_derived3.cpp | 5 +- tests/compile_test_observer_assign_raw.cpp | 2 +- tests/compile_test_observer_construct_raw.cpp | 2 +- tests/compile_test_sealed_assign_raw.cpp | 2 +- tests/compile_test_sealed_construct_raw.cpp | 2 +- tests/compile_test_sealed_release.cpp | 2 +- tests/compile_test_sealed_reset.cpp | 2 +- tests/runtime_tests.cpp | 4449 ----------------- tests/runtime_tests_lifetime.cpp | 2 +- tests/runtime_tests_make_observable.cpp | 2 +- tests/runtime_tests_observer_assignment.cpp | 2 +- tests/runtime_tests_observer_comparison.cpp | 2 +- tests/runtime_tests_observer_construction.cpp | 2 +- tests/runtime_tests_observer_misc.cpp | 2 +- tests/runtime_tests_owner_assignment.cpp | 2 +- tests/runtime_tests_owner_comparison.cpp | 2 +- tests/runtime_tests_owner_construction.cpp | 2 +- tests/runtime_tests_owner_misc.cpp | 2 +- tests/{tests_common2.cpp => tests_common.cpp} | 2 +- tests/tests_common.hpp | 391 +- tests/tests_common2.hpp | 466 -- 28 files changed, 289 insertions(+), 5102 deletions(-) delete mode 100644 tests/runtime_tests.cpp rename tests/{tests_common2.cpp => tests_common.cpp} (82%) delete mode 100644 tests/tests_common2.hpp diff --git a/oup.sublime-project b/oup.sublime-project index 601f2e9..69da2bc 100644 --- a/oup.sublime-project +++ b/oup.sublime-project @@ -181,13 +181,9 @@ "name": "oup_speed_benchmark", "shell_cmd": "make -j12 oup_speed_benchmark", }, - { - "name": "oup_tests", - "shell_cmd": "make -j12 oup_tests", - }, { "name": "oup_tests2", - "shell_cmd": "make -j12 oup_tests2" + "shell_cmd": "make -j12 oup_tests2", }, ], "working_dir": "$folder/build", diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 872731f..939bbcf 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -26,15 +26,15 @@ FetchContent_MakeAvailable(Catch2) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${Catch2_SOURCE_DIR}/extras") -add_executable(oup_tests - ${PROJECT_SOURCE_DIR}/tests/memory_tracker.cpp - ${PROJECT_SOURCE_DIR}/tests/runtime_tests.cpp) -target_link_libraries(oup_tests PRIVATE Catch2::Catch2WithMain) -target_link_libraries(oup_tests PRIVATE oup::oup) -add_platform_definitions(oup_tests) +# add_executable(oup_tests +# ${PROJECT_SOURCE_DIR}/tests/memory_tracker.cpp +# ${PROJECT_SOURCE_DIR}/tests/runtime_tests.cpp) +# target_link_libraries(oup_tests PRIVATE Catch2::Catch2WithMain) +# target_link_libraries(oup_tests PRIVATE oup::oup) +# add_platform_definitions(oup_tests) -add_executable(oup_tests2 - ${PROJECT_SOURCE_DIR}/tests/tests_common2.cpp +add_executable(oup_tests + ${PROJECT_SOURCE_DIR}/tests/tests_common.cpp ${PROJECT_SOURCE_DIR}/tests/memory_tracker.cpp ${PROJECT_SOURCE_DIR}/tests/runtime_tests_owner_misc.cpp ${PROJECT_SOURCE_DIR}/tests/runtime_tests_owner_construction.cpp @@ -46,14 +46,14 @@ add_executable(oup_tests2 ${PROJECT_SOURCE_DIR}/tests/runtime_tests_observer_construction.cpp ${PROJECT_SOURCE_DIR}/tests/runtime_tests_observer_assignment.cpp ${PROJECT_SOURCE_DIR}/tests/runtime_tests_observer_comparison.cpp) -target_link_libraries(oup_tests2 PRIVATE Catch2::Catch2WithMain) -target_link_libraries(oup_tests2 PRIVATE oup::oup) -add_platform_definitions(oup_tests2) +target_link_libraries(oup_tests PRIVATE Catch2::Catch2WithMain) +target_link_libraries(oup_tests PRIVATE oup::oup) +add_platform_definitions(oup_tests) include(CTest) include(Catch) -catch_discover_tests(oup_tests2) +catch_discover_tests(oup_tests) # Compile-time error tests set(CMAKE_TRY_COMPILE_TARGET_TYPE EXECUTABLE) diff --git a/tests/compile_test_copy_assign.cpp b/tests/compile_test_copy_assign.cpp index f81247b..d7c97ea 100644 --- a/tests/compile_test_copy_assign.cpp +++ b/tests/compile_test_copy_assign.cpp @@ -1,8 +1,8 @@ #include "tests_common.hpp" int main() { - test_ptr ptr_orig(new test_object); - test_ptr ptr; + oup::observable_unique_ptr ptr_orig(new test_object); + oup::observable_unique_ptr ptr; ptr = ptr_orig; return 0; } diff --git a/tests/compile_test_copy_const.cpp b/tests/compile_test_copy_const.cpp index 190d76b..b1a65c4 100644 --- a/tests/compile_test_copy_const.cpp +++ b/tests/compile_test_copy_const.cpp @@ -1,7 +1,7 @@ #include "tests_common.hpp" int main() { - test_ptr ptr_orig(new test_object); - test_ptr ptr(ptr_orig); + oup::observable_unique_ptr ptr_orig(new test_object); + oup::observable_unique_ptr ptr(ptr_orig); return 0; } diff --git a/tests/compile_test_good.cpp b/tests/compile_test_good.cpp index 576b854..9270da7 100644 --- a/tests/compile_test_good.cpp +++ b/tests/compile_test_good.cpp @@ -1,6 +1,6 @@ #include "tests_common.hpp" int main() { - test_ptr ptr_orig(new test_object); + oup::observable_unique_ptr ptr_orig(new test_object); return 0; } diff --git a/tests/compile_test_implicit_const_base_to_derived1.cpp b/tests/compile_test_implicit_const_base_to_derived1.cpp index 04ba4d2..391640e 100644 --- a/tests/compile_test_implicit_const_base_to_derived1.cpp +++ b/tests/compile_test_implicit_const_base_to_derived1.cpp @@ -1,6 +1,6 @@ #include "tests_common.hpp" int main() { - test_ptr_derived ptr(new test_object); + oup::observable_unique_ptr ptr(new test_object); return 0; } diff --git a/tests/compile_test_implicit_const_base_to_derived2.cpp b/tests/compile_test_implicit_const_base_to_derived2.cpp index 12c87a2..f33c2eb 100644 --- a/tests/compile_test_implicit_const_base_to_derived2.cpp +++ b/tests/compile_test_implicit_const_base_to_derived2.cpp @@ -1,7 +1,7 @@ #include "tests_common.hpp" int main() { - test_ptr ptr_orig(new test_object); - test_ptr_derived ptr(std::move(ptr_orig)); + oup::observable_unique_ptr ptr_orig(new test_object); + oup::observable_unique_ptr ptr(std::move(ptr_orig)); return 0; } diff --git a/tests/compile_test_implicit_const_base_to_derived3.cpp b/tests/compile_test_implicit_const_base_to_derived3.cpp index e567733..f1f71e0 100644 --- a/tests/compile_test_implicit_const_base_to_derived3.cpp +++ b/tests/compile_test_implicit_const_base_to_derived3.cpp @@ -1,7 +1,8 @@ #include "tests_common.hpp" int main() { - test_ptr_with_deleter ptr_orig(new test_object, test_deleter{42}); - test_ptr_derived_with_deleter ptr(std::move(ptr_orig)); + oup::observable_unique_ptr ptr_orig( + new test_object, test_deleter{42}); + oup::observable_unique_ptr ptr(std::move(ptr_orig)); return 0; } diff --git a/tests/compile_test_observer_assign_raw.cpp b/tests/compile_test_observer_assign_raw.cpp index 50c8581..63ba6dd 100644 --- a/tests/compile_test_observer_assign_raw.cpp +++ b/tests/compile_test_observer_assign_raw.cpp @@ -1,7 +1,7 @@ #include "tests_common.hpp" int main() { - test_optr ptr; + oup::observer_ptr ptr; ptr = new test_object; return 0; } diff --git a/tests/compile_test_observer_construct_raw.cpp b/tests/compile_test_observer_construct_raw.cpp index 7651b13..44e8bbd 100644 --- a/tests/compile_test_observer_construct_raw.cpp +++ b/tests/compile_test_observer_construct_raw.cpp @@ -1,6 +1,6 @@ #include "tests_common.hpp" int main() { - test_optr ptr(new test_object); + oup::observer_ptr ptr(new test_object); return 0; } diff --git a/tests/compile_test_sealed_assign_raw.cpp b/tests/compile_test_sealed_assign_raw.cpp index 631ae39..a21ae82 100644 --- a/tests/compile_test_sealed_assign_raw.cpp +++ b/tests/compile_test_sealed_assign_raw.cpp @@ -1,7 +1,7 @@ #include "tests_common.hpp" int main() { - test_sptr ptr; + oup::observable_sealed_ptr ptr; ptr = new test_object; return 0; } diff --git a/tests/compile_test_sealed_construct_raw.cpp b/tests/compile_test_sealed_construct_raw.cpp index 55a59e3..75cb3fb 100644 --- a/tests/compile_test_sealed_construct_raw.cpp +++ b/tests/compile_test_sealed_construct_raw.cpp @@ -1,6 +1,6 @@ #include "tests_common.hpp" int main() { - test_sptr ptr(new test_object); + oup::observable_sealed_ptr ptr(new test_object); return 0; } diff --git a/tests/compile_test_sealed_release.cpp b/tests/compile_test_sealed_release.cpp index d27a052..4637d1e 100644 --- a/tests/compile_test_sealed_release.cpp +++ b/tests/compile_test_sealed_release.cpp @@ -1,7 +1,7 @@ #include "tests_common.hpp" int main() { - test_sptr ptr; + oup::observable_sealed_ptr ptr; ptr.release(); return 0; } diff --git a/tests/compile_test_sealed_reset.cpp b/tests/compile_test_sealed_reset.cpp index 9c072e3..d476dbc 100644 --- a/tests/compile_test_sealed_reset.cpp +++ b/tests/compile_test_sealed_reset.cpp @@ -1,7 +1,7 @@ #include "tests_common.hpp" int main() { - test_sptr ptr; + oup::observable_sealed_ptr ptr; ptr.reset(new test_object); return 0; } diff --git a/tests/runtime_tests.cpp b/tests/runtime_tests.cpp deleted file mode 100644 index a8def7c..0000000 --- a/tests/runtime_tests.cpp +++ /dev/null @@ -1,4449 +0,0 @@ -#include "catch2_and_overrides.hpp" -#include "memory_tracker.hpp" -#include "tests_common.hpp" - -// TEST_CASE("owner size", "[owner_size]") { -// REQUIRE(sizeof(test_ptr) == 2 * sizeof(void*)); -// } - -// TEST_CASE("owner size sealed", "[owner_size]") { -// REQUIRE(sizeof(test_sptr) == 2 * sizeof(void*)); -// } - -// TEST_CASE("owner default constructor", "[owner_construction]") { -// memory_tracker mem_track; - -// { -// test_ptr ptr; -// REQUIRE(instances == 0); -// REQUIRE(ptr.get() == nullptr); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner default constructor sealed", "[owner_construction]") { -// memory_tracker mem_track; - -// { -// test_sptr ptr; -// REQUIRE(instances == 0); -// REQUIRE(ptr.get() == nullptr); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner default constructor with deleter", "[owner_construction]") { -// memory_tracker mem_track; - -// { -// test_ptr_with_deleter ptr; -// REQUIRE(instances == 0); -// REQUIRE(instances_deleter == 1); -// REQUIRE(ptr.get() == nullptr); -// REQUIRE(ptr.get_deleter().state_ == 0); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_deleter == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner nullptr constructor", "[owner_construction]") { -// memory_tracker mem_track; - -// { -// test_ptr ptr{nullptr}; -// REQUIRE(instances == 0); -// REQUIRE(ptr.get() == nullptr); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner nullptr constructor sealed", "[owner_construction]") { -// memory_tracker mem_track; - -// { -// test_sptr ptr{nullptr}; -// REQUIRE(instances == 0); -// REQUIRE(ptr.get() == nullptr); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner nullptr constructor with deleter", "[owner_construction]") { -// memory_tracker mem_track; - -// { -// test_ptr_with_deleter ptr{nullptr, test_deleter{42}}; -// REQUIRE(instances == 0); -// REQUIRE(instances_deleter == 1); -// REQUIRE(ptr.get() == nullptr); -// REQUIRE(ptr.get_deleter().state_ == 42); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_deleter == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner move constructor", "[owner_construction]") { -// memory_tracker mem_track; - -// { -// test_ptr ptr_orig(new test_object); -// { -// test_ptr ptr(std::move(ptr_orig)); -// REQUIRE(instances == 1); -// REQUIRE(ptr.get() != nullptr); -// } - -// REQUIRE(instances == 0); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner move constructor sealed", "[owner_construction]") { -// memory_tracker mem_track; - -// { -// test_sptr ptr_orig = oup::make_observable_sealed(); -// { -// test_sptr ptr(std::move(ptr_orig)); -// REQUIRE(instances == 1); -// REQUIRE(ptr.get() != nullptr); -// } - -// REQUIRE(instances == 0); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner move constructor with deleter", "[owner_construction]") { -// memory_tracker mem_track; - -// { -// test_ptr_with_deleter ptr_orig(new test_object, test_deleter{42}); -// { -// test_ptr_with_deleter ptr(std::move(ptr_orig)); -// REQUIRE(instances == 1); -// REQUIRE(instances_deleter == 2); -// REQUIRE(ptr.get() != nullptr); -// REQUIRE(ptr.get_deleter().state_ == 42); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_deleter == 1); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_deleter == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner acquiring constructor", "[owner_construction]") { -// memory_tracker mem_track; - -// { -// test_ptr ptr{new test_object}; -// REQUIRE(instances == 1); -// REQUIRE(ptr.get() != nullptr); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner acquiring constructor bad alloc", "[owner_construction]") { -// memory_tracker mem_track; - -// { -// test_object* raw_ptr = new test_object; -// try { -// force_next_allocation_failure = true; -// test_ptr{raw_ptr}; -// } catch (...) { -// } -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner acquiring constructor with deleter", "[owner_construction]") { -// memory_tracker mem_track; - -// { -// test_ptr_with_deleter ptr{new test_object, test_deleter{42}}; -// REQUIRE(instances == 1); -// REQUIRE(instances_deleter == 1); -// REQUIRE(ptr.get() != nullptr); -// REQUIRE(ptr.get_deleter().state_ == 42); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_deleter == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner acquiring constructor with deleter bad alloc", "[owner_construction]") { -// memory_tracker mem_track; - -// { -// test_object* raw_ptr = new test_object; -// try { -// force_next_allocation_failure = true; -// test_ptr_with_deleter{raw_ptr, test_deleter{42}}; -// } catch (...) { -// } -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner acquiring constructor null", "[owner_construction]") { -// memory_tracker mem_track; - -// { -// test_ptr ptr{static_cast(nullptr)}; -// REQUIRE(instances == 0); -// REQUIRE(ptr.get() == nullptr); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner acquiring constructor null with deleter", "[owner_construction]") { -// memory_tracker mem_track; - -// { -// test_ptr_with_deleter ptr{static_cast(nullptr), test_deleter{42}}; -// REQUIRE(instances == 0); -// REQUIRE(instances_deleter == 1); -// REQUIRE(ptr.get() == nullptr); -// REQUIRE(ptr.get_deleter().state_ == 42); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_deleter == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner implicit conversion constructor", "[owner_construction]") { -// memory_tracker mem_track; - -// { -// test_ptr_derived ptr_orig{new test_object_derived}; -// { -// test_ptr ptr(std::move(ptr_orig)); -// REQUIRE(instances == 1); -// REQUIRE(instances_derived == 1); -// REQUIRE(ptr.get() != nullptr); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_derived == 0); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_derived == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner implicit conversion constructor sealed", "[owner_construction]") { -// memory_tracker mem_track; - -// { -// test_sptr_derived ptr_orig = oup::make_observable_sealed(); -// { -// test_sptr ptr(std::move(ptr_orig)); -// REQUIRE(instances == 1); -// REQUIRE(instances_derived == 1); -// REQUIRE(ptr.get() != nullptr); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_derived == 0); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_derived == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner implicit conversion constructor with deleter", "[owner_construction]") { -// memory_tracker mem_track; - -// { -// test_ptr_derived_with_deleter ptr_orig{new test_object_derived, test_deleter{42}}; -// { -// test_ptr_with_deleter ptr(std::move(ptr_orig)); -// REQUIRE(instances == 1); -// REQUIRE(instances_derived == 1); -// REQUIRE(instances_deleter == 2); -// REQUIRE(ptr.get() != nullptr); -// REQUIRE(ptr.get_deleter().state_ == 42); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_derived == 0); -// REQUIRE(instances_deleter == 1); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_derived == 0); -// REQUIRE(instances_deleter == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner explicit conversion constructor", "[owner_construction]") { -// memory_tracker mem_track; - -// { -// test_ptr ptr_orig{new test_object_derived}; -// { -// test_ptr_derived ptr( -// std::move(ptr_orig), dynamic_cast(ptr_orig.get())); -// REQUIRE(instances == 1); -// REQUIRE(instances_derived == 1); -// REQUIRE(ptr.get() != nullptr); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_derived == 0); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_derived == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner explicit conversion constructor sealed", "[owner_construction]") { -// memory_tracker mem_track; - -// { -// test_sptr ptr_orig = oup::make_observable_sealed(); -// { -// test_sptr_derived ptr( -// std::move(ptr_orig), dynamic_cast(ptr_orig.get())); -// REQUIRE(instances == 1); -// REQUIRE(instances_derived == 1); -// REQUIRE(ptr.get() != nullptr); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_derived == 0); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_derived == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner explicit conversion constructor with default deleter", "[owner_construction]") { -// memory_tracker mem_track; - -// { -// test_ptr_with_deleter ptr_orig{new test_object_derived, test_deleter{42}}; -// { -// test_ptr_derived_with_deleter ptr( -// std::move(ptr_orig), dynamic_cast(ptr_orig.get())); -// REQUIRE(instances == 1); -// REQUIRE(instances_derived == 1); -// REQUIRE(instances_deleter == 2); -// REQUIRE(ptr.get() != nullptr); -// REQUIRE(ptr.get_deleter().state_ == 42); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_derived == 0); -// REQUIRE(instances_deleter == 1); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_derived == 0); -// REQUIRE(instances_deleter == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner explicit conversion constructor with custom deleter", "[owner_construction]") { -// memory_tracker mem_track; - -// { -// test_ptr_with_deleter ptr_orig{new test_object_derived, test_deleter{42}}; -// { -// test_ptr_derived_with_deleter ptr( -// std::move(ptr_orig), dynamic_cast(ptr_orig.get()), -// test_deleter{43}); -// REQUIRE(instances == 1); -// REQUIRE(instances_derived == 1); -// REQUIRE(instances_deleter == 2); -// REQUIRE(ptr.get() != nullptr); -// REQUIRE(ptr.get_deleter().state_ == 43); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_derived == 0); -// REQUIRE(instances_deleter == 1); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_derived == 0); -// REQUIRE(instances_deleter == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner explicit conversion constructor with nullptr", "[owner_construction]") { -// memory_tracker mem_track; - -// { -// test_ptr ptr_orig{new test_object_derived}; -// { -// test_ptr_derived ptr(std::move(ptr_orig), -// static_cast(nullptr)); REQUIRE(instances == 0); -// REQUIRE(instances_derived == 0); -// REQUIRE(ptr.get() == nullptr); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_derived == 0); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_derived == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner explicit conversion constructor with nullptr sealed", "[owner_construction]") { -// memory_tracker mem_track; - -// { -// test_sptr ptr_orig = oup::make_observable_sealed(); -// { -// test_sptr_derived ptr(std::move(ptr_orig), -// static_cast(nullptr)); REQUIRE(instances == 0); -// REQUIRE(instances_derived == 0); -// REQUIRE(ptr.get() == nullptr); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_derived == 0); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_derived == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE( -// "owner explicit conversion constructor with nullptr with custom deleter", -// "[owner_construction]") { -// memory_tracker mem_track; - -// { -// test_ptr_with_deleter ptr_orig{new test_object_derived, test_deleter{42}}; -// { -// test_ptr_derived_with_deleter ptr( -// std::move(ptr_orig), static_cast(nullptr), -// test_deleter{43}); -// REQUIRE(instances == 0); -// REQUIRE(instances_derived == 0); -// REQUIRE(instances_deleter == 2); -// REQUIRE(ptr.get() == nullptr); -// REQUIRE(ptr.get_deleter().state_ == 43); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_derived == 0); -// REQUIRE(instances_deleter == 1); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_derived == 0); -// REQUIRE(instances_deleter == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner move assignment operator valid to empty", "[owner_assignment]") { -// memory_tracker mem_track; - -// { -// test_ptr ptr_orig(new test_object); -// { -// test_ptr ptr; -// ptr = std::move(ptr_orig); -// REQUIRE(instances == 1); -// REQUIRE(ptr.get() != nullptr); -// } - -// REQUIRE(instances == 0); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner move assignment operator valid to empty sealed", "[owner_assignment]") { -// memory_tracker mem_track; - -// { -// test_sptr ptr_orig = oup::make_observable_sealed(); -// { -// test_sptr ptr; -// ptr = std::move(ptr_orig); -// REQUIRE(instances == 1); -// REQUIRE(ptr.get() != nullptr); -// } - -// REQUIRE(instances == 0); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner move assignment operator valid to empty with deleter", "[owner_assignment]") { -// memory_tracker mem_track; - -// { -// test_ptr_with_deleter ptr_orig(new test_object, test_deleter{42}); -// { -// test_ptr_with_deleter ptr; -// ptr = std::move(ptr_orig); -// REQUIRE(instances == 1); -// REQUIRE(instances_deleter == 2); -// REQUIRE(ptr.get() != nullptr); -// REQUIRE(ptr.get_deleter().state_ == 42); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_deleter == 1); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_deleter == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner move assignment operator empty to valid", "[owner_assignment]") { -// memory_tracker mem_track; - -// { -// test_ptr ptr_orig; -// { -// test_ptr ptr(new test_object); -// ptr = std::move(ptr_orig); -// REQUIRE(instances == 0); -// REQUIRE(ptr.get() == nullptr); -// } - -// REQUIRE(instances == 0); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner move assignment operator empty to valid sealed", "[owner_assignment]") { -// memory_tracker mem_track; - -// { -// test_sptr ptr_orig; -// { -// test_sptr ptr = oup::make_observable_sealed(); -// ptr = std::move(ptr_orig); -// REQUIRE(instances == 0); -// REQUIRE(ptr.get() == nullptr); -// } - -// REQUIRE(instances == 0); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner move assignment operator empty to valid with deleter", "[owner_assignment]") { -// memory_tracker mem_track; - -// { -// test_ptr_with_deleter ptr_orig; -// { -// test_ptr_with_deleter ptr(new test_object, test_deleter{42}); -// ptr = std::move(ptr_orig); -// REQUIRE(instances == 0); -// REQUIRE(instances_deleter == 2); -// REQUIRE(ptr.get() == nullptr); -// REQUIRE(ptr.get_deleter().state_ == 0); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_deleter == 1); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_deleter == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner move assignment operator empty to empty", "[owner_assignment]") { -// memory_tracker mem_track; - -// { -// test_ptr ptr_orig; -// { -// test_ptr ptr; -// ptr = std::move(ptr_orig); -// REQUIRE(instances == 0); -// REQUIRE(ptr.get() == nullptr); -// } - -// REQUIRE(instances == 0); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner move assignment operator empty to empty sealed", "[owner_assignment]") { -// memory_tracker mem_track; - -// { -// test_sptr ptr_orig; -// { -// test_sptr ptr; -// ptr = std::move(ptr_orig); -// REQUIRE(instances == 0); -// REQUIRE(ptr.get() == nullptr); -// } - -// REQUIRE(instances == 0); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner move assignment operator empty to empty with deleter", "[owner_assignment]") { -// memory_tracker mem_track; - -// { -// test_ptr_with_deleter ptr_orig; -// { -// test_ptr_with_deleter ptr; -// ptr = std::move(ptr_orig); -// REQUIRE(instances == 0); -// REQUIRE(instances_deleter == 2); -// REQUIRE(ptr.get() == nullptr); -// REQUIRE(ptr.get_deleter().state_ == 0); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_deleter == 1); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_deleter == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner move assignment operator valid to valid", "[owner_assignment]") { -// memory_tracker mem_track; - -// { -// test_ptr ptr_orig(new test_object); -// { -// test_ptr ptr(new test_object); -// ptr = std::move(ptr_orig); -// REQUIRE(instances == 1); -// REQUIRE(ptr.get() != nullptr); -// } - -// REQUIRE(instances == 0); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner move assignment operator valid to valid sealed", "[owner_assignment]") { -// memory_tracker mem_track; - -// { -// test_sptr ptr_orig = oup::make_observable_sealed(); -// { -// test_sptr ptr = oup::make_observable_sealed(); -// ptr = std::move(ptr_orig); -// REQUIRE(instances == 1); -// REQUIRE(ptr.get() != nullptr); -// } - -// REQUIRE(instances == 0); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner move assignment operator valid to valid with deleter", "[owner_assignment]") { -// memory_tracker mem_track; - -// { -// test_ptr_with_deleter ptr_orig(new test_object, test_deleter{42}); -// { -// test_ptr_with_deleter ptr(new test_object, test_deleter{43}); -// ptr = std::move(ptr_orig); -// REQUIRE(instances == 1); -// REQUIRE(instances_deleter == 2); -// REQUIRE(ptr.get() != nullptr); -// REQUIRE(ptr.get_deleter().state_ == 42); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_deleter == 1); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_deleter == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner move assignment operator self to self", "[owner_assignment]") { -// memory_tracker mem_track; - -// { -// test_ptr ptr(new test_object); -// ptr = std::move(ptr); -// REQUIRE(instances == 0); -// REQUIRE(ptr.get() == nullptr); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner move assignment operator self to self sealed", "[owner_assignment]") { -// memory_tracker mem_track; - -// { -// test_sptr ptr = oup::make_observable_sealed(); -// ptr = std::move(ptr); -// REQUIRE(instances == 0); -// REQUIRE(ptr.get() == nullptr); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner move assignment operator self to self with deleter", "[owner_assignment]") { -// memory_tracker mem_track; - -// { -// test_ptr_with_deleter ptr(new test_object, test_deleter{42}); -// ptr = std::move(ptr); -// REQUIRE(instances == 0); -// REQUIRE(ptr.get() == nullptr); -// REQUIRE(instances_deleter == 1); -// REQUIRE(ptr.get_deleter().state_ == 0); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_deleter == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner move assignment operator self to self empty", "[owner_assignment]") { -// memory_tracker mem_track; - -// { -// test_ptr ptr; -// ptr = std::move(ptr); -// REQUIRE(instances == 0); -// REQUIRE(ptr.get() == nullptr); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner move assignment operator self to self empty sealed", "[owner_assignment]") { -// memory_tracker mem_track; - -// { -// test_sptr ptr; -// ptr = std::move(ptr); -// REQUIRE(instances == 0); -// REQUIRE(ptr.get() == nullptr); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner move assignment operator self to self empty with deleter", "[owner_assignment]") -// { -// memory_tracker mem_track; - -// { -// test_ptr_with_deleter ptr; -// ptr = std::move(ptr); -// REQUIRE(instances == 0); -// REQUIRE(ptr.get() == nullptr); -// REQUIRE(instances_deleter == 1); -// REQUIRE(ptr.get_deleter().state_ == 0); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_deleter == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner comparison valid ptr vs nullptr", "[owner_comparison]") { -// memory_tracker mem_track; - -// { -// test_ptr ptr(new test_object); -// REQUIRE(ptr != nullptr); -// REQUIRE(!(ptr == nullptr)); -// REQUIRE(nullptr != ptr); -// REQUIRE(!(nullptr == ptr)); -// } - -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner comparison valid ptr vs nullptr sealed", "[owner_comparison]") { -// memory_tracker mem_track; - -// { -// test_sptr ptr = oup::make_observable_sealed(); -// REQUIRE(ptr != nullptr); -// REQUIRE(!(ptr == nullptr)); -// REQUIRE(nullptr != ptr); -// REQUIRE(!(nullptr == ptr)); -// } - -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner comparison valid ptr vs nullptr with deleter", "[owner_comparison]") { -// memory_tracker mem_track; - -// { -// test_ptr_with_deleter ptr(new test_object, test_deleter{42}); -// REQUIRE(ptr != nullptr); -// REQUIRE(!(ptr == nullptr)); -// REQUIRE(nullptr != ptr); -// REQUIRE(!(nullptr == ptr)); -// } - -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner comparison invalid ptr vs nullptr", "[owner_comparison]") { -// memory_tracker mem_track; - -// { -// test_ptr ptr; -// REQUIRE(ptr == nullptr); -// REQUIRE(!(ptr != nullptr)); -// REQUIRE(nullptr == ptr); -// REQUIRE(!(nullptr != ptr)); -// } - -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner comparison invalid ptr vs nullptr sealed", "[owner_comparison]") { -// memory_tracker mem_track; - -// { -// test_sptr ptr; -// REQUIRE(ptr == nullptr); -// REQUIRE(!(ptr != nullptr)); -// REQUIRE(nullptr == ptr); -// REQUIRE(!(nullptr != ptr)); -// } - -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner comparison invalid ptr vs nullptr with deleter", "[owner_comparison]") { -// memory_tracker mem_track; - -// { -// test_ptr_with_deleter ptr; -// REQUIRE(ptr == nullptr); -// REQUIRE(!(ptr != nullptr)); -// REQUIRE(nullptr == ptr); -// REQUIRE(!(nullptr != ptr)); -// } - -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner comparison invalid ptr vs nullptr with deleter explicit", "[owner_comparison]") -// { -// memory_tracker mem_track; - -// { -// test_ptr_with_deleter ptr(nullptr, test_deleter{42}); -// REQUIRE(ptr == nullptr); -// REQUIRE(!(ptr != nullptr)); -// REQUIRE(nullptr == ptr); -// REQUIRE(!(nullptr != ptr)); -// } - -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner comparison invalid ptr vs invalid ptr", "[owner_comparison]") { -// memory_tracker mem_track; - -// { -// test_ptr ptr1; -// test_ptr ptr2; -// REQUIRE(ptr1 == ptr2); -// REQUIRE(!(ptr1 != ptr2)); -// } - -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner comparison invalid ptr vs invalid ptr sealed", "[owner_comparison]") { -// memory_tracker mem_track; - -// { -// test_sptr ptr1; -// test_sptr ptr2; -// REQUIRE(ptr1 == ptr2); -// REQUIRE(!(ptr1 != ptr2)); -// } - -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner comparison invalid ptr vs invalid ptr with deleter", "[owner_comparison]") { -// memory_tracker mem_track; - -// { -// test_ptr_with_deleter ptr1; -// test_ptr_with_deleter ptr2; -// REQUIRE(ptr1 == ptr2); -// REQUIRE(!(ptr1 != ptr2)); -// } - -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE( -// "owner comparison invalid ptr vs invalid ptr with deleter explicit", "[owner_comparison]") { -// memory_tracker mem_track; - -// { -// test_ptr_with_deleter ptr1; -// test_ptr_with_deleter ptr2(nullptr, test_deleter{42}); -// REQUIRE(ptr1 == ptr2); -// REQUIRE(ptr2 == ptr1); -// REQUIRE(!(ptr2 != ptr1)); -// REQUIRE(!(ptr2 != ptr1)); -// } - -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE( -// "owner comparison invalid ptr vs invalid ptr with both deleter explicit", -// "[owner_comparison]") { -// memory_tracker mem_track; - -// { -// test_ptr_with_deleter ptr1(nullptr, test_deleter{43}); -// test_ptr_with_deleter ptr2(nullptr, test_deleter{42}); -// REQUIRE(ptr1 == ptr2); -// REQUIRE(ptr2 == ptr1); -// REQUIRE(!(ptr2 != ptr1)); -// REQUIRE(!(ptr2 != ptr1)); -// } - -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner comparison invalid ptr vs valid ptr", "[owner_comparison]") { -// memory_tracker mem_track; - -// { -// test_ptr ptr1; -// test_ptr ptr2(new test_object); -// REQUIRE(ptr1 != ptr2); -// REQUIRE(!(ptr1 == ptr2)); -// REQUIRE(ptr2 != ptr1); -// REQUIRE(!(ptr2 == ptr1)); -// } - -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner comparison invalid ptr vs valid ptr sealed", "[owner_comparison]") { -// memory_tracker mem_track; - -// { -// test_sptr ptr1; -// test_sptr ptr2 = oup::make_observable_sealed(); -// REQUIRE(ptr1 != ptr2); -// REQUIRE(!(ptr1 == ptr2)); -// REQUIRE(ptr2 != ptr1); -// REQUIRE(!(ptr2 == ptr1)); -// } - -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner comparison invalid ptr vs valid ptr with deleter", "[owner_comparison]") { -// memory_tracker mem_track; - -// { -// test_ptr_with_deleter ptr1; -// test_ptr_with_deleter ptr2(new test_object, test_deleter{42}); -// REQUIRE(ptr1 != ptr2); -// REQUIRE(!(ptr1 == ptr2)); -// REQUIRE(ptr2 != ptr1); -// REQUIRE(!(ptr2 == ptr1)); -// } - -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner comparison invalid ptr vs valid ptr with deleter explicit", -// "[owner_comparison]") { -// memory_tracker mem_track; - -// { -// test_ptr_with_deleter ptr1(nullptr, test_deleter{43}); -// test_ptr_with_deleter ptr2(new test_object, test_deleter{42}); -// REQUIRE(ptr1 != ptr2); -// REQUIRE(!(ptr1 == ptr2)); -// REQUIRE(ptr2 != ptr1); -// REQUIRE(!(ptr2 == ptr1)); -// } - -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner comparison valid ptr vs valid ptr", "[owner_comparison]") { -// memory_tracker mem_track; - -// { -// test_ptr ptr1(new test_object); -// test_ptr ptr2(new test_object); -// REQUIRE(ptr1 != ptr2); -// REQUIRE(!(ptr1 == ptr2)); -// REQUIRE(ptr2 != ptr1); -// REQUIRE(!(ptr2 == ptr1)); -// } - -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner comparison valid ptr vs valid ptr sealed", "[owner_comparison]") { -// memory_tracker mem_track; - -// { -// test_sptr ptr1 = oup::make_observable_sealed(); -// test_sptr ptr2 = oup::make_observable_sealed(); -// REQUIRE(ptr1 != ptr2); -// REQUIRE(!(ptr1 == ptr2)); -// REQUIRE(ptr2 != ptr1); -// REQUIRE(!(ptr2 == ptr1)); -// } - -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner comparison valid ptr vs valid ptr with deleter", "[owner_comparison]") { -// memory_tracker mem_track; - -// { -// test_ptr_with_deleter ptr1(new test_object, test_deleter{43}); -// test_ptr_with_deleter ptr2(new test_object, test_deleter{42}); -// REQUIRE(ptr1 != ptr2); -// REQUIRE(!(ptr1 == ptr2)); -// REQUIRE(ptr2 != ptr1); -// REQUIRE(!(ptr2 == ptr1)); -// } - -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner reset to null", "[owner_utility]") { -// memory_tracker mem_track; - -// { -// test_ptr ptr(new test_object); -// ptr.reset(); -// REQUIRE(instances == 0); -// REQUIRE(ptr.get() == nullptr); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner reset to null sealed", "[owner_utility]") { -// memory_tracker mem_track; - -// { -// test_sptr ptr = oup::make_observable_sealed(); -// ptr.reset(); -// REQUIRE(instances == 0); -// REQUIRE(ptr.get() == nullptr); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner reset to null with deleter", "[owner_utility]") { -// memory_tracker mem_track; - -// { -// test_ptr_with_deleter ptr(new test_object, test_deleter{42}); -// ptr.reset(); -// REQUIRE(instances == 0); -// REQUIRE(instances_deleter == 1); -// REQUIRE(ptr.get() == nullptr); -// REQUIRE(ptr.get_deleter().state_ == 42); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_deleter == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner reset to new", "[owner_utility]") { -// memory_tracker mem_track; - -// { -// test_ptr ptr(new test_object); -// ptr.reset(new test_object); -// REQUIRE(instances == 1); -// REQUIRE(ptr.get() != nullptr); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner reset to new bad alloc", "[owner_utility]") { -// memory_tracker mem_track; - -// { -// test_object* raw_ptr1 = new test_object; -// test_object* raw_ptr2 = new test_object; -// test_ptr ptr(raw_ptr1); -// try { -// force_next_allocation_failure = true; -// ptr.reset(raw_ptr2); -// } catch (...) { -// } -// REQUIRE(instances == 1); -// REQUIRE(ptr.get() == raw_ptr1); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner reset to new with deleter", "[owner_utility]") { -// memory_tracker mem_track; - -// { -// test_ptr_with_deleter ptr(new test_object, test_deleter{42}); -// ptr.reset(new test_object); -// REQUIRE(instances == 1); -// REQUIRE(instances_deleter == 1); -// REQUIRE(ptr.get() != nullptr); -// REQUIRE(ptr.get_deleter().state_ == 42); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_deleter == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner swap no instance", "[owner_utility]") { -// memory_tracker mem_track; - -// { -// test_ptr ptr_orig; -// test_ptr ptr; -// ptr.swap(ptr_orig); -// REQUIRE(instances == 0); -// REQUIRE(ptr_orig.get() == nullptr); -// REQUIRE(ptr.get() == nullptr); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner swap no instance sealed", "[owner_utility]") { -// memory_tracker mem_track; - -// { -// test_sptr ptr_orig; -// test_sptr ptr; -// ptr.swap(ptr_orig); -// REQUIRE(instances == 0); -// REQUIRE(ptr_orig.get() == nullptr); -// REQUIRE(ptr.get() == nullptr); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner swap no instance with deleter", "[owner_utility]") { -// memory_tracker mem_track; - -// { -// test_ptr_with_deleter ptr_orig(nullptr, test_deleter{42}); -// test_ptr_with_deleter ptr(nullptr, test_deleter{43}); -// ptr.swap(ptr_orig); -// REQUIRE(instances == 0); -// REQUIRE(instances_deleter == 2); -// REQUIRE(ptr_orig.get() == nullptr); -// REQUIRE(ptr.get() == nullptr); -// REQUIRE(ptr.get_deleter().state_ == 42); -// REQUIRE(ptr_orig.get_deleter().state_ == 43); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_deleter == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner swap one instance", "[owner_utility]") { -// memory_tracker mem_track; - -// { -// test_ptr ptr_orig(new test_object); -// test_ptr ptr; -// ptr.swap(ptr_orig); -// REQUIRE(instances == 1); -// REQUIRE(ptr_orig.get() == nullptr); -// REQUIRE(ptr.get() != nullptr); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner swap one instance sealed", "[owner_utility]") { -// memory_tracker mem_track; - -// { -// test_sptr ptr_orig = oup::make_observable_sealed(); -// test_sptr ptr; -// ptr.swap(ptr_orig); -// REQUIRE(instances == 1); -// REQUIRE(ptr_orig.get() == nullptr); -// REQUIRE(ptr.get() != nullptr); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner swap one instance with deleter", "[owner_utility]") { -// memory_tracker mem_track; - -// { -// test_ptr_with_deleter ptr_orig(new test_object, test_deleter{42}); -// test_ptr_with_deleter ptr(nullptr, test_deleter{43}); -// ptr.swap(ptr_orig); -// REQUIRE(instances == 1); -// REQUIRE(instances_deleter == 2); -// REQUIRE(ptr_orig.get() == nullptr); -// REQUIRE(ptr.get() != nullptr); -// REQUIRE(ptr.get_deleter().state_ == 42); -// REQUIRE(ptr_orig.get_deleter().state_ == 43); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_deleter == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner swap two instances", "[owner_utility]") { -// memory_tracker mem_track; - -// { -// test_ptr ptr_orig(new test_object); -// test_object* ptr_orig_raw = ptr_orig.get(); -// test_ptr ptr(new test_object); -// test_object* ptr_raw = ptr.get(); -// ptr.swap(ptr_orig); -// REQUIRE(instances == 2); -// REQUIRE(ptr_orig.get() == ptr_raw); -// REQUIRE(ptr.get() == ptr_orig_raw); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner swap two instances sealed", "[owner_utility]") { -// memory_tracker mem_track; - -// { -// test_sptr ptr_orig = oup::make_observable_sealed(); -// test_object* ptr_orig_raw = ptr_orig.get(); -// test_sptr ptr = oup::make_observable_sealed(); -// test_object* ptr_raw = ptr.get(); -// ptr.swap(ptr_orig); -// REQUIRE(instances == 2); -// REQUIRE(ptr_orig.get() == ptr_raw); -// REQUIRE(ptr.get() == ptr_orig_raw); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner swap two instances with deleter", "[owner_utility]") { -// memory_tracker mem_track; - -// { -// test_ptr_with_deleter ptr_orig(new test_object, test_deleter{42}); -// test_object* ptr_orig_raw = ptr_orig.get(); -// test_ptr_with_deleter ptr(new test_object, test_deleter{43}); -// test_object* ptr_raw = ptr.get(); -// ptr.swap(ptr_orig); -// REQUIRE(instances == 2); -// REQUIRE(instances_deleter == 2); -// REQUIRE(ptr_orig.get() == ptr_raw); -// REQUIRE(ptr.get() == ptr_orig_raw); -// REQUIRE(ptr.get_deleter().state_ == 42); -// REQUIRE(ptr_orig.get_deleter().state_ == 43); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_deleter == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner swap self", "[owner_utility]") { -// memory_tracker mem_track; - -// { -// test_ptr ptr(new test_object); -// ptr.swap(ptr); -// REQUIRE(instances == 1); -// REQUIRE(ptr.get() != nullptr); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner swap self sealed", "[owner_utility]") { -// memory_tracker mem_track; - -// { -// test_sptr ptr = oup::make_observable_sealed(); -// ptr.swap(ptr); -// REQUIRE(instances == 1); -// REQUIRE(ptr.get() != nullptr); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner swap self with deleter", "[owner_utility]") { -// memory_tracker mem_track; - -// { -// test_ptr_with_deleter ptr(new test_object, test_deleter{43}); -// ptr.swap(ptr); -// REQUIRE(instances == 1); -// REQUIRE(ptr.get() != nullptr); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_deleter == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner dereference", "[owner_utility]") { -// memory_tracker mem_track; - -// { -// test_ptr ptr(new test_object); -// REQUIRE(ptr->state_ == 1337); -// REQUIRE((*ptr).state_ == 1337); -// } - -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner dereference sealed", "[owner_utility]") { -// memory_tracker mem_track; - -// { -// test_sptr ptr = oup::make_observable_sealed(); -// REQUIRE(ptr->state_ == 1337); -// REQUIRE((*ptr).state_ == 1337); -// } - -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner operator bool valid", "[owner_utility]") { -// memory_tracker mem_track; - -// { -// test_ptr ptr(new test_object); -// if (ptr) { -// } else -// FAIL("if (ptr) should have been true"); -// } - -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner operator bool valid sealed", "[owner_utility]") { -// memory_tracker mem_track; - -// { -// test_sptr ptr = oup::make_observable_sealed(); -// if (ptr) { -// } else -// FAIL("if (ptr) should have been true"); -// } - -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner operator bool invalid", "[owner_utility]") { -// memory_tracker mem_track; - -// { -// test_ptr ptr; -// if (ptr) -// FAIL("if (ptr) should not have been true"); -// } - -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner operator bool invalid sealed", "[owner_utility]") { -// memory_tracker mem_track; - -// { -// test_sptr ptr; -// if (ptr) -// FAIL("if (ptr) should not have been true"); -// } - -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner release valid", "[owner_utility]") { -// memory_tracker mem_track; - -// { -// test_ptr ptr(new test_object); -// test_object* ptr_raw = ptr.release(); -// REQUIRE(ptr_raw != nullptr); -// REQUIRE(ptr.get() == nullptr); -// REQUIRE(instances == 1); -// delete ptr_raw; -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner release valid with observer", "[owner_utility]") { -// memory_tracker mem_track; - -// { -// test_optr optr; -// { -// test_ptr ptr(new test_object); -// optr = ptr; -// test_object* ptr_raw = ptr.release(); -// REQUIRE(ptr_raw != nullptr); -// REQUIRE(ptr.get() == nullptr); -// REQUIRE(instances == 1); -// delete ptr_raw; -// } - -// REQUIRE(optr.expired()); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner release valid from make_observable_unique", "[owner_utility]") { -// memory_tracker mem_track; - -// { -// test_ptr ptr = oup::make_observable_unique(); -// test_object* ptr_raw = ptr.release(); -// REQUIRE(ptr_raw != nullptr); -// REQUIRE(ptr.get() == nullptr); -// REQUIRE(instances == 1); -// delete ptr_raw; -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner release valid from make_observable_unique with observer", "[owner_utility]") { -// memory_tracker mem_track; - -// { -// test_optr optr; -// { -// test_ptr ptr = oup::make_observable_unique(); -// optr = ptr; -// test_object* ptr_raw = ptr.release(); -// REQUIRE(ptr_raw != nullptr); -// REQUIRE(ptr.get() == nullptr); -// REQUIRE(instances == 1); -// delete ptr_raw; -// } - -// REQUIRE(optr.expired()); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner release valid with deleter", "[owner_utility]") { -// memory_tracker mem_track; - -// { -// test_ptr_with_deleter ptr(new test_object, test_deleter{42}); -// test_object* ptr_raw = ptr.release(); -// REQUIRE(ptr_raw != nullptr); -// REQUIRE(ptr.get() == nullptr); -// REQUIRE(instances == 1); -// REQUIRE(instances_deleter == 1); -// REQUIRE(ptr.get_deleter().state_ == 42); -// delete ptr_raw; -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_deleter == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner release valid with deleter with observer", "[owner_utility]") { -// memory_tracker mem_track; - -// { -// test_optr optr; -// { -// test_ptr_with_deleter ptr(new test_object, test_deleter{42}); -// optr = ptr; -// test_object* ptr_raw = ptr.release(); -// REQUIRE(ptr_raw != nullptr); -// REQUIRE(ptr.get() == nullptr); -// REQUIRE(instances == 1); -// REQUIRE(instances_deleter == 1); -// REQUIRE(ptr.get_deleter().state_ == 42); -// delete ptr_raw; -// } - -// REQUIRE(optr.expired()); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_deleter == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner release invalid", "[owner_utility]") { -// memory_tracker mem_track; - -// { -// test_ptr ptr; -// REQUIRE(ptr.release() == nullptr); -// REQUIRE(instances == 0); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("owner release invalid with deleter", "[owner_utility]") { -// memory_tracker mem_track; - -// { -// test_ptr_with_deleter ptr; -// REQUIRE(ptr.release() == nullptr); -// REQUIRE(instances == 0); -// REQUIRE(instances_deleter == 1); -// } - -// REQUIRE(instances == 0); -// REQUIRE(instances_deleter == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("make observable unique", "[make_observable_unique]") { -// memory_tracker mem_track; - -// { -// test_ptr ptr = oup::make_observable_unique(); -// REQUIRE(instances == 1); -// REQUIRE(ptr.get() != nullptr); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("make observable unique throw in constructor", "[make_observable_unique]") { -// memory_tracker mem_track; - -// REQUIRE_THROWS_AS(oup::make_observable_unique(), throw_constructor); - -// REQUIRE(instances_thrower == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("make observable non virtual unique throw in constructor", "[make_observable_unique]") -// { -// memory_tracker mem_track; - -// REQUIRE_THROWS_AS( -// (oup::make_observable< -// test_object_thrower_observer_from_this_non_virtual_unique, -// unique_non_virtual_policy>()), -// throw_constructor); - -// REQUIRE(instances_thrower == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("make observable sealed", "[make_observable_sealed]") { -// memory_tracker mem_track; - -// { -// test_sptr ptr = oup::make_observable_sealed(); -// REQUIRE(instances == 1); -// REQUIRE(ptr.get() != nullptr); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("make observable sealed throw in constructor", "[make_observable_sealed]") { -// memory_tracker mem_track; - -// REQUIRE_THROWS_AS(oup::make_observable_sealed(), throw_constructor); - -// REQUIRE(instances_thrower == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("observer size", "[observer_size]") { -// REQUIRE(sizeof(test_optr) == 2 * sizeof(void*)); -// } - -// TEST_CASE("observer default constructor", "[observer_construction]") { -// memory_tracker mem_track; - -// { -// test_optr ptr; -// REQUIRE(instances == 0); -// REQUIRE(ptr.get() == nullptr); -// REQUIRE(ptr.expired() == true); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("observer nullptr constructor", "[observer_construction]") { -// memory_tracker mem_track; - -// { -// test_optr ptr{nullptr}; -// REQUIRE(instances == 0); -// REQUIRE(ptr.get() == nullptr); -// REQUIRE(ptr.expired() == true); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("observer copy constructor", "[observer_construction]") { -// memory_tracker mem_track; - -// { -// test_ptr ptr_owner{new test_object}; -// test_optr ptr_orig{ptr_owner}; -// { -// test_optr ptr(ptr_orig); -// REQUIRE(instances == 1); -// REQUIRE(ptr.get() != nullptr); -// REQUIRE(ptr.expired() == false); -// REQUIRE(ptr_orig.get() != nullptr); -// REQUIRE(ptr_orig.expired() == false); - -// ptr_owner.reset(); -// REQUIRE(ptr.get() == nullptr); -// REQUIRE(ptr.expired() == true); -// } - -// REQUIRE(instances == 0); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("observer explicit conversion copy constructor ", "[observer_construction]") { -// memory_tracker mem_track; - -// { -// test_ptr ptr_owner{new test_object_derived}; -// test_optr ptr_orig{ptr_owner}; -// { -// test_optr ptr{ptr_orig, static_cast(ptr_orig.get())}; -// REQUIRE(instances == 1); -// REQUIRE(ptr.get() == static_cast(ptr_owner.get())); -// REQUIRE(ptr.expired() == false); -// REQUIRE(ptr_orig.get() == ptr_owner.get()); -// REQUIRE(ptr_orig.expired() == false); - -// ptr_owner.reset(); -// REQUIRE(ptr.get() == nullptr); -// REQUIRE(ptr.expired() == true); -// } - -// REQUIRE(instances == 0); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("observer explicit conversion copy constructor null pointer", -// "[observer_construction]") { -// memory_tracker mem_track; - -// { -// test_ptr ptr_owner{new test_object_derived}; -// test_optr ptr_orig{ptr_owner}; -// { -// test_optr ptr{ptr_orig, static_cast(nullptr)}; -// REQUIRE(instances == 1); -// REQUIRE(ptr.get() == nullptr); -// REQUIRE(ptr.expired() == true); -// REQUIRE(ptr_orig.get() == ptr_owner.get()); -// REQUIRE(ptr_orig.expired() == false); -// } - -// REQUIRE(instances == 1); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -// TEST_CASE("observer explicit conversion copy constructor subobject", "[observer_construction]") { -// memory_tracker mem_track; - -// { -// test_ptr ptr_owner{new test_object_derived}; -// test_optr ptr_orig{ptr_owner}; -// { -// int_optr ptr{ptr_orig, &ptr_owner->state_}; -// REQUIRE(instances == 1); -// REQUIRE(ptr.get() == &ptr_owner->state_); -// REQUIRE(ptr.expired() == false); -// REQUIRE(ptr_orig.get() == ptr_owner.get()); -// REQUIRE(ptr_orig.expired() == false); - -// ptr_owner.reset(); -// REQUIRE(ptr.get() == nullptr); -// REQUIRE(ptr.expired() == true); -// } - -// REQUIRE(instances == 0); -// } - -// REQUIRE(instances == 0); -// REQUIRE(mem_track.allocated() == 0u); -// REQUIRE(mem_track.double_delete() == 0u); -// } - -TEST_CASE("observer from null owner constructor", "[observer_construction]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner; - { - test_optr ptr{ptr_owner}; - REQUIRE(instances == 0); - REQUIRE(ptr.get() == ptr_owner.get()); - REQUIRE(ptr.expired() == true); - } - - REQUIRE(instances == 0); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer from owner constructor", "[observer_construction]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner{new test_object}; - { - test_optr ptr{ptr_owner}; - REQUIRE(instances == 1); - REQUIRE(ptr.get() == ptr_owner.get()); - REQUIRE(ptr.expired() == false); - - ptr_owner.reset(); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr.expired() == true); - } - - REQUIRE(instances == 0); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer from null owner casting constructor", "[observer_construction]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner; - { - test_optr ptr{ptr_owner, static_cast(nullptr)}; - REQUIRE(instances == 0); - REQUIRE(ptr.get() == ptr_owner.get()); - REQUIRE(ptr.expired() == true); - } - - REQUIRE(instances == 0); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer from owner casting constructor", "[observer_construction]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner{new test_object_derived}; - { - test_optr ptr{ptr_owner, dynamic_cast(ptr_owner.get())}; - REQUIRE(instances == 1); - REQUIRE(ptr.get() == ptr_owner.get()); - REQUIRE(ptr.expired() == false); - - ptr_owner.reset(); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr.expired() == true); - } - - REQUIRE(instances == 0); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer move constructor", "[observer_construction]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner{new test_object}; - test_optr ptr_orig{ptr_owner}; - { - test_optr ptr(std::move(ptr_orig)); - REQUIRE(instances == 1); - REQUIRE(ptr.get() != nullptr); - REQUIRE(ptr.expired() == false); - REQUIRE(ptr_orig.get() == nullptr); - REQUIRE(ptr_orig.expired() == true); - - ptr_owner.reset(); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr.expired() == true); - } - - REQUIRE(instances == 0); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer explicit conversion move constructor ", "[observer_construction]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner{new test_object_derived}; - test_optr ptr_orig{ptr_owner}; - { - test_optr ptr{std::move(ptr_orig), static_cast(ptr_orig.get())}; - REQUIRE(instances == 1); - REQUIRE(ptr.get() == static_cast(ptr_owner.get())); - REQUIRE(ptr.expired() == false); - REQUIRE(ptr_orig.get() == nullptr); - REQUIRE(ptr_orig.expired() == true); - - ptr_owner.reset(); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr.expired() == true); - } - - REQUIRE(instances == 0); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer explicit conversion move constructor null pointer", "[observer_construction]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner{new test_object_derived}; - test_optr ptr_orig{ptr_owner}; - { - test_optr ptr{std::move(ptr_orig), static_cast(nullptr)}; - REQUIRE(instances == 1); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr.expired() == true); - REQUIRE(ptr_orig.get() == nullptr); - REQUIRE(ptr_orig.expired() == true); - } - - REQUIRE(instances == 1); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer explicit conversion move constructor subobject", "[observer_construction]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner{new test_object_derived}; - test_optr ptr_orig{ptr_owner}; - { - int_optr ptr{std::move(ptr_orig), &ptr_owner->state_}; - REQUIRE(instances == 1); - REQUIRE(ptr.get() == &ptr_owner->state_); - REQUIRE(ptr.expired() == false); - REQUIRE(ptr_orig.get() == nullptr); - REQUIRE(ptr_orig.expired() == true); - - ptr_owner.reset(); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr.expired() == true); - } - - REQUIRE(instances == 0); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer acquiring constructor", "[observer_construction]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner{new test_object}; - test_optr ptr{ptr_owner}; - REQUIRE(instances == 1); - REQUIRE(ptr.get() != nullptr); - REQUIRE(ptr.expired() == false); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer acquiring constructor sealed", "[observer_construction]") { - memory_tracker mem_track; - - { - test_sptr ptr_owner = oup::make_observable_sealed(); - test_optr ptr{ptr_owner}; - REQUIRE(instances == 1); - REQUIRE(ptr.get() != nullptr); - REQUIRE(ptr.expired() == false); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer acquiring constructor derived", "[observer_construction]") { - memory_tracker mem_track; - - { - test_ptr_derived ptr_owner{new test_object_derived}; - test_optr ptr{ptr_owner}; - REQUIRE(instances == 1); - REQUIRE(ptr.get() != nullptr); - REQUIRE(ptr.expired() == false); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer acquiring constructor derived sealed", "[observer_construction]") { - memory_tracker mem_track; - - { - test_sptr_derived ptr_owner = oup::make_observable_sealed(); - test_optr ptr{ptr_owner}; - REQUIRE(instances == 1); - REQUIRE(ptr.get() != nullptr); - REQUIRE(ptr.expired() == false); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer acquiring constructor with deleter", "[observer_construction]") { - memory_tracker mem_track; - - { - test_ptr_with_deleter ptr_owner{new test_object, test_deleter{42}}; - test_optr ptr{ptr_owner}; - REQUIRE(instances == 1); - REQUIRE(ptr.get() != nullptr); - REQUIRE(ptr.expired() == false); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer implicit copy conversion constructor", "[observer_construction]") { - memory_tracker mem_track; - - { - test_ptr_derived ptr_owner{new test_object_derived}; - test_optr_derived ptr_orig{ptr_owner}; - { - test_optr ptr(ptr_orig); - REQUIRE(instances == 1); - REQUIRE(instances_derived == 1); - REQUIRE(ptr.get() != nullptr); - REQUIRE(ptr.expired() == false); - } - - REQUIRE(instances == 1); - REQUIRE(instances_derived == 1); - REQUIRE(ptr_orig.get() != nullptr); - REQUIRE(ptr_orig.expired() == false); - } - - REQUIRE(instances == 0); - REQUIRE(instances_derived == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer implicit move conversion constructor", "[observer_construction]") { - memory_tracker mem_track; - - { - test_ptr_derived ptr_owner{new test_object_derived}; - test_optr_derived ptr_orig{ptr_owner}; - { - test_optr ptr(std::move(ptr_orig)); - REQUIRE(instances == 1); - REQUIRE(instances_derived == 1); - REQUIRE(ptr.get() != nullptr); - REQUIRE(ptr.expired() == false); - } - - REQUIRE(instances == 1); - REQUIRE(instances_derived == 1); - REQUIRE(ptr_orig.get() == nullptr); - REQUIRE(ptr_orig.expired() == true); - } - - REQUIRE(instances == 0); - REQUIRE(instances_derived == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer expiring", "[observer_utility]") { - memory_tracker mem_track; - - { - test_optr ptr; - - { - test_ptr ptr_owner{new test_object}; - ptr = ptr_owner; - REQUIRE(instances == 1); - REQUIRE(ptr.get() != nullptr); - REQUIRE(ptr.expired() == false); - } - - REQUIRE(instances == 0); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr.expired() == true); - } - - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer expiring sealed", "[observer_utility]") { - memory_tracker mem_track; - - { - test_optr ptr; - - { - test_sptr ptr_owner = oup::make_observable_sealed(); - ptr = ptr_owner; - REQUIRE(instances == 1); - REQUIRE(ptr.get() != nullptr); - REQUIRE(ptr.expired() == false); - } - - REQUIRE(instances == 0); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr.expired() == true); - } - - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer expiring reset", "[observer_utility]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner{new test_object}; - test_optr ptr = ptr_owner; - REQUIRE(!ptr.expired()); - ptr_owner.reset(); - REQUIRE(ptr.expired()); - } - - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer expiring reset sealed", "[observer_utility]") { - memory_tracker mem_track; - - { - test_sptr ptr_owner = oup::make_observable_sealed(); - test_optr ptr = ptr_owner; - REQUIRE(!ptr.expired()); - ptr_owner.reset(); - REQUIRE(ptr.expired()); - } - - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer not expiring when owner moved", "[observer_utility]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner{new test_object}; - test_optr ptr = ptr_owner; - REQUIRE(!ptr.expired()); - test_ptr ptr_owner_new = std::move(ptr_owner); - REQUIRE(!ptr.expired()); - } - - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer not expiring when owner moved sealed", "[observer_utility]") { - memory_tracker mem_track; - - { - test_sptr ptr_owner = oup::make_observable_sealed(); - test_optr ptr = ptr_owner; - REQUIRE(!ptr.expired()); - test_sptr ptr_owner_new = std::move(ptr_owner); - REQUIRE(!ptr.expired()); - } - - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer reset to null", "[observer_utility]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner(new test_object); - test_optr ptr(ptr_owner); - ptr.reset(); - REQUIRE(instances == 1); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr.expired() == true); - } - - REQUIRE(instances == 0); -} - -TEST_CASE("observer swap no instance", "[observer_utility]") { - memory_tracker mem_track; - - { - test_optr ptr_orig; - test_optr ptr; - ptr.swap(ptr_orig); - REQUIRE(instances == 0); - REQUIRE(ptr_orig.get() == nullptr); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr_orig.expired() == true); - REQUIRE(ptr.expired() == true); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer swap one instance", "[observer_utility]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner(new test_object); - test_optr ptr_orig(ptr_owner); - test_optr ptr; - ptr.swap(ptr_orig); - REQUIRE(instances == 1); - REQUIRE(ptr_orig.get() == nullptr); - REQUIRE(ptr.get() != nullptr); - REQUIRE(ptr_orig.expired() == true); - REQUIRE(ptr.expired() == false); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer swap two same instance", "[observer_utility]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner(new test_object); - test_optr ptr_orig(ptr_owner); - test_optr ptr(ptr_owner); - ptr.swap(ptr_orig); - REQUIRE(instances == 1); - REQUIRE(ptr_orig.get() == ptr_owner.get()); - REQUIRE(ptr.get() == ptr_owner.get()); - REQUIRE(ptr_orig.expired() == false); - REQUIRE(ptr.expired() == false); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer swap two different instances", "[observer_utility]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner1(new test_object); - test_ptr ptr_owner2(new test_object); - test_optr ptr_orig(ptr_owner1); - test_optr ptr(ptr_owner2); - ptr.swap(ptr_orig); - REQUIRE(instances == 2); - REQUIRE(ptr_orig.get() == ptr_owner2.get()); - REQUIRE(ptr.get() == ptr_owner1.get()); - REQUIRE(ptr_orig.expired() == false); - REQUIRE(ptr.expired() == false); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer swap self", "[observer_utility]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner(new test_object); - test_optr ptr(ptr_owner); - ptr.swap(ptr); - REQUIRE(instances == 1); - REQUIRE(ptr.get() == ptr_owner.get()); - REQUIRE(ptr.expired() == false); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer dereference", "[observer_utility]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner(new test_object); - test_optr ptr(ptr_owner); - REQUIRE(ptr->state_ == 1337); - REQUIRE((*ptr).state_ == 1337); - } - - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer operator bool valid", "[observer_utility]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner(new test_object); - test_optr ptr(ptr_owner); - if (ptr) { - } else - FAIL("if (ptr) should have been true"); - } - - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer operator bool invalid", "[observer_utility]") { - memory_tracker mem_track; - - { - test_optr ptr; - if (ptr) - FAIL("if (ptr) should not have been true"); - } - - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer get and raw get", "[observer_utility]") { - memory_tracker mem_track; - - { - test_optr ptr; - REQUIRE(ptr.raw_get() == nullptr); - REQUIRE(ptr.get() == nullptr); - test_ptr owner_ptr{new test_object}; - ptr = owner_ptr; - REQUIRE(ptr.raw_get() == owner_ptr.get()); - REQUIRE(ptr.get() == owner_ptr.get()); - test_object* raw_ptr = owner_ptr.get(); - owner_ptr.reset(); - REQUIRE(ptr.raw_get() == raw_ptr); - REQUIRE(ptr.get() == nullptr); - } - - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer copy assignment operator valid to empty", "[observer_assignment]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner{new test_object}; - test_optr ptr_orig{ptr_owner}; - { - test_optr ptr; - ptr = ptr_orig; - REQUIRE(instances == 1); - REQUIRE(ptr.get() == ptr_owner.get()); - REQUIRE(ptr.expired() == false); - REQUIRE(ptr_orig.get() == ptr_owner.get()); - REQUIRE(ptr_orig.expired() == false); - } - - REQUIRE(instances == 1); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer copy assignment operator valid to valid", "[observer_assignment]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner1{new test_object}; - test_ptr ptr_owner2{new test_object}; - test_optr ptr_orig{ptr_owner1}; - { - test_optr ptr(ptr_owner2); - ptr = ptr_orig; - REQUIRE(instances == 2); - REQUIRE(ptr.get() == ptr_owner1.get()); - REQUIRE(ptr.expired() == false); - REQUIRE(ptr_orig.get() == ptr_owner1.get()); - REQUIRE(ptr_orig.expired() == false); - } - - REQUIRE(instances == 2); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer copy assignment operator empty to empty", "[observer_assignment]") { - memory_tracker mem_track; - - { - test_optr ptr_orig; - { - test_optr ptr; - ptr = ptr_orig; - REQUIRE(instances == 0); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr.expired() == true); - REQUIRE(ptr_orig.get() == nullptr); - REQUIRE(ptr_orig.expired() == true); - } - - REQUIRE(instances == 0); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer copy assignment operator self to self", "[observer_assignment]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner{new test_object}; - test_optr ptr{ptr_owner}; - ptr = ptr; - REQUIRE(instances == 1); - REQUIRE(ptr.get() != nullptr); - REQUIRE(ptr.expired() == false); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer copy assignment operator self to self expired", "[observer_assignment]") { - memory_tracker mem_track; - - { - test_optr ptr; - { - test_ptr ptr_owner{new test_object}; - ptr = ptr_owner; - } - ptr = ptr; - REQUIRE(instances == 0); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr.expired() == true); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer copy assignment operator self to self empty", "[observer_assignment]") { - memory_tracker mem_track; - - { - test_optr ptr; - ptr = ptr; - REQUIRE(instances == 0); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr.expired() == true); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer move assignment operator valid to empty", "[observer_assignment]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner{new test_object}; - test_optr ptr_orig{ptr_owner}; - { - test_optr ptr; - ptr = std::move(ptr_orig); - REQUIRE(instances == 1); - REQUIRE(ptr.get() == ptr_owner.get()); - REQUIRE(ptr.expired() == false); - REQUIRE(ptr_orig.get() == nullptr); - REQUIRE(ptr_orig.expired() == true); - } - - REQUIRE(instances == 1); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer move assignment operator valid to valid", "[observer_assignment]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner1{new test_object}; - test_ptr ptr_owner2{new test_object}; - test_optr ptr_orig{ptr_owner1}; - { - test_optr ptr{ptr_owner2}; - ptr = std::move(ptr_orig); - REQUIRE(instances == 2); - REQUIRE(ptr.get() == ptr_owner1.get()); - REQUIRE(ptr.expired() == false); - REQUIRE(ptr_orig.get() == nullptr); - REQUIRE(ptr_orig.expired() == true); - } - - REQUIRE(instances == 2); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer move assignment operator empty to empty", "[observer_assignment]") { - memory_tracker mem_track; - - { - test_optr ptr_orig; - { - test_optr ptr; - ptr = std::move(ptr_orig); - REQUIRE(instances == 0); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr.expired() == true); - REQUIRE(ptr_orig.get() == nullptr); - REQUIRE(ptr_orig.expired() == true); - } - - REQUIRE(instances == 0); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer move assignment operator self to self", "[observer_assignment]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner{new test_object}; - test_optr ptr{ptr_owner}; - ptr = std::move(ptr); - REQUIRE(instances == 1); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr.expired() == true); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer move assignment operator self to self expired", "[observer_assignment]") { - memory_tracker mem_track; - - { - test_optr ptr; - { - test_ptr ptr_owner{new test_object}; - ptr = ptr_owner; - } - ptr = std::move(ptr); - REQUIRE(instances == 0); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr.expired() == true); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer move assignment operator self to self empty", "[observer_assignment]") { - memory_tracker mem_track; - - { - test_optr ptr; - ptr = std::move(ptr); - REQUIRE(instances == 0); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr.expired() == true); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer acquiring assignment operator valid to empty", "[observer_assignment]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner{new test_object}; - test_optr ptr; - ptr = ptr_owner; - - REQUIRE(instances == 1); - REQUIRE(ptr.get() == ptr_owner.get()); - REQUIRE(ptr.expired() == false); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer acquiring assignment operator valid to valid", "[observer_assignment]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner1{new test_object}; - test_ptr ptr_owner2{new test_object}; - test_optr ptr{ptr_owner1}; - ptr = ptr_owner2; - - REQUIRE(instances == 2); - REQUIRE(ptr.get() == ptr_owner2.get()); - REQUIRE(ptr.expired() == false); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer acquiring assignment operator empty to valid", "[observer_assignment]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner1{new test_object}; - test_ptr ptr_owner2; - test_optr ptr{ptr_owner1}; - ptr = ptr_owner2; - - REQUIRE(instances == 1); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr.expired() == true); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer acquiring assignment operator empty to empty", "[observer_assignment]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner; - test_optr ptr; - ptr = ptr_owner; - - REQUIRE(instances == 0); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr.expired() == true); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer acquiring assignment operator valid to empty sealed", "[observer_assignment]") { - memory_tracker mem_track; - - { - test_sptr ptr_owner = oup::make_observable_sealed(); - test_optr ptr; - ptr = ptr_owner; - - REQUIRE(instances == 1); - REQUIRE(ptr.get() == ptr_owner.get()); - REQUIRE(ptr.expired() == false); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer acquiring assignment operator valid to valid sealed", "[observer_assignment]") { - memory_tracker mem_track; - - { - test_sptr ptr_owner1 = oup::make_observable_sealed(); - test_sptr ptr_owner2 = oup::make_observable_sealed(); - test_optr ptr{ptr_owner1}; - ptr = ptr_owner2; - - REQUIRE(instances == 2); - REQUIRE(ptr.get() == ptr_owner2.get()); - REQUIRE(ptr.expired() == false); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer acquiring assignment operator empty to valid sealed", "[observer_assignment]") { - memory_tracker mem_track; - - { - test_sptr ptr_owner1 = oup::make_observable_sealed(); - test_sptr ptr_owner2; - test_optr ptr{ptr_owner1}; - ptr = ptr_owner2; - - REQUIRE(instances == 1); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr.expired() == true); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer acquiring assignment operator empty to empty sealed", "[observer_assignment]") { - memory_tracker mem_track; - - { - test_sptr ptr_owner; - test_optr ptr; - ptr = ptr_owner; - - REQUIRE(instances == 0); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr.expired() == true); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE( - "observer acquiring assignment operator valid to empty with deleter", "[observer_assignment]") { - memory_tracker mem_track; - - { - test_ptr_with_deleter ptr_owner{new test_object, test_deleter{42}}; - test_optr ptr; - ptr = ptr_owner; - - REQUIRE(instances == 1); - REQUIRE(ptr.get() == ptr_owner.get()); - REQUIRE(ptr.expired() == false); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE( - "observer acquiring assignment operator valid to valid with deleter", "[observer_assignment]") { - memory_tracker mem_track; - - { - test_ptr_with_deleter ptr_owner1{new test_object, test_deleter{42}}; - test_ptr_with_deleter ptr_owner2{new test_object, test_deleter{42}}; - test_optr ptr{ptr_owner1}; - ptr = ptr_owner2; - - REQUIRE(instances == 2); - REQUIRE(ptr.get() == ptr_owner2.get()); - REQUIRE(ptr.expired() == false); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE( - "observer acquiring assignment operator empty to valid with deleter", "[observer_assignment]") { - memory_tracker mem_track; - - { - test_ptr_with_deleter ptr_owner1{new test_object, test_deleter{42}}; - test_ptr_with_deleter ptr_owner2{nullptr, test_deleter{43}}; - test_optr ptr{ptr_owner1}; - ptr = ptr_owner2; - - REQUIRE(instances == 1); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr.expired() == true); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE( - "observer acquiring assignment operator empty to empty with deleter", "[observer_assignment]") { - memory_tracker mem_track; - - { - test_ptr_with_deleter ptr_owner{nullptr, test_deleter{42}}; - test_optr ptr; - ptr = ptr_owner; - - REQUIRE(instances == 0); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr.expired() == true); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer comparison valid ptr vs nullptr", "[observer_comparison]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner(new test_object); - test_optr ptr(ptr_owner); - REQUIRE(ptr != nullptr); - REQUIRE(!(ptr == nullptr)); - REQUIRE(nullptr != ptr); - REQUIRE(!(nullptr == ptr)); - } - - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer comparison invalid ptr vs nullptr", "[observer_comparison]") { - memory_tracker mem_track; - - { - test_optr ptr; - REQUIRE(ptr == nullptr); - REQUIRE(!(ptr != nullptr)); - REQUIRE(nullptr == ptr); - REQUIRE(!(nullptr != ptr)); - } - - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer comparison invalid ptr vs invalid ptr", "[observer_comparison]") { - memory_tracker mem_track; - - { - test_optr ptr1; - test_optr ptr2; - REQUIRE(ptr1 == ptr2); - REQUIRE(!(ptr1 != ptr2)); - } - - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer comparison invalid ptr vs valid ptr", "[observer_comparison]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner(new test_object); - test_optr ptr1; - test_optr ptr2(ptr_owner); - REQUIRE(ptr1 != ptr2); - REQUIRE(!(ptr1 == ptr2)); - REQUIRE(ptr2 != ptr1); - REQUIRE(!(ptr2 == ptr1)); - } - - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer comparison valid ptr vs valid ptr same owner", "[observer_comparison]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner(new test_object); - test_optr ptr1(ptr_owner); - test_optr ptr2(ptr_owner); - REQUIRE(ptr1 == ptr2); - REQUIRE(!(ptr1 != ptr2)); - REQUIRE(ptr2 == ptr1); - REQUIRE(!(ptr2 != ptr1)); - } - - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer comparison valid ptr vs valid ptr different owner", "[observer_comparison]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner1(new test_object); - test_ptr ptr_owner2(new test_object); - test_optr ptr1(ptr_owner1); - test_optr ptr2(ptr_owner2); - REQUIRE(ptr1 != ptr2); - REQUIRE(!(ptr1 == ptr2)); - REQUIRE(ptr2 != ptr1); - REQUIRE(!(ptr2 == ptr1)); - } - - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE( - "observer comparison valid ptr vs valid ptr same owner derived", "[observer_comparison]") { - memory_tracker mem_track; - - { - test_ptr_derived ptr_owner(new test_object_derived); - test_optr ptr1(ptr_owner); - test_optr_derived ptr2(ptr_owner); - REQUIRE(ptr1 == ptr2); - REQUIRE(!(ptr1 != ptr2)); - REQUIRE(ptr2 == ptr1); - REQUIRE(!(ptr2 != ptr1)); - } - - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE( - "observer comparison valid ptr vs valid ptr different owner derived", "[observer_comparison]") { - memory_tracker mem_track; - - { - test_ptr ptr_owner1(new test_object); - test_ptr_derived ptr_owner2(new test_object_derived); - test_optr ptr1(ptr_owner1); - test_optr_derived ptr2(ptr_owner2); - REQUIRE(ptr1 != ptr2); - REQUIRE(!(ptr1 == ptr2)); - REQUIRE(ptr2 != ptr1); - REQUIRE(!(ptr2 == ptr1)); - } - - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -struct observer_owner { - oup::observer_ptr obs; -}; - -TEST_CASE("object owning observer pointer to itself", "[system_tests]") { - memory_tracker mem_track; - - { - auto ptr = oup::make_observable_sealed(); - ptr->obs = ptr; - } - - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("object owning observer pointer to other", "[system_tests]") { - memory_tracker mem_track; - - { - auto ptr1 = oup::make_observable_sealed(); - auto ptr2 = oup::make_observable_sealed(); - ptr1->obs = ptr2; - ptr2->obs = ptr1; - } - - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("object owning observer pointer open chain", "[system_tests]") { - memory_tracker mem_track; - - { - auto ptr1 = oup::make_observable_sealed(); - auto ptr2 = oup::make_observable_sealed(); - auto ptr3 = oup::make_observable_sealed(); - ptr1->obs = ptr2; - ptr2->obs = ptr3; - } - - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("object owning observer pointer open chain reversed", "[system_tests]") { - memory_tracker mem_track; - - { - auto ptr1 = oup::make_observable_sealed(); - auto ptr2 = oup::make_observable_sealed(); - auto ptr3 = oup::make_observable_sealed(); - ptr3->obs = ptr2; - ptr2->obs = ptr1; - } - - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("object owning observer pointer closed chain interleaved", "[system_tests]") { - memory_tracker mem_track; - - { - auto ptr1 = oup::make_observable_sealed(); - auto ptr2 = oup::make_observable_sealed(); - auto ptr3 = oup::make_observable_sealed(); - auto ptr4 = oup::make_observable_sealed(); - ptr1->obs = ptr2; - ptr2->obs = ptr4; - ptr3->obs = ptr1; - ptr4->obs = ptr3; - } - - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("pointers in vector", "[system_tests]") { - memory_tracker mem_track; - - { - std::vector vec_own; - std::vector vec_obs; - - vec_own.resize(100); - REQUIRE(std::all_of(vec_own.begin(), vec_own.end(), [](const auto& p) { - return p == nullptr; - }) == true); - - std::generate(vec_own.begin(), vec_own.end(), []() { - return oup::make_observable_sealed(); - }); - REQUIRE(std::none_of(vec_own.begin(), vec_own.end(), [](const auto& p) { - return p == nullptr; - }) == true); - - vec_obs.resize(100); - REQUIRE(std::all_of(vec_obs.begin(), vec_obs.end(), [](const auto& p) { - return p == nullptr; - }) == true); - - std::copy(vec_own.begin(), vec_own.end(), vec_obs.begin()); - REQUIRE(std::none_of(vec_own.begin(), vec_own.end(), [](const auto& p) { - return p == nullptr; - }) == true); - - std::vector vec_own_new = std::move(vec_own); - REQUIRE(std::none_of(vec_own.begin(), vec_own.end(), [](const auto& p) { - return p == nullptr; - }) == true); - - vec_own_new.clear(); - REQUIRE(std::all_of(vec_obs.begin(), vec_obs.end(), [](const auto& p) { - return p == nullptr; - }) == true); - } - - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer from this unique", "[observer_from_this]") { - memory_tracker mem_track; - - { - test_ptr_from_this ptr{new test_object_observer_from_this_unique}; - const test_ptr_from_this& cptr = ptr; - - test_optr_from_this optr_from_this = ptr->observer_from_this(); - test_optr_from_this_const optr_from_this_const = cptr->observer_from_this(); - - REQUIRE(instances == 1); - REQUIRE(optr_from_this.expired() == false); - REQUIRE(optr_from_this_const.expired() == false); - REQUIRE(optr_from_this.get() == ptr.get()); - REQUIRE(optr_from_this_const.get() == ptr.get()); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer from this sealed", "[observer_from_this]") { - memory_tracker mem_track; - - { - test_sptr_from_this ptr = - oup::make_observable_sealed(); - const test_sptr_from_this& cptr = ptr; - - test_optr_from_this_sealed optr_from_this = ptr->observer_from_this(); - test_optr_from_this_const_sealed optr_from_this_const = cptr->observer_from_this(); - - REQUIRE(instances == 1); - REQUIRE(optr_from_this.expired() == false); - REQUIRE(optr_from_this_const.expired() == false); - REQUIRE(optr_from_this.get() == ptr.get()); - REQUIRE(optr_from_this_const.get() == ptr.get()); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer from this non virtual unique", "[observer_from_this]") { - memory_tracker mem_track; - - { - test_ptr_from_this_non_virtual ptr = oup::make_observable< - test_object_observer_from_this_non_virtual_unique, unique_non_virtual_policy>(); - const test_ptr_from_this_non_virtual& cptr = ptr; - - test_optr_from_this_non_virtual_unique optr_from_this = ptr->observer_from_this(); - test_optr_from_this_const_non_virtual_unique optr_from_this_const = - cptr->observer_from_this(); - - REQUIRE(instances == 1); - REQUIRE(optr_from_this.expired() == false); - REQUIRE(optr_from_this_const.expired() == false); - REQUIRE(optr_from_this.get() == ptr.get()); - REQUIRE(optr_from_this_const.get() == ptr.get()); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer from this maybe no block unique", "[observer_from_this]") { - memory_tracker mem_track; - - { - test_ptr_from_this_maybe_no_block ptr = oup::make_observable< - test_object_observer_from_this_maybe_no_block_unique, unique_maybe_no_block_policy>(); - const test_ptr_from_this_maybe_no_block& cptr = ptr; - - test_optr_from_this_maybe_no_block_unique optr_from_this = ptr->observer_from_this(); - test_optr_from_this_const_maybe_no_block_unique optr_from_this_const = - cptr->observer_from_this(); - - REQUIRE(instances == 1); - REQUIRE(optr_from_this.expired() == false); - REQUIRE(optr_from_this_const.expired() == false); - REQUIRE(optr_from_this.get() == ptr.get()); - REQUIRE(optr_from_this_const.get() == ptr.get()); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer from this maybe no block acquire", "[observer_from_this]") { - memory_tracker mem_track; - - { - test_ptr_from_this_maybe_no_block ptr{ - new test_object_observer_from_this_maybe_no_block_unique}; - const test_ptr_from_this_maybe_no_block& cptr = ptr; - - test_optr_from_this_maybe_no_block_unique optr_from_this = ptr->observer_from_this(); - test_optr_from_this_const_maybe_no_block_unique optr_from_this_const = - cptr->observer_from_this(); - - REQUIRE(instances == 1); - REQUIRE(optr_from_this.expired() == false); - REQUIRE(optr_from_this_const.expired() == false); - REQUIRE(optr_from_this.get() == ptr.get()); - REQUIRE(optr_from_this_const.get() == ptr.get()); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer from this maybe no block reset to new", "[observer_from_this]") { - memory_tracker mem_track; - - { - auto* raw_ptr1 = new test_object_observer_from_this_maybe_no_block_unique; - auto* raw_ptr2 = new test_object_observer_from_this_maybe_no_block_unique; - - test_ptr_from_this_maybe_no_block ptr{raw_ptr1}; - const test_ptr_from_this_maybe_no_block& cptr = ptr; - - ptr.reset(raw_ptr2); - - test_optr_from_this_maybe_no_block_unique optr_from_this = ptr->observer_from_this(); - test_optr_from_this_const_maybe_no_block_unique optr_from_this_const = - cptr->observer_from_this(); - - REQUIRE(instances == 1); - REQUIRE(optr_from_this.expired() == false); - REQUIRE(optr_from_this_const.expired() == false); - REQUIRE(optr_from_this.get() == ptr.get()); - REQUIRE(optr_from_this.get() == raw_ptr2); - REQUIRE(optr_from_this_const.get() == ptr.get()); - REQUIRE(optr_from_this_const.get() == raw_ptr2); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer from this maybe no block reset to new after release", "[observer_from_this]") { - memory_tracker mem_track; - - { - auto* raw_ptr = new test_object_observer_from_this_maybe_no_block_unique; - - test_ptr_from_this_maybe_no_block ptr{raw_ptr}; - const test_ptr_from_this_maybe_no_block& cptr = ptr; - - test_optr_from_this_maybe_no_block_unique optr_from_this = ptr->observer_from_this(); - test_optr_from_this_const_maybe_no_block_unique optr_from_this_const = - cptr->observer_from_this(); - - ptr.release(); - - REQUIRE(instances == 1); - REQUIRE(optr_from_this.expired() == false); - REQUIRE(optr_from_this_const.expired() == false); - REQUIRE(optr_from_this.get() == raw_ptr); - REQUIRE(optr_from_this_const.get() == raw_ptr); - - ptr.reset(raw_ptr); - - REQUIRE(instances == 1); - REQUIRE(optr_from_this.expired() == false); - REQUIRE(optr_from_this_const.expired() == false); - REQUIRE(optr_from_this.get() == ptr.get()); - REQUIRE(optr_from_this_const.get() == ptr.get()); - - ptr.reset(); - - REQUIRE(instances == 0); - REQUIRE(optr_from_this.expired() == true); - REQUIRE(optr_from_this_const.expired() == true); - REQUIRE(optr_from_this.get() == nullptr); - REQUIRE(optr_from_this_const.get() == nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer from this maybe no block reset to new bad alloc", "[observer_from_this]") { - memory_tracker mem_track; - - { - auto* raw_ptr1 = new test_object_observer_from_this_maybe_no_block_unique; - auto* raw_ptr2 = new test_object_observer_from_this_maybe_no_block_unique; - - test_ptr_from_this_maybe_no_block ptr{raw_ptr1}; - - try { - force_next_allocation_failure = true; - ptr.reset(raw_ptr2); - } catch (...) { - } - - REQUIRE(instances == 1); - REQUIRE(ptr.get() == raw_ptr1); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer from this virtual sealed", "[observer_from_this]") { - memory_tracker mem_track; - - { - test_sptr_from_this_virtual ptr = oup::make_observable< - test_object_observer_from_this_virtual_sealed, sealed_virtual_policy>(); - const test_sptr_from_this_virtual& cptr = ptr; - - test_optr_from_this_virtual_sealed optr_from_this = ptr->observer_from_this(); - test_optr_from_this_const_virtual_sealed optr_from_this_const = cptr->observer_from_this(); - - REQUIRE(instances == 1); - REQUIRE(optr_from_this.expired() == false); - REQUIRE(optr_from_this_const.expired() == false); - REQUIRE(optr_from_this.get() == ptr.get()); - REQUIRE(optr_from_this_const.get() == ptr.get()); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer from this derived", "[observer_from_this]") { - memory_tracker mem_track; - - { - test_ptr_from_this_derived ptr{new test_object_observer_from_this_derived_unique}; - const test_ptr_from_this_derived& cptr = ptr; - - test_optr_from_this optr_from_this = ptr->observer_from_this(); - test_optr_from_this_const optr_from_this_const = cptr->observer_from_this(); - - REQUIRE(instances == 1); - REQUIRE(optr_from_this.expired() == false); - REQUIRE(optr_from_this_const.expired() == false); - REQUIRE(optr_from_this.get() == ptr.get()); - REQUIRE(optr_from_this_const.get() == ptr.get()); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer from this derived into base", "[observer_from_this]") { - memory_tracker mem_track; - - { - test_object_observer_from_this_unique* orig_ptr = new test_object_observer_from_this_unique; - test_ptr ptr{orig_ptr}; - - test_optr_from_this optr_from_this = orig_ptr->observer_from_this(); - - REQUIRE(instances == 1); - REQUIRE(optr_from_this.expired() == false); - REQUIRE(optr_from_this.get() == ptr.get()); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer from this derived into base after cast", "[observer_from_this]") { - memory_tracker mem_track; - - { - test_object_observer_from_this_unique* orig_ptr = new test_object_observer_from_this_unique; - test_ptr ptr{static_cast(orig_ptr)}; - - const test_object_observer_from_this_unique* orig_cptr = orig_ptr; - - test_optr_from_this optr_from_this = orig_ptr->observer_from_this(); - test_optr_from_this_const optr_from_this_const = orig_cptr->observer_from_this(); - - REQUIRE(instances == 1); - REQUIRE(optr_from_this.expired() == false); - REQUIRE(optr_from_this.get() == ptr.get()); - REQUIRE(optr_from_this_const.expired() == false); - REQUIRE(optr_from_this_const.get() == ptr.get()); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer from this const", "[observer_from_this]") { - memory_tracker mem_track; - - { - test_cptr_from_this ptr{new test_object_observer_from_this_unique}; - test_optr_from_this_const optr_from_this = ptr->observer_from_this(); - - REQUIRE(instances == 1); - REQUIRE(optr_from_this.expired() == false); - REQUIRE(optr_from_this.get() == ptr.get()); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer from this const sealed", "[observer_from_this]") { - memory_tracker mem_track; - - { - test_csptr_from_this ptr = - oup::make_observable_sealed(); - test_optr_from_this_const_sealed optr_from_this = ptr->observer_from_this(); - - REQUIRE(instances == 1); - REQUIRE(optr_from_this.expired() == false); - REQUIRE(optr_from_this.get() == ptr.get()); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer from this after move", "[observer_from_this]") { - memory_tracker mem_track; - - { - test_ptr_from_this ptr1{new test_object_observer_from_this_unique}; - test_ptr_from_this ptr2{std::move(ptr1)}; - const test_ptr_from_this& cptr2 = ptr2; - - test_optr_from_this optr_from_this = ptr2->observer_from_this(); - test_optr_from_this_const optr_from_this_const = cptr2->observer_from_this(); - - REQUIRE(instances == 1); - REQUIRE(optr_from_this.expired() == false); - REQUIRE(optr_from_this_const.expired() == false); - REQUIRE(optr_from_this.get() == ptr2.get()); - REQUIRE(optr_from_this_const.get() == ptr2.get()); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer from this after move sealed", "[observer_from_this]") { - memory_tracker mem_track; - - { - test_sptr_from_this ptr1 = - oup::make_observable_sealed(); - test_sptr_from_this ptr2{std::move(ptr1)}; - const test_sptr_from_this& cptr2 = ptr2; - - test_optr_from_this_sealed optr_from_this = ptr2->observer_from_this(); - test_optr_from_this_const_sealed optr_from_this_const = cptr2->observer_from_this(); - - REQUIRE(instances == 1); - REQUIRE(optr_from_this.expired() == false); - REQUIRE(optr_from_this_const.expired() == false); - REQUIRE(optr_from_this.get() == ptr2.get()); - REQUIRE(optr_from_this_const.get() == ptr2.get()); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer from this after move assignment", "[observer_from_this]") { - memory_tracker mem_track; - - { - test_ptr_from_this ptr1{new test_object_observer_from_this_unique}; - test_ptr_from_this ptr2; - ptr2 = std::move(ptr1); - - const test_ptr_from_this& cptr2 = ptr2; - test_optr_from_this optr_from_this = ptr2->observer_from_this(); - test_optr_from_this_const optr_from_this_const = cptr2->observer_from_this(); - - REQUIRE(instances == 1); - REQUIRE(optr_from_this.expired() == false); - REQUIRE(optr_from_this_const.expired() == false); - REQUIRE(optr_from_this.get() == ptr2.get()); - REQUIRE(optr_from_this_const.get() == ptr2.get()); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer from this after move assignment sealed", "[observer_from_this]") { - memory_tracker mem_track; - - { - test_sptr_from_this ptr1 = - oup::make_observable_sealed(); - test_sptr_from_this ptr2; - ptr2 = std::move(ptr1); - const test_sptr_from_this& cptr2 = ptr2; - - test_optr_from_this_sealed optr_from_this = ptr2->observer_from_this(); - test_optr_from_this_const_sealed optr_from_this_const = cptr2->observer_from_this(); - - REQUIRE(instances == 1); - REQUIRE(optr_from_this.expired() == false); - REQUIRE(optr_from_this_const.expired() == false); - REQUIRE(optr_from_this.get() == ptr2.get()); - REQUIRE(optr_from_this_const.get() == ptr2.get()); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer from this after release", "[observer_from_this]") { - memory_tracker mem_track; - - { - test_ptr_from_this ptr1{new test_object_observer_from_this_unique}; - test_object_observer_from_this_unique* ptr2 = ptr1.release(); - const test_object_observer_from_this_unique* cptr2 = ptr2; - - { - test_optr_from_this optr_from_this = ptr2->observer_from_this(); - test_optr_from_this_const optr_from_this_const = cptr2->observer_from_this(); - - REQUIRE(instances == 1); - REQUIRE(optr_from_this.expired() == false); - REQUIRE(optr_from_this.get() == ptr2); - REQUIRE(optr_from_this_const.expired() == false); - REQUIRE(optr_from_this_const.get() == cptr2); - } - - // The object holds the last reference to the control block - delete ptr2; - REQUIRE(instances == 0); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer from this after release and reset", "[observer_from_this]") { - memory_tracker mem_track; - - { - test_ptr_from_this ptr1{new test_object_observer_from_this_unique}; - test_object_observer_from_this_unique* ptr2 = ptr1.release(); - const test_object_observer_from_this_unique* cptr2 = ptr2; - - test_ptr_from_this ptr3; - ptr3.reset(ptr2); - - test_optr_from_this optr_from_this = ptr2->observer_from_this(); - test_optr_from_this_const optr_from_this_const = cptr2->observer_from_this(); - - REQUIRE(instances == 1); - REQUIRE(optr_from_this.expired() == false); - REQUIRE(optr_from_this_const.expired() == false); - REQUIRE(optr_from_this.get() == ptr2); - REQUIRE(optr_from_this_const.get() == cptr2); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer from this stack", "[observer_from_this]") { - memory_tracker mem_track; - - { - test_object_observer_from_this_unique obj; - const test_object_observer_from_this_unique& cobj = obj; - - test_optr_from_this optr_from_this = obj.observer_from_this(); - test_optr_from_this_const optr_from_this_const = cobj.observer_from_this(); - - REQUIRE(instances == 1); - REQUIRE(optr_from_this.expired() == false); - REQUIRE(optr_from_this_const.expired() == false); - REQUIRE(optr_from_this.get() == &obj); - REQUIRE(optr_from_this_const.get() == &cobj); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer from this heap", "[observer_from_this]") { - memory_tracker mem_track; - - { - test_object_observer_from_this_unique* obj = new test_object_observer_from_this_unique; - const test_object_observer_from_this_unique* cobj = obj; - - test_optr_from_this optr_from_this = obj->observer_from_this(); - test_optr_from_this_const optr_from_this_const = cobj->observer_from_this(); - - REQUIRE(instances == 1); - REQUIRE(optr_from_this.expired() == false); - REQUIRE(optr_from_this_const.expired() == false); - REQUIRE(optr_from_this.get() == obj); - REQUIRE(optr_from_this_const.get() == cobj); - - delete obj; - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer from this stack virtual sealed", "[observer_from_this]") { - memory_tracker mem_track; - - { - test_object_observer_from_this_virtual_sealed obj; - const test_object_observer_from_this_virtual_sealed& cobj = obj; - - REQUIRE_THROWS_AS(obj.observer_from_this(), oup::bad_observer_from_this); - - REQUIRE_THROWS_AS(cobj.observer_from_this(), oup::bad_observer_from_this); - - REQUIRE(instances == 1); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer from this heap virtual sealed", "[observer_from_this]") { - memory_tracker mem_track; - - { - test_object_observer_from_this_virtual_sealed* obj = - new test_object_observer_from_this_virtual_sealed; - const test_object_observer_from_this_virtual_sealed* cobj = obj; - - REQUIRE_THROWS_AS(obj->observer_from_this(), oup::bad_observer_from_this); - - REQUIRE_THROWS_AS(cobj->observer_from_this(), oup::bad_observer_from_this); - - REQUIRE(instances == 1); - - delete obj; - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer from this multiple inheritance", "[observer_from_this]") { - memory_tracker mem_track; - - { - using this_base = - oup::enable_observer_from_this_unique; - using this_deriv = - oup::enable_observer_from_this_unique; - - test_object_observer_from_this_multi_unique* raw_ptr_deriv = - new test_object_observer_from_this_multi_unique; - test_object_observer_from_this_unique* raw_ptr_base = raw_ptr_deriv; - test_ptr_from_this_multi ptr(raw_ptr_deriv); - - test_optr_from_this optr_from_this_base = ptr->this_base::observer_from_this(); - test_optr_from_this_multi optr_from_this_deriv = ptr->this_deriv::observer_from_this(); - - REQUIRE(instances == 1); - REQUIRE(optr_from_this_base.expired() == false); - REQUIRE(optr_from_this_deriv.expired() == false); - REQUIRE(optr_from_this_base.get() == raw_ptr_base); - REQUIRE(optr_from_this_deriv.get() == raw_ptr_deriv); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer from this in constructor", "[observer_from_this]") { - memory_tracker mem_track; - - { - test_ptr_from_this_constructor ptr = - oup::make_observable_unique(); - - REQUIRE(instances == 1); - REQUIRE(ptr->ptr.expired() == false); - REQUIRE(ptr->ptr.get() == ptr.get()); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer from this in constructor sealed", "[observer_from_this]") { - memory_tracker mem_track; - - { - test_sptr_from_this_constructor ptr = - oup::make_observable_sealed(); - - REQUIRE(instances == 1); - REQUIRE(ptr->ptr.expired() == false); - REQUIRE(ptr->ptr.get() == ptr.get()); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer from this in constructor multiple inheritance", "[observer_from_this]") { - memory_tracker mem_track; - - { - test_ptr_from_this_constructor_multi ptr = - oup::make_observable_unique(); - - REQUIRE(instances == 1); - REQUIRE(ptr->ptr.expired() == false); - REQUIRE(ptr->ptr.get() == ptr.get()); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer from this in constructor multiple inheritance sealed", "[observer_from_this]") { - memory_tracker mem_track; - - { - test_sptr_from_this_constructor_multi ptr = - oup::make_observable_sealed(); - - REQUIRE(instances == 1); - REQUIRE(ptr->ptr.expired() == false); - REQUIRE(ptr->ptr.get() == ptr.get()); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("observer from this in constructor sealed virtual throws", "[observer_from_this]") { - memory_tracker mem_track; - - { - REQUIRE_THROWS_AS( - (oup::make_observable< - test_object_observer_from_this_constructor_bad, sealed_virtual_policy>()), - oup::bad_observer_from_this); - - REQUIRE(instances == 0); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("bad_observer_from_this", "[observer_from_this]") { - memory_tracker mem_track; - - oup::bad_observer_from_this e; - REQUIRE(e.what() != nullptr); - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("static pointer cast unique from valid", "[pointer_cast]") { - memory_tracker mem_track; - - { - test_object_derived* raw_ptr = new test_object_derived; - test_ptr ptr_orig{raw_ptr}; - test_ptr_derived ptr = oup::static_pointer_cast(std::move(ptr_orig)); - - REQUIRE(instances == 1); - REQUIRE(ptr_orig == nullptr); - REQUIRE(ptr.get() == raw_ptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("static pointer cast unique from null", "[pointer_cast]") { - memory_tracker mem_track; - - { - test_ptr ptr_orig; - test_ptr_derived ptr = oup::static_pointer_cast(std::move(ptr_orig)); - - REQUIRE(instances == 0); - REQUIRE(ptr_orig == nullptr); - REQUIRE(ptr == nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("static pointer cast sealed from valid", "[pointer_cast]") { - memory_tracker mem_track; - - { - test_sptr_derived ptr_init = oup::make_observable_sealed(); - test_object_derived* raw_ptr = ptr_init.get(); - test_sptr ptr_orig{std::move(ptr_init)}; - test_sptr_derived ptr = oup::static_pointer_cast(std::move(ptr_orig)); - - REQUIRE(instances == 1); - REQUIRE(ptr_orig == nullptr); - REQUIRE(ptr.get() == raw_ptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("static pointer cast sealed from null", "[pointer_cast]") { - memory_tracker mem_track; - - { - test_sptr ptr_orig; - test_sptr_derived ptr = oup::static_pointer_cast(std::move(ptr_orig)); - - REQUIRE(instances == 0); - REQUIRE(ptr_orig == nullptr); - REQUIRE(ptr == nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("static pointer cast observer copy from valid", "[pointer_cast]") { - memory_tracker mem_track; - - { - test_sptr_derived ptr_owner = oup::make_observable_sealed(); - test_object_derived* raw_ptr = ptr_owner.get(); - test_optr ptr_orig{ptr_owner}; - test_optr_derived ptr = oup::static_pointer_cast(ptr_orig); - - REQUIRE(instances == 1); - REQUIRE(ptr_orig.get() == raw_ptr); - REQUIRE(ptr.get() == raw_ptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("static pointer cast observer copy from null", "[pointer_cast]") { - memory_tracker mem_track; - - { - test_optr ptr_orig; - test_optr_derived ptr = oup::static_pointer_cast(ptr_orig); - - REQUIRE(instances == 0); - REQUIRE(ptr_orig == nullptr); - REQUIRE(ptr == nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("static pointer cast observer move from valid", "[pointer_cast]") { - memory_tracker mem_track; - - { - test_sptr_derived ptr_owner = oup::make_observable_sealed(); - test_object_derived* raw_ptr = ptr_owner.get(); - test_optr ptr_orig{ptr_owner}; - test_optr_derived ptr = oup::static_pointer_cast(std::move(ptr_orig)); - - REQUIRE(instances == 1); - REQUIRE(ptr_orig == nullptr); - REQUIRE(ptr.get() == raw_ptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("static pointer cast observer move from null", "[pointer_cast]") { - memory_tracker mem_track; - - { - test_optr ptr_orig; - test_optr_derived ptr = oup::static_pointer_cast(std::move(ptr_orig)); - - REQUIRE(instances == 0); - REQUIRE(ptr_orig == nullptr); - REQUIRE(ptr == nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("const pointer cast unique from valid", "[pointer_cast]") { - memory_tracker mem_track; - - { - test_object* raw_ptr = new test_object; - test_ptr_const ptr_orig{raw_ptr}; - test_ptr ptr = oup::const_pointer_cast(std::move(ptr_orig)); - - REQUIRE(instances == 1); - REQUIRE(ptr_orig == nullptr); - REQUIRE(ptr.get() == raw_ptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("const pointer cast unique from null", "[pointer_cast]") { - memory_tracker mem_track; - - { - test_ptr_const ptr_orig; - test_ptr ptr = oup::const_pointer_cast(std::move(ptr_orig)); - - REQUIRE(instances == 0); - REQUIRE(ptr_orig == nullptr); - REQUIRE(ptr == nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("const pointer cast sealed from valid", "[pointer_cast]") { - memory_tracker mem_track; - - { - test_sptr ptr_init = oup::make_observable_sealed(); - test_object* raw_ptr = ptr_init.get(); - test_sptr_const ptr_orig{std::move(ptr_init)}; - test_sptr ptr = oup::const_pointer_cast(std::move(ptr_orig)); - - REQUIRE(instances == 1); - REQUIRE(ptr_orig == nullptr); - REQUIRE(ptr.get() == raw_ptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("const pointer cast sealed from null", "[pointer_cast]") { - memory_tracker mem_track; - - { - test_sptr_const ptr_orig; - test_sptr ptr = oup::const_pointer_cast(std::move(ptr_orig)); - - REQUIRE(instances == 0); - REQUIRE(ptr_orig == nullptr); - REQUIRE(ptr == nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("const pointer cast observer copy from valid", "[pointer_cast]") { - memory_tracker mem_track; - - { - test_sptr ptr_owner = oup::make_observable_sealed(); - test_object* raw_ptr = ptr_owner.get(); - test_optr_const ptr_orig{ptr_owner}; - test_optr ptr = oup::const_pointer_cast(ptr_orig); - - REQUIRE(instances == 1); - REQUIRE(ptr_orig.get() == raw_ptr); - REQUIRE(ptr.get() == raw_ptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("const pointer cast observer copy from null", "[pointer_cast]") { - memory_tracker mem_track; - - { - test_optr_const ptr_orig; - test_optr ptr = oup::const_pointer_cast(ptr_orig); - - REQUIRE(instances == 0); - REQUIRE(ptr_orig == nullptr); - REQUIRE(ptr == nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("const pointer cast observer move from valid", "[pointer_cast]") { - memory_tracker mem_track; - - { - test_sptr ptr_owner = oup::make_observable_sealed(); - test_object* raw_ptr = ptr_owner.get(); - test_optr_const ptr_orig{ptr_owner}; - test_optr ptr = oup::const_pointer_cast(std::move(ptr_orig)); - - REQUIRE(instances == 1); - REQUIRE(ptr_orig == nullptr); - REQUIRE(ptr.get() == raw_ptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("const pointer cast observer move from null", "[pointer_cast]") { - memory_tracker mem_track; - - { - test_optr_const ptr_orig; - test_optr ptr = oup::const_pointer_cast(std::move(ptr_orig)); - - REQUIRE(instances == 0); - REQUIRE(ptr_orig == nullptr); - REQUIRE(ptr == nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("dynamic pointer cast unique from valid", "[pointer_cast]") { - memory_tracker mem_track; - - { - test_object_derived* raw_ptr = new test_object_derived; - test_ptr ptr_orig{raw_ptr}; - test_ptr_derived ptr = oup::dynamic_pointer_cast(std::move(ptr_orig)); - - REQUIRE(instances == 1); - REQUIRE(ptr_orig == nullptr); - REQUIRE(ptr.get() == raw_ptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("dynamic pointer cast unique from invalid", "[pointer_cast]") { - memory_tracker mem_track; - - { - test_ptr ptr_orig{new test_object_observer_from_this_unique}; - - REQUIRE_THROWS_AS( - oup::dynamic_pointer_cast(std::move(ptr_orig)), std::bad_cast); - - REQUIRE(instances == 1); - REQUIRE(ptr_orig != nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("dynamic pointer cast unique from null", "[pointer_cast]") { - memory_tracker mem_track; - - { - test_ptr ptr_orig; - test_ptr_derived ptr = oup::dynamic_pointer_cast(std::move(ptr_orig)); - - REQUIRE(instances == 0); - REQUIRE(ptr_orig == nullptr); - REQUIRE(ptr == nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("dynamic pointer cast sealed from valid", "[pointer_cast]") { - memory_tracker mem_track; - - { - test_sptr_derived ptr_init = oup::make_observable_sealed(); - test_object_derived* raw_ptr = ptr_init.get(); - test_sptr ptr_orig{std::move(ptr_init)}; - test_sptr_derived ptr = oup::dynamic_pointer_cast(std::move(ptr_orig)); - - REQUIRE(instances == 1); - REQUIRE(ptr_orig == nullptr); - REQUIRE(ptr.get() == raw_ptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("dynamic pointer cast sealed from invalid", "[pointer_cast]") { - memory_tracker mem_track; - - { - test_sptr ptr_orig{oup::make_observable_sealed()}; - - REQUIRE_THROWS_AS( - oup::dynamic_pointer_cast(std::move(ptr_orig)), std::bad_cast); - - REQUIRE(instances == 1); - REQUIRE(ptr_orig != nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("dynamic pointer cast sealed from null", "[pointer_cast]") { - memory_tracker mem_track; - - { - test_sptr ptr_orig; - test_sptr_derived ptr = oup::dynamic_pointer_cast(std::move(ptr_orig)); - - REQUIRE(instances == 0); - REQUIRE(ptr_orig == nullptr); - REQUIRE(ptr == nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("dynamic pointer cast observer copy from valid", "[pointer_cast]") { - memory_tracker mem_track; - - { - test_sptr_derived ptr_owner = oup::make_observable_sealed(); - test_object_derived* raw_ptr = ptr_owner.get(); - test_optr ptr_orig{ptr_owner}; - test_optr_derived ptr = oup::dynamic_pointer_cast(ptr_orig); - - REQUIRE(instances == 1); - REQUIRE(ptr_orig.get() == raw_ptr); - REQUIRE(ptr.get() == raw_ptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("dynamic pointer cast observer copy from invalid", "[pointer_cast]") { - memory_tracker mem_track; - - { - test_sptr_from_this ptr_owner = - oup::make_observable_sealed(); - test_optr ptr_orig{ptr_owner}; - test_optr_derived ptr = oup::dynamic_pointer_cast(ptr_orig); - - REQUIRE(instances == 1); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr_orig.get() != nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("dynamic pointer cast observer copy from null", "[pointer_cast]") { - memory_tracker mem_track; - - { - test_optr ptr_orig; - test_optr_derived ptr = oup::dynamic_pointer_cast(ptr_orig); - - REQUIRE(instances == 0); - REQUIRE(ptr_orig == nullptr); - REQUIRE(ptr == nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("dynamic pointer cast observer move from valid", "[pointer_cast]") { - memory_tracker mem_track; - - { - test_sptr_derived ptr_owner = oup::make_observable_sealed(); - test_object_derived* raw_ptr = ptr_owner.get(); - test_optr ptr_orig{ptr_owner}; - test_optr_derived ptr = oup::dynamic_pointer_cast(std::move(ptr_orig)); - - REQUIRE(instances == 1); - REQUIRE(ptr_orig == nullptr); - REQUIRE(ptr.get() == raw_ptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("dynamic pointer cast observer move from invalid", "[pointer_cast]") { - memory_tracker mem_track; - - { - test_sptr_from_this ptr_owner = - oup::make_observable_sealed(); - test_optr ptr_orig{ptr_owner}; - test_optr_derived ptr = oup::dynamic_pointer_cast(std::move(ptr_orig)); - - REQUIRE(instances == 1); - REQUIRE(ptr.get() == nullptr); - REQUIRE(ptr_orig.get() == nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} - -TEST_CASE("dynamic pointer cast observer move from null", "[pointer_cast]") { - memory_tracker mem_track; - - { - test_optr ptr_orig; - test_optr_derived ptr = oup::dynamic_pointer_cast(std::move(ptr_orig)); - - REQUIRE(instances == 0); - REQUIRE(ptr_orig == nullptr); - REQUIRE(ptr == nullptr); - } - - REQUIRE(instances == 0); - REQUIRE(mem_track.allocated() == 0u); - REQUIRE(mem_track.double_delete() == 0u); -} diff --git a/tests/runtime_tests_lifetime.cpp b/tests/runtime_tests_lifetime.cpp index 801dcd1..93dad22 100644 --- a/tests/runtime_tests_lifetime.cpp +++ b/tests/runtime_tests_lifetime.cpp @@ -1,6 +1,6 @@ #include "catch2_and_overrides.hpp" #include "memory_tracker.hpp" -#include "tests_common2.hpp" +#include "tests_common.hpp" TEMPLATE_LIST_TEST_CASE( "release valid owner with observer", "[lifetime],[release],[owner],[observer]", owner_types) { diff --git a/tests/runtime_tests_make_observable.cpp b/tests/runtime_tests_make_observable.cpp index 6c510fb..1176719 100644 --- a/tests/runtime_tests_make_observable.cpp +++ b/tests/runtime_tests_make_observable.cpp @@ -1,6 +1,6 @@ #include "catch2_and_overrides.hpp" #include "memory_tracker.hpp" -#include "tests_common2.hpp" +#include "tests_common.hpp" TEMPLATE_LIST_TEST_CASE("make observable", "[make_observable],[owner]", owner_types) { if constexpr (can_use_make_observable) { diff --git a/tests/runtime_tests_observer_assignment.cpp b/tests/runtime_tests_observer_assignment.cpp index bb226f9..a9cfb27 100644 --- a/tests/runtime_tests_observer_assignment.cpp +++ b/tests/runtime_tests_observer_assignment.cpp @@ -1,6 +1,6 @@ #include "catch2_and_overrides.hpp" #include "memory_tracker.hpp" -#include "tests_common2.hpp" +#include "tests_common.hpp" // TEMPLATE_LIST_TEST_CASE( // "owner move assignment operator valid to empty", "[assignment],[owner]", owner_types) { diff --git a/tests/runtime_tests_observer_comparison.cpp b/tests/runtime_tests_observer_comparison.cpp index dc07c7b..8b77cf6 100644 --- a/tests/runtime_tests_observer_comparison.cpp +++ b/tests/runtime_tests_observer_comparison.cpp @@ -1,6 +1,6 @@ #include "catch2_and_overrides.hpp" #include "memory_tracker.hpp" -#include "tests_common2.hpp" +#include "tests_common.hpp" // TEMPLATE_LIST_TEST_CASE( // "owner comparison valid ptr vs nullptr", "[comparison],[owner]", owner_types) { diff --git a/tests/runtime_tests_observer_construction.cpp b/tests/runtime_tests_observer_construction.cpp index cab1398..3c92b1a 100644 --- a/tests/runtime_tests_observer_construction.cpp +++ b/tests/runtime_tests_observer_construction.cpp @@ -1,6 +1,6 @@ #include "catch2_and_overrides.hpp" #include "memory_tracker.hpp" -#include "tests_common2.hpp" +#include "tests_common.hpp" TEMPLATE_LIST_TEST_CASE("observer default constructor", "[construction],[observer]", owner_types) { memory_tracker mem_track; diff --git a/tests/runtime_tests_observer_misc.cpp b/tests/runtime_tests_observer_misc.cpp index bcb59b9..4a7e223 100644 --- a/tests/runtime_tests_observer_misc.cpp +++ b/tests/runtime_tests_observer_misc.cpp @@ -1,6 +1,6 @@ #include "catch2_and_overrides.hpp" #include "memory_tracker.hpp" -#include "tests_common2.hpp" +#include "tests_common.hpp" TEMPLATE_LIST_TEST_CASE("observer size", "[size],[observer]", owner_types) { REQUIRE(sizeof(observer_ptr) == 2 * sizeof(void*)); diff --git a/tests/runtime_tests_owner_assignment.cpp b/tests/runtime_tests_owner_assignment.cpp index cec0706..49c4780 100644 --- a/tests/runtime_tests_owner_assignment.cpp +++ b/tests/runtime_tests_owner_assignment.cpp @@ -1,6 +1,6 @@ #include "catch2_and_overrides.hpp" #include "memory_tracker.hpp" -#include "tests_common2.hpp" +#include "tests_common.hpp" TEMPLATE_LIST_TEST_CASE( "owner move assignment operator valid to empty", "[assignment],[owner]", owner_types) { diff --git a/tests/runtime_tests_owner_comparison.cpp b/tests/runtime_tests_owner_comparison.cpp index 0bd6cc1..72b54f2 100644 --- a/tests/runtime_tests_owner_comparison.cpp +++ b/tests/runtime_tests_owner_comparison.cpp @@ -1,6 +1,6 @@ #include "catch2_and_overrides.hpp" #include "memory_tracker.hpp" -#include "tests_common2.hpp" +#include "tests_common.hpp" TEMPLATE_LIST_TEST_CASE( "owner comparison valid ptr vs nullptr", "[comparison],[owner]", owner_types) { diff --git a/tests/runtime_tests_owner_construction.cpp b/tests/runtime_tests_owner_construction.cpp index 2d025f0..679903c 100644 --- a/tests/runtime_tests_owner_construction.cpp +++ b/tests/runtime_tests_owner_construction.cpp @@ -1,6 +1,6 @@ #include "catch2_and_overrides.hpp" #include "memory_tracker.hpp" -#include "tests_common2.hpp" +#include "tests_common.hpp" TEMPLATE_LIST_TEST_CASE("owner default constructor", "[construction],[owner]", owner_types) { memory_tracker mem_track; diff --git a/tests/runtime_tests_owner_misc.cpp b/tests/runtime_tests_owner_misc.cpp index d6173a1..ba43764 100644 --- a/tests/runtime_tests_owner_misc.cpp +++ b/tests/runtime_tests_owner_misc.cpp @@ -1,6 +1,6 @@ #include "catch2_and_overrides.hpp" #include "memory_tracker.hpp" -#include "tests_common2.hpp" +#include "tests_common.hpp" TEMPLATE_LIST_TEST_CASE("owner size", "[size],[owner]", owner_types) { using deleter_type = get_deleter; diff --git a/tests/tests_common2.cpp b/tests/tests_common.cpp similarity index 82% rename from tests/tests_common2.cpp rename to tests/tests_common.cpp index ee981a8..313bfa7 100644 --- a/tests/tests_common2.cpp +++ b/tests/tests_common.cpp @@ -1,4 +1,4 @@ -#include "tests_common2.hpp" +#include "tests_common.hpp" int instances = 0; int instances_derived = 0; diff --git a/tests/tests_common.hpp b/tests/tests_common.hpp index 93f8acc..455dc51 100644 --- a/tests/tests_common.hpp +++ b/tests/tests_common.hpp @@ -2,15 +2,30 @@ #include -int instances = 0; -int instances_derived = 0; -int instances_thrower = 0; -int instances_deleter = 0; +extern int instances; +extern int instances_derived; +extern int instances_deleter; + +extern bool next_test_object_constructor_throws; + +struct throw_constructor : std::exception {}; struct test_object { - int state_ = 1337; + enum class state { default_init = 1337, special_init = 42 } state_ = state::default_init; + + test_object() { + if (next_test_object_constructor_throws) { + next_test_object_constructor_throws = false; + throw throw_constructor{}; + } + ++instances; + } - test_object() noexcept { + explicit test_object(state s) : state_(s) { + if (next_test_object_constructor_throws) { + next_test_object_constructor_throws = false; + throw throw_constructor{}; + } ++instances; } @@ -26,36 +41,25 @@ struct test_object { }; struct test_object_derived : test_object { - test_object_derived() noexcept { + test_object_derived() { ++instances_derived; } - virtual ~test_object_derived() noexcept { - --instances_derived; - } -}; - -struct throw_constructor : std::exception {}; - -struct test_object_thrower { - test_object_thrower() { - throw throw_constructor{}; + explicit test_object_derived(state s) : test_object(s) { + ++instances_derived; } - ~test_object_thrower() { - --instances_thrower; + virtual ~test_object_derived() noexcept { + --instances_derived; } - - test_object_thrower(const test_object_thrower&) = delete; - test_object_thrower(test_object_thrower&&) = delete; - - test_object_thrower& operator=(const test_object_thrower&) = delete; - test_object_thrower& operator=(test_object_thrower&&) = delete; }; struct test_object_observer_from_this_unique : public test_object, - public oup::enable_observer_from_this_unique {}; + public oup::enable_observer_from_this_unique { + test_object_observer_from_this_unique() = default; + test_object_observer_from_this_unique(state s) : test_object(s) {} +}; struct test_object_observer_from_this_sealed : public test_object, @@ -63,6 +67,10 @@ struct test_object_observer_from_this_sealed : explicit test_object_observer_from_this_sealed(control_block_type& block) : oup::enable_observer_from_this_sealed(block) {} + + explicit test_object_observer_from_this_sealed(control_block_type& block, state s) : + test_object(s), + oup::enable_observer_from_this_sealed(block) {} }; struct sealed_virtual_policy { @@ -93,7 +101,10 @@ struct test_object_observer_from_this_virtual_sealed : public test_object, public oup::basic_enable_observer_from_this< test_object_observer_from_this_virtual_sealed, - sealed_virtual_policy> {}; + sealed_virtual_policy> { + test_object_observer_from_this_virtual_sealed() = default; + test_object_observer_from_this_virtual_sealed(state s) : test_object(s) {} +}; struct test_object_observer_from_this_non_virtual_unique : public test_object, @@ -105,38 +116,47 @@ struct test_object_observer_from_this_non_virtual_unique : oup::basic_enable_observer_from_this< test_object_observer_from_this_non_virtual_unique, unique_non_virtual_policy>(block) {} + + explicit test_object_observer_from_this_non_virtual_unique(control_block_type& block, state s) : + test_object(s), + oup::basic_enable_observer_from_this< + test_object_observer_from_this_non_virtual_unique, + unique_non_virtual_policy>(block) {} }; struct test_object_observer_from_this_maybe_no_block_unique : public test_object, public oup::basic_enable_observer_from_this< test_object_observer_from_this_maybe_no_block_unique, - unique_maybe_no_block_policy> {}; - -struct test_object_thrower_observer_from_this_non_virtual_unique : - public oup::basic_enable_observer_from_this< - test_object_thrower_observer_from_this_non_virtual_unique, - unique_non_virtual_policy>, - test_object_thrower { - test_object_thrower_observer_from_this_non_virtual_unique(control_block_type& block) : - oup::basic_enable_observer_from_this< - test_object_thrower_observer_from_this_non_virtual_unique, - unique_non_virtual_policy>(block) {} + unique_maybe_no_block_policy> { + test_object_observer_from_this_maybe_no_block_unique() = default; + test_object_observer_from_this_maybe_no_block_unique(state s) : test_object(s) {} }; struct test_object_observer_from_this_derived_unique : - public test_object_observer_from_this_unique {}; + public test_object_observer_from_this_unique { + test_object_observer_from_this_derived_unique() = default; + test_object_observer_from_this_derived_unique(state s) : + test_object_observer_from_this_unique(s) {} +}; struct test_object_observer_from_this_derived_sealed : public test_object_observer_from_this_sealed { explicit test_object_observer_from_this_derived_sealed(control_block_type& block) : test_object_observer_from_this_sealed(block) {} + + explicit test_object_observer_from_this_derived_sealed(control_block_type& block, state s) : + test_object_observer_from_this_sealed(block, s) {} }; struct test_object_observer_from_this_multi_unique : public test_object_observer_from_this_unique, - public oup::enable_observer_from_this_unique {}; + public oup::enable_observer_from_this_unique { + test_object_observer_from_this_multi_unique() = default; + test_object_observer_from_this_multi_unique(state s) : + test_object_observer_from_this_unique(s) {} +}; struct test_object_observer_from_this_multi_sealed : public test_object_observer_from_this_sealed, @@ -148,6 +168,10 @@ struct test_object_observer_from_this_multi_sealed : explicit test_object_observer_from_this_multi_sealed(control_block_type& block) : test_object_observer_from_this_sealed(block), oup::enable_observer_from_this_sealed(block) {} + + explicit test_object_observer_from_this_multi_sealed(control_block_type& block, state s) : + test_object_observer_from_this_sealed(block, s), + oup::enable_observer_from_this_sealed(block) {} }; struct test_object_observer_from_this_constructor_unique : @@ -160,6 +184,10 @@ struct test_object_observer_from_this_constructor_unique : test_object_observer_from_this_constructor_unique() { ptr = observer_from_this(); } + + explicit test_object_observer_from_this_constructor_unique(state s) : test_object(s) { + ptr = observer_from_this(); + } }; struct test_object_observer_from_this_constructor_sealed : @@ -174,6 +202,13 @@ struct test_object_observer_from_this_constructor_sealed : block) { ptr = observer_from_this(); } + + explicit test_object_observer_from_this_constructor_sealed(control_block_type& block, state s) : + test_object(s), + oup::enable_observer_from_this_sealed( + block) { + ptr = observer_from_this(); + } }; struct test_object_observer_from_this_constructor_bad : @@ -187,6 +222,10 @@ struct test_object_observer_from_this_constructor_bad : explicit test_object_observer_from_this_constructor_bad() { ptr = observer_from_this(); } + + explicit test_object_observer_from_this_constructor_bad(state s) : test_object(s) { + ptr = observer_from_this(); + } }; struct test_object_observer_from_this_constructor_multi_unique : @@ -200,6 +239,12 @@ struct test_object_observer_from_this_constructor_multi_unique : ptr = oup::enable_observer_from_this_unique< test_object_observer_from_this_constructor_multi_unique>::observer_from_this(); } + + test_object_observer_from_this_constructor_multi_unique(state s) : + test_object_observer_from_this_constructor_unique(s) { + ptr = oup::enable_observer_from_this_unique< + test_object_observer_from_this_constructor_multi_unique>::observer_from_this(); + } }; struct test_object_observer_from_this_constructor_multi_sealed : @@ -219,16 +264,30 @@ struct test_object_observer_from_this_constructor_multi_sealed : ptr = oup::enable_observer_from_this_sealed< test_object_observer_from_this_constructor_multi_sealed>::observer_from_this(); } + + explicit test_object_observer_from_this_constructor_multi_sealed( + control_block_type& block, state s) : + test_object_observer_from_this_constructor_sealed(block, s), + oup::enable_observer_from_this_sealed< + test_object_observer_from_this_constructor_multi_sealed>(block) { + ptr = oup::enable_observer_from_this_sealed< + test_object_observer_from_this_constructor_multi_sealed>::observer_from_this(); + } }; struct test_deleter { - int state_ = 0; + enum class state { + default_init = 1334, + special_init_1 = 59846, + special_init_2 = 221, + empty = 0 + } state_ = state::default_init; test_deleter() noexcept { ++instances_deleter; } - explicit test_deleter(int state) noexcept : state_(state) { + explicit test_deleter(state s) noexcept : state_(s) { ++instances_deleter; } @@ -237,7 +296,7 @@ struct test_deleter { } test_deleter(test_deleter&& source) noexcept : state_(source.state_) { - source.state_ = 0; + source.state_ = state::empty; ++instances_deleter; } @@ -249,7 +308,7 @@ struct test_deleter { test_deleter& operator=(test_deleter&& source) noexcept { state_ = source.state_; - source.state_ = 0; + source.state_ = state::empty; return *this; } @@ -257,105 +316,151 @@ struct test_deleter { delete ptr; } - void operator()(test_object_thrower* ptr) noexcept { - delete ptr; - } - void operator()(std::nullptr_t) noexcept {} }; -using test_ptr = oup::observable_unique_ptr; -using test_sptr = oup::observable_sealed_ptr; - -using test_ptr_const = oup::observable_unique_ptr; -using test_sptr_const = oup::observable_sealed_ptr; - -using test_ptr_derived = oup::observable_unique_ptr; -using test_sptr_derived = oup::observable_sealed_ptr; - -using test_ptr_with_deleter = oup::observable_unique_ptr; -using test_ptr_derived_with_deleter = oup::observable_unique_ptr; - -using test_ptr_thrower = oup::observable_unique_ptr; -using test_sptr_thrower = oup::observable_sealed_ptr; - -using test_ptr_thrower_with_deleter = oup::observable_unique_ptr; - -using test_ptr_from_this = oup::observable_unique_ptr; -using test_sptr_from_this = oup::observable_sealed_ptr; - -using test_ptr_from_this_non_virtual = oup::basic_observable_ptr< - test_object_observer_from_this_non_virtual_unique, - oup::default_delete, - unique_non_virtual_policy>; - -using test_ptr_from_this_maybe_no_block = oup::basic_observable_ptr< - test_object_observer_from_this_maybe_no_block_unique, - oup::default_delete, - unique_maybe_no_block_policy>; - -using test_sptr_from_this_virtual = oup::basic_observable_ptr< - test_object_observer_from_this_virtual_sealed, - oup::placement_delete, - sealed_virtual_policy>; - -using test_cptr_from_this = oup::observable_unique_ptr; -using test_csptr_from_this = - oup::observable_sealed_ptr; - -using test_ptr_from_this_derived = - oup::observable_unique_ptr; -using test_sptr_from_this_derived = - oup::observable_sealed_ptr; - -using test_ptr_from_this_multi = - oup::observable_unique_ptr; -using test_sptr_from_this_multi = - oup::observable_sealed_ptr; - -using test_ptr_from_this_constructor = - oup::observable_unique_ptr; -using test_sptr_from_this_constructor = - oup::observable_sealed_ptr; - -using test_ptr_from_this_constructor_multi = - oup::observable_unique_ptr; -using test_sptr_from_this_constructor_multi = - oup::observable_sealed_ptr; - -using test_optr = oup::observer_ptr; -using test_optr_const = oup::observer_ptr; -using test_optr_derived = oup::observer_ptr; -using test_optr_from_this = oup::observer_ptr; -using test_optr_from_this_const = oup::observer_ptr; -using test_optr_from_this_derived = - oup::observer_ptr; -using test_optr_from_this_derived_const = - oup::observer_ptr; -using test_optr_from_this_multi = oup::observer_ptr; -using test_optr_from_this_multi_const = - oup::observer_ptr; -using test_optr_from_this_sealed = oup::observer_ptr; -using test_optr_from_this_const_sealed = - oup::observer_ptr; -using test_optr_from_this_non_virtual_unique = - oup::observer_ptr; -using test_optr_from_this_const_non_virtual_unique = - oup::observer_ptr; -using test_optr_from_this_maybe_no_block_unique = - oup::observer_ptr; -using test_optr_from_this_const_maybe_no_block_unique = - oup::observer_ptr; -using test_optr_from_this_virtual_sealed = - oup::observer_ptr; -using test_optr_from_this_const_virtual_sealed = - oup::observer_ptr; -using test_optr_from_this_derived_sealed = - oup::observer_ptr; -using test_optr_from_this_derived_const_sealed = - oup::observer_ptr; -using test_optr_from_this_multi_sealed = - oup::observer_ptr; -using test_optr_from_this_multi_const_sealed = - oup::observer_ptr; -using int_optr = oup::observer_ptr; +template +using get_object = typename T::element_type; + +template +using get_deleter = typename T::deleter_type; + +template +using get_policy = typename T::policy; + +template +using get_observer_policy = typename T::observer_policy; + +template +using observer_ptr = typename T::observer_type; + +template +constexpr bool is_sealed = get_policy::is_sealed; + +template +constexpr bool has_stateful_deleter = !std::is_empty_v>; + +template +constexpr bool has_eoft = oup::has_enable_observer_from_this, get_policy>; + +template +constexpr bool eoft_constructor_takes_control_block = + has_eoft&& get_policy::eoft_constructor_takes_control_block; + +template +constexpr bool eoft_allocates = has_eoft&& + oup::policy_queries>::eoft_constructor_allocates(); + +template +constexpr bool must_use_make_observable = is_sealed || eoft_constructor_takes_control_block; + +template +constexpr bool can_use_make_observable = (is_sealed && + std::is_same_v, oup::placement_delete>) || + std::is_same_v, oup::default_delete>; + +template +constexpr bool has_base = std::is_base_of_v>; + +template +using base_ptr = oup::basic_observable_ptr< + std::conditional_t>, const test_object, test_object>, + get_deleter, + get_policy>; + +template +using base_observer_ptr = typename base_ptr::observer_type; + +template +using get_state = std:: + conditional_t>, const test_object::state, test_object::state>; + +template +using state_observer_ptr = oup::basic_observer_ptr, get_observer_policy>; + +template +get_object* make_instance() { + return new std::remove_cv_t>; +} + +template +get_deleter make_deleter_instance_1() { + return get_deleter(test_deleter::state::special_init_1); +} + +template +get_deleter make_deleter_instance_2() { + return get_deleter(test_deleter::state::special_init_2); +} + +template +T make_pointer_deleter_1() { + if constexpr (must_use_make_observable) { + return oup::make_observable, get_policy>(); + } else { + if constexpr (has_stateful_deleter) { + return T(make_instance(), make_deleter_instance_1()); + } else { + return T(make_instance()); + } + } +} + +template +T make_pointer_deleter_2() { + if constexpr (must_use_make_observable) { + return oup::make_observable, get_policy>(); + } else { + if constexpr (has_stateful_deleter) { + return T(make_instance(), make_deleter_instance_2()); + } else { + return T(make_instance()); + } + } +} + +template +T make_empty_pointer_deleter_1() { + if constexpr (has_stateful_deleter) { + return T(nullptr, make_deleter_instance_1()); + } else { + return T{}; + } +} + +template +T make_empty_pointer_deleter_2() { + if constexpr (has_stateful_deleter) { + return T(nullptr, make_deleter_instance_2()); + } else { + return T{}; + } +} + +// clang-format off +using owner_types = std::tuple< + oup::observable_unique_ptr, + oup::observable_sealed_ptr, + oup::observable_unique_ptr, + oup::observable_sealed_ptr, + oup::observable_unique_ptr, + oup::observable_sealed_ptr, + oup::observable_unique_ptr, + oup::observable_unique_ptr, + oup::observable_unique_ptr, + oup::observable_sealed_ptr, + oup::basic_observable_ptr, + oup::basic_observable_ptr, + oup::basic_observable_ptr, + oup::observable_unique_ptr, + oup::observable_sealed_ptr, + oup::observable_unique_ptr, + oup::observable_sealed_ptr, + oup::observable_unique_ptr, + oup::observable_sealed_ptr, + oup::observable_unique_ptr, + oup::observable_sealed_ptr, + oup::observable_unique_ptr, + oup::observable_sealed_ptr + >; +// clang-format on diff --git a/tests/tests_common2.hpp b/tests/tests_common2.hpp deleted file mode 100644 index 455dc51..0000000 --- a/tests/tests_common2.hpp +++ /dev/null @@ -1,466 +0,0 @@ -#include "oup/observable_unique_ptr.hpp" - -#include - -extern int instances; -extern int instances_derived; -extern int instances_deleter; - -extern bool next_test_object_constructor_throws; - -struct throw_constructor : std::exception {}; - -struct test_object { - enum class state { default_init = 1337, special_init = 42 } state_ = state::default_init; - - test_object() { - if (next_test_object_constructor_throws) { - next_test_object_constructor_throws = false; - throw throw_constructor{}; - } - ++instances; - } - - explicit test_object(state s) : state_(s) { - if (next_test_object_constructor_throws) { - next_test_object_constructor_throws = false; - throw throw_constructor{}; - } - ++instances; - } - - virtual ~test_object() noexcept { - --instances; - } - - test_object(const test_object&) = delete; - test_object(test_object&&) = delete; - - test_object& operator=(const test_object&) = delete; - test_object& operator=(test_object&&) = delete; -}; - -struct test_object_derived : test_object { - test_object_derived() { - ++instances_derived; - } - - explicit test_object_derived(state s) : test_object(s) { - ++instances_derived; - } - - virtual ~test_object_derived() noexcept { - --instances_derived; - } -}; - -struct test_object_observer_from_this_unique : - public test_object, - public oup::enable_observer_from_this_unique { - test_object_observer_from_this_unique() = default; - test_object_observer_from_this_unique(state s) : test_object(s) {} -}; - -struct test_object_observer_from_this_sealed : - public test_object, - public oup::enable_observer_from_this_sealed { - - explicit test_object_observer_from_this_sealed(control_block_type& block) : - oup::enable_observer_from_this_sealed(block) {} - - explicit test_object_observer_from_this_sealed(control_block_type& block, state s) : - test_object(s), - oup::enable_observer_from_this_sealed(block) {} -}; - -struct sealed_virtual_policy { - static constexpr bool is_sealed = true; - static constexpr bool allow_eoft_in_constructor = false; - static constexpr bool allow_eoft_multiple_inheritance = true; - static constexpr bool eoft_constructor_takes_control_block = false; - using observer_policy = oup::default_observer_policy; -}; - -struct unique_non_virtual_policy { - static constexpr bool is_sealed = false; - static constexpr bool allow_eoft_in_constructor = true; - static constexpr bool allow_eoft_multiple_inheritance = true; - static constexpr bool eoft_constructor_takes_control_block = true; - using observer_policy = oup::default_observer_policy; -}; - -struct unique_maybe_no_block_policy { - static constexpr bool is_sealed = false; - static constexpr bool allow_eoft_in_constructor = false; - static constexpr bool allow_eoft_multiple_inheritance = true; - static constexpr bool eoft_constructor_takes_control_block = false; - using observer_policy = oup::default_observer_policy; -}; - -struct test_object_observer_from_this_virtual_sealed : - public test_object, - public oup::basic_enable_observer_from_this< - test_object_observer_from_this_virtual_sealed, - sealed_virtual_policy> { - test_object_observer_from_this_virtual_sealed() = default; - test_object_observer_from_this_virtual_sealed(state s) : test_object(s) {} -}; - -struct test_object_observer_from_this_non_virtual_unique : - public test_object, - public oup::basic_enable_observer_from_this< - test_object_observer_from_this_non_virtual_unique, - unique_non_virtual_policy> { - - explicit test_object_observer_from_this_non_virtual_unique(control_block_type& block) : - oup::basic_enable_observer_from_this< - test_object_observer_from_this_non_virtual_unique, - unique_non_virtual_policy>(block) {} - - explicit test_object_observer_from_this_non_virtual_unique(control_block_type& block, state s) : - test_object(s), - oup::basic_enable_observer_from_this< - test_object_observer_from_this_non_virtual_unique, - unique_non_virtual_policy>(block) {} -}; - -struct test_object_observer_from_this_maybe_no_block_unique : - public test_object, - public oup::basic_enable_observer_from_this< - test_object_observer_from_this_maybe_no_block_unique, - unique_maybe_no_block_policy> { - test_object_observer_from_this_maybe_no_block_unique() = default; - test_object_observer_from_this_maybe_no_block_unique(state s) : test_object(s) {} -}; - -struct test_object_observer_from_this_derived_unique : - public test_object_observer_from_this_unique { - test_object_observer_from_this_derived_unique() = default; - test_object_observer_from_this_derived_unique(state s) : - test_object_observer_from_this_unique(s) {} -}; - -struct test_object_observer_from_this_derived_sealed : - public test_object_observer_from_this_sealed { - - explicit test_object_observer_from_this_derived_sealed(control_block_type& block) : - test_object_observer_from_this_sealed(block) {} - - explicit test_object_observer_from_this_derived_sealed(control_block_type& block, state s) : - test_object_observer_from_this_sealed(block, s) {} -}; - -struct test_object_observer_from_this_multi_unique : - public test_object_observer_from_this_unique, - public oup::enable_observer_from_this_unique { - test_object_observer_from_this_multi_unique() = default; - test_object_observer_from_this_multi_unique(state s) : - test_object_observer_from_this_unique(s) {} -}; - -struct test_object_observer_from_this_multi_sealed : - public test_object_observer_from_this_sealed, - public oup::enable_observer_from_this_sealed { - - using control_block_type = oup::enable_observer_from_this_sealed< - test_object_observer_from_this_multi_sealed>::control_block_type; - - explicit test_object_observer_from_this_multi_sealed(control_block_type& block) : - test_object_observer_from_this_sealed(block), - oup::enable_observer_from_this_sealed(block) {} - - explicit test_object_observer_from_this_multi_sealed(control_block_type& block, state s) : - test_object_observer_from_this_sealed(block, s), - oup::enable_observer_from_this_sealed(block) {} -}; - -struct test_object_observer_from_this_constructor_unique : - public test_object, - public oup::enable_observer_from_this_unique< - test_object_observer_from_this_constructor_unique> { - - oup::observer_ptr ptr; - - test_object_observer_from_this_constructor_unique() { - ptr = observer_from_this(); - } - - explicit test_object_observer_from_this_constructor_unique(state s) : test_object(s) { - ptr = observer_from_this(); - } -}; - -struct test_object_observer_from_this_constructor_sealed : - public test_object, - public oup::enable_observer_from_this_sealed< - test_object_observer_from_this_constructor_sealed> { - - oup::observer_ptr ptr; - - explicit test_object_observer_from_this_constructor_sealed(control_block_type& block) : - oup::enable_observer_from_this_sealed( - block) { - ptr = observer_from_this(); - } - - explicit test_object_observer_from_this_constructor_sealed(control_block_type& block, state s) : - test_object(s), - oup::enable_observer_from_this_sealed( - block) { - ptr = observer_from_this(); - } -}; - -struct test_object_observer_from_this_constructor_bad : - public test_object, - public oup::basic_enable_observer_from_this< - test_object_observer_from_this_constructor_bad, - sealed_virtual_policy> { - - oup::observer_ptr ptr; - - explicit test_object_observer_from_this_constructor_bad() { - ptr = observer_from_this(); - } - - explicit test_object_observer_from_this_constructor_bad(state s) : test_object(s) { - ptr = observer_from_this(); - } -}; - -struct test_object_observer_from_this_constructor_multi_unique : - public test_object_observer_from_this_constructor_unique, - public oup::enable_observer_from_this_unique< - test_object_observer_from_this_constructor_multi_unique> { - - oup::observer_ptr ptr; - - test_object_observer_from_this_constructor_multi_unique() { - ptr = oup::enable_observer_from_this_unique< - test_object_observer_from_this_constructor_multi_unique>::observer_from_this(); - } - - test_object_observer_from_this_constructor_multi_unique(state s) : - test_object_observer_from_this_constructor_unique(s) { - ptr = oup::enable_observer_from_this_unique< - test_object_observer_from_this_constructor_multi_unique>::observer_from_this(); - } -}; - -struct test_object_observer_from_this_constructor_multi_sealed : - public test_object_observer_from_this_constructor_sealed, - public oup::enable_observer_from_this_sealed< - test_object_observer_from_this_constructor_multi_sealed> { - - using control_block_type = oup::enable_observer_from_this_sealed< - test_object_observer_from_this_constructor_multi_sealed>::control_block_type; - - oup::observer_ptr ptr; - - explicit test_object_observer_from_this_constructor_multi_sealed(control_block_type& block) : - test_object_observer_from_this_constructor_sealed(block), - oup::enable_observer_from_this_sealed< - test_object_observer_from_this_constructor_multi_sealed>(block) { - ptr = oup::enable_observer_from_this_sealed< - test_object_observer_from_this_constructor_multi_sealed>::observer_from_this(); - } - - explicit test_object_observer_from_this_constructor_multi_sealed( - control_block_type& block, state s) : - test_object_observer_from_this_constructor_sealed(block, s), - oup::enable_observer_from_this_sealed< - test_object_observer_from_this_constructor_multi_sealed>(block) { - ptr = oup::enable_observer_from_this_sealed< - test_object_observer_from_this_constructor_multi_sealed>::observer_from_this(); - } -}; - -struct test_deleter { - enum class state { - default_init = 1334, - special_init_1 = 59846, - special_init_2 = 221, - empty = 0 - } state_ = state::default_init; - - test_deleter() noexcept { - ++instances_deleter; - } - - explicit test_deleter(state s) noexcept : state_(s) { - ++instances_deleter; - } - - test_deleter(const test_deleter& source) noexcept : state_(source.state_) { - ++instances_deleter; - } - - test_deleter(test_deleter&& source) noexcept : state_(source.state_) { - source.state_ = state::empty; - ++instances_deleter; - } - - ~test_deleter() noexcept { - --instances_deleter; - } - - test_deleter& operator=(const test_deleter&) = default; - - test_deleter& operator=(test_deleter&& source) noexcept { - state_ = source.state_; - source.state_ = state::empty; - return *this; - } - - void operator()(test_object* ptr) noexcept { - delete ptr; - } - - void operator()(std::nullptr_t) noexcept {} -}; - -template -using get_object = typename T::element_type; - -template -using get_deleter = typename T::deleter_type; - -template -using get_policy = typename T::policy; - -template -using get_observer_policy = typename T::observer_policy; - -template -using observer_ptr = typename T::observer_type; - -template -constexpr bool is_sealed = get_policy::is_sealed; - -template -constexpr bool has_stateful_deleter = !std::is_empty_v>; - -template -constexpr bool has_eoft = oup::has_enable_observer_from_this, get_policy>; - -template -constexpr bool eoft_constructor_takes_control_block = - has_eoft&& get_policy::eoft_constructor_takes_control_block; - -template -constexpr bool eoft_allocates = has_eoft&& - oup::policy_queries>::eoft_constructor_allocates(); - -template -constexpr bool must_use_make_observable = is_sealed || eoft_constructor_takes_control_block; - -template -constexpr bool can_use_make_observable = (is_sealed && - std::is_same_v, oup::placement_delete>) || - std::is_same_v, oup::default_delete>; - -template -constexpr bool has_base = std::is_base_of_v>; - -template -using base_ptr = oup::basic_observable_ptr< - std::conditional_t>, const test_object, test_object>, - get_deleter, - get_policy>; - -template -using base_observer_ptr = typename base_ptr::observer_type; - -template -using get_state = std:: - conditional_t>, const test_object::state, test_object::state>; - -template -using state_observer_ptr = oup::basic_observer_ptr, get_observer_policy>; - -template -get_object* make_instance() { - return new std::remove_cv_t>; -} - -template -get_deleter make_deleter_instance_1() { - return get_deleter(test_deleter::state::special_init_1); -} - -template -get_deleter make_deleter_instance_2() { - return get_deleter(test_deleter::state::special_init_2); -} - -template -T make_pointer_deleter_1() { - if constexpr (must_use_make_observable) { - return oup::make_observable, get_policy>(); - } else { - if constexpr (has_stateful_deleter) { - return T(make_instance(), make_deleter_instance_1()); - } else { - return T(make_instance()); - } - } -} - -template -T make_pointer_deleter_2() { - if constexpr (must_use_make_observable) { - return oup::make_observable, get_policy>(); - } else { - if constexpr (has_stateful_deleter) { - return T(make_instance(), make_deleter_instance_2()); - } else { - return T(make_instance()); - } - } -} - -template -T make_empty_pointer_deleter_1() { - if constexpr (has_stateful_deleter) { - return T(nullptr, make_deleter_instance_1()); - } else { - return T{}; - } -} - -template -T make_empty_pointer_deleter_2() { - if constexpr (has_stateful_deleter) { - return T(nullptr, make_deleter_instance_2()); - } else { - return T{}; - } -} - -// clang-format off -using owner_types = std::tuple< - oup::observable_unique_ptr, - oup::observable_sealed_ptr, - oup::observable_unique_ptr, - oup::observable_sealed_ptr, - oup::observable_unique_ptr, - oup::observable_sealed_ptr, - oup::observable_unique_ptr, - oup::observable_unique_ptr, - oup::observable_unique_ptr, - oup::observable_sealed_ptr, - oup::basic_observable_ptr, - oup::basic_observable_ptr, - oup::basic_observable_ptr, - oup::observable_unique_ptr, - oup::observable_sealed_ptr, - oup::observable_unique_ptr, - oup::observable_sealed_ptr, - oup::observable_unique_ptr, - oup::observable_sealed_ptr, - oup::observable_unique_ptr, - oup::observable_sealed_ptr, - oup::observable_unique_ptr, - oup::observable_sealed_ptr - >; -// clang-format on From 0ccb03e1f63fde366c895c8e8a13314ebb11f81e Mon Sep 17 00:00:00 2001 From: Corentin Schreiber Date: Mon, 26 Sep 2022 21:47:04 +0100 Subject: [PATCH 07/81] Fix missing eoft check --- tests/runtime_tests_lifetime.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/tests/runtime_tests_lifetime.cpp b/tests/runtime_tests_lifetime.cpp index 93dad22..eb4ead6 100644 --- a/tests/runtime_tests_lifetime.cpp +++ b/tests/runtime_tests_lifetime.cpp @@ -20,8 +20,14 @@ TEMPLATE_LIST_TEST_CASE( auto* ptr_released = ptr.release(); REQUIRE(ptr_released == ptr_raw); REQUIRE(ptr.get() == nullptr); - REQUIRE(optr.get() != nullptr); - REQUIRE(!optr.expired()); + + if constexpr (has_eoft) { + REQUIRE(optr.get() != nullptr); + REQUIRE(!optr.expired()); + } else { + REQUIRE(optr.get() == nullptr); + REQUIRE(optr.expired()); + } REQUIRE(instances == 1); if constexpr (has_stateful_deleter) { @@ -70,8 +76,14 @@ TEMPLATE_LIST_TEST_CASE( auto* ptr_released = ptr.release(); REQUIRE(ptr_released == ptr_raw); REQUIRE(ptr.get() == nullptr); - REQUIRE(optr.get() != nullptr); - REQUIRE(!optr.expired()); + + if constexpr (has_eoft) { + REQUIRE(optr.get() != nullptr); + REQUIRE(!optr.expired()); + } else { + REQUIRE(optr.get() == nullptr); + REQUIRE(optr.expired()); + } REQUIRE(instances == 1); if constexpr (has_stateful_deleter) { From 7e9ac00dad653fed6e151a189336e6565548a3f5 Mon Sep 17 00:00:00 2001 From: Corentin Schreiber Date: Mon, 26 Sep 2022 21:57:36 +0100 Subject: [PATCH 08/81] Update coverage code --- .github/workflows/cmake.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 93a89bf..f6646fc 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -72,6 +72,6 @@ jobs: - name: Compute Code Coverage if: runner.os == 'Linux' && matrix.platform.compiler == 'g++' && matrix.build-type == 'Debug' run: | - gcov ${{github.workspace}}/build/tests/CMakeFiles/oup_tests.dir/runtime_tests.cpp.gcda + gcov ${{github.workspace}}/build/tests/CMakeFiles/oup_tests.dir/*.gcda ls | grep '.gcov' | grep -v observable_unique_ptr | xargs -d"\n" rm bash <(curl -s https://codecov.io/bash) From 4a2e8fcfd039e8801b79391d7414f5da357c53cc Mon Sep 17 00:00:00 2001 From: Corentin Schreiber Date: Sat, 1 Oct 2022 13:43:01 +0100 Subject: [PATCH 09/81] Move memory_tracker implementation to C++ Prevents bad optimisations in Emscripten --- tests/memory_tracker.cpp | 17 +++++++++++++++++ tests/memory_tracker.hpp | 21 +++++---------------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/tests/memory_tracker.cpp b/tests/memory_tracker.cpp index 1d7aba1..2741361 100644 --- a/tests/memory_tracker.cpp +++ b/tests/memory_tracker.cpp @@ -118,3 +118,20 @@ void operator delete(void* p, std::align_val_t al) noexcept { void operator delete[](void* p, std::align_val_t al) noexcept { deallocate(p, true, al); } + +memory_tracker::memory_tracker() noexcept : + initial_allocations(::num_allocations), initial_double_delete(::double_delete) { + ::memory_tracking = true; +} + +memory_tracker::~memory_tracker() noexcept { + ::memory_tracking = false; +} + +std::size_t memory_tracker::allocated() const { + return ::num_allocations - initial_allocations; +} + +std::size_t memory_tracker::double_delete() const { + return ::double_delete - initial_double_delete; +} diff --git a/tests/memory_tracker.hpp b/tests/memory_tracker.hpp index 2f30d93..819c71e 100644 --- a/tests/memory_tracker.hpp +++ b/tests/memory_tracker.hpp @@ -32,20 +32,9 @@ struct memory_tracker { std::size_t initial_allocations; std::size_t initial_double_delete; - memory_tracker() noexcept : - initial_allocations(::num_allocations), initial_double_delete(::double_delete) { - ::memory_tracking = true; - } - - ~memory_tracker() noexcept { - ::memory_tracking = false; - } - - std::size_t allocated() const { - return ::num_allocations - initial_allocations; - } - - std::size_t double_delete() const { - return ::double_delete - initial_double_delete; - } + memory_tracker() noexcept; + ~memory_tracker() noexcept; + + std::size_t allocated() const; + std::size_t double_delete() const; }; From 490e5cc1fed2502a37d8116afd0705e757fc3a33 Mon Sep 17 00:00:00 2001 From: Corentin Schreiber Date: Sat, 1 Oct 2022 13:43:16 +0100 Subject: [PATCH 10/81] Added debug statements to allocation functions --- tests/memory_tracker.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/memory_tracker.cpp b/tests/memory_tracker.cpp index 2741361..39504da 100644 --- a/tests/memory_tracker.cpp +++ b/tests/memory_tracker.cpp @@ -1,5 +1,7 @@ #include "memory_tracker.hpp" +#include + void* allocations[max_allocations]; void* allocations_array[max_allocations]; std::size_t allocations_bytes[max_allocations]; @@ -9,12 +11,20 @@ std::size_t double_delete = 0u; bool memory_tracking = false; bool force_next_allocation_failure = false; +constexpr bool debug_alloc = false; + void* allocate(std::size_t size, bool array, std::align_val_t align) { if (memory_tracking && num_allocations == max_allocations) { + if (debug_alloc) { + printf("alloc %ld failed\n", size); + } throw std::bad_alloc(); } if (force_next_allocation_failure) { + if (debug_alloc) { + printf("alloc %ld failed\n", size); + } force_next_allocation_failure = false; throw std::bad_alloc(); } @@ -33,9 +43,16 @@ void* allocate(std::size_t size, bool array, std::align_val_t align) { } if (!p) { + if (debug_alloc) { + printf("alloc %ld failed\n", size); + } throw std::bad_alloc(); } + if (debug_alloc) { + printf("alloc %ld -> %p\n", size, p); + } + if (memory_tracking) { if (array) { allocations_array[num_allocations] = p; @@ -57,6 +74,10 @@ void deallocate(void* p, bool array, std::align_val_t align [[maybe_unused]]) { return; } + if (debug_alloc) { + printf("dealloc %p\n", p); + } + if (memory_tracking) { bool found = false; void** allocations_type = array ? allocations_array : allocations; From f46a77910746463b3247c47bf5bbe53a2b1a92a8 Mon Sep 17 00:00:00 2001 From: Corentin Schreiber Date: Sat, 1 Oct 2022 13:44:53 +0100 Subject: [PATCH 11/81] Added snatch Catch2 was too resource-hungry for Emscripten --- oup.sublime-project | 66 +- tests/CMakeLists.txt | 28 +- tests/catch2_and_overrides.hpp | 17 - tests/cxxopts.hpp | 2611 +++++++++++++++++ tests/cxxopts_LICENSE | 19 + tests/runtime_tests_lifetime.cpp | 82 +- tests/runtime_tests_make_observable.cpp | 70 +- tests/runtime_tests_observer_assignment.cpp | 194 +- tests/runtime_tests_observer_comparison.cpp | 82 +- tests/runtime_tests_observer_construction.cpp | 164 +- tests/runtime_tests_observer_misc.cpp | 6 +- tests/runtime_tests_owner_assignment.cpp | 214 +- tests/runtime_tests_owner_comparison.cpp | 92 +- tests/runtime_tests_owner_construction.cpp | 290 +- tests/runtime_tests_owner_misc.cpp | 290 +- tests/snatch.cpp | 330 +++ tests/snatch.hpp | 257 ++ tests/testing.hpp | 19 + 18 files changed, 4012 insertions(+), 819 deletions(-) delete mode 100644 tests/catch2_and_overrides.hpp create mode 100644 tests/cxxopts.hpp create mode 100644 tests/cxxopts_LICENSE create mode 100644 tests/snatch.cpp create mode 100644 tests/snatch.hpp create mode 100644 tests/testing.hpp diff --git a/oup.sublime-project b/oup.sublime-project index 69da2bc..62d8803 100644 --- a/oup.sublime-project +++ b/oup.sublime-project @@ -67,123 +67,115 @@ }, { "name": "ContinuousCoverage", - "shell_cmd": "make -j12 ContinuousCoverage", + "shell_cmd": "make -j12 ContinuousCoverage" }, { "name": "ContinuousMemCheck", - "shell_cmd": "make -j12 ContinuousMemCheck", + "shell_cmd": "make -j12 ContinuousMemCheck" }, { "name": "ContinuousStart", - "shell_cmd": "make -j12 ContinuousStart", + "shell_cmd": "make -j12 ContinuousStart" }, { "name": "ContinuousSubmit", - "shell_cmd": "make -j12 ContinuousSubmit", + "shell_cmd": "make -j12 ContinuousSubmit" }, { "name": "ContinuousTest", - "shell_cmd": "make -j12 ContinuousTest", + "shell_cmd": "make -j12 ContinuousTest" }, { "name": "ContinuousUpdate", - "shell_cmd": "make -j12 ContinuousUpdate", + "shell_cmd": "make -j12 ContinuousUpdate" }, { "name": "Experimental", - "shell_cmd": "make -j12 Experimental", + "shell_cmd": "make -j12 Experimental" }, { "name": "ExperimentalBuild", - "shell_cmd": "make -j12 ExperimentalBuild", + "shell_cmd": "make -j12 ExperimentalBuild" }, { "name": "ExperimentalConfigure", - "shell_cmd": "make -j12 ExperimentalConfigure", + "shell_cmd": "make -j12 ExperimentalConfigure" }, { "name": "ExperimentalCoverage", - "shell_cmd": "make -j12 ExperimentalCoverage", + "shell_cmd": "make -j12 ExperimentalCoverage" }, { "name": "ExperimentalMemCheck", - "shell_cmd": "make -j12 ExperimentalMemCheck", + "shell_cmd": "make -j12 ExperimentalMemCheck" }, { "name": "ExperimentalStart", - "shell_cmd": "make -j12 ExperimentalStart", + "shell_cmd": "make -j12 ExperimentalStart" }, { "name": "ExperimentalSubmit", - "shell_cmd": "make -j12 ExperimentalSubmit", + "shell_cmd": "make -j12 ExperimentalSubmit" }, { "name": "ExperimentalTest", - "shell_cmd": "make -j12 ExperimentalTest", + "shell_cmd": "make -j12 ExperimentalTest" }, { "name": "ExperimentalUpdate", - "shell_cmd": "make -j12 ExperimentalUpdate", + "shell_cmd": "make -j12 ExperimentalUpdate" }, { "name": "Nightly", - "shell_cmd": "make -j12 Nightly", + "shell_cmd": "make -j12 Nightly" }, { "name": "NightlyBuild", - "shell_cmd": "make -j12 NightlyBuild", + "shell_cmd": "make -j12 NightlyBuild" }, { "name": "NightlyConfigure", - "shell_cmd": "make -j12 NightlyConfigure", + "shell_cmd": "make -j12 NightlyConfigure" }, { "name": "NightlyCoverage", - "shell_cmd": "make -j12 NightlyCoverage", + "shell_cmd": "make -j12 NightlyCoverage" }, { "name": "NightlyMemCheck", - "shell_cmd": "make -j12 NightlyMemCheck", + "shell_cmd": "make -j12 NightlyMemCheck" }, { "name": "NightlyMemoryCheck", - "shell_cmd": "make -j12 NightlyMemoryCheck", + "shell_cmd": "make -j12 NightlyMemoryCheck" }, { "name": "NightlyStart", - "shell_cmd": "make -j12 NightlyStart", + "shell_cmd": "make -j12 NightlyStart" }, { "name": "NightlySubmit", - "shell_cmd": "make -j12 NightlySubmit", + "shell_cmd": "make -j12 NightlySubmit" }, { "name": "NightlyTest", - "shell_cmd": "make -j12 NightlyTest", + "shell_cmd": "make -j12 NightlyTest" }, { "name": "NightlyUpdate", - "shell_cmd": "make -j12 NightlyUpdate", - }, - { - "name": "Catch2", - "shell_cmd": "make -j12 Catch2", - }, - { - "name": "Catch2WithMain", - "shell_cmd": "make -j12 Catch2WithMain", + "shell_cmd": "make -j12 NightlyUpdate" }, { "name": "oup_size_benchmark", - "shell_cmd": "make -j12 oup_size_benchmark", + "shell_cmd": "make -j12 oup_size_benchmark" }, { "name": "oup_speed_benchmark", - "shell_cmd": "make -j12 oup_speed_benchmark", + "shell_cmd": "make -j12 oup_speed_benchmark" }, { - "name": "oup_tests2", - "shell_cmd": "make -j12 oup_tests2", + "name": "oup_tests", + "shell_cmd": "make -j12 oup_tests" }, ], "working_dir": "$folder/build", diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 939bbcf..617507f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,4 +1,5 @@ function(add_platform_definitions TARGET) + target_compile_features(oup INTERFACE cxx_std_20) if(CMAKE_SYSTEM_NAME MATCHES "Emscripten") target_compile_definitions(${TARGET} PRIVATE OUP_PLATFORM_WASM) target_compile_definitions(${TARGET} PRIVATE OUP_COMPILER_EMSCRIPTEN) @@ -14,26 +15,10 @@ function(add_platform_definitions TARGET) endif() endfunction() -include(FetchContent) - -FetchContent_Declare( - Catch2 - GIT_REPOSITORY https://github.com/cschreib/Catch2.git - GIT_TAG 911eb82cf37f4017cb7f3260485e9d7351e18a4f -) - -FetchContent_MakeAvailable(Catch2) - set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${Catch2_SOURCE_DIR}/extras") -# add_executable(oup_tests -# ${PROJECT_SOURCE_DIR}/tests/memory_tracker.cpp -# ${PROJECT_SOURCE_DIR}/tests/runtime_tests.cpp) -# target_link_libraries(oup_tests PRIVATE Catch2::Catch2WithMain) -# target_link_libraries(oup_tests PRIVATE oup::oup) -# add_platform_definitions(oup_tests) - add_executable(oup_tests + ${PROJECT_SOURCE_DIR}/tests/snatch.cpp ${PROJECT_SOURCE_DIR}/tests/tests_common.cpp ${PROJECT_SOURCE_DIR}/tests/memory_tracker.cpp ${PROJECT_SOURCE_DIR}/tests/runtime_tests_owner_misc.cpp @@ -46,14 +31,10 @@ add_executable(oup_tests ${PROJECT_SOURCE_DIR}/tests/runtime_tests_observer_construction.cpp ${PROJECT_SOURCE_DIR}/tests/runtime_tests_observer_assignment.cpp ${PROJECT_SOURCE_DIR}/tests/runtime_tests_observer_comparison.cpp) -target_link_libraries(oup_tests PRIVATE Catch2::Catch2WithMain) target_link_libraries(oup_tests PRIVATE oup::oup) add_platform_definitions(oup_tests) include(CTest) -include(Catch) - -catch_discover_tests(oup_tests) # Compile-time error tests set(CMAKE_TRY_COMPILE_TARGET_TYPE EXECUTABLE) @@ -62,10 +43,12 @@ message(STATUS "Running compile-time tests...") function(run_compile_test TEST_NAME TEST_FILE EXPECTED) try_compile(COMPILE_TEST_RESULT ${PROJECT_SOURCE_DIR}/tests + SOURCES ${PROJECT_SOURCE_DIR}/tests/${TEST_FILE} + ${PROJECT_SOURCE_DIR}/tests/tests_common.cpp CMAKE_FLAGS "-DINCLUDE_DIRECTORIES=${PROJECT_SOURCE_DIR}/include" - "-DCMAKE_CXX_STANDARD=17") + "-DCMAKE_CXX_STANDARD=20") if(COMPILE_TEST_RESULT STREQUAL EXPECTED) message(STATUS "Test ${TEST_NAME} passed.") @@ -90,7 +73,6 @@ run_compile_test("is_sealed_reset_allowed" compile_test_sealed_reset.cpp FALSE) message(STATUS "Running compile-time tests ended.") # Benchmarks - add_executable(oup_size_benchmark ${PROJECT_SOURCE_DIR}/tests/memory_tracker.cpp ${PROJECT_SOURCE_DIR}/tests/size_benchmark.cpp) diff --git a/tests/catch2_and_overrides.hpp b/tests/catch2_and_overrides.hpp deleted file mode 100644 index 5a879aa..0000000 --- a/tests/catch2_and_overrides.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#include - -// Replace Catch2's REQUIRE_THROWS_AS, which allocates on Windows; -// this confuses our memory leak checks. -#undef REQUIRE_THROWS_AS -#define REQUIRE_THROWS_AS(EXPRESSION, EXCEPTION) \ - do { \ - try { \ - EXPRESSION; \ - FAIL("no exception thrown"); \ - } catch (const EXCEPTION&) { \ - } catch (const std::exception& e) { \ - FAIL(e.what()); \ - } catch (...) { \ - FAIL("unexpected exception thrown"); \ - } \ - } while (0) diff --git a/tests/cxxopts.hpp b/tests/cxxopts.hpp new file mode 100644 index 0000000..12456a7 --- /dev/null +++ b/tests/cxxopts.hpp @@ -0,0 +1,2611 @@ +/* + +Copyright (c) 2014, 2015, 2016, 2017 Jarryd Beck + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef CXXOPTS_HPP_INCLUDED +#define CXXOPTS_HPP_INCLUDED + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__GNUC__) && !defined(__clang__) +# if (__GNUC__ * 10 + __GNUC_MINOR__) < 49 +# define CXXOPTS_NO_REGEX true +# endif +#endif + +#ifndef CXXOPTS_NO_REGEX +# include +#endif // CXXOPTS_NO_REGEX + +// Nonstandard before C++17, which is coincidentally what we also need for +#ifdef __has_include +# if __has_include() +# include +# ifdef __cpp_lib_optional +# define CXXOPTS_HAS_OPTIONAL +# endif +# endif +#endif + +#if __cplusplus >= 201603L +#define CXXOPTS_NODISCARD [[nodiscard]] +#else +#define CXXOPTS_NODISCARD +#endif + +#ifndef CXXOPTS_VECTOR_DELIMITER +#define CXXOPTS_VECTOR_DELIMITER ',' +#endif + +#define CXXOPTS__VERSION_MAJOR 3 +#define CXXOPTS__VERSION_MINOR 0 +#define CXXOPTS__VERSION_PATCH 0 + +#if (__GNUC__ < 10 || (__GNUC__ == 10 && __GNUC_MINOR__ < 1)) && __GNUC__ >= 6 + #define CXXOPTS_NULL_DEREF_IGNORE +#endif + +namespace cxxopts +{ + static constexpr struct { + uint8_t major, minor, patch; + } version = { + CXXOPTS__VERSION_MAJOR, + CXXOPTS__VERSION_MINOR, + CXXOPTS__VERSION_PATCH + }; +} // namespace cxxopts + +//when we ask cxxopts to use Unicode, help strings are processed using ICU, +//which results in the correct lengths being computed for strings when they +//are formatted for the help output +//it is necessary to make sure that can be found by the +//compiler, and that icu-uc is linked in to the binary. + +#ifdef CXXOPTS_USE_UNICODE +#include + +namespace cxxopts +{ + using String = icu::UnicodeString; + + inline + String + toLocalString(std::string s) + { + return icu::UnicodeString::fromUTF8(std::move(s)); + } + +#if defined(__GNUC__) +// GNU GCC with -Weffc++ will issue a warning regarding the upcoming class, we want to silence it: +// warning: base class 'class std::enable_shared_from_this' has accessible non-virtual destructor +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +#pragma GCC diagnostic ignored "-Weffc++" +// This will be ignored under other compilers like LLVM clang. +#endif + class UnicodeStringIterator : public + std::iterator + { + public: + + UnicodeStringIterator(const icu::UnicodeString* string, int32_t pos) + : s(string) + , i(pos) + { + } + + value_type + operator*() const + { + return s->char32At(i); + } + + bool + operator==(const UnicodeStringIterator& rhs) const + { + return s == rhs.s && i == rhs.i; + } + + bool + operator!=(const UnicodeStringIterator& rhs) const + { + return !(*this == rhs); + } + + UnicodeStringIterator& + operator++() + { + ++i; + return *this; + } + + UnicodeStringIterator + operator+(int32_t v) + { + return UnicodeStringIterator(s, i + v); + } + + private: + const icu::UnicodeString* s; + int32_t i; + }; +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + + inline + String& + stringAppend(String&s, String a) + { + return s.append(std::move(a)); + } + + inline + String& + stringAppend(String& s, size_t n, UChar32 c) + { + for (size_t i = 0; i != n; ++i) + { + s.append(c); + } + + return s; + } + + template + String& + stringAppend(String& s, Iterator begin, Iterator end) + { + while (begin != end) + { + s.append(*begin); + ++begin; + } + + return s; + } + + inline + size_t + stringLength(const String& s) + { + return s.length(); + } + + inline + std::string + toUTF8String(const String& s) + { + std::string result; + s.toUTF8String(result); + + return result; + } + + inline + bool + empty(const String& s) + { + return s.isEmpty(); + } +} + +namespace std +{ + inline + cxxopts::UnicodeStringIterator + begin(const icu::UnicodeString& s) + { + return cxxopts::UnicodeStringIterator(&s, 0); + } + + inline + cxxopts::UnicodeStringIterator + end(const icu::UnicodeString& s) + { + return cxxopts::UnicodeStringIterator(&s, s.length()); + } +} + +//ifdef CXXOPTS_USE_UNICODE +#else + +namespace cxxopts +{ + using String = std::string; + + template + T + toLocalString(T&& t) + { + return std::forward(t); + } + + inline + size_t + stringLength(const String& s) + { + return s.length(); + } + + inline + String& + stringAppend(String&s, const String& a) + { + return s.append(a); + } + + inline + String& + stringAppend(String& s, size_t n, char c) + { + return s.append(n, c); + } + + template + String& + stringAppend(String& s, Iterator begin, Iterator end) + { + return s.append(begin, end); + } + + template + std::string + toUTF8String(T&& t) + { + return std::forward(t); + } + + inline + bool + empty(const std::string& s) + { + return s.empty(); + } +} // namespace cxxopts + +//ifdef CXXOPTS_USE_UNICODE +#endif + +namespace cxxopts +{ + namespace + { +#ifdef _WIN32 + const std::string LQUOTE("\'"); + const std::string RQUOTE("\'"); +#else + const std::string LQUOTE("‘"); + const std::string RQUOTE("’"); +#endif + } // namespace + +#if defined(__GNUC__) +// GNU GCC with -Weffc++ will issue a warning regarding the upcoming class, we want to silence it: +// warning: base class 'class std::enable_shared_from_this' has accessible non-virtual destructor +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +#pragma GCC diagnostic ignored "-Weffc++" +// This will be ignored under other compilers like LLVM clang. +#endif + class Value : public std::enable_shared_from_this + { + public: + + virtual ~Value() = default; + + virtual + std::shared_ptr + clone() const = 0; + + virtual void + parse(const std::string& text) const = 0; + + virtual void + parse() const = 0; + + virtual bool + has_default() const = 0; + + virtual bool + is_container() const = 0; + + virtual bool + has_implicit() const = 0; + + virtual std::string + get_default_value() const = 0; + + virtual std::string + get_implicit_value() const = 0; + + virtual std::shared_ptr + default_value(const std::string& value) = 0; + + virtual std::shared_ptr + implicit_value(const std::string& value) = 0; + + virtual std::shared_ptr + no_implicit_value() = 0; + + virtual bool + is_boolean() const = 0; + }; +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + class OptionException : public std::exception + { + public: + explicit OptionException(std::string message) + : m_message(std::move(message)) + { + } + + CXXOPTS_NODISCARD + const char* + what() const noexcept override + { + return m_message.c_str(); + } + + private: + std::string m_message; + }; + + class OptionSpecException : public OptionException + { + public: + + explicit OptionSpecException(const std::string& message) + : OptionException(message) + { + } + }; + + class OptionParseException : public OptionException + { + public: + explicit OptionParseException(const std::string& message) + : OptionException(message) + { + } + }; + + class option_exists_error : public OptionSpecException + { + public: + explicit option_exists_error(const std::string& option) + : OptionSpecException("Option " + LQUOTE + option + RQUOTE + " already exists") + { + } + }; + + class invalid_option_format_error : public OptionSpecException + { + public: + explicit invalid_option_format_error(const std::string& format) + : OptionSpecException("Invalid option format " + LQUOTE + format + RQUOTE) + { + } + }; + + class option_syntax_exception : public OptionParseException { + public: + explicit option_syntax_exception(const std::string& text) + : OptionParseException("Argument " + LQUOTE + text + RQUOTE + + " starts with a - but has incorrect syntax") + { + } + }; + + class option_not_exists_exception : public OptionParseException + { + public: + explicit option_not_exists_exception(const std::string& option) + : OptionParseException("Option " + LQUOTE + option + RQUOTE + " does not exist") + { + } + }; + + class missing_argument_exception : public OptionParseException + { + public: + explicit missing_argument_exception(const std::string& option) + : OptionParseException( + "Option " + LQUOTE + option + RQUOTE + " is missing an argument" + ) + { + } + }; + + class option_requires_argument_exception : public OptionParseException + { + public: + explicit option_requires_argument_exception(const std::string& option) + : OptionParseException( + "Option " + LQUOTE + option + RQUOTE + " requires an argument" + ) + { + } + }; + + class option_not_has_argument_exception : public OptionParseException + { + public: + option_not_has_argument_exception + ( + const std::string& option, + const std::string& arg + ) + : OptionParseException( + "Option " + LQUOTE + option + RQUOTE + + " does not take an argument, but argument " + + LQUOTE + arg + RQUOTE + " given" + ) + { + } + }; + + class option_not_present_exception : public OptionParseException + { + public: + explicit option_not_present_exception(const std::string& option) + : OptionParseException("Option " + LQUOTE + option + RQUOTE + " not present") + { + } + }; + + class option_has_no_value_exception : public OptionException + { + public: + explicit option_has_no_value_exception(const std::string& option) + : OptionException( + !option.empty() ? + ("Option " + LQUOTE + option + RQUOTE + " has no value") : + "Option has no value") + { + } + }; + + class argument_incorrect_type : public OptionParseException + { + public: + explicit argument_incorrect_type + ( + const std::string& arg + ) + : OptionParseException( + "Argument " + LQUOTE + arg + RQUOTE + " failed to parse" + ) + { + } + }; + + class option_required_exception : public OptionParseException + { + public: + explicit option_required_exception(const std::string& option) + : OptionParseException( + "Option " + LQUOTE + option + RQUOTE + " is required but not present" + ) + { + } + }; + + template + void throw_or_mimic(const std::string& text) + { + static_assert(std::is_base_of::value, + "throw_or_mimic only works on std::exception and " + "deriving classes"); + +#ifndef CXXOPTS_NO_EXCEPTIONS + // If CXXOPTS_NO_EXCEPTIONS is not defined, just throw + throw T{text}; +#else + // Otherwise manually instantiate the exception, print what() to stderr, + // and exit + T exception{text}; + std::cerr << exception.what() << std::endl; + std::exit(EXIT_FAILURE); +#endif + } + + namespace values + { + namespace parser_tool + { + struct IntegerDesc + { + std::string negative = ""; + std::string base = ""; + std::string value = ""; + }; + struct ArguDesc { + std::string arg_name = ""; + bool grouping = false; + bool set_value = false; + std::string value = ""; + }; +#ifdef CXXOPTS_NO_REGEX + inline IntegerDesc SplitInteger(const std::string &text) + { + if (text.empty()) + { + throw_or_mimic(text); + } + IntegerDesc desc; + const char *pdata = text.c_str(); + if (*pdata == '-') + { + pdata += 1; + desc.negative = "-"; + } + if (strncmp(pdata, "0x", 2) == 0) + { + pdata += 2; + desc.base = "0x"; + } + if (*pdata != '\0') + { + desc.value = std::string(pdata); + } + else + { + throw_or_mimic(text); + } + return desc; + } + + inline bool IsTrueText(const std::string &text) + { + const char *pdata = text.c_str(); + if (*pdata == 't' || *pdata == 'T') + { + pdata += 1; + if (strncmp(pdata, "rue\0", 4) == 0) + { + return true; + } + } + else if (strncmp(pdata, "1\0", 2) == 0) + { + return true; + } + return false; + } + + inline bool IsFalseText(const std::string &text) + { + const char *pdata = text.c_str(); + if (*pdata == 'f' || *pdata == 'F') + { + pdata += 1; + if (strncmp(pdata, "alse\0", 5) == 0) + { + return true; + } + } + else if (strncmp(pdata, "0\0", 2) == 0) + { + return true; + } + return false; + } + + inline std::pair SplitSwitchDef(const std::string &text) + { + std::string short_sw, long_sw; + const char *pdata = text.c_str(); + if (isalnum(*pdata) && *(pdata + 1) == ',') { + short_sw = std::string(1, *pdata); + pdata += 2; + } + while (*pdata == ' ') { pdata += 1; } + if (isalnum(*pdata)) { + const char *store = pdata; + pdata += 1; + while (isalnum(*pdata) || *pdata == '-' || *pdata == '_') { + pdata += 1; + } + if (*pdata == '\0') { + long_sw = std::string(store, pdata - store); + } else { + throw_or_mimic(text); + } + } + return std::pair(short_sw, long_sw); + } + + inline ArguDesc ParseArgument(const char *arg, bool &matched) + { + ArguDesc argu_desc; + const char *pdata = arg; + matched = false; + if (strncmp(pdata, "--", 2) == 0) + { + pdata += 2; + if (isalnum(*pdata)) + { + argu_desc.arg_name.push_back(*pdata); + pdata += 1; + while (isalnum(*pdata) || *pdata == '-' || *pdata == '_') + { + argu_desc.arg_name.push_back(*pdata); + pdata += 1; + } + if (argu_desc.arg_name.length() > 1) + { + if (*pdata == '=') + { + argu_desc.set_value = true; + pdata += 1; + if (*pdata != '\0') + { + argu_desc.value = std::string(pdata); + } + matched = true; + } + else if (*pdata == '\0') + { + matched = true; + } + } + } + } + else if (strncmp(pdata, "-", 1) == 0) + { + pdata += 1; + argu_desc.grouping = true; + while (isalnum(*pdata)) + { + argu_desc.arg_name.push_back(*pdata); + pdata += 1; + } + matched = !argu_desc.arg_name.empty() && *pdata == '\0'; + } + return argu_desc; + } + +#else // CXXOPTS_NO_REGEX + + namespace + { + + std::basic_regex integer_pattern + ("(-)?(0x)?([0-9a-zA-Z]+)|((0x)?0)"); + std::basic_regex truthy_pattern + ("(t|T)(rue)?|1"); + std::basic_regex falsy_pattern + ("(f|F)(alse)?|0"); + + std::basic_regex option_matcher + ("--([[:alnum:]][-_[:alnum:]]+)(=(.*))?|-([[:alnum:]]+)"); + std::basic_regex option_specifier + ("(([[:alnum:]]),)?[ ]*([[:alnum:]][-_[:alnum:]]*)?"); + + } // namespace + + inline IntegerDesc SplitInteger(const std::string &text) + { + std::smatch match; + std::regex_match(text, match, integer_pattern); + + if (match.length() == 0) + { + throw_or_mimic(text); + } + + IntegerDesc desc; + desc.negative = match[1]; + desc.base = match[2]; + desc.value = match[3]; + + if (match.length(4) > 0) + { + desc.base = match[5]; + desc.value = "0"; + return desc; + } + + return desc; + } + + inline bool IsTrueText(const std::string &text) + { + std::smatch result; + std::regex_match(text, result, truthy_pattern); + return !result.empty(); + } + + inline bool IsFalseText(const std::string &text) + { + std::smatch result; + std::regex_match(text, result, falsy_pattern); + return !result.empty(); + } + + inline std::pair SplitSwitchDef(const std::string &text) + { + std::match_results result; + std::regex_match(text.c_str(), result, option_specifier); + if (result.empty()) + { + throw_or_mimic(text); + } + + const std::string& short_sw = result[2]; + const std::string& long_sw = result[3]; + + return std::pair(short_sw, long_sw); + } + + inline ArguDesc ParseArgument(const char *arg, bool &matched) + { + std::match_results result; + std::regex_match(arg, result, option_matcher); + matched = !result.empty(); + + ArguDesc argu_desc; + if (matched) { + argu_desc.arg_name = result[1].str(); + argu_desc.set_value = result[2].length() > 0; + argu_desc.value = result[3].str(); + if (result[4].length() > 0) + { + argu_desc.grouping = true; + argu_desc.arg_name = result[4].str(); + } + } + + return argu_desc; + } + +#endif // CXXOPTS_NO_REGEX +#undef CXXOPTS_NO_REGEX + } + + namespace detail + { + template + struct SignedCheck; + + template + struct SignedCheck + { + template + void + operator()(bool negative, U u, const std::string& text) + { + if (negative) + { + if (u > static_cast((std::numeric_limits::min)())) + { + throw_or_mimic(text); + } + } + else + { + if (u > static_cast((std::numeric_limits::max)())) + { + throw_or_mimic(text); + } + } + } + }; + + template + struct SignedCheck + { + template + void + operator()(bool, U, const std::string&) const {} + }; + + template + void + check_signed_range(bool negative, U value, const std::string& text) + { + SignedCheck::is_signed>()(negative, value, text); + } + } // namespace detail + + template + void + checked_negate(R& r, T&& t, const std::string&, std::true_type) + { + // if we got to here, then `t` is a positive number that fits into + // `R`. So to avoid MSVC C4146, we first cast it to `R`. + // See https://github.com/jarro2783/cxxopts/issues/62 for more details. + r = static_cast(-static_cast(t-1)-1); + } + + template + void + checked_negate(R&, T&&, const std::string& text, std::false_type) + { + throw_or_mimic(text); + } + + template + void + integer_parser(const std::string& text, T& value) + { + parser_tool::IntegerDesc int_desc = parser_tool::SplitInteger(text); + + using US = typename std::make_unsigned::type; + constexpr bool is_signed = std::numeric_limits::is_signed; + + const bool negative = int_desc.negative.length() > 0; + const uint8_t base = int_desc.base.length() > 0 ? 16 : 10; + const std::string & value_match = int_desc.value; + + US result = 0; + + for (char ch : value_match) + { + US digit = 0; + + if (ch >= '0' && ch <= '9') + { + digit = static_cast(ch - '0'); + } + else if (base == 16 && ch >= 'a' && ch <= 'f') + { + digit = static_cast(ch - 'a' + 10); + } + else if (base == 16 && ch >= 'A' && ch <= 'F') + { + digit = static_cast(ch - 'A' + 10); + } + else + { + throw_or_mimic(text); + } + + const US next = static_cast(result * base + digit); + if (result > next) + { + throw_or_mimic(text); + } + + result = next; + } + + detail::check_signed_range(negative, result, text); + + if (negative) + { + checked_negate(value, result, text, std::integral_constant()); + } + else + { + value = static_cast(result); + } + } + + template + void stringstream_parser(const std::string& text, T& value) + { + std::stringstream in(text); + in >> value; + if (!in) { + throw_or_mimic(text); + } + } + + template ::value>::type* = nullptr + > + void parse_value(const std::string& text, T& value) + { + integer_parser(text, value); + } + + inline + void + parse_value(const std::string& text, bool& value) + { + if (parser_tool::IsTrueText(text)) + { + value = true; + return; + } + + if (parser_tool::IsFalseText(text)) + { + value = false; + return; + } + + throw_or_mimic(text); + } + + inline + void + parse_value(const std::string& text, std::string& value) + { + value = text; + } + + // The fallback parser. It uses the stringstream parser to parse all types + // that have not been overloaded explicitly. It has to be placed in the + // source code before all other more specialized templates. + template ::value>::type* = nullptr + > + void + parse_value(const std::string& text, T& value) { + stringstream_parser(text, value); + } + + template + void + parse_value(const std::string& text, std::vector& value) + { + if (text.empty()) { + T v; + parse_value(text, v); + value.emplace_back(std::move(v)); + return; + } + std::stringstream in(text); + std::string token; + while(!in.eof() && std::getline(in, token, CXXOPTS_VECTOR_DELIMITER)) { + T v; + parse_value(token, v); + value.emplace_back(std::move(v)); + } + } + +#ifdef CXXOPTS_HAS_OPTIONAL + template + void + parse_value(const std::string& text, std::optional& value) + { + T result; + parse_value(text, result); + value = std::move(result); + } +#endif + + inline + void parse_value(const std::string& text, char& c) + { + if (text.length() != 1) + { + throw_or_mimic(text); + } + + c = text[0]; + } + + template + struct type_is_container + { + static constexpr bool value = false; + }; + + template + struct type_is_container> + { + static constexpr bool value = true; + }; + + template + class abstract_value : public Value + { + using Self = abstract_value; + + public: + abstract_value() + : m_result(std::make_shared()) + , m_store(m_result.get()) + { + } + + explicit abstract_value(T* t) + : m_store(t) + { + } + + ~abstract_value() override = default; + + abstract_value& operator=(const abstract_value&) = default; + + abstract_value(const abstract_value& rhs) + { + if (rhs.m_result) + { + m_result = std::make_shared(); + m_store = m_result.get(); + } + else + { + m_store = rhs.m_store; + } + + m_default = rhs.m_default; + m_implicit = rhs.m_implicit; + m_default_value = rhs.m_default_value; + m_implicit_value = rhs.m_implicit_value; + } + + void + parse(const std::string& text) const override + { + parse_value(text, *m_store); + } + + bool + is_container() const override + { + return type_is_container::value; + } + + void + parse() const override + { + parse_value(m_default_value, *m_store); + } + + bool + has_default() const override + { + return m_default; + } + + bool + has_implicit() const override + { + return m_implicit; + } + + std::shared_ptr + default_value(const std::string& value) override + { + m_default = true; + m_default_value = value; + return shared_from_this(); + } + + std::shared_ptr + implicit_value(const std::string& value) override + { + m_implicit = true; + m_implicit_value = value; + return shared_from_this(); + } + + std::shared_ptr + no_implicit_value() override + { + m_implicit = false; + return shared_from_this(); + } + + std::string + get_default_value() const override + { + return m_default_value; + } + + std::string + get_implicit_value() const override + { + return m_implicit_value; + } + + bool + is_boolean() const override + { + return std::is_same::value; + } + + const T& + get() const + { + if (m_store == nullptr) + { + return *m_result; + } + return *m_store; + } + + protected: + std::shared_ptr m_result{}; + T* m_store{}; + + bool m_default = false; + bool m_implicit = false; + + std::string m_default_value{}; + std::string m_implicit_value{}; + }; + + template + class standard_value : public abstract_value + { + public: + using abstract_value::abstract_value; + + CXXOPTS_NODISCARD + std::shared_ptr + clone() const override + { + return std::make_shared>(*this); + } + }; + + template <> + class standard_value : public abstract_value + { + public: + ~standard_value() override = default; + + standard_value() + { + set_default_and_implicit(); + } + + explicit standard_value(bool* b) + : abstract_value(b) + { + set_default_and_implicit(); + } + + std::shared_ptr + clone() const override + { + return std::make_shared>(*this); + } + + private: + + void + set_default_and_implicit() + { + m_default = true; + m_default_value = "false"; + m_implicit = true; + m_implicit_value = "true"; + } + }; + } // namespace values + + template + std::shared_ptr + value() + { + return std::make_shared>(); + } + + template + std::shared_ptr + value(T& t) + { + return std::make_shared>(&t); + } + + class OptionAdder; + + class OptionDetails + { + public: + OptionDetails + ( + std::string short_, + std::string long_, + String desc, + std::shared_ptr val + ) + : m_short(std::move(short_)) + , m_long(std::move(long_)) + , m_desc(std::move(desc)) + , m_value(std::move(val)) + , m_count(0) + { + m_hash = std::hash{}(m_long + m_short); + } + + OptionDetails(const OptionDetails& rhs) + : m_desc(rhs.m_desc) + , m_value(rhs.m_value->clone()) + , m_count(rhs.m_count) + { + } + + OptionDetails(OptionDetails&& rhs) = default; + + CXXOPTS_NODISCARD + const String& + description() const + { + return m_desc; + } + + CXXOPTS_NODISCARD + const Value& + value() const { + return *m_value; + } + + CXXOPTS_NODISCARD + std::shared_ptr + make_storage() const + { + return m_value->clone(); + } + + CXXOPTS_NODISCARD + const std::string& + short_name() const + { + return m_short; + } + + CXXOPTS_NODISCARD + const std::string& + long_name() const + { + return m_long; + } + + size_t + hash() const + { + return m_hash; + } + + private: + std::string m_short{}; + std::string m_long{}; + String m_desc{}; + std::shared_ptr m_value{}; + int m_count; + + size_t m_hash{}; + }; + + struct HelpOptionDetails + { + std::string s; + std::string l; + String desc; + bool has_default; + std::string default_value; + bool has_implicit; + std::string implicit_value; + std::string arg_help; + bool is_container; + bool is_boolean; + }; + + struct HelpGroupDetails + { + std::string name{}; + std::string description{}; + std::vector options{}; + }; + + class OptionValue + { + public: + void + parse + ( + const std::shared_ptr& details, + const std::string& text + ) + { + ensure_value(details); + ++m_count; + m_value->parse(text); + m_long_name = &details->long_name(); + } + + void + parse_default(const std::shared_ptr& details) + { + ensure_value(details); + m_default = true; + m_long_name = &details->long_name(); + m_value->parse(); + } + + void + parse_no_value(const std::shared_ptr& details) + { + m_long_name = &details->long_name(); + } + +#if defined(CXXOPTS_NULL_DEREF_IGNORE) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnull-dereference" +#endif + + CXXOPTS_NODISCARD + size_t + count() const noexcept + { + return m_count; + } + +#if defined(CXXOPTS_NULL_DEREF_IGNORE) +#pragma GCC diagnostic pop +#endif + + // TODO: maybe default options should count towards the number of arguments + CXXOPTS_NODISCARD + bool + has_default() const noexcept + { + return m_default; + } + + template + const T& + as() const + { + if (m_value == nullptr) { + throw_or_mimic( + m_long_name == nullptr ? "" : *m_long_name); + } + +#ifdef CXXOPTS_NO_RTTI + return static_cast&>(*m_value).get(); +#else + return dynamic_cast&>(*m_value).get(); +#endif + } + + private: + void + ensure_value(const std::shared_ptr& details) + { + if (m_value == nullptr) + { + m_value = details->make_storage(); + } + } + + + const std::string* m_long_name = nullptr; + // Holding this pointer is safe, since OptionValue's only exist in key-value pairs, + // where the key has the string we point to. + std::shared_ptr m_value{}; + size_t m_count = 0; + bool m_default = false; + }; + + class KeyValue + { + public: + KeyValue(std::string key_, std::string value_) + : m_key(std::move(key_)) + , m_value(std::move(value_)) + { + } + + CXXOPTS_NODISCARD + const std::string& + key() const + { + return m_key; + } + + CXXOPTS_NODISCARD + const std::string& + value() const + { + return m_value; + } + + template + T + as() const + { + T result; + values::parse_value(m_value, result); + return result; + } + + private: + std::string m_key; + std::string m_value; + }; + + using ParsedHashMap = std::unordered_map; + using NameHashMap = std::unordered_map; + + class ParseResult + { + public: + + ParseResult() = default; + ParseResult(const ParseResult&) = default; + + ParseResult(NameHashMap&& keys, ParsedHashMap&& values, std::vector sequential, std::vector&& unmatched_args) + : m_keys(std::move(keys)) + , m_values(std::move(values)) + , m_sequential(std::move(sequential)) + , m_unmatched(std::move(unmatched_args)) + { + } + + ParseResult& operator=(ParseResult&&) = default; + ParseResult& operator=(const ParseResult&) = default; + + size_t + count(const std::string& o) const + { + auto iter = m_keys.find(o); + if (iter == m_keys.end()) + { + return 0; + } + + auto viter = m_values.find(iter->second); + + if (viter == m_values.end()) + { + return 0; + } + + return viter->second.count(); + } + + const OptionValue& + operator[](const std::string& option) const + { + auto iter = m_keys.find(option); + + if (iter == m_keys.end()) + { + throw_or_mimic(option); + } + + auto viter = m_values.find(iter->second); + + if (viter == m_values.end()) + { + throw_or_mimic(option); + } + + return viter->second; + } + + const std::vector& + arguments() const + { + return m_sequential; + } + + const std::vector& + unmatched() const + { + return m_unmatched; + } + + private: + NameHashMap m_keys{}; + ParsedHashMap m_values{}; + std::vector m_sequential{}; + std::vector m_unmatched{}; + }; + + struct Option + { + Option + ( + std::string opts, + std::string desc, + std::shared_ptr value = ::cxxopts::value(), + std::string arg_help = "" + ) + : opts_(std::move(opts)) + , desc_(std::move(desc)) + , value_(std::move(value)) + , arg_help_(std::move(arg_help)) + { + } + + std::string opts_; + std::string desc_; + std::shared_ptr value_; + std::string arg_help_; + }; + + using OptionMap = std::unordered_map>; + using PositionalList = std::vector; + using PositionalListIterator = PositionalList::const_iterator; + + class OptionParser + { + public: + OptionParser(const OptionMap& options, const PositionalList& positional, bool allow_unrecognised) + : m_options(options) + , m_positional(positional) + , m_allow_unrecognised(allow_unrecognised) + { + } + + ParseResult + parse(int argc, const char* const* argv); + + bool + consume_positional(const std::string& a, PositionalListIterator& next); + + void + checked_parse_arg + ( + int argc, + const char* const* argv, + int& current, + const std::shared_ptr& value, + const std::string& name + ); + + void + add_to_option(OptionMap::const_iterator iter, const std::string& option, const std::string& arg); + + void + parse_option + ( + const std::shared_ptr& value, + const std::string& name, + const std::string& arg = "" + ); + + void + parse_default(const std::shared_ptr& details); + + void + parse_no_value(const std::shared_ptr& details); + + private: + + void finalise_aliases(); + + const OptionMap& m_options; + const PositionalList& m_positional; + + std::vector m_sequential{}; + bool m_allow_unrecognised; + + ParsedHashMap m_parsed{}; + NameHashMap m_keys{}; + }; + + class Options + { + public: + + explicit Options(std::string program, std::string help_string = "") + : m_program(std::move(program)) + , m_help_string(toLocalString(std::move(help_string))) + , m_custom_help("[OPTION...]") + , m_positional_help("positional parameters") + , m_show_positional(false) + , m_allow_unrecognised(false) + , m_width(76) + , m_tab_expansion(false) + , m_options(std::make_shared()) + { + } + + Options& + positional_help(std::string help_text) + { + m_positional_help = std::move(help_text); + return *this; + } + + Options& + custom_help(std::string help_text) + { + m_custom_help = std::move(help_text); + return *this; + } + + Options& + show_positional_help() + { + m_show_positional = true; + return *this; + } + + Options& + allow_unrecognised_options() + { + m_allow_unrecognised = true; + return *this; + } + + Options& + set_width(size_t width) + { + m_width = width; + return *this; + } + + Options& + set_tab_expansion(bool expansion=true) + { + m_tab_expansion = expansion; + return *this; + } + + ParseResult + parse(int argc, const char* const* argv); + + OptionAdder + add_options(std::string group = ""); + + void + add_options + ( + const std::string& group, + std::initializer_list