3
0

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 3 years have passed since last update.

お手軽assertで失敗時の詳細(左辺値・右辺値)を確認する

Posted at

小ネタです。

TL;DR

以下のコードをヘッダ等に忍ばせておくことで、
お手軽に失敗時の詳細(左辺値・右辺値)を確認できるassertが書けます。

static inline void ASSERT_EQ_IMPL(const std::string &file, const int lineno,
                                  const std::string &func,
                                  const std::string &exp_symbol,
                                  const auto &exp,
                                  const std::string &act_symbol,
                                  const auto &act) {
  if (exp == act) {
    return;
  }
  std::cerr << file << ": " << lineno << ": " << func << ": error: check "
            << exp_symbol << " == " << act_symbol << " has failed [" << exp
            << " != " << act << "]" << std::endl;
  std::terminate();
}

# define ASSERT_EQ(exp, act)                                                    \
  do {                                                                         \
    ASSERT_EQ_IMPL(__FILE__, __LINE__, __func__, #exp, exp, #act, act);        \
  } while (0)

背景

LeetCodeのような短いプログラムのテストを書くときや、
main loopも含めたライブラリのテストを書く時は、
GoogleTest等のtesting frameworkの導入が手間に感じるときがあります。

そのような場合、私は普通のassertでテストを書くのですが、
下記のように一致しなかったことしかわからず、実際の値がどうなっていたのかがわからないため、
解析しづらいことが多いです。

そこで、失敗時の左辺値・右辺値を出力するようにしたASSERT_EQが、冒頭のものです。
後々GoogleTestに移行したときにちょっとでも楽になるようにI/FはGoogleTestに合わせています。

従来のassertを使ったテストコード

  int exp = 1;
  int act = 2;

  assert(exp == act);

従来のassertの出力

test11: test.cc:87: int main(): Assertion `exp == act' failed.

今回のASSERT_EQの使用例

以下のように、整数値でもstd::stringでも比較できます。

テストコード(整数)

  int exp = 1;
  int act = 2;
  ASSERT_EQ(exp, act);

出力(整数)

test.cc: 19: TestInt: error: check exp == act has failed [0 != 1]

テストコード(文字列)

  std::string exp = "expected string";
  std::string act = "actual string";
  ASSERT_EQ(exp, act);

出力(文字列)

test.cc: 65: TestString: error: check exp == act has failed [expected string != actual string]

仮引数の型推論(C++14)なんか使えないんだけど?

最初の例は仮引数の型推論を使っているので、C++14でコンパイルする必要があります。
テンプレートを使えばC++11でも同じようなことが書けます。

template <class T1, class T2>
static inline void ASSERT_EQ_IMPL(const std::string &file, const int lineno,
                                  const std::string &func, const std::string &exp_symbol,
                                  const T1 &exp, const std::string &act_symbol, const T2 &act) {
  if (exp == act) {
    return;
  }
  std::cerr << file << ": " << lineno << ": " << func << ": error: check "
            << exp_symbol << " == " << act_symbol << " has failed [" << exp
            << " != " << act << "]" << std::endl;
  std::terminate();
}

# define ASSERT_EQ(exp, act)                                                    \
  do {                                                                         \
    ASSERT_EQ_IMPL(__FILE__, __LINE__, __func__, #exp, exp, #act, act);        \
  } while (0)

Scoped Enumの比較に使うとエラーになるんだけど?

型チェックが厳格なのでありがたいScoped Enumですが、iostreamによる出力ができないためそのままではエラーになります。
下記のサイトで紹介してくれている実装を使うことで、Scoped Enumも比較できるようになります(田原さん、ありがとうございます)。

scoped enumをお手軽に出力できるようにする | Theolizer®

実装

テストも含めた実装はこちらに置いています。

参考

3
0
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
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?