マクロでテーブル駆動テスト

# 実装
```test.h
#ifdef TEST

// テスト実行ではもとのmain関数は無効化
#define main main_

#define ARGS_0
#define ARGS_1 t->a1
#define ARGS_2 ARGS_1, t->a2
#define ARGS_3 ARGS_2, t->a3
#define ARGS_4 ARGS_3, t->a4
// テストできる関数の引数の数は4個まで

#define MEM_DEF_1(_1) _1 a0;
#define MEM_DEF_2(_1, _2) MEM_DEF_1(_1) _2 a1;
#define MEM_DEF_3(_1, _2, _3) MEM_DEF_2(_1, _2) _3 a2;
#define MEM_DEF_4(_1, _2, _3, _4) MEM_DEF_3(_1, _2, _3) _4 a3;
#define MEM_DEF_5(_1, _2, _3, _4, _5) MEM_DEF_4(_1, _2, _3, _4) _5 a4;

#define GET_M(_1, _2, _3, _4, _5, NAME, ...) NAME
#define EXPAND(...) __VA_ARGS__
#define DO_FN(fn, ...) \
  fn(GET_M(__VA_ARGS__, ARGS_4, ARGS_3, ARGS_2, ARGS_1, ARGS_0))
#define SIGNATURE(...) \
  struct { \
    GET_M(__VA_ARGS__, MEM_DEF_5, MEM_DEF_4, MEM_DEF_3, MEM_DEF_2, MEM_DEF_1) \
    (__VA_ARGS__) \
  }

// 引数のsignatureは (int, char, bool) のようなフォーマット
// つまり
// SIGNATURE signature
// は
// SIGNATURE (int, char, bool)
// に展開される。EXPAND signature も同じ要領
#define table_driven_test(name, fn, signature, ...) \
  typedef SIGNATURE signature sigstruct##name; \
  __attribute__((constructor)) void tabledriventest##name() { \
    sigstruct##name data[] = __VA_ARGS__; \
    printf("Testing " #name "... => "); \
    for (size_t i = 0; i < sizeof(data) / sizeof(data[0]); i++) { \
      sigstruct##name *t = data + i; \
      typeof(t->a0) result = DO_FN(fn, EXPAND signature); \
      if (!eq(result, t->a0)) { \
        printf("[NG] Test case %zu failed: expected ", i); \
        print(t->a0); \
        printf(", but got "); \
        print(result); \
        puts(""); \
        return; \
      } \
    } \
    puts("[OK]"); \
  }

#else

#define table_driven_test(...)

#endif
```
```test.c
#ifdef TEST
int main() {}
#endif
```
コード内の`eq()`とか`print()`はマクロの`_Generic`とか`attribute`の`overloadable`とかで実現してください
テストケースが失敗したときは、
- テストケースの番号
- 予想の返り値
- 実際の返り値

が出力されます
# 使い方
ソースと一緒に`test.c`もビルド
テストを有効にするときはコンパイルオプションで`-DTEST`を追加
```
table_driven_test (
    テストの名前,
    テストする関数の名前,
    (関数の返り値の型, 引数1の型, 引数2の型, ...),
    {
        { 予想の返り値1, 引数1_1, 引数1_2, ...},
        { 予想の返り値2, 引数2_1, 引数2_2, ...},
        ...
    }
)
```
# 例
```example.c
#include "test.h"
#include <stdio.h>
#include <math.h>

int main() {}

double avg_score(int math, int jap, int eng) {
  if (math < 0 || 100 < math || jap < 0 || 100 < jap || eng < 0 || 100 < eng)
    return -1.0;
  return (math + jap + eng) / 3.0;
}

// テスト対象の関数↑の返り値の型がdoubleだからeqとprintもdouble型のが必要
__attribute__((overloadable)) _Bool eq(double lhs, double rhs) {
    return fabs(lhs - rhs) < 0.01;
}
// eqとかprintは他のファイルに分割してtest.hでincludeした方が見栄えがいい
// 他の型を追加するには
// __attribute__((overloadable)) _Bool eq(int lhs, int rhs) {
//     return lhs == rhs;
// }

__attribute__((overloadable)) void print(double x) {
    printf("%lf", x);
}
// __attribute__((overloadable)) void print(int x) {
//     printf("%d", x);
// }

table_driven_test (
    calculate_average_score, // テストの名前
    avg_score, // テスト対象の関数
    (double, int, int, int), // (関数の返り値の型, 引数の型)
    { // テストケースの配列
        {-1.0, 101, 100, 100},
        {-1.0, -1, 0, 0},
        {50.0, 0, 50, 100},
        {100.0, 100, 100, 100},
        {99.0, 100, 99, 98},
        {0.0, 0, 0, 0}
    } // 全部成功するはず
)

```
コンパイル
```shell-session
$ # example.c, test.{c,h}をカレントディレクトリに用意
$ clang example.c test.c -DTEST # gccも可
```