use ratatui::{backend::TestBackend, Terminal};
use rgx::app::App;
use rgx::engine::{EngineFlags, EngineKind};
use rgx::ui;
fn create_test_terminal() -> Terminal<TestBackend> {
let backend = TestBackend::new(80, 24);
Terminal::new(backend).unwrap()
}
#[test]
fn render_empty_state() {
let mut terminal = create_test_terminal();
let app = App::new(EngineKind::RustRegex, EngineFlags::default());
terminal.draw(|frame| ui::render(frame, &app)).unwrap();
}
#[test]
fn render_with_pattern() {
let mut terminal = create_test_terminal();
let mut app = App::new(EngineKind::RustRegex, EngineFlags::default());
app.set_test_string("hello 123 world 456");
app.set_pattern(r"\d+");
terminal.draw(|frame| ui::render(frame, &app)).unwrap();
assert_eq!(app.matches.len(), 2);
}
#[test]
fn render_with_error() {
let mut terminal = create_test_terminal();
let mut app = App::new(EngineKind::RustRegex, EngineFlags::default());
app.set_pattern(r"(unclosed");
terminal.draw(|frame| ui::render(frame, &app)).unwrap();
assert!(app.error.is_some());
}
#[test]
fn render_with_captures() {
let mut terminal = create_test_terminal();
let mut app = App::new(EngineKind::RustRegex, EngineFlags::default());
app.set_test_string("user@example.com");
app.set_pattern(r"(\w+)@(\w+)\.(\w+)");
terminal.draw(|frame| ui::render(frame, &app)).unwrap();
assert_eq!(app.matches.len(), 1);
assert_eq!(app.matches[0].captures.len(), 3);
}
#[test]
fn render_help_overlay() {
let mut terminal = create_test_terminal();
let mut app = App::new(EngineKind::RustRegex, EngineFlags::default());
app.overlay.help = true;
terminal.draw(|frame| ui::render(frame, &app)).unwrap();
}
#[test]
fn engine_switching() {
let mut app = App::new(EngineKind::RustRegex, EngineFlags::default());
app.set_test_string("hello 123");
app.set_pattern(r"\d+");
assert_eq!(app.matches.len(), 1);
app.switch_engine();
assert_eq!(app.engine_kind, EngineKind::FancyRegex);
assert_eq!(app.matches.len(), 1);
}
#[test]
fn flag_toggles() {
let mut app = App::new(EngineKind::RustRegex, EngineFlags::default());
app.set_test_string("Hello HELLO hello");
app.set_pattern("hello");
assert_eq!(app.matches.len(), 1);
app.flags.toggle_case_insensitive();
app.recompute();
assert_eq!(app.matches.len(), 3); }
#[test]
fn match_display_shows_results() {
let mut terminal = create_test_terminal();
let mut app = App::new(EngineKind::RustRegex, EngineFlags::default());
app.set_test_string("user@example");
app.set_pattern(r"(\w+)@(\w+)");
assert_eq!(app.matches.len(), 1);
assert_eq!(app.matches[0].text, "user@example");
assert_eq!(app.matches[0].captures.len(), 2);
terminal.draw(|frame| ui::render(frame, &app)).unwrap();
let buffer = terminal.backend().buffer().clone();
let buffer_text: String = buffer
.content()
.iter()
.map(|cell| cell.symbol().chars().next().unwrap_or(' '))
.collect();
assert!(
buffer_text.contains("Match 1"),
"Buffer should contain 'Match 1' but got: {}",
buffer_text
);
}
#[test]
fn multiline_test_string_renders() {
let mut terminal = create_test_terminal();
let mut app = App::new(EngineKind::RustRegex, EngineFlags::default());
app.set_test_string("hello\nworld");
app.set_pattern(r"\w+");
assert_eq!(app.matches.len(), 2);
assert_eq!(app.matches[0].text, "hello");
assert_eq!(app.matches[1].text, "world");
terminal.draw(|frame| ui::render(frame, &app)).unwrap();
}
#[test]
fn narrow_terminal_layout() {
let backend = TestBackend::new(40, 24);
let mut terminal = Terminal::new(backend).unwrap();
let mut app = App::new(EngineKind::RustRegex, EngineFlags::default());
app.set_test_string("test");
app.set_pattern(r"\w+");
terminal.draw(|frame| ui::render(frame, &app)).unwrap();
}
#[test]
fn render_with_replacement() {
let mut terminal = create_test_terminal();
let mut app = App::new(EngineKind::RustRegex, EngineFlags::default());
app.set_test_string("hello 123 world 456");
app.set_pattern(r"\d+");
app.set_replacement("[NUM]");
assert!(app.replace_result.is_some());
let result = app.replace_result.as_ref().unwrap();
assert_eq!(result.output, "hello [NUM] world [NUM]");
terminal.draw(|frame| ui::render(frame, &app)).unwrap();
}
#[test]
fn render_empty_replacement() {
let mut app = App::new(EngineKind::RustRegex, EngineFlags::default());
app.set_test_string("hello 123");
app.set_pattern(r"\d+");
assert!(app.replace_result.is_none());
}
#[test]
fn panel_cycling_includes_replace() {
let mut app = App::new(EngineKind::RustRegex, EngineFlags::default());
assert_eq!(app.focused_panel, 0);
app.focused_panel = (app.focused_panel + 1) % 5;
assert_eq!(app.focused_panel, 1);
app.focused_panel = (app.focused_panel + 1) % 5;
assert_eq!(app.focused_panel, 2); app.focused_panel = (app.focused_panel + 1) % 5;
assert_eq!(app.focused_panel, 3); app.focused_panel = (app.focused_panel + 1) % 5;
assert_eq!(app.focused_panel, 4); app.focused_panel = (app.focused_panel + 1) % 5;
assert_eq!(app.focused_panel, 0); }
#[test]
fn replacement_with_named_groups() {
let mut app = App::new(EngineKind::RustRegex, EngineFlags::default());
app.set_test_string("2024-01");
app.set_pattern(r"(?P<y>\d{4})-(?P<m>\d{2})");
app.set_replacement("${m}/${y}");
assert!(app.replace_result.is_some());
let result = app.replace_result.as_ref().unwrap();
assert_eq!(result.output, "01/2024");
}
#[test]
fn replacement_clears_on_empty_template() {
let mut app = App::new(EngineKind::RustRegex, EngineFlags::default());
app.set_test_string("hello 123");
app.set_pattern(r"\d+");
app.set_replacement("[NUM]");
assert!(app.replace_result.is_some());
app.set_replacement("");
assert!(app.replace_result.is_none());
}
#[test]
fn undo_redo_regex_editor() {
let mut app = App::new(EngineKind::RustRegex, EngineFlags::default());
app.set_test_string("hello 123");
app.regex_editor.insert_char('\\');
app.regex_editor.insert_char('d');
app.regex_editor.insert_char('+');
app.recompute();
assert_eq!(app.matches.len(), 1);
app.regex_editor.undo();
app.recompute();
assert_eq!(app.regex_editor.content(), "\\d");
app.regex_editor.redo();
app.recompute();
assert_eq!(app.regex_editor.content(), "\\d+");
}
#[test]
fn pattern_history_navigation() {
let mut app = App::new(EngineKind::RustRegex, EngineFlags::default());
app.set_test_string("abc 123 def 456");
app.set_pattern(r"\d+");
app.commit_pattern_to_history();
app.set_pattern(r"\w+");
app.commit_pattern_to_history();
assert_eq!(app.history.entries.len(), 2);
app.set_pattern("current");
app.history_prev();
assert_eq!(app.regex_editor.content(), r"\w+");
app.history_prev();
assert_eq!(app.regex_editor.content(), r"\d+");
app.history_next();
assert_eq!(app.regex_editor.content(), r"\w+");
app.history_next();
assert_eq!(app.regex_editor.content(), "current");
}
#[test]
fn pattern_history_dedup() {
let mut app = App::new(EngineKind::RustRegex, EngineFlags::default());
app.set_pattern(r"\d+");
app.commit_pattern_to_history();
app.commit_pattern_to_history(); assert_eq!(app.history.entries.len(), 1);
}
#[test]
fn match_selection_navigation() {
let mut app = App::new(EngineKind::RustRegex, EngineFlags::default());
app.set_test_string("aa bb cc");
app.set_pattern(r"\w+");
assert_eq!(app.matches.len(), 3);
assert_eq!(app.selection.match_index, 0);
assert_eq!(app.selection.capture_index, None);
app.select_match_next();
assert_eq!(app.selection.match_index, 1);
app.select_match_next();
assert_eq!(app.selection.match_index, 2);
app.select_match_next();
assert_eq!(app.selection.match_index, 2);
app.select_match_prev();
assert_eq!(app.selection.match_index, 1);
app.select_match_prev();
assert_eq!(app.selection.match_index, 0);
app.select_match_prev();
assert_eq!(app.selection.match_index, 0);
}
#[test]
fn match_selection_with_captures() {
let mut app = App::new(EngineKind::RustRegex, EngineFlags::default());
app.set_test_string("user@example");
app.set_pattern(r"(\w+)@(\w+)");
assert_eq!(app.matches.len(), 1);
assert_eq!(app.matches[0].captures.len(), 2);
assert_eq!(app.selection.match_index, 0);
assert_eq!(app.selection.capture_index, None);
app.select_match_next();
assert_eq!(app.selection.match_index, 0);
assert_eq!(app.selection.capture_index, Some(0));
app.select_match_next();
assert_eq!(app.selection.match_index, 0);
assert_eq!(app.selection.capture_index, Some(1));
app.select_match_prev();
assert_eq!(app.selection.capture_index, Some(0));
app.select_match_prev();
assert_eq!(app.selection.capture_index, None);
}
#[test]
fn selection_resets_on_rematch() {
let mut app = App::new(EngineKind::RustRegex, EngineFlags::default());
app.set_test_string("aa bb");
app.set_pattern(r"\w+");
app.select_match_next();
assert_eq!(app.selection.match_index, 1);
app.set_test_string("aa bb cc");
assert_eq!(app.selection.match_index, 0);
assert_eq!(app.selection.capture_index, None);
}
#[test]
fn help_pages_render() {
let mut terminal = create_test_terminal();
let mut app = App::new(EngineKind::RustRegex, EngineFlags::default());
app.overlay.help = true;
terminal.draw(|frame| ui::render(frame, &app)).unwrap();
app.overlay.help_page = 1;
terminal.draw(|frame| ui::render(frame, &app)).unwrap();
app.overlay.help_page = 2;
terminal.draw(|frame| ui::render(frame, &app)).unwrap();
}
#[test]
fn help_page_clamped() {
let mut terminal = create_test_terminal();
let mut app = App::new(EngineKind::RustRegex, EngineFlags::default());
app.overlay.help = true;
app.overlay.help_page = 99; terminal.draw(|frame| ui::render(frame, &app)).unwrap();
}
#[test]
fn multiline_flag_matching() {
let mut app = App::new(
EngineKind::RustRegex,
EngineFlags {
multi_line: true,
..Default::default()
},
);
app.set_test_string("line1\nno match\nline42");
app.set_pattern(r"^line\d+$");
assert_eq!(app.matches.len(), 2);
assert_eq!(app.matches[0].text, "line1");
assert_eq!(app.matches[1].text, "line42");
}
#[test]
fn dotall_flag_matching() {
let mut app = App::new(
EngineKind::RustRegex,
EngineFlags {
dot_matches_newline: true,
..Default::default()
},
);
app.set_test_string("a\nb");
app.set_pattern("a.b");
assert_eq!(app.matches.len(), 1);
assert_eq!(app.matches[0].text, "a\nb");
}
#[test]
fn whitespace_visualization_toggle() {
let mut app = App::new(EngineKind::RustRegex, EngineFlags::default());
assert!(!app.show_whitespace);
app.show_whitespace = true;
assert!(app.show_whitespace);
let mut terminal = create_test_terminal();
app.set_test_string("hello world\nfoo bar");
app.set_pattern(r"\w+");
terminal.draw(|frame| ui::render(frame, &app)).unwrap();
}
#[test]
fn compute_layout_does_not_panic() {
use ratatui::layout::Rect;
let _ = ui::compute_layout(Rect::new(0, 0, 120, 40));
let _ = ui::compute_layout(Rect::new(0, 0, 40, 20));
let _ = ui::compute_layout(Rect::new(0, 0, 10, 10));
}
#[test]
fn test_empty_state_render() {
let mut terminal = create_test_terminal();
let app = App::new(EngineKind::RustRegex, EngineFlags::default());
assert!(app.regex_editor.content().is_empty());
assert!(app.test_editor.content().is_empty());
assert!(app.matches.is_empty());
assert!(app.error.is_none());
terminal.draw(|frame| ui::render(frame, &app)).unwrap();
}
#[test]
fn test_replace_invalid_capture_ref() {
let mut app = App::new(EngineKind::RustRegex, EngineFlags::default());
app.set_test_string("hello world");
app.set_pattern(r"(\w+) (\w+)");
app.set_replacement("$99");
assert!(app.replace_result.is_some());
let result = app.replace_result.as_ref().unwrap();
assert!(!result.output.is_empty() || result.output.is_empty());
}