warriors/trisha/cli/tests/source_pipeline.rs

#![cfg(feature = "triton")]
use std::path::PathBuf;
use std::process::{Command, Output};

struct Fixture(PathBuf);
impl Fixture {
    fn new() -> Self {
        static NEXT: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
        let id = NEXT.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
        let dir = std::env::temp_dir().join(format!("trisha-cli-{}-{}", std::process::id(), id));
        std::fs::create_dir_all(&dir).unwrap();
        std::fs::write(
            dir.join("main.tri"),
            "program main\nfn main() { let x = pub_read()\n pub_write(x + 7) }\n",
        )
        .unwrap();
        Self(dir)
    }
    fn run(&self, args: &[&str]) -> Output {
        Command::new(env!("CARGO_BIN_EXE_trisha"))
            .current_dir(&self.0)
            .args(args)
            .output()
            .unwrap()
    }
}
impl Drop for Fixture {
    fn drop(&mut self) {
        let _ = std::fs::remove_dir_all(&self.0);
    }
}

#[test]
fn describe_and_state_share_embedded_network_dataset() {
    let fixture = Fixture::new();
    let output = fixture.run(&["describe", "--target", "neptune"]);
    assert!(output.status.success());
    let package: trident::target::TargetPackage = serde_json::from_slice(&output.stdout).unwrap();
    package.validate().unwrap();
    assert_eq!(package.owner, "trisha");
    assert!(package.modules.contains_key("vm.triton.hash"));
    assert!(package.modules.contains_key("os.neptune.auth"));
    assert!(!package.modules.contains_key("std.crypto.auth"));
    assert!(!package.runtime.deploy);
    for state in package.states {
        let output = fixture.run(&["state", "show", &state.union, &state.name]);
        assert!(output.status.success());
        let text = String::from_utf8(output.stdout).unwrap();
        assert!(text.contains(&state.display_name));
        assert!(text.contains(&state.currency_symbol));
    }
    assert!(!fixture
        .run(&["describe", "--target", "nox"])
        .status
        .success());
}

#[test]
fn source_cli_executes_proves_and_rejects_tampered_claim() {
    let f = Fixture::new();
    let run = f.run(&["run", "main.tri", "--input-values", "5"]);
    assert!(
        run.status.success(),
        "{}",
        String::from_utf8_lossy(&run.stderr)
    );
    assert_eq!(String::from_utf8_lossy(&run.stdout).trim(), "12");
    let prove = f.run(&[
        "prove",
        "main.tri",
        "--input-values",
        "5",
        "--output",
        "proof.toml",
    ]);
    assert!(
        prove.status.success(),
        "{}",
        String::from_utf8_lossy(&prove.stderr)
    );
    assert!(f.run(&["verify", "proof.toml"]).status.success());
    for target in ["nox", "unknown"] {
        assert!(!f
            .run(&["verify", "proof.toml", "--target", target])
            .status
            .success());
        assert!(!f
            .run(&["verify", "batch", "proof.toml", "--target", target])
            .status
            .success());
    }
    let path = f.0.join("proof.toml");
    let text = std::fs::read_to_string(&path).unwrap();
    let altered = text.replace("public_output = [\"12\"]", "public_output = [\"13\"]");
    assert_ne!(altered, text);
    std::fs::write(path, altered).unwrap();
    assert!(!f.run(&["verify", "proof.toml"]).status.success());
}

#[test]
fn unsupported_targets_digests_and_deployment_fail() {
    let f = Fixture::new();
    std::fs::write(f.0.join("raw.tasm"), "push 1 write_io 1 halt").unwrap();
    for target in ["nox", "tritno", "../../triton"] {
        for operation in ["run", "prove"] {
            let output = f.run(&[operation, "--tasm", "raw.tasm", "--target", target]);
            assert!(!output.status.success());
            assert!(String::from_utf8_lossy(&output.stderr).contains("does not provide target"));
            assert!(!f
                .run(&[operation, "batch", "main.tri", "--target", target])
                .status
                .success());
        }
        assert!(!f
            .run(&["build", "main.tri", "--target", target])
            .status
            .success());
        assert!(!f.0.join("main.tasm").exists());
    }
    assert!(!f
        .run(&["run", "main.tri", "--digests", "1,2,3"])
        .status
        .success());
    assert!(!f.run(&["deploy", "main.tri"]).status.success());
    assert!(f.run(&["deploy", "main.tri", "--dry-run"]).status.success());
}

