1 /* 2 * Created by Phil Nash on 21/02/2017. 3 * Copyright (c) 2017 Two Blue Cubes Ltd. All rights reserved. 4 * 5 * Distributed under the Boost Software License, Version 1.0. (See accompanying 6 * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 */ 8 #ifndef TWOBLUECUBES_CATCH_MATCHERS_VECTOR_H_INCLUDED 9 #define TWOBLUECUBES_CATCH_MATCHERS_VECTOR_H_INCLUDED 10 11 #include "catch_matchers.h" 12 #include "catch_approx.h" 13 14 #include <algorithm> 15 16 namespace Catch { 17 namespace Matchers { 18 19 namespace Vector { 20 template<typename T, typename Alloc> 21 struct ContainsElementMatcher : MatcherBase<std::vector<T, Alloc>> { 22 ContainsElementMatcherContainsElementMatcher23 ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {} 24 matchContainsElementMatcher25 bool match(std::vector<T, Alloc> const &v) const override { 26 for (auto const& el : v) { 27 if (el == m_comparator) { 28 return true; 29 } 30 } 31 return false; 32 } 33 describeContainsElementMatcher34 std::string describe() const override { 35 return "Contains: " + ::Catch::Detail::stringify( m_comparator ); 36 } 37 38 T const& m_comparator; 39 }; 40 41 template<typename T, typename AllocComp, typename AllocMatch> 42 struct ContainsMatcher : MatcherBase<std::vector<T, AllocMatch>> { 43 ContainsMatcherContainsMatcher44 ContainsMatcher(std::vector<T, AllocComp> const &comparator) : m_comparator( comparator ) {} 45 matchContainsMatcher46 bool match(std::vector<T, AllocMatch> const &v) const override { 47 // !TBD: see note in EqualsMatcher 48 if (m_comparator.size() > v.size()) 49 return false; 50 for (auto const& comparator : m_comparator) { 51 auto present = false; 52 for (const auto& el : v) { 53 if (el == comparator) { 54 present = true; 55 break; 56 } 57 } 58 if (!present) { 59 return false; 60 } 61 } 62 return true; 63 } describeContainsMatcher64 std::string describe() const override { 65 return "Contains: " + ::Catch::Detail::stringify( m_comparator ); 66 } 67 68 std::vector<T, AllocComp> const& m_comparator; 69 }; 70 71 template<typename T, typename AllocComp, typename AllocMatch> 72 struct EqualsMatcher : MatcherBase<std::vector<T, AllocMatch>> { 73 EqualsMatcherEqualsMatcher74 EqualsMatcher(std::vector<T, AllocComp> const &comparator) : m_comparator( comparator ) {} 75 matchEqualsMatcher76 bool match(std::vector<T, AllocMatch> const &v) const override { 77 // !TBD: This currently works if all elements can be compared using != 78 // - a more general approach would be via a compare template that defaults 79 // to using !=. but could be specialised for, e.g. std::vector<T, Alloc> etc 80 // - then just call that directly 81 if (m_comparator.size() != v.size()) 82 return false; 83 for (std::size_t i = 0; i < v.size(); ++i) 84 if (m_comparator[i] != v[i]) 85 return false; 86 return true; 87 } describeEqualsMatcher88 std::string describe() const override { 89 return "Equals: " + ::Catch::Detail::stringify( m_comparator ); 90 } 91 std::vector<T, AllocComp> const& m_comparator; 92 }; 93 94 template<typename T, typename AllocComp, typename AllocMatch> 95 struct ApproxMatcher : MatcherBase<std::vector<T, AllocMatch>> { 96 ApproxMatcherApproxMatcher97 ApproxMatcher(std::vector<T, AllocComp> const& comparator) : m_comparator( comparator ) {} 98 matchApproxMatcher99 bool match(std::vector<T, AllocMatch> const &v) const override { 100 if (m_comparator.size() != v.size()) 101 return false; 102 for (std::size_t i = 0; i < v.size(); ++i) 103 if (m_comparator[i] != approx(v[i])) 104 return false; 105 return true; 106 } describeApproxMatcher107 std::string describe() const override { 108 return "is approx: " + ::Catch::Detail::stringify( m_comparator ); 109 } 110 template <typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> epsilonApproxMatcher111 ApproxMatcher& epsilon( T const& newEpsilon ) { 112 approx.epsilon(newEpsilon); 113 return *this; 114 } 115 template <typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> marginApproxMatcher116 ApproxMatcher& margin( T const& newMargin ) { 117 approx.margin(newMargin); 118 return *this; 119 } 120 template <typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> scaleApproxMatcher121 ApproxMatcher& scale( T const& newScale ) { 122 approx.scale(newScale); 123 return *this; 124 } 125 126 std::vector<T, AllocComp> const& m_comparator; 127 mutable Catch::Detail::Approx approx = Catch::Detail::Approx::custom(); 128 }; 129 130 template<typename T, typename AllocComp, typename AllocMatch> 131 struct UnorderedEqualsMatcher : MatcherBase<std::vector<T, AllocMatch>> { UnorderedEqualsMatcherUnorderedEqualsMatcher132 UnorderedEqualsMatcher(std::vector<T, AllocComp> const& target) : m_target(target) {} matchUnorderedEqualsMatcher133 bool match(std::vector<T, AllocMatch> const& vec) const override { 134 if (m_target.size() != vec.size()) { 135 return false; 136 } 137 return std::is_permutation(m_target.begin(), m_target.end(), vec.begin()); 138 } 139 describeUnorderedEqualsMatcher140 std::string describe() const override { 141 return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target); 142 } 143 private: 144 std::vector<T, AllocComp> const& m_target; 145 }; 146 147 } // namespace Vector 148 149 // The following functions create the actual matcher objects. 150 // This allows the types to be inferred 151 152 template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp> Contains(std::vector<T,AllocComp> const & comparator)153 Vector::ContainsMatcher<T, AllocComp, AllocMatch> Contains( std::vector<T, AllocComp> const& comparator ) { 154 return Vector::ContainsMatcher<T, AllocComp, AllocMatch>( comparator ); 155 } 156 157 template<typename T, typename Alloc = std::allocator<T>> VectorContains(T const & comparator)158 Vector::ContainsElementMatcher<T, Alloc> VectorContains( T const& comparator ) { 159 return Vector::ContainsElementMatcher<T, Alloc>( comparator ); 160 } 161 162 template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp> Equals(std::vector<T,AllocComp> const & comparator)163 Vector::EqualsMatcher<T, AllocComp, AllocMatch> Equals( std::vector<T, AllocComp> const& comparator ) { 164 return Vector::EqualsMatcher<T, AllocComp, AllocMatch>( comparator ); 165 } 166 167 template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp> Approx(std::vector<T,AllocComp> const & comparator)168 Vector::ApproxMatcher<T, AllocComp, AllocMatch> Approx( std::vector<T, AllocComp> const& comparator ) { 169 return Vector::ApproxMatcher<T, AllocComp, AllocMatch>( comparator ); 170 } 171 172 template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp> UnorderedEquals(std::vector<T,AllocComp> const & target)173 Vector::UnorderedEqualsMatcher<T, AllocComp, AllocMatch> UnorderedEquals(std::vector<T, AllocComp> const& target) { 174 return Vector::UnorderedEqualsMatcher<T, AllocComp, AllocMatch>( target ); 175 } 176 177 } // namespace Matchers 178 } // namespace Catch 179 180 #endif // TWOBLUECUBES_CATCH_MATCHERS_VECTOR_H_INCLUDED 181