#![allow(deprecated)]
#![allow(clippy::unwrap_used)] #![allow(clippy::expect_used)]
use assert_cmd::Command;
use predicates::prelude::*;
use std::fs;
use std::path::PathBuf;
use tempfile::TempDir;
#[allow(deprecated)]
fn bashrs_cmd() -> Command {
assert_cmd::cargo_bin_cmd!("bashrs")
}
#[test]
fn test_config_004_detect_random() {
let temp_dir = TempDir::new().unwrap();
let test_file = temp_dir.path().join("test-bashrc");
let content = r#"export SESSION_ID=$RANDOM
export PATH="/usr/local/bin:$PATH"
export EDITOR=vim"#;
fs::write(&test_file, content).unwrap();
let output = bashrs_cmd()
.arg("config")
.arg("analyze")
.arg(&test_file)
.assert()
.success();
output
.stdout(predicate::str::contains("CONFIG-004"))
.stdout(predicate::str::contains("Non-deterministic"));
}
#[test]
fn test_config_004_detect_timestamp() {
let temp_dir = TempDir::new().unwrap();
let test_file = temp_dir.path().join("test-bashrc");
let content = r#"export BUILD_TAG="build-$(date +%s)""#;
fs::write(&test_file, content).unwrap();
let output = bashrs_cmd()
.arg("config")
.arg("analyze")
.arg(&test_file)
.assert()
.success();
output
.stdout(predicate::str::contains("CONFIG-004"))
.stdout(predicate::str::contains("Non-deterministic"));
}
#[test]
fn test_config_004_detect_process_id() {
let temp_dir = TempDir::new().unwrap();
let test_file = temp_dir.path().join("test-bashrc");
let content = r#"export TEMP_DIR="/tmp/work-$$""#;
fs::write(&test_file, content).unwrap();
let output = bashrs_cmd()
.arg("config")
.arg("analyze")
.arg(&test_file)
.assert()
.success();
output
.stdout(predicate::str::contains("CONFIG-004"))
.stdout(predicate::str::contains("Non-deterministic"));
}
#[test]
fn test_config_004_detect_multiple() {
let temp_dir = TempDir::new().unwrap();
let test_file = temp_dir.path().join("test-bashrc");
let content = r#"export SESSION_ID=$RANDOM
export BUILD_TAG="build-$(date +%s)"
export TEMP_DIR="/tmp/work-$$""#;
fs::write(&test_file, content).unwrap();
let output = bashrs_cmd()
.arg("config")
.arg("analyze")
.arg(&test_file)
.assert()
.success();
output.stdout(predicate::str::contains("CONFIG-004"));
}
#[test]
fn test_config_004_lint_shows_issues() {
let temp_dir = TempDir::new().unwrap();
let test_file = temp_dir.path().join("test-bashrc");
let content = r#"export SESSION_ID=$RANDOM"#;
fs::write(&test_file, content).unwrap();
bashrs_cmd()
.arg("config")
.arg("lint")
.arg(&test_file)
.assert()
.failure() .stdout(predicate::str::contains("CONFIG-004"));
}
#[test]
fn test_config_004_purify_removes_constructs() {
let temp_dir = TempDir::new().unwrap();
let test_file = temp_dir.path().join("test-bashrc");
let output_file = temp_dir.path().join("output-bashrc");
let content = r#"export PATH="/usr/local/bin:$PATH"
export SESSION_ID=$RANDOM
export EDITOR=vim"#;
fs::write(&test_file, content).unwrap();
bashrs_cmd()
.arg("config")
.arg("purify")
.arg(&test_file)
.arg("--output")
.arg(&output_file)
.arg("--dry-run")
.assert()
.success();
let purified = fs::read_to_string(&output_file).unwrap();
assert!(purified.contains("export PATH"));
assert!(purified.contains("export EDITOR"));
assert!(purified.contains("# RASH: Non-deterministic construct removed"));
assert!(purified.contains("# export SESSION_ID=$RANDOM"));
}
#[test]
fn test_config_004_with_fixture_file() {
let mut fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
fixture.push("tests/fixtures/configs/messy-bashrc.sh");
let output = bashrs_cmd()
.arg("config")
.arg("lint")
.arg(&fixture)
.assert()
.failure();
output.stdout(predicate::str::contains("CONFIG-004"));
}
#[test]
fn test_config_004_no_issues() {
let temp_dir = TempDir::new().unwrap();
let test_file = temp_dir.path().join("test-bashrc");
let content = r#"export PATH="/usr/local/bin:$PATH"
export EDITOR=vim
export VERSION="1.0.0"
alias ll='ls -la'"#;
fs::write(&test_file, content).unwrap();
let output = bashrs_cmd()
.arg("config")
.arg("analyze")
.arg(&test_file)
.assert()
.success();
let stdout = String::from_utf8(output.get_output().stdout.clone()).unwrap();
if stdout.contains("CONFIG-004") {
panic!("Expected no CONFIG-004 issues, but found some");
}
}
#[test]
fn test_config_004_idempotent_purification() {
let temp_dir = TempDir::new().unwrap();
let test_file = temp_dir.path().join("test-bashrc");
let output_file1 = temp_dir.path().join("output1-bashrc");
let output_file2 = temp_dir.path().join("output2-bashrc");
let content = r#"export SESSION_ID=$RANDOM"#;
fs::write(&test_file, content).unwrap();
bashrs_cmd()
.arg("config")
.arg("purify")
.arg(&test_file)
.arg("--output")
.arg(&output_file1)
.arg("--dry-run")
.assert()
.success();
bashrs_cmd()
.arg("config")
.arg("purify")
.arg(&output_file1)
.arg("--output")
.arg(&output_file2)
.arg("--dry-run")
.assert()
.success();
let purified1 = fs::read_to_string(&output_file1).unwrap();
let purified2 = fs::read_to_string(&output_file2).unwrap();
assert_eq!(purified1, purified2, "Purification should be idempotent");
}