2017-02-21 17:05:04 +01:00
|
|
|
/*
|
|
|
|
* Created by Phil Nash on 21/02/2017.
|
|
|
|
* Copyright (c) 2017 Two Blue Cubes Ltd. All rights reserved.
|
|
|
|
*
|
|
|
|
* 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)
|
|
|
|
*/
|
|
|
|
#ifndef TWOBLUECUBES_CATCH_MATCHERS_VECTOR_H_INCLUDED
|
|
|
|
#define TWOBLUECUBES_CATCH_MATCHERS_VECTOR_H_INCLUDED
|
|
|
|
|
2017-09-07 12:24:33 +02:00
|
|
|
#include "catch_matchers.h"
|
2019-01-14 15:31:09 +01:00
|
|
|
#include "catch_approx.h"
|
2017-02-21 17:05:04 +01:00
|
|
|
|
2017-12-07 17:07:25 +01:00
|
|
|
#include <algorithm>
|
|
|
|
|
2017-02-21 17:05:04 +01:00
|
|
|
namespace Catch {
|
|
|
|
namespace Matchers {
|
|
|
|
|
|
|
|
namespace Vector {
|
2020-04-16 15:36:54 +02:00
|
|
|
template<typename T, typename Alloc>
|
|
|
|
struct ContainsElementMatcher : MatcherBase<std::vector<T, Alloc>> {
|
2017-02-21 17:05:04 +01:00
|
|
|
|
|
|
|
ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {}
|
|
|
|
|
2020-04-16 15:36:54 +02:00
|
|
|
bool match(std::vector<T, Alloc> const &v) const override {
|
2017-07-28 15:11:05 +02:00
|
|
|
for (auto const& el : v) {
|
|
|
|
if (el == m_comparator) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
2017-02-21 17:05:04 +01:00
|
|
|
}
|
|
|
|
|
2017-07-20 16:57:17 +02:00
|
|
|
std::string describe() const override {
|
2017-05-02 23:51:03 +02:00
|
|
|
return "Contains: " + ::Catch::Detail::stringify( m_comparator );
|
2017-02-21 17:05:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
T const& m_comparator;
|
|
|
|
};
|
|
|
|
|
2020-04-16 15:36:54 +02:00
|
|
|
template<typename T, typename AllocComp, typename AllocMatch>
|
|
|
|
struct ContainsMatcher : MatcherBase<std::vector<T, AllocMatch>> {
|
2017-02-21 17:05:04 +01:00
|
|
|
|
2020-04-16 15:36:54 +02:00
|
|
|
ContainsMatcher(std::vector<T, AllocComp> const &comparator) : m_comparator( comparator ) {}
|
2017-02-21 17:05:04 +01:00
|
|
|
|
2020-04-16 15:36:54 +02:00
|
|
|
bool match(std::vector<T, AllocMatch> const &v) const override {
|
2017-02-21 17:05:04 +01:00
|
|
|
// !TBD: see note in EqualsMatcher
|
|
|
|
if (m_comparator.size() > v.size())
|
|
|
|
return false;
|
2017-07-28 15:11:05 +02:00
|
|
|
for (auto const& comparator : m_comparator) {
|
|
|
|
auto present = false;
|
|
|
|
for (const auto& el : v) {
|
|
|
|
if (el == comparator) {
|
|
|
|
present = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!present) {
|
2017-02-21 17:05:04 +01:00
|
|
|
return false;
|
2017-07-28 15:11:05 +02:00
|
|
|
}
|
|
|
|
}
|
2017-02-21 17:05:04 +01:00
|
|
|
return true;
|
|
|
|
}
|
2017-07-20 16:57:17 +02:00
|
|
|
std::string describe() const override {
|
2017-05-02 23:51:03 +02:00
|
|
|
return "Contains: " + ::Catch::Detail::stringify( m_comparator );
|
2017-02-21 17:05:04 +01:00
|
|
|
}
|
|
|
|
|
2020-04-16 15:36:54 +02:00
|
|
|
std::vector<T, AllocComp> const& m_comparator;
|
2017-02-21 17:05:04 +01:00
|
|
|
};
|
|
|
|
|
2020-04-16 15:36:54 +02:00
|
|
|
template<typename T, typename AllocComp, typename AllocMatch>
|
|
|
|
struct EqualsMatcher : MatcherBase<std::vector<T, AllocMatch>> {
|
2017-02-21 17:05:04 +01:00
|
|
|
|
2020-04-16 15:36:54 +02:00
|
|
|
EqualsMatcher(std::vector<T, AllocComp> const &comparator) : m_comparator( comparator ) {}
|
2017-02-21 17:05:04 +01:00
|
|
|
|
2020-04-16 15:36:54 +02:00
|
|
|
bool match(std::vector<T, AllocMatch> const &v) const override {
|
2017-02-21 17:05:04 +01:00
|
|
|
// !TBD: This currently works if all elements can be compared using !=
|
|
|
|
// - a more general approach would be via a compare template that defaults
|
2020-04-16 15:36:54 +02:00
|
|
|
// to using !=. but could be specialised for, e.g. std::vector<T, Alloc> etc
|
2017-02-21 17:05:04 +01:00
|
|
|
// - then just call that directly
|
|
|
|
if (m_comparator.size() != v.size())
|
|
|
|
return false;
|
2017-09-18 18:13:17 +02:00
|
|
|
for (std::size_t i = 0; i < v.size(); ++i)
|
2017-02-21 17:05:04 +01:00
|
|
|
if (m_comparator[i] != v[i])
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
2017-07-20 16:57:17 +02:00
|
|
|
std::string describe() const override {
|
2017-05-02 23:51:03 +02:00
|
|
|
return "Equals: " + ::Catch::Detail::stringify( m_comparator );
|
2017-02-21 17:05:04 +01:00
|
|
|
}
|
2020-04-16 15:36:54 +02:00
|
|
|
std::vector<T, AllocComp> const& m_comparator;
|
2017-02-21 17:05:04 +01:00
|
|
|
};
|
|
|
|
|
2020-04-16 15:36:54 +02:00
|
|
|
template<typename T, typename AllocComp, typename AllocMatch>
|
|
|
|
struct ApproxMatcher : MatcherBase<std::vector<T, AllocMatch>> {
|
2019-01-14 15:31:09 +01:00
|
|
|
|
2020-04-16 15:36:54 +02:00
|
|
|
ApproxMatcher(std::vector<T, AllocComp> const& comparator) : m_comparator( comparator ) {}
|
2019-01-14 15:31:09 +01:00
|
|
|
|
2020-04-16 15:36:54 +02:00
|
|
|
bool match(std::vector<T, AllocMatch> const &v) const override {
|
2019-01-14 15:31:09 +01:00
|
|
|
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 <typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
|
|
|
ApproxMatcher& epsilon( T const& newEpsilon ) {
|
|
|
|
approx.epsilon(newEpsilon);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
template <typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
|
|
|
ApproxMatcher& margin( T const& newMargin ) {
|
|
|
|
approx.margin(newMargin);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
template <typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
|
|
|
ApproxMatcher& scale( T const& newScale ) {
|
|
|
|
approx.scale(newScale);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2020-04-16 15:36:54 +02:00
|
|
|
std::vector<T, AllocComp> const& m_comparator;
|
2019-01-14 15:31:09 +01:00
|
|
|
mutable Catch::Detail::Approx approx = Catch::Detail::Approx::custom();
|
|
|
|
};
|
|
|
|
|
2020-04-16 15:36:54 +02:00
|
|
|
template<typename T, typename AllocComp, typename AllocMatch>
|
|
|
|
struct UnorderedEqualsMatcher : MatcherBase<std::vector<T, AllocMatch>> {
|
|
|
|
UnorderedEqualsMatcher(std::vector<T, AllocComp> const& target) : m_target(target) {}
|
|
|
|
bool match(std::vector<T, AllocMatch> const& vec) const override {
|
2017-12-07 17:07:25 +01:00
|
|
|
// Note: This is a reimplementation of std::is_permutation,
|
|
|
|
// because I don't want to include <algorithm> inside the common path
|
|
|
|
if (m_target.size() != vec.size()) {
|
|
|
|
return false;
|
|
|
|
}
|
2019-04-19 17:54:21 +02:00
|
|
|
return std::is_permutation(m_target.begin(), m_target.end(), vec.begin());
|
2017-12-07 17:07:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string describe() const override {
|
|
|
|
return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target);
|
|
|
|
}
|
|
|
|
private:
|
2020-04-16 15:36:54 +02:00
|
|
|
std::vector<T, AllocComp> const& m_target;
|
2017-12-07 17:07:25 +01:00
|
|
|
};
|
|
|
|
|
2017-02-21 17:05:04 +01:00
|
|
|
} // namespace Vector
|
|
|
|
|
|
|
|
// The following functions create the actual matcher objects.
|
|
|
|
// This allows the types to be inferred
|
|
|
|
|
2020-04-21 19:09:45 +02:00
|
|
|
template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
|
2020-04-16 15:36:54 +02:00
|
|
|
Vector::ContainsMatcher<T, AllocComp, AllocMatch> Contains( std::vector<T, AllocComp> const& comparator ) {
|
|
|
|
return Vector::ContainsMatcher<T, AllocComp, AllocMatch>( comparator );
|
2017-02-21 17:05:04 +01:00
|
|
|
}
|
|
|
|
|
2020-04-16 15:36:54 +02:00
|
|
|
template<typename T, typename Alloc = std::allocator<T>>
|
|
|
|
Vector::ContainsElementMatcher<T, Alloc> VectorContains( T const& comparator ) {
|
|
|
|
return Vector::ContainsElementMatcher<T, Alloc>( comparator );
|
2017-02-21 17:05:04 +01:00
|
|
|
}
|
|
|
|
|
2020-04-21 19:09:45 +02:00
|
|
|
template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
|
2020-04-16 15:36:54 +02:00
|
|
|
Vector::EqualsMatcher<T, AllocComp, AllocMatch> Equals( std::vector<T, AllocComp> const& comparator ) {
|
|
|
|
return Vector::EqualsMatcher<T, AllocComp, AllocMatch>( comparator );
|
2017-02-21 17:05:04 +01:00
|
|
|
}
|
|
|
|
|
2020-04-21 19:09:45 +02:00
|
|
|
template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
|
2020-04-16 15:36:54 +02:00
|
|
|
Vector::ApproxMatcher<T, AllocComp, AllocMatch> Approx( std::vector<T, AllocComp> const& comparator ) {
|
|
|
|
return Vector::ApproxMatcher<T, AllocComp, AllocMatch>( comparator );
|
2019-01-14 15:31:09 +01:00
|
|
|
}
|
|
|
|
|
2020-04-21 19:09:45 +02:00
|
|
|
template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
|
2020-04-16 15:36:54 +02:00
|
|
|
Vector::UnorderedEqualsMatcher<T, AllocComp, AllocMatch> UnorderedEquals(std::vector<T, AllocComp> const& target) {
|
|
|
|
return Vector::UnorderedEqualsMatcher<T, AllocComp, AllocMatch>( target );
|
2017-12-07 17:07:25 +01:00
|
|
|
}
|
|
|
|
|
2017-02-21 17:05:04 +01:00
|
|
|
} // namespace Matchers
|
|
|
|
} // namespace Catch
|
|
|
|
|
|
|
|
#endif // TWOBLUECUBES_CATCH_MATCHERS_VECTOR_H_INCLUDED
|