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

小ネタです。

# TL;DR

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


```c++
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`を使ったテストコード

```c++
  int exp = 1;
  int act = 2;

  assert(exp == act);
```

## 従来の`assert`の出力
```
test11: test.cc:87: int main(): Assertion `exp == act' failed.
```

# 今回の`ASSERT_EQ`の使用例

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

## テストコード（整数）

```c++
  int exp = 1;
  int act = 2;
  ASSERT_EQ(exp, act);
```

## 出力（整数）

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

## テストコード（文字列）

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

## 出力（文字列）

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



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

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

```c++
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®](https://theolizer.com/cpp/ostream-enum/)

# 実装

テストも含めた実装は[こちら](https://github.com/takeoverjp/lassert)に置いています。

# 参考

- [scoped enumをお手軽に出力できるようにする | Theolizer®](https://theolizer.com/cpp/ostream-enum/)
- [ブログズミ: Google Test を使ってみる - その２ （アサーション）](https://srz-zumix.blogspot.com/2011/12/google-test.html)
- [takeoverjp/lassert: Lightweight c++ power assert.](https://github.com/takeoverjp/lassert)