#![allow(clippy::collapsible_if)]
use std::io::Write as _;
mod fixtures;
#[test]
fn test_basic() {
let mut fixture = fixtures::Fixture::new("input");
fixture.screenguard(false);
let mut run = fixture.build();
for utf8 in &[true, false] {
for ctrl in &[true, false] {
for meta in &[true, false] {
for special_keys in &[true, false] {
for single in &[true, false] {
run_input_test(
&mut run,
*utf8,
*ctrl,
*meta,
*special_keys,
*single,
);
}
}
}
}
}
}
#[test]
fn test_async() {
let mut fixture = fixtures::Fixture::new("input");
fixture.screenguard(false);
fixture.features("async");
let mut run = fixture.build();
for utf8 in &[true, false] {
for ctrl in &[true, false] {
for meta in &[true, false] {
for special_keys in &[true, false] {
for single in &[true, false] {
run_input_test(
&mut run,
*utf8,
*ctrl,
*meta,
*special_keys,
*single,
);
}
}
}
}
}
}
// the structure of the if statements here are easier to interpret uncollapsed
#[allow(clippy::collapsible_else_if)]
fn run_input_test(
fixture: &mut fixtures::BuiltFixture,
utf8: bool,
ctrl: bool,
meta: bool,
special_keys: bool,
single: bool,
) {
let mut args = vec![];
if !utf8 {
args.push("--disable-utf8")
}
if !ctrl {
args.push("--disable-ctrl")
}
if !meta {
args.push("--disable-meta")
}
if !special_keys {
args.push("--disable-special-keys")
}
if !single {
args.push("--disable-single")
}
fixture.run(&args, |pty| {
let mut r = std::io::BufReader::new(pty);
assert_no_more_lines(&mut r);
write(r.get_mut(), textmode::Key::Up);
if special_keys {
assert_line(&mut r, "Up: [27, 91, 65]");
} else {
if single {
assert_line(&mut r, "Byte(27): [27]");
if utf8 {
assert_line(&mut r, "Char('['): [91]");
assert_line(&mut r, "Char('A'): [65]");
} else {
assert_line(&mut r, "Byte(91): [91]");
assert_line(&mut r, "Byte(65): [65]");
}
} else {
if utf8 {
assert_line(&mut r, "Bytes([27]): [27]");
assert_line(&mut r, "String(\"[A\"): [91, 65]");
} else {
// TODO: ideally this wouldn't make a difference
if meta {
assert_line(&mut r, "Bytes([27]): [27]");
assert_line(&mut r, "Bytes([91, 65]): [91, 65]");
} else {
assert_line(
&mut r,
"Bytes([27, 91, 65]): [27, 91, 65]",
);
}
}
}
}
assert_no_more_lines(&mut r);
write(r.get_mut(), textmode::Key::Meta(b'c'));
if meta {
assert_line(&mut r, "Meta(99): [27, 99]");
} else {
if special_keys {
assert_line(&mut r, "Escape: [27]");
if utf8 {
if single {
assert_line(&mut r, "Char('c'): [99]");
} else {
assert_line(&mut r, "String(\"c\"): [99]");
}
} else {
if single {
assert_line(&mut r, "Byte(99): [99]");
} else {
assert_line(&mut r, "Bytes([99]): [99]");
}
}
} else {
if single {
assert_line(&mut r, "Byte(27): [27]");
if utf8 {
assert_line(&mut r, "Char('c'): [99]");
} else {
assert_line(&mut r, "Byte(99): [99]");
}
} else {
if utf8 {
assert_line(&mut r, "Bytes([27]): [27]");
assert_line(&mut r, "String(\"c\"): [99]");
} else {
assert_line(&mut r, "Bytes([27, 99]): [27, 99]");
}
}
}
}
assert_no_more_lines(&mut r);
write(r.get_mut(), textmode::Key::String("foo".to_string()));
if single {
if utf8 {
assert_line(&mut r, "Char('f'): [102]");
assert_line(&mut r, "Char('o'): [111]");
assert_line(&mut r, "Char('o'): [111]");
} else {
assert_line(&mut r, "Byte(102): [102]");
assert_line(&mut r, "Byte(111): [111]");
assert_line(&mut r, "Byte(111): [111]");
}
} else {
if utf8 {
assert_line(&mut r, "String(\"foo\"): [102, 111, 111]");
} else {
assert_line(
&mut r,
"Bytes([102, 111, 111]): [102, 111, 111]",
);
}
}
assert_no_more_lines(&mut r);
write(r.get_mut(), textmode::Key::String("🎉".to_string()));
if single {
if utf8 {
assert_line(&mut r, "Char('🎉'): [240, 159, 142, 137]");
} else {
assert_line(&mut r, "Byte(240): [240]");
assert_line(&mut r, "Byte(159): [159]");
assert_line(&mut r, "Byte(142): [142]");
assert_line(&mut r, "Byte(137): [137]");
}
} else {
if utf8 {
assert_line(&mut r, "String(\"🎉\"): [240, 159, 142, 137]");
} else {
assert_line(
&mut r,
"Bytes([240, 159, 142, 137]): [240, 159, 142, 137]",
);
}
}
assert_no_more_lines(&mut r);
write(r.get_mut(), textmode::Key::Bytes(vec![102, 111, 111, 240]));
if single {
if utf8 {
assert_line(&mut r, "Char('f'): [102]");
assert_line(&mut r, "Char('o'): [111]");
assert_line(&mut r, "Char('o'): [111]");
} else {
assert_line(&mut r, "Byte(102): [102]");
assert_line(&mut r, "Byte(111): [111]");
assert_line(&mut r, "Byte(111): [111]");
assert_line(&mut r, "Byte(240): [240]");
}
} else {
if utf8 {
assert_line(&mut r, "String(\"foo\"): [102, 111, 111]");
} else {
assert_line(
&mut r,
"Bytes([102, 111, 111, 240]): [102, 111, 111, 240]",
);
}
}
assert_no_more_lines(&mut r);
write(r.get_mut(), textmode::Key::Bytes(vec![159]));
if utf8 {
assert_no_more_lines(&mut r);
} else {
if single {
assert_line(&mut r, "Byte(159): [159]");
} else {
assert_line(&mut r, "Bytes([159]): [159]");
}
}
write(r.get_mut(), textmode::Key::Bytes(vec![142]));
if utf8 {
assert_no_more_lines(&mut r);
} else {
if single {
assert_line(&mut r, "Byte(142): [142]");
} else {
assert_line(&mut r, "Bytes([142]): [142]");
}
}
write(r.get_mut(), textmode::Key::Bytes(vec![137]));
if utf8 {
if single {
assert_line(&mut r, "Char('🎉'): [240, 159, 142, 137]");
} else {
assert_line(&mut r, "String(\"🎉\"): [240, 159, 142, 137]");
}
} else {
if single {
assert_line(&mut r, "Byte(137): [137]");
} else {
assert_line(&mut r, "Bytes([137]): [137]");
}
}
assert_no_more_lines(&mut r);
write(r.get_mut(), textmode::Key::Bytes(vec![240, 102, 111, 111]));
if utf8 {
if single {
assert_line(&mut r, "Byte(240): [240]");
assert_line(&mut r, "Char('f'): [102]");
assert_line(&mut r, "Char('o'): [111]");
assert_line(&mut r, "Char('o'): [111]");
} else {
// TODO: ideally this would be Bytes([240]) followed by
// String("foo") but figuring that out in a general way seems
// hard, and this is a pretty minor edge case
assert_line(
&mut r,
"Bytes([240, 102, 111, 111]): [240, 102, 111, 111]",
);
}
} else {
if single {
assert_line(&mut r, "Byte(240): [240]");
assert_line(&mut r, "Byte(102): [102]");
assert_line(&mut r, "Byte(111): [111]");
assert_line(&mut r, "Byte(111): [111]");
} else {
assert_line(
&mut r,
"Bytes([240, 102, 111, 111]): [240, 102, 111, 111]",
);
}
}
assert_no_more_lines(&mut r);
write(r.get_mut(), textmode::Key::Ctrl(b'c'));
if ctrl {
assert_line(&mut r, "Ctrl(99): [3]");
} else {
if single {
assert_line(&mut r, "Byte(3): [3]");
} else {
assert_line(&mut r, "Bytes([3]): [3]");
}
}
assert_no_more_lines(&mut r);
});
}
#[track_caller]
fn write(f: &mut pty_process::blocking::Pty, key: textmode::Key) {
f.write_all(&key.into_bytes()).unwrap();
}
#[track_caller]
fn read(
f: &mut std::io::BufReader<&mut pty_process::blocking::Pty>,
) -> String {
std::string::String::from_utf8(fixtures::read_line(f)).unwrap()
}
#[track_caller]
fn assert_line(
f: &mut std::io::BufReader<&mut pty_process::blocking::Pty>,
expected: &str,
) {
assert_eq!(read(f), format!("{}\r\n", expected));
}
#[track_caller]
fn assert_no_more_lines(
f: &mut std::io::BufReader<&mut pty_process::blocking::Pty>,
) {
if fixtures::read_ready(f.get_ref()) || !f.buffer().is_empty() {
use std::io::Read as _;
let mut buf = vec![0; 4096];
let bytes = f.read(&mut buf).unwrap();
buf.truncate(bytes);
panic!(
"got bytes: \"{}\"({:?})",
std::string::String::from_utf8_lossy(&buf),
buf
);
}
}