#![allow(unused_must_use)]
use slt::widgets::TextareaState;
use slt::{EventBuilder, KeyCode, KeyModifiers, TestBackend};
fn ctrl_z() -> Vec<slt::event::Event> {
EventBuilder::new()
.key_with(KeyCode::Char('z'), KeyModifiers::CONTROL)
.build()
}
fn ctrl_y() -> Vec<slt::event::Event> {
EventBuilder::new()
.key_with(KeyCode::Char('y'), KeyModifiers::CONTROL)
.build()
}
#[test]
fn textarea_undo_redo_roundtrip() {
let mut tb = TestBackend::new(40, 10);
let mut state = TextareaState::new();
let typing = EventBuilder::new().key('h').key('i').build();
tb.render_with_events(typing, 0, 1, |ui| {
ui.textarea(&mut state, 5);
});
assert_eq!(state.lines, vec!["hi"]);
tb.render_with_events(ctrl_z(), 0, 1, |ui| {
ui.textarea(&mut state, 5);
});
assert_eq!(
state.lines,
vec![""],
"after Ctrl+Z the typing burst should fully undo"
);
tb.render_with_events(ctrl_y(), 0, 1, |ui| {
ui.textarea(&mut state, 5);
});
assert_eq!(
state.lines,
vec!["hi"],
"Ctrl+Y should redo the undone burst"
);
}
#[test]
fn textarea_rapid_typing_coalesces_into_one_undo() {
let mut tb = TestBackend::new(40, 10);
let mut state = TextareaState::new();
let typing = EventBuilder::new()
.key('h')
.key('e')
.key('l')
.key('l')
.key('o')
.build();
tb.render_with_events(typing, 0, 1, |ui| {
ui.textarea(&mut state, 5);
});
assert_eq!(state.lines, vec!["hello"]);
tb.render_with_events(ctrl_z(), 0, 1, |ui| {
ui.textarea(&mut state, 5);
});
assert_eq!(
state.lines,
vec![""],
"one Ctrl+Z should clear the entire typing burst"
);
}
#[test]
fn textarea_undo_past_beginning_is_noop() {
let mut tb = TestBackend::new(40, 10);
let mut state = TextareaState::new();
let events = EventBuilder::new()
.key_with(KeyCode::Char('z'), KeyModifiers::CONTROL)
.key_with(KeyCode::Char('z'), KeyModifiers::CONTROL)
.key_with(KeyCode::Char('z'), KeyModifiers::CONTROL)
.build();
tb.render_with_events(events, 0, 1, |ui| {
ui.textarea(&mut state, 5);
});
assert_eq!(state.lines, vec![""]);
assert_eq!(state.cursor_row, 0);
assert_eq!(state.cursor_col, 0);
}
#[test]
fn textarea_history_capped_at_max() {
let mut tb = TestBackend::new(40, 10);
let mut state = TextareaState::new().history_max(4);
let mut builder = EventBuilder::new();
for ch in ['a', 'b', 'c', 'd', 'e'] {
builder = builder
.key(ch)
.key_code(KeyCode::Enter)
.key_code(KeyCode::Backspace)
.key_code(KeyCode::Backspace);
}
let events = builder.build();
tb.render_with_events(events, 0, 1, |ui| {
ui.textarea(&mut state, 5);
});
assert!(
state.history_len() <= state.history_cap(),
"history_len()={} exceeded history_cap()={}",
state.history_len(),
state.history_cap()
);
assert_eq!(state.history_cap(), 4);
}
#[test]
fn textarea_redo_invalidated_by_new_edit() {
let mut tb = TestBackend::new(40, 10);
let mut state = TextareaState::new();
let typing = EventBuilder::new().key('a').build();
tb.render_with_events(typing, 0, 1, |ui| {
ui.textarea(&mut state, 5);
});
assert_eq!(state.lines, vec!["a"]);
tb.render_with_events(ctrl_z(), 0, 1, |ui| {
ui.textarea(&mut state, 5);
});
assert_eq!(state.lines, vec![""]);
let new_typing = EventBuilder::new().key('b').build();
tb.render_with_events(new_typing, 0, 1, |ui| {
ui.textarea(&mut state, 5);
});
assert_eq!(state.lines, vec!["b"]);
tb.render_with_events(ctrl_y(), 0, 1, |ui| {
ui.textarea(&mut state, 5);
});
assert_eq!(
state.lines,
vec!["b"],
"redo should not resurrect a branch invalidated by a new edit"
);
}