use bevy_debugger_mcp::pattern_learning::{
AnonymizedCommand, DebugPattern, PatternLearningSystem, PatternMiner, TimeBucket,
};
use bevy_debugger_mcp::suggestion_engine::{
DebugSuggestion, SuggestionContext, SuggestionEngine, SystemState,
};
use bevy_debugger_mcp::brp_messages::DebugCommand;
use std::collections::HashMap;
use std::sync::Arc;
use std::time::Duration;
use tokio::time::sleep;
#[tokio::test]
async fn test_pattern_anonymization() {
let system = PatternLearningSystem::new();
let session_id = "test_session_1";
system.start_session(session_id.to_string()).await;
let commands = vec![
DebugCommand::InspectEntity { entity_id: 123 },
DebugCommand::GetHierarchy { entity_id: 456 },
DebugCommand::GetSystemInfo,
];
for cmd in commands {
system.record_command(session_id, cmd, Duration::from_millis(5)).await;
}
system.end_session(session_id, true).await.unwrap();
}
#[tokio::test]
async fn test_pattern_mining() {
let miner = PatternMiner::new(2, 5);
let cmd1 = AnonymizedCommand {
command_type: "inspect".to_string(),
param_shape: HashMap::new(),
time_bucket: TimeBucket::Fast,
};
let cmd2 = AnonymizedCommand {
command_type: "profile".to_string(),
param_shape: HashMap::new(),
time_bucket: TimeBucket::Medium,
};
let cmd3 = AnonymizedCommand {
command_type: "observe".to_string(),
param_shape: HashMap::new(),
time_bucket: TimeBucket::Fast,
};
let sequences = vec![
vec![cmd1.clone(), cmd2.clone(), cmd3.clone()],
vec![cmd1.clone(), cmd2.clone()],
vec![cmd1.clone(), cmd3.clone()],
];
let patterns = miner.mine_patterns(&sequences);
assert!(!patterns.is_empty());
assert!(patterns.iter().any(|p| p.len() == 1 && p[0] == cmd1)); }
#[tokio::test]
async fn test_k_anonymity() {
let system = PatternLearningSystem::new();
for i in 0..3 {
let session_id = format!("session_{}", i);
system.start_session(session_id.clone()).await;
system.record_command(
&session_id,
DebugCommand::GetSystemInfo,
Duration::from_millis(10),
).await;
system.end_session(&session_id, true).await.unwrap();
}
let patterns = system.find_matching_patterns(&[]).await;
assert!(patterns.is_empty());
for i in 3..6 {
let session_id = format!("session_{}", i);
system.start_session(session_id.clone()).await;
system.record_command(
&session_id,
DebugCommand::GetSystemInfo,
Duration::from_millis(10),
).await;
system.end_session(&session_id, true).await.unwrap();
}
}
#[tokio::test]
async fn test_pattern_matching() {
let system = PatternLearningSystem::new();
for i in 0..10 {
let session_id = format!("session_{}", i);
system.start_session(session_id.clone()).await;
system.record_command(
&session_id,
DebugCommand::GetSystemInfo,
Duration::from_millis(5),
).await;
system.record_command(
&session_id,
DebugCommand::InspectEntity { entity_id: i as u32 },
Duration::from_millis(15),
).await;
system.record_command(
&session_id,
DebugCommand::ProfileSystem {
system_name: "test".to_string(),
duration_seconds: Some(1),
},
Duration::from_millis(100),
).await;
system.end_session(&session_id, true).await.unwrap();
}
let test_sequence = vec![
AnonymizedCommand {
command_type: "get_system_info".to_string(),
param_shape: HashMap::new(),
time_bucket: TimeBucket::Fast,
},
];
let matches = system.find_matching_patterns(&test_sequence).await;
}
#[tokio::test]
async fn test_suggestion_generation() {
let pattern_system = Arc::new(PatternLearningSystem::new());
let suggestion_engine = SuggestionEngine::new(pattern_system.clone());
let context = SuggestionContext {
session_id: "test_session".to_string(),
recent_commands: vec![
DebugCommand::GetSystemInfo,
],
system_state: SystemState {
entity_count: 1000,
fps: 25.0, memory_mb: 600.0, active_systems: 50,
has_errors: false,
},
user_goal: Some("Fix performance issues".to_string()),
};
let suggestions = suggestion_engine.generate_suggestions(&context).await;
assert!(!suggestions.is_empty());
assert!(suggestions.iter().any(|s| s.command.contains("profile")));
}
#[tokio::test]
async fn test_suggestion_with_errors() {
let pattern_system = Arc::new(PatternLearningSystem::new());
let suggestion_engine = SuggestionEngine::new(pattern_system.clone());
let context = SuggestionContext {
session_id: "error_session".to_string(),
recent_commands: vec![],
system_state: SystemState {
entity_count: 100,
fps: 60.0,
memory_mb: 100.0,
active_systems: 10,
has_errors: true, },
user_goal: None,
};
let suggestions = suggestion_engine.generate_suggestions(&context).await;
assert!(!suggestions.is_empty());
let first_suggestion = &suggestions[0];
assert!(first_suggestion.priority >= 10);
assert!(first_suggestion.command.contains("detect_issues") ||
first_suggestion.reasoning.contains("error"));
}
#[tokio::test]
async fn test_suggestion_tracking() {
let pattern_system = Arc::new(PatternLearningSystem::new());
let suggestion_engine = SuggestionEngine::new(pattern_system.clone());
suggestion_engine.track_suggestion_acceptance("test_suggestion_1", true, true).await;
suggestion_engine.track_suggestion_acceptance("test_suggestion_1", true, false).await;
suggestion_engine.track_suggestion_acceptance("test_suggestion_2", false, false).await;
let metrics = suggestion_engine.get_suggestion_metrics().await;
assert!(metrics.contains_key("test_suggestion_1"));
let (acceptance_rate, success_rate) = metrics.get("test_suggestion_1").unwrap();
assert_eq!(*acceptance_rate, 1.0); assert_eq!(*success_rate, 0.5); }
#[tokio::test]
async fn test_pattern_export_import() {
let system = PatternLearningSystem::new();
for i in 0..10 {
let session_id = format!("export_session_{}", i);
system.start_session(session_id.clone()).await;
system.record_command(
&session_id,
DebugCommand::GetSystemInfo,
Duration::from_millis(10),
).await;
system.end_session(&session_id, true).await.unwrap();
}
let exported = system.export_patterns().await.unwrap();
assert!(!exported.is_empty());
let new_system = PatternLearningSystem::new();
new_system.import_patterns(&exported).await.unwrap();
}
#[tokio::test]
async fn test_privacy_preservation() {
let system = PatternLearningSystem::new();
let session_id = "privacy_test";
system.start_session(session_id.to_string()).await;
system.record_command(
session_id,
DebugCommand::InspectEntity { entity_id: 12345 },
Duration::from_millis(10),
).await;
system.record_command(
session_id,
DebugCommand::ProfileSystem {
system_name: "super_secret_system".to_string(),
duration_seconds: Some(5),
},
Duration::from_millis(50),
).await;
system.end_session(session_id, true).await.unwrap();
let exported = system.export_patterns().await.unwrap();
assert!(!exported.contains("12345"));
assert!(!exported.contains("super_secret_system"));
}
#[tokio::test]
async fn test_pattern_confidence_calculation() {
let system = PatternLearningSystem::new();
for i in 0..20 {
let session_id = format!("confidence_session_{}", i);
system.start_session(session_id.clone()).await;
system.record_command(
&session_id,
DebugCommand::GetSystemInfo,
Duration::from_millis(10),
).await;
let success = i % 2 == 0;
system.end_session(&session_id, success).await.unwrap();
}
}
#[tokio::test]
async fn test_sequence_length_limits() {
let system = PatternLearningSystem::new();
let session_id = "long_session";
system.start_session(session_id.to_string()).await;
for i in 0..20 {
system.record_command(
session_id,
DebugCommand::GetSystemInfo,
Duration::from_millis(5),
).await;
}
system.end_session(session_id, true).await.unwrap();
}
#[tokio::test]
async fn test_concurrent_sessions() {
let system = Arc::new(PatternLearningSystem::new());
let mut handles = vec![];
for i in 0..5 {
let system_clone = system.clone();
let handle = tokio::spawn(async move {
let session_id = format!("concurrent_{}", i);
system_clone.start_session(session_id.clone()).await;
for _ in 0..3 {
system_clone.record_command(
&session_id,
DebugCommand::GetSystemInfo,
Duration::from_millis(10),
).await;
sleep(Duration::from_millis(10)).await;
}
system_clone.end_session(&session_id, true).await.unwrap();
});
handles.push(handle);
}
for handle in handles {
handle.await.unwrap();
}
}