cli.rs

2.9 kB · rust · 110 lines

1#[path = "common/sha256.rs"]2mod sha256;34use serde_json::Value;5use std::path::Path;6use std::process::{Command, Output};78fn stored(module: &str, path: &str) -> Value {9    let file = Path::new(env!("CARGO_MANIFEST_DIR"))10        .join("fixtures")11        .join(format!("{module}.json"));12    let text = std::fs::read_to_string(&file)13        .unwrap_or_else(|_| panic!("{} is missing; run the fixtures example", file.display()));14    let rows: Vec<Value> = serde_json::from_str(&text).unwrap();15    rows.into_iter()16        .find(|row| row["fn"] == path)17        .unwrap_or_else(|| panic!("{module}.json holds no {path} row"))["out"]18        .clone()19}2021fn mrly(words: &[&str]) -> Output {22    Command::new(env!("CARGO_BIN_EXE_mrly"))23        .args(words)24        .output()25        .expect("the mrly binary runs")26}2728fn printed(door: &str, args: &str) -> Value {29    let out = mrly(&[door, args]);30    assert!(31        out.status.success(),32        "{door} {args}: {}",33        String::from_utf8_lossy(&out.stderr)34    );35    serde_json::from_slice(&out.stdout).expect("the door prints one json value")36}3738fn hashed(value: &Value) -> Value {39    let bytes: Vec<u8> = serde_json::from_value(value.clone()).expect("a list of bytes");40    Value::String(sha256::hex(&bytes))41}4243#[test]44fn core_replays_its_png() {45    let colors = "[[[255,0,0,255],[0,255,0,255],[0,0,255,255],[255,255,255,255]],2,2,3]";46    assert_eq!(47        hashed(&printed("core.codec.png", colors)),48        stored("core", "core::png")49    );50}5152#[test]53fn num_replays_its_factorial() {54    assert_eq!(55        printed("num.factor.factorial", "[25]"),56        stored("num", "num::factor::factorial")57    );58}5960#[test]61fn math_replays_its_fill() {62    assert_eq!(63        printed("math.counts.fill", r#"["23",3,3,2,2]"#),64        stored("math", "math::counts::fill")65    );66}6768#[test]69fn gen_replays_its_background() {70    assert_eq!(71        hashed(&printed("gen.background", "[1,2,2]")),72        stored("gen", "gen::background")73    );74}7576#[test]77fn life_replays_its_counts() {78    assert_eq!(79        printed("life.counts", r#"["Primes",8,false,false]"#),80        stored("life", "life::counts")81    );82}8384#[test]85fn font_replays_its_path() {86    assert_eq!(printed("font.path", r#"["M"]"#), stored("font", "font::path"));87}8889#[test]90fn a_rust_error_exits_one_on_stderr() {91    let out = mrly(&["num.factor.factorial", "[40]"]);92    assert_eq!(out.status.code(), Some(1));93    assert!(out.stdout.is_empty());94    assert_eq!(95        String::from_utf8_lossy(&out.stderr).trim(),96        "a factorial of 40 passes u128"97    );98}99100#[test]101fn list_names_every_door_with_its_types() {102    let out = mrly(&["list"]);103    assert!(out.status.success());104    let text = String::from_utf8(out.stdout).unwrap();105    assert!(106        text.lines()107            .any(|line| line == "num.factor.gcd(a: u128, b: u128) -> u128"),108        "list does not name num.factor.gcd"109    );110}