プロコンやWebテストの入力〜結果検証までを楽チンにするソリューション

# はじめに

AtCoderはじめました。プロコンは頭の体操になるので楽しいですね！
ただやっていて思ったのは

### テストケースを手打ちで入力して出力を確認するのめんどくさい!

ってことです。
かといってUnitテストなんて書いている余裕はない...
もっとお手軽に検証できないか...

### そうだスクリプトを書けばいいじゃないか！！！！

ということでやってみました。

# 環境
環境は以下を満たしていればいいです。

- Bashを実行できる環境
    - 今回はmacOSで実行
- コマンドラインから実行できる言語
    - 今回はJava8を使用
    - 他の言語でも対応可能なはず（未検証）

# テストケースを自動検証する

今回は例として以下の問題を解きます。
[A - はじめてのあっとこーだー（Welcome to AtCoder）](https://beta.atcoder.jp/contests/practice/tasks/practice_1)

> ### 問題文
> 高橋君はデータの加工が行いたいです。
整数 $a,b,c$ と、文字列 $s$ が与えられます。
整数 $a+b+c$ と、文字列 $s$ を並べて表示しなさい。

> ###入力
> 入力は以下の形式で与えられる。

```text:入力
a
b c
s
```
>
- $1$ 行目は、整数 $a$ $(1≦a≦1,000)$ が与えられる。
- $2$ 行目は、整数 $b,c$ $(1≦b,c≦1,000)$ が与えられる。
- $3$ 行目は、文字列 $s$ が与えられる。この文字列の長さは $1$ 文字以上 $100$ 文字以下である。

> ### 出力
> $a+b+c$ と $s$ を空白区切りで $1$ 行に出力せよ。**また、出力の末尾には改行を入れること。**

標準入力にテストケースを入力させるため、テストケースをtextファイルに記述します。

```text:input.txt
1
2 3
test
```
AtCoderの解答例を使って確認していきましょう。

```java:Main.java
import java.util.*;
public class Main {
	public static void main(String[] args){
		Scanner sc = new Scanner(System.in);
		// 整数の入力
		int a = sc.nextInt();
		// スペース区切りの整数の入力
		int b = sc.nextInt();
		int c = sc.nextInt();
		// 文字列の入力
		String s = sc.next();
		// 出力
		System.out.println((a+b+c) + " " + s);
	}
}
```
あとはこのテストケースをパイプで標準入力に流し込んであげるだけ。

```sh:terminal
$ javac Main.java # Javaなのでコンパイルを行う
$ cat input.txt | java Main # 実行

# 出力結果
6 test
```

また出力例と比較したい場合は`diff`コマンドを使ってあげることで簡単に違う部分を発見できます。

まず出力例のtextファイルを作成します。

```text:expected.txt
6 text
```

以下のコマンドを実行すると検証ができます。

```sh:terminal
$ javac Main.java # Javaなのでコンパイルを行う
$ cat input.txt | java Main > output.txt # 実行&ファイルに書き込み
$ diff -u expected.txt output.txt

#　完全一致の場合何も出力されない
```

あとはこれをshellスクリプトに書き込んでいい感じにまとめてあげれば完成です！

```sh:test.sh
#!/bin/sh

javac Main.java # Javaなのでコンパイルを行う
cat input.txt | java Main > output.txt # 実行&ファイルに書き込み
diff -u expected.txt output.txt
```

ディレクトリ構成は以下のように全て同じディレクトリにまとめてください。

```terminal:terminal
$ tree .
├── input.txt
├── expected.txt
└── test.sh
```

```terminal:実行
$ sh test.sh
```

# 完成スクリプト
以下、私が作ったshellスクリプトです。参考になれば。

GitHub
[https://github.com/terappy/auto-test-tool](https://github.com/terappy/auto-test-tool)

```sh:test.sh
#!/bin/sh

CMDNAME=`basename $0`

# get option
while getopts e: OPT
do
  case $OPT in
    "e" ) FLG_E="TRUE" ; VALUE_E="$OPTARG" ;;
      * ) echo "Usage: $CMDNAME [-e VALUE] PARAMETERS" 1>&2
          exit 1 ;;
  esac
done

# remove option value
shift `expr $OPTIND - 1`

# check the number of arguments
if [ $# -ne 2 ]; then
  echo "Usage: $CMDNAME classname input-file-name" 1>&2
  exit 1
fi

echo "---------------------"
echo "input is":
echo "---------------------"
cat $2

echo ""
echo "---------------------"
echo "output is":
echo "---------------------"
# decide output file name.
OUTFILE_NAME="out-$2"

# compile the target java file.
javac $1.java

# execute with input file and write result into $OUTFILE_NAME
cat $2 | java $1 > $OUTFILE_NAME
cat $OUTFILE_NAME


if [ "$FLG_E" = "TRUE" ]; then
  echo ""
  echo "---------------------"
  echo "verification result":
  echo "---------------------"

  # verification
  if diff -u $VALUE_E $OUTFILE_NAME ; then
    echo "====================="
    echo "All matched!!"
    echo "====================="
  else
    echo "====================="
    echo "Miss matched"
    echo "====================="
  fi
fi
```

### 使い方

以下を実行してください。引数は以下のものを入力してください。

- CLASS_NAME
    - クラス名を入れる
    - Main.javaなら`Main`
- INPUT_TEXTFILE
    - 入力したい文字列を格納したtextファイル
- EXPECTED_RESULT_TEXTFILE
    - 出力例を格納したtextファイル


```terminal
$ sh test.sh ${CLASS_NAME} ${INPUT_TEXTFILE}
```
or

```terminal:出力例との検証をする場合
$ sh test.sh -e ${EXPECTED_RESULT_TEXTFILE} ${CLASS_NAME} ${INPUT_TEXTFILE}
```

#### 使用例

```terminal
$ sh test.sh -e expected.txt Main input.txt
```

# おまけ

JavaであればIDEとしてIntelliJを使う人も多いと思います。IntelliJにはプロコンで使えるCHelperという便利なプラグインがあって、今回やったテストケースの実行がお手軽にできる上、入出力に用いるクラスやメソッドを指定できます。Javaでプロコンやるならこれを使った方がいいです←。

### CHelper参考サイト

- [Using CHelper plugin in IntelliJ for a coding contest](https://stackoverflow.com/questions/38492050/using-chelper-plugin-in-intellij-for-a-coding-contest)
- [プログラミングコンテストで便利なIntelliJプラグイン CHelperを使う](http://takashima0411.hatenablog.com/entry/2016/08/02/165638)


# 最後に

プロコンにおいて解答時間は貴重なもの、そして検証は何度も行う作業なのでこうしてスクリプトでサクッと検証できるようにしておくのはマストだと思っています。
参考になれば幸いです。