smix-cli 0.2.1

smix — AI-native iOS Simulator automation CLI (cement). v3.1 c12 MVP: doctor + sim subcommands. record/run/repl/watch land in c13/c-final.
//! v5.1 c8 — `scripts/v5/selftest-gate.sh` 已 refactor 走 `smix selftest single`
//! 取代 `cargo run --release --example selftest_full_surface --`。本 lint test
//! 钉:
//!   - script 不再含 `cargo run.*selftest_full_surface`
//!   - script 含 `smix selftest single`
//!   - 关键 capsule 三连仍在(c4 落地的 wire 不破)

use std::path::{Path, PathBuf};

fn repo_root() -> PathBuf {
    PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .parent()
        .and_then(Path::parent)
        .expect("smix-cli lives under <repo>/crates")
        .to_path_buf()
}

fn script_path() -> PathBuf {
    repo_root().join("scripts/v5/selftest-gate.sh")
}

fn read_script() -> String {
    std::fs::read_to_string(script_path()).expect("read selftest-gate.sh")
}

#[test]
fn case01_no_longer_invokes_cargo_run_example() {
    let body = read_script();
    assert!(
        !body.contains("cargo run --release --example selftest_full_surface"),
        "selftest-gate.sh must no longer shell out to `cargo run --example selftest_full_surface` — c8 refactored to call `smix selftest single` CLI subcommand instead"
    );
    // 同时不应再有 `--example selftest_full_surface` 的 cargo 调用(防 cycle 改 release 模式)。
    assert!(
        !body.contains("--example selftest_full_surface"),
        "no remaining `--example selftest_full_surface` references in gate.sh"
    );
}

#[test]
fn case02_invokes_smix_selftest_single() {
    let body = read_script();
    assert!(
        body.contains("smix selftest single") || body.contains("selftest single"),
        "selftest-gate.sh must invoke `smix selftest single` via $SMIX_BIN"
    );
    assert!(
        body.contains("$SMIX_BIN"),
        "selftest-gate.sh must use $SMIX_BIN (consistent with capsule up/down invocation form)"
    );
}

#[test]
fn case03_capsule_three_tier_preserved() {
    let body = read_script();
    // c4 落地的 capsule up + trap cleanup + down 三连不能破。
    for needle in [
        "capsule up",
        "capsule down",
        "trap cleanup EXIT",
        "exit 9",
        "exit 11",
        "exit 12",
    ] {
        assert!(
            body.contains(needle),
            "selftest-gate.sh must preserve c4 capsule 三连 / exit code wire — missing `{needle}`",
        );
    }
}