| 
									
										
										
										
											2020-03-02 14:25:43 +01:00
										 |  |  | // Distributed under the Boost Software License, Version 1.0. (See accompanying
 | 
					
						
							|  |  |  | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <catch2/catch_test_macros.hpp>
 | 
					
						
							| 
									
										
										
										
											2020-03-09 11:13:07 +01:00
										 |  |  | #include <catch2/matchers/catch_matchers_container_properties.hpp>
 | 
					
						
							| 
									
										
										
										
											2020-03-02 14:25:43 +01:00
										 |  |  | #include <catch2/matchers/catch_matchers_contains.hpp>
 | 
					
						
							| 
									
										
										
										
											2020-12-13 15:41:12 +01:00
										 |  |  | #include <catch2/matchers/catch_matchers_floating_point.hpp>
 | 
					
						
							| 
									
										
										
										
											2020-03-02 14:25:43 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include <array>
 | 
					
						
							|  |  |  | #include <cmath>
 | 
					
						
							|  |  |  | #include <list>
 | 
					
						
							| 
									
										
										
										
											2020-03-09 11:13:07 +01:00
										 |  |  | #include <map>
 | 
					
						
							| 
									
										
										
										
											2020-03-02 14:25:43 +01:00
										 |  |  | #include <vector>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-09 11:13:07 +01:00
										 |  |  | namespace { | 
					
						
							| 
									
										
										
										
											2020-03-02 14:25:43 +01:00
										 |  |  | namespace unrelated { | 
					
						
							|  |  |  |     class needs_ADL_begin { | 
					
						
							|  |  |  |         std::array<int, 5> elements{ {1, 2, 3, 4, 5} }; | 
					
						
							|  |  |  |     public: | 
					
						
							|  |  |  |         using iterator = std::array<int, 5>::iterator; | 
					
						
							|  |  |  |         using const_iterator = std::array<int, 5>::const_iterator; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const_iterator Begin() const { return elements.begin(); } | 
					
						
							|  |  |  |         const_iterator End() const { return elements.end(); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         friend const_iterator begin(needs_ADL_begin const& lhs) { | 
					
						
							|  |  |  |             return lhs.Begin(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         friend const_iterator end(needs_ADL_begin const& rhs) { | 
					
						
							|  |  |  |             return rhs.End(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2020-03-09 11:13:07 +01:00
										 |  |  | } // end unrelated namespace
 | 
					
						
							| 
									
										
										
										
											2020-03-02 14:25:43 +01:00
										 |  |  | } // end anon namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct MoveOnlyTestElement { | 
					
						
							|  |  |  |     int num = 0; | 
					
						
							|  |  |  |     MoveOnlyTestElement(int n) :num(n) {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     MoveOnlyTestElement(MoveOnlyTestElement&& rhs) = default; | 
					
						
							|  |  |  |     MoveOnlyTestElement& operator=(MoveOnlyTestElement&& rhs) = default; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     friend bool operator==(MoveOnlyTestElement const& lhs, MoveOnlyTestElement const& rhs) { | 
					
						
							|  |  |  |         return lhs.num == rhs.num; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     friend std::ostream& operator<<(std::ostream& out, MoveOnlyTestElement const& elem) { | 
					
						
							|  |  |  |         out << elem.num; | 
					
						
							|  |  |  |         return out; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST_CASE("Basic use of the Contains range matcher", "[matchers][templated][contains]") { | 
					
						
							|  |  |  |     using Catch::Matchers::Contains; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     SECTION("Different argument ranges, same element type, default comparison") { | 
					
						
							|  |  |  |         std::array<int, 3> a{ { 1,2,3 } }; | 
					
						
							|  |  |  |         std::vector<int> b{ 0,1,2 }; | 
					
						
							|  |  |  |         std::list<int> c{ 4,5,6 }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // A contains 1
 | 
					
						
							|  |  |  |         REQUIRE_THAT(a,  Contains(1)); | 
					
						
							|  |  |  |         // B contains 1
 | 
					
						
							|  |  |  |         REQUIRE_THAT(b,  Contains(1)); | 
					
						
							|  |  |  |         // C does not contain 1
 | 
					
						
							|  |  |  |         REQUIRE_THAT(c, !Contains(1)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     SECTION("Different argument ranges, same element type, custom comparison") { | 
					
						
							|  |  |  |         std::array<int, 3> a{ { 1,2,3 } }; | 
					
						
							|  |  |  |         std::vector<int> b{ 0,1,2 }; | 
					
						
							|  |  |  |         std::list<int> c{ 4,5,6 }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         auto close_enough = [](int lhs, int rhs) { return std::abs(lhs - rhs) <= 1; }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // A contains 1, which is "close enough" to 0
 | 
					
						
							|  |  |  |         REQUIRE_THAT(a,  Contains(0, close_enough)); | 
					
						
							|  |  |  |         // B contains 0 directly
 | 
					
						
							|  |  |  |         REQUIRE_THAT(b,  Contains(0, close_enough)); | 
					
						
							|  |  |  |         // C does not contain anything "close enough" to 0
 | 
					
						
							|  |  |  |         REQUIRE_THAT(c, !Contains(0, close_enough)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     SECTION("Different element type, custom comparisons") { | 
					
						
							|  |  |  |         std::array<std::string, 3> a{ { "abc", "abcd" , "abcde" } }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         REQUIRE_THAT(a, Contains(4, [](auto&& lhs, size_t sz) { | 
					
						
							|  |  |  |             return lhs.size() == sz; | 
					
						
							|  |  |  |         })); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     SECTION("Can handle type that requires ADL-found free function begin and end") { | 
					
						
							|  |  |  |         unrelated::needs_ADL_begin in; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         REQUIRE_THAT(in,  Contains(1)); | 
					
						
							|  |  |  |         REQUIRE_THAT(in, !Contains(8)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     SECTION("Initialization with move only types") { | 
					
						
							|  |  |  |         std::array<MoveOnlyTestElement, 3> in{ { MoveOnlyTestElement{ 1 }, MoveOnlyTestElement{ 2 }, MoveOnlyTestElement{ 3 } } }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         REQUIRE_THAT(in,  Contains(MoveOnlyTestElement{ 2 })); | 
					
						
							|  |  |  |         REQUIRE_THAT(in, !Contains(MoveOnlyTestElement{ 9 })); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     SECTION("Matching using matcher") { | 
					
						
							|  |  |  |         std::array<double, 4> in{ {1, 2, 3} }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         REQUIRE_THAT(in, Contains(Catch::Matchers::WithinAbs(0.5, 0.5))); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2020-03-09 11:13:07 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     struct has_empty { | 
					
						
							|  |  |  |         bool empty() const { return false; } | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace unrelated { | 
					
						
							|  |  |  |     struct ADL_empty { | 
					
						
							|  |  |  |         bool Empty() const { return true; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         friend bool empty(ADL_empty e) { | 
					
						
							|  |  |  |             return e.Empty(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } // end namespace unrelated
 | 
					
						
							|  |  |  | } // end unnamed namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST_CASE("Basic use of the Empty range matcher", "[matchers][templated][empty]") { | 
					
						
							|  |  |  |     using Catch::Matchers::IsEmpty; | 
					
						
							|  |  |  |     SECTION("Simple, std-provided containers") { | 
					
						
							|  |  |  |         std::array<int, 0> empty_array{}; | 
					
						
							|  |  |  |         std::array<double, 1> non_empty_array{}; | 
					
						
							|  |  |  |         REQUIRE_THAT(empty_array, IsEmpty()); | 
					
						
							|  |  |  |         REQUIRE_THAT(non_empty_array, !IsEmpty()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         std::vector<std::string> empty_vec; | 
					
						
							|  |  |  |         std::vector<char> non_empty_vec{ 'a', 'b', 'c' }; | 
					
						
							|  |  |  |         REQUIRE_THAT(empty_vec, IsEmpty()); | 
					
						
							|  |  |  |         REQUIRE_THAT(non_empty_vec, !IsEmpty()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         std::list<std::list<std::list<int>>> inner_lists_are_empty; | 
					
						
							|  |  |  |         inner_lists_are_empty.push_back({}); | 
					
						
							|  |  |  |         REQUIRE_THAT(inner_lists_are_empty, !IsEmpty()); | 
					
						
							|  |  |  |         REQUIRE_THAT(inner_lists_are_empty.front(), IsEmpty()); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     SECTION("Type with empty") { | 
					
						
							|  |  |  |         REQUIRE_THAT(has_empty{}, !IsEmpty()); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     SECTION("Type requires ADL found empty free function") { | 
					
						
							|  |  |  |         REQUIRE_THAT(unrelated::ADL_empty{}, IsEmpty()); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace { | 
					
						
							|  |  |  |     class LessThanMatcher final : public Catch::Matchers::MatcherBase<size_t> { | 
					
						
							|  |  |  |         size_t m_target; | 
					
						
							|  |  |  |     public: | 
					
						
							|  |  |  |         explicit LessThanMatcher(size_t target): | 
					
						
							|  |  |  |             m_target(target) | 
					
						
							|  |  |  |         {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         bool match(size_t const& size) const override { | 
					
						
							|  |  |  |             return size < m_target; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         std::string describe() const override { | 
					
						
							|  |  |  |             return "is less than " + std::to_string(m_target); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     LessThanMatcher Lt(size_t sz) { | 
					
						
							|  |  |  |         return LessThanMatcher{ sz }; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     namespace unrelated { | 
					
						
							|  |  |  |         struct ADL_size { | 
					
						
							|  |  |  |             size_t sz() const { | 
					
						
							|  |  |  |                 return 12; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             friend size_t size(ADL_size s) { | 
					
						
							|  |  |  |                 return s.sz(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  |     } // end namespace unrelated
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     struct has_size { | 
					
						
							|  |  |  |         size_t size() const { | 
					
						
							|  |  |  |             return 13; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } // end unnamed namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST_CASE("Usage of the SizeIs range matcher", "[matchers][templated][size]") { | 
					
						
							|  |  |  |     using Catch::Matchers::SizeIs; | 
					
						
							|  |  |  |     SECTION("Some with stdlib containers") { | 
					
						
							|  |  |  |         std::vector<int> empty_vec; | 
					
						
							|  |  |  |         REQUIRE_THAT(empty_vec,  SizeIs(0)); | 
					
						
							|  |  |  |         REQUIRE_THAT(empty_vec, !SizeIs(2)); | 
					
						
							|  |  |  |         REQUIRE_THAT(empty_vec,  SizeIs(Lt(2))); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         std::array<int, 2> arr{}; | 
					
						
							|  |  |  |         REQUIRE_THAT(arr,  SizeIs(2)); | 
					
						
							|  |  |  |         REQUIRE_THAT(arr,  SizeIs( Lt(3))); | 
					
						
							|  |  |  |         REQUIRE_THAT(arr, !SizeIs(!Lt(3))); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         std::map<int, int> map{ {1, 1}, {2, 2}, {3, 3} }; | 
					
						
							|  |  |  |         REQUIRE_THAT(map, SizeIs(3)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     SECTION("Type requires ADL found size free function") { | 
					
						
							|  |  |  |         REQUIRE_THAT(unrelated::ADL_size{}, SizeIs(12)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     SECTION("Type has size member") { | 
					
						
							|  |  |  |         REQUIRE_THAT(has_size{}, SizeIs(13)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |