#![allow(clippy::unwrap_used)]
#![allow(clippy::expect_used)]
#![allow(non_snake_case)]
use assert_cmd::Command;
use predicates::prelude::*;
use std::io::Write;
use tempfile::TempDir;
#[allow(deprecated)]
fn bashrs_cmd() -> Command {
assert_cmd::cargo_bin_cmd!("bashrs")
}
#[test]
fn test_PMAT210_lint_changed_in_help() {
bashrs_cmd()
.arg("lint")
.arg("--help")
.assert()
.success()
.stdout(predicate::str::contains("--changed"))
.stdout(predicate::str::contains("--since"));
}
#[test]
fn test_PMAT210_lint_changed_help_shows_description() {
bashrs_cmd()
.arg("lint")
.arg("--help")
.assert()
.success()
.stdout(predicate::str::contains("Only lint files changed in git"))
.stdout(predicate::str::contains("CI optimization"));
}
#[test]
fn test_PMAT210_lint_since_requires_changed() {
bashrs_cmd()
.arg("lint")
.arg("--since")
.arg("main")
.assert()
.failure()
.stderr(predicate::str::contains("required"));
}
#[test]
fn test_PMAT210_lint_changed_no_files_required() {
let result = bashrs_cmd().arg("lint").arg("--changed").assert();
let output = String::from_utf8_lossy(&result.get_output().stderr);
assert!(
!output.contains("required arguments were not provided"),
"Should not require FILE when --changed is used"
);
}
fn setup_git_repo() -> TempDir {
let dir = TempDir::new().unwrap();
let path = dir.path();
std::process::Command::new("git")
.args(["init"])
.current_dir(path)
.output()
.unwrap();
std::process::Command::new("git")
.args(["config", "user.email", "test@test.com"])
.current_dir(path)
.output()
.unwrap();
std::process::Command::new("git")
.args(["config", "user.name", "Test"])
.current_dir(path)
.output()
.unwrap();
std::fs::write(path.join("clean.sh"), "#!/bin/sh\necho \"hello\"\n").unwrap();
std::process::Command::new("git")
.args(["add", "clean.sh"])
.current_dir(path)
.output()
.unwrap();
std::process::Command::new("git")
.args(["commit", "-m", "initial"])
.current_dir(path)
.output()
.unwrap();
dir
}
#[test]
fn test_PMAT210_lint_changed_no_changes() {
let dir = setup_git_repo();
bashrs_cmd()
.arg("lint")
.arg("--changed")
.current_dir(dir.path())
.assert()
.success()
.stdout(predicate::str::contains("No changed shell files found"));
}
#[test]
fn test_PMAT210_lint_changed_with_dirty_file() {
let dir = setup_git_repo();
std::fs::write(dir.path().join("clean.sh"), "#!/bin/bash\necho $RANDOM\n").unwrap();
bashrs_cmd()
.arg("lint")
.arg("--changed")
.current_dir(dir.path())
.assert()
.failure() .stdout(predicate::str::contains("DET001"));
}
#[test]
fn test_PMAT210_lint_changed_with_untracked_file() {
let dir = setup_git_repo();
std::fs::write(
dir.path().join("new_script.sh"),
"#!/bin/bash\necho $RANDOM\n",
)
.unwrap();
bashrs_cmd()
.arg("lint")
.arg("--changed")
.current_dir(dir.path())
.assert()
.failure()
.stdout(predicate::str::contains("new_script.sh"));
}
#[test]
fn test_PMAT210_lint_changed_ignores_non_shell() {
let dir = setup_git_repo();
std::fs::write(dir.path().join("readme.md"), "# Hello\n").unwrap();
bashrs_cmd()
.arg("lint")
.arg("--changed")
.current_dir(dir.path())
.assert()
.success()
.stdout(predicate::str::contains("No changed shell files found"));
}
#[test]
fn test_PMAT210_lint_changed_with_staged_file() {
let dir = setup_git_repo();
std::fs::write(dir.path().join("staged.sh"), "#!/bin/bash\necho $RANDOM\n").unwrap();
std::process::Command::new("git")
.args(["add", "staged.sh"])
.current_dir(dir.path())
.output()
.unwrap();
bashrs_cmd()
.arg("lint")
.arg("--changed")
.current_dir(dir.path())
.assert()
.failure()
.stdout(predicate::str::contains("staged.sh"));
}
#[test]
fn test_PMAT210_lint_changed_with_makefile() {
let dir = setup_git_repo();
let mut f = std::fs::File::create(dir.path().join("Makefile")).unwrap();
writeln!(f, "all:\n\techo hello").unwrap();
bashrs_cmd()
.arg("lint")
.arg("--changed")
.current_dir(dir.path())
.assert()
.stdout(
predicate::str::contains("Found 1 changed file")
.or(predicate::str::contains("Makefile")),
);
}
#[test]
fn test_PMAT210_lint_changed_since_default_is_head() {
bashrs_cmd()
.arg("lint")
.arg("--help")
.assert()
.success()
.stdout(predicate::str::contains("[default: HEAD]"));
}
#[test]
fn test_PMAT210_lint_changed_not_a_git_repo() {
let dir = TempDir::new().unwrap();
std::fs::write(dir.path().join("script.sh"), "#!/bin/sh\necho hi\n").unwrap();
bashrs_cmd()
.arg("lint")
.arg("--changed")
.current_dir(dir.path())
.assert()
.failure();
}
#[test]
fn test_PMAT210_lint_changed_with_fix() {
let dir = setup_git_repo();
std::fs::write(
dir.path().join("fixable.sh"),
"#!/bin/sh\nmkdir /tmp/test\n",
)
.unwrap();
bashrs_cmd()
.arg("lint")
.arg("--changed")
.arg("--fix")
.current_dir(dir.path())
.assert()
.stdout(predicate::str::contains("IDEM001").or(predicate::str::contains("fixable.sh")));
}
#[test]
fn test_PMAT210_lint_changed_plus_explicit_files() {
let dir = setup_git_repo();
std::fs::write(dir.path().join("explicit.sh"), "#!/bin/sh\necho hello\n").unwrap();
bashrs_cmd()
.arg("lint")
.arg("--changed")
.arg(dir.path().join("explicit.sh"))
.current_dir(dir.path())
.assert()
.success();
}