Skip to content

Commit

Permalink
Add in_interval matcher
Browse files Browse the repository at this point in the history
  • Loading branch information
jimporter committed Feb 25, 2024
1 parent bda6660 commit 54518c8
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 0 deletions.
10 changes: 10 additions & 0 deletions doc/built-in-matchers.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,16 @@ according to the `<` operator.
A matcher that returns `true` when the actual value is less than or equal to
`value` according to the `<=` operator.
### in_interval(*low*, *high*[, *bounds*])
A matcher that returns `true` when the actual value is between `low` and `high`.
`bounds` can be one of the following:
* `interval::closed`: expects `low <= actual <= high`
* `interval::left_open`: expects `low < actual <= high`
* `interval::right_open`: expects `low <= actual < high` (the default)
* `interval::open`: expects `low < actual < high`
## Arithmetic
*&lt;mettle/matchers/arithmetic.hpp&gt;*
{: .subtitle}
Expand Down
56 changes: 56 additions & 0 deletions include/mettle/matchers/relational.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,62 @@ namespace mettle {
return basic_matcher(std::forward<T>(expected), std::less_equal<>(), "<= ");
}

enum class interval {
closed = 0b00,
left_open = 0b10,
right_open = 0b01,
open = 0b11
};

template<typename Low, typename High>
class in_interval : public matcher_tag {
public:
in_interval(detail::any_capture<Low> low, detail::any_capture<High> high,
interval bounds = interval::right_open) :
low_(std::move(low)), high_(std::move(high)), bounds_(bounds) {}

template<typename U>
bool operator ()(U &&actual) const {
if (left_open()) {
if (actual <= low_.value) return false;
} else {
if (actual < low_.value) return false;
}

if (right_open()) {
if (actual >= high_.value) return false;
} else {
if (actual > high_.value) return false;
}

return true;
}

std::string desc() const {
std::ostringstream ss;
ss << "in " << (left_open() ? "(" : "[") << to_printable(low_.value)
<< " .. " << to_printable(high_.value) << (right_open() ? ")" : "]");
return ss.str();
}
private:
inline bool left_open() const {
return static_cast<int>(bounds_) & static_cast<int>(interval::left_open);
}

inline bool right_open() const {
return static_cast<int>(bounds_) & static_cast<int>(interval::right_open);
}

detail::any_capture<Low> low_;
detail::any_capture<High> high_;
interval bounds_;
};

template<typename Low, typename High>
in_interval(Low &&, High &&) -> in_interval<Low, High>;
template<typename Low, typename High>
in_interval(Low &&, High &&, interval) -> in_interval<Low, High>;

} // namespace mettle

#endif
39 changes: 39 additions & 0 deletions test/matchers/test_matchers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,45 @@ suite<> test_matchers("matchers", [](auto &_) {

expect(less_equal(123).desc(), equal_to("<= 123"));
});

subsuite<>(_, "in_interval()", [](auto &_) {
_.test("right_open", []() {
expect(123, in_interval(100, 200));
expect(100, in_interval(100, 200));
expect(200, is_not(in_interval(100, 200)));
expect(in_interval(100, 200).desc(), equal_to("in [100 .. 200)"));

expect(123, in_interval(100, 200, interval::right_open));
expect(100, in_interval(100, 200, interval::right_open));
expect(200, is_not(in_interval(100, 200, interval::right_open)));
expect(in_interval(100, 200, interval::right_open).desc(),
equal_to("in [100 .. 200)"));
});

_.test("left_open", [] () {
expect(123, in_interval(100, 200, interval::left_open));
expect(100, is_not(in_interval(100, 200, interval::left_open)));
expect(200, in_interval(100, 200, interval::left_open));
expect(in_interval(100, 200, interval::left_open).desc(),
equal_to("in (100 .. 200]"));
});

_.test("open", [] () {
expect(123, in_interval(100, 200, interval::open));
expect(100, is_not(in_interval(100, 200, interval::open)));
expect(200, is_not(in_interval(100, 200, interval::open)));
expect(in_interval(100, 200, interval::open).desc(),
equal_to("in (100 .. 200)"));
});

_.test("closed", [] () {
expect(123, in_interval(100, 200, interval::closed));
expect(100, in_interval(100, 200, interval::closed));
expect(200, in_interval(100, 200, interval::closed));
expect(in_interval(100, 200, interval::closed).desc(),
equal_to("in [100 .. 200]"));
});
});
});

subsuite<>(_, "arithmetic", [](auto &_) {
Expand Down

0 comments on commit 54518c8

Please sign in to comment.