use super::*;
#[test]
fn test_default_config() {
let config = VisualizeConfig::default();
assert_eq!(config.tick_rate_ms, 50);
assert_eq!(config.history_size, 300);
assert!(config.enable_anomaly);
assert!(!config.enable_ml);
}
#[test]
fn test_config_clone() {
let config = VisualizeConfig {
tick_rate_ms: 100,
enable_ml: true,
ml_clusters: 5,
..Default::default()
};
let cloned = config.clone();
assert_eq!(cloned.tick_rate_ms, 100);
assert!(cloned.enable_ml);
assert_eq!(cloned.ml_clusters, 5);
}
#[test]
fn test_config_all_fields() {
let config = VisualizeConfig {
tick_rate_ms: 100,
enable_anomaly: false,
enable_ml: true,
ml_clusters: 5,
anomaly_threshold: 2.5,
history_size: 500,
deterministic: true,
show_fps: true,
pid: Some(1234),
enable_source: true,
filter: Some("read|write".to_string()),
otlp_endpoint: Some("http://localhost:4317".to_string()),
enable_metrics: true,
enable_alerts: true,
alert_latency_threshold_us: 5000,
alert_error_rate_percent: 2.5,
};
assert_eq!(config.tick_rate_ms, 100);
assert!(!config.enable_anomaly);
assert!(config.enable_ml);
assert_eq!(config.ml_clusters, 5);
assert!((config.anomaly_threshold - 2.5).abs() < f32::EPSILON);
assert_eq!(config.history_size, 500);
assert!(config.deterministic);
assert!(config.show_fps);
assert_eq!(config.pid, Some(1234));
assert!(config.enable_source);
assert_eq!(config.filter, Some("read|write".to_string()));
assert_eq!(config.otlp_endpoint, Some("http://localhost:4317".to_string()));
assert!(config.enable_metrics);
assert!(config.enable_alerts);
assert_eq!(config.alert_latency_threshold_us, 5000);
assert!((config.alert_error_rate_percent - 2.5).abs() < f32::EPSILON);
}
#[test]
fn test_inject_demo_data() {
let config = VisualizeConfig::default();
let mut app = app::VisualizeApp::new(config);
assert_eq!(app.total_syscalls, 0);
for tick in 0..10 {
inject_demo_data(&mut app, tick);
}
assert!(app.total_syscalls > 0);
assert!(!app.latency_history.is_empty());
}
#[test]
fn test_inject_demo_data_deterministic() {
let config = VisualizeConfig::default();
let mut app1 = app::VisualizeApp::new(config.clone());
let mut app2 = app::VisualizeApp::new(config);
inject_demo_data(&mut app1, 42);
inject_demo_data(&mut app2, 42);
assert_eq!(app1.total_syscalls, app2.total_syscalls);
}
#[test]
fn test_inject_demo_data_distribution() {
let config = VisualizeConfig::default();
let mut app = app::VisualizeApp::new(config);
for tick in 0..100 {
inject_demo_data(&mut app, tick);
}
assert!(app.total_syscalls > 500);
assert!(app.total_errors > 0);
assert!(app.anomaly_count > 0);
}
#[test]
fn test_config_debug() {
let config = VisualizeConfig::default();
let debug_str = format!("{:?}", config);
assert!(debug_str.contains("tick_rate_ms"));
assert!(debug_str.contains("enable_anomaly"));
}
#[test]
fn test_sprint56_config_defaults() {
let config = VisualizeConfig::default();
assert!(!config.enable_metrics);
assert!(!config.enable_alerts);
assert_eq!(config.alert_latency_threshold_us, 10_000);
assert!((config.alert_error_rate_percent - 5.0).abs() < f32::EPSILON);
}
#[test]
fn test_config_with_sprint56_features() {
let config = VisualizeConfig {
enable_metrics: true,
enable_alerts: true,
alert_latency_threshold_us: 20_000,
alert_error_rate_percent: 10.0,
..Default::default()
};
assert!(config.enable_metrics);
assert!(config.enable_alerts);
assert_eq!(config.alert_latency_threshold_us, 20_000);
assert!((config.alert_error_rate_percent - 10.0).abs() < f32::EPSILON);
}
#[test]
fn test_inject_demo_data_syscall_categories() {
let config = VisualizeConfig::default();
let mut app = app::VisualizeApp::new(config);
for tick in 0..200 {
inject_demo_data(&mut app, tick);
}
assert!(app.total_syscalls > 1000);
}
#[test]
fn test_inject_demo_data_anomaly_detection() {
let config = VisualizeConfig::default();
let mut app = app::VisualizeApp::new(config);
for tick in 0..500 {
inject_demo_data(&mut app, tick);
}
assert!(app.anomaly_count > 0);
}
#[test]
fn test_inject_demo_data_error_rate() {
let config = VisualizeConfig::default();
let mut app = app::VisualizeApp::new(config);
for tick in 0..1000 {
inject_demo_data(&mut app, tick);
}
let error_rate = app.total_errors as f64 / app.total_syscalls as f64;
assert!(error_rate > 0.01 && error_rate < 0.05);
}
#[test]
fn test_config_with_pid() {
let config = VisualizeConfig { pid: Some(12345), ..Default::default() };
assert_eq!(config.pid, Some(12345));
}
#[test]
fn test_config_with_filter() {
let config = VisualizeConfig { filter: Some("mmap|munmap".to_string()), ..Default::default() };
assert_eq!(config.filter, Some("mmap|munmap".to_string()));
}
#[test]
fn test_config_with_otlp() {
let config = VisualizeConfig {
otlp_endpoint: Some("http://jaeger:4317".to_string()),
..Default::default()
};
assert_eq!(config.otlp_endpoint, Some("http://jaeger:4317".to_string()));
}
#[test]
fn test_visualize_config_deterministic_mode() {
let config = VisualizeConfig { deterministic: true, ..Default::default() };
assert!(config.deterministic);
}
#[test]
fn test_update_frame_stats() {
let config = VisualizeConfig::default();
let mut app = app::VisualizeApp::new(config);
let mut frame_times: Vec<u64> = Vec::with_capacity(60);
update_frame_stats(&mut app, &mut frame_times, 1000);
assert_eq!(app.frame_id, 1);
assert_eq!(app.avg_frame_time_us, 1000);
assert_eq!(app.max_frame_time_us, 1000);
assert_eq!(frame_times.len(), 1);
update_frame_stats(&mut app, &mut frame_times, 2000);
assert_eq!(app.frame_id, 2);
assert_eq!(app.avg_frame_time_us, 1500); assert_eq!(app.max_frame_time_us, 2000);
assert_eq!(frame_times.len(), 2);
for i in 0..65 {
update_frame_stats(&mut app, &mut frame_times, 100 + i as u64);
}
assert_eq!(frame_times.len(), 60); }
#[test]
fn test_handle_key_input_quit() {
let config = VisualizeConfig::default();
let mut app = app::VisualizeApp::new(config);
let key_q = event::KeyEvent::new(KeyCode::Char('q'), KeyModifiers::NONE);
assert!(handle_key_input(&mut app, key_q));
let key_ctrl_c = event::KeyEvent::new(KeyCode::Char('c'), KeyModifiers::CONTROL);
assert!(handle_key_input(&mut app, key_ctrl_c));
}
#[test]
fn test_handle_key_input_other_keys() {
let config = VisualizeConfig::default();
let mut app = app::VisualizeApp::new(config);
let key_a = event::KeyEvent::new(KeyCode::Char('a'), KeyModifiers::NONE);
assert!(!handle_key_input(&mut app, key_a));
let key_enter = event::KeyEvent::new(KeyCode::Enter, KeyModifiers::NONE);
assert!(!handle_key_input(&mut app, key_enter));
let key_tab = event::KeyEvent::new(KeyCode::Tab, KeyModifiers::NONE);
assert!(!handle_key_input(&mut app, key_tab));
}
#[test]
fn test_create_tracer_handle_demo_mode() {
let (tx, _rx) = mpsc::channel::<VisualizerEvent>();
let setup = create_tracer_handle(None, None, tx);
assert!(setup.demo_mode);
assert!(setup.handle.is_none());
}
#[test]
fn test_terminal_guard_drop() {
{
let _guard = TerminalGuard;
}
}
#[test]
#[allow(unsafe_code)]
fn test_suppress_stdio_safe() {
unsafe {
let saved_stdout = libc::dup(libc::STDOUT_FILENO);
let saved_stderr = libc::dup(libc::STDERR_FILENO);
assert!(saved_stdout >= 0, "failed to dup stdout");
assert!(saved_stderr >= 0, "failed to dup stderr");
suppress_stdio();
libc::dup2(saved_stdout, libc::STDOUT_FILENO);
libc::dup2(saved_stderr, libc::STDERR_FILENO);
libc::close(saved_stdout);
libc::close(saved_stderr);
}
}
#[test]
fn test_handle_tracer_finish_none() {
let config = VisualizeConfig::default();
let mut app = app::VisualizeApp::new(config);
let mut handle: Option<thread::JoinHandle<Result<i32>>> = None;
handle_tracer_finish(&mut app, &mut handle);
assert!(!app.trace_complete); }
#[test]
fn test_open_tty_fallback() {
let _file = open_tty();
}