use std::path::PathBuf;
use assert_cmd::Command;
use serde_json::Value;
use tempfile::TempDir;
const FIXTURE_TEMPLATE: &str =
include_str!("../../crap4ts/tests/fixtures/istanbul-jest/coverage-final.json");
fn build_crap4ts_fixture() -> (TempDir, PathBuf) {
let tmp = tempfile::tempdir().expect("tempdir");
let canonical = std::fs::canonicalize(tmp.path()).expect("canonicalize tempdir");
for (name, content) in [
(
"simple.ts",
include_str!("../../crap4ts/tests/fixtures/ts-fixtures/simple.ts"),
),
(
"arrow.ts",
include_str!("../../crap4ts/tests/fixtures/ts-fixtures/arrow.ts"),
),
(
"Button.tsx",
include_str!("../../crap4ts/tests/fixtures/ts-fixtures/Button.tsx"),
),
(
"map.ts",
include_str!("../../crap4ts/tests/fixtures/ts-fixtures/map.ts"),
),
(
"mixed.ts",
include_str!("../../crap4ts/tests/fixtures/ts-fixtures/mixed.ts"),
),
] {
std::fs::write(canonical.join(name), content).expect("write fixture");
}
let payload = FIXTURE_TEMPLATE.replace(
"{SRC_ROOT}",
&canonical.to_string_lossy().replace('\\', "/"),
);
std::fs::write(canonical.join("coverage-final.json"), payload)
.expect("write coverage-final.json");
(tmp, canonical)
}
fn top_level_threshold(stdout: &[u8], who: &str) -> f64 {
let envelope: Value = serde_json::from_slice(stdout)
.unwrap_or_else(|e| panic!("{who} --format json emits valid JSON: {e}"));
envelope
.get("threshold")
.and_then(Value::as_f64)
.unwrap_or_else(|| panic!("{who} envelope has a numeric top-level `threshold`"))
}
fn crap4ts_threshold(extra_args: &[&str]) -> f64 {
let (_tmp, root) = build_crap4ts_fixture();
let coverage = root.join("coverage-final.json");
let output = Command::cargo_bin("crap4ts")
.expect("crap4ts binary discoverable in workspace")
.arg("--coverage")
.arg(&coverage)
.arg("--src")
.arg(&root)
.args(extra_args)
.args(["--format", "json", "--no-fail"])
.output()
.expect("crap4ts binary executes");
assert!(
output.status.success(),
"crap4ts exited non-zero: stdout={}\nstderr={}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr),
);
top_level_threshold(&output.stdout, "crap4ts")
}
fn crap4rs_threshold(extra_args: &[&str]) -> f64 {
let output = Command::cargo_bin("crap4rs")
.expect("crap4rs binary discoverable in workspace")
.args([
"--coverage",
"../crap4rs/tests/fixtures/crap4rs-self.lcov",
"--src",
"../crap4rs/src",
])
.args(extra_args)
.args(["--format", "json", "--no-fail"])
.output()
.expect("crap4rs binary executes");
assert!(
output.status.success(),
"crap4rs exited non-zero: stdout={}\nstderr={}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr),
);
top_level_threshold(&output.stdout, "crap4rs")
}
#[test]
fn default_gate_crap4ts_no_flag_is_cyclomatic_default() {
assert_eq!(
crap4ts_threshold(&[]),
15.0,
"crap4ts no-flag default must resolve to the cyclomatic \
`default` cutoff via metric-keyed routing"
);
}
#[test]
fn default_gate_crap4ts_strict_is_cyclomatic_strict() {
assert_eq!(
crap4ts_threshold(&["--strict"]),
8.0,
"crap4ts --strict must resolve to the cyclomatic `strict` cutoff"
);
}
#[test]
fn default_gate_crap4ts_lenient_is_cyclomatic_lenient() {
assert_eq!(
crap4ts_threshold(&["--lenient"]),
25.0,
"crap4ts --lenient must resolve to the cyclomatic `lenient` cutoff"
);
}
#[test]
fn default_gate_crap4rs_no_flag_is_cognitive_default() {
assert_eq!(
crap4rs_threshold(&[]),
15.0,
"crap4rs no-flag default must resolve to the cognitive \
`default` cutoff via metric-keyed routing"
);
}
#[test]
fn default_gate_crap4rs_strict_is_cognitive_strict() {
assert_eq!(
crap4rs_threshold(&["--strict"]),
8.0,
"crap4rs --strict (cognitive metric) must resolve to the \
cognitive `strict` cutoff"
);
}
#[test]
fn default_gate_crap4rs_metric_cyclomatic_no_flag_is_default() {
assert_eq!(
crap4rs_threshold(&["--metric", "cyclomatic"]),
15.0,
"crap4rs --metric cyclomatic no-flag default must resolve to \
the cyclomatic `default` cutoff"
);
}
#[test]
fn default_gate_crap4rs_metric_cyclomatic_strict_is_strict() {
assert_eq!(
crap4rs_threshold(&["--metric", "cyclomatic", "--strict"]),
8.0,
"crap4rs --metric cyclomatic --strict must resolve to the \
cyclomatic `strict` cutoff"
);
}