use assert_cmd::Command;
use big_code_analysis::CSV_HEADER;
use std::io::Write;
use tempfile::TempDir;
mod common;
use common::validators::{assert_checkstyle_well_formed_and_structural, validate_sarif};
fn cli() -> Command {
Command::cargo_bin("bca").unwrap()
}
fn write_rust_fixture(dir: &TempDir) -> String {
let path = dir.path().join("fixture.rs");
let mut f = std::fs::File::create(&path).expect("create fixture");
f.write_all(b"fn f(x: u32) -> u32 { if x > 0 { x } else { 0 } }\n")
.expect("write fixture");
path.to_str().expect("fixture path is utf-8").to_string()
}
fn run_metrics(format: &str, fixture_path: &str) -> String {
let output = cli()
.args(["--paths", fixture_path, "metrics", "-O", format])
.assert()
.success()
.get_output()
.stdout
.clone();
String::from_utf8(output).expect("CLI output is UTF-8")
}
fn run_check_offender_doc(format: &str, fixture_path: &str) -> String {
let output = cli()
.args([
"--paths",
fixture_path,
"check",
"--threshold",
"cyclomatic=1",
"--output-format",
format,
"--no-fail",
])
.assert()
.success()
.get_output()
.stdout
.clone();
String::from_utf8(output).expect("CLI output is UTF-8")
}
#[test]
fn cli_check_sarif_output_validates_against_schema() {
let dir = TempDir::new().unwrap();
let fixture = write_rust_fixture(&dir);
let out = run_check_offender_doc("sarif", &fixture);
if let Err(violations) = validate_sarif(&out) {
panic!(
"SARIF schema violations from CLI output:\n {}\n\nfull document:\n{}",
violations.join("\n "),
out,
);
}
let doc: serde_json::Value = serde_json::from_str(&out).expect("SARIF stdout parses as JSON");
let results = doc["runs"][0]["results"]
.as_array()
.expect("runs[0].results is an array");
assert!(
!results.is_empty(),
"expected at least one SARIF result for branchy fixture; doc was:\n{out}",
);
}
#[test]
fn cli_check_checkstyle_output_is_well_formed() {
let dir = TempDir::new().unwrap();
let fixture = write_rust_fixture(&dir);
let out = run_check_offender_doc("checkstyle", &fixture);
assert_checkstyle_well_formed_and_structural(&out);
assert!(
out.contains("<file"),
"expected at least one <file> element in checkstyle output; out was:\n{out}",
);
assert!(
out.contains("cyclomatic"),
"expected cyclomatic metric in checkstyle output; out was:\n{out}",
);
}
#[test]
fn cli_csv_output_round_trips_through_csv_crate() {
let dir = TempDir::new().unwrap();
let fixture = write_rust_fixture(&dir);
let out = run_metrics("csv", &fixture);
let mut rdr = csv::ReaderBuilder::new()
.has_headers(false)
.from_reader(out.as_bytes());
let mut rows = 0;
for record in rdr.records() {
let record = record.expect("CLI CSV output round-trips through csv::Reader");
assert_eq!(
record.len(),
CSV_HEADER.len(),
"row {rows} field count {} differs from CSV_HEADER ({})",
record.len(),
CSV_HEADER.len(),
);
rows += 1;
}
assert!(
rows >= 2,
"expected header + at least one data row in CLI csv output, got {rows} rows"
);
}