use super::*;
use crate::input::{Event, Key, Modifiers};
#[path = "selection_tests.rs"]
mod selection_tests;
#[test]
fn test_init() {
let state = InputField::init();
assert!(state.is_empty());
assert_eq!(state.value(), "");
assert_eq!(state.cursor_position(), 0);
}
#[test]
fn test_new() {
let state = InputFieldState::new();
assert!(state.is_empty());
assert_eq!(state.value(), "");
assert_eq!(state.cursor_position(), 0);
assert_eq!(state.placeholder(), "");
}
#[test]
fn test_with_value() {
let state = InputFieldState::with_value("hello");
assert_eq!(state.value(), "hello");
assert_eq!(state.cursor_position(), 5);
}
#[test]
fn test_with_placeholder() {
let state = InputFieldState::with_placeholder("Enter text...");
assert_eq!(state.placeholder(), "Enter text...");
assert!(state.is_empty());
}
#[test]
fn test_insert_char() {
let mut state = InputField::init();
let output = InputField::update(&mut state, InputFieldMessage::Insert('a'));
assert_eq!(state.value(), "a");
assert_eq!(state.cursor_position(), 1);
assert_eq!(output, Some(InputFieldOutput::Changed("a".to_string())));
InputField::update(&mut state, InputFieldMessage::Insert('b'));
assert_eq!(state.value(), "ab");
assert_eq!(state.cursor_position(), 2);
}
#[test]
fn test_insert_unicode() {
let mut state = InputField::init();
InputField::update(&mut state, InputFieldMessage::Insert('日'));
InputField::update(&mut state, InputFieldMessage::Insert('本'));
assert_eq!(state.value(), "日本");
assert_eq!(state.cursor_position(), 2);
assert_eq!(state.len(), 2);
}
#[test]
fn test_backspace() {
let mut state = InputFieldState::with_value("abc");
let output = InputField::update(&mut state, InputFieldMessage::Backspace);
assert_eq!(state.value(), "ab");
assert_eq!(output, Some(InputFieldOutput::Changed("ab".to_string())));
InputField::update(&mut state, InputFieldMessage::Backspace);
InputField::update(&mut state, InputFieldMessage::Backspace);
assert_eq!(state.value(), "");
let output = InputField::update(&mut state, InputFieldMessage::Backspace);
assert_eq!(output, None);
}
#[test]
fn test_delete() {
let mut state = InputFieldState::with_value("abc");
state.set_cursor_position(0);
let output = InputField::update(&mut state, InputFieldMessage::Delete);
assert_eq!(state.value(), "bc");
assert_eq!(output, Some(InputFieldOutput::Changed("bc".to_string())));
state.cursor = state.value.len();
let output = InputField::update(&mut state, InputFieldMessage::Delete);
assert_eq!(output, None);
}
#[test]
fn test_cursor_movement() {
let mut state = InputFieldState::with_value("hello");
InputField::update(&mut state, InputFieldMessage::Left);
assert_eq!(state.cursor_position(), 4);
InputField::update(&mut state, InputFieldMessage::Left);
assert_eq!(state.cursor_position(), 3);
InputField::update(&mut state, InputFieldMessage::Right);
assert_eq!(state.cursor_position(), 4);
InputField::update(&mut state, InputFieldMessage::Home);
assert_eq!(state.cursor_position(), 0);
InputField::update(&mut state, InputFieldMessage::End);
assert_eq!(state.cursor_position(), 5);
}
#[test]
fn test_cursor_bounds() {
let mut state = InputFieldState::with_value("hi");
state.set_cursor_position(0);
InputField::update(&mut state, InputFieldMessage::Left);
assert_eq!(state.cursor_position(), 0);
state.set_cursor_position(10); assert_eq!(state.cursor_position(), 2); InputField::update(&mut state, InputFieldMessage::Right);
assert_eq!(state.cursor_position(), 2);
}
#[test]
fn test_word_navigation() {
let mut state = InputFieldState::with_value("hello world test");
InputField::update(&mut state, InputFieldMessage::WordLeft);
assert_eq!(state.cursor_position(), 12);
InputField::update(&mut state, InputFieldMessage::WordLeft);
assert_eq!(state.cursor_position(), 6);
InputField::update(&mut state, InputFieldMessage::WordLeft);
assert_eq!(state.cursor_position(), 0);
InputField::update(&mut state, InputFieldMessage::WordRight);
assert_eq!(state.cursor_position(), 6);
InputField::update(&mut state, InputFieldMessage::WordRight);
assert_eq!(state.cursor_position(), 12); }
#[test]
fn test_delete_word_back() {
let mut state = InputFieldState::with_value("hello world");
let output = InputField::update(&mut state, InputFieldMessage::DeleteWordBack);
assert_eq!(state.value(), "hello ");
assert_eq!(
output,
Some(InputFieldOutput::Changed("hello ".to_string()))
);
InputField::update(&mut state, InputFieldMessage::DeleteWordBack);
assert_eq!(state.value(), "");
let output = InputField::update(&mut state, InputFieldMessage::DeleteWordBack);
assert_eq!(output, None);
}
#[test]
fn test_delete_word_forward() {
let mut state = InputFieldState::with_value("hello world");
state.set_cursor_position(0);
let output = InputField::update(&mut state, InputFieldMessage::DeleteWordForward);
assert_eq!(state.value(), "world");
assert_eq!(output, Some(InputFieldOutput::Changed("world".to_string())));
state.cursor = state.value.len();
let output = InputField::update(&mut state, InputFieldMessage::DeleteWordForward);
assert_eq!(output, None);
}
#[test]
fn test_clear() {
let mut state = InputFieldState::with_value("hello");
let output = InputField::update(&mut state, InputFieldMessage::Clear);
assert_eq!(state.value(), "");
assert_eq!(state.cursor_position(), 0);
assert_eq!(output, Some(InputFieldOutput::Changed("".to_string())));
let output = InputField::update(&mut state, InputFieldMessage::Clear);
assert_eq!(output, None);
}
#[test]
fn test_set_value() {
let mut state = InputField::init();
let output = InputField::update(
&mut state,
InputFieldMessage::SetValue("new value".to_string()),
);
assert_eq!(state.value(), "new value");
assert_eq!(state.cursor_position(), 9);
assert_eq!(
output,
Some(InputFieldOutput::Changed("new value".to_string()))
);
let output = InputField::update(
&mut state,
InputFieldMessage::SetValue("new value".to_string()),
);
assert_eq!(output, None);
}
#[test]
fn test_submit() {
let mut state = InputFieldState::with_value("submitted text");
let output = InputField::update(&mut state, InputFieldMessage::Submit);
assert_eq!(
output,
Some(InputFieldOutput::Submitted("submitted text".to_string()))
);
assert_eq!(state.value(), "submitted text");
}
#[test]
fn test_insert_at_cursor() {
let mut state = InputFieldState::with_value("helo");
state.set_cursor_position(3);
InputField::update(&mut state, InputFieldMessage::Insert('l'));
assert_eq!(state.value(), "hello");
assert_eq!(state.cursor_position(), 4);
}
#[test]
fn test_len() {
let state = InputFieldState::with_value("hello");
assert_eq!(state.len(), 5);
let state = InputFieldState::with_value("日本語");
assert_eq!(state.len(), 3);
}
#[test]
fn test_view() {
let state = InputFieldState::with_value("Hello");
let (mut terminal, theme) = crate::component::test_utils::setup_render(40, 10);
terminal
.draw(|frame| {
InputField::view(
&state,
&mut RenderContext::new(frame, frame.area(), &theme).focused(true),
);
})
.unwrap();
insta::assert_snapshot!(terminal.backend().to_string());
}
#[test]
fn test_view_unfocused() {
let state = InputFieldState::with_value("Hello");
let (mut terminal, theme) = crate::component::test_utils::setup_render(40, 10);
terminal
.draw(|frame| {
InputField::view(
&state,
&mut RenderContext::new(frame, frame.area(), &theme).focused(true),
);
})
.unwrap();
insta::assert_snapshot!(terminal.backend().to_string());
}
#[test]
fn test_view_disabled() {
let state = InputFieldState::with_value("Hello");
let (mut terminal, theme) = crate::component::test_utils::setup_render(40, 10);
terminal
.draw(|frame| {
InputField::view(
&state,
&mut RenderContext::new(frame, frame.area(), &theme).disabled(true),
);
})
.unwrap();
insta::assert_snapshot!(terminal.backend().to_string());
}
#[test]
fn test_view_placeholder() {
let mut state = InputField::init();
state.set_placeholder("Enter text...");
let (mut terminal, theme) = crate::component::test_utils::setup_render(40, 10);
terminal
.draw(|frame| {
InputField::view(
&state,
&mut RenderContext::new(frame, frame.area(), &theme).focused(true),
);
})
.unwrap();
insta::assert_snapshot!(terminal.backend().to_string());
}
#[test]
fn test_insert_emoji() {
let mut state = InputFieldState::new();
InputField::update(&mut state, InputFieldMessage::Insert('\u{1F600}')); assert_eq!(state.value(), "\u{1F600}");
assert_eq!(state.cursor_position(), 1);
}
#[test]
fn test_cursor_with_multi_byte() {
let mut state = InputFieldState::new();
InputField::update(&mut state, InputFieldMessage::Insert('日'));
InputField::update(&mut state, InputFieldMessage::Insert('\u{1F600}'));
InputField::update(&mut state, InputFieldMessage::Insert('本'));
assert_eq!(state.value(), "日\u{1F600}本");
assert_eq!(state.cursor_position(), 3);
}
#[test]
fn test_backspace_emoji() {
let mut state = InputFieldState::new();
InputField::update(&mut state, InputFieldMessage::Insert('A'));
InputField::update(&mut state, InputFieldMessage::Insert('\u{1F600}'));
InputField::update(&mut state, InputFieldMessage::Insert('B'));
assert_eq!(state.value(), "A\u{1F600}B");
InputField::update(&mut state, InputFieldMessage::Backspace);
assert_eq!(state.value(), "A\u{1F600}");
InputField::update(&mut state, InputFieldMessage::Backspace);
assert_eq!(state.value(), "A");
}
#[test]
fn test_combining_diacritics() {
let mut state = InputFieldState::new();
InputField::update(&mut state, InputFieldMessage::Insert('e'));
InputField::update(&mut state, InputFieldMessage::Insert('\u{0301}'));
assert!(state.value().contains('e'));
assert!(state.value().contains('\u{0301}'));
}
#[test]
fn test_word_nav_with_emoji() {
let mut state = InputFieldState::new();
for c in "hello ".chars() {
InputField::update(&mut state, InputFieldMessage::Insert(c));
}
InputField::update(&mut state, InputFieldMessage::Insert('\u{1F600}'));
for c in " world".chars() {
InputField::update(&mut state, InputFieldMessage::Insert(c));
}
assert_eq!(state.value(), "hello \u{1F600} world");
InputField::update(&mut state, InputFieldMessage::Home);
assert_eq!(state.cursor_position(), 0);
InputField::update(&mut state, InputFieldMessage::WordRight);
assert!(state.cursor_position() > 0);
}
#[test]
fn test_handle_event_char_insert() {
let state = InputField::init();
let msg = InputField::handle_event(
&state,
&Event::char('a'),
&EventContext::new().focused(true),
);
assert_eq!(msg, Some(InputFieldMessage::Insert('a')));
}
#[test]
fn test_handle_event_backspace() {
let state = InputField::init();
let msg = InputField::handle_event(
&state,
&Event::key(Key::Backspace),
&EventContext::new().focused(true),
);
assert_eq!(msg, Some(InputFieldMessage::Backspace));
}
#[test]
fn test_handle_event_delete() {
let state = InputField::init();
let msg = InputField::handle_event(
&state,
&Event::key(Key::Delete),
&EventContext::new().focused(true),
);
assert_eq!(msg, Some(InputFieldMessage::Delete));
}
#[test]
fn test_handle_event_left() {
let state = InputField::init();
let msg = InputField::handle_event(
&state,
&Event::key(Key::Left),
&EventContext::new().focused(true),
);
assert_eq!(msg, Some(InputFieldMessage::Left));
}
#[test]
fn test_handle_event_right() {
let state = InputField::init();
let msg = InputField::handle_event(
&state,
&Event::key(Key::Right),
&EventContext::new().focused(true),
);
assert_eq!(msg, Some(InputFieldMessage::Right));
}
#[test]
fn test_handle_event_home() {
let state = InputField::init();
let msg = InputField::handle_event(
&state,
&Event::key(Key::Home),
&EventContext::new().focused(true),
);
assert_eq!(msg, Some(InputFieldMessage::Home));
}
#[test]
fn test_handle_event_end() {
let state = InputField::init();
let msg = InputField::handle_event(
&state,
&Event::key(Key::End),
&EventContext::new().focused(true),
);
assert_eq!(msg, Some(InputFieldMessage::End));
}
#[test]
fn test_handle_event_enter() {
let state = InputField::init();
let msg = InputField::handle_event(
&state,
&Event::key(Key::Enter),
&EventContext::new().focused(true),
);
assert_eq!(msg, Some(InputFieldMessage::Submit));
}
#[test]
fn test_handle_event_ctrl_left() {
let state = InputField::init();
let msg = InputField::handle_event(
&state,
&Event::key_with(Key::Left, Modifiers::CONTROL),
&EventContext::new().focused(true),
);
assert_eq!(msg, Some(InputFieldMessage::WordLeft));
}
#[test]
fn test_handle_event_ctrl_right() {
let state = InputField::init();
let msg = InputField::handle_event(
&state,
&Event::key_with(Key::Right, Modifiers::CONTROL),
&EventContext::new().focused(true),
);
assert_eq!(msg, Some(InputFieldMessage::WordRight));
}
#[test]
fn test_handle_event_ignored_when_unfocused() {
let state = InputField::init();
let msg = InputField::handle_event(&state, &Event::char('a'), &EventContext::default());
assert_eq!(msg, None);
}
#[test]
fn test_dispatch_event_char() {
let mut state = InputField::init();
let output = InputField::dispatch_event(
&mut state,
&Event::char('a'),
&EventContext::new().focused(true),
);
assert_eq!(output, Some(InputFieldOutput::Changed("a".to_string())));
}
#[test]
fn test_handle_event_ignored_when_disabled() {
let state = InputField::init();
let msg = InputField::handle_event(
&state,
&Event::char('a'),
&EventContext::new().focused(true).disabled(true),
);
assert_eq!(msg, None);
let msg = InputField::handle_event(
&state,
&Event::key(Key::Backspace),
&EventContext::new().focused(true).disabled(true),
);
assert_eq!(msg, None);
let msg = InputField::handle_event(
&state,
&Event::key(Key::Enter),
&EventContext::new().focused(true).disabled(true),
);
assert_eq!(msg, None);
let msg = InputField::handle_event(
&state,
&Event::key(Key::Left),
&EventContext::new().focused(true).disabled(true),
);
assert_eq!(msg, None);
}
#[test]
fn test_dispatch_event_ignored_when_disabled() {
let mut state = InputField::init();
let output = InputField::dispatch_event(
&mut state,
&Event::char('a'),
&EventContext::new().focused(true).disabled(true),
);
assert_eq!(output, None);
assert!(state.is_empty());
}
#[test]
fn test_cursor_display_position_ascii() {
let state = InputFieldState::with_value("hello");
assert_eq!(state.cursor_display_position(), 5);
assert_eq!(state.cursor_position(), 5);
}
#[test]
fn test_cursor_display_position_emoji() {
let mut state = InputFieldState::new();
InputField::update(&mut state, InputFieldMessage::Insert('A'));
InputField::update(&mut state, InputFieldMessage::Insert('\u{1F600}'));
InputField::update(&mut state, InputFieldMessage::Insert('B'));
assert_eq!(state.cursor_position(), 3);
assert_eq!(state.cursor_display_position(), 4);
InputField::update(&mut state, InputFieldMessage::Left);
assert_eq!(state.cursor_position(), 2);
assert_eq!(state.cursor_display_position(), 3);
}
#[test]
fn test_cursor_display_position_cjk() {
let mut state = InputFieldState::new();
InputField::update(&mut state, InputFieldMessage::Insert('日'));
InputField::update(&mut state, InputFieldMessage::Insert('本'));
assert_eq!(state.cursor_position(), 2);
assert_eq!(state.cursor_display_position(), 4);
}
#[test]
fn test_cursor_display_position_mixed() {
let mut state = InputFieldState::new();
InputField::update(&mut state, InputFieldMessage::Insert('A'));
InputField::update(&mut state, InputFieldMessage::Insert('日'));
InputField::update(&mut state, InputFieldMessage::Insert('\u{1F600}'));
InputField::update(&mut state, InputFieldMessage::Insert('B'));
assert_eq!(state.cursor_position(), 4);
assert_eq!(state.cursor_display_position(), 6);
}
#[test]
fn test_cursor_display_position_empty() {
let state = InputFieldState::new();
assert_eq!(state.cursor_display_position(), 0);
}
#[test]
fn test_annotation_emitted() {
use crate::annotation::{WidgetType, with_annotations};
let mut state = InputFieldState::new();
InputField::update(&mut state, InputFieldMessage::Insert('H'));
InputField::update(&mut state, InputFieldMessage::Insert('i'));
let (mut terminal, theme) = crate::component::test_utils::setup_render(30, 5);
let registry = with_annotations(|| {
terminal
.draw(|frame| {
InputField::view(
&state,
&mut RenderContext::new(frame, frame.area(), &theme).focused(true),
);
})
.unwrap();
});
assert_eq!(registry.len(), 1);
let regions = registry.find_by_type(&WidgetType::Input);
assert_eq!(regions.len(), 1);
assert_eq!(regions[0].annotation.value, Some("Hi".to_string()));
}