#[test]
fn duplicate_batch_destinations_fail_before_writing_proofs() {
    let f = Fixture::new();
    std::fs::create_dir(f.0.join("other")).unwrap();
    std::fs::copy(f.0.join("main.tri"), f.0.join("other/main.tri")).unwrap();
    let result = f.run(&[
        "prove",
        "batch",
        "main.tri",
        "other/main.tri",
        "--output",
        "proofs",
    ]);
    assert!(!result.status.success());
    assert!(String::from_utf8_lossy(&result.stderr).contains("collision"));
    assert!(!f.0.join("proofs/main.proof.toml").exists());
}

#[test]
fn embedded_libraries_and_project_profiles_work_outside_checkout() {
    let f = Fixture::new();
    std::fs::write(f.0.join("trident.toml"), "[project]\nname = \"isolated\"\nentry = \"main.tri\"\ntarget = \"neptune\"\n[targets.release]\nflags = [\"selected\"]\n").unwrap();
    std::fs::write(f.0.join("main.tri"), "program isolated\nuse vm.core.convert\nuse os.neptune.xfield\n#[cfg(selected)]\nfn chosen() -> Field { 38 }\n#[cfg(not(selected))]\nfn chosen() -> Field { 99 }\nfn main() { pub_write(convert.as_field(convert.as_u32(chosen()))) }\n").unwrap();
    let output = Command::new(env!("CARGO_BIN_EXE_trisha"))
        .current_dir(&f.0)
        .env_remove("TRIDENT_STDLIB")
        .env_remove("TRIDENT_OSLIB")
        .env_remove("TRIDENT_EXTLIB")
        .args(["run", ".", "--profile", "release"])
        .output()
        .unwrap();
    assert!(
        output.status.success(),
        "{}",
        String::from_utf8_lossy(&output.stderr)
    );
    assert_eq!(String::from_utf8_lossy(&output.stdout).trim(), "38");
    assert!(!f.run(&["run", ".", "--target", "triton"]).status.success());
    assert!(f
        .run(&["build", ".", "--profile", "release"])
        .status
        .success());
    assert!(f.0.join("main.tasm").is_file());
    assert!(f
        .run(&[
            "prove",
            ".",
            "--profile",
            "release",
            "--output",
            "project.proof.toml"
        ])
        .status
        .success());
    assert!(f.run(&["verify", "project.proof.toml"]).status.success());
    assert!(!f
        .run(&[
            "prove",
            ".",
            "--target",
            "triton",
            "--output",
            "wrong.proof.toml"
        ])
        .status
        .success());
    assert!(!f.0.join("wrong.proof.toml").exists());
    assert!(f
        .run(&["run", "batch", "main.tri", "--profile", "release"])
        .status
        .success());
}

#[test]
fn test_cli_runs_assertions_and_reports_failures_and_skips() {
    let f = Fixture::new();
    std::fs::write(f.0.join("main.tri"), "program suite\nfn main() { assert(false) }\n#[test]\nfn good() { assert(2 + 3 == 5) }\n#[cfg(release)]\n#[test]\nfn bad() { assert(false) }").unwrap();
    let debug = f.run(&["test", "main.tri"]);
    assert!(
        debug.status.success(),
        "{}",
        String::from_utf8_lossy(&debug.stderr)
    );
    assert!(String::from_utf8_lossy(&debug.stderr).contains("1 passed; 0 failed; 1 skipped"));
    let release = f.run(&["test", "main.tri", "--profile", "release"]);
    assert!(!release.status.success());
    assert!(String::from_utf8_lossy(&release.stderr).contains("1 passed; 1 failed; 0 skipped"));
}

Graph