diff --git a/src/catch2/matchers/catch_matchers_vector.hpp b/src/catch2/matchers/catch_matchers_vector.hpp index e5d68949..cd506292 100644 --- a/src/catch2/matchers/catch_matchers_vector.hpp +++ b/src/catch2/matchers/catch_matchers_vector.hpp @@ -16,164 +16,172 @@ namespace Catch { namespace Matchers { - namespace Vector { - template - struct ContainsElementMatcher final : MatcherBase> { + template + struct ContainsElementMatcher final : MatcherBase> { - ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {} + ContainsElementMatcher(T const& comparator): + m_comparator(comparator) + {} - bool match(std::vector const &v) const override { - for (auto const& el : v) { - if (el == m_comparator) { - return true; + bool match(std::vector const& v) const override { + for (auto const& el : v) { + if (el == m_comparator) { + return true; + } + } + return false; + } + + std::string describe() const override { + return "Contains: " + ::Catch::Detail::stringify( m_comparator ); + } + + T const& m_comparator; + }; + + template + struct ContainsMatcher final : MatcherBase> { + + ContainsMatcher(std::vector const& comparator): + m_comparator(comparator) + {} + + bool match(std::vector const& v) const override { + // !TBD: see note in EqualsMatcher + if (m_comparator.size() > v.size()) + return false; + for (auto const& comparator : m_comparator) { + auto present = false; + for (const auto& el : v) { + if (el == comparator) { + present = true; + break; } } + if (!present) { + return false; + } + } + return true; + } + std::string describe() const override { + return "Contains: " + ::Catch::Detail::stringify( m_comparator ); + } + + std::vector const& m_comparator; + }; + + template + struct EqualsMatcher final : MatcherBase> { + + EqualsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} + + bool match(std::vector const &v) const override { + // !TBD: This currently works if all elements can be compared using != + // - a more general approach would be via a compare template that defaults + // to using !=. but could be specialised for, e.g. std::vector etc + // - then just call that directly + if (m_comparator.size() != v.size()) + return false; + for (std::size_t i = 0; i < v.size(); ++i) + if (m_comparator[i] != v[i]) + return false; + return true; + } + std::string describe() const override { + return "Equals: " + ::Catch::Detail::stringify( m_comparator ); + } + std::vector const& m_comparator; + }; + + template + struct ApproxMatcher final : MatcherBase> { + + ApproxMatcher(std::vector const& comparator) : m_comparator( comparator ) {} + + bool match(std::vector const &v) const override { + if (m_comparator.size() != v.size()) + return false; + for (std::size_t i = 0; i < v.size(); ++i) + if (m_comparator[i] != approx(v[i])) + return false; + return true; + } + std::string describe() const override { + return "is approx: " + ::Catch::Detail::stringify( m_comparator ); + } + template ::value>> + ApproxMatcher& epsilon( T const& newEpsilon ) { + approx.epsilon(newEpsilon); + return *this; + } + template ::value>> + ApproxMatcher& margin( T const& newMargin ) { + approx.margin(newMargin); + return *this; + } + template ::value>> + ApproxMatcher& scale( T const& newScale ) { + approx.scale(newScale); + return *this; + } + + std::vector const& m_comparator; + mutable Catch::Approx approx = Catch::Approx::custom(); + }; + + template + struct UnorderedEqualsMatcher final : MatcherBase> { + UnorderedEqualsMatcher(std::vector const& target) : m_target(target) {} + bool match(std::vector const& vec) const override { + // Note: This is a reimplementation of std::is_permutation, + // because I don't want to include inside the common path + if (m_target.size() != vec.size()) { return false; } + return std::is_permutation(m_target.begin(), m_target.end(), vec.begin()); + } - std::string describe() const override { - return "Contains: " + ::Catch::Detail::stringify( m_comparator ); - } + std::string describe() const override { + return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target); + } + private: + std::vector const& m_target; + }; - T const& m_comparator; - }; - - template - struct ContainsMatcher final : MatcherBase> { - - ContainsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} - - bool match(std::vector const &v) const override { - // !TBD: see note in EqualsMatcher - if (m_comparator.size() > v.size()) - return false; - for (auto const& comparator : m_comparator) { - auto present = false; - for (const auto& el : v) { - if (el == comparator) { - present = true; - break; - } - } - if (!present) { - return false; - } - } - return true; - } - std::string describe() const override { - return "Contains: " + ::Catch::Detail::stringify( m_comparator ); - } - - std::vector const& m_comparator; - }; - - template - struct EqualsMatcher final : MatcherBase> { - - EqualsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} - - bool match(std::vector const &v) const override { - // !TBD: This currently works if all elements can be compared using != - // - a more general approach would be via a compare template that defaults - // to using !=. but could be specialised for, e.g. std::vector etc - // - then just call that directly - if (m_comparator.size() != v.size()) - return false; - for (std::size_t i = 0; i < v.size(); ++i) - if (m_comparator[i] != v[i]) - return false; - return true; - } - std::string describe() const override { - return "Equals: " + ::Catch::Detail::stringify( m_comparator ); - } - std::vector const& m_comparator; - }; - - template - struct ApproxMatcher final : MatcherBase> { - - ApproxMatcher(std::vector const& comparator) : m_comparator( comparator ) {} - - bool match(std::vector const &v) const override { - if (m_comparator.size() != v.size()) - return false; - for (std::size_t i = 0; i < v.size(); ++i) - if (m_comparator[i] != approx(v[i])) - return false; - return true; - } - std::string describe() const override { - return "is approx: " + ::Catch::Detail::stringify( m_comparator ); - } - template ::value>> - ApproxMatcher& epsilon( T const& newEpsilon ) { - approx.epsilon(newEpsilon); - return *this; - } - template ::value>> - ApproxMatcher& margin( T const& newMargin ) { - approx.margin(newMargin); - return *this; - } - template ::value>> - ApproxMatcher& scale( T const& newScale ) { - approx.scale(newScale); - return *this; - } - - std::vector const& m_comparator; - mutable Catch::Approx approx = Catch::Approx::custom(); - }; - - template - struct UnorderedEqualsMatcher final : MatcherBase> { - UnorderedEqualsMatcher(std::vector const& target) : m_target(target) {} - bool match(std::vector const& vec) const override { - // Note: This is a reimplementation of std::is_permutation, - // because I don't want to include inside the common path - if (m_target.size() != vec.size()) { - return false; - } - return std::is_permutation(m_target.begin(), m_target.end(), vec.begin()); - } - - std::string describe() const override { - return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target); - } - private: - std::vector const& m_target; - }; - - } // namespace Vector // The following functions create the actual matcher objects. // This allows the types to be inferred + + //! Creates a matcher that matches vectors that contain all elements in `comparator` template - Vector::ContainsMatcher Contains( std::vector const& comparator ) { - return Vector::ContainsMatcher( comparator ); + ContainsMatcher Contains( std::vector const& comparator ) { + return ContainsMatcher( comparator ); } + //! Creates a matcher that matches vectors that contain `comparator` as an element template - Vector::ContainsElementMatcher VectorContains( T const& comparator ) { - return Vector::ContainsElementMatcher( comparator ); + ContainsElementMatcher VectorContains( T const& comparator ) { + return ContainsElementMatcher( comparator ); } + //! Creates a matcher that matches vectors that are exactly equal to `comparator` template - Vector::EqualsMatcher Equals( std::vector const& comparator ) { - return Vector::EqualsMatcher( comparator ); + EqualsMatcher Equals( std::vector const& comparator ) { + return EqualsMatcher( comparator ); } + //! Creates a matcher that matches vectors that `comparator` as an element template - Vector::ApproxMatcher Approx( std::vector const& comparator ) { - return Vector::ApproxMatcher( comparator ); + ApproxMatcher Approx( std::vector const& comparator ) { + return ApproxMatcher( comparator ); } + //! Creates a matcher that matches vectors that is equal to `target` modulo permutation template - Vector::UnorderedEqualsMatcher UnorderedEquals(std::vector const& target) { - return Vector::UnorderedEqualsMatcher(target); + UnorderedEqualsMatcher UnorderedEquals(std::vector const& target) { + return UnorderedEqualsMatcher(target); } } // namespace Matchers