| 3027 | } |
| 3028 | |
| 3029 | fn collect_test_aggregation_included_files( |
| 3030 | root_prefix: &str, |
| 3031 | excluded_dir_rel: &str, |
| 3032 | ) -> (Option<String>, BTreeSet<String>) { |
| 3033 | let direct_aggregator_rel = test_aggregator_rel_for_dir(excluded_dir_rel); |
| 3034 | let primary_aggregator = join_project_path(root_prefix, &direct_aggregator_rel) |
| 3035 | .exists() |
| 3036 | .then_some(direct_aggregator_rel.clone()); |
| 3037 | let mut included_files = BTreeSet::new(); |
| 3038 | let mut check_dir = excluded_dir_rel.to_string(); |
| 3039 | |
| 3040 | while check_dir.starts_with("tests/") && check_dir != "tests" { |
| 3041 | let aggregator_rel = test_aggregator_rel_for_dir(&check_dir); |
| 3042 | let aggregator = join_project_path(root_prefix, &aggregator_rel); |
| 3043 | if aggregator.exists() { |
| 3044 | for include in parse_aggregator_includes(&aggregator) { |
| 3045 | let resolved = resolve_test_include(root_prefix, &aggregator_rel, &include); |
| 3046 | if Path::new(&resolved).exists() { |
| 3047 | included_files.insert(resolved); |
| 3048 | } |
| 3049 | } |
| 3050 | } |
| 3051 | let Some((parent, _)) = check_dir.rsplit_once('/') else { |
| 3052 | break; |
| 3053 | }; |
| 3054 | check_dir = parent.to_string(); |
| 3055 | } |
| 3056 | |
| 3057 | (primary_aggregator, included_files) |
| 3058 | } |
| 3059 | |
| 3060 | fn test_aggregation_check_single_file(file_path: &str) -> Vec<String> { |
| 3061 | let normalized = normalize_path(file_path); |