use std::path::{Path, PathBuf};
use crate::tdg::file_discovery::{self, Policy, TEST_SOURCE_SKIP_REASON};
const THREE_UNWRAPS: &str = "pub fn a(x: Option<i32>) -> i32 { x.unwrap() }\n\
pub fn b(x: Option<i32>) -> i32 { x.unwrap() }\n\
pub fn c(x: Option<i32>) -> i32 { x.unwrap() }\n";
fn write(dir: &Path, relative: &str, body: &str) -> PathBuf {
let path = dir.join(relative);
std::fs::create_dir_all(path.parent().expect("parent")).expect("mkdir");
std::fs::write(&path, body).expect("write");
path
}
fn test_source_paths(root: &Path) -> Vec<PathBuf> {
[
"tests/bad.rs",
"benches/bad.rs",
"examples/bad.rs",
"fuzz/bad.rs",
]
.iter()
.map(|relative| write(root, relative, THREE_UNWRAPS))
.chain(
["src/bad_test.rs", "src/bad_tests.rs", "src/test_bad.rs"]
.iter()
.map(|relative| write(root, relative, THREE_UNWRAPS)),
)
.collect()
}
#[test]
fn both_analyzer_policies_refuse_the_same_test_sources() {
let dir = tempfile::tempdir().expect("tempdir");
for path in test_source_paths(dir.path()) {
let ast = file_discovery::refusal(&path, Policy::ast());
let heuristic = file_discovery::refusal(&path, Policy::heuristic());
assert_eq!(
ast,
heuristic,
"{} must get ONE skip-or-grade answer, not one per analyzer",
path.display()
);
assert_eq!(
ast.as_deref(),
Some(TEST_SOURCE_SKIP_REASON),
"{} is test or bench source",
path.display()
);
}
}
#[test]
fn grades_source_refuses_test_sources_and_says_why() {
let dir = tempfile::tempdir().expect("tempdir");
for path in test_source_paths(dir.path()) {
assert!(
!crate::tdg::grades_source(&path),
"{} is test source; grading it is how MCP produced 90.0/A for a file \
`pmat tdg` reports as skipped",
path.display()
);
assert_eq!(
crate::tdg::analyzer_simple::not_gradable_reason(&path).as_deref(),
Some(TEST_SOURCE_SKIP_REASON),
"the reason must be the one `pmat tdg` publishes in `skip_reason`"
);
}
}
#[test]
fn the_heuristic_analyzer_grades_production_source_and_refuses_test_source() {
let dir = tempfile::tempdir().expect("tempdir");
let production = write(dir.path(), "src/widget.rs", THREE_UNWRAPS);
let analyzer = crate::tdg::TdgAnalyzerSimple::new().expect("analyzer");
let graded = analyzer
.analyze_file(&production)
.expect("production source is graded");
assert!(
graded.total < 70.0,
"three unwraps are three critical defects: {} is not a verdict",
graded.total
);
for path in test_source_paths(dir.path()) {
let refused = analyzer
.analyze_file(&path)
.expect_err("test source must come back refused, never as a score");
assert!(
refused.to_string().contains(TEST_SOURCE_SKIP_REASON),
"refusal must name the rule, got: {refused}"
);
}
}
#[tokio::test]
async fn the_ast_analyzer_refuses_what_the_heuristic_analyzer_refuses() {
let dir = tempfile::tempdir().expect("tempdir");
let analyzer = crate::tdg::TdgAnalyzer::new().expect("analyzer");
for path in test_source_paths(dir.path()) {
let refused = analyzer
.analyze_file(&path)
.await
.expect_err("test source must come back refused, never as a score");
assert!(
refused.to_string().contains(TEST_SOURCE_SKIP_REASON),
"refusal must name the rule, got: {refused}"
);
}
}
#[tokio::test]
async fn mcp_quality_gate_reports_a_skipped_file_as_unmeasured_not_as_an_a() {
let dir = tempfile::tempdir().expect("tempdir");
for path in test_source_paths(dir.path()) {
let verdict = crate::mcp_pmcp::tool_functions::check_quality_gates(
std::slice::from_ref(&path),
false,
)
.await
.expect("gate reports");
assert_eq!(
verdict["passed"],
false,
"{}: a file this build refuses to grade must not pass a gate — {verdict}",
path.display()
);
assert!(
verdict["score"].is_null() && verdict["grade"].is_null(),
"{}: unmeasured is null, not 90.0/A — {verdict}",
path.display()
);
assert_eq!(
verdict["files_analyzed"],
0,
"{}: nothing was graded — {verdict}",
path.display()
);
let not_measured = verdict["not_measured"]
.as_array()
.expect("not_measured array");
assert!(
not_measured.iter().any(|v| v == "score"),
"{}: `not_measured: []` is a positive claim of full coverage — {verdict}",
path.display()
);
}
}
#[test]
fn a_project_walk_excludes_test_source_for_both_policies() {
let dir = tempfile::tempdir().expect("tempdir");
write(dir.path(), "src/widget.rs", THREE_UNWRAPS);
let hidden = test_source_paths(dir.path());
for policy in [Policy::ast(), Policy::heuristic()] {
let found = file_discovery::discover(dir.path(), policy).expect("walk");
assert_eq!(
found.gradable.len(),
1,
"only src/widget.rs is production source, got {:?}",
found.gradable
);
for path in &hidden {
assert!(
!found.ungraded.iter().any(|(file, _)| file == path),
"{} is excluded by policy, not a hole in the verdict",
path.display()
);
}
}
}
#[test]
fn the_defect_count_does_not_depend_on_where_the_bytes_sit() {
use crate::tdg::Language;
let analyzer = crate::tdg::TdgAnalyzerSimple::new().expect("analyzer");
let production = analyzer
.analyze_source(
THREE_UNWRAPS,
Language::Rust,
Some(PathBuf::from("/w/widget.rs")),
)
.expect("scored");
assert_eq!(production.critical_defects_count, 3, "three unwraps");
for label in [
"/w/examples/bad.rs",
"/w/benches/bad.rs",
"/w/src/bad_tests.rs",
] {
let elsewhere = analyzer
.analyze_source(THREE_UNWRAPS, Language::Rust, Some(PathBuf::from(label)))
.expect("scored");
assert_eq!(
elsewhere.critical_defects_count, production.critical_defects_count,
"{label}: the same bytes carry the same defects; a detector that \
excludes by PATH turns 'not detected here' into a perfect grade"
);
assert_eq!(
elsewhere.total, production.total,
"{label}: and therefore the same score"
);
}
}
#[test]
fn a_shebang_script_is_disclosed_like_its_dotted_twin() {
let dir = tempfile::tempdir().expect("tempdir");
let script = "#!/usr/bin/env bash\nset -euo pipefail\ndeploy() { :; }\n";
write(dir.path(), "deploy", script);
write(dir.path(), "deploy.sh", script);
write(dir.path(), "LICENSE", "All rights reserved.\n");
let found = file_discovery::discover(dir.path(), Policy::heuristic()).expect("walk");
let disclosed: Vec<String> = found
.ungraded
.iter()
.filter_map(|(path, _)| path.file_name()?.to_str().map(str::to_string))
.collect();
assert!(
disclosed.contains(&"deploy".to_string()),
"an extensionless shell script is source this build cannot grade, and a \
silent drop is exactly what `not_measured: []` misreports: {disclosed:?}"
);
assert!(
disclosed.contains(&"deploy.sh".to_string()),
"the dotted twin was already disclosed: {disclosed:?}"
);
assert!(
!disclosed.contains(&"LICENSE".to_string()),
"a licence is not source and is not a hole in a source average: {disclosed:?}"
);
}
#[test]
fn ungradable_source_is_named_from_one_authority_plus_its_declared_gaps() {
let dir = tempfile::tempdir().expect("tempdir");
for name in ["a.sh", "a.zig", "a.php", "a.f90", "a.vue", "a.awk"] {
write(dir.path(), name, "x\n");
}
write(dir.path(), "a.json", "{}\n");
let found = file_discovery::discover(dir.path(), Policy::heuristic()).expect("walk");
let disclosed: Vec<String> = found
.ungraded
.iter()
.filter_map(|(path, _)| path.file_name()?.to_str().map(str::to_string))
.collect();
for name in ["a.sh", "a.zig", "a.php", "a.f90", "a.vue", "a.awk"] {
assert!(
disclosed.contains(&name.to_string()),
"{name} is source this build cannot grade and must be disclosed: {disclosed:?}"
);
}
assert!(
!disclosed.contains(&"a.json".to_string()),
"data is not a hole in a source average: {disclosed:?}"
);
}