#[path = "support/dependency.rs"]
mod support;
#[path = "support/group_members.rs"]
mod group_members;
#[path = "support/site_file.rs"]
mod site_file;
use group_members::members;
use site_file::site;
use echoes::{Echoes, SourceFile, TargetScan, group};
fn check_pair(case: &support::Case, failing: bool) {
let info: &[&str] = if failing { &["compile_fail"] } else { &[] };
let sites = [site("a", &case.a, info), site("b", &case.b, info)];
let report = group(&sites, 1, 0);
let expected = if case.family == "control" {
vec![vec!["a", "b"]]
} else {
vec![vec!["a"], vec!["b"]]
};
assert_eq!(
members(&report.groups),
expected,
"{} failing={failing}",
case.id
);
}
#[test]
fn dependency_negatives_and_alpha_control_keep_their_actual_members() {
for case in support::cases()
.iter()
.filter(|case| case.expected != "same" || case.family == "control")
{
check_pair(case, false);
}
}
#[test]
fn dependency_failing_mode_preserves_every_baseline_relation() {
for case in support::cases() {
check_pair(case, true);
}
}
#[test]
fn dependency_compile_fail_flags_separate_matching_source_forms() {
let case = support::cases()
.iter()
.find(|case| case.id == "C01_alpha_control")
.unwrap();
let sites = [
site("pass_a", &case.a, &[]),
site("pass_b", &case.b, &[]),
site("fail_a", &case.a, &["compile_fail"]),
site("fail_b", &case.b, &["compile_fail"]),
];
let report = group(&sites, 2, 0);
assert_eq!(
members(&report.groups),
vec![vec!["fail_a", "fail_b"], vec!["pass_a", "pass_b"]]
);
}
#[test]
fn dependency_text_fallback_keeps_literal_distinctions_and_site_identity() {
let sites = [
site("compact", "let value = @ 1;", &[]),
site("spaced", "let value = @ 1;", &[]),
site("different", "let value = @ 2;", &[]),
];
let report = group(&sites, 1, 0);
assert_eq!(
members(&report.groups),
vec![vec!["compact", "spaced"], vec!["different"]]
);
assert!(report.groups.iter().all(|group| group.unparsed));
}
#[test]
fn dependency_text_fallback_filters_by_original_word_count() {
let sites = [
site("first", "let value=@;", &["compile_fail"]),
site("second", "let value=@;", &["compile_fail"]),
];
let included = group(&sites, 2, 2);
assert_eq!(members(&included.groups), vec![vec!["first", "second"]]);
assert!(included.groups[0].unparsed);
assert_eq!(included.groups[0].tokens, 2);
assert_eq!(
members(group(&sites, 2, 3).groups.iter()),
Vec::<Vec<&str>>::new()
);
}
#[test]
fn dependency_nesting_fallback_cannot_merge_with_the_parsed_form() {
let deep = format!("let value = {}1u32{};", "(".repeat(256), ")".repeat(256));
let sites = [
site("plain", "let value = 1u32;", &[]),
site("parentheses", "let other = ((1u32));", &[]),
site("deep", &deep, &[]),
];
let report = group(&sites, 1, 0);
assert_eq!(
members(&report.groups),
vec![vec!["deep"], vec!["parentheses", "plain"]]
);
let parsed = report.groups.iter().find(|group| !group.unparsed).unwrap();
let fallback = report.groups.iter().find(|group| group.unparsed).unwrap();
assert_eq!(
parsed
.sites
.iter()
.map(|site| site.item.as_str())
.collect::<Vec<_>>(),
["parentheses", "plain"]
);
assert_eq!(fallback.sites[0].item, "deep");
}
#[test]
fn dependency_function_groups_respect_original_module_scopes() {
let text = "mod left {\n\
pub fn first(input: u32) -> u32 { input & 15u32 }\n\
pub fn second(value: u32) -> u32 { value & 15u32 }\n\
}\n\
mod right {\n\
pub fn third(input: u32) -> u32 { input & 15u32 }\n\
pub fn fourth(value: u32) -> u32 { value & 15u32 }\n\
}\n";
let target = TargetScan {
name: "dependency".to_owned(),
files: vec![SourceFile {
path: "src/lib.rs".to_owned(),
segments: Vec::new(),
cfg: Vec::new(),
parsed: syn::parse_file(text).unwrap(),
text: text.to_owned(),
rustdoc: true,
}],
library: true,
};
let report =
Echoes::default()
.functions()
.fn_min_tokens(0)
.run_targets("", &[target], &|_, _| None);
assert_eq!(
members(&report.groups),
vec![
vec!["dependency::left::first", "dependency::left::second"],
vec!["dependency::right::fourth", "dependency::right::third"]
]
);
assert!(
report
.groups
.iter()
.flat_map(|group| &group.sites)
.all(|site| site.public)
);
}