Cleanup vector matchers

Once again, added doxygen comments and removed the inner-most namespace.
This commit is contained in:
Martin Hořeňovský 2020-03-28 15:17:12 +01:00
parent 904c47a634
commit ca5af2e85b
No known key found for this signature in database
GPG Key ID: DE48307B8B0D381A

View File

@ -16,164 +16,172 @@
namespace Catch { namespace Catch {
namespace Matchers { namespace Matchers {
namespace Vector { template<typename T>
template<typename T> struct ContainsElementMatcher final : MatcherBase<std::vector<T>> {
struct ContainsElementMatcher final : MatcherBase<std::vector<T>> {
ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {} ContainsElementMatcher(T const& comparator):
m_comparator(comparator)
{}
bool match(std::vector<T> const &v) const override { bool match(std::vector<T> const& v) const override {
for (auto const& el : v) { for (auto const& el : v) {
if (el == m_comparator) { if (el == m_comparator) {
return true; return true;
}
}
return false;
}
std::string describe() const override {
return "Contains: " + ::Catch::Detail::stringify( m_comparator );
}
T const& m_comparator;
};
template<typename T>
struct ContainsMatcher final : MatcherBase<std::vector<T>> {
ContainsMatcher(std::vector<T> const& comparator):
m_comparator(comparator)
{}
bool match(std::vector<T> 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<T> const& m_comparator;
};
template<typename T>
struct EqualsMatcher final : MatcherBase<std::vector<T>> {
EqualsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {}
bool match(std::vector<T> 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<T> 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<T> const& m_comparator;
};
template<typename T>
struct ApproxMatcher final : MatcherBase<std::vector<T>> {
ApproxMatcher(std::vector<T> const& comparator) : m_comparator( comparator ) {}
bool match(std::vector<T> 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 <typename = std::enable_if_t<std::is_constructible<double, T>::value>>
ApproxMatcher& epsilon( T const& newEpsilon ) {
approx.epsilon(newEpsilon);
return *this;
}
template <typename = std::enable_if_t<std::is_constructible<double, T>::value>>
ApproxMatcher& margin( T const& newMargin ) {
approx.margin(newMargin);
return *this;
}
template <typename = std::enable_if_t<std::is_constructible<double, T>::value>>
ApproxMatcher& scale( T const& newScale ) {
approx.scale(newScale);
return *this;
}
std::vector<T> const& m_comparator;
mutable Catch::Approx approx = Catch::Approx::custom();
};
template<typename T>
struct UnorderedEqualsMatcher final : MatcherBase<std::vector<T>> {
UnorderedEqualsMatcher(std::vector<T> const& target) : m_target(target) {}
bool match(std::vector<T> const& vec) const override {
// 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; return false;
} }
return std::is_permutation(m_target.begin(), m_target.end(), vec.begin());
}
std::string describe() const override { std::string describe() const override {
return "Contains: " + ::Catch::Detail::stringify( m_comparator ); return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target);
} }
private:
std::vector<T> const& m_target;
};
T const& m_comparator;
};
template<typename T>
struct ContainsMatcher final : MatcherBase<std::vector<T>> {
ContainsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {}
bool match(std::vector<T> 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<T> const& m_comparator;
};
template<typename T>
struct EqualsMatcher final : MatcherBase<std::vector<T>> {
EqualsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {}
bool match(std::vector<T> 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<T> 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<T> const& m_comparator;
};
template<typename T>
struct ApproxMatcher final : MatcherBase<std::vector<T>> {
ApproxMatcher(std::vector<T> const& comparator) : m_comparator( comparator ) {}
bool match(std::vector<T> 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 <typename = std::enable_if_t<std::is_constructible<double, T>::value>>
ApproxMatcher& epsilon( T const& newEpsilon ) {
approx.epsilon(newEpsilon);
return *this;
}
template <typename = std::enable_if_t<std::is_constructible<double, T>::value>>
ApproxMatcher& margin( T const& newMargin ) {
approx.margin(newMargin);
return *this;
}
template <typename = std::enable_if_t<std::is_constructible<double, T>::value>>
ApproxMatcher& scale( T const& newScale ) {
approx.scale(newScale);
return *this;
}
std::vector<T> const& m_comparator;
mutable Catch::Approx approx = Catch::Approx::custom();
};
template<typename T>
struct UnorderedEqualsMatcher final : MatcherBase<std::vector<T>> {
UnorderedEqualsMatcher(std::vector<T> const& target) : m_target(target) {}
bool match(std::vector<T> const& vec) const override {
// 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;
}
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<T> const& m_target;
};
} // namespace Vector
// The following functions create the actual matcher objects. // The following functions create the actual matcher objects.
// This allows the types to be inferred // This allows the types to be inferred
//! Creates a matcher that matches vectors that contain all elements in `comparator`
template<typename T> template<typename T>
Vector::ContainsMatcher<T> Contains( std::vector<T> const& comparator ) { ContainsMatcher<T> Contains( std::vector<T> const& comparator ) {
return Vector::ContainsMatcher<T>( comparator ); return ContainsMatcher<T>( comparator );
} }
//! Creates a matcher that matches vectors that contain `comparator` as an element
template<typename T> template<typename T>
Vector::ContainsElementMatcher<T> VectorContains( T const& comparator ) { ContainsElementMatcher<T> VectorContains( T const& comparator ) {
return Vector::ContainsElementMatcher<T>( comparator ); return ContainsElementMatcher<T>( comparator );
} }
//! Creates a matcher that matches vectors that are exactly equal to `comparator`
template<typename T> template<typename T>
Vector::EqualsMatcher<T> Equals( std::vector<T> const& comparator ) { EqualsMatcher<T> Equals( std::vector<T> const& comparator ) {
return Vector::EqualsMatcher<T>( comparator ); return EqualsMatcher<T>( comparator );
} }
//! Creates a matcher that matches vectors that `comparator` as an element
template<typename T> template<typename T>
Vector::ApproxMatcher<T> Approx( std::vector<T> const& comparator ) { ApproxMatcher<T> Approx( std::vector<T> const& comparator ) {
return Vector::ApproxMatcher<T>( comparator ); return ApproxMatcher<T>( comparator );
} }
//! Creates a matcher that matches vectors that is equal to `target` modulo permutation
template<typename T> template<typename T>
Vector::UnorderedEqualsMatcher<T> UnorderedEquals(std::vector<T> const& target) { UnorderedEqualsMatcher<T> UnorderedEquals(std::vector<T> const& target) {
return Vector::UnorderedEqualsMatcher<T>(target); return UnorderedEqualsMatcher<T>(target);
} }
} // namespace Matchers } // namespace Matchers