linear-cli 0.3.2

A powerful CLI for Linear.app - manage issues, projects, cycles, and more from your terminal
use std::process::Command;

/// Helper to run CLI commands and capture output
fn run_cli(args: &[&str]) -> (i32, String, String) {
    let output = Command::new(env!("CARGO_BIN_EXE_linear-cli"))
        .args(args)
        .output()
        .expect("Failed to execute command");

    let stdout = String::from_utf8_lossy(&output.stdout).to_string();
    let stderr = String::from_utf8_lossy(&output.stderr).to_string();
    let code = output.status.code().unwrap_or(-1);

    (code, stdout, stderr)
}

#[test]
fn test_help_command() {
    let (code, stdout, _stderr) = run_cli(&["--help"]);
    assert_eq!(code, 0);
    assert!(stdout.contains("A powerful CLI for Linear.app"));
    assert!(stdout.contains("Commands:"));
}

#[test]
fn test_version_command() {
    let (code, stdout, _stderr) = run_cli(&["--version"]);
    assert_eq!(code, 0);
    assert!(stdout.contains("linear") || stdout.contains("0.1"));
}

#[test]
fn test_projects_help() {
    let (code, stdout, _stderr) = run_cli(&["projects", "--help"]);
    assert_eq!(code, 0);
    assert!(stdout.contains("list"));
    assert!(stdout.contains("create"));
}

#[test]
fn test_issues_help() {
    let (code, stdout, _stderr) = run_cli(&["issues", "--help"]);
    assert_eq!(code, 0);
    assert!(stdout.contains("list"));
    assert!(stdout.contains("create"));
    assert!(stdout.contains("start"));
    assert!(stdout.contains("stop"));
}

#[test]
fn test_teams_help() {
    let (code, stdout, _stderr) = run_cli(&["teams", "--help"]);
    assert_eq!(code, 0);
    assert!(stdout.contains("list"));
}

#[test]
fn test_config_help() {
    let (code, stdout, _stderr) = run_cli(&["config", "--help"]);
    assert_eq!(code, 0);
    assert!(stdout.contains("set-key"));
    assert!(stdout.contains("show"));
    assert!(stdout.contains("workspace-add"));
    assert!(stdout.contains("workspace-list"));
}

#[test]
fn test_bulk_help() {
    let (code, stdout, _stderr) = run_cli(&["bulk", "--help"]);
    assert_eq!(code, 0);
    assert!(stdout.contains("update-state"));
    assert!(stdout.contains("assign"));
    assert!(stdout.contains("label"));
}

#[test]
fn test_search_help() {
    let (code, stdout, _stderr) = run_cli(&["search", "--help"]);
    assert_eq!(code, 0);
    assert!(stdout.contains("issues"));
    assert!(stdout.contains("projects"));
}

#[test]
fn test_git_help() {
    let (code, stdout, _stderr) = run_cli(&["git", "--help"]);
    assert_eq!(code, 0);
    assert!(stdout.contains("checkout"));
    assert!(stdout.contains("branch"));
}

#[test]
fn test_sync_help() {
    let (code, stdout, _stderr) = run_cli(&["sync", "--help"]);
    assert_eq!(code, 0);
    assert!(stdout.contains("status"));
    assert!(stdout.contains("push"));
}

#[test]
fn test_aliases_work() {
    // Test short aliases
    let (code1, stdout1, _) = run_cli(&["p", "--help"]);
    let (code2, stdout2, _) = run_cli(&["projects", "--help"]);
    assert_eq!(code1, 0);
    assert_eq!(code2, 0);
    assert_eq!(stdout1, stdout2);

    let (code3, stdout3, _) = run_cli(&["i", "--help"]);
    let (code4, stdout4, _) = run_cli(&["issues", "--help"]);
    assert_eq!(code3, 0);
    assert_eq!(code4, 0);
    assert_eq!(stdout3, stdout4);
}

#[test]
fn test_output_format_option() {
    let (code, stdout, _stderr) = run_cli(&["--help"]);
    assert_eq!(code, 0);
    assert!(stdout.contains("--output"));
    assert!(stdout.contains("table"));
    assert!(stdout.contains("json"));
}

#[test]
fn test_invalid_command() {
    let (code, _stdout, stderr) = run_cli(&["invalid-command"]);
    assert_ne!(code, 0);
    assert!(stderr.contains("error") || stderr.contains("invalid"));
}

// --- Additional alias tests ---

#[test]
fn test_teams_alias() {
    let (code1, stdout1, _) = run_cli(&["t", "--help"]);
    let (code2, stdout2, _) = run_cli(&["teams", "--help"]);
    assert_eq!(code1, 0);
    assert_eq!(code2, 0);
    assert_eq!(stdout1, stdout2);
}

