Skip to content

Commit

Permalink
Merge pull request #271 from eranpeer/approx-matcher
Browse files Browse the repository at this point in the history
Added an ApproxEq matcher.
  • Loading branch information
FranckRJ committed May 20, 2022
2 parents 9e7a657 + 54a6e0b commit a64f1c7
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 0 deletions.
52 changes: 52 additions & 0 deletions include/fakeit/argument_matchers.hpp
Expand Up @@ -434,6 +434,50 @@ namespace fakeit {
return new Matcher(std::forward<ExpectedTRef>(this->_expectedRef));
}
};

template<typename ExpectedTRef, typename ExpectedMarginTRef>
struct ApproxEqCreator {
using ExpectedT = typename naked_type<ExpectedTRef>::type;
using ExpectedMarginT = typename naked_type<ExpectedMarginTRef>::type;

template <typename ActualT, typename = void>
struct IsTypeCompatible : std::false_type {};

template <typename ActualT>
struct IsTypeCompatible<ActualT, fk_void_t<decltype(std::abs(std::declval<ActualT>() - std::declval<ExpectedT>()) <= std::declval<ExpectedMarginT>())>> : std::true_type {};

ExpectedTRef _expectedRef;
ExpectedMarginTRef _expectedMarginRef;

template <typename T, typename U>
ApproxEqCreator(T &&expectedRef, U &&expectedMarginRef)
: _expectedRef(std::forward<T>(expectedRef))
, _expectedMarginRef(std::forward<U>(expectedMarginRef)) {
}

template<typename ActualT>
TypedMatcher<ActualT> *createMatcher() const {
struct Matcher : public TypedMatcher<ActualT> {
const ExpectedT _expected;
const ExpectedMarginT _expectedMargin;

Matcher(ExpectedTRef expected, ExpectedMarginTRef expectedMargin)
: _expected{std::forward<ExpectedTRef>(expected)}
, _expectedMargin{std::forward<ExpectedMarginTRef>(expectedMargin)} {
}

virtual std::string format() const override {
return TypeFormatter<ExpectedT>::format(this->_expected) + std::string("+/-") + TypeFormatter<ExpectedMarginT>::format(this->_expectedMargin);
}

virtual bool matches(const ActualT &actual) const override {
return std::abs(actual - this->_expected) <= this->_expectedMargin;
}
};

return new Matcher(std::forward<ExpectedTRef>(this->_expectedRef), std::forward<ExpectedMarginTRef>(this->_expectedMarginRef));
}
};
}

struct AnyMatcher {
Expand Down Expand Up @@ -547,4 +591,12 @@ namespace fakeit {
return mc;
}

template<typename T, typename U,
typename std::enable_if<std::is_arithmetic<typename naked_type<T>::type>::value, int>::type = 0,
typename std::enable_if<std::is_arithmetic<typename naked_type<U>::type>::value, int>::type = 0>
internal::ApproxEqCreator<T&&, U&&> ApproxEq(T &&expected, U &&margin) {
internal::ApproxEqCreator<T&&, U&&> mc(std::forward<T>(expected), std::forward<U>(margin));
return mc;
}

}
33 changes: 33 additions & 0 deletions tests/argument_matching_tests.cpp
Expand Up @@ -38,6 +38,7 @@ struct ArgumentMatchingTests: tpunit::TestFixture {
TEST(ArgumentMatchingTests::test_str_eq_matcher), TEST(ArgumentMatchingTests::test_str_gt_matcher),
TEST(ArgumentMatchingTests::test_str_ge_matcher), TEST(ArgumentMatchingTests::test_str_lt_matcher),
TEST(ArgumentMatchingTests::test_str_le_matcher), TEST(ArgumentMatchingTests::test_str_ne_matcher),
TEST(ArgumentMatchingTests::test_approx_eq_matcher),
TEST(ArgumentMatchingTests::test_any_matcher), TEST(ArgumentMatchingTests::test_any_matcher2),
TEST(ArgumentMatchingTests::test_any_matcher3),
TEST(ArgumentMatchingTests::pass_reference_by_value),
Expand All @@ -48,6 +49,7 @@ struct ArgumentMatchingTests: tpunit::TestFixture {
TEST(ArgumentMatchingTests::format_StrEq), TEST(ArgumentMatchingTests::format_StrGt),
TEST(ArgumentMatchingTests::format_StrGe), TEST(ArgumentMatchingTests::format_StrLt),
TEST(ArgumentMatchingTests::format_StrLe), TEST(ArgumentMatchingTests::format_StrNe),
TEST(ArgumentMatchingTests::format_ApproxEq),
TEST(ArgumentMatchingTests::test_move_only_type), TEST(ArgumentMatchingTests::test_no_slicing)
) //
{
Expand Down Expand Up @@ -76,6 +78,7 @@ struct ArgumentMatchingTests: tpunit::TestFixture {
virtual int strfunc(const char*) = 0;
virtual int funcMoveOnly(MoveOnlyType) = 0;
virtual int funcSlicing(const Base&) = 0;
virtual int funcDouble(double) = 0;
};

void mixed_matchers() {
Expand Down Expand Up @@ -292,6 +295,20 @@ struct ArgumentMatchingTests: tpunit::TestFixture {
Verify(Method(mock, strfunc).Using(StrNe("second"))).Once();
}

void test_approx_eq_matcher() {
Mock<SomeInterface> mock;

When(Method(mock, funcDouble).Using(ApproxEq(5, 0.2))).Return(1);
When(Method(mock, funcDouble).Using(ApproxEq(7., 1))).Return(2);

SomeInterface& i = mock.get();
ASSERT_EQUAL(1, i.funcDouble(5.1));
ASSERT_EQUAL(2, i.funcDouble(6.5));

Verify(Method(mock, funcDouble).Using(ApproxEq(5, 0.2))).Once();
Verify(Method(mock, funcDouble).Using(ApproxEq(7., 1))).Once();
}

void test_any_matcher() {

Mock<SomeInterface> mock;
Expand Down Expand Up @@ -551,6 +568,22 @@ struct ArgumentMatchingTests: tpunit::TestFixture {
}
}

void format_ApproxEq() {
Mock<SomeInterface> mock;
try {
fakeit::Verify(Method(mock, funcDouble).Using(ApproxEq(5, 0.1))).setFileInfo("test file", 1, "test method").Exactly(Once);
} catch (SequenceVerificationException& e) {
std::string expectedMsg{ formatLineNumner("test file", 1) };
expectedMsg += ": Verification error\n";
expectedMsg += "Expected pattern: mock.funcDouble(5+/-0.1)\n";
expectedMsg += "Expected matches: exactly 1\n";
expectedMsg += "Actual matches : 0\n";
expectedMsg += "Actual sequence : total of 0 actual invocations.";
std::string actualMsg { to_string(e) };
ASSERT_EQUAL(expectedMsg, actualMsg);
}
}

void test_move_only_type() {
Mock<SomeInterface> mock;

Expand Down

0 comments on commit a64f1c7

Please sign in to comment.