#[path = "common/mod.rs"]
mod common;
use common::{parse_json, run_fallow, run_fallow_combined, run_fallow_raw};
#[test]
fn fail_on_issues_check_exits_1_with_issues() {
let output = run_fallow(
"check",
"basic-project",
&["--fail-on-issues", "--format", "json", "--quiet"],
);
assert_eq!(
output.code, 1,
"check --fail-on-issues should exit 1 with issues"
);
}
#[test]
fn fail_on_issues_dupes_exits_1_with_clones() {
let output = run_fallow(
"dupes",
"duplicate-code",
&[
"--threshold",
"0.1",
"--fail-on-issues",
"--format",
"json",
"--quiet",
],
);
assert!(
output.code == 0 || output.code == 1,
"dupes with --fail-on-issues should not crash, got {}",
output.code
);
}
#[test]
fn combined_mode_runs_successfully() {
let output = run_fallow_combined("basic-project", &["--format", "json", "--quiet"]);
assert!(
output.code == 0 || output.code == 1,
"combined mode should not crash, got exit code {}",
output.code
);
let json: serde_json::Value = serde_json::from_str(&output.stdout)
.unwrap_or_else(|e| panic!("combined output should be JSON: {e}"));
assert!(json.is_object(), "combined output should be a JSON object");
}
#[test]
fn combined_only_dead_code() {
let output = run_fallow_combined(
"basic-project",
&["--only", "dead-code", "--format", "json", "--quiet"],
);
assert!(
output.code == 0 || output.code == 1,
"combined --only dead-code should not crash"
);
}
#[test]
fn combined_skip_dead_code() {
let output = run_fallow_combined(
"basic-project",
&["--skip", "dead-code", "--format", "json", "--quiet"],
);
assert!(
output.code == 0 || output.code == 1,
"combined --skip dead-code should not crash"
);
}
#[test]
fn combined_only_and_skip_are_mutually_exclusive() {
let output = run_fallow_combined(
"basic-project",
&[
"--only",
"dead-code",
"--skip",
"health",
"--format",
"json",
"--quiet",
],
);
assert_eq!(
output.code, 2,
"--only and --skip together should exit 2 (invalid args)"
);
}
#[test]
fn save_baseline_creates_file() {
let dir = std::env::temp_dir().join(format!("fallow-baseline-test-{}", std::process::id()));
let _ = std::fs::remove_dir_all(&dir);
let _ = std::fs::create_dir_all(&dir);
let baseline_path = dir.join("baseline.json");
let output = run_fallow(
"check",
"basic-project",
&[
"--save-baseline",
baseline_path.to_str().unwrap(),
"--format",
"json",
"--quiet",
],
);
assert!(
output.code == 0 || output.code == 1,
"save-baseline should not crash"
);
assert!(
baseline_path.exists(),
"--save-baseline should create the baseline file"
);
let content = std::fs::read_to_string(&baseline_path).unwrap();
let _: serde_json::Value =
serde_json::from_str(&content).expect("baseline file should be valid JSON");
let _ = std::fs::remove_dir_all(&dir);
}
#[test]
fn baseline_filters_known_issues() {
let dir = std::env::temp_dir().join(format!(
"fallow-baseline-filter-test-{}",
std::process::id()
));
let _ = std::fs::remove_dir_all(&dir);
let _ = std::fs::create_dir_all(&dir);
let baseline_path = dir.join("baseline.json");
run_fallow(
"check",
"basic-project",
&[
"--save-baseline",
baseline_path.to_str().unwrap(),
"--format",
"json",
"--quiet",
],
);
let output = run_fallow(
"check",
"basic-project",
&[
"--baseline",
baseline_path.to_str().unwrap(),
"--format",
"json",
"--quiet",
],
);
let json = parse_json(&output);
let total = json["total_issues"].as_u64().unwrap_or(0);
assert_eq!(
total, 0,
"baseline should filter all known issues, got {total}"
);
let _ = std::fs::remove_dir_all(&dir);
}
#[test]
fn changed_since_accepts_head() {
let output = run_fallow(
"check",
"basic-project",
&["--changed-since", "HEAD", "--format", "json", "--quiet"],
);
assert!(
output.code == 0 || output.code == 1,
"check --changed-since HEAD should not crash, got exit {}. stderr: {}",
output.code,
output.stderr
);
let json = parse_json(&output);
assert!(
json.get("total_issues").is_some(),
"should still have total_issues key even with --changed-since"
);
}
#[test]
fn nonexistent_root_exits_2() {
let output = run_fallow_raw(&[
"check",
"--root",
"/nonexistent/path/for/testing",
"--quiet",
]);
assert_eq!(output.code, 2, "nonexistent root should exit 2");
}
#[test]
fn no_package_json_returns_empty_results() {
let output = run_fallow(
"check",
"error-no-package-json",
&["--format", "json", "--quiet"],
);
assert_eq!(
output.code, 0,
"missing package.json should exit 0 with no issues, stderr: {}",
output.stderr
);
let json = parse_json(&output);
assert_eq!(
json["total_issues"].as_u64().unwrap_or(0),
0,
"should have 0 issues without package.json"
);
}