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> 21 struct ContainsElementMatcher : MatcherBase<std::vector<T>> { 22 ContainsElementMatcherContainsElementMatcher23 ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {} 24 matchContainsElementMatcher25 bool match(std::vector<T> 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> 42 struct ContainsMatcher : MatcherBase<std::vector<T>> { 43 ContainsMatcherContainsMatcher44 ContainsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {} 45 matchContainsMatcher46 bool match(std::vector<T> 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> const& m_comparator; 69 }; 70 71 template<typename T> 72 struct EqualsMatcher : MatcherBase<std::vector<T>> { 73 EqualsMatcherEqualsMatcher74 EqualsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {} 75 matchEqualsMatcher76 bool match(std::vector<T> 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> 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> const& m_comparator; 92 }; 93 94 template<typename T> 95 struct ApproxMatcher : MatcherBase<std::vector<T>> { 96 ApproxMatcherApproxMatcher97 ApproxMatcher(std::vector<T> const& comparator) : m_comparator( comparator ) {} 98 matchApproxMatcher99 bool match(std::vector<T> 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> const& m_comparator; 127 mutable Catch::Detail::Approx approx = Catch::Detail::Approx::custom(); 128 }; 129 130 template<typename T> 131 struct UnorderedEqualsMatcher : MatcherBase<std::vector<T>> { UnorderedEqualsMatcherUnorderedEqualsMatcher132 UnorderedEqualsMatcher(std::vector<T> const& target) : m_target(target) {} matchUnorderedEqualsMatcher133 bool match(std::vector<T> const& vec) const override { 134 // Note: This is a reimplementation of std::is_permutation, 135 // because I don't want to include <algorithm> inside the common path 136 if (m_target.size() != vec.size()) { 137 return false; 138 } 139 return std::is_permutation(m_target.begin(), m_target.end(), vec.begin()); 140 } 141 describeUnorderedEqualsMatcher142 std::string describe() const override { 143 return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target); 144 } 145 private: 146 std::vector<T> const& m_target; 147 }; 148 149 } // namespace Vector 150 151 // The following functions create the actual matcher objects. 152 // This allows the types to be inferred 153 154 template<typename T> Contains(std::vector<T> const & comparator)155 Vector::ContainsMatcher<T> Contains( std::vector<T> const& comparator ) { 156 return Vector::ContainsMatcher<T>( comparator ); 157 } 158 159 template<typename T> VectorContains(T const & comparator)160 Vector::ContainsElementMatcher<T> VectorContains( T const& comparator ) { 161 return Vector::ContainsElementMatcher<T>( comparator ); 162 } 163 164 template<typename T> Equals(std::vector<T> const & comparator)165 Vector::EqualsMatcher<T> Equals( std::vector<T> const& comparator ) { 166 return Vector::EqualsMatcher<T>( comparator ); 167 } 168 169 template<typename T> Approx(std::vector<T> const & comparator)170 Vector::ApproxMatcher<T> Approx( std::vector<T> const& comparator ) { 171 return Vector::ApproxMatcher<T>( comparator ); 172 } 173 174 template<typename T> UnorderedEquals(std::vector<T> const & target)175 Vector::UnorderedEqualsMatcher<T> UnorderedEquals(std::vector<T> const& target) { 176 return Vector::UnorderedEqualsMatcher<T>(target); 177 } 178 179 } // namespace Matchers 180 } // namespace Catch 181 182 #endif // TWOBLUECUBES_CATCH_MATCHERS_VECTOR_H_INCLUDED 183