【Atcoder】シェルスクリプトを用いて自動でテストを行う

# シェルスクリプトを用いて自動でテストを行う（テストケース）

【経緯】Atcoderの競プロ典型90問を解こうとしたら、
 　　　　アレ!?　今まで使っていた提出ボタンがない!?（テスト用のファイルはあります）
　　　　そこで、シェルスクリプトを使ってテストを自動化させたのでそのやり方を書いています。

#### ①ファイルの位置を確認
これから作るものは以下のようなフォルダの構造になっています。

```:フォルダ構造
001-----in-----01_sample_01.txt
     |         01_sample_02.txt
     |         01_sample_03.txt
     |         01_sample_04.txt
     |         02_all_01.txt
     |         02_all_02.txt
     |         02_all_03.txt
     |         02_all_04.txt
     |         02_all_05.txt
     |         02_all_06.txt
     |         02_all_07.txt
     |         02_all_08.txt
     |         02_all_09.txt
     |         02_all_10.txt
     |         02_all_11.txt
     |         02_all_12.txt
     |         02_all_13.txt
     |         02_all_14.txt
     |         02_all_15.txt
     |         02_all_16.txt
     |
     |--out----01_sample_01.txt
     |         01_sample_02.txt
     |         01_sample_03.txt
     |         01_sample_04.txt
     |         02_all_01.txt
     |         02_all_02.txt
     |         02_all_03.txt
     |         02_all_04.txt
     |         02_all_05.txt
     |         02_all_06.txt
     |         02_all_07.txt
     |         02_all_08.txt
     |         02_all_09.txt
     |         02_all_10.txt
     |         02_all_11.txt
     |         02_all_12.txt
     |         02_all_13.txt
     |         02_all_14.txt
     |         02_all_15.txt
     |         02_all_16.txt
     |
     |--answer(実行ファイル)
     |
     |--answer.cpp
     |
     |--test.sh(これから作ります)
```
テキストファイルは実行ファイルを使った時の入力と出力に対応します。
inフォルダ内やoutフォルダ内の中身は、例えば以下のようなものです。
```:. / in / 01_sample_01.txt
3 4
```
```:. / out / 01_sample_01.txt
7
```
この場合、3,4が入力に対応し、7が正しくプログラムが実行した際に想定される出力に対応します。

#### ②コンパイル（実行ファイルがない時）
まず、実行ファイルがない、もしくは名前がanswerでない人は001のフォルダ内でこのコマンドを入力してください。

```C++:~/001
g++ -Wall -o answer answer.cpp
```
ここではanswer.cppとしましたが、これはコンパイルしたいファイルを書いてください。
（C++でない言語はコンパイルをこの方法ではできません。コンパイルのやり方を検索してください）
エラーが出た人は文法に誤りがあります。エラーメッセージを読んで修正してから次に進んでください。


#### ③以下をコピー
以下のファイルをコピーし名前を「test.sh」としましょう！これはテストが通ればpassed、通らなければ、failedを表示します。そして、最後に何個のテストに合格したか、一つのファイルを実行するのにかかった時間の最大値を表示させるようになっています。また、この方法は改行を無視して比べているのことに注意してください。
```ShellScript:test.sh
#!/bin/bash
total_tests=0
total_passed=0
max_time=0

for i in in/*.txt; do
  start_time=$(date +%s.%N)
  j=out/$(basename $i)
  if diff -wB <(./answer < $i) <(cat $j) >/dev/null ; then
    echo "Testcase $(basename $i) passed"
    (( total_passed++ ))
  else
    echo "Testcase $(basename $i) failed"
  fi
  (( total_tests++ ))
  end_time=$(date +%s.%N)
  time_diff=$(echo "$end_time - $start_time" | bc)
  if (( $(echo "$time_diff > $max_time" | bc -l) )); then
    max_time=$time_diff
  fi
done

echo "Passed: $total_passed / $total_tests"
echo "Maximum time for a single test: $max_time seconds"

```

#### ④遂に実行
001フォルダ内で以下のようなコマンドを実行しましょう。

```:~/001
$  ./test.sh
```

```:実行例
Testcase 01_sample_01.txt passed
Testcase 01_sample_02.txt passed
Testcase 01_sample_03.txt passed
Testcase 01_sample_04.txt passed
Testcase 02_all_01.txt passed
Testcase 02_all_02.txt failed
Testcase 02_all_03.txt passed
Testcase 02_all_04.txt passed
Testcase 02_all_05.txt passed
Testcase 02_all_06.txt failed
Testcase 02_all_07.txt passed
Testcase 02_all_08.txt passed
Testcase 02_all_09.txt passed
Testcase 02_all_10.txt passed
Testcase 02_all_11.txt passed
Testcase 02_all_12.txt passed
Testcase 02_all_13.txt passed
Testcase 02_all_14.txt passed
Testcase 02_all_15.txt passed
Testcase 02_all_16.txt passed
Passed: 18 / 20
Maximum time for a single test: .084885815 seconds
```



#### まとめ
いかがだったでしょうか？テストケースの作り方について書かれているものがほとんどなかったので、この記事を書きました。テストをまとめて実行したい人はぜひ試してみてください!!