1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Boost.TestのBOOST_CHECK_CLOSEの配列バージョンを作った (タイトルを修正しました)

Last updated at Posted at 2015-07-19

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を使っているので、古いコンパイラーでは動かない可能性があります。

最後に

あまり細かい検証を行っていないので、場合によっては動かないかもしれません。
その時は、よろしければ御一報ください。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?