use std::path::Path;
use crate::source_scan_tests::{CrateRoot, classified_sources, module_name, real_roots, source_root};
#[path = "standards_review_boundary_fixture_tests.rs"]
mod fixtures;
const CLIENT_FILE: &str = "standards_review/standards_review_client.rs";
const SERVICE_ONLY_MODULES: [&str; 3] = ["standards_review_client", "standards_review_run", "service_review"];
const SERVICE_ONLY_FILE_PREFIXES: [&str; 3] =
["standards_review/standards_review_client", "standards_review/standards_review_run", "service/service_review"];
fn may_name_service_modules(file: &str) -> bool {
return file == "lib.rs"
|| file.starts_with("source_guard/standards_review_boundary_")
|| file.starts_with("landing/service_work")
|| SERVICE_ONLY_FILE_PREFIXES.iter().any(|prefix| return file.starts_with(prefix));
}
fn native_sources_in(root: &Path, roots: &[CrateRoot]) -> Result<Vec<(String, String)>, String> {
let mut sources: Vec<(String, String)> = Vec::new();
for file in classified_sources(root, roots)? {
let text: String = std::fs::read_to_string(root.join(file.path.as_str()))
.map_err(|error| return format!("cannot read {}: {error}", file.path))?;
sources.push((file.path, text));
}
return Ok(sources);
}
fn native_sources() -> Vec<(String, String)> {
return native_sources_in(&source_root(), &real_roots()).expect("the crate's own sources");
}
fn without_declarations(text: &str) -> String {
let mut kept: Vec<&str> = Vec::new();
for line in text.lines() {
let declares_service_module: bool =
module_name(line).is_some_and(|name| return SERVICE_ONLY_MODULES.contains(&name));
if !declares_service_module {
kept.push(line);
}
}
return kept.join("\n");
}
fn violations(sources: &[(String, String)]) -> Vec<String> {
let mut found: Vec<String> = Vec::new();
for (file, text) in sources {
let client_tests: bool = file.starts_with("standards_review/standards_review_client");
if text.contains("ureq") && !client_tests && !file.starts_with("source_guard/standards_review_boundary_") {
found.push(format!("{file} names the HTTP library"));
}
let scanned: String = without_declarations(text).replace("service_review_key", "");
if !may_name_service_modules(file) && SERVICE_ONLY_MODULES.iter().any(|module| return scanned.contains(module)) {
found.push(format!("{file} names a service-only module"));
}
}
return found;
}
#[test]
fn the_network_client_is_reachable_only_from_the_service_run() {
let sources: Vec<(String, String)> = native_sources();
assert_eq!(violations(sources.as_slice()), Vec::<String>::new());
}
#[test]
fn the_scan_sees_the_client_and_flags_a_planted_import() {
let sources: Vec<(String, String)> = native_sources();
let client: &(String, String) = sources.iter().find(|(file, _)| return file == CLIENT_FILE).expect("the client file");
assert!(client.1.contains("ureq"), "the scan must see the library where it is used");
let client_path_files: Vec<&str> = vec!["main.rs", "invocation/entry.rs", "invocation/forwarding.rs", "commit/commit_command.rs"];
for file in client_path_files {
assert!(sources.iter().any(|(name, _)| return name == file), "{file} is part of the scanned tree");
}
let mut planted: Vec<(String, String)> = sources.clone();
planted.push((String::from("forwarding_extra.rs"), String::from("use super::standards_review_client::post_decision;")));
planted.push((String::from("entry_extra.rs"), String::from("let agent = ureq::Agent::new_with_defaults();")));
let found: Vec<String> = violations(planted.as_slice());
assert_eq!(found.len(), 2, "{found:?}");
assert!(found.iter().any(|line| return line.starts_with("forwarding_extra.rs")));
assert!(found.iter().any(|line| return line.starts_with("entry_extra.rs")));
}