CでZig風のテスト

# はじめに
Zig言語では, テストを以下のように書ける.
``` zig
test "test name" {
  ...
}
```
Cでは標準のテスト構文がないからテストを書くのがそこそこ面倒である.
そこで, CでもZigくらい簡潔に書けるテスト構文をマクロで実装した.
# 機能
- `test`ブロックの最後に到達したらテスト成功
- `expect(cond)`で条件をチェックでき, `false`の場合テスト失敗
- `unreachable`で到達してはいけない箇所を明示でき, そこに到達したらテスト失敗
```目指す形.c
int add(int x, int y) { return x + y; }

test(add_function_test) {
  expect(add(4, 5) == 9);
  expect(add(9, 2) == 11);

  int x = 15, y = 30;
  expect(add(x, y) == x + y);
}

test(unreachable_example) {
  for (;;) {
    break;
    unreachable;
  }
}
```
# ソースコード
説明は後
```testing.h
#include <setjmp.h>

#ifdef TEST_MODE
extern int test_success_count;
extern int test_failed_count;
// test() マクロ
#define test(name)                                                             \
  void test##name(jmp_buf);                                                    \
  __attribute__((constructor)) void testrunner##name() {                       \
    jmp_buf jb;                                                                \
    if (setjmp(jb) == 0)                                                       \
      test##name(jb);                                                          \
    else {                                                                     \
      puts(#name ": [NG]");                                                    \
      test_failed_count++;                                                     \
      return;                                                                  \
    }                                                                          \
    puts(#name ": [OK]");                                                      \
    test_success_count++;                                                      \
  }                                                                            \
  void test##name(jmp_buf jb)

#else
#define test(name) void test_dummy##name(jmp_buf jb)
#endif

// expect() マクロ
#define expect(cond)                                                           \
  if (!(cond)) {                                                               \
    printf("Failed at %s:%d " #cond " ", __FILE__, __LINE__);                  \
    longjmp(jb, 1);                                                            \
  }

// unreachable マクロ
#define unreachable                                                            \
  do {                                                                         \
    printf("Reached line %s:%d", __FILE__, __LINE__);                          \
    longjmp(jb, 1);                                                            \
  } while (0)

```
```testing.c
#include "testing.h"
#include <stdio.h>

#ifdef TEST_MODE
#undef main

// 処理はconstructorとdestructorにやらせるからmain関数は空
int main() {}

// 他のファイルにあるであろうもともとのmain関数を無効化
#define main main_

int test_success_count;
int test_failed_count;

// テスト結果の集計を出力
__attribute__((destructor)) void report_test_result() {
  printf("\nPassed: %d/%d\n", test_success_count, test_success_count + test_failed_count);
}
#endif
```
# 使い方
`testing.h`をinclude
テストを有効化するときは`-DTEST_MODE`をつけて`testing.c`もいっしょにビルド
# 説明
### setjmpを使う理由
当初は`test##name()`でのテストの結果を`testrunner##name()`に返すとき`bool`の返り値で返そうと思ってたけどそれだと
```c
test(name) {
  ...
  return true;
}
```
みたいにブロックの終わりに毎回`return`を書く必要があり, それは冗長でかっこ悪いと思ったから`longjmp`を使って結果を返すことにした. これにより, 
- `test`ブロックの最後に到達 → 成功
- 途中で`longjmp`が呼ばれる → 失敗

のように, Zigに近い構文を実現した.
`longjmp`を使う場面はマクロで隠蔽してあるから構造化プログラミングの観点からも問題ない(多分).
### テスト自動実行について
#### `testrunner##name()`
`constructor`属性がついてるので定義だけしておけばプログラム開始時に勝手に呼ばれる.
#### `report_test_result()`
`destructor`属性がついてるので確実にすべてのテストが終わった後に勝手に呼ばれる.
### エラー報告について
`expect()`, `unreachable`は失敗したとき
- 現在のファイル名
- 現在の行数
- 条件式(`expect()`の場合)

を表示してから`longjmp`する.