use super::*;
#[test]
fn feed_decodes_plain_key_to_input_event_key() {
let mut parser = Parser::new();
let events = parser.feed(b"a");
assert_eq!(events.len(), 1);
match &events[0] {
InputEvent::Key(key) => assert_eq!(key.name, "a"),
other => panic!("expected key, got {other:?}"),
}
}
#[test]
fn feed_decodes_csi_arrow_to_named_key() {
let mut parser = Parser::new();
let events = parser.feed(b"\x1b[A");
assert_eq!(events.len(), 1);
match &events[0] {
InputEvent::Key(key) => {
assert_eq!(key.name, "up");
assert!(!key.is_kitty_protocol);
}
other => panic!("expected key, got {other:?}"),
}
}
#[test]
fn feed_decodes_kitty_csi_u_first() {
let mut parser = Parser::new();
let events = parser.feed(b"\x1b[97;5u");
assert_eq!(events.len(), 1);
match &events[0] {
InputEvent::Key(key) => {
assert_eq!(key.name, "a");
assert!(key.ctrl);
assert!(key.is_kitty_protocol);
}
other => panic!("expected key, got {other:?}"),
}
}
#[test]
fn feed_emits_paste_event_verbatim() {
let mut parser = Parser::new();
let events = parser.feed(b"\x1b[200~hello world\x1b[201~");
assert_eq!(events, vec![InputEvent::Paste(b"hello world".to_vec())]);
}
#[test]
fn feed_interleaves_text_paste_and_keys() {
let mut parser = Parser::new();
let events = parser.feed(b"before\x1b[200~pasted\x1b[201~after");
assert_eq!(events.len(), 3);
assert!(matches!(&events[0], InputEvent::Key(k) if k.sequence == "before"));
assert_eq!(events[1], InputEvent::Paste(b"pasted".to_vec()));
assert!(matches!(&events[2], InputEvent::Key(k) if k.sequence == "after"));
}
#[test]
fn feed_buffers_partial_sequence_across_calls() {
let mut parser = Parser::new();
assert_eq!(parser.feed(b"\x1b["), vec![]);
assert!(parser.has_pending_escape());
let events = parser.feed(b"1;5A");
assert_eq!(events.len(), 1);
match &events[0] {
InputEvent::Key(key) => {
assert_eq!(key.name, "up");
assert!(key.ctrl);
}
other => panic!("expected key, got {other:?}"),
}
}
#[test]
fn feed_splits_batched_backspace_into_individual_key_events() {
let mut parser = Parser::new();
let events = parser.feed(b"\x7f\x7f");
assert_eq!(events.len(), 2);
for event in &events {
match event {
InputEvent::Key(key) => assert_eq!(key.name, "backspace"),
other => panic!("expected key, got {other:?}"),
}
}
}
#[test]
fn flush_pending_escape_returns_buffered_bytes() {
let mut parser = Parser::new();
assert_eq!(parser.feed(b"\x1b"), vec![]);
assert_eq!(parser.flush_pending_escape(), Some(b"\x1b".to_vec()));
assert_eq!(parser.flush_pending_escape(), None);
}
#[test]
fn reset_clears_pending_state() {
let mut parser = Parser::new();
assert_eq!(parser.feed(b"\x1b["), vec![]);
parser.reset();
let events = parser.feed(b"A");
assert_eq!(events.len(), 1);
assert!(matches!(&events[0], InputEvent::Key(k) if k.name == "a"));
}
#[test]
fn feed_decodes_paste_across_every_fragmentation_boundary() {
const START: &[u8] = b"\x1b[200~";
const END: &[u8] = b"\x1b[201~";
let bodies: [&[u8]; 4] = [
b"hello world",
b"line1\rline2\r",
b"esc\x1bmore\x03ctl",
b"rocket \xf0\x9f\x9a\x80 end",
];
for body in bodies {
let mut seq = Vec::new();
seq.extend_from_slice(START);
seq.extend_from_slice(body);
seq.extend_from_slice(END);
let expected = vec![InputEvent::Paste(body.to_vec())];
for split in 1..seq.len() {
let mut parser = Parser::new();
let mut events = parser.feed(&seq[..split]);
events.extend(parser.feed(&seq[split..]));
assert_eq!(
events, expected,
"2-way split at {split} for body {body:?} did not decode to one verbatim paste"
);
}
let mut parser = Parser::new();
let mut events = Vec::new();
for &byte in &seq {
events.extend(parser.feed(&[byte]));
}
assert_eq!(
events, expected,
"byte-by-byte feed for body {body:?} did not decode to one verbatim paste"
);
}
}