#![cfg(any())]
use bevy::prelude::*;
use bevy_ratatui::event::KeyEvent as RatatuiKeyEvent;
use clap::Parser;
use crossterm::event::{KeyCode, KeyEventKind, KeyModifiers};
use ai_code_buddy::{
args::Args,
bevy_states::app::AppState,
core::review::{CommitStatus, Issue, Review},
events::{
analysis::AnalysisEvent, app::AppEvent, overview::OverviewEvent, reports::ReportsEvent,
},
widget_states::{
analysis::AnalysisWidgetState,
overview::{OverviewComponent, OverviewWidgetState, SelectionDirection},
reports::{ExportStatus, ReportFormat, ReportsWidgetState, ViewMode},
},
widgets::{analysis::AnalysisPlugin, overview::OverviewPlugin, reports::ReportsPlugin},
};
fn create_test_app() -> App {
let mut app = App::new();
app.add_plugins((
MinimalPlugins,
AnalysisPlugin,
OverviewPlugin,
ReportsPlugin,
));
app.insert_resource(Args::parse_from(["test", "/test/repo"]));
app
}
fn create_mock_review() -> Review {
Review {
issues: vec![
Issue {
category: "Security".to_string(),
description: "Test security issue".to_string(),
file: "src/test.rs".to_string(),
line: 42,
severity: "high".to_string(),
commit_status: CommitStatus::Modified,
},
Issue {
category: "Performance".to_string(),
description: "Test performance issue".to_string(),
file: "src/main.rs".to_string(),
line: 100,
severity: "medium".to_string(),
commit_status: CommitStatus::Staged,
},
],
files_count: 10,
issues_count: 2,
critical_issues: 1,
high_issues: 1,
medium_issues: 1,
low_issues: 0,
}
}
fn create_key_event(code: KeyCode, kind: KeyEventKind) -> RatatuiKeyEvent {
RatatuiKeyEvent {
code,
modifiers: KeyModifiers::NONE,
kind,
state: crossterm::event::KeyEventState::NONE,
}
}
#[cfg(test)]
mod analysis_widget_tests {
use super::*;
#[test]
fn test_analysis_plugin_build() {
let mut app = create_test_app();
app.update();
assert!(app.world().contains_resource::<AnalysisWidgetState>());
assert!(app.world().contains_resource::<Events<AnalysisEvent>>());
}
#[test]
fn test_analysis_widget_state_initialization() {
let state = AnalysisWidgetState::default();
assert!(!state.is_analyzing);
assert!(state.review.is_none());
assert_eq!(state.selected_issue, 0);
assert_eq!(state.current_file, "");
assert_eq!(state.progress, 0.0);
}
#[test]
fn test_analysis_start_analysis() {
let mut state = AnalysisWidgetState::default();
state.start_analysis();
assert!(state.is_analyzing);
assert_eq!(state.progress, 0.0);
assert_eq!(state.current_file, "");
}
#[test]
fn test_analysis_issue_selection_movement() {
let mut state = AnalysisWidgetState::default();
state.review = Some(create_mock_review());
state.move_issue_selection(1);
assert_eq!(state.selected_issue, 1);
state.move_issue_selection(-1);
assert_eq!(state.selected_issue, 0);
state.move_issue_selection(-1);
assert_eq!(state.selected_issue, 0);
state.move_issue_selection(10);
assert_eq!(state.selected_issue, 1); }
#[test]
fn test_analysis_progress_update() {
let mut state = AnalysisWidgetState::default();
state.update_progress(0.5, "Analyzing files...".to_string());
assert_eq!(state.progress, 0.5);
assert_eq!(state.current_file, "Analyzing files...");
}
#[test]
fn test_analysis_complete() {
let mut state = AnalysisWidgetState::default();
let review = create_mock_review();
state.start_analysis();
assert!(state.is_analyzing);
state.complete_analysis(review.clone());
assert!(!state.is_analyzing);
assert!(state.review.is_some());
assert_eq!(state.review.unwrap().issues_count, 2);
}
#[test]
fn test_analysis_key_events() {
let mut app = create_test_app();
app.update();
let key_event = create_key_event(KeyCode::Esc, KeyEventKind::Press);
app.world_mut()
.send_event(AnalysisEvent::KeyEvent(key_event));
app.update();
let app_events = app.world().resource::<Events<AppEvent>>();
let mut cursor = app_events.get_cursor();
assert!(cursor
.read(app_events)
.any(|event| matches!(event, AppEvent::SwitchTo(AppState::Overview))));
}
#[test]
fn test_analysis_enter_key_starts_analysis() {
let mut app = create_test_app();
app.update();
let key_event = create_key_event(KeyCode::Enter, KeyEventKind::Release);
app.world_mut()
.send_event(AnalysisEvent::KeyEvent(key_event));
app.update();
let analysis_state = app.world().resource::<AnalysisWidgetState>();
assert!(analysis_state.is_analyzing);
}
#[test]
fn test_analysis_navigation_keys() {
let mut app = create_test_app();
app.update();
let mut analysis_state = app.world_mut().resource_mut::<AnalysisWidgetState>();
analysis_state.review = Some(create_mock_review());
drop(analysis_state);
let key_event = create_key_event(KeyCode::Up, KeyEventKind::Release);
app.world_mut()
.send_event(AnalysisEvent::KeyEvent(key_event));
app.update();
let key_event = create_key_event(KeyCode::Down, KeyEventKind::Release);
app.world_mut()
.send_event(AnalysisEvent::KeyEvent(key_event));
app.update();
}
#[test]
fn test_analysis_r_key_switches_to_reports() {
let mut app = create_test_app();
app.update();
let key_event = create_key_event(KeyCode::Char('r'), KeyEventKind::Release);
app.world_mut()
.send_event(AnalysisEvent::KeyEvent(key_event));
app.update();
let app_events = app.world().resource::<Events<AppEvent>>();
let mut cursor = app_events.get_cursor();
assert!(cursor
.read(app_events)
.any(|event| matches!(event, AppEvent::SwitchTo(AppState::Reports))));
}
}
#[cfg(test)]
mod overview_widget_tests {
use super::*;
#[test]
fn test_overview_plugin_build() {
let mut app = create_test_app();
app.update();
assert!(app.world().contains_resource::<OverviewWidgetState>());
assert!(app.world().contains_resource::<Events<OverviewEvent>>());
}
#[test]
fn test_overview_widget_state_initialization() {
let state = OverviewWidgetState::default();
assert_eq!(state.selected_component, OverviewComponent::StartAnalysis);
assert!(!state.show_help);
}
#[test]
fn test_overview_component_navigation() {
let mut state = OverviewWidgetState::default();
state.move_selection(SelectionDirection::Next);
assert_eq!(state.selected_component, OverviewComponent::ViewReports);
state.move_selection(SelectionDirection::Next);
assert_eq!(state.selected_component, OverviewComponent::Help);
state.move_selection(SelectionDirection::Next);
assert_eq!(state.selected_component, OverviewComponent::Exit);
state.move_selection(SelectionDirection::Next);
assert_eq!(state.selected_component, OverviewComponent::StartAnalysis);
state.move_selection(SelectionDirection::Previous);
assert_eq!(state.selected_component, OverviewComponent::Exit);
}
#[test]
fn test_overview_help_toggle() {
let mut state = OverviewWidgetState::default();
assert!(!state.show_help);
state.toggle_help();
assert!(state.show_help);
state.toggle_help();
assert!(!state.show_help);
}
#[test]
fn test_overview_repo_info_update() {
let mut state = OverviewWidgetState::default();
state.update_repo_info(
"/new/path".to_string(),
"feature".to_string(),
"main".to_string(),
);
assert_eq!(state.repo_info.path, "/new/path");
assert_eq!(state.repo_info.source_branch, "feature");
assert_eq!(state.repo_info.target_branch, "main");
}
#[test]
fn test_overview_is_over_component() {
let state = OverviewWidgetState::default();
let start_analysis_rect = ratatui::layout::Rect::new(10, 10, 20, 3);
assert!(state.is_over_component(
15,
11,
start_analysis_rect,
OverviewComponent::StartAnalysis
));
assert!(!state.is_over_component(
5,
5,
start_analysis_rect,
OverviewComponent::StartAnalysis
));
}
#[test]
fn test_overview_key_events() {
let mut app = create_test_app();
app.update();
let key_event = create_key_event(KeyCode::Tab, KeyEventKind::Release);
app.world_mut()
.send_event(OverviewEvent::KeyEvent(key_event));
app.update();
let overview_state = app.world().resource::<OverviewWidgetState>();
assert_eq!(
overview_state.selected_component,
OverviewComponent::ViewReports
);
}
#[test]
fn test_overview_enter_key_activation() {
let mut app = create_test_app();
app.update();
let key_event = create_key_event(KeyCode::Enter, KeyEventKind::Release);
app.world_mut()
.send_event(OverviewEvent::KeyEvent(key_event));
app.update();
let app_events = app.world().resource::<Events<AppEvent>>();
let mut cursor = app_events.get_cursor();
assert!(cursor
.read(app_events)
.any(|event| matches!(event, AppEvent::SwitchTo(AppState::Analysis))));
}
#[test]
fn test_overview_help_key() {
let mut app = create_test_app();
app.update();
let key_event = create_key_event(KeyCode::Char('?'), KeyEventKind::Release);
app.world_mut()
.send_event(OverviewEvent::KeyEvent(key_event));
app.update();
let overview_state = app.world().resource::<OverviewWidgetState>();
assert!(overview_state.show_help);
}
}
#[cfg(test)]
mod reports_widget_tests {
use super::*;
#[test]
fn test_reports_plugin_build() {
let mut app = create_test_app();
app.update();
assert!(app.world().contains_resource::<ReportsWidgetState>());
assert!(app.world().contains_resource::<Events<ReportsEvent>>());
}
#[test]
fn test_reports_widget_state_initialization() {
let state = ReportsWidgetState::default();
assert_eq!(state.current_format, ReportFormat::Html);
assert_eq!(state.view_mode, ViewMode::Summary);
assert_eq!(state.export_status, ExportStatus::None);
assert!(state.review.is_none());
}
#[test]
fn test_reports_set_review() {
let mut state = ReportsWidgetState::default();
let review = create_mock_review();
state.set_review(review.clone());
assert!(state.review.is_some());
assert_eq!(state.review.as_ref().unwrap().issues_count, 2);
}
#[test]
fn test_reports_format_cycling() {
let mut state = ReportsWidgetState::default();
assert_eq!(state.current_format, ReportFormat::Html);
state.next_format();
assert_eq!(state.current_format, ReportFormat::Json);
state.next_format();
assert_eq!(state.current_format, ReportFormat::Markdown);
state.next_format();
assert_eq!(state.current_format, ReportFormat::Csv);
state.next_format();
assert_eq!(state.current_format, ReportFormat::Html);
state.previous_format();
assert_eq!(state.current_format, ReportFormat::Csv);
}
#[test]
fn test_reports_view_mode_toggling() {
let mut state = ReportsWidgetState::default();
assert_eq!(state.view_mode, ViewMode::Summary);
state.toggle_view_mode();
assert_eq!(state.view_mode, ViewMode::Details);
state.toggle_view_mode();
assert_eq!(state.view_mode, ViewMode::Summary);
}
#[test]
fn test_reports_export_lifecycle() {
let mut state = ReportsWidgetState::default();
state.review = Some(create_mock_review());
assert_eq!(state.export_status, ExportStatus::None);
state.start_export();
assert_eq!(state.export_status, ExportStatus::InProgress);
state.complete_export();
assert_eq!(state.export_status, ExportStatus::Success);
state.export_error("Test error".to_string());
assert_eq!(
state.export_status,
ExportStatus::Error("Test error".to_string())
);
}
#[test]
fn test_reports_generate_report_with_review() {
let mut state = ReportsWidgetState::default();
state.review = Some(create_mock_review());
let report = state.generate_report();
assert!(report.contains("Security"));
assert!(report.contains("Performance"));
assert!(report.contains("Test security issue"));
assert!(report.contains("Test performance issue"));
}
#[test]
fn test_reports_generate_report_without_review() {
let state = ReportsWidgetState::default();
let report = state.generate_report();
assert!(report.contains("No analysis data available"));
}
#[test]
fn test_reports_key_events() {
let mut app = create_test_app();
app.update();
let key_event = create_key_event(KeyCode::Char('f'), KeyEventKind::Release);
app.world_mut()
.send_event(ReportsEvent::KeyEvent(key_event));
app.update();
let reports_state = app.world().resource::<ReportsWidgetState>();
assert_eq!(reports_state.current_format, ReportFormat::Json);
}
#[test]
fn test_reports_view_mode_toggle_key() {
let mut app = create_test_app();
app.update();
let key_event = create_key_event(KeyCode::Char('v'), KeyEventKind::Release);
app.world_mut()
.send_event(ReportsEvent::KeyEvent(key_event));
app.update();
let reports_state = app.world().resource::<ReportsWidgetState>();
assert_eq!(reports_state.view_mode, ViewMode::Details);
}
#[test]
fn test_reports_export_key() {
let mut app = create_test_app();
app.update();
let mut reports_state = app.world_mut().resource_mut::<ReportsWidgetState>();
reports_state.review = Some(create_mock_review());
drop(reports_state);
let key_event = create_key_event(KeyCode::Char('e'), KeyEventKind::Release);
app.world_mut()
.send_event(ReportsEvent::KeyEvent(key_event));
app.update();
let reports_state = app.world().resource::<ReportsWidgetState>();
assert_eq!(reports_state.export_status, ExportStatus::InProgress);
}
#[test]
fn test_reports_escape_key() {
let mut app = create_test_app();
app.update();
let key_event = create_key_event(KeyCode::Esc, KeyEventKind::Press);
app.world_mut()
.send_event(ReportsEvent::KeyEvent(key_event));
app.update();
let app_events = app.world().resource::<Events<AppEvent>>();
let mut cursor = app_events.get_cursor();
assert!(cursor
.read(app_events)
.any(|event| matches!(event, AppEvent::SwitchTo(AppState::Analysis))));
}
}
#[test]
fn legacy_widgets_comprehensive_placeholder() {
assert!(true);
}