auto sorted(T &&compare) { return make_matcher( std::forward<T>(compare), [](const auto &value, auto &&compare) { return std::is_sorted(std::begin(value), std::end(value), compare); }, "sorted by "); }
auto near_to_abs(T &&expected, const T &tolerance) { return make_matcher( std::forward<T>(expected), [tolerance](const auto &actual, const auto &expected) -> bool { return std::abs(actual - expected) <= tolerance; }, "~= " ); }
auto near_to(T &&expected, const T &epsilon) { return make_matcher( std::forward<T>(expected), [epsilon](const auto &actual, const auto &expected) -> bool { // If one of expected or actual is NaN, mag is undefined, but that's ok // because we'll always return false in that case, just like we should. auto mag = std::max<T>(std::abs(expected), std::abs(actual)); return std::abs(actual - expected) <= mag * epsilon; }, "~= " ); }
inline auto thrown() { return make_matcher([](auto &&value) -> match_result { try { value(); return {false, "threw nothing"}; } catch(const std::exception &e) { std::ostringstream ss; ss << "threw " << to_printable(e); return {true, ss.str()}; } catch(...) { return {true, "threw unknown exception"}; } }, "threw exception"); }
inline auto sorted() { return make_matcher([](const auto &value) { return std::is_sorted(std::begin(value), std::end(value)); }, "sorted"); }