use bevy_debugger_mcp::{
brp_client::BrpClient,
brp_messages::{DebugCommand, DebugOverlayType},
config::Config,
debug_command_processor::{DebugCommandProcessor, DebugCommandRouter, DebugCommandRequest},
visual_debug_overlay::*,
visual_debug_overlay_processor::{VisualDebugOverlayProcessor, OverlayMetrics},
};
use serde_json::json;
use std::sync::Arc;
use std::time::Duration;
use tokio::sync::RwLock;
use uuid::Uuid;
fn create_test_config() -> Config {
Config {
bevy_brp_host: "localhost".to_string(),
bevy_brp_port: 15702,
mcp_port: 3000,
}
}
fn create_test_brp_client() -> Arc<RwLock<BrpClient>> {
let config = create_test_config();
Arc::new(RwLock::new(BrpClient::new(&config)))
}
#[tokio::test]
async fn test_visual_debug_overlay_creation() {
let brp_client = create_test_brp_client();
let overlay = VisualDebugOverlay::new(brp_client);
assert!(overlay.get_config().enabled);
assert_eq!(overlay.get_config().max_highlighted_entities, MAX_HIGHLIGHTED_ENTITIES);
assert_eq!(overlay.get_config().performance_budget_ms, MAX_FRAME_IMPACT_MS);
}
#[tokio::test]
async fn test_custom_overlay_config() {
let brp_client = create_test_brp_client();
let custom_config = OverlayConfig {
enabled: true,
max_highlighted_entities: 50,
performance_budget_ms: 1.5,
show_metrics: true,
text_scale: 1.2,
};
let overlay = VisualDebugOverlay::with_config(brp_client, custom_config);
assert_eq!(overlay.get_config().max_highlighted_entities, 50);
assert_eq!(overlay.get_config().performance_budget_ms, 1.5);
assert!(overlay.get_config().show_metrics);
assert_eq!(overlay.get_config().text_scale, 1.2);
}
#[tokio::test]
async fn test_entity_highlighting() {
let brp_client = create_test_brp_client();
let overlay = VisualDebugOverlay::new(brp_client);
let entity_ids = vec![1, 2, 3];
let result = overlay.highlight_entities(
entity_ids.clone(),
Some([1.0, 0.0, 0.0, 0.8]), Some(HighlightMode::Outline),
).await;
assert!(result.is_err());
let too_many_entities: Vec<u64> = (0..200).collect();
let result = overlay.highlight_entities(too_many_entities, None, None).await;
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("Too many entities"));
}
#[tokio::test]
async fn test_collider_visualization() {
let brp_client = create_test_brp_client();
let overlay = VisualDebugOverlay::new(brp_client);
let config = ColliderVisualizationConfig {
show_colliders: true,
collider_color: [0.0, 1.0, 0.0, 0.5],
show_normals: true,
show_contacts: true,
alpha: 0.5,
};
let result = overlay.show_colliders(Some(config)).await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_transform_gizmos() {
let brp_client = create_test_brp_client();
let overlay = VisualDebugOverlay::new(brp_client);
let config = TransformGizmoConfig {
enabled: true,
show_local: true,
show_world: true,
scale: 2.0,
show_rotation: true,
};
let result = overlay.show_transform_gizmos(Some(config)).await;
assert!(result.is_err()); }
#[tokio::test]
async fn test_metrics_overlay() {
let brp_client = create_test_brp_client();
let overlay = VisualDebugOverlay::new(brp_client);
let config = MetricsOverlayConfig {
show_fps: true,
show_frame_time: true,
show_entity_count: true,
show_system_timings: true,
position: [0.02, 0.02],
text_size: 18.0,
background_opacity: 0.8,
};
let result = overlay.show_metrics(Some(config)).await;
assert!(result.is_err()); }
#[tokio::test]
async fn test_debug_markers() {
let brp_client = create_test_brp_client();
let overlay = VisualDebugOverlay::new(brp_client);
let marker = DebugMarker {
id: "test_marker_1".to_string(),
position: [10.0, 5.0, 0.0],
text: "Test Position".to_string(),
color: [1.0, 1.0, 0.0, 1.0],
size: 1.0,
screen_space: false,
};
let result = overlay.add_debug_marker(marker).await;
assert!(result.is_err());
let result = overlay.remove_debug_marker("test_marker_1").await;
assert!(result.is_err()); }
#[tokio::test]
async fn test_performance_budget() {
let brp_client = create_test_brp_client();
let overlay = VisualDebugOverlay::new(brp_client);
assert!(!overlay.is_budget_exceeded().await);
overlay.update_performance_metrics(&DebugOverlayType::EntityHighlight, 3.0).await;
assert!(overlay.is_budget_exceeded().await);
let metrics = overlay.get_performance_metrics().await;
assert!(metrics.contains_key(&DebugOverlayType::EntityHighlight));
assert!(*metrics.get(&DebugOverlayType::EntityHighlight).unwrap() >= 3.0);
}
#[test]
fn test_highlight_modes() {
use serde_json;
let modes = vec![
HighlightMode::Outline,
HighlightMode::Tint,
HighlightMode::Glow,
HighlightMode::Wireframe,
HighlightMode::Solid,
];
for mode in modes {
let json = serde_json::to_string(&mode).unwrap();
let deserialized: HighlightMode = serde_json::from_str(&json).unwrap();
assert_eq!(deserialized, mode);
}
}
#[tokio::test]
async fn test_visual_debug_processor() {
let brp_client = create_test_brp_client();
let processor = VisualDebugOverlayProcessor::new(brp_client);
let set_command = DebugCommand::SetVisualDebug {
overlay_type: DebugOverlayType::EntityHighlight,
enabled: true,
config: Some(json!({
"default_color": [1.0, 0.0, 0.0, 1.0],
"default_mode": "outline"
})),
};
assert!(processor.supports_command(&set_command));
assert!(processor.supports_command(&DebugCommand::GetStatus));
assert!(processor.validate(&set_command).await.is_ok());
let large_config = json!({
"data": "x".repeat(11_000) });
let invalid_command = DebugCommand::SetVisualDebug {
overlay_type: DebugOverlayType::EntityHighlight,
enabled: true,
config: Some(large_config),
};
assert!(processor.validate(&invalid_command).await.is_err());
}
#[tokio::test]
async fn test_overlay_state_management() {
let brp_client = create_test_brp_client();
let processor = VisualDebugOverlayProcessor::new(brp_client);
let state = processor.get_state();
{
let state_guard = state.read().await;
assert!(state_guard.get_all_overlay_statuses().is_empty());
assert!(!state_guard.is_performance_budget_exceeded());
}
{
let mut state_guard = state.write().await;
let result = state_guard
.set_overlay_enabled(
&DebugOverlayType::EntityHighlight,
true,
Some(json!({
"default_color": [1.0, 0.0, 0.0, 1.0],
"default_mode": "outline"
})),
)
.await;
assert!(result.is_err());
let overlay_status = state_guard.get_overlay_status(&DebugOverlayType::EntityHighlight);
assert!(overlay_status.is_some());
let status = overlay_status.unwrap();
assert!(status.enabled);
assert_eq!(status.config["default_color"], json!([1.0, 0.0, 0.0, 1.0]));
}
}
#[tokio::test]
async fn test_performance_metrics_tracking() {
let brp_client = create_test_brp_client();
let processor = VisualDebugOverlayProcessor::new(brp_client);
let state = processor.get_state();
{
let mut state_guard = state.write().await;
assert!(!state_guard.is_performance_budget_exceeded());
let high_cost_metrics = OverlayMetrics {
render_time_us: 3000, element_count: 1000,
memory_usage_bytes: 1024 * 1024,
update_count: 50,
};
state_guard.update_metrics(&DebugOverlayType::EntityHighlight, high_cost_metrics);
assert!(state_guard.is_performance_budget_exceeded());
let low_cost_metrics = OverlayMetrics {
render_time_us: 500, element_count: 10,
memory_usage_bytes: 1024,
update_count: 5,
};
state_guard.update_metrics(&DebugOverlayType::EntityHighlight, low_cost_metrics);
assert!(!state_guard.is_performance_budget_exceeded());
}
}
#[tokio::test]
async fn test_debug_command_router_integration() {
let brp_client = create_test_brp_client();
let router = DebugCommandRouter::new();
let processor = Arc::new(VisualDebugOverlayProcessor::new(brp_client));
router.register_processor("visual_debug_overlay".to_string(), processor).await;
let command = DebugCommand::SetVisualDebug {
overlay_type: DebugOverlayType::EntityHighlight,
enabled: true,
config: Some(json!({"color": [1.0, 0.0, 0.0, 1.0]})),
};
let request = DebugCommandRequest::new(
command,
Uuid::new_v4().to_string(),
Some(5),
);
let result = router.queue_command(request).await;
assert!(result.is_ok());
let process_result = router.process_next().await;
assert!(process_result.is_some());
}
#[tokio::test]
async fn test_processing_time_estimates() {
let brp_client = create_test_brp_client();
let processor = VisualDebugOverlayProcessor::new(brp_client);
let set_visual_cmd = DebugCommand::SetVisualDebug {
overlay_type: DebugOverlayType::EntityHighlight,
enabled: true,
config: None,
};
let get_status_cmd = DebugCommand::GetStatus;
let set_time = processor.estimate_processing_time(&set_visual_cmd);
let get_time = processor.estimate_processing_time(&get_status_cmd);
assert!(set_time > get_time);
assert!(set_time <= Duration::from_millis(100)); }
#[tokio::test]
async fn test_overlay_performance() {
let brp_client = create_test_brp_client();
let processor = VisualDebugOverlayProcessor::new(brp_client);
let cmd = DebugCommand::SetVisualDebug {
overlay_type: DebugOverlayType::EntityHighlight,
enabled: true,
config: Some(json!({"default_color": [1.0, 0.0, 0.0, 1.0]})),
};
let start = std::time::Instant::now();
let _result = processor.process(cmd).await;
let duration = start.elapsed();
assert!(duration.as_millis() < 1000, "SetVisualDebug took too long: {:?}", duration);
}
#[tokio::test]
async fn test_status_performance() {
let brp_client = create_test_brp_client();
let processor = VisualDebugOverlayProcessor::new(brp_client);
let cmd = DebugCommand::GetStatus;
let start = std::time::Instant::now();
let result = processor.process(cmd).await;
let duration = start.elapsed();
assert!(result.is_ok());
assert!(duration.as_millis() < 100, "GetStatus took too long: {:?}", duration);
}
#[tokio::test]
async fn test_multiple_overlay_types() {
let brp_client = create_test_brp_client();
let overlay = VisualDebugOverlay::new(brp_client);
let entity_highlight_result = overlay.highlight_entities(
vec![1, 2],
Some([1.0, 0.0, 0.0, 1.0]),
Some(HighlightMode::Glow)
).await;
let colliders_result = overlay.show_colliders(None).await;
let gizmos_result = overlay.show_transform_gizmos(None).await;
let metrics_result = overlay.show_metrics(None).await;
assert!(entity_highlight_result.is_err());
assert!(colliders_result.is_err());
assert!(gizmos_result.is_err());
assert!(metrics_result.is_err());
}
#[tokio::test]
async fn test_overlay_cleanup() {
let brp_client = create_test_brp_client();
let overlay = VisualDebugOverlay::new(brp_client);
let result = overlay.clear_all_overlays().await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_custom_overlay_types() {
let brp_client = create_test_brp_client();
let processor = VisualDebugOverlayProcessor::new(brp_client);
let state = processor.get_state();
{
let state_guard = state.read().await;
let custom_overlay = DebugOverlayType::Custom("test_overlay".to_string());
let key = state_guard.overlay_type_to_key(&custom_overlay);
assert_eq!(key, "custom_test_overlay");
}
}
#[tokio::test]
async fn test_many_overlays_stress() {
let brp_client = create_test_brp_client();
let processor = VisualDebugOverlayProcessor::new(brp_client);
let state = processor.get_state();
{
let mut state_guard = state.write().await;
for i in 0..10 {
let custom_overlay = DebugOverlayType::Custom(format!("stress_test_{}", i));
let result = state_guard
.set_overlay_enabled(
&custom_overlay,
true,
Some(json!({"test_value": i})),
)
.await;
assert!(result.is_err());
}
assert_eq!(state_guard.get_all_overlay_statuses().len(), 10);
}
}