use assert_cmd::Command;
use predicates::prelude::*;
fn fixture_src() -> &'static str {
"tests/fixtures/sample_project/src"
}
fn fixture_lcov() -> &'static str {
"tests/fixtures/sample_project/lcov.info"
}
fn cmd() -> Command {
Command::cargo_bin("cargo-crap").expect("binary must be built")
}
#[test]
fn help_flag_exits_successfully() {
cmd()
.arg("--help")
.assert()
.success()
.stdout(predicate::str::contains("CRAP"));
}
#[test]
fn version_flag_exits_successfully() {
cmd()
.arg("--version")
.assert()
.success()
.stdout(predicate::str::contains("cargo-crap"));
}
#[test]
fn human_output_lists_all_fixture_functions() {
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.assert()
.stdout(predicate::str::contains("trivial"))
.stdout(predicate::str::contains("moderate"))
.stdout(predicate::str::contains("crappy"));
}
#[test]
fn without_lcov_functions_are_scored_pessimistically() {
cmd()
.arg("--path")
.arg(fixture_src())
.assert()
.stdout(predicate::str::contains("crappy"));
}
#[test]
fn json_output_is_valid_json_array() {
let output = cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--format")
.arg("json")
.output()
.expect("run");
let stdout = String::from_utf8(output.stdout).expect("utf8");
let parsed: serde_json::Value =
serde_json::from_str(&stdout).expect("stdout must be valid JSON");
assert!(parsed.is_array(), "JSON output must be an array");
}
#[test]
fn json_entries_have_required_fields() {
let output = cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--format")
.arg("json")
.output()
.expect("run");
let stdout = String::from_utf8(output.stdout).expect("utf8");
let entries: serde_json::Value = serde_json::from_str(&stdout).expect("valid JSON");
let first = &entries[0];
assert!(
first.get("function").is_some(),
"entry must have 'function'"
);
assert!(first.get("crap").is_some(), "entry must have 'crap'");
assert!(
first.get("cyclomatic").is_some(),
"entry must have 'cyclomatic'"
);
}
#[test]
fn fail_above_exits_one_when_threshold_exceeded() {
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--fail-above")
.assert()
.failure(); }
#[test]
fn fail_above_exits_zero_when_nothing_exceeds_high_threshold() {
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--fail-above")
.arg("--threshold")
.arg("9999")
.assert()
.success();
}
#[test]
fn top_limits_output_rows() {
let output = cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--format")
.arg("json")
.arg("--top")
.arg("1")
.output()
.expect("run");
let stdout = String::from_utf8(output.stdout).expect("utf8");
let entries: serde_json::Value = serde_json::from_str(&stdout).expect("valid JSON");
assert_eq!(
entries.as_array().map(|a| a.len()),
Some(1),
"--top 1 must return exactly 1 entry"
);
}
#[test]
fn missing_optimistic_does_not_flag_uncovered_functions() {
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--missing")
.arg("optimistic")
.arg("--fail-above")
.arg("--threshold")
.arg("30")
.assert()
.success();
}
#[test]
fn missing_skip_drops_uncovered_functions_from_output() {
let output = cmd()
.arg("--path")
.arg(fixture_src())
.arg("--missing")
.arg("skip")
.arg("--format")
.arg("json")
.output()
.expect("run");
let stdout = String::from_utf8(output.stdout).expect("utf8");
let entries: serde_json::Value = serde_json::from_str(&stdout).expect("valid JSON");
assert_eq!(
entries.as_array().map(|a| a.len()),
Some(0),
"--missing skip with no lcov must produce empty output"
);
}
#[test]
fn min_filter_keeps_only_entries_at_or_above_cutoff() {
let output = cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--min")
.arg("5")
.arg("--format")
.arg("json")
.output()
.expect("run");
let stdout = String::from_utf8(output.stdout).expect("utf8");
let entries: serde_json::Value = serde_json::from_str(&stdout).expect("valid JSON");
for entry in entries.as_array().expect("array") {
let crap = entry["crap"].as_f64().expect("crap is a number");
assert!(
crap >= 5.0,
"entry '{}' with crap={crap} must not appear with --min 5",
entry["function"]
);
}
assert!(
!stdout.contains("\"trivial\""),
"trivial (CRAP≈1.0) must be excluded by --min 5"
);
}
#[test]
fn nonexistent_path_exits_with_error() {
cmd()
.arg("--path")
.arg("/this/path/does/not/exist")
.assert()
.failure()
.stderr(predicate::str::contains("does not exist"));
}
#[test]
fn github_format_emits_warning_annotations() {
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--format")
.arg("github")
.assert()
.success()
.stdout(predicate::str::contains("::warning"))
.stdout(predicate::str::contains("crappy"));
}
#[test]
fn github_format_is_empty_when_threshold_is_very_high() {
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--format")
.arg("github")
.arg("--threshold")
.arg("9999")
.assert()
.success()
.stdout(predicate::str::is_empty());
}
#[test]
fn exclude_drops_matching_files_from_output() {
let output = cmd()
.arg("--path")
.arg(fixture_src())
.arg("--exclude")
.arg("**/*.rs") .arg("--format")
.arg("json")
.output()
.expect("run");
let stdout = String::from_utf8(output.stdout).expect("utf8");
let entries: serde_json::Value = serde_json::from_str(&stdout).expect("valid JSON");
assert_eq!(
entries.as_array().map(|a| a.len()),
Some(0),
"--exclude '**/*.rs' must produce empty output"
);
}
#[test]
fn exclude_invalid_glob_exits_with_error() {
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--exclude")
.arg("[invalid")
.assert()
.failure()
.stderr(predicate::str::contains("invalid exclude pattern"));
}
#[test]
fn allow_suppresses_matching_function() {
let output_before = cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--format")
.arg("json")
.output()
.expect("run");
let before: serde_json::Value =
serde_json::from_slice(&output_before.stdout).expect("valid JSON");
let names_before: Vec<_> = before
.as_array()
.unwrap()
.iter()
.filter_map(|e| e["function"].as_str())
.collect();
assert!(
names_before.contains(&"trivial"),
"trivial must appear without --allow"
);
let output_after = cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--allow")
.arg("trivial")
.arg("--format")
.arg("json")
.output()
.expect("run");
let after: serde_json::Value =
serde_json::from_slice(&output_after.stdout).expect("valid JSON");
let names_after: Vec<_> = after
.as_array()
.unwrap()
.iter()
.filter_map(|e| e["function"].as_str())
.collect();
assert!(
!names_after.contains(&"trivial"),
"--allow trivial must suppress it, got: {names_after:?}"
);
}
#[test]
fn allow_wildcard_suppresses_all_matching() {
let output = cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--allow")
.arg("*")
.arg("--format")
.arg("json")
.output()
.expect("run");
let stdout = String::from_utf8(output.stdout).expect("utf8");
let entries: serde_json::Value = serde_json::from_str(&stdout).expect("valid JSON");
assert_eq!(
entries.as_array().map(|a| a.len()),
Some(0),
"--allow '*' must suppress all entries"
);
}
#[test]
fn allow_invalid_glob_exits_with_error() {
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--allow")
.arg("[invalid")
.assert()
.failure()
.stderr(predicate::str::contains("invalid allow pattern"));
}
#[test]
fn output_writes_to_file() {
let dir = tempfile::tempdir().expect("tempdir");
let out_path = dir.path().join("out.json");
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--format")
.arg("json")
.arg("--output")
.arg(&out_path)
.assert()
.success();
let content = std::fs::read_to_string(&out_path).expect("output file must exist");
let parsed: serde_json::Value = serde_json::from_str(&content).expect("valid JSON");
assert!(parsed.is_array(), "--output must write a JSON array");
assert!(
!parsed.as_array().unwrap().is_empty(),
"output file must contain at least one entry"
);
}
#[test]
fn baseline_shows_delta_output() {
let dir = tempfile::tempdir().expect("tempdir");
let baseline_path = dir.path().join("baseline.json");
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--format")
.arg("json")
.arg("--output")
.arg(&baseline_path)
.assert()
.success();
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--baseline")
.arg(&baseline_path)
.assert()
.success()
.stdout(predicate::str::contains("unchanged"));
}
#[test]
fn baseline_json_output_has_entries_and_removed() {
let dir = tempfile::tempdir().expect("tempdir");
let baseline_path = dir.path().join("baseline.json");
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--format")
.arg("json")
.arg("--output")
.arg(&baseline_path)
.assert()
.success();
let output = cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--baseline")
.arg(&baseline_path)
.arg("--format")
.arg("json")
.output()
.expect("run");
let parsed: serde_json::Value = serde_json::from_slice(&output.stdout).expect("valid JSON");
assert!(
parsed.get("entries").is_some(),
"delta JSON must have 'entries' key"
);
assert!(
parsed.get("removed").is_some(),
"delta JSON must have 'removed' key"
);
}
#[test]
fn fail_regression_requires_baseline() {
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--fail-regression")
.assert()
.failure()
.stderr(predicate::str::contains(
"--fail-regression requires --baseline",
));
}
#[test]
fn fail_regression_exits_zero_when_nothing_regressed() {
let dir = tempfile::tempdir().expect("tempdir");
let baseline_path = dir.path().join("baseline.json");
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--format")
.arg("json")
.arg("--output")
.arg(&baseline_path)
.assert()
.success();
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--baseline")
.arg(&baseline_path)
.arg("--fail-regression")
.assert()
.success();
}
fn regression_baseline(dir: &tempfile::TempDir) -> std::path::PathBuf {
let baseline = serde_json::json!([{
"file": "tests/fixtures/sample_project/src/lib.rs",
"function": "crappy",
"line": 24,
"cyclomatic": 12.0,
"coverage": 100.0,
"crap": 1.0
}]);
let path = dir.path().join("baseline.json");
std::fs::write(&path, baseline.to_string()).expect("write baseline");
path
}
#[test]
fn github_format_with_regression_emits_warning() {
let dir = tempfile::tempdir().expect("tempdir");
let baseline_path = regression_baseline(&dir);
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--baseline")
.arg(&baseline_path)
.arg("--format")
.arg("github")
.assert()
.success()
.stdout(predicate::str::contains("::warning"))
.stdout(predicate::str::contains("crappy"));
}
#[test]
fn markdown_format_with_baseline_shows_delta_table() {
let dir = tempfile::tempdir().expect("tempdir");
let baseline_path = dir.path().join("baseline.json");
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--format")
.arg("json")
.arg("--output")
.arg(&baseline_path)
.assert()
.success();
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--baseline")
.arg(&baseline_path)
.arg("--format")
.arg("markdown")
.assert()
.success()
.stdout(predicate::str::contains("|---"))
.stdout(predicate::str::contains("↑"));
}
#[test]
fn markdown_format_with_regression_shows_delta_row() {
let dir = tempfile::tempdir().expect("tempdir");
let baseline_path = regression_baseline(&dir);
let output = cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--baseline")
.arg(&baseline_path)
.arg("--format")
.arg("markdown")
.output()
.expect("run");
let stdout = String::from_utf8(output.stdout).expect("utf8");
assert!(
stdout.contains("crappy"),
"markdown delta table must name the regressed function"
);
assert!(
stdout.contains('+'),
"delta column must show positive delta for regression"
);
}
fn removed_baseline(dir: &tempfile::TempDir) -> std::path::PathBuf {
let baseline = serde_json::json!([{
"file": "tests/fixtures/sample_project/src/lib.rs",
"function": "phantom_that_was_deleted",
"line": 1,
"cyclomatic": 1.0,
"coverage": 100.0,
"crap": 1.0
}]);
let path = dir.path().join("baseline.json");
std::fs::write(&path, baseline.to_string()).expect("write baseline");
path
}
#[test]
fn delta_human_shows_removed_functions_section() {
let dir = tempfile::tempdir().expect("tempdir");
let baseline_path = removed_baseline(&dir);
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--baseline")
.arg(&baseline_path)
.assert()
.success()
.stdout(predicate::str::contains("Removed since baseline"))
.stdout(predicate::str::contains("phantom_that_was_deleted"));
}
#[test]
fn delta_markdown_shows_removed_functions_section() {
let dir = tempfile::tempdir().expect("tempdir");
let baseline_path = removed_baseline(&dir);
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--baseline")
.arg(&baseline_path)
.arg("--format")
.arg("markdown")
.assert()
.success()
.stdout(predicate::str::contains("Removed since baseline"))
.stdout(predicate::str::contains("phantom_that_was_deleted"));
}
#[test]
fn delta_human_no_functions_found_when_everything_excluded() {
let dir = tempfile::tempdir().expect("tempdir");
let baseline_path = dir.path().join("baseline.json");
std::fs::write(&baseline_path, "[]").expect("write empty baseline");
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--exclude")
.arg("**/*.rs")
.arg("--baseline")
.arg(&baseline_path)
.assert()
.success()
.stdout(predicate::str::contains("No functions found"));
}
#[test]
fn markdown_format_empty_when_all_excluded() {
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--exclude")
.arg("**/*.rs")
.arg("--format")
.arg("markdown")
.assert()
.success()
.stdout(predicate::str::contains("No functions found"));
}
#[test]
fn markdown_format_all_clean_shows_tick_summary() {
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--missing")
.arg("optimistic")
.arg("--threshold")
.arg("9999")
.arg("--format")
.arg("markdown")
.assert()
.success()
.stdout(predicate::str::contains("✓"));
}
#[test]
fn markdown_format_none_coverage_shows_dash() {
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--format")
.arg("markdown")
.assert()
.success()
.stdout(predicate::str::contains("—"));
}
#[test]
fn markdown_format_produces_gfm_table() {
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--format")
.arg("markdown")
.assert()
.success()
.stdout(predicate::str::contains("|---"))
.stdout(predicate::str::contains("crappy"))
.stdout(predicate::str::contains("CRAP"));
}
#[test]
fn markdown_format_contains_all_fixture_functions() {
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--format")
.arg("markdown")
.assert()
.stdout(predicate::str::contains("trivial"))
.stdout(predicate::str::contains("moderate"))
.stdout(predicate::str::contains("crappy"));
}
#[test]
fn summary_prints_aggregate_stats_without_table() {
let output = cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--summary")
.output()
.expect("run");
let stdout = String::from_utf8(output.stdout).expect("utf8");
assert!(
stdout.contains("Analyzed"),
"summary must mention 'Analyzed'"
);
assert!(stdout.contains("Crappy"), "summary must mention 'Crappy'");
assert!(
!stdout.contains('╞'),
"summary must not contain table borders"
);
}
#[test]
fn summary_names_worst_offender_when_crappy() {
let output = cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--summary")
.output()
.expect("run");
let stdout = String::from_utf8(output.stdout).expect("utf8");
assert!(
stdout.contains("crappy"),
"summary must name the worst function, got: {stdout}"
);
}
#[test]
fn summary_exits_zero_when_all_clean() {
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--missing")
.arg("optimistic")
.arg("--summary")
.arg("--fail-above")
.assert()
.success()
.stdout(predicate::str::contains("Crappy: 0"));
}
#[test]
fn workspace_flag_analyzes_workspace_members() {
cmd()
.arg("--workspace")
.arg("--format")
.arg("json")
.assert()
.success()
.stdout(predicate::str::is_match(r"^\[").expect("json starts with ["))
.stdout(predicate::str::contains("function"));
}
#[test]
fn cargo_subcommand_form_strips_crap_argument() {
Command::cargo_bin("cargo-crap")
.expect("binary must be built")
.args(["crap", "--path", fixture_src(), "--format", "json"])
.assert()
.success()
.stdout(predicate::str::is_match(r"^\[").expect("json starts with ["));
}
#[test]
fn fail_regression_exits_one_when_regression_exists() {
let dir = tempfile::tempdir().expect("tempdir");
let baseline_path = regression_baseline(&dir);
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--baseline")
.arg(&baseline_path)
.arg("--fail-regression")
.assert()
.failure(); }
#[test]
fn fail_above_with_baseline_exits_one_when_crappy() {
let dir = tempfile::tempdir().expect("tempdir");
let baseline_path = regression_baseline(&dir);
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--baseline")
.arg(&baseline_path)
.arg("--fail-above") .assert()
.failure();
}
#[test]
fn fail_above_with_baseline_exits_zero_when_clean() {
let dir = tempfile::tempdir().expect("tempdir");
let baseline_path = dir.path().join("baseline.json");
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--format")
.arg("json")
.arg("--output")
.arg(&baseline_path)
.assert()
.success();
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--baseline")
.arg(&baseline_path)
.arg("--fail-above")
.arg("--threshold")
.arg("9999") .assert()
.success();
}
#[test]
fn delta_human_table_shows_function_names() {
let dir = tempfile::tempdir().expect("tempdir");
let baseline_path = removed_baseline(&dir);
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--baseline")
.arg(&baseline_path)
.assert()
.success()
.stdout(predicate::str::contains("crappy"))
.stdout(predicate::str::contains("trivial"));
}
#[test]
fn delta_human_summary_shows_accurate_counts() {
let dir = tempfile::tempdir().expect("tempdir");
let baseline_path = dir.path().join("baseline.json");
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--format")
.arg("json")
.arg("--output")
.arg(&baseline_path)
.assert()
.success();
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--baseline")
.arg(&baseline_path)
.assert()
.success()
.stdout(predicate::str::contains("0 regressed"))
.stdout(predicate::str::contains("0 improved"))
.stdout(predicate::str::contains("0 new"))
.stdout(predicate::str::contains("3 unchanged"));
}
#[test]
fn delta_markdown_summary_shows_accurate_counts() {
let dir = tempfile::tempdir().expect("tempdir");
let baseline_path = dir.path().join("baseline.json");
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--format")
.arg("json")
.arg("--output")
.arg(&baseline_path)
.assert()
.success();
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--baseline")
.arg(&baseline_path)
.arg("--format")
.arg("markdown")
.assert()
.success()
.stdout(predicate::str::contains("0 regressed"))
.stdout(predicate::str::contains("0 improved"))
.stdout(predicate::str::contains("0 new"))
.stdout(predicate::str::contains("3 unchanged"));
}
#[test]
fn summary_with_baseline_shows_delta_counts() {
let dir = tempfile::tempdir().expect("tempdir");
let baseline_path = dir.path().join("baseline.json");
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--format")
.arg("json")
.arg("--output")
.arg(&baseline_path)
.assert()
.success();
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--baseline")
.arg(&baseline_path)
.arg("--summary")
.assert()
.success()
.stdout(predicate::str::contains("0 regressed"))
.stdout(predicate::str::contains("0 improved"))
.stdout(predicate::str::contains("0 new"))
.stdout(predicate::str::contains("3 unchanged"));
}
#[test]
fn github_new_function_above_threshold_gets_warning() {
let dir = tempfile::tempdir().expect("tempdir");
let baseline_path = removed_baseline(&dir);
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--baseline")
.arg(&baseline_path)
.arg("--format")
.arg("github")
.assert()
.success()
.stdout(predicate::str::contains("::warning"))
.stdout(predicate::str::contains("crappy"));
}
#[test]
fn github_new_function_at_threshold_is_not_warned() {
let dir = tempfile::tempdir().expect("tempdir");
let baseline_path = removed_baseline(&dir);
let output = cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--baseline")
.arg(&baseline_path)
.arg("--format")
.arg("github")
.arg("--threshold")
.arg("156") .output()
.expect("run");
assert!(
output.stdout.is_empty(),
"function at exactly the threshold must not emit a warning, got: {}",
String::from_utf8_lossy(&output.stdout)
);
}
#[test]
fn markdown_clean_summary_says_none_exceed() {
cmd()
.arg("--path")
.arg(fixture_src())
.arg("--lcov")
.arg(fixture_lcov())
.arg("--missing")
.arg("optimistic")
.arg("--threshold")
.arg("9999")
.arg("--format")
.arg("markdown")
.assert()
.success()
.stdout(predicate::str::contains("none exceed CRAP threshold"));
}