2015/07/22 修正:タイトルが致命的なまでに間違っていました(内容自体に修正はありません)
タイトルのとおり
boost.testには、二つの値が等しいかをテストするマクロBOOST_CHECK_EQUALがあります。また、その配列バージョンに、要素ごとに等しいかのテストを行うBOOST_CHECK_EQUAL_COLLECTIONSというマクロもあります。
また、実数型の演算は誤差が発生する可能性があるので、誤差を考慮したうえで、正しい値になっているかを確認する必要があります。その時に使う誤差を許容して比較するマクロ、BOOST_CHECK_CLOSEはありますが、残念なことにその配列バージョンはありません。
ないなら作ればいいじゃないかということで、作りました。
ついでに、配列のbeginとendを指定するのが冗長だったので、そのあたりの処理もマクロにしました。
# include <boost/type_traits.hpp>
namespace boost {
namespace test_tools {
namespace tt_detail {
struct close_coll_impl {
template <typename Left, typename Right, typename ToleranceType>
assertion_result operator()(Left left_begin, Left left_end, Right right_begin,
Right right_end, ToleranceType tolerance) {
assertion_result pr(true);
std::size_t pos = 0;
math::fpc::close_at_tolerance<typename comp_supertype<
boost::remove_reference<decltype(*Left())>::type,
boost::remove_reference<decltype(*Right())>::type>::type>
pred(tolerance, math::fpc::FPC_STRONG);
for (; left_begin != left_end && right_begin != right_end;
++left_begin, ++right_begin, ++pos) {
if (!pred(*left_begin, *right_begin)) {
pr = false;
pr.message() << "\nMismatch at position " << pos << ": "
<< ::boost::test_tools::tt_detail::print_helper(
*left_begin)
<< " != " << ::boost::test_tools::tt_detail::print_helper(
*right_begin);
}
}
if (left_begin != left_end) {
std::size_t r_size = pos;
while (left_begin != left_end) {
++pos;
++left_begin;
}
pr = false;
pr.message() << "\nCollections size mismatch: " << pos
<< " != " << r_size;
}
if (right_begin != right_end) {
std::size_t l_size = pos;
while (right_begin != right_end) {
++pos;
++right_begin;
}
pr = false;
pr.message() << "\nCollections size mismatch: " << l_size
<< " != " << pos;
}
return pr;
}
};
}
}
}
//---------------------------------------------------------------------------
# define BOOST_WARN_CLOSE_COLLECTIONS(L_begin, L_end, R_begin, R_end, T) \
BOOST_TEST_TOOL_IMPL(1, ::boost::test_tools::tt_detail::close_coll_impl(), \
"", WARN, CHECK_EQUAL_COLL, \
(L_begin)(L_end)(R_begin)(R_end)( \
::boost::math::fpc::percent_tolerance(T))) /**/
# define BOOST_CHECK_CLOSE_COLLECTIONS(L_begin, L_end, R_begin, R_end, T) \
BOOST_TEST_TOOL_IMPL(1, ::boost::test_tools::tt_detail::close_coll_impl(), \
"", CHECK, CHECK_EQUAL_COLL, \
(L_begin)(L_end)(R_begin)(R_end)( \
::boost::math::fpc::percent_tolerance(T))) /**/
# define BOOST_REQUIRE_CLOSE_COLLECTIONS(L_begin, L_end, R_begin, R_end, T) \
BOOST_TEST_TOOL_IMPL(1, ::boost::test_tools::tt_detail::close_coll_impl(), \
"", REQUIRE, CHECK_EQUAL_COLL, \
(L_begin)(L_end)(R_begin)(R_end)( \
::boost::math::fpc::percent_tolerance(T))) /**/
//---------------------------------------------------------------------------
# define BOOST_WARN_EQUAL_RANGES(left, right) \
BOOST_WARN_EQUAL_COLLECTIONS(std::begin(left), std::end(left), \
std::begin(right), std::end(right))
# define BOOST_CHECK_EQUAL_RANGES(left, right) \
BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(left), std::end(left), \
std::begin(right), std::end(right))
# define BOOST_REQUIRE_EQUAL_RANGES(left, right) \
BOOST_REQUIRE_EQUAL_COLLECTIONS(std::begin(left), std::end(left), \
std::begin(right), std::end(right))
//---------------------------------------------------------------------------
# define BOOST_WARN_CLOSE_RANGES(left, right, t) \
BOOST_WARN_CLOSE_COLLECTIONS(std::begin(left), std::end(left), \
std::begin(right), std::end(right), t)
# define BOOST_CHECK_CLOSE_RANGES(left, right, t) \
BOOST_CHECK_CLOSE_COLLECTIONS(std::begin(left), std::end(left), \
std::begin(right), std::end(right), t)
# define BOOST_REQUIRE_CLOSE_RANGES(left, right, t) \
BOOST_REQUIRE_CLOSE_COLLECTIONS(std::begin(left), std::end(left), \
std::begin(right), std::end(right), t)
BOOST_CHECK_CLOSEの配列バージョンのマクロはBOOST_CHECK_CLOSE_COLLECTIONSです。
また、配列の範囲の指定を自動化したのが、BOOST_CHECK_CLOSE_RANGESです。
ついでに、BOOST_CHECK_EQUAL_COLLECTIONSの範囲指定を自動化バージョン、BOOST_CHECK_EQUAL_RANGESも作りました。
簡単な解説
close_coll_impl構造体は、BOOST_CHECK_EQUAL_COLLECTIONSで利用しているequal_coll_implのほとんどコピーです。二つの値を比較する関数は、BOOST_CHECK_CLOSEのcheck_is_close_t構造体を参考にしました。
値を比較する関数の型にdecltypeを使っているので、古いコンパイラーでは動かない可能性があります。
最後に
あまり細かい検証を行っていないので、場合によっては動かないかもしれません。
その時は、よろしければ御一報ください。