Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
3
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

@Cassin01

競技プログラミング用テスト

モチベーション

ある日AtCoderにて人のコードを眺めていたところテストを搭載したスニペットを使っている人がいました1

「かっこいい❤️」

自分でも作ってみました。

実装

fn main() {
    // 入力
    let n = input::<usize>();
    let a = input::<usize>();

    // 何らかの処理

    // 出力
    println!("{}", max_ave);
    println!("{}", cnt);
}

#[cfg(test)]
mod tests {
    #[test]
    fn tester() {
        // テストケースをここに書く
        // (入力, 期待する出力) 
        let inputs = [
("
5 2 2
1 2 3 4 5
", "
4.500000
1
"),

("
4 2 3
10 20 10 10
", "
15.000000
3
"),
       ];

        for (input, expected) in inputs.iter() {
            call(input, expected.to_string());
        }
    }

    fn call<T: AsRef<str>>(input: T, expected: String) {
        use std::process::{Command, Stdio};
        use std::io::{Read, Write};

        let mut cmd_echo = Command::new("echo")
            .arg(input.as_ref())
            .stdout(Stdio::piped())
            .spawn()
            .unwrap();
        let mut cmd_run = Command::new("cargo")
            .arg("run")
            .stdin(Stdio::piped())
            .stdout(Stdio::piped())
            .spawn()
            .unwrap();

        // 実行と標準出力の受け取り
        if let Some(ref mut stdout) = cmd_echo.stdout {
            if let Some(ref mut stdin) = cmd_run.stdin {
                let mut buf: Vec<u8> = Vec::new();
                stdout.read_to_end(&mut buf).unwrap();
                stdin.write_all(&buf).unwrap();
            }
        }

        let res = cmd_run.wait_with_output().unwrap().stdout;
        let res_string = String::from_utf8(res.to_vec()).unwrap();

        // convert '\n' into space
        let actual = res_string
            .replace("\n", " ")
            .trim_end_matches(' ')
            .trim_start_matches(' ')
            .to_owned();
        let expected = expected
            .replace("\n", " ")
            .trim_end_matches(' ')
            .trim_start_matches(' ')
            .to_owned();

        // split into a vector
        let actual = actual
            .split(' ')
            .map(|s| s.parse::<f64>().unwrap())
            .collect::<Vec<_>>();
        let expected = expected
            .split(' ')
            .map(|s| s.parse::<f64>().unwrap())
            .collect::<Vec<_>>();

        assert_eq!(actual, expected);
    }
}

実行

$ cargo test

工夫した点

先述したサイト1の実装はsolve関数に回答のための主要な処理を書き、main関数から呼び出していました。テストでは
solve関数を呼び出し、入力は全rustaceanがいいねしたであろうtanakhさんのinputマクロ2に手を加えたものを使用していました。

これに対し自作のテストはmain関数をテストから完全に独立させて自由に書けるようにしました。

コードについて

TopCoder や AtCoder は改行とスペースを区別しないらしいので改行コードを全てスペースに直しています。

テストケース

テストケースはinputs変数 Vec<()>に書いている
のですが、先述したサイト1のFireFox拡張を使えば
よりスッキリ書くことができると思います今度試してみます。

感想

シェルのパイプ処理がクレートなしで書けたのがよかったです
だけど少し複雑で大変だったです。

その他

こうした方がいいよなど思う所がありましたら是非コメントください❤️

参考

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
3
Help us understand the problem. What are the problem?