Rust、使ってみたいなぁって思って、いつもやってるAtCoderで試してみようと思いました。
はじめに - AtCoderコンテストにRustで参加するためのガイドブック
を参考に、テストのあたりを改良してみました。実際に解くのはまだやってないです……
いろいろインストール
上記を参考にRustをインストール。さらにcargo-generateのインストール(同ガイドブック。以下略)をします。
ガイドに従って雛形のプロジェクトをゲットします
$ cargo generate --git https://github.com/rust-lang-ja/atcoder-rust-base --branch ja
🤷 Project Name: abc000
🔧 Creating project called `abc000`...
✨ Done! New project created /Users/ユーザー/programing/Rust/abc000
Project Name:
のあとのabc000
は自分で入力。
$ cd abc000
移動。
中身
- abc000/src/main.rs
ここに解答を書く。 - abc000/tests
テスト関係。主にここをいじる
カスタマイズ
テストケースの作成のところに、Rustのテスト機能を使ってテストケースを試す方法が載ってます。ただ、テストケースがプログラム中に書き込んであって ちょっとカッコ悪い/コピペする時位置調整がめんどい のでファイルから読み込むようにします。
rust: ファイル読み書き - nju33 を参考にabc000/tests/sample_inputs.rs
を以下のように書き換えます。
use std::fs;
use cli_test_dir::*;
#[test]
fn sample() {
let input = fs::read_to_string("tests/input.txt").unwrap();
let output = fs::read_to_string("tests/output.txt").unwrap();
let testdir = TestDir::new("main", "");
let res = testdir.cmd()
.output_with_stdin(input)
.tee_output()
.expect_success();
assert_eq!(res.stdout_str(), output);
assert!(res.stderr_str().is_empty());
}
途中の.tee_output()
は、出力をテスト結果画面に出力するオプション、のようなものなので出力が長いとき等は削るのもあり。
さらに、入出力サンプルを入れるファイルをabc000/tests/input.txt
・abc000/tests/output.txt
と作成します。ガイドライン通りに雛形をゲットしているとABC086 - C - Travelingの解答コードが入っているので、それに合わせて
2
3 1 2
6 1 1
Yes
とします。(特にoutput、最後の改行をやらないと一致判定で失敗するので注意)
お試し
テストしてみます。
$ cargo build
これはこのプロジェクトを使う前準備的なもの、らしい。proconioを使えるようにしたりする。
$ cargo test
Compiling abc000 v0.1.0 (/Users/ユーザー/programing/Rust/abc000)
Finished test [unoptimized + debuginfo] target(s) in 1.64s
Running target/debug/deps/main-028731574152944b
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
Running target/debug/deps/sample_inputs-c49f316d7d463d6e
running 1 test
Yes
test sample ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
サンプルの通過が判定できました!あとは各ケースをコピペすればいい。ctrl+A``ctrl+V
で全体を上書きできるので楽。
さらに改良
一致判定はしないで、単に出力をしてみたいときもあるのでabc000/tests/sample_inputs.rs
を書き換えます。
use std::fs;
use std::io::Write; //new!!
use cli_test_dir::*;
#[test]
fn sample() {
let input = fs::read_to_string("tests/input.txt").unwrap();
let output = fs::read_to_string("tests/output.txt").unwrap();
let testdir = TestDir::new("main", "");
let res = testdir.cmd()
.output_with_stdin(input)
.tee_output()
.expect_success();
//assert_eq!(res.stdout_str(), output); ここじゃなくて
assert!(res.stderr_str().is_empty());
//new!!
let mut file = fs::File::create("tests/view.txt").unwrap();
write!(&mut file, "{}", res.stdout_str()).unwrap();
assert_eq!(res.stdout_str(), output); //後ろに回す
}
Rust - ファイルに書き込む | rust Tutorial を参考にしました。出力をabc000/tests/view.txt
に書き出してくれます。
テストはエラーが出た時点で終了してしまうので、output.txt
との一致判定は最後に回しました。とにかくview.txt
に出力して欲しいので。
おしまい
Rust、入力がめっちゃめんどくさい雰囲気だったんですけどproconioなるクレート(ライブラリ的な?)のおかげで楽にできます。ありがてぇ。