#[test]
fn test_to_dot_different_reference_kinds() {
let mut java_class = create_test_node(
"Java:class:User",
NodeKind::Class,
"User",
"com.example.User",
Language::Java,
);
java_class.add_reference(ReferenceKind::Inherits, "KotlinBase".to_string(), None);
java_class.add_reference(
ReferenceKind::Implements,
"KotlinInterface".to_string(),
None,
);
java_class.add_reference(ReferenceKind::Calls, "KotlinFunction".to_string(), None);
let kotlin_base = create_test_node(
"Kotlin:class:KotlinBase",
NodeKind::Class,
"KotlinBase",
"com.example.KotlinBase",
Language::Kotlin,
);
let kotlin_interface = create_test_node(
"Kotlin:interface:KotlinInterface",
NodeKind::Interface,
"KotlinInterface",
"com.example.KotlinInterface",
Language::Kotlin,
);
let kotlin_function = create_test_node(
"Kotlin:function:KotlinFunction",
NodeKind::Function,
"KotlinFunction",
"com.example.KotlinFunction",
Language::Kotlin,
);
let mut deps = CrossLanguageDependencies::new();
deps.add_nodes(vec![
java_class,
kotlin_base,
kotlin_interface,
kotlin_function,
]);
deps.detect_all();
let dot = deps.to_dot();
assert!(dot.contains("bold")); assert!(dot.contains("dashed")); assert!(dot.contains("solid")); }
#[test]
fn test_typescript_interface_single_char_after_i() {
let resolver = TypeScriptJavaResolver;
let ts_node = create_test_node(
"TypeScript:interface:IA",
NodeKind::Interface,
"IA",
"IA",
Language::TypeScript,
);
let java_node = create_test_node(
"Java:class:A",
NodeKind::Class,
"A",
"com.example.A",
Language::Java,
);
let reference = crate::ast::polyglot::unified_node::NodeReference {
kind: ReferenceKind::Uses,
target_id: String::new(),
target_name: "IA".to_string(),
target_language: Some(Language::Java),
};
assert!(resolver.can_resolve(
Language::TypeScript,
Language::Java,
&ts_node,
&reference,
&java_node,
));
}
#[test]
fn test_java_kotlin_resolver_different_package_depth() {
let resolver = JavaKotlinResolver;
let java_node = create_test_node(
"Java:class:User",
NodeKind::Class,
"User",
"com.example.User",
Language::Java,
);
let kotlin_node = create_test_node(
"Kotlin:class:Service",
NodeKind::Class,
"Service",
"com.example.api.Service",
Language::Kotlin,
);
let reference = crate::ast::polyglot::unified_node::NodeReference {
kind: ReferenceKind::Uses,
target_id: String::new(),
target_name: "com.example.Service".to_string(), target_language: Some(Language::Kotlin),
};
assert!(!resolver.can_resolve(
Language::Java,
Language::Kotlin,
&java_node,
&reference,
&kotlin_node,
));
}
#[test]
fn test_java_scala_resolver_package_parts_mismatch() {
let resolver = JavaScalaResolver;
let java_node = create_test_node(
"Java:class:User",
NodeKind::Class,
"User",
"com.example.User",
Language::Java,
);
let scala_node = create_test_node(
"Scala:class:DifferentService",
NodeKind::Class,
"DifferentService",
"com.example.DifferentService",
Language::Scala,
);
let reference = crate::ast::polyglot::unified_node::NodeReference {
kind: ReferenceKind::Uses,
target_id: String::new(),
target_name: "com.example.Service".to_string(), target_language: Some(Language::Scala),
};
assert!(!resolver.can_resolve(
Language::Java,
Language::Scala,
&java_node,
&reference,
&scala_node,
));
}
#[test]
fn test_typescript_java_no_interface_prefix() {
let resolver = TypeScriptJavaResolver;
let ts_node = create_test_node(
"TypeScript:interface:UserInterface",
NodeKind::Interface,
"UserInterface",
"UserInterface",
Language::TypeScript,
);
let java_node = create_test_node(
"Java:class:User",
NodeKind::Class,
"User",
"com.example.User",
Language::Java,
);
let reference = crate::ast::polyglot::unified_node::NodeReference {
kind: ReferenceKind::Uses,
target_id: String::new(),
target_name: "UserInterface".to_string(),
target_language: Some(Language::Java),
};
assert!(!resolver.can_resolve(
Language::TypeScript,
Language::Java,
&ts_node,
&reference,
&java_node,
));
}
#[test]
fn test_cross_language_dependency_struct() {
let dep = CrossLanguageDependency {
source_id: "source".to_string(),
target_id: "target".to_string(),
source_language: Language::Java,
target_language: Language::Kotlin,
kind: ReferenceKind::Inherits,
confidence: 0.95,
metadata: {
let mut m = HashMap::new();
m.insert("key".to_string(), "value".to_string());
m
},
};
assert_eq!(dep.source_id, "source");
assert_eq!(dep.target_id, "target");
assert_eq!(dep.source_language, Language::Java);
assert_eq!(dep.target_language, Language::Kotlin);
assert_eq!(dep.kind, ReferenceKind::Inherits);
assert!((dep.confidence - 0.95).abs() < f64::EPSILON);
assert_eq!(dep.metadata.get("key"), Some(&"value".to_string()));
}
#[test]
fn test_cross_language_dependencies_default() {
let deps = CrossLanguageDependencies::default();
assert!(deps.get_dependencies().is_empty());
}
#[test]
fn test_detect_with_name_resolver_integration() {
let mut deps = CrossLanguageDependencies::new();
deps.add_name_resolver(Language::Java, Box::new(JavaKotlinResolver));
let mut java_node = create_test_node(
"Java:class:Client",
NodeKind::Class,
"Client",
"com.example.Client",
Language::Java,
);
let ref1 = crate::ast::polyglot::unified_node::NodeReference {
kind: ReferenceKind::Uses,
target_id: String::new(),
target_name: "com.example.KotlinService".to_string(),
target_language: Some(Language::Kotlin),
};
java_node.references.push(ref1);
let kotlin_node = create_test_node(
"Kotlin:class:KotlinService",
NodeKind::Class,
"KotlinService",
"com.example.KotlinService",
Language::Kotlin,
);
deps.add_nodes(vec![java_node, kotlin_node]);
deps.detect_all();
let result = deps.get_dependencies();
assert!(!result.is_empty());
}
#[test]
fn test_all_reference_kinds() {
let all_kinds = [
ReferenceKind::Inherits,
ReferenceKind::Implements,
ReferenceKind::Calls,
ReferenceKind::Uses,
ReferenceKind::Creates,
ReferenceKind::Imports,
ReferenceKind::Annotates,
ReferenceKind::DependsOn,
];
for kind in all_kinds {
let mut java_node = create_test_node(
&format!("Java:class:Source{:?}", kind),
NodeKind::Class,
&format!("Source{:?}", kind),
&format!("com.example.Source{:?}", kind),
Language::Java,
);
java_node.add_reference(kind, format!("Target{:?}", kind), None);
let kotlin_node = create_test_node(
&format!("Kotlin:class:Target{:?}", kind),
NodeKind::Class,
&format!("Target{:?}", kind),
&format!("com.example.Target{:?}", kind),
Language::Kotlin,
);
let mut deps = CrossLanguageDependencies::new();
deps.add_nodes(vec![java_node, kotlin_node]);
deps.detect_all();
let filtered = deps.filter_by_kind(kind);
assert!(
!filtered.is_empty(),
"Expected at least one dependency of kind {:?}",
kind
);
assert_eq!(filtered[0].kind, kind);
}
}
#[test]
fn test_fqn_map_building() {
let mut deps = CrossLanguageDependencies::new();
let node1 = create_test_node(
"Java:method:process1",
NodeKind::Method,
"process",
"com.example.Service.process",
Language::Java,
);
let node2 = create_test_node(
"Java:method:process2",
NodeKind::Method,
"process",
"com.example.Service.process",
Language::Java,
);
deps.add_nodes(vec![node1, node2]);
let result = deps.detect_all();
assert!(result.is_empty());
}
#[test]
fn test_nodes_grouped_by_language() {
let mut deps = CrossLanguageDependencies::new();
let java_node = create_test_node(
"Java:class:JavaClass",
NodeKind::Class,
"JavaClass",
"com.example.JavaClass",
Language::Java,
);
let kotlin_node = create_test_node(
"Kotlin:class:KotlinClass",
NodeKind::Class,
"KotlinClass",
"com.example.KotlinClass",
Language::Kotlin,
);
let scala_node = create_test_node(
"Scala:class:ScalaClass",
NodeKind::Class,
"ScalaClass",
"com.example.ScalaClass",
Language::Scala,
);
let ts_node = create_test_node(
"TypeScript:class:TsClass",
NodeKind::Class,
"TsClass",
"TsClass",
Language::TypeScript,
);
deps.add_nodes(vec![java_node, kotlin_node, scala_node, ts_node]);
deps.detect_all();
let java_deps = deps.filter_by_source_language(Language::Java);
let kotlin_deps = deps.filter_by_source_language(Language::Kotlin);
let scala_deps = deps.filter_by_source_language(Language::Scala);
let ts_deps = deps.filter_by_source_language(Language::TypeScript);
assert!(java_deps.is_empty());
assert!(kotlin_deps.is_empty());
assert!(scala_deps.is_empty());
assert!(ts_deps.is_empty());
}
#[test]
fn test_to_dot_empty() {
let deps = CrossLanguageDependencies::new();
let dot = deps.to_dot();
assert!(dot.starts_with("digraph CrossLanguageDependencies {"));
assert!(dot.ends_with("}\n"));
assert!(!dot.contains("->"));
}
#[test]
fn test_cross_language_dependency_clone_debug() {
let dep = CrossLanguageDependency {
source_id: "source".to_string(),
target_id: "target".to_string(),
source_language: Language::Java,
target_language: Language::Kotlin,
kind: ReferenceKind::Inherits,
confidence: 1.0,
metadata: HashMap::new(),
};
let cloned = dep.clone();
assert_eq!(dep.source_id, cloned.source_id);
assert_eq!(dep.target_id, cloned.target_id);
let debug_str = format!("{:?}", dep);
assert!(debug_str.contains("CrossLanguageDependency"));
assert!(debug_str.contains("source"));
assert!(debug_str.contains("target"));
}
#[test]
fn test_deeply_nested_packages() {
let resolver = JavaKotlinResolver;
let java_node = create_test_node(
"Java:class:User",
NodeKind::Class,
"User",
"com.example.api.v2.internal.User",
Language::Java,
);
let kotlin_node = create_test_node(
"Kotlin:class:Service",
NodeKind::Class,
"Service",
"com.example.api.v2.internal.Service",
Language::Kotlin,
);
let reference = crate::ast::polyglot::unified_node::NodeReference {
kind: ReferenceKind::Uses,
target_id: String::new(),
target_name: "com.example.api.v2.internal.Service".to_string(),
target_language: Some(Language::Kotlin),
};
assert!(resolver.can_resolve(
Language::Java,
Language::Kotlin,
&java_node,
&reference,
&kotlin_node,
));
}
#[test]
fn test_cross_language_dependency_serde() {
let dep = CrossLanguageDependency {
source_id: "source".to_string(),
target_id: "target".to_string(),
source_language: Language::Java,
target_language: Language::Kotlin,
kind: ReferenceKind::Inherits,
confidence: 0.9,
metadata: {
let mut m = HashMap::new();
m.insert("key".to_string(), "value".to_string());
m
},
};
let json = serde_json::to_string(&dep).unwrap();
let deserialized: CrossLanguageDependency = serde_json::from_str(&json).unwrap();
assert_eq!(dep.source_id, deserialized.source_id);
assert_eq!(dep.target_id, deserialized.target_id);
assert_eq!(dep.kind, deserialized.kind);
assert!((dep.confidence - deserialized.confidence).abs() < f64::EPSILON);
}