#[test]
fn test_comments_alias() {
    let (code1, stdout1, _) = run_cli(&["cm", "--help"]);
    let (code2, stdout2, _) = run_cli(&["comments", "--help"]);
    assert_eq!(code1, 0);
    assert_eq!(code2, 0);
    assert_eq!(stdout1, stdout2);
}

#[test]
fn test_git_alias() {
    let (code1, stdout1, _) = run_cli(&["g", "--help"]);
    let (code2, stdout2, _) = run_cli(&["git", "--help"]);
    assert_eq!(code1, 0);
    assert_eq!(code2, 0);
    assert_eq!(stdout1, stdout2);
}

#[test]
fn test_search_alias() {
    let (code1, stdout1, _) = run_cli(&["s", "--help"]);
    let (code2, stdout2, _) = run_cli(&["search", "--help"]);
    assert_eq!(code1, 0);
    assert_eq!(code2, 0);
    assert_eq!(stdout1, stdout2);
}

// --- Help text completeness ---

#[test]
fn test_notifications_help() {
    let (code, stdout, _stderr) = run_cli(&["notifications", "--help"]);
    assert_eq!(code, 0);
    assert!(stdout.contains("list"));
    assert!(stdout.contains("read"));
}

#[test]
fn test_labels_help() {
    let (code, stdout, _stderr) = run_cli(&["labels", "--help"]);
    assert_eq!(code, 0);
    assert!(stdout.contains("list"));
}

#[test]
fn test_cycles_help() {
    let (code, stdout, _stderr) = run_cli(&["cycles", "--help"]);
    assert_eq!(code, 0);
    assert!(stdout.contains("list"));
}

#[test]
fn test_cache_help() {
    let (code, stdout, _stderr) = run_cli(&["cache", "--help"]);
    assert_eq!(code, 0);
    assert!(stdout.contains("status"));
    assert!(stdout.contains("clear"));
}

#[test]
fn test_export_help() {
    let (code, stdout, _stderr) = run_cli(&["export", "--help"]);
    assert_eq!(code, 0);
    assert!(stdout.contains("csv"));
}

#[test]
fn test_uploads_help() {
    let (code, stdout, _stderr) = run_cli(&["uploads", "--help"]);
    assert_eq!(code, 0);
    assert!(stdout.contains("fetch"));
}

// --- Subcommand help tests ---

#[test]
fn test_issues_list_help() {
    let (code, stdout, _stderr) = run_cli(&["issues", "list", "--help"]);
    assert_eq!(code, 0);
    assert!(stdout.contains("--team"));
    assert!(stdout.contains("--state"));
    assert!(stdout.contains("--assignee"));
}

#[test]
fn test_issues_create_help() {
    let (code, stdout, _stderr) = run_cli(&["issues", "create", "--help"]);
    assert_eq!(code, 0);
    assert!(stdout.contains("--team"));
    assert!(stdout.contains("--priority"));
    assert!(stdout.contains("--description"));
    assert!(stdout.contains("--dry-run"));
}

#[test]
fn test_bulk_update_state_help() {
    let (code, stdout, _stderr) = run_cli(&["bulk", "update-state", "--help"]);
    assert_eq!(code, 0);
    assert!(stdout.contains("STATE"));
    assert!(stdout.contains("--issues"));
}

// --- Global flags ---

#[test]
fn test_quiet_flag_exists() {
    let (code, stdout, _stderr) = run_cli(&["--help"]);
    assert_eq!(code, 0);
    assert!(stdout.contains("--quiet") || stdout.contains("-q"));
}

#[test]
fn test_dry_run_flag_exists() {
    let (code, stdout, _stderr) = run_cli(&["--help"]);
    assert_eq!(code, 0);
    assert!(stdout.contains("--dry-run"));
}

#[test]
fn test_compact_flag_exists() {
    let (code, stdout, _stderr) = run_cli(&["--help"]);
    assert_eq!(code, 0);
    assert!(stdout.contains("--compact"));
}

#[test]
fn test_fields_flag_exists() {
    let (code, stdout, _stderr) = run_cli(&["--help"]);
    assert_eq!(code, 0);
    assert!(stdout.contains("--fields"));
}

// --- CLI name consistency ---

#[test]
fn test_binary_name_in_help() {
    let (code, stdout, _stderr) = run_cli(&["--help"]);
    assert_eq!(code, 0);
    // The help should show the binary name
    assert!(
        stdout.contains("linear-cli") || stdout.contains("Usage:"),
        "Help output should contain binary name or usage info"
    );
}

#[test]
fn test_version_contains_semver() {
    let (code, stdout, _stderr) = run_cli(&["--version"]);
    assert_eq!(code, 0);
    // Version should contain a semver-like pattern (digit.digit)
    assert!(
        stdout.chars().any(|c| c == '.'),
        "Version output should contain a dot-separated version number"
    );
}