アルゴリズムを考えるためにGoogle Testを使う

# はじめに

https://github.com/drken1215/book_algorithm_solution

のC++コードでは標準入力からデータを与えているが, 動作確認するときに毎回入力するのは面倒.
そこで, 問題を解くときにはテストコードを書いて動作確認を自動化しておくと便利.

また, アルゴリズムを考えるときの取っ掛かりとして,
簡単なテストパターンだけ通るようにコードを書いてみるとアルゴリズムを考えやすい.

テストフレームワークとしては, **Google Test** を使う.

https://github.com/google/googletest

# インストール

MacではhomebrewでGoogle Testをインストールできる. [^1]

```console
$ brew install googletest
```

<details><summary>Intel Macではインクルードパスやライブラリパスにも自動で入る.</summary>

```console
$ ls -lhFG /usr/local/include/{gmock,gtest}
lrwxr-xr-x  1 skkzsh  admin    41B  8 23 12:20 /usr/local/include/gmock@ -> ../Cellar/googletest/1.15.2/include/gmock
lrwxr-xr-x  1 skkzsh  admin    41B  8 23 12:20 /usr/local/include/gtest@ -> ../Cellar/googletest/1.15.2/include/gtest

$ ls -lhFG /usr/local/lib/*{gmock,gtest}*.a
lrwxr-xr-x  1 skkzsh  admin    42B  8 23 12:20 /usr/local/lib/libgmock.a@ -> ../Cellar/googletest/1.15.2/lib/libgmock.a
lrwxr-xr-x  1 skkzsh  admin    47B  8 23 12:20 /usr/local/lib/libgmock_main.a@ -> ../Cellar/googletest/1.15.2/lib/libgmock_main.a
lrwxr-xr-x  1 skkzsh  admin    42B  8 23 12:20 /usr/local/lib/libgtest.a@ -> ../Cellar/googletest/1.15.2/lib/libgtest.a
lrwxr-xr-x  1 skkzsh  admin    47B  8 23 12:20 /usr/local/lib/libgtest_main.a@ -> ../Cellar/googletest/1.15.2/lib/libgtest_main.a
```
</details>

Appleシリコンでは以下の記事を参考にパスを通す.

https://qiita.com/skkzsh/items/3af16ae3a97f131ee1ff

[^1]: [リリースノート](https://github.com/google/googletest/releases/tag/v1.15.2) に書いているとおり, Google公式としては最新コミットからのビルドが推奨されています. が, 本記事では簡易化のためhomebrewでのインストールを紹介しています.


# テストコード

アルゴリズムの簡単な動作確認では, Google Testの [`EXPECT_EQ`](https://google.github.io/googletest/reference/assertions.html#EXPECT_EQ) が使える.
[パラメータ化テスト](https://google.github.io/googletest/advanced.html#how-to-write-value-parameterized-tests) は下記のように書ける.

```c++:solution_7_1.cpp
#include "gtest/gtest.h"
using std::vector;

int func(vector<int> a, vector<int> b) {
// 省略
}

const struct TestParam {
    const vector<int> a;  // 入力
    const vector<int> b;  // 入力
    const int expected;   // 出力の期待値
} PARAMS[] {
    {
        {2, 3, 1},
        {4, 0, 5},
        2,
    },
    {
        {0, 1, 5},
        {2, 3, 4},
        2,
    },
    {
        {2, 3},
        {0, 1},
        0,
    },
    {
        {0, 7, 2, 4, 1},
        {8, 6, 5, 9, 3},
        5,
    },
    {
        {0, 1, 5, 6, 7},
        {2, 3, 4, 8, 9},
        4,
    },
};

class TestSuite : public ::testing::TestWithParam<TestParam> {};

TEST_P(TestSuite, Ex) {
    EXPECT_EQ(func(GetParam().a, GetParam().b), GetParam().expected);
}

INSTANTIATE_TEST_SUITE_P(
    Inst,
    TestSuite,
    ::testing::ValuesIn(PARAMS)
);
```

# コンパイルとテスト実行

コンパイルとテスト実行は下記のとおり.

```console
$ g++ -Wall -Wextra -std=c++20 -lgtest_main -lgtest -lpthread solution_7_1.cpp
$ ./a.out
Running main() from /tmp/googletest-20220910-4336-bl42bb/googletest-release-1.12.1/googletest/src/gtest_main.cc
[==========] Running 5 tests from 1 test suite.
[----------] Global test environment set-up.
[----------] 5 tests from Inst/TestSuite
[ RUN      ] Inst/TestSuite.Ex/0
[       OK ] Inst/TestSuite.Ex/0 (0 ms)
[ RUN      ] Inst/TestSuite.Ex/1
[       OK ] Inst/TestSuite.Ex/1 (0 ms)
[ RUN      ] Inst/TestSuite.Ex/2
[       OK ] Inst/TestSuite.Ex/2 (0 ms)
[ RUN      ] Inst/TestSuite.Ex/3
[       OK ] Inst/TestSuite.Ex/3 (0 ms)
[ RUN      ] Inst/TestSuite.Ex/4
[       OK ] Inst/TestSuite.Ex/4 (0 ms)
[----------] 5 tests from Inst/TestSuite (0 ms total)

[----------] Global test environment tear-down
[==========] 5 tests from 1 test suite ran. (1 ms total)
[  PASSED  ] 5 tests.
```

`Makefile` の書き方は以下の記事に続く.

https://qiita.com/skkzsh/items/08ec6d2fd151ebc6d079

# 確認環境
```console
$ g++ -v
Apple clang version 15.0.0 (clang-1500.1.0.2.5)
Target: x86_64-apple-darwin22.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
```