pub mod composition;
pub mod context;
pub mod daemon_client;
pub mod dedup;
pub mod engines;
pub mod findings;
pub mod ir;
pub mod types;
pub use context::L2Context;
pub use types::*;
pub trait L2Engine: Send + Sync {
fn name(&self) -> &'static str;
fn finding_types(&self) -> &[&'static str];
fn languages(&self) -> &[tldr_core::Language] {
&[]
}
fn analyze(&self, ctx: &context::L2Context) -> types::L2AnalyzerOutput;
}
pub fn l2_engine_registry() -> Vec<Box<dyn L2Engine>> {
vec![
Box::new(engines::tldr_differential::TldrDifferentialEngine::new()),
]
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_l2_engine_registry_contains_engines() {
let engines = l2_engine_registry();
assert_eq!(engines.len(), 1, "Registry should contain exactly 1 engine (TldrDifferentialEngine)");
assert!(
engines.iter().any(|e| e.name() == "TldrDifferentialEngine"),
"Registry must contain TldrDifferentialEngine"
);
}
#[test]
fn test_tldr_engine_registered() {
let engines = l2_engine_registry();
let engine = engines.iter().find(|e| e.name() == "TldrDifferentialEngine");
assert!(engine.is_some(), "TldrDifferentialEngine must be in registry");
let engine = engine.unwrap();
assert_eq!(engine.finding_types().len(), 11);
}
#[test]
fn test_l2_engine_trait_object_safe() {
struct MockEngine;
impl L2Engine for MockEngine {
fn name(&self) -> &'static str {
"MockEngine"
}
fn finding_types(&self) -> &[&'static str] {
&["test-finding"]
}
fn analyze(&self, _ctx: &context::L2Context) -> types::L2AnalyzerOutput {
types::L2AnalyzerOutput {
findings: vec![],
status: types::AnalyzerStatus::Complete,
duration_ms: 0,
functions_analyzed: 0,
functions_skipped: 0,
}
}
}
let engine: Box<dyn L2Engine> = Box::new(MockEngine);
assert_eq!(engine.name(), "MockEngine");
assert_eq!(engine.finding_types(), &["test-finding"]);
assert!(engine.languages().is_empty());
let ctx = context::L2Context::new(
std::path::PathBuf::from("/tmp/test"),
tldr_core::Language::Rust,
vec![],
context::FunctionDiff {
changed: vec![],
inserted: vec![],
deleted: vec![],
},
std::collections::HashMap::new(),
std::collections::HashMap::new(),
std::collections::HashMap::new(),
);
let output = engine.analyze(&ctx);
assert!(output.findings.is_empty());
assert_eq!(output.status, types::AnalyzerStatus::Complete);
assert_eq!(output.duration_ms, 0);
assert_eq!(output.functions_analyzed, 0);
assert_eq!(output.functions_skipped, 0);
}
}