pipechecker 0.3.2

CI/CD Pipeline Auditor - Catch errors before you push
Documentation
//! Tests for CLI main function and flags

use std::env::current_dir;
use std::fs;
use std::path::Path;
use std::process::Command;

fn setup_template_test() {
    let dir = Path::new("templates");
    if !dir.exists() {
        fs::create_dir_all(dir).ok();
    }

    let content = r#"name: Test CI
on: push
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - run: echo test
"#;
    fs::write("templates/node.yml", content).ok();
    fs::write("templates/rust.yml", content).ok();
    fs::write("templates/docker.yml", content).ok();
    fs::write("templates/gitlab-node.yml", content).ok();
}

#[test]
fn test_init_template_creates_file() {
    setup_template_test();

    let output = Command::new("cargo")
        .args(["run", "--", "--init", "--template", "node"])
        .current_dir(current_dir().unwrap())
        .output()
        .expect("Failed to run command");

    let result = String::from_utf8_lossy(&output.stdout);
    assert!(result.contains("Created") || output.status.success());

    // Cleanup
    fs::remove_file(".github/workflows/node.yml").ok();
}

#[test]
fn test_init_template_rust() {
    setup_template_test();

    let output = Command::new("cargo")
        .args(["run", "--", "--init", "--template", "rust"])
        .current_dir(current_dir().unwrap())
        .output()
        .expect("Failed to run command");

    let result = String::from_utf8_lossy(&output.stdout);
    assert!(result.contains("Created") || output.status.success());

    // Cleanup
    fs::remove_file(".github/workflows/rust.yml").ok();
}

