o7 0.1.0

O7 workflow DSL runner
Documentation
use assert_cmd::Command;
use predicates::prelude::*;
use tempfile::TempDir;
use std::fs;
use std::path::PathBuf;

/// Write a minimal valid .7 workflow file into a temp directory, returning the file path.
fn write_test_workflow(dir: &TempDir) -> PathBuf {
    let file = dir.path().join("test.7");
    fs::write(&file, "version 1\nworkflow main\n  exec\n    harness: h\n    prompt: \"hi\"\n").unwrap();
    file
}

#[test]
fn test_version_flag() {
    Command::cargo_bin("o7").unwrap()
        .arg("--version")
        .assert()
        .success()
        .stdout(predicate::str::contains("o7"));
}

#[test]
fn test_help_flag() {
    Command::cargo_bin("o7").unwrap()
        .arg("--help")
        .assert()
        .success()
        .stdout(predicate::str::contains("workflow DSL runner"));
}

#[test]
fn test_help_run_subcommand() {
    Command::cargo_bin("o7").unwrap()
        .args(["run", "--help"])
        .assert()
        .success()
        .stdout(predicate::str::contains("Run a workflow"));
}

#[test]
fn test_lint_valid_file() {
    let dir = TempDir::new().unwrap();
    let file = write_test_workflow(&dir);

    Command::cargo_bin("o7").unwrap()
        .args(["lint", file.to_str().unwrap()])
        .assert()
        .success()
        .stdout(predicate::str::contains("No errors found"));
}

#[test]
fn test_lint_invalid_file() {
    let dir = TempDir::new().unwrap();
    let file = dir.path().join("test.7");
    fs::write(&file, "workflow main\n").unwrap();

    Command::cargo_bin("o7").unwrap()
        .args(["lint", file.to_str().unwrap()])
        .assert()
        .failure();
}

#[test]
fn test_lint_nonexistent_file() {
    Command::cargo_bin("o7").unwrap()
        .args(["lint", "/nonexistent/test.7"])
        .assert()
        .failure()
        .stderr(predicate::str::contains("file not found"));
}

#[test]
fn test_parse_valid_file() {
    let dir = TempDir::new().unwrap();
    let file = write_test_workflow(&dir);

    Command::cargo_bin("o7").unwrap()
        .args(["parse", file.to_str().unwrap()])
        .assert()
        .success()
        .stdout(predicate::str::contains("OK"));
}

#[test]
fn test_parse_valid_file_shows_workflow_names() {
    let dir = TempDir::new().unwrap();
    let file = dir.path().join("test.7");
    fs::write(
        &file,
        "version 1\nworkflow main\n  exec\n    harness: h\n    prompt: \"hi\"\nworkflow deploy\n  exec\n    harness: h\n    prompt: \"go\"\n",
    ).unwrap();

    Command::cargo_bin("o7").unwrap()
        .args(["parse", file.to_str().unwrap()])
        .assert()
        .success()
        .stdout(predicate::str::contains("2 workflow(s)"))
        .stdout(predicate::str::contains("main"))
        .stdout(predicate::str::contains("deploy"));
}

#[test]
fn test_parse_invalid_file() {
    let dir = TempDir::new().unwrap();
    let file = dir.path().join("test.7");
    fs::write(&file, "workflow main\n").unwrap();

    Command::cargo_bin("o7").unwrap()
        .args(["parse", file.to_str().unwrap()])
        .assert()
        .failure()
        .stderr(predicate::str::contains("Parse errors"));
}

#[test]
fn test_tui_fails_without_terminal() {
    // The TUI requires a real terminal; in CI/test it fails with an OS error.
    let dir = TempDir::new().unwrap();
    let file = write_test_workflow(&dir);

    Command::cargo_bin("o7").unwrap()
        .args(["tui", file.to_str().unwrap()])
        .assert()
        .failure()
        .stderr(predicate::str::contains("TUI error:"));
}

#[test]
fn test_inspect_no_runs() {
    let dir = TempDir::new().unwrap();

    Command::cargo_bin("o7").unwrap()
        .args(["inspect", "--project", dir.path().to_str().unwrap()])
        .assert()
        .success()
        .stdout(predicate::str::contains("No runs found"));
}

#[test]
fn test_inspect_nonexistent_run() {
    let dir = TempDir::new().unwrap();

    Command::cargo_bin("o7").unwrap()
        .args(["inspect", "nonexistent-run", "--project", dir.path().to_str().unwrap()])
        .assert()
        .failure()
        .stderr(predicate::str::contains("Run not found"));
}

#[test]
fn test_no_args_shows_help() {
    Command::cargo_bin("o7").unwrap()
        .assert()
        .success()
        .stdout(predicate::str::contains("Usage"));
}

#[test]
fn test_wiz_appears_in_main_help() {
    Command::cargo_bin("o7").unwrap()
        .arg("--help")
        .assert()
        .success()
        .stdout(predicate::str::contains("wiz"));
}

#[test]
fn test_wiz_subcommand_help() {
    Command::cargo_bin("o7").unwrap()
        .args(["wiz", "--help"])
        .assert()
        .success()
        .stdout(predicate::str::contains("Interactively configure"));
}