-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Matchers interface #1307
Comments
Hey there! I recently started using Catch and stumbled across this question as I too wanted something to emulate the EXPECT_THAT call from Google Test. I wound up writing something that relies on the gsl span type (will be added to the C++ standard in C++20 I believe) The code looks like this:
I'm currently compiling with C++17 which means you get class template argument deduction and can write code like this:
If you're not using C++17 you can wrap the calls in a function to avoid having to use this syntax:
I hope this might be some use or might give you an idea about another approach. |
Tom,
Your suggestion feels like a Catch::Matchers::Vector::Equals<T> but for
span instead of vector.
I believe the Catch convention for something like this (following Vector's
precedent) would be Catch::Matchers::*Span*::Equals<T>.
I wouldn't want to use the term "ElementsAre" here, because it's doing
something significantly different from Googletest's ElementsAre.
That Googletest function takes a sequence of element matchers and returns a
polymorphic matcher that can match any kind of sequence container for an
element-wise match against those element matchers.
https://github.com/google/googletest/blob/master/googlemock/docs/cheat_sheet.md#container-matchers
I feel it's wasteful for Catch2 to require a different variant of Equals
for each kind of sequence container, and that the Catch::Matchers::Vector
namespace is a useful first draft that should be generalized. Instead of
creating an Equals for each container type (vector, span, array, many
more), we would be better off making a Catch::Matcher::Sequence::Equals
template that can produce an element-wise Equals matcher for any sequence
type.
A sequence can be considered logically "equal" to an expected sequence and
still be of different type. This keeps the test author from having to
create a specific container type just to specify expectations. The test
author should be able to do that very concisely with a std::initializer
list, vector, or array, let's say.
…On Tue, Jul 30, 2019 at 4:33 PM Tom Hulton-Harrop ***@***.***> wrote:
Hey there!
I recently started using Catch and stumbled across this question as I too
wanted something to emulate the EXPECT_THAT call from Google Test.
I wound up writing something that relies on the gsl span type (will be
added to the C++ standard in C++20 I believe)
The code looks like this:
#include "catch2/catch.hpp"
#include <sstream>
#include "gsl/span"
template<typename T>
class ElementsAreSpan
: public Catch::MatcherBase<gsl::span<const T>>
{
gsl::span<const T> m_span;
public:
ElementsAreSpan(const T* const t, gsl::index size)
: m_span(t, size) {}
explicit ElementsAreSpan(gsl::span<const T> span)
: m_span(span) {}
bool match(const gsl::span<const T>& span) const override {
return m_span == span;
}
std::string describe() const override {
std::ostringstream ss;
ss << "actual, expected: { ";
for (const auto& element : m_span) {
ss << element << ", ";
}
ss << "}";
return ss.str();
}
};
I'm currently compiling with C++17 which means you get class template
argument deduction and can write code like this:
my_type_t result_end = calculate_something();
const float result_arr[] = {10.0f, 40.0f, 100.0f};
CHECK_THAT(span(result_end_arr), ElementsAreSpan(result_end.elems(), 3));
If you're not using C++17 you can wrap the calls in a function to avoid
having to use this syntax:
CHECK_THAT(span<float>(result_end_arr), ElementsAreSpa<float>n(result_end.elems(), 3));
I hope this might be some use or might give you an idea about another
approach.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#1307?email_source=notifications&email_token=ACBWORG2AA5TBYFAPRWDUI3QCCQRXA5CNFSM4FDK2YZ2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD3FHIXQ#issuecomment-516584542>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ACBWORDLFMR7UDNSSJSSEC3QCCQRXANCNFSM4FDK2YZQ>
.
|
Hey Billy, Thanks for the feedback. For some context, my matcher was just a quick experiment to try and help port some existing tests I had from Google Test to Catch2. I like the Hamcrest style naming of I actually wound up moving away from the I've combined this with You could take this one step further and have two templated types that can both be subscripted but unfortunately, usage gets more complicated with template deductions where you have to wind up manually specifying both types which can be a bit of a pain... So at the moment, I have code that looks like this constexpr real_t x_axis[] = { 1.0f, 0.0f };
CHECK_THAT(make_span(x_axis), make_elements_sub(as::vec2::axis_x(), 2)); // function to avoid needing ctad - naming isn't great :P whereas it could look like this... constexpr real_t x_axis[] = { 1.0f, 1.0f };
auto matcher = make_elements_sub<vec2_t, decltype(x_axis)>(as::vec2::axis_x(), 2); // must be initialized outside CHECK_THAT otherwise you get compile errors about too many arguments provided to function-like macro invocation
CHECK_THAT(x_axis, matcher); but it doesn't look that great either... Do you have an example of what you had in mind? I'd be happy to port my code over to something more idiomatic. Thanks! Tom |
This commit extends the Matchers feature with the ability to have type-independent (e.g. templated) matchers. This is done by adding a new base type that Matchers can extend, `MatcherGenericBase`, and overloads of operators `!`, `&&` and `||` that handle matchers extending `MatcherGenericBase` in a special manner. These new matchers can also take their arguments as values and non-const references. Closes #1307 Closes #1553 Closes #1554 Co-authored-by: Martin Hořeňovský <[email protected]>
This will be possible for Matchers in v3. |
Oh awesome! 😄 Is this something we can do today or in the near future? Thanks! |
You can use it right now from the dev-v3 branch. Check tests for #1843 for examples. |
Hello,
I wanted to extend matchers to cover functionalities known from gmock.
Starting from generic checks like "Contains" or "ElementsAre". Contains is defined for vector now, an cannot be easily extended to support other containers. Writing generic ElementsAre also fails for me.
In gmock they operate on any class that has container-like interface. You just write:
EXPECT_THAT(some_container, ElementsAre(e0, e1, ..., en));
In Catch we must directly specify container type under ElementsAre.
Gmock does this by trying to cast given matcher to expected one - at this point you can write generic conversion operator that will create matcher for specific container.
Maybe REQUIRE_THAT makro should be changed? Or current approach has some advantage that I fail to see?
BR
The text was updated successfully, but these errors were encountered: