Skip to content

Commit 049dc65

Browse files
committed
Custom matchers and Expectation::to
1 parent 7fe4e88 commit 049dc65

File tree

5 files changed

+64
-8
lines changed

5 files changed

+64
-8
lines changed

include/expectations/expectation.hpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,21 @@ class Expectation : public Child {
3737
bool is_positive = true; // Have we been negated?
3838

3939
public:
40+
Expectation(Expectation const &copy)
41+
: // Child(((Expectation)copy).get_parent())
42+
target(copy.target),
43+
block(copy.block),
44+
has_block(copy.has_block),
45+
is_positive(copy.is_positive){};
46+
4047
/**
4148
* @brief Create an Expectation using a value.
4249
*
4350
* @param value The target to test, an explicit value.
4451
*
4552
* @return The constructed Expectation.
4653
*/
47-
Expectation(ItBase &it, A &value) : Child(it), target(value) {}
54+
Expectation(ItBase &it, A value) : Child(it), target(value) {}
4855

4956
/**
5057
* @brief Create an Expectation using a function.
@@ -81,6 +88,9 @@ class Expectation : public Child {
8188

8289
Expectation &not_();
8390

91+
template <class M>
92+
bool to(M matcher, std::string msg = "");
93+
8494
bool to_be(std::function<bool(A)>, std::string msg = "");
8595
bool to_be_null(std::string msg = "");
8696
bool to_be_true(std::string msg = "");
@@ -107,7 +117,7 @@ class Expectation : public Child {
107117
*/
108118
template <typename A>
109119
Expectation<A> &Expectation<A>::not_() {
110-
is_positive = not is_positive;
120+
this->is_positive = not this->is_positive;
111121
return *this;
112122
}
113123

@@ -244,6 +254,18 @@ Matchers::BeWithin<A, E> Expectation<A>::to_be_within(E expected,
244254
matcher.set_message(msg);
245255
return matcher;
246256
}
257+
258+
template <typename A>
259+
template <class M>
260+
bool Expectation<A>::to(M matcher, std::string msg) {
261+
static_assert(
262+
std::is_base_of<Matchers::BaseMatcher<A, typename M::expected_t>,
263+
M>::value,
264+
"Matcher is not a subclass of BaseMatcher.");
265+
// auto base_matcher = static_cast<Matchers::BaseMatcher<A,typename
266+
// M::expected_t>>(matcher);
267+
return matcher.set_message(msg).run();
268+
}
247269
}
248270

249271
#endif /* EXPECTATION_H */

include/matchers/basematcher.hpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,14 @@ class BaseMatcher : public Runnable, public Pretty {
4141
virtual std::string description();
4242
Actual &get_actual() { return expectation.get_target(); }
4343
Expected &get_expected() { return expected; }
44+
Expectation<Actual> &get_expectation() { return expectation; }
4445
virtual BaseMatcher &set_message(std::string message) {
4546
this->message = message;
4647
return *this;
4748
}
4849
bool run() override;
50+
51+
typedef Expected expected_t;
4952
};
5053

5154
template <typename A, typename E>
@@ -65,7 +68,9 @@ std::string BaseMatcher<A, E>::failure_message_when_negated() {
6568
template <typename A, typename E>
6669
std::string BaseMatcher<A, E>::description() {
6770
std::stringstream ss;
68-
ss << this->name_to_sentance() << this->to_sentance(expected);
71+
std::string pretty_expected = this->to_sentance(expected);
72+
ss << "match " << this->name_to_sentance(Util::demangle(typeid(*this).name()))
73+
<< "(" << pretty_expected.substr(1, pretty_expected.length()) << ")";
6974
return ss.str();
7075
}
7176

include/matchers/pretty_matchers.hpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ class BaseMatcher;
1919
*/
2020
struct Pretty {
2121
std::string _name = "";
22-
std::string name();
23-
std::string name_to_sentance();
22+
std::string name(std::string name);
23+
std::string name_to_sentance(std::string name);
2424
static std::string split_words(std::string sym);
2525
static std::string underscore(std::string camel_cased_word);
2626
static std::string last(const std::string &s, const char delim);
@@ -164,11 +164,13 @@ std::string Pretty::to_word_type(T &item) {
164164
return word;
165165
}
166166

167-
std::string Pretty::name_to_sentance() { return split_words(name()); }
167+
std::string Pretty::name_to_sentance(std::string n) {
168+
return split_words(name(n));
169+
}
168170

169-
std::string Pretty::name() {
171+
std::string Pretty::name(std::string name) {
170172
if (_name.empty()) {
171-
return last(typeid(this).name(), ':');
173+
return last(name, ':');
172174
} else {
173175
return _name;
174176
}

spec/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ add_executable( describe_a_spec describe_a_spec.cpp )
66
target_link_libraries( describe_a_spec c++spec ${CMAKE_THREAD_LIBS_INIT} )
77
add_test ( describe_a_spec describe_a_spec )
88

9+
add_executable( expectation_spec expectations/expectation_spec.cpp )
10+
target_link_libraries( expectation_spec c++spec ${CMAKE_THREAD_LIBS_INIT} )
11+
add_test ( expectation_spec expectation_spec )
12+
13+
914
add_executable( be_within_spec matchers/be_within_spec.cpp )
1015
target_link_libraries( be_within_spec c++spec ${CMAKE_THREAD_LIBS_INIT} )
1116
add_test ( be_within_spec be_within_spec )
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#include "cppspec.hpp"
2+
3+
// Very simple int<=>int custom matcher
4+
struct CustomMatcher : public Matchers::BaseMatcher<int, int> {
5+
CustomMatcher(CustomMatcher const &copy)
6+
: Matchers::BaseMatcher<int,int>(((CustomMatcher)copy).get_expectation(),
7+
((CustomMatcher)copy).get_expected()){};
8+
CustomMatcher(Expectations::Expectation<int> &expectation, int expected)
9+
: Matchers::BaseMatcher<int,int>(expectation, expected){};
10+
bool match() { return get_expected() == get_actual(); }
11+
};
12+
13+
describe expectation_spec("Expectation", $ {
14+
context("Extensible .to", _ {
15+
it("accepts a custom BaseMatcher subclass", _ {
16+
auto e = expect(2);
17+
e.to(CustomMatcher(e, 4));
18+
});
19+
});
20+
});
21+
22+
int main() { return expectation_spec.run() ? EXIT_SUCCESS : EXIT_FAILURE; }

0 commit comments

Comments
 (0)