use super::support::{build_workspace, empty_cfg_test, globset, run_check_a, run_check_b};
use crate::adapters::analyzers::architecture::compiled::CompiledCallParity;
use crate::adapters::analyzers::architecture::layer_rule::LayerDefinitions;
use crate::adapters::analyzers::architecture::{MatchLocation, ViolationKind};
use std::collections::HashSet;
fn rlm_fixture() -> Vec<(&'static str, &'static str)> {
vec![
(
"src/application/session.rs",
r#"
pub struct RlmSession;
pub struct Response;
pub struct Error;
impl RlmSession {
pub fn open_cwd() -> Result<RlmSession, Error> { todo!() }
pub fn open(path: &str) -> Result<RlmSession, Error> { todo!() }
pub fn diff(&self, path: &str) -> Result<Response, Error> { todo!() }
pub fn files(&self) -> Result<Response, Error> { todo!() }
pub fn insert(&self, content: &str) -> Result<Response, Error> { todo!() }
pub fn stats(&self) -> Response { todo!() }
pub fn genuinely_unused(&self) {}
}
"#,
),
(
"src/cli/handlers.rs",
r#"
use crate::application::session::RlmSession;
pub struct CliError;
fn map_err(_e: crate::application::session::Error) -> CliError { CliError }
pub fn cmd_diff(path: &str) -> Result<(), CliError> {
let session = RlmSession::open_cwd().map_err(map_err)?;
let _ = session.diff(path).map_err(map_err)?;
Ok(())
}
pub fn cmd_files() -> Result<(), CliError> {
let session = RlmSession::open_cwd().map_err(map_err)?;
let _ = session.files().map_err(map_err)?;
Ok(())
}
pub fn cmd_stats() -> Result<(), CliError> {
let session = RlmSession::open_cwd().map_err(map_err)?;
let _ = session.stats();
Ok(())
}
"#,
),
(
"src/mcp/handlers.rs",
r#"
use crate::application::session::RlmSession;
pub fn handle_diff(session: &RlmSession, path: &str) -> String {
let _ = session.diff(path);
String::new()
}
pub fn handle_files(session: &RlmSession) -> String {
let _ = session.files();
String::new()
}
pub fn handle_insert(session: &RlmSession, content: &str) -> String {
let _ = session.insert(content);
String::new()
}
"#,
),
]
}
fn rlm_layers() -> LayerDefinitions {
LayerDefinitions::new(
vec![
"application".to_string(),
"cli".to_string(),
"mcp".to_string(),
],
vec![
("application".to_string(), globset(&["src/application/**"])),
("cli".to_string(), globset(&["src/cli/**"])),
("mcp".to_string(), globset(&["src/mcp/**"])),
],
)
}
fn rlm_config() -> CompiledCallParity {
CompiledCallParity {
adapters: vec!["cli".to_string(), "mcp".to_string()],
target: "application".to_string(),
call_depth: 3,
exclude_targets: globset(&[]),
transparent_wrappers: HashSet::new(),
transparent_macros: HashSet::new(),
promoted_attributes: HashSet::new(),
single_touchpoint: crate::config::architecture::SingleTouchpointMode::default(),
}
}
fn missing_adapters_for(findings: &[MatchLocation], target_fn: &str) -> Option<Vec<String>> {
findings.iter().find_map(|f| match &f.kind {
ViolationKind::CallParityMissingAdapter {
target_fn: tf,
missing_adapters,
..
} if tf == target_fn => Some(missing_adapters.clone()),
_ => None,
})
}
#[test]
fn rlm_snapshot_check_a_no_spurious_findings() {
let ws = build_workspace(&rlm_fixture());
let findings = run_check_a(&ws, &rlm_layers(), &rlm_config(), &empty_cfg_test());
assert!(
findings.is_empty(),
"Check A should be clean on rlm-shape fixture, got {} findings: {:?}",
findings.len(),
findings
.iter()
.map(|f| format!("{}:{}", f.file, f.line))
.collect::<Vec<_>>()
);
}
#[test]
fn rlm_snapshot_check_b_diff_reached_from_both_adapters() {
let ws = build_workspace(&rlm_fixture());
let findings = run_check_b(&ws, &rlm_layers(), &rlm_config(), &empty_cfg_test());
let missing = missing_adapters_for(&findings, "crate::application::session::RlmSession::diff");
assert!(
missing.is_none(),
"RlmSession::diff should be reached from both adapters, got missing={:?}",
missing
);
}
#[test]
fn rlm_snapshot_check_b_files_reached_from_both_adapters() {
let ws = build_workspace(&rlm_fixture());
let findings = run_check_b(&ws, &rlm_layers(), &rlm_config(), &empty_cfg_test());
let missing = missing_adapters_for(&findings, "crate::application::session::RlmSession::files");
assert!(missing.is_none(), "RlmSession::files should be reached");
}
#[test]
fn rlm_snapshot_check_b_asymmetric_coverage_flagged() {
let ws = build_workspace(&rlm_fixture());
let findings = run_check_b(&ws, &rlm_layers(), &rlm_config(), &empty_cfg_test());
let missing = missing_adapters_for(&findings, "crate::application::session::RlmSession::stats")
.expect("stats should be missing from some adapter");
assert_eq!(missing, vec!["mcp".to_string()]);
let missing =
missing_adapters_for(&findings, "crate::application::session::RlmSession::insert")
.expect("insert should be missing from some adapter");
assert_eq!(missing, vec!["cli".to_string()]);
}
#[test]
fn rlm_snapshot_check_b_unreached_pub_fn_is_flagged() {
let ws = build_workspace(&rlm_fixture());
let findings = run_check_b(&ws, &rlm_layers(), &rlm_config(), &empty_cfg_test());
let missing = missing_adapters_for(
&findings,
"crate::application::session::RlmSession::genuinely_unused",
)
.expect("genuinely_unused must be flagged");
let set: HashSet<String> = missing.into_iter().collect();
assert!(set.contains("cli"));
assert!(set.contains("mcp"));
}
#[test]
fn rlm_snapshot_total_findings_budget() {
let ws = build_workspace(&rlm_fixture());
let layers = rlm_layers();
let cp = rlm_config();
let check_a = run_check_a(&ws, &layers, &cp, &empty_cfg_test());
let check_b = run_check_b(&ws, &layers, &cp, &empty_cfg_test());
assert_eq!(check_a.len(), 0, "Check A: {:?}", check_a);
assert_eq!(
check_b.len(),
5,
"Check B count drifted: {:?}",
check_b
.iter()
.filter_map(|f| match &f.kind {
ViolationKind::CallParityMissingAdapter { target_fn, .. } =>
Some(target_fn.as_str()),
_ => None,
})
.collect::<Vec<_>>()
);
}