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