darq 0.1.0

darq CLI + TUI — autonomous issue → PR pipeline with SAT and a learning loop.
Documentation
//! CLI integration tests — exercise the binary from the outside.

use std::process::Command;

fn darq() -> Command {
    let mut cmd = Command::new(env!("CARGO_BIN_EXE_darq"));
    cmd.env("RUST_LOG", "error"); // suppress info logs in tests
    cmd
}

#[test]
fn help_shows_all_commands() {
    let output = darq().arg("--help").output().unwrap();
    let stdout = String::from_utf8_lossy(&output.stdout);

    assert!(output.status.success());
    assert!(stdout.contains("status"));
    assert!(stdout.contains("run"));
    assert!(stdout.contains("milestone"));
}

#[test]
fn run_help_shows_subcommands() {
    let output = darq().args(["run", "--help"]).output().unwrap();
    let stdout = String::from_utf8_lossy(&output.stdout);

    assert!(output.status.success());
    assert!(stdout.contains("list"));
    assert!(stdout.contains("show"));
    assert!(stdout.contains("approve"));
    assert!(stdout.contains("cancel"));
}

#[test]
fn milestone_help_shows_subcommands() {
    let output = darq().args(["milestone", "--help"]).output().unwrap();
    let stdout = String::from_utf8_lossy(&output.stdout);

    assert!(output.status.success());
    assert!(stdout.contains("next"));
    assert!(stdout.contains("sweep"));
}

#[test]
fn status_runs_without_crash() {
    let output = darq().arg("status").output().unwrap();
    let stdout = String::from_utf8_lossy(&output.stdout);

    assert!(output.status.success());
    assert!(stdout.contains("Daemon Status"));
    assert!(stdout.contains("Total:"));
}

#[test]
fn run_list_empty_runs_without_crash() {
    let output = darq().args(["run", "list"]).output().unwrap();
    let stdout = String::from_utf8_lossy(&output.stdout);

    // Command should succeed and show either runs or "No runs found"
    assert!(output.status.success());
    assert!(
        stdout.contains("No runs found.") || stdout.contains("ID"),
        "Expected run list output, got: {stdout}"
    );
}

#[test]
fn run_show_nonexistent_returns_not_found() {
    let output = darq().args(["run", "show", "fake-id"]).output().unwrap();
    let stdout = String::from_utf8_lossy(&output.stdout);

    assert!(output.status.success());
    assert!(stdout.contains("Run not found"));
}

#[test]
fn milestone_next_shows_placeholder() {
    let output = darq().args(["milestone", "next"]).output().unwrap();
    let stdout = String::from_utf8_lossy(&output.stdout);

    assert!(output.status.success());
    assert!(stdout.contains("milestone") || stdout.contains("sweep"));
}

#[test]
fn milestone_sweep_fails_without_setup() {
    let output = darq()
        .args(["milestone", "sweep", "v1.0"])
        .output()
        .unwrap();
    let combined = format!(
        "{}{}",
        String::from_utf8_lossy(&output.stdout),
        String::from_utf8_lossy(&output.stderr)
    );

    // Sweep either fails with missing config or unsupported operation
    // (full sweep via socket not yet implemented)
    assert!(
        combined.contains("repo")
            || combined.contains("No repo")
            || combined.contains("not yet")
            || combined.contains("Sweep"),
        "Expected sweep error, got: {combined}"
    );
}

#[test]
fn run_issue_help_shows_options() {
    let output = darq().args(["run", "issue", "--help"]).output().unwrap();
    let stdout = String::from_utf8_lossy(&output.stdout);

    assert!(output.status.success());
    assert!(stdout.contains("NUMBER") || stdout.contains("<NUMBER>"));
    assert!(stdout.contains("--full"));
}

#[test]
fn run_issue_without_number_fails() {
    let output = darq().args(["run", "issue"]).output().unwrap();

    assert!(!output.status.success());
}

#[test]
fn run_milestone_help_shows_options() {
    let output = darq()
        .args(["run", "milestone", "--help"])
        .output()
        .unwrap();
    let stdout = String::from_utf8_lossy(&output.stdout);

    assert!(output.status.success());
    assert!(
        stdout.contains("NAME"),
        "Expected NAME in help, got: {stdout}"
    );
    assert!(
        stdout.contains("--dry-run"),
        "Expected --dry-run in help, got: {stdout}"
    );
}

#[test]
fn run_milestone_without_name_fails() {
    let output = darq().args(["run", "milestone"]).output().unwrap();

    assert!(
        !output.status.success(),
        "Expected non-zero exit when NAME is missing"
    );
}