From 440d47cae6431de3332ac934b6056a970cc1a0d7 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 26 Feb 2025 11:24:59 +0100 Subject: build: remove conan --- tests/CMakeLists.txt | 33 ++ tests/src/arithmetic.cpp | 297 ++++++++++ tests/src/constructors.cpp | 102 ++++ tests/src/conversion.cpp | 133 +++++ tests/src/derivation_clause.cpp | 63 +++ tests/src/equality_comparison.cpp | 102 ++++ tests/src/hash.cpp | 59 ++ tests/src/io_operators.cpp | 110 ++++ tests/src/iterable.cpp | 1060 ++++++++++++++++++++++++++++++++++++ tests/src/relational_operators.cpp | 249 +++++++++ tests/src/threeway_comparison.cpp | 52 ++ 11 files changed, 2260 insertions(+) create mode 100644 tests/CMakeLists.txt create mode 100644 tests/src/arithmetic.cpp create mode 100644 tests/src/constructors.cpp create mode 100644 tests/src/conversion.cpp create mode 100644 tests/src/derivation_clause.cpp create mode 100644 tests/src/equality_comparison.cpp create mode 100644 tests/src/hash.cpp create mode 100644 tests/src/io_operators.cpp create mode 100644 tests/src/iterable.cpp create mode 100644 tests/src/relational_operators.cpp create mode 100644 tests/src/threeway_comparison.cpp (limited to 'tests') diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..47b8331 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,33 @@ +find_package("Catch2" "3.1" + COMPONENTS "Catch2WithMain" + REQUIRED +) + +include("CTest") +include("Catch") + +file(GLOB SOURCES + RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" + CONFIGURE_DEPENDS + "src/*.cpp" +) + + +add_executable("${PROJECT_NAME}_tests" + ${SOURCES} +) + +target_link_libraries("${PROJECT_NAME}_tests" + "${PROJECT_NAME}::${PROJECT_NAME}" + "Catch2::Catch2WithMain" +) + +target_compile_options("${PROJECT_NAME}_tests" PRIVATE + "$<$:-Wall>" + "$<$:-Wextra>" + "$<$:-Werror>" + "$<$:-pedantic-errors>" + "$<$:-fconcepts-diagnostics-depth=5>" +) + +catch_discover_tests("${PROJECT_NAME}_tests") diff --git a/tests/src/arithmetic.cpp b/tests/src/arithmetic.cpp new file mode 100644 index 0000000..30c243f --- /dev/null +++ b/tests/src/arithmetic.cpp @@ -0,0 +1,297 @@ +#include "newtype/newtype.hpp" + +#include + +#include + +SCENARIO("Addition", "[arithmetic]") +{ + struct addable_type + { + auto constexpr operator+(addable_type const &) const -> addable_type + { + return {}; + }; + }; + + GIVEN("A new_type instance not deriving nt::Arithmetic") + { + using type_alias = nt::new_type; + + THEN("it is not addable") + { + STATIC_REQUIRE(!nt::concepts::addable); + } + } + + GIVEN("A new_type deriving nt::Arithmetic") + { + using type_alias = nt::new_type; + + THEN("it is addable") + { + STATIC_REQUIRE(nt::concepts::addable); + } + } + + GIVEN("A new_type over a non-addable class type deriving nt::Arithmetic") + { + using type_alias = nt::new_type; + + THEN("it is not addable") + { + STATIC_REQUIRE(!nt::concepts::addable == nt::concepts::addable); + } + } + + GIVEN("A new_type over an addable class type deriving nt::Arithmetic") + { + using type_alias = nt::new_type; + + THEN("it is addable") + { + STATIC_REQUIRE(nt::concepts::addable == nt::concepts::addable); + } + } + + GIVEN("A new_type deriving nt::Arithmetic") + { + using type_alias = nt::new_type; + + THEN("addition produces the same type") + { + STATIC_REQUIRE(std::is_same_v() + std::declval())>); + } + } + + GIVEN("Two objects of a new_type deriving nt::Arithmetic") + { + using type_alias = nt::new_type; + auto lhs = type_alias{24}; + auto rhs = type_alias{18}; + + THEN("addition produces the correct result with respect to the base type") + { + REQUIRE((lhs + rhs).decay() == 24 + 18); + } + } +} + +SCENARIO("Subtraction", "[arithmetic]") +{ + struct subtractable_type + { + auto constexpr operator-(subtractable_type const &) const -> subtractable_type + { + return {}; + }; + }; + + GIVEN("A new_type not deriving nt::arithmetic") + { + using type_alias = nt::new_type; + + THEN("it is not subtractable") + { + STATIC_REQUIRE(!nt::concepts::subtractable); + } + } + + GIVEN("A new_type deriving nt::Arithmetic") + { + using type_alias = nt::new_type; + + THEN("it is subtractable") + { + STATIC_REQUIRE(nt::concepts::subtractable); + } + } + + GIVEN("A new_type over a non-subtractable class type deriving nt::Arithmetic") + { + using type_alias = nt::new_type; + + THEN("it is not addable") + { + STATIC_REQUIRE(!nt::concepts::subtractable); + } + } + + GIVEN("A new_type over a subtractable class type deriving nt::Arithmetic") + { + using type_alias = nt::new_type; + + THEN("it is subtractable") + { + STATIC_REQUIRE(nt::concepts::subtractable); + } + } + + GIVEN("A new_type deriving nt::Arithmetic") + { + using type_alias = nt::new_type; + + THEN("subtraction produces the same type") + { + STATIC_REQUIRE(std::is_same_v() - std::declval())>); + } + } + + GIVEN("Two objects of a new_type deriving nt::Arithmetic") + { + using type_alias = nt::new_type; + auto lhs = type_alias{24}; + auto rhs = type_alias{18}; + + THEN("subtraction produces the correct result with respect to the base type") + { + REQUIRE((lhs - rhs).decay() == 24 - 18); + } + } +} + +SCENARIO("Multiplication", "[arithmetic]") +{ + struct multipliable_type + { + auto constexpr operator*(multipliable_type const &) const -> multipliable_type + { + return {}; + }; + }; + + GIVEN("A new_type not deriving nt::arithmetic") + { + using type_alias = nt::new_type; + + THEN("it is not multipliable") + { + STATIC_REQUIRE(!nt::concepts::multipliable); + } + } + + GIVEN("A new_type deriving nt::Arithmetic") + { + using type_alias = nt::new_type; + + THEN("it is multipliable") + { + STATIC_REQUIRE(nt::concepts::multipliable); + } + } + + GIVEN("A new_type over a non-multipliable class type deriving nt::Arithmetic") + { + using type_alias = nt::new_type; + + THEN("it is not multipliable") + { + STATIC_REQUIRE(!nt::concepts::multipliable); + } + } + + GIVEN("A new_type over a multipliable class type deriving nt::Arithmetic") + { + using type_alias = nt::new_type; + + THEN("it is multipliable") + { + STATIC_REQUIRE(nt::concepts::multipliable); + } + } + + GIVEN("A new_type deriving nt::Arithmetic") + { + using type_alias = nt::new_type; + + THEN("multiplication produces the same type") + { + STATIC_REQUIRE(std::is_same_v() * std::declval())>); + } + } + + GIVEN("Two objects of a new_type deriving nt::Arithmetic") + { + using type_alias = nt::new_type; + auto lhs = type_alias{24}; + auto rhs = type_alias{18}; + + THEN("multiplication produces the correct result with respect to the base type") + { + REQUIRE((lhs * rhs).decay() == 24 * 18); + } + } +} + +SCENARIO("Division", "[arithmetic]") +{ + struct dividable_type + { + auto constexpr operator/(dividable_type const &) const -> dividable_type + { + return {}; + }; + }; + + GIVEN("A new_type not deriving nt::arithmetic") + { + using type_alias = nt::new_type; + + THEN("it is not divisible") + { + STATIC_REQUIRE(!nt::concepts::divisible); + } + } + + GIVEN("A new_type deriving nt::Arithmetic") + { + using type_alias = nt::new_type; + + THEN("it is divisible") + { + STATIC_REQUIRE(nt::concepts::divisible); + } + } + + GIVEN("A new_type over a non-divisible class type deriving nt::Arithmetic") + { + using type_alias = nt::new_type; + + THEN("it is not divisible") + { + STATIC_REQUIRE(!nt::concepts::divisible); + } + } + + GIVEN("A new_type over a divisible class type deriving nt::Arithmetic") + { + using type_alias = nt::new_type; + + THEN("it is divisible") + { + STATIC_REQUIRE(nt::concepts::divisible); + } + } + + GIVEN("A new_type deriving nt::Arithmetic") + { + using type_alias = nt::new_type; + + THEN("division produces the same type") + { + STATIC_REQUIRE(std::is_same_v() / std::declval())>); + } + } + + GIVEN("Two objects of a new_type deriving nt::Arithmetic") + { + using type_alias = nt::new_type; + auto lhs = type_alias{30}; + auto rhs = type_alias{15}; + + THEN("division produces the correct result with respect to the base type") + { + REQUIRE((lhs / rhs).decay() == 30 / 15); + } + } +} diff --git a/tests/src/constructors.cpp b/tests/src/constructors.cpp new file mode 100644 index 0000000..b866f2e --- /dev/null +++ b/tests/src/constructors.cpp @@ -0,0 +1,102 @@ +#include "newtype/newtype.hpp" + +#include +#include + +#include + +using fundamental_types = std::tuple; + +TEMPLATE_LIST_TEST_CASE("Scenario: Construction from Fundamental Types", "[construction]", fundamental_types) +{ + GIVEN("A new_type over a fundamental type") + { + using type_alias = nt::new_type; + + THEN("objects of it can be constructed from the fundamental type") + { + STATIC_REQUIRE(std::is_constructible_v); + } + } +} + +SCENARIO("Default Construction", "[construction]") +{ + struct not_default_constructible + { + not_default_constructible() = delete; + }; + + GIVEN("A new_type over a default-constructible type") + { + using type_alias = nt::new_type; + static_assert(std::is_default_constructible_v); + + THEN("it is default-constructible") + { + STATIC_REQUIRE(std::is_default_constructible_v); + } + } + + GIVEN("A new_type over a type that is not default-constructible") + { + using type_alias = nt::new_type; + static_assert(!std::is_default_constructible_v); + + THEN("it is not default-constructible") + { + STATIC_REQUIRE_FALSE(std::is_default_constructible_v); + } + } +} + +SCENARIO("Copy Construction", "[construction]") +{ + struct not_copy_constructible + { + not_copy_constructible() = default; + not_copy_constructible(not_copy_constructible const &) = delete; + not_copy_constructible(not_copy_constructible &&) = default; + auto operator=(not_copy_constructible const &) -> not_copy_constructible & = default; + auto operator=(not_copy_constructible &&) -> not_copy_constructible & = default; + }; + + GIVEN("A new_type over a copy-constructible type") + { + using type_alias = nt::new_type; + static_assert(std::is_copy_constructible_v); + + THEN("it is copy-constructible") + { + STATIC_REQUIRE(std::is_copy_constructible_v); + } + } + + GIVEN("A new_type over a type that is not copy-constructible") + { + using type_alias = nt::new_type; + static_assert(!std::is_copy_constructible_v); + + THEN("it is not copy-constructible") + { + STATIC_REQUIRE_FALSE(std::is_copy_constructible_v); + } + } +} diff --git a/tests/src/conversion.cpp b/tests/src/conversion.cpp new file mode 100644 index 0000000..e7ce51c --- /dev/null +++ b/tests/src/conversion.cpp @@ -0,0 +1,133 @@ +#include "newtype/newtype.hpp" + +#include +#include +#include + +#include +#include +#include + +using test_types = std::tuple; + +TEMPLATE_LIST_TEST_CASE("Scenario: Implicit Conversions", "[conversion]", test_types) +{ + GIVEN("A new_type not deriving nt::ImplicitConversion") + { + using type_alias = nt::new_type; + + THEN("it is not implicitly convertible to the base type") + { + STATIC_REQUIRE(!std::is_convertible_v); + } + } + + GIVEN("A new_type deriving nt::ImplicitConversion") + { + using type_alias = nt::new_type; + + THEN("it is implicitly convertible to the base type") + { + STATIC_REQUIRE(std::is_convertible_v); + } + } +} + +TEMPLATE_LIST_TEST_CASE("Scenario: Decay", "[conversion]", test_types) +{ + GIVEN("Any new_type") + { + using type_alias = nt::new_type; + + THEN("it's decay() member function returns a value of the base type") + { + STATIC_REQUIRE(std::is_same_v().decay())>); + } + } + + GIVEN("Any new_type") + { + using type_alias = nt::new_type; + + WHEN("an object of that type is constructed") + { + auto integral_value = GENERATE(take(64, random(0, 127))); + auto value = [integral_value] { + if constexpr (std::is_same_v) + { + return std::to_string(integral_value); + } + else + { + return static_cast(integral_value); + } + }(); + auto obj = type_alias{value}; + + THEN("it's decay() member function return the underlying value") + { + REQUIRE(obj.decay() == value); + } + } + } +} + +SCENARIO("Nothrow Decay") +{ + struct strange_type + { + strange_type(strange_type const &) noexcept(false) + { + } + }; + + GIVEN("A new_type over a nothrow-copyable type") + { + using type_alias = nt::new_type; + + THEN("the decay member function is nothrow-invokable") + { + STATIC_REQUIRE(noexcept(std::declval().decay())); + } + } + + GIVEN("A new_type over a non-nothrow-copyable type") + { + using type_alias = nt::new_type; + + THEN("the decay member function is not nothrow-invokable") + { + STATIC_REQUIRE(!noexcept(std::declval().decay())); + } + } +} + +SCENARIO("Nothrow Conversion") +{ + struct strange_type + { + strange_type(strange_type const &) noexcept(false) + { + } + }; + + GIVEN("A new_type over a nothrow-copy-constructible type") + { + using type_alias = nt::new_type; + + THEN("the decay member function is nothrow-invokable") + { + STATIC_REQUIRE(noexcept(std::declval().operator int())); + } + } + + GIVEN("A new_type over a non-nothrow-copy-constructible type") + { + using type_alias = nt::new_type; + + THEN("the decay member function is not nothrow-invokable") + { + STATIC_REQUIRE(!noexcept(std::declval().operator strange_type())); + } + } +} diff --git a/tests/src/derivation_clause.cpp b/tests/src/derivation_clause.cpp new file mode 100644 index 0000000..78bd3d4 --- /dev/null +++ b/tests/src/derivation_clause.cpp @@ -0,0 +1,63 @@ +#include "newtype/newtype.hpp" + +#include + +#include + +SCENARIO("Derivation Clause", "[infrastructure]") +{ + GIVEN("An empty derivation clause") + { + auto clause = nt::deriving(); + + THEN("it doesn't contain any derivable") + { + STATIC_REQUIRE_FALSE(nt::derives); + } + } + + GIVEN("A derivation clause containing only nt::Show") + { + auto clause = deriving(nt::Show); + + THEN("it doesn't contain nt::EqBase") + { + STATIC_REQUIRE_FALSE(nt::derives); + } + + THEN("it contains nt::Show") + { + STATIC_REQUIRE(nt::derives); + } + } + + GIVEN("A derivation clause containing only nt::Show and nt::EqBase") + { + auto clause = deriving(nt::Show, nt::EqBase); + + THEN("it contains nt::EqBase") + { + STATIC_REQUIRE(nt::derives); + } + + THEN("it contains nt::Show") + { + STATIC_REQUIRE(nt::derives); + } + + THEN("it contains both nt::Show and nt::EqBase") + { + STATIC_REQUIRE(nt::derives); + } + + THEN("it does not contain nt::Arithmetic") + { + STATIC_REQUIRE_FALSE(nt::derives); + } + + THEN("it does not contain both nt::Arithmetic and nt::Show") + { + STATIC_REQUIRE_FALSE(nt::derives); + } + } +} diff --git a/tests/src/equality_comparison.cpp b/tests/src/equality_comparison.cpp new file mode 100644 index 0000000..e0be7f9 --- /dev/null +++ b/tests/src/equality_comparison.cpp @@ -0,0 +1,102 @@ +#include "newtype/newtype.hpp" + +#include + +#include +#include +#include + +SCENARIO("Equality Comparison", "[compare]") +{ + GIVEN("A new_type over an equality comparable type") + { + using type_alias = nt::new_type; + + THEN("two objects of it with the same value compare equal") + { + REQUIRE(type_alias{42} == type_alias{42}); + } + + THEN("two objects of it with the same value do not compare not-equal") + { + REQUIRE_FALSE(type_alias{42} != type_alias{42}); + } + + THEN("two object of it with different values do not compare equal") + { + REQUIRE_FALSE(type_alias{42} == type_alias{43}); + } + + THEN("two object of it with different values compare not-equal") + { + REQUIRE(type_alias{42} != type_alias{43}); + } + + THEN("equality comparison returns bool") + { + STATIC_REQUIRE(std::is_same_v() == std::declval())>); + } + + THEN("inequality comparison returns bool") + { + STATIC_REQUIRE(std::is_same_v() != std::declval())>); + } + } + + GIVEN("A new_type deriving nt::EqBase") + { + using type_alias = nt::new_type; + + THEN("an instance of it compares equal to the equivalent base type value") + { + REQUIRE(type_alias{42} == 42); + } + + THEN("an instance of it comapres not-equal to a different base type value") + { + REQUIRE(type_alias{42} != 43); + } + } + + GIVEN("A new_type over a nothrow-comparable type") + { + using type_alias = nt::new_type; + + static_assert(nt::concepts::nothrow_equality_comparable); + static_assert(nt::concepts::nothrow_inequality_comparable); + + THEN("it is nothrow-equality-comparable") + { + STATIC_REQUIRE(nt::concepts::nothrow_equality_comparable); + } + + THEN("it is nothrow-inequality-comparable") + { + STATIC_REQUIRE(nt::concepts::nothrow_inequality_comparable); + } + } + + GIVEN("A new_type over a non-nothrow-comparable type") + { + struct not_nothrow_comparable + { + auto operator==(not_nothrow_comparable) const noexcept(false) -> bool; + auto operator!=(not_nothrow_comparable) const noexcept(false) -> bool; + }; + + using type_alias = nt::new_type; + + static_assert(!nt::concepts::nothrow_equality_comparable); + static_assert(!nt::concepts::nothrow_inequality_comparable); + + THEN("it is not nothrow-equality-comparable") + { + STATIC_REQUIRE_FALSE(nt::concepts::nothrow_equality_comparable); + } + + THEN("it is not nothrow-inequality-comparable") + { + STATIC_REQUIRE_FALSE(noexcept(std::declval() != std::declval())); + } + } +} diff --git a/tests/src/hash.cpp b/tests/src/hash.cpp new file mode 100644 index 0000000..94f252f --- /dev/null +++ b/tests/src/hash.cpp @@ -0,0 +1,59 @@ +#include "newtype/newtype.hpp" + +#include +#include + +#include +#include + +TEMPLATE_TEST_CASE("Hash", "[hash]", std::string, int) +{ + GIVEN("A new_type not deriving nt::Hash") + { + using type_alias = nt::new_type; + static_assert(nt::concepts::hashable); + + THEN("it is not hashable") + { + STATIC_REQUIRE_FALSE(nt::concepts::hashable); + } + } + + GIVEN("A new_type over a hashable type deriving nt::Hash") + { + using type_alias = nt::new_type; + static_assert(nt::concepts::hashable); + + THEN("it is hashable") + { + STATIC_REQUIRE(nt::concepts::hashable); + } + } + + GIVEN("A new_type over a non-hashable type deriving nt::Hash") + { + struct non_hashable + { + }; + using type_alias = nt::new_type; + static_assert(!nt::concepts::hashable); + + THEN("it is not hashable") + { + STATIC_REQUIRE_FALSE(nt::concepts::hashable); + } + } + + GIVEN("A hashable new_type") + { + using type_alias = nt::new_type; + static_assert(nt::concepts::hashable); + + THEN("it can be used a the key in an unordered_map") + { + auto map = std::unordered_map{}; + map[type_alias{42}] = 43; + REQUIRE(map[type_alias{42}] == 43); + } + } +} diff --git a/tests/src/io_operators.cpp b/tests/src/io_operators.cpp new file mode 100644 index 0000000..f7f8f29 --- /dev/null +++ b/tests/src/io_operators.cpp @@ -0,0 +1,110 @@ +#include "newtype/newtype.hpp" + +#include + +#include +#include +#include +#include +#include + +inline namespace traits_extensions +{ + + template + struct has_stream_input : std::false_type + { + }; + + template + struct has_stream_input() >> std::declval())>> : std::true_type + { + }; + + template + auto constexpr has_stream_input_v = has_stream_input::value; + + template + struct has_stream_output : std::false_type + { + }; + + template + struct has_stream_output() << std::declval())>> : std::true_type + { + }; + + template + auto constexpr has_stream_output_v = has_stream_output::value; + +} // namespace traits_extensions + +SCENARIO("Stream Input") +{ + GIVEN("A new_type over a stream-inputtable type deriving nt::Read") + { + using type_alias = nt::new_type; + static_assert(has_stream_input_v); + + THEN("it has the stream input operator") + { + STATIC_REQUIRE(has_stream_input_v); + } + + THEN("an instance of it can be read from an std::istream") + { + auto obj = type_alias{}; + auto str = std::istringstream{"42"}; + + str >> obj; + + REQUIRE(obj.decay() == 42); + } + } + + GIVEN("A new_type over a non-stream-inputtable type deriving nt::Read") + { + using type_alias = nt::new_type; + static_assert(!has_stream_input_v); + + THEN("it does not have the input operator") + { + STATIC_REQUIRE(!has_stream_input_v); + } + } +} + +SCENARIO("Stream Output") +{ + GIVEN("A new_type over a stream-outputtable type deriving nt::Show") + { + using type_alias = nt::new_type; + static_assert(has_stream_output_v); + + THEN("it has the stream output operator") + { + STATIC_REQUIRE(has_stream_output_v); + } + + THEN("an instance of it can be written to an std::ostream") + { + auto obj = type_alias{42}; + auto str = std::ostringstream{}; + + str << obj; + + REQUIRE(str.str() == "42"); + } + } + + GIVEN("A new_type over a non-stream-outputtable type deriving nt::Show") + { + using type_alias = nt::new_type; + static_assert(!has_stream_output_v); + + THEN("it does not have the output operator") + { + STATIC_REQUIRE(!has_stream_output_v); + } + } +} diff --git a/tests/src/iterable.cpp b/tests/src/iterable.cpp new file mode 100644 index 0000000..85b7edc --- /dev/null +++ b/tests/src/iterable.cpp @@ -0,0 +1,1060 @@ +#include "newtype/newtype.hpp" + +#include + +#include +#include +#include +#include + +namespace iterable_types +{ + + struct with_member + { + using iterator = char *; + using const_iterator = char const *; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + auto constexpr begin() -> iterator; + auto constexpr begin() const -> const_iterator; + auto constexpr cbegin() const -> const_iterator; + auto constexpr rbegin() -> reverse_iterator; + auto constexpr rbegin() const -> const_reverse_iterator; + auto constexpr crbegin() const -> const_reverse_iterator; + + auto constexpr end() -> iterator; + auto constexpr end() const -> const_iterator; + auto constexpr cend() const -> const_iterator; + auto constexpr rend() -> reverse_iterator; + auto constexpr rend() const -> const_reverse_iterator; + auto constexpr crend() const -> const_reverse_iterator; + }; + + struct with_free + { + using iterator = char *; + using const_iterator = char const *; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + }; + + auto constexpr begin(with_free &) -> with_free::iterator; + auto constexpr begin(with_free const &) -> with_free::const_iterator; + auto constexpr cbegin(with_free const &) -> with_free::const_iterator; + auto constexpr rbegin(with_free &) -> with_free::reverse_iterator; + auto constexpr rbegin(with_free const &) -> with_free::const_reverse_iterator; + auto constexpr crbegin(with_free const &) -> with_free::const_reverse_iterator; + auto constexpr end(with_free &) -> with_free::iterator; + auto constexpr end(with_free const &) -> with_free::const_iterator; + auto constexpr cend(with_free const &) -> with_free::const_iterator; + auto constexpr rend(with_free &) -> with_free::reverse_iterator; + auto constexpr rend(with_free const &) -> with_free::const_reverse_iterator; + auto constexpr crend(with_free const &) -> with_free::const_reverse_iterator; + +} // namespace iterable_types + +SCENARIO("Iterators", "[iterators]") +{ + GIVEN("A new_type over a non-iterable base type not deriving nt::Iterable") + { + using type_alias = nt::new_type; + static_assert(!nt::concepts::beginnable); + static_assert(!nt::concepts::beginnable); + static_assert(!nt::concepts::cbeginnable); + static_assert(!nt::concepts::rbeginnable); + static_assert(!nt::concepts::rbeginnable); + static_assert(!nt::concepts::crbeginnable); + static_assert(!nt::concepts::endable); + static_assert(!nt::concepts::endable); + static_assert(!nt::concepts::cendable); + static_assert(!nt::concepts::rendable); + static_assert(!nt::concepts::rendable); + static_assert(!nt::concepts::crendable); + + THEN("it has no begin") + { + STATIC_REQUIRE_FALSE(nt::concepts::beginnable); + } + + THEN("it has no constant begin") + { + STATIC_REQUIRE_FALSE(nt::concepts::beginnable); + } + + THEN("it has no cbegin") + { + STATIC_REQUIRE_FALSE(nt::concepts::cbeginnable); + } + + THEN("it has no rbegin") + { + STATIC_REQUIRE_FALSE(nt::concepts::rbeginnable); + } + + THEN("it has no constant rbegin") + { + STATIC_REQUIRE_FALSE(nt::concepts::rbeginnable); + } + + THEN("it has no crbegin") + { + STATIC_REQUIRE_FALSE(nt::concepts::crbeginnable); + } + + THEN("it has no end") + { + STATIC_REQUIRE_FALSE(nt::concepts::endable); + } + + THEN("it has no constant end") + { + STATIC_REQUIRE_FALSE(nt::concepts::endable); + } + + THEN("it has no cend") + { + STATIC_REQUIRE_FALSE(nt::concepts::cendable); + } + + THEN("it has no rend") + { + STATIC_REQUIRE_FALSE(nt::concepts::rendable); + } + + THEN("it has no constant rend") + { + STATIC_REQUIRE_FALSE(nt::concepts::rendable); + } + + THEN("it has no crend") + { + STATIC_REQUIRE_FALSE(nt::concepts::crendable); + } + } + + GIVEN("A new_type over a non-iterable base type deriving nt::Iterable") + { + using type_alias = nt::new_type; + static_assert(!nt::concepts::beginnable); + static_assert(!nt::concepts::beginnable); + static_assert(!nt::concepts::cbeginnable); + static_assert(!nt::concepts::rbeginnable); + static_assert(!nt::concepts::rbeginnable); + static_assert(!nt::concepts::crbeginnable); + static_assert(!nt::concepts::endable); + static_assert(!nt::concepts::endable); + static_assert(!nt::concepts::cendable); + static_assert(!nt::concepts::rendable); + static_assert(!nt::concepts::rendable); + static_assert(!nt::concepts::crendable); + + THEN("it has no begin") + { + STATIC_REQUIRE_FALSE(nt::concepts::beginnable); + } + + THEN("it has no constant begin") + { + STATIC_REQUIRE_FALSE(nt::concepts::beginnable); + } + + THEN("it has no cbegin") + { + STATIC_REQUIRE_FALSE(nt::concepts::cbeginnable); + } + + THEN("it has no rbegin") + { + STATIC_REQUIRE_FALSE(nt::concepts::rbeginnable); + } + + THEN("it has no constant rbegin") + { + STATIC_REQUIRE_FALSE(nt::concepts::rbeginnable); + } + + THEN("it has no crbegin") + { + STATIC_REQUIRE_FALSE(nt::concepts::crbeginnable); + } + + THEN("it has no end") + { + STATIC_REQUIRE_FALSE(nt::concepts::endable); + } + + THEN("it has no constant end") + { + STATIC_REQUIRE_FALSE(nt::concepts::endable); + } + + THEN("it has no cend") + { + STATIC_REQUIRE_FALSE(nt::concepts::cendable); + } + + THEN("it has no rend") + { + STATIC_REQUIRE_FALSE(nt::concepts::rendable); + } + + THEN("it has no constant rend") + { + STATIC_REQUIRE_FALSE(nt::concepts::rendable); + } + + THEN("it has no crend") + { + STATIC_REQUIRE_FALSE(nt::concepts::crendable); + } + } + + GIVEN("A new_type over an iterable base type not deriving nt::Iterable") + { + using type_alias = nt::new_type, struct tag>; + static_assert(nt::concepts::beginnable); + static_assert(nt::concepts::const_beginnable); + static_assert(nt::concepts::cbeginnable); + static_assert(nt::concepts::rbeginnable); + static_assert(nt::concepts::const_rbeginnable); + static_assert(nt::concepts::crbeginnable); + static_assert(nt::concepts::endable); + static_assert(nt::concepts::const_endable); + static_assert(nt::concepts::cendable); + static_assert(nt::concepts::rendable); + static_assert(nt::concepts::const_rendable); + static_assert(nt::concepts::crendable); + + THEN("it has no begin") + { + STATIC_REQUIRE_FALSE(nt::concepts::beginnable); + } + + THEN("it has no constant begin") + { + STATIC_REQUIRE_FALSE(nt::concepts::beginnable); + } + + THEN("it has no cbegin") + { + STATIC_REQUIRE_FALSE(nt::concepts::cbeginnable); + } + + THEN("it has no rbegin") + { + STATIC_REQUIRE_FALSE(nt::concepts::rbeginnable); + } + + THEN("it has no constant rbegin") + { + STATIC_REQUIRE_FALSE(nt::concepts::rbeginnable); + } + + THEN("it has no crbegin") + { + STATIC_REQUIRE_FALSE(nt::concepts::crbeginnable); + } + + THEN("it has no end") + { + STATIC_REQUIRE_FALSE(nt::concepts::endable); + } + + THEN("it has no constant end") + { + STATIC_REQUIRE_FALSE(nt::concepts::endable); + } + + THEN("it has no cend") + { + STATIC_REQUIRE_FALSE(nt::concepts::cendable); + } + + THEN("it has no rend") + { + STATIC_REQUIRE_FALSE(nt::concepts::rendable); + } + + THEN("it has no constant rend") + { + STATIC_REQUIRE_FALSE(nt::concepts::rendable); + } + + THEN("it has no crend") + { + STATIC_REQUIRE_FALSE(nt::concepts::crendable); + } + } + + GIVEN("A new_type over an iterable base type deriving nt::Iterable") + { + using type_alias = nt::new_type, struct tag, deriving(nt::Iterable)>; + static_assert(nt::concepts::beginnable); + static_assert(nt::concepts::const_beginnable); + static_assert(nt::concepts::cbeginnable); + static_assert(nt::concepts::rbeginnable); + static_assert(nt::concepts::const_rbeginnable); + static_assert(nt::concepts::crbeginnable); + static_assert(nt::concepts::endable); + static_assert(nt::concepts::const_endable); + static_assert(nt::concepts::cendable); + static_assert(nt::concepts::rendable); + static_assert(nt::concepts::const_rendable); + static_assert(nt::concepts::crendable); + + THEN("it has begin") + { + STATIC_REQUIRE(nt::concepts::beginnable); + } + + THEN("it has constant begin") + { + STATIC_REQUIRE(nt::concepts::const_beginnable); + } + + THEN("it has cbegin") + { + STATIC_REQUIRE(nt::concepts::cbeginnable); + } + + THEN("it has rbegin") + { + STATIC_REQUIRE(nt::concepts::rbeginnable); + } + + THEN("it has constant rbegin") + { + STATIC_REQUIRE(nt::concepts::const_rbeginnable); + } + + THEN("it has crbegin") + { + STATIC_REQUIRE(nt::concepts::crbeginnable); + } + + THEN("it has end") + { + STATIC_REQUIRE(nt::concepts::endable); + } + + THEN("it has constant end") + { + STATIC_REQUIRE(nt::concepts::const_endable); + } + + THEN("it has cend") + { + STATIC_REQUIRE(nt::concepts::cendable); + } + + THEN("it has rend") + { + STATIC_REQUIRE(nt::concepts::rendable); + } + + THEN("it has constant rend") + { + STATIC_REQUIRE(nt::concepts::const_rendable); + } + + THEN("it has crend") + { + STATIC_REQUIRE(nt::concepts::crendable); + } + } +} + +SCENARIO("Iterators (member)", "[iterators]") +{ + GIVEN("A new_type over a non-iterable base type not deriving nt::Iterable") + { + using type_alias = nt::new_type; + static_assert(!nt::concepts::member_begin); + static_assert(!nt::concepts::const_member_begin); + static_assert(!nt::concepts::member_cbegin); + static_assert(!nt::concepts::member_rbegin); + static_assert(!nt::concepts::const_member_rbegin); + static_assert(!nt::concepts::member_crbegin); + static_assert(!nt::concepts::member_end); + static_assert(!nt::concepts::const_member_end); + static_assert(!nt::concepts::member_cend); + static_assert(!nt::concepts::member_rend); + static_assert(!nt::concepts::const_member_rend); + static_assert(!nt::concepts::member_crend); + + THEN("it has no member begin") + { + STATIC_REQUIRE_FALSE(nt::concepts::member_begin); + } + + THEN("it has no member constant begin") + { + STATIC_REQUIRE_FALSE(nt::concepts::member_begin); + } + + THEN("it has no member cbegin") + { + STATIC_REQUIRE_FALSE(nt::concepts::member_cbegin); + } + + THEN("it has no member rbegin") + { + STATIC_REQUIRE_FALSE(nt::concepts::member_rbegin); + } + + THEN("it has no member constant rbegin") + { + STATIC_REQUIRE_FALSE(nt::concepts::member_rbegin); + } + + THEN("it has no member crbegin") + { + STATIC_REQUIRE_FALSE(nt::concepts::member_crbegin); + } + + THEN("it has no member end") + { + STATIC_REQUIRE_FALSE(nt::concepts::member_end); + } + + THEN("it has no member constant end") + { + STATIC_REQUIRE_FALSE(nt::concepts::member_end); + } + + THEN("it has no member cend") + { + STATIC_REQUIRE_FALSE(nt::concepts::member_cend); + } + + THEN("it has no member rend") + { + STATIC_REQUIRE_FALSE(nt::concepts::member_rend); + } + + THEN("it has no member constant rend") + { + STATIC_REQUIRE_FALSE(nt::concepts::member_rend); + } + + THEN("it has no member crend") + { + STATIC_REQUIRE_FALSE(nt::concepts::member_crend); + } + } + + GIVEN("A new_type over a non-iterable base type deriving nt::Iterable") + { + using type_alias = nt::new_type; + static_assert(!nt::concepts::member_begin); + static_assert(!nt::concepts::const_member_begin); + static_assert(!nt::concepts::member_cbegin); + static_assert(!nt::concepts::member_rbegin); + static_assert(!nt::concepts::const_member_rbegin); + static_assert(!nt::concepts::member_crbegin); + static_assert(!nt::concepts::member_end); + static_assert(!nt::concepts::const_member_end); + static_assert(!nt::concepts::member_cend); + static_assert(!nt::concepts::member_rend); + static_assert(!nt::concepts::const_member_rend); + static_assert(!nt::concepts::member_crend); + + THEN("it has no member begin") + { + STATIC_REQUIRE_FALSE(nt::concepts::member_begin); + } + + THEN("it has no member constant begin") + { + STATIC_REQUIRE_FALSE(nt::concepts::member_begin); + } + + THEN("it has no member cbegin") + { + STATIC_REQUIRE_FALSE(nt::concepts::member_cbegin); + } + + THEN("it has no member rbegin") + { + STATIC_REQUIRE_FALSE(nt::concepts::member_rbegin); + } + + THEN("it has no member constant rbegin") + { + STATIC_REQUIRE_FALSE(nt::concepts::member_rbegin); + } + + THEN("it has no member crbegin") + { + STATIC_REQUIRE_FALSE(nt::concepts::member_crbegin); + } + + THEN("it has no member end") + { + STATIC_REQUIRE_FALSE(nt::concepts::member_end); + } + + THEN("it has no member constant end") + { + STATIC_REQUIRE_FALSE(nt::concepts::member_end); + } + + THEN("it has no member cend") + { + STATIC_REQUIRE_FALSE(nt::concepts::member_cend); + } + + THEN("it has no member rend") + { + STATIC_REQUIRE_FALSE(nt::concepts::member_rend); + } + + THEN("it has no member constant rend") + { + STATIC_REQUIRE_FALSE(nt::concepts::member_rend); + } + + THEN("it has no member crend") + { + STATIC_REQUIRE_FALSE(nt::concepts::member_crend); + } + } + + GIVEN("A new_type over an iterable base type not deriving nt::Iterable") + { + using type_alias = nt::new_type, struct tag>; + static_assert(nt::concepts::member_begin); + static_assert(nt::concepts::const_member_begin); + static_assert(nt::concepts::member_cbegin); + static_assert(nt::concepts::member_rbegin); + static_assert(nt::concepts::const_member_rbegin); + static_assert(nt::concepts::member_crbegin); + static_assert(nt::concepts::member_end); + static_assert(nt::concepts::const_member_end); + static_assert(nt::concepts::member_cend); + static_assert(nt::concepts::member_rend); + static_assert(nt::concepts::const_member_rend); + static_assert(nt::concepts::member_crend); + + THEN("it has no member begin") + { + STATIC_REQUIRE_FALSE(nt::concepts::member_begin); + } + + THEN("it has no member constant begin") + { + STATIC_REQUIRE_FALSE(nt::concepts::member_begin); + } + + THEN("it has no member cbegin") + { + STATIC_REQUIRE_FALSE(nt::concepts::member_cbegin); + } + + THEN("it has no member rbegin") + { + STATIC_REQUIRE_FALSE(nt::concepts::member_rbegin); + } + + THEN("it has no member constant rbegin") + { + STATIC_REQUIRE_FALSE(nt::concepts::member_rbegin); + } + + THEN("it has no member crbegin") + { + STATIC_REQUIRE_FALSE(nt::concepts::member_crbegin); + } + + THEN("it has no member end") + { + STATIC_REQUIRE_FALSE(nt::concepts::member_end); + } + + THEN("it has no member constant end") + { + STATIC_REQUIRE_FALSE(nt::concepts::member_end); + } + + THEN("it has no member cend") + { + STATIC_REQUIRE_FALSE(nt::concepts::member_cend); + } + + THEN("it has no member rend") + { + STATIC_REQUIRE_FALSE(nt::concepts::member_rend); + } + + THEN("it has no member constant rend") + { + STATIC_REQUIRE_FALSE(nt::concepts::member_rend); + } + + THEN("it has no member crend") + { + STATIC_REQUIRE_FALSE(nt::concepts::member_crend); + } + } + + GIVEN("A new_type over an iterable base type deriving nt::Iterable") + { + using type_alias = nt::new_type, struct tag, deriving(nt::Iterable)>; + static_assert(nt::concepts::member_begin); + static_assert(nt::concepts::const_member_begin); + static_assert(nt::concepts::member_cbegin); + static_assert(nt::concepts::member_rbegin); + static_assert(nt::concepts::const_member_rbegin); + static_assert(nt::concepts::member_crbegin); + static_assert(nt::concepts::member_end); + static_assert(nt::concepts::const_member_end); + static_assert(nt::concepts::member_cend); + static_assert(nt::concepts::member_rend); + static_assert(nt::concepts::const_member_rend); + static_assert(nt::concepts::member_crend); + + THEN("it has member begin") + { + STATIC_REQUIRE(nt::concepts::member_begin); + } + + THEN("it has member constant begin") + { + STATIC_REQUIRE(nt::concepts::const_member_begin); + } + + THEN("it has member cbegin") + { + STATIC_REQUIRE(nt::concepts::member_cbegin); + } + + THEN("it has member rbegin") + { + STATIC_REQUIRE(nt::concepts::member_rbegin); + } + + THEN("it has member constant rbegin") + { + STATIC_REQUIRE(nt::concepts::const_member_rbegin); + } + + THEN("it has member crbegin") + { + STATIC_REQUIRE(nt::concepts::member_crbegin); + } + + THEN("it has member end") + { + STATIC_REQUIRE(nt::concepts::member_end); + } + + THEN("it has member constant end") + { + STATIC_REQUIRE(nt::concepts::const_member_end); + } + + THEN("it has member cend") + { + STATIC_REQUIRE(nt::concepts::member_cend); + } + + THEN("it has member rend") + { + STATIC_REQUIRE(nt::concepts::member_rend); + } + + THEN("it has member constant rend") + { + STATIC_REQUIRE(nt::concepts::const_member_rend); + } + + THEN("it has member crend") + { + STATIC_REQUIRE(nt::concepts::member_crend); + } + } +} + +SCENARIO("Iterators (free)", "[iterators]") +{ + GIVEN("A new_type over a non-iterable base type not deriving nt::Iterable") + { + using type_alias = nt::new_type; + static_assert(!nt::concepts::free_begin); + static_assert(!nt::concepts::const_free_begin); + static_assert(!nt::concepts::free_cbegin); + static_assert(!nt::concepts::free_rbegin); + static_assert(!nt::concepts::const_free_rbegin); + static_assert(!nt::concepts::free_crbegin); + static_assert(!nt::concepts::free_end); + static_assert(!nt::concepts::const_free_end); + static_assert(!nt::concepts::free_cend); + static_assert(!nt::concepts::free_rend); + static_assert(!nt::concepts::const_free_rend); + static_assert(!nt::concepts::free_crend); + + THEN("it has no free begin") + { + STATIC_REQUIRE_FALSE(nt::concepts::free_begin); + } + + THEN("it has no free constant begin") + { + STATIC_REQUIRE_FALSE(nt::concepts::const_free_begin); + } + + THEN("it has no free cbegin") + { + STATIC_REQUIRE_FALSE(nt::concepts::free_cbegin); + } + + THEN("it has no free rbegin") + { + STATIC_REQUIRE_FALSE(nt::concepts::free_rbegin); + } + + THEN("it has no free constant rbegin") + { + STATIC_REQUIRE_FALSE(nt::concepts::const_free_rbegin); + } + + THEN("it has no free crbegin") + { + STATIC_REQUIRE_FALSE(nt::concepts::free_crbegin); + } + + THEN("it has no free end") + { + STATIC_REQUIRE_FALSE(nt::concepts::free_end); + } + + THEN("it has no free constant end") + { + STATIC_REQUIRE_FALSE(nt::concepts::const_free_end); + } + + THEN("it has no free cend") + { + STATIC_REQUIRE_FALSE(nt::concepts::free_cend); + } + + THEN("it has no free rend") + { + STATIC_REQUIRE_FALSE(nt::concepts::free_rend); + } + + THEN("it has no free constant rend") + { + STATIC_REQUIRE_FALSE(nt::concepts::const_free_rend); + } + + THEN("it has no free crend") + { + STATIC_REQUIRE_FALSE(nt::concepts::free_crend); + } + } + + GIVEN("A new_type over a non-iterable base type deriving nt::Iterable") + { + using type_alias = nt::new_type; + static_assert(!nt::concepts::free_begin); + static_assert(!nt::concepts::const_free_begin); + static_assert(!nt::concepts::free_cbegin); + static_assert(!nt::concepts::free_rbegin); + static_assert(!nt::concepts::const_free_rbegin); + static_assert(!nt::concepts::free_crbegin); + static_assert(!nt::concepts::free_end); + static_assert(!nt::concepts::const_free_end); + static_assert(!nt::concepts::free_cend); + static_assert(!nt::concepts::free_rend); + static_assert(!nt::concepts::const_free_rend); + static_assert(!nt::concepts::free_crend); + + THEN("it has no free begin") + { + STATIC_REQUIRE_FALSE(nt::concepts::free_begin); + } + + THEN("it has no free constant begin") + { + STATIC_REQUIRE_FALSE(nt::concepts::const_free_begin); + } + + THEN("it has no free cbegin") + { + STATIC_REQUIRE_FALSE(nt::concepts::free_cbegin); + } + + THEN("it has no free rbegin") + { + STATIC_REQUIRE_FALSE(nt::concepts::free_rbegin); + } + + THEN("it has no free constant rbegin") + { + STATIC_REQUIRE_FALSE(nt::concepts::const_free_rbegin); + } + + THEN("it has no free crbegin") + { + STATIC_REQUIRE_FALSE(nt::concepts::free_crbegin); + } + + THEN("it has no free end") + { + STATIC_REQUIRE_FALSE(nt::concepts::free_end); + } + + THEN("it has no free constant end") + { + STATIC_REQUIRE_FALSE(nt::concepts::const_free_end); + } + + THEN("it has no free cend") + { + STATIC_REQUIRE_FALSE(nt::concepts::free_cend); + } + + THEN("it has no free rend") + { + STATIC_REQUIRE_FALSE(nt::concepts::free_rend); + } + + THEN("it has no free constant rend") + { + STATIC_REQUIRE_FALSE(nt::concepts::const_free_rend); + } + + THEN("it has no free crend") + { + STATIC_REQUIRE_FALSE(nt::concepts::free_crend); + } + } + + GIVEN("A new_type over an iterable base type not deriving nt::Iterable") + { + using type_alias = nt::new_type, struct tag>; + static_assert(nt::concepts::free_begin); + static_assert(nt::concepts::const_free_begin); + static_assert(nt::concepts::free_cbegin); + static_assert(nt::concepts::free_rbegin); + static_assert(nt::concepts::const_free_rbegin); + static_assert(nt::concepts::free_crbegin); + static_assert(nt::concepts::free_end); + static_assert(nt::concepts::const_free_end); + static_assert(nt::concepts::free_cend); + static_assert(nt::concepts::free_rend); + static_assert(nt::concepts::const_free_rend); + static_assert(nt::concepts::free_crend); + + THEN("it has no free begin") + { + STATIC_REQUIRE_FALSE(nt::concepts::free_begin); + } + + THEN("it has no free constant begin") + { + STATIC_REQUIRE_FALSE(nt::concepts::free_begin); + } + + THEN("it has no free cbegin") + { + STATIC_REQUIRE_FALSE(nt::concepts::free_cbegin); + } + + THEN("it has no free rbegin") + { + STATIC_REQUIRE_FALSE(nt::concepts::free_rbegin); + } + + THEN("it has no free constant rbegin") + { + STATIC_REQUIRE_FALSE(nt::concepts::free_rbegin); + } + + THEN("it has no free crbegin") + { + STATIC_REQUIRE_FALSE(nt::concepts::free_crbegin); + } + + THEN("it has no free end") + { + STATIC_REQUIRE_FALSE(nt::concepts::free_end); + } + + THEN("it has no free constant end") + { + STATIC_REQUIRE_FALSE(nt::concepts::free_end); + } + + THEN("it has no free cend") + { + STATIC_REQUIRE_FALSE(nt::concepts::free_cend); + } + + THEN("it has no free rend") + { + STATIC_REQUIRE_FALSE(nt::concepts::free_rend); + } + + THEN("it has no free constant rend") + { + STATIC_REQUIRE_FALSE(nt::concepts::free_rend); + } + + THEN("it has no free crend") + { + STATIC_REQUIRE_FALSE(nt::concepts::free_crend); + } + } + + GIVEN("A new_type over an iterable base type deriving nt::Iterable") + { + using type_alias = nt::new_type, struct tag, deriving(nt::Iterable)>; + static_assert(nt::concepts::free_begin); + static_assert(nt::concepts::const_free_begin); + static_assert(nt::concepts::free_cbegin); + static_assert(nt::concepts::free_rbegin); + static_assert(nt::concepts::const_free_rbegin); + static_assert(nt::concepts::free_crbegin); + static_assert(nt::concepts::free_end); + static_assert(nt::concepts::const_free_end); + static_assert(nt::concepts::free_cend); + static_assert(nt::concepts::free_rend); + static_assert(nt::concepts::const_free_rend); + static_assert(nt::concepts::free_crend); + + THEN("it has free begin") + { + STATIC_REQUIRE(nt::concepts::free_begin); + } + + THEN("it has free constant begin") + { + STATIC_REQUIRE(nt::concepts::const_free_begin); + } + + THEN("it has free cbegin") + { + STATIC_REQUIRE(nt::concepts::free_cbegin); + } + + THEN("it has free rbegin") + { + STATIC_REQUIRE(nt::concepts::free_rbegin); + } + + THEN("it has free constant rbegin") + { + STATIC_REQUIRE(nt::concepts::const_free_rbegin); + } + + THEN("it has free crbegin") + { + STATIC_REQUIRE(nt::concepts::free_crbegin); + } + + THEN("it has free end") + { + STATIC_REQUIRE(nt::concepts::free_end); + } + + THEN("it has free constant end") + { + STATIC_REQUIRE(nt::concepts::const_free_end); + } + + THEN("it has free cend") + { + STATIC_REQUIRE(nt::concepts::free_cend); + } + + THEN("it has free rend") + { + STATIC_REQUIRE(nt::concepts::free_rend); + } + + THEN("it has free constant rend") + { + STATIC_REQUIRE(nt::concepts::const_free_rend); + } + + THEN("it has free crend") + { + STATIC_REQUIRE(nt::concepts::free_crend); + } + } +} + +SCENARIO("Iterator Semantics", "[iterators]") +{ + GIVEN("An iterable new_type") + { + using type_alias = nt::new_type, struct tag, deriving(nt::Iterable)>; + + THEN("a non-const object can be used in value range-based for") + { + auto obj = type_alias{{1, 2, 3}}; + auto res = 0; + for (auto e : obj) + { + res += e; + } + REQUIRE(res == 6); + } + + THEN("a const object can be used in value range-based for") + { + auto const obj = type_alias{{1, 2, 3}}; + auto res = 0; + for (auto e : obj) + { + res += e; + } + REQUIRE(res == 6); + } + + THEN("a non-const object can be used in reference range-based for") + { + auto obj = type_alias{{1, 2, 3}}; + auto res = 0; + for (auto & e : obj) + { + res += e; + } + REQUIRE(res == 6); + } + + THEN("a const object can be used in const-reference range-based for") + { + auto const obj = type_alias{{1, 2, 3}}; + auto res = 0; + for (auto const & e : obj) + { + res += e; + } + REQUIRE(res == 6); + } + + THEN("using an instance of it in an STL algorithm yields the same results as using an instance of the base type") + { + auto const base_obj = type_alias::base_type{{1, 2, 3}}; + auto const nt_obj = type_alias{base_obj}; + + auto base_res = std::accumulate(begin(base_obj), end(base_obj), 0); + auto nt_res = std::accumulate(begin(nt_obj), end(nt_obj), 0); + + REQUIRE(nt_res == base_res); + } + + THEN("iterating over an instance yields the same elements in the same order as iterating over an instance of the base type") + { + auto const base_obj = type_alias::base_type{{1, 2, 3}}; + auto const nt_obj = type_alias{base_obj}; + + REQUIRE(std::equal(cbegin(nt_obj), cend(nt_obj), cbegin(base_obj), cend(base_obj))); + } + } +} diff --git a/tests/src/relational_operators.cpp b/tests/src/relational_operators.cpp new file mode 100644 index 0000000..e852957 --- /dev/null +++ b/tests/src/relational_operators.cpp @@ -0,0 +1,249 @@ +#include "newtype/newtype.hpp" + +#include + +#include +#include +#include +#include + +SCENARIO("Relational Operator Availability") +{ + GIVEN("A new_type over a relationally comparable type not deriving nt::Relational") + { + using type_alias = nt::new_type; + static_assert(nt::concepts::less_than_comparable); + static_assert(nt::concepts::less_than_equal_comparable); + static_assert(nt::concepts::greater_than_comparable); + static_assert(nt::concepts::greater_than_equal_comparable); + + THEN("it does not have <") + { + STATIC_REQUIRE_FALSE(nt::concepts::less_than_comparable); + } + + THEN("it does not have <=") + { + STATIC_REQUIRE_FALSE(nt::concepts::less_than_equal_comparable); + } + + THEN("it does not have >") + { + STATIC_REQUIRE_FALSE(nt::concepts::greater_than_comparable); + } + + THEN("it does not have >=") + { + STATIC_REQUIRE_FALSE(nt::concepts::greater_than_equal_comparable); + } + } + + GIVEN("A new_type over a relationally comparable type deriving nt::Relational") + { + using type_alias = nt::new_type; + static_assert(nt::concepts::less_than_comparable); + static_assert(nt::concepts::less_than_equal_comparable); + static_assert(nt::concepts::greater_than_comparable); + static_assert(nt::concepts::greater_than_equal_comparable); + + THEN("it does have <") + { + STATIC_REQUIRE(nt::concepts::less_than_comparable); + } + + THEN("it does have <=") + { + STATIC_REQUIRE(nt::concepts::less_than_equal_comparable); + } + + THEN("it does have >") + { + STATIC_REQUIRE(nt::concepts::greater_than_comparable); + } + + THEN("it does have >=") + { + STATIC_REQUIRE(nt::concepts::greater_than_equal_comparable); + } + } + + GIVEN("A new_type over a type that is not relationally comparable not deriving nt::Relational") + { + using type_alias = nt::new_type; + static_assert(!nt::concepts::less_than_comparable); + static_assert(!nt::concepts::less_than_equal_comparable); + static_assert(!nt::concepts::greater_than_comparable); + static_assert(!nt::concepts::greater_than_equal_comparable); + + THEN("it does not have <") + { + STATIC_REQUIRE_FALSE(nt::concepts::less_than_comparable); + } + + THEN("it does not have <=") + { + STATIC_REQUIRE_FALSE(nt::concepts::less_than_equal_comparable); + } + + THEN("it does not have >") + { + STATIC_REQUIRE_FALSE(nt::concepts::greater_than_comparable); + } + + THEN("it does not have >=") + { + STATIC_REQUIRE_FALSE(nt::concepts::greater_than_equal_comparable); + } + } + + GIVEN("A new_type over a type that is not relationally comparable deriving nt::Relational") + { + using type_alias = nt::new_type; + static_assert(!nt::concepts::less_than_comparable); + static_assert(!nt::concepts: