Read-only mirrors. Development, issues and pull requests are on GitHub.

summaryrefslogtreecommitdiffhomepage
path: root/tests/SelfTest/UsageTests
diff options
context:
space:
mode:
authorJohn Beard2023-01-21 23:33:04 +0000
committerGitHub2023-01-22 00:33:04 +0100
commitefca9a0f1826885c1574ed44fc37c8d82ded4546 (patch)
tree1b7284ecb35feae1e7134ccd7eb3503b4e91c991 /tests/SelfTest/UsageTests
parentdd36f83b88f3a3d7796469bb2d91f9af71bfa675 (diff)
downloadcatch3-efca9a0f1826885c1574ed44fc37c8d82ded4546.tar.gz
Added ElementsAre and UnorderedElementsAre (#2377)
Co-authored-by: Garz4 <fancygarz4@gmail.com> Co-authored-by: Martin Hořeňovský <martin.horenovsky@gmail.com>
Diffstat (limited to 'tests/SelfTest/UsageTests')
-rw-r--r--tests/SelfTest/UsageTests/MatchersRanges.tests.cpp223
1 files changed, 223 insertions, 0 deletions
diff --git a/tests/SelfTest/UsageTests/MatchersRanges.tests.cpp b/tests/SelfTest/UsageTests/MatchersRanges.tests.cpp
index f30af703..02186783 100644
--- a/tests/SelfTest/UsageTests/MatchersRanges.tests.cpp
+++ b/tests/SelfTest/UsageTests/MatchersRanges.tests.cpp
@@ -9,6 +9,7 @@
#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_container_properties.hpp>
#include <catch2/matchers/catch_matchers_contains.hpp>
+#include <catch2/matchers/catch_matchers_range_equals.hpp>
#include <catch2/matchers/catch_matchers_floating_point.hpp>
#include <catch2/matchers/catch_matchers_quantifiers.hpp>
#include <catch2/matchers/catch_matchers_predicate.hpp>
@@ -832,3 +833,225 @@ TEST_CASE( "The quantifier range matchers support types with different types ret
}
#endif
+
+TEST_CASE( "Usage of RangeEquals range matcher", "[matchers][templated][quantifiers]" ) {
+ using Catch::Matchers::RangeEquals;
+
+ // In these tests, the types are always the same - type conversion is in the next section
+ SECTION( "Basic usage" ) {
+ SECTION( "Empty container matches empty container" ) {
+ const std::vector<int> empty_vector;
+ CHECK_THAT( empty_vector, RangeEquals( empty_vector ) );
+ }
+ SECTION( "Empty container does not match non-empty container" ) {
+ const std::vector<int> empty_vector;
+ const std::vector<int> non_empty_vector{ 1 };
+ CHECK_THAT( empty_vector, !RangeEquals( non_empty_vector ) );
+ // ...and in reverse
+ CHECK_THAT( non_empty_vector, !RangeEquals( empty_vector ) );
+ }
+ SECTION( "Two equal 1-length non-empty containers" ) {
+ const std::array<int, 1> non_empty_array{ { 1 } };
+ CHECK_THAT( non_empty_array, RangeEquals( non_empty_array ) );
+ }
+ SECTION( "Two equal-sized, equal, non-empty containers" ) {
+ const std::array<int, 3> array_a{ { 1, 2, 3 } };
+ CHECK_THAT( array_a, RangeEquals( array_a ) );
+ }
+ SECTION( "Two equal-sized, non-equal, non-empty containers" ) {
+ const std::array<int, 3> array_a{ { 1, 2, 3 } };
+ const std::array<int, 3> array_b{ { 2, 2, 3 } };
+ const std::array<int, 3> array_c{ { 1, 2, 2 } };
+ CHECK_THAT( array_a, !RangeEquals( array_b ) );
+ CHECK_THAT( array_a, !RangeEquals( array_c ) );
+ }
+ SECTION( "Two non-equal-sized, non-empty containers (with same first "
+ "elements)" ) {
+ const std::vector<int> vector_a{ 1, 2, 3 };
+ const std::vector<int> vector_b{ 1, 2, 3, 4 };
+ CHECK_THAT( vector_a, !RangeEquals( vector_b ) );
+ }
+ }
+
+ SECTION( "Custom predicate" ) {
+
+ auto close_enough = []( int lhs, int rhs ) {
+ return std::abs( lhs - rhs ) <= 1;
+ };
+
+ SECTION( "Two equal non-empty containers (close enough)" ) {
+ const std::vector<int> vector_a{ { 1, 2, 3 } };
+ const std::vector<int> vector_a_plus_1{ { 2, 3, 4 } };
+ CHECK_THAT( vector_a, RangeEquals( vector_a_plus_1, close_enough ) );
+ }
+ SECTION( "Two non-equal non-empty containers (close enough)" ) {
+ const std::vector<int> vector_a{ { 1, 2, 3 } };
+ const std::vector<int> vector_b{ { 3, 3, 4 } };
+ CHECK_THAT( vector_a, !RangeEquals( vector_b, close_enough ) );
+ }
+ }
+
+ // Cannot usefully test short-circuits, as the complexiy of std::equal is
+ // only guaranteed to be O(n) or better (even if many implementations
+ // short-circuit if the range lengths differ for
+ // LegacyRandomAccessIterators)
+}
+
+TEST_CASE( "Usage of UnorderedRangeEquals range matcher",
+ "[matchers][templated][quantifiers]" ) {
+ using Catch::Matchers::UnorderedRangeEquals;
+
+ // In these tests, the types are always the same - type conversion is in the
+ // next section
+ SECTION( "Basic usage" ) {
+ SECTION( "Empty container matches empty container" ) {
+ const std::vector<int> empty_vector;
+ CHECK_THAT( empty_vector, UnorderedRangeEquals( empty_vector ) );
+ }
+ SECTION( "Empty container does not match non-empty container" ) {
+ const std::vector<int> empty_vector;
+ const std::vector<int> non_empty_vector{ 1 };
+ CHECK_THAT( empty_vector,
+ !UnorderedRangeEquals( non_empty_vector ) );
+ // ...and in reverse
+ CHECK_THAT( non_empty_vector,
+ !UnorderedRangeEquals( empty_vector ) );
+ }
+ SECTION( "Two equal 1-length non-empty containers" ) {
+ const std::array<int, 1> non_empty_array{ { 1 } };
+ CHECK_THAT( non_empty_array,
+ UnorderedRangeEquals( non_empty_array ) );
+ }
+ SECTION( "Two equal-sized, equal, non-empty containers" ) {
+ const std::array<int, 3> array_a{ { 1, 2, 3 } };
+ CHECK_THAT( array_a, UnorderedRangeEquals( array_a ) );
+ }
+ SECTION( "Two equal-sized, non-equal, non-empty containers" ) {
+ const std::array<int, 3> array_a{ { 1, 2, 3 } };
+ const std::array<int, 3> array_b{ { 2, 2, 3 } };
+ CHECK_THAT( array_a, !UnorderedRangeEquals( array_b ) );
+ }
+ SECTION( "Two non-equal-sized, non-empty containers" ) {
+ const std::vector<int> vector_a{ 1, 2, 3 };
+ const std::vector<int> vector_b{ 1, 2, 3, 4 };
+ CHECK_THAT( vector_a, !UnorderedRangeEquals( vector_b ) );
+ }
+ }
+
+ SECTION( "Custom predicate" ) {
+
+ auto close_enough = []( int lhs, int rhs ) {
+ return std::abs( lhs - rhs ) <= 1;
+ };
+
+ SECTION( "Two equal non-empty containers (close enough)" ) {
+ const std::vector<int> vector_a{ { 1, 10, 20 } };
+ const std::vector<int> vector_a_plus_1{ { 11, 21, 2 } };
+ CHECK_THAT( vector_a,
+ UnorderedRangeEquals( vector_a_plus_1, close_enough ) );
+ }
+ SECTION( "Two non-equal non-empty containers (close enough)" ) {
+ const std::vector<int> vector_a{ { 1, 10, 21 } };
+ const std::vector<int> vector_b{ { 11, 21, 3 } };
+ CHECK_THAT( vector_a,
+ !UnorderedRangeEquals( vector_b, close_enough ) );
+ }
+ }
+
+ // As above with RangeEquals, short cicuiting and other optimisations
+ // are left to the STL implementation
+}
+
+/**
+ * Return true if the type given has a random access iterator type.
+ */
+template <typename Container>
+static constexpr bool ContainerIsRandomAccess( const Container& ) {
+ using array_iter_category = typename std::iterator_traits<
+ typename Container::iterator>::iterator_category;
+
+ return std::is_base_of<std::random_access_iterator_tag,
+ array_iter_category>::value;
+}
+
+TEST_CASE( "Type conversions of RangeEquals and similar",
+ "[matchers][templated][quantifiers]" ) {
+ using Catch::Matchers::RangeEquals;
+ using Catch::Matchers::UnorderedRangeEquals;
+
+ // In these test, we can always test RangeEquals and
+ // UnorderedRangeEquals in the same way, since we're mostly
+ // testing the template type deductions (and RangeEquals
+ // implies UnorderedRangeEquals)
+
+ SECTION( "Container conversions" ) {
+ SECTION( "Two equal containers of different container types" ) {
+ const std::array<int, 3> array_int_a{ { 1, 2, 3 } };
+ const int c_array[3] = { 1, 2, 3 };
+ CHECK_THAT( array_int_a, RangeEquals( c_array ) );
+ CHECK_THAT( array_int_a, UnorderedRangeEquals( c_array ) );
+ }
+ SECTION( "Two equal containers of different container types "
+ "(differ in array N)" ) {
+ const std::array<int, 3> array_int_3{ { 1, 2, 3 } };
+ const std::array<int, 4> array_int_4{ { 1, 2, 3, 4 } };
+ CHECK_THAT( array_int_3, !RangeEquals( array_int_4 ) );
+ CHECK_THAT( array_int_3, !UnorderedRangeEquals( array_int_4 ) );
+ }
+ SECTION( "Two equal containers of different container types and value "
+ "types" ) {
+ const std::array<int, 3> array_int_a{ { 1, 2, 3 } };
+ const std::vector<int> vector_char_a{ 1, 2, 3 };
+ CHECK_THAT( array_int_a, RangeEquals( vector_char_a ) );
+ CHECK_THAT( array_int_a, UnorderedRangeEquals( vector_char_a ) );
+ }
+ SECTION( "Two equal containers, one random access, one not" ) {
+ const std::array<int, 3> array_int_a{ { 1, 2, 3 } };
+ const std::list<int> list_char_a{ 1, 2, 3 };
+
+ // Verify these types really are different in random access nature
+ STATIC_REQUIRE( ContainerIsRandomAccess( array_int_a ) !=
+ ContainerIsRandomAccess( list_char_a ) );
+
+ CHECK_THAT( array_int_a, RangeEquals( list_char_a ) );
+ CHECK_THAT( array_int_a, UnorderedRangeEquals( list_char_a ) );
+ }
+ }
+
+ SECTION( "Value type" ) {
+ SECTION( "Two equal containers of different value types" ) {
+ const std::vector<int> vector_int_a{ 1, 2, 3 };
+ const std::vector<char> vector_char_a{ 1, 2, 3 };
+ CHECK_THAT( vector_int_a, RangeEquals( vector_char_a ) );
+ CHECK_THAT( vector_int_a, UnorderedRangeEquals( vector_char_a ) );
+ }
+ SECTION( "Two non-equal containers of different value types" ) {
+ const std::vector<int> vector_int_a{ 1, 2, 3 };
+ const std::vector<char> vector_char_b{ 1, 2, 2 };
+ CHECK_THAT( vector_int_a, !RangeEquals( vector_char_b ) );
+ CHECK_THAT( vector_int_a, !UnorderedRangeEquals( vector_char_b ) );
+ }
+ }
+
+ SECTION( "Ranges with begin that needs ADL" ) {
+ unrelated::needs_ADL_begin<int> a{ 1, 2, 3 }, b{ 3, 2, 1 };
+ REQUIRE_THAT( a, !RangeEquals( b ) );
+ REQUIRE_THAT( a, UnorderedRangeEquals( b ) );
+ }
+
+ SECTION( "Custom predicate" ) {
+
+ auto close_enough = []( int lhs, int rhs ) {
+ return std::abs( lhs - rhs ) <= 1;
+ };
+
+ SECTION( "Two equal non-empty containers (close enough)" ) {
+ const std::vector<int> vector_a{ { 1, 2, 3 } };
+ const std::array<char, 3> array_a_plus_1{ { 2, 3, 4 } };
+ CHECK_THAT( vector_a,
+ RangeEquals( array_a_plus_1, close_enough ) );
+ CHECK_THAT( vector_a,
+ UnorderedRangeEquals( array_a_plus_1, close_enough ) );
+ }
+ }
+} \ No newline at end of file