use debtmap::organization::domain_patterns::{FileContext, MethodInfo};
use debtmap::organization::{cluster_methods_by_domain, DomainPattern, DomainPatternDetector};
use std::collections::HashSet;
#[test]
fn test_observer_pattern_cluster_detection() {
let detector = DomainPatternDetector::new();
let methods = vec![
MethodInfo {
name: "register_observer_interfaces".to_string(),
body: "self.observer_registry.register(interface)".to_string(),
doc_comment: Some("Register observer interface".to_string()),
},
MethodInfo {
name: "detect_observer_dispatch".to_string(),
body: "self.observer_registry.dispatch_event()".to_string(),
doc_comment: None,
},
MethodInfo {
name: "populate_observer_registry".to_string(),
body: "self.observer_registry.populate()".to_string(),
doc_comment: None,
},
MethodInfo {
name: "notify_all_observers".to_string(),
body: "self.observer_registry.notify_all()".to_string(),
doc_comment: None,
},
];
let context = FileContext {
methods: methods.clone(),
structures: ["ObserverRegistry".to_string()].into_iter().collect(),
call_edges: vec![],
};
let clusters = cluster_methods_by_domain(&methods, &context, &detector);
assert!(
clusters.contains_key(&DomainPattern::ObserverPattern),
"Observer pattern cluster should be detected. Found clusters: {:?}",
clusters.keys().collect::<Vec<_>>()
);
let observer_cluster = &clusters[&DomainPattern::ObserverPattern];
assert!(
observer_cluster.len() >= 3,
"Observer cluster should have at least 3 methods, got {}",
observer_cluster.len()
);
}
#[test]
fn test_callback_pattern_detection() {
let detector = DomainPatternDetector::new();
let methods = vec![
MethodInfo {
name: "check_for_callback_patterns".to_string(),
body: "self.callback_tracker.check()".to_string(),
doc_comment: None,
},
MethodInfo {
name: "extract_callback_expr".to_string(),
body: "self.callback_tracker.extract()".to_string(),
doc_comment: None,
},
MethodInfo {
name: "check_for_event_bindings".to_string(),
body: "self.callback_tracker.check_bindings()".to_string(),
doc_comment: None,
},
];
let context = FileContext {
methods: methods.clone(),
structures: ["CallbackTracker".to_string()].into_iter().collect(),
call_edges: vec![],
};
let clusters = cluster_methods_by_domain(&methods, &context, &detector);
assert!(
clusters.contains_key(&DomainPattern::CallbackPattern),
"Callback pattern cluster should be detected"
);
let callback_cluster = &clusters[&DomainPattern::CallbackPattern];
assert_eq!(callback_cluster.len(), 3);
}
#[test]
fn test_domain_pattern_integration_with_responsibility_classification() {
let detector = DomainPatternDetector::new();
let method_infos = vec![
MethodInfo {
name: "register_observer".to_string(),
body: "self.observer_registry.register(obs)".to_string(),
doc_comment: None,
},
MethodInfo {
name: "notify_observers".to_string(),
body: "self.observer_registry.notify_all()".to_string(),
doc_comment: None,
},
MethodInfo {
name: "unregister_observer".to_string(),
body: "self.observer_registry.remove(obs)".to_string(),
doc_comment: None,
},
MethodInfo {
name: "format_output".to_string(),
body: "format!(\"{}\", data)".to_string(),
doc_comment: None,
},
MethodInfo {
name: "parse_input".to_string(),
body: "parse(input_str)".to_string(),
doc_comment: None,
},
];
let context = FileContext {
methods: method_infos.clone(),
structures: ["ObserverRegistry".to_string()].into_iter().collect(),
call_edges: vec![],
};
let clusters = cluster_methods_by_domain(&method_infos, &context, &detector);
assert!(
clusters.contains_key(&DomainPattern::ObserverPattern),
"Should have Observer Pattern cluster. Clusters: {:?}",
clusters.keys().collect::<Vec<_>>()
);
let observer_cluster = &clusters[&DomainPattern::ObserverPattern];
assert_eq!(
observer_cluster.len(),
3,
"Observer pattern cluster should have 3 methods"
);
let observer_names: Vec<&str> = observer_cluster.iter().map(|m| m.name.as_str()).collect();
assert!(observer_names.contains(&"register_observer"));
assert!(observer_names.contains(&"notify_observers"));
assert!(observer_names.contains(&"unregister_observer"));
}
#[test]
fn test_minimum_cluster_size_threshold() {
let detector = DomainPatternDetector::new();
let methods = vec![
MethodInfo {
name: "register_observer".to_string(),
body: "self.observer_registry.register(obs)".to_string(),
doc_comment: None,
},
MethodInfo {
name: "notify_observers".to_string(),
body: "self.observer_registry.notify_all()".to_string(),
doc_comment: None,
},
];
let context = FileContext {
methods: methods.clone(),
structures: ["ObserverRegistry".to_string()].into_iter().collect(),
call_edges: vec![],
};
let clusters = cluster_methods_by_domain(&methods, &context, &detector);
assert!(
clusters.is_empty(),
"Should not create cluster with only 2 methods (below threshold of 3)"
);
}
#[test]
fn test_mixed_patterns_separation() {
let detector = DomainPatternDetector::new();
let methods = vec![
MethodInfo {
name: "register_observer".to_string(),
body: "self.observer_registry.add(obs)".to_string(),
doc_comment: None,
},
MethodInfo {
name: "notify_observers".to_string(),
body: "self.observer_registry.notify()".to_string(),
doc_comment: None,
},
MethodInfo {
name: "unregister_observer".to_string(),
body: "self.observer_registry.remove(obs)".to_string(),
doc_comment: None,
},
MethodInfo {
name: "with_config".to_string(),
body: "self.builder.with_config(config)".to_string(),
doc_comment: None,
},
MethodInfo {
name: "with_options".to_string(),
body: "self.builder.with_options(opts)".to_string(),
doc_comment: None,
},
MethodInfo {
name: "build".to_string(),
body: "self.builder.build()".to_string(),
doc_comment: None,
},
];
let context = FileContext {
methods: methods.clone(),
structures: ["ObserverRegistry".to_string(), "Builder".to_string()]
.into_iter()
.collect(),
call_edges: vec![],
};
let clusters = cluster_methods_by_domain(&methods, &context, &detector);
assert!(
clusters.contains_key(&DomainPattern::ObserverPattern),
"Should detect observer pattern"
);
assert!(
clusters.contains_key(&DomainPattern::BuilderPattern),
"Should detect builder pattern"
);
assert_eq!(clusters[&DomainPattern::ObserverPattern].len(), 3);
assert_eq!(clusters[&DomainPattern::BuilderPattern].len(), 3);
}
#[test]
fn test_pattern_confidence_threshold() {
let detector = DomainPatternDetector::new();
let method = MethodInfo {
name: "observer_helper".to_string(),
body: "println!(\"helper\")".to_string(), doc_comment: None,
};
let context = FileContext {
methods: vec![method.clone()],
structures: HashSet::new(), call_edges: vec![],
};
let result = detector.detect_method_domain(&method, &context);
if let Some(matched) = result {
assert!(
matched.confidence < 0.60,
"Weak signals should not meet confidence threshold"
);
}
}
#[test]
fn test_all_patterns_have_valid_definitions() {
let patterns = DomainPattern::all_patterns();
assert_eq!(patterns.len(), 6, "Should have 6 domain patterns defined");
for pattern in patterns {
assert!(
!pattern.keywords().is_empty(),
"Pattern {:?} should have keywords",
pattern
);
let module_name = pattern.module_name();
assert!(
!module_name.is_empty(),
"Pattern {:?} should have module name",
pattern
);
let description = pattern.description();
assert!(
!description.is_empty(),
"Pattern {:?} should have description",
pattern
);
}
}