use crate::adapters::shared::cfg_test_files::collect_cfg_test_file_paths;
type ClassifyCase = (
&'static str,
&'static [(&'static str, &'static str)],
&'static [&'static str],
&'static [&'static str],
);
#[test]
fn cfg_test_classification_propagates_and_honours_package_roots() {
let cases: &[ClassifyCase] = &[
(
"cfg-test status propagates transitively through a mod chain",
&[
("src/parent.rs", "#[cfg(test)]\nmod tests;"),
("src/parent/tests/mod.rs", "mod golden;"),
(
"src/parent/tests/golden.rs",
"pub fn helper() -> u32 { 42 }",
),
],
&["src/parent/tests/mod.rs", "src/parent/tests/golden.rs"],
&[],
),
(
"a package nested under an outer `tests` segment classifies its own tests/",
&[
("fixtures/tests/retry/src/lib.rs", "pub fn run() {}"),
(
"fixtures/tests/retry/tests/integration.rs",
"#[test] fn it() {}",
),
("fixtures/tests/other.rs", "pub fn outer() {}"),
],
&["fixtures/tests/retry/tests/integration.rs"],
&["fixtures/tests/other.rs"],
),
];
for (label, files, present, absent) in cases {
let parsed: Vec<(String, String, syn::File)> = files
.iter()
.map(|(p, c)| (p.to_string(), c.to_string(), syn::parse_file(c).unwrap()))
.collect();
let result = collect_cfg_test_file_paths(&parsed);
for p in *present {
assert!(
result.contains(*p),
"case {label}: {p} must be cfg-test: {result:?}"
);
}
for a in *absent {
assert!(
!result.contains(*a),
"case {label}: {a} must NOT be cfg-test: {result:?}"
);
}
}
}
#[test]
fn cfg_test_propagation_does_not_tag_unrelated_files() {
let prod_code = r#"
mod helpers;
"#;
let helpers_code = r#"
pub fn util() {}
"#;
let parsed = vec![
(
"src/prod.rs".to_string(),
prod_code.to_string(),
syn::parse_file(prod_code).unwrap(),
),
(
"src/prod/helpers.rs".to_string(),
helpers_code.to_string(),
syn::parse_file(helpers_code).unwrap(),
),
];
let result = collect_cfg_test_file_paths(&parsed);
assert!(
!result.contains("src/prod/helpers.rs"),
"production sub-module must not be cfg-test: {result:?}"
);
}
#[test]
fn per_crate_tests_dir_recognized_as_integration_test() {
let code = r#"
#[tokio::test]
async fn end_to_end() {}
"#;
let lib = "pub fn run() {}";
let parsed = vec![
(
"crates/sv-utility-retry/src/lib.rs".to_string(),
lib.to_string(),
syn::parse_file(lib).unwrap(),
),
(
"crates/sv-utility-retry/tests/integration.rs".to_string(),
code.to_string(),
syn::parse_file(code).unwrap(),
),
];
let result = collect_cfg_test_file_paths(&parsed);
assert!(
result.contains("crates/sv-utility-retry/tests/integration.rs"),
"per-crate tests/ integration file must be cfg-test: {result:?}"
);
}
#[test]
fn workspace_root_tests_dir_recognized_as_integration_test() {
let code = "#[test] fn it_works() {}";
let lib = "pub fn run() {}";
let parsed = vec![
(
"src/lib.rs".to_string(),
lib.to_string(),
syn::parse_file(lib).unwrap(),
),
(
"tests/integration.rs".to_string(),
code.to_string(),
syn::parse_file(code).unwrap(),
),
];
let result = collect_cfg_test_file_paths(&parsed);
assert!(
result.contains("tests/integration.rs"),
"analysis-root tests/ integration file must be cfg-test: {result:?}"
);
}
#[test]
fn tests_dir_only_classified_at_a_real_package_root() {
let crate_lib = "pub fn run() {}";
let it = "#[test] fn it() {}";
let fixture = "pub fn support() {}";
let tool = "pub fn helper() {}";
let parsed = vec![
(
"crates/x/src/lib.rs".to_string(),
crate_lib.to_string(),
syn::parse_file(crate_lib).unwrap(),
),
(
"crates/x/tests/it.rs".to_string(),
it.to_string(),
syn::parse_file(it).unwrap(),
),
(
"fixtures/tests/support.rs".to_string(),
fixture.to_string(),
syn::parse_file(fixture).unwrap(),
),
(
"tools/shared/tests/helpers.rs".to_string(),
tool.to_string(),
syn::parse_file(tool).unwrap(),
),
];
let result = collect_cfg_test_file_paths(&parsed);
assert!(
result.contains("crates/x/tests/it.rs"),
"tests/ at a real package root (has sibling src/) must be cfg-test: {result:?}"
);
assert!(
!result.contains("fixtures/tests/support.rs"),
"tests/ with no sibling src/ must NOT be cfg-test: {result:?}"
);
assert!(
!result.contains("tools/shared/tests/helpers.rs"),
"nested non-package-root tests/ must NOT be cfg-test: {result:?}"
);
}
#[test]
fn tests_dir_next_to_src_without_crate_root_file_not_classified() {
let internal = "pub fn data() {}"; let support = "pub fn support() {}";
let parsed = vec![
(
"vendor/widget/src/internal.rs".to_string(),
internal.to_string(),
syn::parse_file(internal).unwrap(),
),
(
"vendor/widget/tests/support.rs".to_string(),
support.to_string(),
syn::parse_file(support).unwrap(),
),
];
let result = collect_cfg_test_file_paths(&parsed);
assert!(
!result.contains("vendor/widget/tests/support.rs"),
"tests/ next to a src/ without a crate-root file must NOT be cfg-test: {result:?}"
);
}
#[test]
fn tests_dir_next_to_crate_root_file_classified() {
let lib = "pub fn run() {}";
let it = "#[test] fn it() {}";
let parsed = vec![
(
"vendor/widget/src/lib.rs".to_string(),
lib.to_string(),
syn::parse_file(lib).unwrap(),
),
(
"vendor/widget/tests/support.rs".to_string(),
it.to_string(),
syn::parse_file(it).unwrap(),
),
];
let result = collect_cfg_test_file_paths(&parsed);
assert!(
result.contains("vendor/widget/tests/support.rs"),
"tests/ next to a crate-root file must be cfg-test: {result:?}"
);
}
#[test]
fn tests_dir_next_to_bin_only_crate_classified() {
let bin = "fn main() {}";
let it = "#[test] fn it() {}";
let parsed = vec![
(
"crates/cli/src/bin/tool.rs".to_string(),
bin.to_string(),
syn::parse_file(bin).unwrap(),
),
(
"crates/cli/tests/it.rs".to_string(),
it.to_string(),
syn::parse_file(it).unwrap(),
),
];
let result = collect_cfg_test_file_paths(&parsed);
assert!(
result.contains("crates/cli/tests/it.rs"),
"tests/ next to a src/bin/ autobinary crate must be cfg-test: {result:?}"
);
}
#[test]
fn is_integration_test_path_matches_package_root_tests_only() {
use crate::adapters::shared::cfg_test_files::is_integration_test_path;
use std::collections::HashSet;
let roots: HashSet<String> = ["", "crates/x", "crates/my-src-tool"]
.iter()
.map(|s| s.to_string())
.collect();
assert!(is_integration_test_path("tests/it.rs", &roots));
assert!(is_integration_test_path("crates/x/tests/it.rs", &roots));
assert!(is_integration_test_path(
"crates/my-src-tool/tests/it.rs",
&roots
));
assert!(!is_integration_test_path(
"fixtures/tests/support.rs",
&roots
));
assert!(!is_integration_test_path(
"tools/shared/tests/helpers.rs",
&roots
));
assert!(!is_integration_test_path("src/foo/tests/bar.rs", &roots));
assert!(!is_integration_test_path(
"crates/x/src/foo/tests/bar.rs",
&roots
));
assert!(!is_integration_test_path("src/lib.rs", &roots));
}
#[test]
fn nested_src_tests_dir_not_blanket_classified_as_integration() {
let code = "pub fn connect() {}";
let parsed = vec![(
"src/database/tests/connection.rs".to_string(),
code.to_string(),
syn::parse_file(code).unwrap(),
)];
let result = collect_cfg_test_file_paths(&parsed);
assert!(
!result.contains("src/database/tests/connection.rs"),
"production file under src/**/tests/ must not be auto cfg-test: {result:?}"
);
}
#[test]
fn src_tests_dir_reached_via_cfg_test_mod_still_classified() {
let parent_code = r#"
#[cfg(test)]
mod tests;
"#;
let child_code = "pub fn helper() -> u32 { 42 }";
let parsed = vec![
(
"src/database.rs".to_string(),
parent_code.to_string(),
syn::parse_file(parent_code).unwrap(),
),
(
"src/database/tests.rs".to_string(),
child_code.to_string(),
syn::parse_file(child_code).unwrap(),
),
];
let result = collect_cfg_test_file_paths(&parsed);
assert!(
result.contains("src/database/tests.rs"),
"src test file reached via #[cfg(test)] mod must still be cfg-test: {result:?}"
);
}
#[test]
fn collect_cfg_test_file_paths_basic() {
let parent_code = r#"
#[cfg(test)]
mod helpers;
"#;
let child_code = "pub fn h() {}";
let parent_ast = syn::parse_file(parent_code).unwrap();
let child_ast = syn::parse_file(child_code).unwrap();
let parsed = vec![
(
"src/lib.rs".to_string(),
parent_code.to_string(),
parent_ast,
),
(
"src/helpers.rs".to_string(),
child_code.to_string(),
child_ast,
),
];
let result = collect_cfg_test_file_paths(&parsed);
assert!(
result.contains("src/helpers.rs"),
"Should detect src/helpers.rs as cfg-test file"
);
}
#[test]
fn inner_cfg_test_file_attribute_marks_file_as_cfg_test() {
let code = r#"
#![cfg(test)]
pub fn helper() -> u32 { 42 }
"#;
let parsed = vec![(
"src/foo_tests.rs".to_string(),
code.to_string(),
syn::parse_file(code).unwrap(),
)];
let result = collect_cfg_test_file_paths(&parsed);
assert!(
result.contains("src/foo_tests.rs"),
"inner `#![cfg(test)]` must tag the file as cfg-test: {result:?}"
);
}
#[test]
fn path_attribute_on_cfg_test_mod_redirects_to_target_file() {
let parent_code = r#"
#[cfg(test)]
#[path = "foo_tests.rs"]
mod tests;
"#;
let companion_code = r#"
pub fn helper() -> u32 { 42 }
"#;
let parsed = vec![
(
"src/foo.rs".to_string(),
parent_code.to_string(),
syn::parse_file(parent_code).unwrap(),
),
(
"src/foo_tests.rs".to_string(),
companion_code.to_string(),
syn::parse_file(companion_code).unwrap(),
),
];
let result = collect_cfg_test_file_paths(&parsed);
assert!(
result.contains("src/foo_tests.rs"),
"`#[path]` on a cfg-test mod must redirect to the target file: {result:?}"
);
}
#[test]
fn path_attribute_resolves_relative_to_parent_dir() {
let parent_code = r#"
#[cfg(test)]
#[path = "rust_tests.rs"]
mod tests;
"#;
let companion_code = r#"
pub fn helper() -> u32 { 42 }
"#;
let parsed = vec![
(
"src/ingest/code/rust.rs".to_string(),
parent_code.to_string(),
syn::parse_file(parent_code).unwrap(),
),
(
"src/ingest/code/rust_tests.rs".to_string(),
companion_code.to_string(),
syn::parse_file(companion_code).unwrap(),
),
];
let result = collect_cfg_test_file_paths(&parsed);
assert!(
result.contains("src/ingest/code/rust_tests.rs"),
"relative `#[path]` must resolve against the parent file's directory: {result:?}"
);
}
#[test]
fn nested_file_under_src_bin_is_not_an_autobinary_crate_root() {
let parsed = vec![
(
"myapp/src/bin/sub/deep.rs".to_string(),
"fn main() {}".to_string(),
syn::parse_file("fn main() {}").unwrap(),
),
(
"myapp/tests/it.rs".to_string(),
"#[test] fn it() {}".to_string(),
syn::parse_file("#[test] fn it() {}").unwrap(),
),
];
let result = collect_cfg_test_file_paths(&parsed);
assert!(
!result.contains("myapp/tests/it.rs"),
"tests/ next to a NESTED src/bin file (not a real crate root) must not \
be classified as integration: {result:?}"
);
}
#[test]
fn inline_mod_does_not_propagate_cfg_test_to_same_named_external_file() {
let lib = "#[cfg(test)]\nmod c;\npub fn run() {}";
let c = "mod m { pub fn x() -> u32 { 1 } }"; let m = "pub fn y() -> u32 { 2 }"; let parsed = vec![
(
"pkg/src/lib.rs".to_string(),
lib.to_string(),
syn::parse_file(lib).unwrap(),
),
(
"pkg/src/c.rs".to_string(),
c.to_string(),
syn::parse_file(c).unwrap(),
),
(
"pkg/src/c/m.rs".to_string(),
m.to_string(),
syn::parse_file(m).unwrap(),
),
];
let result = collect_cfg_test_file_paths(&parsed);
assert!(
result.contains("pkg/src/c.rs"),
"c.rs is reached via `#[cfg(test)] mod c;` and must be cfg-test: {result:?}"
);
assert!(
!result.contains("pkg/src/c/m.rs"),
"an INLINE `mod m` must not propagate cfg-test to the external file \
`c/m.rs`: {result:?}"
);
}