|
1 |
| -/** @file */ |
| 1 | +/** |
| 2 | + * Copyright 2016 Katherine Whitlock |
| 3 | + * |
| 4 | + * @file matcher_base.hpp |
| 5 | + * @brief Contains the base class for all Matchers |
| 6 | + * |
| 7 | + * @author Katherine Whitlock (toroidalcode) |
| 8 | + */ |
| 9 | + |
2 | 10 | #ifndef CPPSPEC_MATCHERS_MATCHER_BASE_HPP
|
3 | 11 | #define CPPSPEC_MATCHERS_MATCHER_BASE_HPP
|
4 | 12 | #pragma once
|
5 | 13 |
|
6 | 14 | #include <string>
|
7 |
| -#include "pretty_matchers.hpp" |
8 | 15 | #include "expectations/handler.hpp"
|
9 | 16 | #include "it_base.hpp"
|
| 17 | +#include "pretty_matchers.hpp" |
10 | 18 |
|
11 | 19 | namespace CppSpec {
|
12 | 20 |
|
13 | 21 | template <class T>
|
14 |
| -class Expectation; |
| 22 | +class Expectation; // Forward declaration of Expectation |
15 | 23 |
|
16 | 24 | namespace Matchers {
|
17 | 25 |
|
| 26 | +/** |
| 27 | + * @brief the base class for all Matcher classes and objects |
| 28 | + * |
| 29 | + * @tparam Actual the type of Actual 'thing' to match against |
| 30 | + * in the context of `expect(2)`, it would be `int` |
| 31 | + * |
| 32 | + * @tparam Expected the type of Expected 'thing' to match for |
| 33 | + * in the contet of `expect(2).to_equal(2.0)`, |
| 34 | + * it would be `float` |
| 35 | + */ |
18 | 36 | template <typename Actual, typename Expected>
|
19 | 37 | class MatcherBase : public Runnable, public Pretty {
|
20 | 38 | std::string custom_failure_message = "";
|
21 | 39 |
|
22 | 40 | protected:
|
23 |
| - Expected expected; |
| 41 | + Expected expected; // The expected object contained by the matcher |
| 42 | + |
| 43 | + // A reference to the Expectation (i.e. `expect(2)`) |
24 | 44 | Expectation<Actual> ℰ
|
25 | 45 |
|
26 | 46 | public:
|
| 47 | + // Copy constructor |
27 | 48 | MatcherBase(MatcherBase<Actual, Expected> const ©) = default;
|
28 | 49 |
|
| 50 | + // Constructor when matcher has no 'object' to match for |
29 | 51 | explicit MatcherBase(Expectation<Actual> &expectation)
|
30 | 52 | : Runnable(*expectation.get_parent()), // We want the parent of the
|
31 | 53 | // matcher to be the `it` block,
|
32 | 54 | // not the
|
33 | 55 | // Expectation.
|
34 | 56 | expectation(expectation) {}
|
35 | 57 |
|
| 58 | + // Constructor when the matcher has an object to match for. This is the most |
| 59 | + // commonly used constructor |
36 | 60 | MatcherBase(Expectation<Actual> &expectation, Expected expected)
|
37 | 61 | : Runnable(*expectation.get_parent()),
|
38 | 62 | expected(expected),
|
39 | 63 | expectation(expectation) {}
|
40 | 64 |
|
41 |
| - // TODO: match and negated match should return Result |
42 |
| - virtual bool match() = 0; |
43 |
| - virtual bool negated_match() { return !match(); } |
| 65 | + /*--------- Helper functions -------------*/ |
| 66 | + |
44 | 67 | virtual std::string failure_message();
|
45 | 68 | virtual std::string failure_message_when_negated();
|
46 | 69 | virtual std::string description();
|
| 70 | + |
| 71 | + // Get the 'actual' object from the Expectation |
47 | 72 | Actual &get_actual() { return expectation.get_target(); }
|
| 73 | + |
| 74 | + // Get the 'expected' object from the Matcher |
48 | 75 | Expected &get_expected() { return expected; }
|
| 76 | + |
| 77 | + // Get the Expectation itself |
49 | 78 | Expectation<Actual> &get_expectation() { return expectation; }
|
| 79 | + |
| 80 | + // Set the message to give on match failure |
50 | 81 | virtual MatcherBase &set_message(std::string message);
|
| 82 | + |
| 83 | + /*--------- Primary functions -------------*/ |
| 84 | + |
| 85 | + // Run the matcher |
51 | 86 | Result run(Formatters::BaseFormatter &printer) override;
|
| 87 | + |
| 88 | + // TODO: match and negated match should return Result |
| 89 | + virtual bool match() = 0; |
| 90 | + virtual bool negated_match() { return !match(); } |
| 91 | + |
| 92 | + // typedef Expected |
52 | 93 | typedef Expected expected_t;
|
53 | 94 | };
|
54 | 95 |
|
| 96 | +/** |
| 97 | + * @brief Set a custom failure message |
| 98 | + * |
| 99 | + * @param message the message to give |
| 100 | + * @return the modified Matcher |
| 101 | + */ |
55 | 102 | template <typename A, typename E>
|
56 | 103 | MatcherBase<A, E> &MatcherBase<A, E>::set_message(std::string message) {
|
57 | 104 | this->custom_failure_message = message;
|
58 | 105 | return *this;
|
59 | 106 | }
|
60 | 107 |
|
| 108 | +/** |
| 109 | + * @brief Get message to give on match failure |
| 110 | + * |
| 111 | + * @return the message |
| 112 | + */ |
61 | 113 | template <typename A, typename E>
|
62 | 114 | std::string MatcherBase<A, E>::failure_message() {
|
63 | 115 | if (not custom_failure_message.empty()) {
|
64 | 116 | return this->custom_failure_message;
|
65 | 117 | } else {
|
66 | 118 | std::stringstream ss;
|
67 |
| - ss << "expected " << Pretty::to_word(get_actual()) << " to " << description(); |
| 119 | + ss << "expected " << Pretty::to_word(get_actual()) << " to " |
| 120 | + << description(); |
68 | 121 | return ss.str();
|
69 | 122 | }
|
70 | 123 | }
|
71 | 124 |
|
| 125 | +/** |
| 126 | +* @brief Get message to give on match failure when negated |
| 127 | +* |
| 128 | +* @return the message |
| 129 | +*/ |
72 | 130 | template <typename A, typename E>
|
73 | 131 | std::string MatcherBase<A, E>::failure_message_when_negated() {
|
74 | 132 | if (not custom_failure_message.empty()) {
|
75 | 133 | return this->custom_failure_message;
|
76 | 134 | } else {
|
77 | 135 | std::stringstream ss;
|
78 |
| - ss << "expected " << Pretty::to_word(get_actual()) << " to not " << description(); |
| 136 | + ss << "expected " << Pretty::to_word(get_actual()) << " to not " |
| 137 | + << description(); |
79 | 138 | return ss.str();
|
80 | 139 | }
|
81 | 140 | }
|
82 | 141 |
|
| 142 | +/** |
| 143 | +* @brief Get the description of the Matcher |
| 144 | +* |
| 145 | +* @return the description |
| 146 | +*/ |
83 | 147 | template <typename A, typename E>
|
84 | 148 | std::string MatcherBase<A, E>::description() {
|
85 | 149 | std::stringstream ss;
|
86 | 150 | std::string pretty_expected = this->to_sentance(expected);
|
87 |
| -// ss << "match " << this->name_to_sentance(Util::demangle(typeid(*this).name())) |
88 |
| -// << "(" << pretty_expected.substr(1, pretty_expected.length()) << ")"; |
| 151 | + // ss << "match " << |
| 152 | + // this->name_to_sentance(Util::demangle(typeid(*this).name())) |
| 153 | + // << "(" << pretty_expected.substr(1, pretty_expected.length()) << ")"; |
89 | 154 | ss << "match" << Pretty::to_sentance(expected);
|
90 | 155 | return ss.str();
|
91 | 156 | }
|
92 | 157 |
|
| 158 | +/** |
| 159 | + * @brief Run the Matcher object |
| 160 | + * |
| 161 | + * @param printer the formatter to print using |
| 162 | + * |
| 163 | + * @return the Result of running the Matcher |
| 164 | + */ |
93 | 165 | template <typename A, typename E>
|
94 | 166 | Result MatcherBase<A, E>::run(Formatters::BaseFormatter &printer) {
|
95 | 167 | ItBase *par = static_cast<ItBase *>(this->get_parent());
|
96 | 168 | // If we need a description for our test, generate it
|
97 | 169 | // unless we're ignoring the output.
|
98 | 170 | if (par->needs_description() && !expectation.get_ignore_failure()) {
|
99 | 171 | std::stringstream ss;
|
100 |
| - ss << (expectation.get_sign() |
101 |
| - ? PositiveExpectationHandler::verb() |
102 |
| - : NegativeExpectationHandler::verb()) |
| 172 | + ss << (expectation.get_sign() ? PositiveExpectationHandler::verb() |
| 173 | + : NegativeExpectationHandler::verb()) |
103 | 174 | << " " << this->description();
|
104 | 175 | std::string ss_str = ss.str();
|
105 | 176 | par->set_description(ss_str);
|
106 | 177 | }
|
107 | 178 |
|
108 |
| - Result matched = |
109 |
| - expectation.get_sign() |
110 |
| - ? PositiveExpectationHandler::handle_matcher<A>(*this) |
111 |
| - : NegativeExpectationHandler::handle_matcher<A>(*this); |
| 179 | + Result matched = expectation.get_sign() |
| 180 | + ? PositiveExpectationHandler::handle_matcher(*this) |
| 181 | + : NegativeExpectationHandler::handle_matcher(*this); |
112 | 182 |
|
113 | 183 | // If our items didn't match, we obviously failed.
|
114 | 184 | // Only report the failure if we aren't actively ignoring it.
|
|
0 commit comments