diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4f81c000..1be01da7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -125,6 +125,7 @@ set(INTERNAL_HEADERS ${SOURCES_DIR}/catch_totals.hpp ${SOURCES_DIR}/catch_translate_exception.hpp ${SOURCES_DIR}/internal/catch_uncaught_exceptions.hpp + ${SOURCES_DIR}/internal/catch_unique_ptr.hpp ${SOURCES_DIR}/catch_version.hpp ${SOURCES_DIR}/catch_version_macros.hpp ${SOURCES_DIR}/internal/catch_wildcard_pattern.hpp diff --git a/src/catch2/catch_all.hpp b/src/catch2/catch_all.hpp index b0f31196..fab323bd 100644 --- a/src/catch2/catch_all.hpp +++ b/src/catch2/catch_all.hpp @@ -85,6 +85,7 @@ #include #include #include +#include #include #include #include diff --git a/src/catch2/internal/catch_unique_ptr.hpp b/src/catch2/internal/catch_unique_ptr.hpp new file mode 100644 index 00000000..f963e9d6 --- /dev/null +++ b/src/catch2/internal/catch_unique_ptr.hpp @@ -0,0 +1,110 @@ +#ifndef CATCH_UNIQUE_PTR_HPP_INCLUDED +#define CATCH_UNIQUE_PTR_HPP_INCLUDED + +#include +#include + +namespace Catch { +namespace Detail { + // reimplementation of unique_ptr for improved compilation times + // Does not support custom deleters (and thus does not require EBO) + // Does not support arrays + template + class unique_ptr { + T* m_ptr; + public: + constexpr unique_ptr(std::nullptr_t = nullptr): + m_ptr{} + {} + explicit constexpr unique_ptr(T* ptr): + m_ptr(ptr) + {} + + template ::value>> + unique_ptr(unique_ptr&& from): + m_ptr(from.release()) + {} + + template ::value>> + unique_ptr& operator=(unique_ptr&& from) { + reset(from.release()); + + return *this; + } + + unique_ptr(unique_ptr const&) = delete; + unique_ptr& operator=(unique_ptr const&) = delete; + + unique_ptr(unique_ptr&& rhs) noexcept: + m_ptr(rhs.m_ptr) { + rhs.m_ptr = nullptr; + } + unique_ptr& operator=(unique_ptr&& rhs) noexcept { + reset(rhs.release()); + + return *this; + } + + ~unique_ptr() { + delete m_ptr; + } + + T& operator*() { + assert(m_ptr); + return *m_ptr; + } + T const& operator*() const { + assert(m_ptr); + return *m_ptr; + } + T* operator->() const noexcept { + assert(m_ptr); + return m_ptr; + } + + T* get() { return m_ptr; } + T const* get() const { return m_ptr; } + + void reset(T* ptr = nullptr) { + delete m_ptr; + m_ptr = ptr; + } + + T* release() { + auto temp = m_ptr; + m_ptr = nullptr; + return temp; + } + + explicit operator bool() const { + return m_ptr; + } + + friend void swap(unique_ptr& lhs, unique_ptr& rhs) { + auto temp = lhs.m_ptr; + lhs.m_ptr = rhs.m_ptr; + rhs.m_ptr = temp; + } + }; + + // Purposefully doesn't exist + // We could also rely on compiler warning + werror for calling plain delete + // on a T[], but this seems better. + // Maybe add definition and a static assert? + template + class unique_ptr; + + template + unique_ptr make_unique(Args&&... args) { + // static_cast does the same thing as std::forward in + // this case, but does not require including big header () + // and compiles faster thanks to not requiring template instantiation + // and overload resolution + return unique_ptr(new T(static_cast(args)...)); + } + + +} // end namespace Detail +} // end namespace Catch + +#endif // CATCH_UNIQUE_PTR_HPP_INCLUDED diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8b3c9092..a5fdf802 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -27,6 +27,7 @@ set(TEST_SOURCES ${SELF_TEST_DIR}/IntrospectiveTests/StringManip.tests.cpp ${SELF_TEST_DIR}/IntrospectiveTests/Xml.tests.cpp ${SELF_TEST_DIR}/IntrospectiveTests/ToString.tests.cpp + ${SELF_TEST_DIR}/IntrospectiveTests/UniquePtr.tests.cpp ${SELF_TEST_DIR}/UsageTests/Approx.tests.cpp ${SELF_TEST_DIR}/UsageTests/BDD.tests.cpp ${SELF_TEST_DIR}/UsageTests/Benchmark.tests.cpp diff --git a/tests/SelfTest/Baselines/automake.sw.approved.txt b/tests/SelfTest/Baselines/automake.sw.approved.txt index 88a43ede..ffde555a 100644 --- a/tests/SelfTest/Baselines/automake.sw.approved.txt +++ b/tests/SelfTest/Baselines/automake.sw.approved.txt @@ -222,6 +222,7 @@ Message from section two :test-result: PASS Tracker :test-result: PASS Trim strings :test-result: FAIL Unexpected exceptions can be translated +:test-result: PASS Upcasting special member functions :test-result: PASS Usage of the SizeIs range matcher :test-result: PASS Use a custom approx :test-result: PASS Variadic macros @@ -268,6 +269,7 @@ loose text artifact :test-result: PASS long long :test-result: FAIL looped SECTION tests :test-result: FAIL looped tests +:test-result: PASS make_unique reimplementation :test-result: PASS mean :test-result: PASS measure :test-result: FAIL mix info, unscoped info and warning @@ -331,6 +333,7 @@ loose text artifact :test-result: PASS tuple :test-result: PASS tuple,tuple<>,float> :test-result: PASS uniform samples +:test-result: PASS unique_ptr reimplementation: basic functionality :test-result: PASS vec> -> toString :test-result: PASS vector -> toString :test-result: PASS vector -> toString diff --git a/tests/SelfTest/Baselines/compact.sw.approved.txt b/tests/SelfTest/Baselines/compact.sw.approved.txt index 4d2fcbe2..d7a756f4 100644 --- a/tests/SelfTest/Baselines/compact.sw.approved.txt +++ b/tests/SelfTest/Baselines/compact.sw.approved.txt @@ -1587,6 +1587,8 @@ StringManip.tests.cpp:: passed: trim(StringRef(whitespace_at_both_e == There is no extra whitespace here Exception.tests.cpp:: failed: unexpected exception with message: '3.14' +UniquePtr.tests.cpp:: passed: bptr->i == 3 for: 3 == 3 +UniquePtr.tests.cpp:: passed: bptr->i == 3 for: 3 == 3 MatchersRanges.tests.cpp:: passed: empty_vec, SizeIs(0) for: { } has size == 0 MatchersRanges.tests.cpp:: passed: empty_vec, !SizeIs(2) for: { } not has size == 2 MatchersRanges.tests.cpp:: passed: empty_vec, SizeIs(Lt(2)) for: { } size matches is less than 2 @@ -1794,6 +1796,9 @@ Misc.tests.cpp:: failed: ( fib[i] % 2 ) == 0 for: 1 == 0 with 1 mes Misc.tests.cpp:: passed: ( fib[i] % 2 ) == 0 for: 0 == 0 with 1 message: 'Testing if fib[5] (8) is even' Misc.tests.cpp:: failed: ( fib[i] % 2 ) == 0 for: 1 == 0 with 1 message: 'Testing if fib[6] (13) is even' Misc.tests.cpp:: failed: ( fib[i] % 2 ) == 0 for: 1 == 0 with 1 message: 'Testing if fib[7] (21) is even' +UniquePtr.tests.cpp:: passed: !(lval.has_moved) for: !false +UniquePtr.tests.cpp:: passed: rval.has_moved for: true +UniquePtr.tests.cpp:: passed: *ptr == std::tuple{1, 2., 3} for: {?} == {?} InternalBenchmark.tests.cpp:: passed: m == 19. for: 19.0 == 19.0 InternalBenchmark.tests.cpp:: passed: x == 17 for: 17 == 17 InternalBenchmark.tests.cpp:: passed: x == 23 for: 23 == 23 @@ -1990,6 +1995,29 @@ InternalBenchmark.tests.cpp:: passed: e.point == 23 for: 23.0 == 23 InternalBenchmark.tests.cpp:: passed: e.upper_bound == 23 for: 23.0 == 23 InternalBenchmark.tests.cpp:: passed: e.lower_bound == 23 for: 23.0 == 23 InternalBenchmark.tests.cpp:: passed: e.confidence_interval == 0.95 for: 0.95 == 0.95 +UniquePtr.tests.cpp:: passed: !(ptr) for: !{?} +UniquePtr.tests.cpp:: passed: ptr.get() == 0 for: 0 == 0 +UniquePtr.tests.cpp:: passed: ptr for: {?} +UniquePtr.tests.cpp:: passed: *ptr == 0 for: 0 == 0 +UniquePtr.tests.cpp:: passed: ptr.get() == naked_ptr for: 0x == 0x +UniquePtr.tests.cpp:: passed: !(ptr) for: !{?} +UniquePtr.tests.cpp:: passed: ptr.get() == 0 for: 0 == 0 +UniquePtr.tests.cpp:: passed: ptr for: {?} +UniquePtr.tests.cpp:: passed: *ptr == 0 for: 0 == 0 +UniquePtr.tests.cpp:: passed: ptr.get() == naked_ptr for: 0x == 0x +UniquePtr.tests.cpp:: passed: ptr for: {?} +UniquePtr.tests.cpp:: passed: ptr.get() != 0 for: 0x != 0 +UniquePtr.tests.cpp:: passed: *ptr == 2 for: 2 == 2 +UniquePtr.tests.cpp:: passed: !(ptr) for: !{?} +UniquePtr.tests.cpp:: passed: ptr.get() == 0 for: 0 == 0 +UniquePtr.tests.cpp:: passed: !(ptr1) for: !{?} +UniquePtr.tests.cpp:: passed: ptr2 for: {?} +UniquePtr.tests.cpp:: passed: *ptr2 == 1 for: 1 == 1 +UniquePtr.tests.cpp:: passed: !(ptr2) for: !{?} +UniquePtr.tests.cpp:: passed: ptr1 for: {?} +UniquePtr.tests.cpp:: passed: *ptr1 == 2 for: 2 == 2 +UniquePtr.tests.cpp:: passed: *ptr1 == 2 for: 2 == 2 +UniquePtr.tests.cpp:: passed: *ptr2 == 1 for: 1 == 1 ToStringVector.tests.cpp:: passed: ::Catch::Detail::stringify(v) == "{ }" for: "{ }" == "{ }" ToStringVector.tests.cpp:: passed: ::Catch::Detail::stringify(v) == "{ { \"hello\" }, { \"world\" } }" for: "{ { "hello" }, { "world" } }" == diff --git a/tests/SelfTest/Baselines/console.std.approved.txt b/tests/SelfTest/Baselines/console.std.approved.txt index f92173e5..ee6710d3 100644 --- a/tests/SelfTest/Baselines/console.std.approved.txt +++ b/tests/SelfTest/Baselines/console.std.approved.txt @@ -1380,6 +1380,6 @@ due to unexpected exception with message: Why would you throw a std::string? =============================================================================== -test cases: 334 | 260 passed | 70 failed | 4 failed as expected -assertions: 1896 | 1744 passed | 131 failed | 21 failed as expected +test cases: 337 | 263 passed | 70 failed | 4 failed as expected +assertions: 1924 | 1772 passed | 131 failed | 21 failed as expected diff --git a/tests/SelfTest/Baselines/console.sw.approved.txt b/tests/SelfTest/Baselines/console.sw.approved.txt index 4123232c..450d8025 100644 --- a/tests/SelfTest/Baselines/console.sw.approved.txt +++ b/tests/SelfTest/Baselines/console.sw.approved.txt @@ -11547,6 +11547,30 @@ Exception.tests.cpp:: FAILED: due to unexpected exception with message: 3.14 +------------------------------------------------------------------------------- +Upcasting special member functions + Move constructor +------------------------------------------------------------------------------- +UniquePtr.tests.cpp: +............................................................................... + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( bptr->i == 3 ) +with expansion: + 3 == 3 + +------------------------------------------------------------------------------- +Upcasting special member functions + move assignment +------------------------------------------------------------------------------- +UniquePtr.tests.cpp: +............................................................................... + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( bptr->i == 3 ) +with expansion: + 3 == 3 + ------------------------------------------------------------------------------- Usage of the SizeIs range matcher Some with stdlib containers @@ -13096,6 +13120,42 @@ with expansion: with message: Testing if fib[7] (21) is even +------------------------------------------------------------------------------- +make_unique reimplementation + From lvalue copies +------------------------------------------------------------------------------- +UniquePtr.tests.cpp: +............................................................................... + +UniquePtr.tests.cpp:: PASSED: + REQUIRE_FALSE( lval.has_moved ) +with expansion: + !false + +------------------------------------------------------------------------------- +make_unique reimplementation + From rvalue moves +------------------------------------------------------------------------------- +UniquePtr.tests.cpp: +............................................................................... + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( rval.has_moved ) +with expansion: + true + +------------------------------------------------------------------------------- +make_unique reimplementation + Variadic constructor +------------------------------------------------------------------------------- +UniquePtr.tests.cpp: +............................................................................... + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( *ptr == std::tuple{1, 2., 3} ) +with expansion: + {?} == {?} + ------------------------------------------------------------------------------- mean ------------------------------------------------------------------------------- @@ -14485,6 +14545,186 @@ InternalBenchmark.tests.cpp:: PASSED: with expansion: 0.95 == 0.95 +------------------------------------------------------------------------------- +unique_ptr reimplementation: basic functionality + Default constructed unique_ptr is empty +------------------------------------------------------------------------------- +UniquePtr.tests.cpp: +............................................................................... + +UniquePtr.tests.cpp:: PASSED: + REQUIRE_FALSE( ptr ) +with expansion: + !{?} + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( ptr.get() == 0 ) +with expansion: + 0 == 0 + +------------------------------------------------------------------------------- +unique_ptr reimplementation: basic functionality + Take ownership of allocation +------------------------------------------------------------------------------- +UniquePtr.tests.cpp: +............................................................................... + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( ptr ) +with expansion: + {?} + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( *ptr == 0 ) +with expansion: + 0 == 0 + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( ptr.get() == naked_ptr ) +with expansion: + 0x == 0x + +------------------------------------------------------------------------------- +unique_ptr reimplementation: basic functionality + Take ownership of allocation + Plain reset deallocates +------------------------------------------------------------------------------- +UniquePtr.tests.cpp: +............................................................................... + +UniquePtr.tests.cpp:: PASSED: + REQUIRE_FALSE( ptr ) +with expansion: + !{?} + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( ptr.get() == 0 ) +with expansion: + 0 == 0 + +------------------------------------------------------------------------------- +unique_ptr reimplementation: basic functionality + Take ownership of allocation +------------------------------------------------------------------------------- +UniquePtr.tests.cpp: +............................................................................... + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( ptr ) +with expansion: + {?} + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( *ptr == 0 ) +with expansion: + 0 == 0 + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( ptr.get() == naked_ptr ) +with expansion: + 0x == 0x + +------------------------------------------------------------------------------- +unique_ptr reimplementation: basic functionality + Take ownership of allocation + Reset replaces ownership +------------------------------------------------------------------------------- +UniquePtr.tests.cpp: +............................................................................... + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( ptr ) +with expansion: + {?} + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( ptr.get() != 0 ) +with expansion: + 0x != 0 + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( *ptr == 2 ) +with expansion: + 2 == 2 + +------------------------------------------------------------------------------- +unique_ptr reimplementation: basic functionality + Release releases ownership +------------------------------------------------------------------------------- +UniquePtr.tests.cpp: +............................................................................... + +UniquePtr.tests.cpp:: PASSED: + CHECK_FALSE( ptr ) +with expansion: + !{?} + +UniquePtr.tests.cpp:: PASSED: + CHECK( ptr.get() == 0 ) +with expansion: + 0 == 0 + +------------------------------------------------------------------------------- +unique_ptr reimplementation: basic functionality + Move constructor +------------------------------------------------------------------------------- +UniquePtr.tests.cpp: +............................................................................... + +UniquePtr.tests.cpp:: PASSED: + REQUIRE_FALSE( ptr1 ) +with expansion: + !{?} + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( ptr2 ) +with expansion: + {?} + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( *ptr2 == 1 ) +with expansion: + 1 == 1 + +------------------------------------------------------------------------------- +unique_ptr reimplementation: basic functionality + Move assignment +------------------------------------------------------------------------------- +UniquePtr.tests.cpp: +............................................................................... + +UniquePtr.tests.cpp:: PASSED: + REQUIRE_FALSE( ptr2 ) +with expansion: + !{?} + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( ptr1 ) +with expansion: + {?} + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( *ptr1 == 2 ) +with expansion: + 2 == 2 + +------------------------------------------------------------------------------- +unique_ptr reimplementation: basic functionality + free swap +------------------------------------------------------------------------------- +UniquePtr.tests.cpp: +............................................................................... + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( *ptr1 == 2 ) +with expansion: + 2 == 2 + +UniquePtr.tests.cpp:: PASSED: + REQUIRE( *ptr2 == 1 ) +with expansion: + 1 == 1 + ------------------------------------------------------------------------------- vec> -> toString ------------------------------------------------------------------------------- @@ -14792,6 +15032,6 @@ Misc.tests.cpp: Misc.tests.cpp:: PASSED: =============================================================================== -test cases: 334 | 244 passed | 86 failed | 4 failed as expected -assertions: 1913 | 1744 passed | 148 failed | 21 failed as expected +test cases: 337 | 247 passed | 86 failed | 4 failed as expected +assertions: 1941 | 1772 passed | 148 failed | 21 failed as expected diff --git a/tests/SelfTest/Baselines/junit.sw.approved.txt b/tests/SelfTest/Baselines/junit.sw.approved.txt index 9c4dd7cb..839cf6e6 100644 --- a/tests/SelfTest/Baselines/junit.sw.approved.txt +++ b/tests/SelfTest/Baselines/junit.sw.approved.txt @@ -1,7 +1,7 @@ - + @@ -1256,6 +1256,8 @@ FAILED: Exception.tests.cpp: + + @@ -1577,6 +1579,9 @@ Testing if fib[7] (21) is even Misc.tests.cpp: + + + @@ -1733,6 +1738,14 @@ Exception.tests.cpp: + + + + + + + + diff --git a/tests/SelfTest/Baselines/sonarqube.sw.approved.txt b/tests/SelfTest/Baselines/sonarqube.sw.approved.txt index 42422727..2809f95b 100644 --- a/tests/SelfTest/Baselines/sonarqube.sw.approved.txt +++ b/tests/SelfTest/Baselines/sonarqube.sw.approved.txt @@ -180,6 +180,21 @@ + + + + + + + + + + + + + + + diff --git a/tests/SelfTest/Baselines/tap.sw.approved.txt b/tests/SelfTest/Baselines/tap.sw.approved.txt index b28c70d4..d03b250e 100644 --- a/tests/SelfTest/Baselines/tap.sw.approved.txt +++ b/tests/SelfTest/Baselines/tap.sw.approved.txt @@ -3021,6 +3021,10 @@ ok {test-number} - trim(StringRef(trailing_whitespace)) == StringRef(no_whitespa ok {test-number} - trim(StringRef(whitespace_at_both_ends)) == StringRef(no_whitespace) for: There is no extra whitespace here == There is no extra whitespace here # Unexpected exceptions can be translated not ok {test-number} - unexpected exception with message: '3.14' +# Upcasting special member functions +ok {test-number} - bptr->i == 3 for: 3 == 3 +# Upcasting special member functions +ok {test-number} - bptr->i == 3 for: 3 == 3 # Usage of the SizeIs range matcher ok {test-number} - empty_vec, SizeIs(0) for: { } has size == 0 # Usage of the SizeIs range matcher @@ -3418,6 +3422,12 @@ ok {test-number} - ( fib[i] % 2 ) == 0 for: 0 == 0 with 1 message: 'Testing if f not ok {test-number} - ( fib[i] % 2 ) == 0 for: 1 == 0 with 1 message: 'Testing if fib[6] (13) is even' # looped tests not ok {test-number} - ( fib[i] % 2 ) == 0 for: 1 == 0 with 1 message: 'Testing if fib[7] (21) is even' +# make_unique reimplementation +ok {test-number} - !(lval.has_moved) for: !false +# make_unique reimplementation +ok {test-number} - rval.has_moved for: true +# make_unique reimplementation +ok {test-number} - *ptr == std::tuple{1, 2., 3} for: {?} == {?} # mean ok {test-number} - m == 19. for: 19.0 == 19.0 # measure @@ -3742,6 +3752,52 @@ ok {test-number} - e.upper_bound == 23 for: 23.0 == 23 ok {test-number} - e.lower_bound == 23 for: 23.0 == 23 # uniform samples ok {test-number} - e.confidence_interval == 0.95 for: 0.95 == 0.95 +# unique_ptr reimplementation: basic functionality +ok {test-number} - !(ptr) for: !{?} +# unique_ptr reimplementation: basic functionality +ok {test-number} - ptr.get() == 0 for: 0 == 0 +# unique_ptr reimplementation: basic functionality +ok {test-number} - ptr for: {?} +# unique_ptr reimplementation: basic functionality +ok {test-number} - *ptr == 0 for: 0 == 0 +# unique_ptr reimplementation: basic functionality +ok {test-number} - ptr.get() == naked_ptr for: 0x == 0x +# unique_ptr reimplementation: basic functionality +ok {test-number} - !(ptr) for: !{?} +# unique_ptr reimplementation: basic functionality +ok {test-number} - ptr.get() == 0 for: 0 == 0 +# unique_ptr reimplementation: basic functionality +ok {test-number} - ptr for: {?} +# unique_ptr reimplementation: basic functionality +ok {test-number} - *ptr == 0 for: 0 == 0 +# unique_ptr reimplementation: basic functionality +ok {test-number} - ptr.get() == naked_ptr for: 0x == 0x +# unique_ptr reimplementation: basic functionality +ok {test-number} - ptr for: {?} +# unique_ptr reimplementation: basic functionality +ok {test-number} - ptr.get() != 0 for: 0x != 0 +# unique_ptr reimplementation: basic functionality +ok {test-number} - *ptr == 2 for: 2 == 2 +# unique_ptr reimplementation: basic functionality +ok {test-number} - !(ptr) for: !{?} +# unique_ptr reimplementation: basic functionality +ok {test-number} - ptr.get() == 0 for: 0 == 0 +# unique_ptr reimplementation: basic functionality +ok {test-number} - !(ptr1) for: !{?} +# unique_ptr reimplementation: basic functionality +ok {test-number} - ptr2 for: {?} +# unique_ptr reimplementation: basic functionality +ok {test-number} - *ptr2 == 1 for: 1 == 1 +# unique_ptr reimplementation: basic functionality +ok {test-number} - !(ptr2) for: !{?} +# unique_ptr reimplementation: basic functionality +ok {test-number} - ptr1 for: {?} +# unique_ptr reimplementation: basic functionality +ok {test-number} - *ptr1 == 2 for: 2 == 2 +# unique_ptr reimplementation: basic functionality +ok {test-number} - *ptr1 == 2 for: 2 == 2 +# unique_ptr reimplementation: basic functionality +ok {test-number} - *ptr2 == 1 for: 1 == 1 # vec> -> toString ok {test-number} - ::Catch::Detail::stringify(v) == "{ }" for: "{ }" == "{ }" # vec> -> toString @@ -3818,5 +3874,5 @@ ok {test-number} - q3 == 23. for: 23.0 == 23.0 ok {test-number} - # xmlentitycheck ok {test-number} - -1..1905 +1..1933 diff --git a/tests/SelfTest/Baselines/teamcity.sw.approved.txt b/tests/SelfTest/Baselines/teamcity.sw.approved.txt index b73aa2e9..3f64f272 100644 --- a/tests/SelfTest/Baselines/teamcity.sw.approved.txt +++ b/tests/SelfTest/Baselines/teamcity.sw.approved.txt @@ -547,6 +547,8 @@ Exception.tests.cpp:|nunexpected exception with message:|n "For so ##teamcity[testStarted name='Unexpected exceptions can be translated'] Exception.tests.cpp:|nunexpected exception with message:|n "3.14"'] ##teamcity[testFinished name='Unexpected exceptions can be translated' duration="{duration}"] +##teamcity[testStarted name='Upcasting special member functions'] +##teamcity[testFinished name='Upcasting special member functions' duration="{duration}"] ##teamcity[testStarted name='Usage of the SizeIs range matcher'] ##teamcity[testFinished name='Usage of the SizeIs range matcher' duration="{duration}"] ##teamcity[testStarted name='Use a custom approx'] @@ -671,6 +673,8 @@ Misc.tests.cpp:|nexpression failed with message:|n "Testing if fib Misc.tests.cpp:|nexpression failed with message:|n "Testing if fib|[6|] (13) is even"|n CHECK( ( fib|[i|] % 2 ) == 0 )|nwith expansion:|n 1 == 0|n'] Misc.tests.cpp:|nexpression failed with message:|n "Testing if fib|[7|] (21) is even"|n CHECK( ( fib|[i|] % 2 ) == 0 )|nwith expansion:|n 1 == 0|n'] ##teamcity[testFinished name='looped tests' duration="{duration}"] +##teamcity[testStarted name='make_unique reimplementation'] +##teamcity[testFinished name='make_unique reimplementation' duration="{duration}"] ##teamcity[testStarted name='mean'] ##teamcity[testFinished name='mean' duration="{duration}"] ##teamcity[testStarted name='measure'] @@ -807,6 +811,8 @@ Exception.tests.cpp:|nunexpected exception with message:|n "Why wo ##teamcity[testFinished name='tuple,tuple<>,float>' duration="{duration}"] ##teamcity[testStarted name='uniform samples'] ##teamcity[testFinished name='uniform samples' duration="{duration}"] +##teamcity[testStarted name='unique_ptr reimplementation: basic functionality'] +##teamcity[testFinished name='unique_ptr reimplementation: basic functionality' duration="{duration}"] ##teamcity[testStarted name='vec> -> toString'] ##teamcity[testFinished name='vec> -> toString' duration="{duration}"] ##teamcity[testStarted name='vector -> toString'] diff --git a/tests/SelfTest/Baselines/xml.sw.approved.txt b/tests/SelfTest/Baselines/xml.sw.approved.txt index 10d7f304..45d444c1 100644 --- a/tests/SelfTest/Baselines/xml.sw.approved.txt +++ b/tests/SelfTest/Baselines/xml.sw.approved.txt @@ -13944,6 +13944,31 @@ There is no extra whitespace here + +
+ + + bptr->i == 3 + + + 3 == 3 + + + +
+
+ + + bptr->i == 3 + + + 3 == 3 + + + +
+ +
@@ -15773,6 +15798,42 @@ loose text artifact + +
+ + + !(lval.has_moved) + + + !false + + + +
+
+ + + rval.has_moved + + + true + + + +
+
+ + + *ptr == std::tuple<int, double, int>{1, 2., 3} + + + {?} == {?} + + + +
+ +
@@ -17416,6 +17477,220 @@ loose text artifact + +
+ + + !(ptr) + + + !{?} + + + + + ptr.get() == 0 + + + 0 == 0 + + + +
+
+ + + ptr + + + {?} + + + + + *ptr == 0 + + + 0 == 0 + + + + + ptr.get() == naked_ptr + + + 0x == 0x + + +
+ + + !(ptr) + + + !{?} + + + + + ptr.get() == 0 + + + 0 == 0 + + + +
+ +
+
+ + + ptr + + + {?} + + + + + *ptr == 0 + + + 0 == 0 + + + + + ptr.get() == naked_ptr + + + 0x == 0x + + +
+ + + ptr + + + {?} + + + + + ptr.get() != 0 + + + 0x != 0 + + + + + *ptr == 2 + + + 2 == 2 + + + +
+ +
+
+ + + !(ptr) + + + !{?} + + + + + ptr.get() == 0 + + + 0 == 0 + + + +
+
+ + + !(ptr1) + + + !{?} + + + + + ptr2 + + + {?} + + + + + *ptr2 == 1 + + + 1 == 1 + + + +
+
+ + + !(ptr2) + + + !{?} + + + + + ptr1 + + + {?} + + + + + *ptr1 == 2 + + + 2 == 2 + + + +
+
+ + + *ptr1 == 2 + + + 2 == 2 + + + + + *ptr2 == 1 + + + 1 == 1 + + + +
+ +
@@ -17756,7 +18031,7 @@ loose text artifact
- + - + diff --git a/tests/SelfTest/IntrospectiveTests/UniquePtr.tests.cpp b/tests/SelfTest/IntrospectiveTests/UniquePtr.tests.cpp new file mode 100644 index 00000000..bc7fe228 --- /dev/null +++ b/tests/SelfTest/IntrospectiveTests/UniquePtr.tests.cpp @@ -0,0 +1,133 @@ +#include +#include + +#include + +namespace { + struct unique_ptr_test_helper { + bool dummy = false; + }; +} // end unnamed namespace + +TEST_CASE("unique_ptr reimplementation: basic functionality", "[internals][unique-ptr]") { + using Catch::Detail::unique_ptr; + SECTION("Default constructed unique_ptr is empty") { + unique_ptr ptr; + REQUIRE_FALSE(ptr); + REQUIRE(ptr.get() == nullptr); + } + SECTION("Take ownership of allocation") { + auto naked_ptr = new int{ 0 }; + unique_ptr ptr(naked_ptr); + REQUIRE(ptr); + REQUIRE(*ptr == 0); + REQUIRE(ptr.get() == naked_ptr); + SECTION("Plain reset deallocates") { + ptr.reset(); // this makes naked_ptr dangling! + REQUIRE_FALSE(ptr); + REQUIRE(ptr.get() == nullptr); + } + SECTION("Reset replaces ownership") { + ptr.reset(new int{ 2 }); + REQUIRE(ptr); + REQUIRE(ptr.get() != nullptr); + REQUIRE(*ptr == 2); + } + } + SECTION("Release releases ownership") { + auto naked_ptr = new int{ 1 }; + unique_ptr ptr(naked_ptr); + ptr.release(); + CHECK_FALSE(ptr); + CHECK(ptr.get() == nullptr); + delete naked_ptr; + } + SECTION("Move constructor") { + unique_ptr ptr1(new int{ 1 }); + auto ptr2(std::move(ptr1)); + REQUIRE_FALSE(ptr1); + REQUIRE(ptr2); + REQUIRE(*ptr2 == 1); + } + SECTION("Move assignment") { + unique_ptr ptr1(new int{ 1 }), ptr2(new int{ 2 }); + ptr1 = std::move(ptr2); + REQUIRE_FALSE(ptr2); + REQUIRE(ptr1); + REQUIRE(*ptr1 == 2); + } + SECTION("free swap") { + unique_ptr ptr1(new int{ 1 }), ptr2(new int{ 2 }); + swap(ptr1, ptr2); + REQUIRE(*ptr1 == 2); + REQUIRE(*ptr2 == 1); + } +} + + +namespace { + struct base { + int i; + base(int i) :i(i) {} + }; + struct derived : base { using base::base; }; + struct unrelated {}; + +} // end unnamed namespace + +static_assert( std::is_constructible, + Catch::Detail::unique_ptr>::value, "Upcasting is supported"); +static_assert(!std::is_constructible, + Catch::Detail::unique_ptr>::value, "Downcasting is not supported"); +static_assert(!std::is_constructible, + Catch::Detail::unique_ptr>::value, "Cannot just convert one ptr type to another"); + +TEST_CASE("Upcasting special member functions", "[internals][unique-ptr]") { + using Catch::Detail::unique_ptr; + + unique_ptr dptr(new derived{3}); + SECTION("Move constructor") { + unique_ptr bptr(std::move(dptr)); + REQUIRE(bptr->i == 3); + } + SECTION("move assignment") { + unique_ptr bptr(new base{ 1 }); + bptr = std::move(dptr); + REQUIRE(bptr->i == 3); + } +} + +namespace { + struct move_detector { + bool has_moved = false; + move_detector() = default; + move_detector(move_detector const& rhs) = default; + move_detector& operator=(move_detector const& rhs) = default; + + move_detector(move_detector&& rhs) { + rhs.has_moved = true; + } + move_detector& operator=(move_detector&& rhs) { + rhs.has_moved = true; + return *this; + } + }; +} // end unnamed namespace + +TEST_CASE("make_unique reimplementation", "[internals][unique-ptr]") { + using Catch::Detail::make_unique; + SECTION("From lvalue copies") { + move_detector lval; + auto ptr = make_unique(lval); + REQUIRE_FALSE(lval.has_moved); + } + SECTION("From rvalue moves") { + move_detector rval; + auto ptr = make_unique(std::move(rval)); + REQUIRE(rval.has_moved); + } + SECTION("Variadic constructor") { + auto ptr = make_unique>(1, 2., 3); + REQUIRE(*ptr == std::tuple{1, 2., 3}); + } +}