diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 313d57e3..98f2ffd8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -61,6 +61,7 @@ set(INTERNAL_HEADERS ${SOURCES_DIR}/internal/catch_clara.hpp ${SOURCES_DIR}/internal/catch_commandline.hpp ${SOURCES_DIR}/internal/catch_source_line_info.hpp + ${SOURCES_DIR}/internal/catch_compare_traits.hpp ${SOURCES_DIR}/internal/catch_compiler_capabilities.hpp ${SOURCES_DIR}/catch_config.hpp ${SOURCES_DIR}/internal/catch_config_android_logwrite.hpp diff --git a/src/catch2/catch_all.hpp b/src/catch2/catch_all.hpp index 9c5241be..1fc49abf 100644 --- a/src/catch2/catch_all.hpp +++ b/src/catch2/catch_all.hpp @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include diff --git a/src/catch2/internal/catch_compare_traits.hpp b/src/catch2/internal/catch_compare_traits.hpp new file mode 100644 index 00000000..381dba89 --- /dev/null +++ b/src/catch2/internal/catch_compare_traits.hpp @@ -0,0 +1,47 @@ + +// Copyright Catch2 Authors +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.txt or copy at +// https://www.boost.org/LICENSE_1_0.txt) + +// SPDX-License-Identifier: BSL-1.0 +#ifndef CATCH_COMPARE_TRAITS_HPP_INCLUDED +#define CATCH_COMPARE_TRAITS_HPP_INCLUDED + +#include + +#include + +namespace Catch { + namespace Detail { + +#define CATCH_DEFINE_COMPARABLE_TRAIT( id, op ) \ + template \ + struct is_##id##_comparable : std::false_type {}; \ + template \ + struct is_##id##_comparable< \ + T, \ + U, \ + void_t() op std::declval() )>> \ + : std::true_type {}; \ + template \ + struct is_##id##_0_comparable : std::false_type {}; \ + template \ + struct is_##id##_0_comparable() op 0 )>> \ + : std::true_type {}; + + // We need all 6 pre-spaceship comparison ops: <, <=, >, >=, ==, != + CATCH_DEFINE_COMPARABLE_TRAIT( lt, < ) + CATCH_DEFINE_COMPARABLE_TRAIT( le, <= ) + CATCH_DEFINE_COMPARABLE_TRAIT( gt, > ) + CATCH_DEFINE_COMPARABLE_TRAIT( ge, >= ) + CATCH_DEFINE_COMPARABLE_TRAIT( eq, == ) + CATCH_DEFINE_COMPARABLE_TRAIT( ne, != ) + +#undef CATCH_DEFINE_COMPARABLE_TRAIT + + } // namespace Detail +} // namespace Catch + +#endif // CATCH_COMPARE_TRAITS_HPP_INCLUDED diff --git a/src/catch2/meson.build b/src/catch2/meson.build index 5af841ce..1083897d 100644 --- a/src/catch2/meson.build +++ b/src/catch2/meson.build @@ -72,6 +72,7 @@ internal_headers = [ 'internal/catch_case_sensitive.hpp', 'internal/catch_clara.hpp', 'internal/catch_commandline.hpp', + 'internal/catch_compare_traits.hpp', 'internal/catch_compiler_capabilities.hpp', 'internal/catch_config_android_logwrite.hpp', 'internal/catch_config_counter.hpp', diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 46d62428..c6f93d96 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -99,6 +99,7 @@ set(TEST_SOURCES ${SELF_TEST_DIR}/IntrospectiveTests/String.tests.cpp ${SELF_TEST_DIR}/IntrospectiveTests/StringManip.tests.cpp ${SELF_TEST_DIR}/IntrospectiveTests/Xml.tests.cpp + ${SELF_TEST_DIR}/IntrospectiveTests/Traits.tests.cpp ${SELF_TEST_DIR}/IntrospectiveTests/ToString.tests.cpp ${SELF_TEST_DIR}/IntrospectiveTests/UniquePtr.tests.cpp ${SELF_TEST_DIR}/helpers/parse_test_spec.cpp diff --git a/tests/SelfTest/IntrospectiveTests/Traits.tests.cpp b/tests/SelfTest/IntrospectiveTests/Traits.tests.cpp new file mode 100644 index 00000000..35d30c76 --- /dev/null +++ b/tests/SelfTest/IntrospectiveTests/Traits.tests.cpp @@ -0,0 +1,74 @@ + +// Copyright Catch2 Authors +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.txt or copy at +// https://www.boost.org/LICENSE_1_0.txt) + +// SPDX-License-Identifier: BSL-1.0 + +#include +#include + +// Should only be constructible from literal 0. +// Used by `TypeWithLit0Comparisons` for testing comparison +// ops that only work with literal zero, the way std::*orderings do +struct ZeroLiteralDetector { + constexpr ZeroLiteralDetector( ZeroLiteralDetector* ) noexcept {} + + template ::value>> + constexpr ZeroLiteralDetector( T ) = delete; +}; + +struct TypeWithLit0Comparisons { +#define DEFINE_COMP_OP( op ) \ + friend bool operator op( TypeWithLit0Comparisons, ZeroLiteralDetector ) { \ + return true; \ + } \ + friend bool operator op( ZeroLiteralDetector, TypeWithLit0Comparisons ) { \ + return false; \ + } + + DEFINE_COMP_OP( < ) + DEFINE_COMP_OP( <= ) + DEFINE_COMP_OP( > ) + DEFINE_COMP_OP( >= ) + DEFINE_COMP_OP( == ) + DEFINE_COMP_OP( != ) + +#undef DEFINE_COMP_OP +}; + + +#define ADD_TRAIT_TEST_CASE( op ) \ + TEST_CASE( "is_" #op "_comparable", \ + "[traits][is_comparable][approvals]" ) { \ + using Catch::Detail::is_##op##_0_comparable; \ + using Catch::Detail::is_##op##_comparable; \ + \ + STATIC_REQUIRE( is_##op##_comparable::value ); \ + STATIC_REQUIRE( \ + is_##op##_comparable::value ); \ + STATIC_REQUIRE( !is_##op##_comparable::value ); \ + STATIC_REQUIRE( \ + !is_##op##_comparable::value ); \ + STATIC_REQUIRE( \ + !is_##op##_comparable::value ); \ + \ + STATIC_REQUIRE( is_##op##_0_comparable::value ); \ + STATIC_REQUIRE( \ + is_##op##_0_comparable::value ); \ + STATIC_REQUIRE( !is_##op##_0_comparable::value ); \ + \ + /* This test fails with MSVC in permissive mode, because of course it does */ \ + /* STATIC_REQUIRE( !is_##op##_0_comparable::value ); */ \ +} + +ADD_TRAIT_TEST_CASE(lt) +ADD_TRAIT_TEST_CASE(gt) +ADD_TRAIT_TEST_CASE(le) +ADD_TRAIT_TEST_CASE(ge) +ADD_TRAIT_TEST_CASE(eq) +ADD_TRAIT_TEST_CASE(ne) + +#undef ADD_TRAIT_TEST_CASE diff --git a/tests/meson.build b/tests/meson.build index f869b29e..c8bdfb4b 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -31,6 +31,7 @@ self_test_sources = files( 'SelfTest/IntrospectiveTests/TestSpecParser.tests.cpp', 'SelfTest/IntrospectiveTests/TextFlow.tests.cpp', 'SelfTest/IntrospectiveTests/ToString.tests.cpp', + 'SelfTest/IntrospectiveTests/Traits.tests.cpp', 'SelfTest/IntrospectiveTests/UniquePtr.tests.cpp', 'SelfTest/IntrospectiveTests/Xml.tests.cpp', 'SelfTest/TestRegistrations.cpp',