use super::*;
use crate::episode::{Episode, ExecutionStep};
use crate::pattern::Pattern;
use crate::types::{ComplexityLevel, ExecutionResult, TaskContext, TaskOutcome, TaskType};
use uuid::Uuid;
fn create_test_episode(success: bool) -> Episode {
let context = TaskContext {
language: Some("rust".to_string()),
framework: Some("tokio".to_string()),
complexity: ComplexityLevel::Moderate,
domain: "testing".to_string(),
tags: vec!["async".to_string()],
};
let mut episode = Episode::new("Test task".to_string(), context, TaskType::Testing);
let mut step = ExecutionStep::new(1, "tool1".to_string(), "action".to_string());
step.result = Some(if success {
ExecutionResult::Success {
output: "OK".to_string(),
}
} else {
ExecutionResult::Error {
message: "FAIL".to_string(),
}
});
episode.add_step(step);
episode.complete(if success {
TaskOutcome::Success {
verdict: "Done".to_string(),
artifacts: vec![],
}
} else {
TaskOutcome::Failure {
reason: "Failed".to_string(),
error_details: None,
}
});
episode
}
fn create_test_pattern(domain: &str, success_rate: f32) -> Pattern {
Pattern::ToolSequence {
id: Uuid::new_v4(),
tools: vec!["tool1".to_string()],
context: TaskContext {
domain: domain.to_string(),
language: Some("rust".to_string()),
framework: None,
complexity: ComplexityLevel::Moderate,
tags: vec!["async".to_string()],
},
success_rate,
avg_latency: chrono::Duration::milliseconds(100),
occurrence_count: 5,
effectiveness: crate::pattern::PatternEffectiveness::new(),
}
}
#[test]
fn test_relative_affinity_ambiguous() {
let affinity = RelativeAffinity {
score_old: 0.7,
score_new: 0.75,
drel: 0.05 / 0.75,
};
assert!(affinity.is_ambiguous(0.25));
assert!(affinity.clarity() > 0.9);
}
#[test]
fn test_relative_affinity_clear() {
let affinity = RelativeAffinity {
score_old: 0.3,
score_new: 0.9,
drel: 0.6 / 0.9,
};
assert!(!affinity.is_ambiguous(0.25));
assert!(affinity.clarity() < 0.5);
}
#[test]
fn test_episode_assignment_guard_allows() {
let guard = EpisodeAssignmentGuard::new(0.85, 0.8);
assert!(guard.allows_mutation());
assert!(guard.allows_retrieval());
assert!(guard.rejection_reason().is_none());
}
#[test]
fn test_episode_assignment_guard_rejects_low_success() {
let guard = EpisodeAssignmentGuard::new(0.5, 0.8);
assert!(!guard.allows_mutation());
assert!(guard.allows_retrieval());
let reason = guard.rejection_reason().unwrap();
assert!(matches!(reason, RejectionReason::LowSuccessRate { .. }));
}
#[test]
fn test_episode_assignment_guard_rejects_ambiguous() {
let guard = EpisodeAssignmentGuard::new(0.85, 0.1);
assert!(!guard.allows_mutation());
assert!(guard.allows_retrieval());
let reason = guard.rejection_reason().unwrap();
assert!(matches!(reason, RejectionReason::AmbiguousAffinity { .. }));
}
#[test]
fn test_classifier_compute_affinity() {
let classifier = PatternAffinityClassifier::new();
let episode = create_test_episode(true);
let old_patterns: Vec<Pattern> = vec![create_test_pattern("testing", 0.9)];
let new_patterns: Vec<Pattern> = vec![create_test_pattern("web-api", 0.7)];
let affinity = classifier.compute_affinity(&episode, &old_patterns, &new_patterns, None);
assert!(affinity.score_old > affinity.score_new);
}
#[test]
fn test_classifier_should_gate_ambiguous() {
let classifier = PatternAffinityClassifier::new();
let episode = create_test_episode(true);
let patterns: Vec<Pattern> = vec![
create_test_pattern("testing", 0.9),
create_test_pattern("testing", 0.8),
];
let old_patterns = &patterns[..1];
let new_patterns = &patterns[1..];
let should_gate = classifier.should_gate_episode(&episode, old_patterns, new_patterns, None);
let _ = should_gate;
}
#[test]
fn test_context_similarity_same_domain() {
let episode = create_test_episode(true);
let pattern = create_test_pattern("testing", 0.9);
let similarity = context_similarity(&episode, &pattern);
assert!(similarity > 0.5);
}
#[test]
fn test_context_similarity_different_domain() {
let episode = create_test_episode(true);
let pattern = create_test_pattern("web-api", 0.7);
let similarity = context_similarity(&episode, &pattern);
assert!((0.0..=1.0).contains(&similarity));
}