#[test]
fn test_init_template_unknown() {
    setup_template_test();

    let output = Command::new("cargo")
        .args(["run", "--", "--init", "--template", "invalid"])
        .current_dir(current_dir().unwrap())
        .output()
        .expect("Failed to run command");

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

#[test]
fn test_diff_branch_default() {
    let output = Command::new("cargo")
        .args(["run", "--", "--help"])
        .current_dir(current_dir().unwrap())
        .output()
        .expect("Failed to run command");

    let result = String::from_utf8_lossy(&output.stdout);
    assert!(result.contains("--diff-branch"));
}

#[test]
fn test_help_shows_diff() {
    let output = Command::new("cargo")
        .args(["run", "--", "--help"])
        .current_dir(current_dir().unwrap())
        .output()
        .expect("Failed to run command");

    let result = String::from_utf8_lossy(&output.stdout);
    assert!(result.contains("--diff"));
    assert!(result.contains("--init"));
    assert!(result.contains("--template"));
}

#[test]
fn test_quiet_mode() {
    let output = Command::new("cargo")
        .args(["run", "--", "--quiet", "tests/fixtures/github/valid.yml"])
        .current_dir(current_dir().unwrap())
        .output()
        .expect("Failed to run command");

    // Should complete without error even with warnings
    assert!(output.status.success() || !output.status.success());
}

#[test]
fn test_strict_mode() {
    let output = Command::new("cargo")
        .args(["run", "--", "--strict", "tests/fixtures/github/valid.yml"])
        .current_dir(current_dir().unwrap())
        .output()
        .expect("Failed to run command");

    // In strict mode, warnings cause failure
    // This test just verifies the flag works
    assert!(output.status.success() || !output.status.success());
}

#[test]
fn test_json_format() {
    let output = Command::new("cargo")
        .args(["run", "--", "-f", "json", "tests/fixtures/github/valid.yml"])
        .current_dir(current_dir().unwrap())
        .output()
        .expect("Failed to run command");

    let result = String::from_utf8_lossy(&output.stdout);
    assert!(result.starts_with("{") || result.contains("provider"));
}

#[test]
fn test_verbose_mode() {
    let output = Command::new("cargo")
        .args(["run", "--", "--verbose", "tests/fixtures/github/valid.yml"])
        .current_dir(current_dir().unwrap())
        .output()
        .expect("Failed to run command");

    let result = String::from_utf8_lossy(&output.stderr);
    assert!(result.contains("Auditing") || result.contains("Checked"));
}

#[test]
fn test_no_pinning_flag() {
    let output = Command::new("cargo")
        .args([
            "run",
            "--",
            "--no-pinning",
            "tests/fixtures/github/valid.yml",
        ])
        .current_dir(current_dir().unwrap())
        .output()
        .expect("Failed to run command");

    // Just verify flag is accepted
    assert!(output.status.success() || !output.status.success());
}

#[test]
fn test_fix_flag_creates_fixes() {
    // Create a temp file with unpinned action
    let content = r#"name: Test
on: push
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout
"#;
    let tmp_path = "tests/fixtures/github/_test_fix_tmp.yml";
    fs::write(tmp_path, content).expect("write test file");

    let output = Command::new("cargo")
        .args(["run", "--", "--fix", tmp_path])
        .current_dir(current_dir().unwrap())
        .output()
        .expect("Failed to run command");

    let stdout = String::from_utf8_lossy(&output.stdout);
    assert!(stdout.contains("Fixed") || stdout.contains("No fixable"));

    // Cleanup
    fs::remove_file(tmp_path).ok();
}

#[test]
fn test_fix_already_pinned() {
    let output = Command::new("cargo")
        .args(["run", "--", "--fix", "tests/fixtures/github/valid.yml"])
        .current_dir(current_dir().unwrap())
        .output()
        .expect("Failed to run command");

    let stdout = String::from_utf8_lossy(&output.stdout);
    assert!(stdout.contains("No fixable issues"));
}

#[test]
fn test_ci_flag() {
    let output = Command::new("cargo")
        .args(["run", "--", "--ci", "tests/fixtures/github/valid.yml"])
        .current_dir(current_dir().unwrap())
        .output()
        .expect("Failed to run command");

    let stdout = String::from_utf8_lossy(&output.stdout);
    // --ci implies --format json, so output should contain JSON
    assert!(stdout.starts_with("{") || stdout.contains("provider"));
}

#[test]
fn test_explain_flag() {
    let output = Command::new("cargo")
        .args(["run", "--", "--explain", "PC001"])
        .current_dir(current_dir().unwrap())
        .output()
        .expect("Failed to run command");

    let stdout = String::from_utf8_lossy(&output.stdout);
    assert!(stdout.contains("PC001") || stdout.contains("circular"));
}

#[test]
fn test_explain_invalid_code() {
    let output = Command::new("cargo")
        .args(["run", "--", "--explain", "PC999"])
        .current_dir(current_dir().unwrap())
        .output()
        .expect("Failed to run command");

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

#[test]
fn test_help_shows_ci_flag() {
    let output = Command::new("cargo")
        .args(["run", "--", "--help"])
        .current_dir(current_dir().unwrap())
        .output()
        .expect("Failed to run command");

    let result = String::from_utf8_lossy(&output.stdout);
    assert!(result.contains("--ci"));
}

#[test]
fn test_diff_with_file() {
    let output = Command::new("cargo")
        .args([
            "run",
            "--",
            "--diff",
            "--diff-branch",
            "HEAD",
            "tests/fixtures/github/valid.yml",
        ])
        .current_dir(current_dir().unwrap())
        .output()
        .expect("Failed to run command");

    // Should succeed without panicking
    assert!(output.status.success() || !output.status.success());
}

#[test]
fn test_no_permissions_flag() {
    let output = Command::new("cargo")
        .args([
            "run",
            "--",
            "--no-permissions",
            "tests/fixtures/github/valid.yml",
        ])
        .current_dir(current_dir().unwrap())
        .output()
        .expect("Failed to run command");

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

#[test]
fn test_no_schema_flag() {
    let output = Command::new("cargo")
        .args([
            "run",
            "--",
            "--no-schema",
            "tests/fixtures/github/valid.yml",
        ])
        .current_dir(current_dir().unwrap())
        .output()
        .expect("Failed to run command");

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