use debtmap::analyzers::trait_implementation_tracker::{
TraitExtractor, TraitImplementationTracker,
};
use debtmap::analyzers::trait_resolver::{ResolutionPriority, TraitResolver};
use debtmap::priority::call_graph::FunctionId;
use im::HashSet;
use std::path::PathBuf;
use std::sync::Arc;
#[test]
fn test_basic_trait_definition_extraction() {
let code = r#"
trait Display {
fn fmt(&self) -> String;
}
trait Debug {
fn debug(&self) -> String {
format!("Debug: {:?}", self)
}
}
"#;
let ast = syn::parse_file(code).unwrap();
let mut extractor = TraitExtractor::new(PathBuf::from("test.rs"));
let tracker = extractor.extract(&ast);
assert!(tracker.get_trait("Display").is_some());
assert!(tracker.get_trait("Debug").is_some());
let display = tracker.get_trait("Display").unwrap();
assert_eq!(display.name, "Display");
assert_eq!(display.methods.len(), 1);
assert_eq!(display.methods[0].name, "fmt");
assert!(!display.methods[0].has_default);
let debug = tracker.get_trait("Debug").unwrap();
assert_eq!(debug.methods.len(), 1);
assert!(debug.methods[0].has_default);
}
#[test]
fn test_trait_implementation_extraction() {
let code = r#"
trait Display {
fn fmt(&self) -> String;
}
struct MyStruct {
value: i32,
}
impl Display for MyStruct {
fn fmt(&self) -> String {
format!("MyStruct({})", self.value)
}
}
"#;
let ast = syn::parse_file(code).unwrap();
let mut extractor = TraitExtractor::new(PathBuf::from("test.rs"));
let tracker = extractor.extract(&ast);
assert!(tracker.implements_trait("MyStruct", "Display"));
assert_eq!(tracker.get_traits_for_type("MyStruct").unwrap().len(), 1);
}
#[test]
fn test_generic_trait_implementation() {
let code = r#"
trait Container<T> {
fn get(&self) -> &T;
}
struct Box<T> {
value: T,
}
impl<T> Container<T> for Box<T> {
fn get(&self) -> &T {
&self.value
}
}
"#;
let ast = syn::parse_file(code).unwrap();
let mut extractor = TraitExtractor::new(PathBuf::from("test.rs"));
let tracker = extractor.extract(&ast);
assert!(tracker.implementations.contains_key("Container"));
let impls = tracker.implementations.get("Container").unwrap();
assert_eq!(impls.len(), 1);
assert_eq!(impls[0].implementing_type, "Box<T>");
}
#[test]
fn test_blanket_implementation_detection() {
let code = r#"
trait ToString {
fn to_string(&self) -> String;
}
impl<T: std::fmt::Display> ToString for T {
fn to_string(&self) -> String {
format!("{}", self)
}
}
"#;
let ast = syn::parse_file(code).unwrap();
let mut extractor = TraitExtractor::new(PathBuf::from("test.rs"));
let tracker = extractor.extract(&ast);
assert!(!tracker.blanket_impls.is_empty());
assert_eq!(tracker.blanket_impls[0].trait_name, "ToString");
assert!(tracker.blanket_impls[0].is_blanket);
}
#[test]
fn test_trait_object_resolution() {
let code = r#"
trait Handler {
fn handle(&self);
}
struct FileHandler;
struct NetworkHandler;
impl Handler for FileHandler {
fn handle(&self) {}
}
impl Handler for NetworkHandler {
fn handle(&self) {}
}
"#;
let ast = syn::parse_file(code).unwrap();
let mut extractor = TraitExtractor::new(PathBuf::from("test.rs"));
let tracker = extractor.extract(&ast);
let implementors = tracker.get_implementors("Handler").unwrap();
assert_eq!(implementors.len(), 2);
assert!(implementors.contains("FileHandler"));
assert!(implementors.contains("NetworkHandler"));
let methods = tracker.resolve_trait_object_call("Handler", "handle");
assert_eq!(methods.len(), 2);
}
#[test]
fn test_associated_type_tracking() {
let code = r#"
trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
}
struct Counter {
count: u32,
}
impl Iterator for Counter {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
self.count += 1;
Some(self.count)
}
}
"#;
let ast = syn::parse_file(code).unwrap();
let mut extractor = TraitExtractor::new(PathBuf::from("test.rs"));
let tracker = extractor.extract(&ast);
let iterator = tracker.get_trait("Iterator").unwrap();
assert_eq!(iterator.associated_types.len(), 1);
assert_eq!(iterator.associated_types[0].name, "Item");
}
#[test]
fn test_method_resolution_order() {
let tracker = TraitImplementationTracker::new();
let mut resolver = TraitResolver::new(Arc::new(tracker.clone()));
let func_id = FunctionId::new(PathBuf::from("test.rs"), "MyType::method".to_string(), 10);
resolver.register_inherent_method("MyType".to_string(), "method".to_string(), func_id);
let traits_in_scope = HashSet::new();
let resolved = resolver.resolve_method_call("MyType", "method", &traits_in_scope);
assert!(resolved.is_some());
assert_eq!(
resolved.unwrap().priority,
ResolutionPriority::InherentMethod
);
}
#[test]
fn test_supertrait_tracking() {
let code = r#"
trait Display {
fn fmt(&self) -> String;
}
trait Debug: Display {
fn debug(&self) -> String;
}
"#;
let ast = syn::parse_file(code).unwrap();
let mut extractor = TraitExtractor::new(PathBuf::from("test.rs"));
let tracker = extractor.extract(&ast);
let debug = tracker.get_trait("Debug").unwrap();
assert_eq!(debug.supertraits.len(), 1);
assert_eq!(debug.supertraits[0], "Display");
}
#[test]
fn test_multiple_trait_bounds() {
let code = r#"
trait Clone {
fn clone(&self) -> Self;
}
trait Send {}
trait Sync {}
fn process<T: Clone + Send + Sync>(item: T) {
let _cloned = item.clone();
}
"#;
let ast = syn::parse_file(code).unwrap();
let mut extractor = TraitExtractor::new(PathBuf::from("test.rs"));
let tracker = extractor.extract(&ast);
assert!(tracker.get_trait("Clone").is_some());
assert!(tracker.get_trait("Send").is_some());
assert!(tracker.get_trait("Sync").is_some());
}
#[test]
fn test_negative_trait_impl() {
let code = r#"
struct NoSend;
// Negative implementation (simplified for testing)
impl !Send for NoSend {}
"#;
let result = syn::parse_file(code);
assert!(result.is_ok() || result.is_err()); }
#[test]
fn test_trait_method_confidence_scoring() {
let tracker = Arc::new(TraitImplementationTracker::new());
let mut resolver = TraitResolver::new(tracker);
let func_id = FunctionId::new(PathBuf::from("test.rs"), "Type::method".to_string(), 5);
resolver.register_inherent_method("Type".to_string(), "method".to_string(), func_id);
let traits_in_scope = HashSet::new();
let resolved = resolver.resolve_method_call("Type", "method", &traits_in_scope);
assert!(resolved.is_some());
let method = resolved.unwrap();
assert_eq!(method.confidence, 1.0); }
#[test]
fn test_resolve_all_methods_with_name() {
let tracker = Arc::new(TraitImplementationTracker::new());
let resolver = TraitResolver::new(tracker);
let methods = resolver.find_all_methods("clone");
assert_eq!(methods.len(), 0);
}
#[test]
fn test_cache_functionality() {
let tracker = Arc::new(TraitImplementationTracker::new());
let mut resolver = TraitResolver::new(tracker);
let traits_in_scope = HashSet::new();
let _ = resolver.resolve_method_call("Type", "method", &traits_in_scope);
let (_hits1, total1) = resolver.cache_stats();
let _ = resolver.resolve_method_call("Type", "method", &traits_in_scope);
let (_hits2, total2) = resolver.cache_stats();
assert_eq!(total1, 1);
assert_eq!(total2, 1);
resolver.clear_cache();
let (_hits3, total3) = resolver.cache_stats();
assert_eq!(total3, 0);
}