refactor: modularize codebase and add 404 unit tests (#13)
CI / Format (push) Successful in 4s
CI / Clippy (push) Successful in 4m19s
CI / Detect Changes (push) Successful in 5s
CI / Tests (push) Successful in 5m15s
CI / Deploy Agent (push) Successful in 2s
CI / Deploy Dashboard (push) Successful in 2s
CI / Deploy Docs (push) Has been skipped
CI / Deploy MCP (push) Successful in 2s
CI / Security Audit (push) Successful in 1m44s
CI / Format (push) Successful in 4s
CI / Clippy (push) Successful in 4m19s
CI / Detect Changes (push) Successful in 5s
CI / Tests (push) Successful in 5m15s
CI / Deploy Agent (push) Successful in 2s
CI / Deploy Dashboard (push) Successful in 2s
CI / Deploy Docs (push) Has been skipped
CI / Deploy MCP (push) Successful in 2s
CI / Security Audit (push) Successful in 1m44s
This commit was merged in pull request #13.
This commit is contained in:
@@ -172,3 +172,185 @@ impl GraphEngine {
|
||||
ImpactAnalyzer::new(code_graph)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use compliance_core::models::graph::{CodeEdgeKind, CodeNode, CodeNodeKind};
|
||||
|
||||
fn make_node(qualified_name: &str) -> CodeNode {
|
||||
CodeNode {
|
||||
id: None,
|
||||
repo_id: "test".to_string(),
|
||||
graph_build_id: "build1".to_string(),
|
||||
qualified_name: qualified_name.to_string(),
|
||||
name: qualified_name
|
||||
.split("::")
|
||||
.last()
|
||||
.unwrap_or(qualified_name)
|
||||
.to_string(),
|
||||
kind: CodeNodeKind::Function,
|
||||
file_path: "src/main.rs".to_string(),
|
||||
start_line: 1,
|
||||
end_line: 10,
|
||||
language: "rust".to_string(),
|
||||
community_id: None,
|
||||
is_entry_point: false,
|
||||
graph_index: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn build_test_node_map(names: &[&str]) -> HashMap<String, NodeIndex> {
|
||||
let mut graph: DiGraph<String, String> = DiGraph::new();
|
||||
let mut map = HashMap::new();
|
||||
for name in names {
|
||||
let idx = graph.add_node(name.to_string());
|
||||
map.insert(name.to_string(), idx);
|
||||
}
|
||||
map
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_resolve_edge_target_direct_match() {
|
||||
let engine = GraphEngine::new(1000);
|
||||
let node_map = build_test_node_map(&["src/main.rs::foo", "src/main.rs::bar"]);
|
||||
let result = engine.resolve_edge_target("src/main.rs::foo", &node_map);
|
||||
assert!(result.is_some());
|
||||
assert_eq!(result.unwrap(), node_map["src/main.rs::foo"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_resolve_edge_target_short_name_match() {
|
||||
let engine = GraphEngine::new(1000);
|
||||
let node_map = build_test_node_map(&["src/main.rs::foo", "src/main.rs::bar"]);
|
||||
let result = engine.resolve_edge_target("foo", &node_map);
|
||||
assert!(result.is_some());
|
||||
assert_eq!(result.unwrap(), node_map["src/main.rs::foo"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_resolve_edge_target_method_match() {
|
||||
let engine = GraphEngine::new(1000);
|
||||
let node_map = build_test_node_map(&["src/main.rs::MyStruct::do_thing"]);
|
||||
let result = engine.resolve_edge_target("do_thing", &node_map);
|
||||
assert!(result.is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_resolve_edge_target_self_method() {
|
||||
let engine = GraphEngine::new(1000);
|
||||
let node_map = build_test_node_map(&["src/main.rs::MyStruct::process"]);
|
||||
let result = engine.resolve_edge_target("self.process", &node_map);
|
||||
assert!(result.is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_resolve_edge_target_no_match() {
|
||||
let engine = GraphEngine::new(1000);
|
||||
let node_map = build_test_node_map(&["src/main.rs::foo"]);
|
||||
let result = engine.resolve_edge_target("nonexistent", &node_map);
|
||||
assert!(result.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_resolve_edge_target_empty_map() {
|
||||
let engine = GraphEngine::new(1000);
|
||||
let node_map = HashMap::new();
|
||||
let result = engine.resolve_edge_target("anything", &node_map);
|
||||
assert!(result.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_resolve_edge_target_dot_notation() {
|
||||
let engine = GraphEngine::new(1000);
|
||||
let node_map = build_test_node_map(&["src/app.js.handler"]);
|
||||
let result = engine.resolve_edge_target("handler", &node_map);
|
||||
assert!(result.is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_build_petgraph_empty() {
|
||||
let engine = GraphEngine::new(1000);
|
||||
let output = ParseOutput::default();
|
||||
let code_graph = engine.build_petgraph(output).unwrap();
|
||||
assert_eq!(code_graph.nodes.len(), 0);
|
||||
assert_eq!(code_graph.edges.len(), 0);
|
||||
assert_eq!(code_graph.graph.node_count(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_build_petgraph_nodes_get_graph_index() {
|
||||
let engine = GraphEngine::new(1000);
|
||||
let mut output = ParseOutput::default();
|
||||
output.nodes.push(make_node("src/main.rs::foo"));
|
||||
output.nodes.push(make_node("src/main.rs::bar"));
|
||||
|
||||
let code_graph = engine.build_petgraph(output).unwrap();
|
||||
assert_eq!(code_graph.nodes.len(), 2);
|
||||
assert_eq!(code_graph.graph.node_count(), 2);
|
||||
// All nodes should have a graph_index assigned
|
||||
for node in &code_graph.nodes {
|
||||
assert!(node.graph_index.is_some());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_build_petgraph_resolves_edges() {
|
||||
let engine = GraphEngine::new(1000);
|
||||
let mut output = ParseOutput::default();
|
||||
output.nodes.push(make_node("src/main.rs::foo"));
|
||||
output.nodes.push(make_node("src/main.rs::bar"));
|
||||
output.edges.push(CodeEdge {
|
||||
id: None,
|
||||
repo_id: "test".to_string(),
|
||||
graph_build_id: "build1".to_string(),
|
||||
source: "src/main.rs::foo".to_string(),
|
||||
target: "bar".to_string(), // short name, should resolve
|
||||
kind: CodeEdgeKind::Calls,
|
||||
file_path: "src/main.rs".to_string(),
|
||||
line_number: Some(5),
|
||||
});
|
||||
|
||||
let code_graph = engine.build_petgraph(output).unwrap();
|
||||
assert_eq!(code_graph.edges.len(), 1);
|
||||
assert_eq!(code_graph.graph.edge_count(), 1);
|
||||
// The resolved edge target should be the full qualified name
|
||||
assert_eq!(code_graph.edges[0].target, "src/main.rs::bar");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_build_petgraph_skips_unresolved_edges() {
|
||||
let engine = GraphEngine::new(1000);
|
||||
let mut output = ParseOutput::default();
|
||||
output.nodes.push(make_node("src/main.rs::foo"));
|
||||
output.edges.push(CodeEdge {
|
||||
id: None,
|
||||
repo_id: "test".to_string(),
|
||||
graph_build_id: "build1".to_string(),
|
||||
source: "src/main.rs::foo".to_string(),
|
||||
target: "external_crate::something".to_string(),
|
||||
kind: CodeEdgeKind::Calls,
|
||||
file_path: "src/main.rs".to_string(),
|
||||
line_number: Some(5),
|
||||
});
|
||||
|
||||
let code_graph = engine.build_petgraph(output).unwrap();
|
||||
assert_eq!(code_graph.edges.len(), 0);
|
||||
assert_eq!(code_graph.graph.edge_count(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_code_graph_node_map_consistency() {
|
||||
let engine = GraphEngine::new(1000);
|
||||
let mut output = ParseOutput::default();
|
||||
output.nodes.push(make_node("a::b"));
|
||||
output.nodes.push(make_node("a::c"));
|
||||
output.nodes.push(make_node("a::d"));
|
||||
|
||||
let code_graph = engine.build_petgraph(output).unwrap();
|
||||
assert_eq!(code_graph.node_map.len(), 3);
|
||||
assert!(code_graph.node_map.contains_key("a::b"));
|
||||
assert!(code_graph.node_map.contains_key("a::c"));
|
||||
assert!(code_graph.node_map.contains_key("a::d"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user