From 9e204e0dcccb4a1c9a0153822b4b0bdd22ad8fb6 Mon Sep 17 00:00:00 2001 From: Aram Drevekenin Date: Thu, 3 Sep 2020 16:47:44 +0200 Subject: [PATCH] tests! --- Cargo.lock | 127 +++++++++++++ Cargo.toml | 3 + src/main.rs | 108 +++++++---- src/os_input_output.rs | 32 ++-- src/tests/binary_inputs.rs | 3 + src/tests/fakes.rs | 168 ++++++++++++++++++ src/tests/integration.rs | 99 +++++++++++ src/tests/mod.rs | 4 + src/tests/possible_inputs.rs | 33 ++++ ...gration__split_terminals_vertically-2.snap | 24 +++ ...gration__split_terminals_vertically-3.snap | 24 +++ ...gration__split_terminals_vertically-4.snap | 24 +++ ...tegration__split_terminals_vertically.snap | 24 +++ ...tegration__starts_with_one_terminal-2.snap | 24 +++ ...integration__starts_with_one_terminal.snap | 24 +++ 15 files changed, 674 insertions(+), 47 deletions(-) create mode 100644 src/tests/binary_inputs.rs create mode 100644 src/tests/fakes.rs create mode 100644 src/tests/integration.rs create mode 100644 src/tests/mod.rs create mode 100644 src/tests/possible_inputs.rs create mode 100644 src/tests/snapshots/mosaic__tests__integration__split_terminals_vertically-2.snap create mode 100644 src/tests/snapshots/mosaic__tests__integration__split_terminals_vertically-3.snap create mode 100644 src/tests/snapshots/mosaic__tests__integration__split_terminals_vertically-4.snap create mode 100644 src/tests/snapshots/mosaic__tests__integration__split_terminals_vertically.snap create mode 100644 src/tests/snapshots/mosaic__tests__integration__starts_with_one_terminal-2.snap create mode 100644 src/tests/snapshots/mosaic__tests__integration__starts_with_one_terminal.snap diff --git a/Cargo.lock b/Cargo.lock index e0d91b4a..aaaec76b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -118,6 +118,20 @@ dependencies = [ "cache-padded", ] +[[package]] +name = "console" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c0994e656bba7b922d8dd1245db90672ffb701e684e45be58f20719d69abc5a" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "terminal_size", + "termios", + "winapi", +] + [[package]] name = "crossbeam-utils" version = "0.7.2" @@ -129,6 +143,24 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "difference" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" + +[[package]] +name = "dtoa" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "134951f4028bdadb9b84baf4232681efbf277da25144b9b0ad65df75946c422b" + +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + [[package]] name = "event-listener" version = "2.3.0" @@ -283,6 +315,26 @@ dependencies = [ "libc", ] +[[package]] +name = "insta" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617e921abc813f96a3b00958c079e7bf1e2db998f8a04f1546dd967373a418ee" +dependencies = [ + "console", + "difference", + "lazy_static", + "serde", + "serde_json", + "serde_yaml", +] + +[[package]] +name = "itoa" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" + [[package]] name = "js-sys" version = "0.3.44" @@ -313,6 +365,12 @@ version = "0.2.71" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" +[[package]] +name = "linked-hash-map" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a" + [[package]] name = "log" version = "0.4.11" @@ -334,6 +392,7 @@ version = "0.1.0" dependencies = [ "async-std", "futures", + "insta", "libc", "nix", "signal-hook", @@ -446,6 +505,12 @@ version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + [[package]] name = "scoped-tls" version = "1.0.0" @@ -458,6 +523,49 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" +[[package]] +name = "serde" +version = "1.0.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e54c9a88f2da7238af84b5101443f0c0d0a3bbdc455e34a5c9497b1903ed55d5" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "609feed1d0a73cc36a0182a840a9b37b4a82f0b1150369f0536a9e3f2a31dc48" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_yaml" +version = "0.8.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3e2dd40a7cdc18ca80db804b7f461a39bb721160a85c9a1fa30134bf3c02a5" +dependencies = [ + "dtoa", + "linked-hash-map", + "serde", + "yaml-rust", +] + [[package]] name = "signal-hook" version = "0.1.16" @@ -528,6 +636,16 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "terminal_size" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a14cd9f8c72704232f0bfc8455c0e861f0ad4eb60cc9ec8a170e231414c1e13" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "termios" version = "0.3.2" @@ -703,3 +821,12 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "yaml-rust" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39f0c922f1a334134dc2f7a8b67dc5d25f0735263feec974345ff706bcf20b0d" +dependencies = [ + "linked-hash-map", +] diff --git a/Cargo.toml b/Cargo.toml index 19033587..ac02214c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,3 +19,6 @@ futures = "0.3.5" [dependencies.async-std] version = "1.3.0" features = ["unstable"] + +[dev-dependencies] +insta = "0.16.1" diff --git a/src/main.rs b/src/main.rs index f5fee096..f62d529a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,6 @@ +#[cfg(test)] +mod tests; + mod os_input_output; use ::std::fmt::{self, Display, Formatter}; @@ -14,7 +17,9 @@ use async_std::task::*; use ::std::pin::*; use std::sync::mpsc::{channel, Sender, Receiver}; -use crate::os_input_output::{get_os_input, OsInputOutput, OsApi}; +use crate::os_input_output::{get_os_input, OsApi}; + +use vte::Perform; struct ReadFromPid { pid: RawFd, @@ -32,16 +37,19 @@ impl ReadFromPid { impl Stream for ReadFromPid { type Item = Vec; - fn poll_next(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { + fn poll_next(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { let mut read_buffer = [0; 115200]; - let read_result = &self.os_input.read(self.pid, &mut read_buffer); + let pid = self.pid; + let read_result = &self.os_input.read_from_tty_stdout(pid, &mut read_buffer); match read_result { Ok(res) => { - // TODO: this might become an issue with multiple panes sending data simultaneously - // ...consider returning None if res == 0 and handling it in the task (or sending - // Poll::Pending?) - let res = Some(read_buffer[..=*res].to_vec()); - return Poll::Ready(res) + if *res == 0 { + // indicates end of file + return Poll::Ready(None); + } else { + let res = Some(read_buffer[..=*res].to_vec()); + return Poll::Ready(res); + } }, Err(e) => { match e { @@ -59,8 +67,8 @@ impl Stream for ReadFromPid { } } -#[derive(Clone, Debug)] -struct TerminalCharacter { +#[derive(Clone)] +pub struct TerminalCharacter { pub character: char, pub ansi_code: Option, } @@ -106,7 +114,14 @@ impl Display for TerminalCharacter { } } -struct TerminalOutput { +impl ::std::fmt::Debug for TerminalCharacter { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.character); + Ok(()) + } +} + +pub struct TerminalOutput { pub pid: RawFd, pub characters: Vec, pub display_rows: u16, @@ -155,7 +170,8 @@ impl TerminalOutput { self.unhook(); }, VteEvent::OscDispatch(params, bell_terminated) => { - self.osc_dispatch(params, bell_terminated); + let params: Vec<&[u8]> = params.iter().map(|p| &p[..]).collect(); + self.osc_dispatch(¶ms[..], bell_terminated); }, VteEvent::CsiDispatch(params, intermediates, ignore, c) => { self.csi_dispatch(¶ms, &intermediates, ignore, c); @@ -337,6 +353,14 @@ impl TerminalOutput { (None, None) => 0 } } + fn index_of_beginning_of_last_canonical_line (&self) -> usize { + if self.newline_indices.is_empty() { + 0 + } else { + // return last + *self.newline_indices.last().unwrap() + } + } fn index_of_beginning_of_line (&self, index_in_line: usize) -> usize { let last_newline_index = if self.newline_indices.is_empty() { None @@ -404,8 +428,7 @@ impl TerminalOutput { const DEBUGGING: bool = false; -// vte methods -impl TerminalOutput { +impl vte::Perform for TerminalOutput { fn print(&mut self, c: char) { if DEBUGGING { println!("\r[print] {:?}", c); @@ -424,14 +447,15 @@ impl TerminalOutput { self.characters.push(space_character.clone()); }; self.characters.push(terminal_character); - } - let start_of_last_line = self.index_of_beginning_of_line(self.cursor_position); - let difference_from_last_newline = self.cursor_position - start_of_last_line; - if difference_from_last_newline == self.display_cols as usize { - self.linebreak_indices.push(self.cursor_position); + let start_of_last_line = self.index_of_beginning_of_line(self.cursor_position); + let difference_from_last_newline = self.cursor_position - start_of_last_line; + if difference_from_last_newline == self.display_cols as usize { + self.linebreak_indices.push(self.cursor_position); + } } self.cursor_position += 1; + } } @@ -478,9 +502,8 @@ impl TerminalOutput { } } - // fn osc_dispatch(&mut self, params: &[&[u8]], bell_terminated: bool) { + fn osc_dispatch(&mut self, params: &[&[u8]], bell_terminated: bool) { // TODO: normalize vec/slices for all of these methods and the enum - fn osc_dispatch(&mut self, params: Vec>, bell_terminated: bool) { if DEBUGGING { println!("\r[osc_dispatch] params={:?} bell_terminated={}", params, bell_terminated); } @@ -503,7 +526,7 @@ impl TerminalOutput { let param_string = params.iter().map(|p| p.to_string()).collect::>().join(";"); self.pending_ansi_code = Some(format!("\u{1b}[{}m", param_string)); } - } else if c == 'C' { // move cursor + } else if c == 'C' { // move cursor forward self.cursor_position += params[0] as usize; // TODO: negative value? } else if c == 'K' { // clear line (0 => right, 1 => left, 2 => all) if params[0] == 0 { @@ -527,6 +550,25 @@ impl TerminalOutput { self.characters.truncate(self.cursor_position + 1); } // TODO: implement 1, 2, and 3 + } else if c == 'H' { // goto row/col + let row = params[0] as usize - 1; // we subtract 1 here because this csi is 1 indexed and we index from 0 + let col = params[1] as usize - 1; + + match self.newline_indices.get(row as usize) { + Some(index_of_next_row) => { + let index_of_row = index_of_next_row - self.display_cols as usize; + self.cursor_position = index_of_row + col as usize; + } + None => { + let start_of_last_line = self.index_of_beginning_of_last_canonical_line(); + let num_of_lines_to_add = row - self.newline_indices.len(); + for i in 0..num_of_lines_to_add { + self.newline_indices.push(start_of_last_line + ((i + 1) * self.display_cols as usize)); + } + let index_of_row = self.newline_indices.last().unwrap_or(&0); // TODO: better + self.cursor_position = index_of_row + col as usize; + } + } } } } @@ -542,7 +584,8 @@ impl TerminalOutput { } } -enum VteEvent { // TODO: try not to allocate Vecs +#[derive(Debug)] +pub enum VteEvent { // TODO: try not to allocate Vecs Print(char), Execute(u8), // byte Hook(Vec, Vec, bool, char), // params, intermediates, ignore, char @@ -643,6 +686,7 @@ fn split_horizontally_with_gap (rect: &Winsize) -> (Winsize, Winsize) { (first_rect, second_rect) } +#[derive(Debug)] enum ScreenInstruction { Pty(RawFd, VteEvent), Render, @@ -732,10 +776,10 @@ impl Screen { let terminal_output = self.terminals.get_mut(&pid).unwrap(); terminal_output.handle_event(event); } - pub fn write_to_active_terminal(&self, byte: u8) { + pub fn write_to_active_terminal(&mut self, byte: u8) { if let Some(active_terminal_id) = &self.get_active_terminal_id() { let mut buffer = [byte]; - self.os_api.write(*active_terminal_id, &mut buffer).expect("failed to write to terminal"); + self.os_api.write_to_tty_stdin(*active_terminal_id, &mut buffer).expect("failed to write to terminal"); self.os_api.tcdrain(*active_terminal_id).expect("failed to drain terminal"); } } @@ -747,6 +791,7 @@ impl Screen { let mut stdout = self.os_api.get_stdout_writer(); for (_pid, terminal) in self.terminals.iter_mut() { if let Some(vte_output) = terminal.buffer_as_vte_output() { + // write boundaries if terminal.x_coords + terminal.display_cols < self.full_screen_ws.ws_col { let boundary_x_coords = terminal.x_coords + terminal.display_cols; let mut vte_output_boundaries = String::new(); @@ -990,19 +1035,19 @@ impl PtyBus { } } -fn main() { +pub fn main() { let os_input = get_os_input(); - start(os_input); + start(Box::new(os_input)); } -fn start(os_input: OsInputOutput) { +pub fn start(mut os_input: Box) { let mut active_threads = vec![]; let full_screen_ws = os_input.get_terminal_size_using_fd(0); os_input.into_raw_mode(0); - let mut screen = Screen::new(&full_screen_ws, Box::new(os_input.clone())); + let mut screen = Screen::new(&full_screen_ws, os_input.clone()); let send_screen_instructions = screen.send_screen_instructions.clone(); - let mut pty_bus = PtyBus::new(send_screen_instructions.clone(), Box::new(os_input.clone())); + let mut pty_bus = PtyBus::new(send_screen_instructions.clone(), os_input.clone()); let send_pty_instructions = pty_bus.send_pty_instructions.clone(); active_threads.push( @@ -1094,8 +1139,9 @@ fn start(os_input: OsInputOutput) { } // cleanup(); let reset_style = "\u{1b}[m"; - let goodbye_message = format!("\r{}Bye from Mosaic!", reset_style); + let goodbye_message = format!("\n\r{}Bye from Mosaic!", reset_style); os_input.get_stdout_writer().write(goodbye_message.as_bytes()).unwrap(); + os_input.get_stdout_writer().flush().unwrap(); } diff --git a/src/os_input_output.rs b/src/os_input_output.rs index f69a47a4..75c131c7 100644 --- a/src/os_input_output.rs +++ b/src/os_input_output.rs @@ -62,8 +62,8 @@ fn spawn_terminal () -> (RawFd, RawFd) { let pid_primary = fork_pty_res.master; let pid_secondary = match fork_pty_res.fork_result { ForkResult::Parent { child } => { - fcntl(pid_primary, FcntlArg::F_SETFL(OFlag::empty())).expect("could not fcntl"); - // fcntl(pid_primary, FcntlArg::F_SETFL(OFlag::O_NONBLOCK)).expect("could not fcntl"); + // fcntl(pid_primary, FcntlArg::F_SETFL(OFlag::empty())).expect("could not fcntl"); + fcntl(pid_primary, FcntlArg::F_SETFL(OFlag::O_NONBLOCK)).expect("could not fcntl"); child }, ForkResult::Child => { @@ -87,13 +87,13 @@ pub struct OsInputOutput {} pub trait OsApi: Send + Sync { fn get_terminal_size_using_fd(&self, pid: RawFd) -> Winsize; - fn set_terminal_size_using_fd(&self, pid: RawFd, cols: u16, rows: u16); - fn into_raw_mode(&self, pid: RawFd); - fn spawn_terminal(&self) -> (RawFd, RawFd); - fn read(&self, pid: RawFd, buf: &mut [u8]) -> Result; - fn write(&self, pid: RawFd, buf: &mut [u8]) -> Result; - fn tcdrain(&self, pid: RawFd) -> Result<(), nix::Error>; - fn kill(&self, pid: RawFd) -> Result<(), nix::Error>; + fn set_terminal_size_using_fd(&mut self, pid: RawFd, cols: u16, rows: u16); + fn into_raw_mode(&mut self, pid: RawFd); + fn spawn_terminal(&mut self) -> (RawFd, RawFd); + fn read_from_tty_stdout(&mut self, pid: RawFd, buf: &mut [u8]) -> Result; + fn write_to_tty_stdin(&mut self, pid: RawFd, buf: &mut [u8]) -> Result; + fn tcdrain(&mut self, pid: RawFd) -> Result<(), nix::Error>; + fn kill(&mut self, pid: RawFd) -> Result<(), nix::Error>; fn get_stdin_reader(&self) -> Box; fn get_stdout_writer(&self) -> Box; fn box_clone(&self) -> Box; @@ -103,22 +103,22 @@ impl OsApi for OsInputOutput { fn get_terminal_size_using_fd(&self, pid: RawFd) -> Winsize { get_terminal_size_using_fd(pid) } - fn set_terminal_size_using_fd(&self, pid: RawFd, cols: u16, rows: u16) { + fn set_terminal_size_using_fd(&mut self, pid: RawFd, cols: u16, rows: u16) { set_terminal_size_using_fd(pid, cols, rows); } - fn into_raw_mode(&self, pid: RawFd) { + fn into_raw_mode(&mut self, pid: RawFd) { into_raw_mode(pid); } - fn spawn_terminal(&self) -> (RawFd, RawFd) { + fn spawn_terminal(&mut self) -> (RawFd, RawFd) { spawn_terminal() } - fn read(&self, pid: RawFd, buf: &mut [u8]) -> Result { + fn read_from_tty_stdout(&mut self, pid: RawFd, buf: &mut [u8]) -> Result { read(pid, buf) } - fn write(&self, pid: RawFd, buf: &mut [u8]) -> Result { + fn write_to_tty_stdin(&mut self, pid: RawFd, buf: &mut [u8]) -> Result { write(pid, buf) } - fn tcdrain(&self, pid: RawFd) -> Result<(), nix::Error> { + fn tcdrain(&mut self, pid: RawFd) -> Result<(), nix::Error> { tcdrain(pid) } fn box_clone(&self) -> Box { @@ -135,7 +135,7 @@ impl OsApi for OsInputOutput { let stdout = ::std::io::stdout(); Box::new(stdout) } - fn kill(&self, fd: RawFd) -> Result<(), nix::Error> { + fn kill(&mut self, fd: RawFd) -> Result<(), nix::Error> { kill(Pid::from_raw(fd), None) } } diff --git a/src/tests/binary_inputs.rs b/src/tests/binary_inputs.rs new file mode 100644 index 00000000..62194e3b --- /dev/null +++ b/src/tests/binary_inputs.rs @@ -0,0 +1,3 @@ +pub const COL_121: &[u8] = &[27, 91, 49, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 50, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 51, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 52, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 53, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 54, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 55, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 56, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 57, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 49, 48, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 49, 49, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 49, 50, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 49, 51, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 49, 52, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 49, 53, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 49, 54, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 49, 55, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 49, 56, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 49, 57, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 50, 48, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 50, 49, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 50, 50, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 50, 51, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 50, 52, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 50, 53, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 50, 54, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 50, 55, 59, 49, 72, 27, 91, 109, 27, 91, 109, 87, 27, 91, 109, 101, 27, 91, 109, 108, 27, 91, 109, 99, 27, 91, 109, 111, 27, 91, 109, 109, 27, 91, 109, 101, 27, 91, 109, 32, 27, 91, 109, 116, 27, 91, 109, 111, 27, 91, 109, 32, 27, 91, 109, 102, 27, 91, 109, 105, 27, 91, 109, 115, 27, 91, 109, 104, 27, 91, 109, 44, 27, 91, 109, 32, 27, 91, 109, 116, 27, 91, 109, 104, 27, 91, 109, 101, 27, 91, 109, 32, 27, 91, 109, 102, 27, 91, 109, 114, 27, 91, 109, 105, 27, 91, 109, 101, 27, 91, 109, 110, 27, 91, 109, 100, 27, 91, 109, 108, 27, 91, 109, 121, 27, 91, 109, 32, 27, 91, 109, 105, 27, 91, 109, 110, 27, 91, 109, 116, 27, 91, 109, 101, 27, 91, 109, 114, 27, 91, 109, 97, 27, 91, 109, 99, 27, 91, 109, 116, 27, 91, 109, 105, 27, 91, 109, 118, 27, 91, 109, 101, 27, 91, 109, 32, 27, 91, 109, 115, 27, 91, 109, 104, 27, 91, 109, 101, 27, 91, 109, 108, 27, 91, 109, 108, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 50, 56, 59, 49, 72, 27, 91, 109, 27, 91, 52, 56, 59, 53, 59, 54, 109, 226, 139, 138, 27, 91, 52, 56, 59, 53, 59, 54, 109, 62, 27, 91, 109, 32, 27, 91, 51, 56, 59, 53, 59, 51, 109, 126, 27, 91, 51, 56, 59, 53, 59, 51, 109, 47, 27, 91, 51, 56, 59, 53, 59, 51, 109, 99, 27, 91, 51, 56, 59, 53, 59, 51, 109, 47, 27, 91, 51, 56, 59, 53, 59, 51, 109, 109, 27, 91, 51, 56, 59, 53, 59, 51, 109, 111, 27, 91, 51, 56, 59, 53, 59, 51, 109, 115, 27, 91, 51, 56, 59, 53, 59, 51, 109, 97, 27, 91, 51, 56, 59, 53, 59, 51, 109, 105, 27, 91, 51, 56, 59, 53, 59, 51, 109, 99, 27, 91, 109, 32, 27, 91, 109, 111, 27, 91, 109, 110, 27, 91, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 109, 109, 27, 91, 51, 56, 59, 53, 59, 50, 109, 97, 27, 91, 51, 56, 59, 53, 59, 50, 109, 105, 27, 91, 51, 56, 59, 53, 59, 50, 109, 110, 27, 91, 109, 32, 27, 91, 109, 226, 168, 175, 27, 91, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 49, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 48, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 58, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 52, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 55, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 58, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 48, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 51, 13, 27, 91, 50, 52, 67]; + +pub const COL_60: &[u8] = &[27, 91, 49, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 50, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 51, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 52, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 53, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 54, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 55, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 56, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 57, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 49, 48, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 49, 49, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 49, 50, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 49, 51, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 49, 52, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 49, 53, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 49, 54, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 49, 55, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 49, 56, 59, 49, 72, 27, 91, 109, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 49, 57, 59, 49, 72, 27, 91, 109, 27, 91, 109, 87, 27, 91, 109, 101, 27, 91, 109, 108, 27, 91, 109, 99, 27, 91, 109, 111, 27, 91, 109, 109, 27, 91, 109, 101, 27, 91, 109, 32, 27, 91, 109, 116, 27, 91, 109, 111, 27, 91, 109, 32, 27, 91, 109, 102, 27, 91, 109, 105, 27, 91, 109, 115, 27, 91, 109, 104, 27, 91, 109, 44, 27, 91, 109, 32, 27, 91, 109, 116, 27, 91, 109, 104, 27, 91, 109, 101, 27, 91, 109, 32, 27, 91, 109, 102, 27, 91, 109, 114, 27, 91, 109, 105, 27, 91, 109, 101, 27, 91, 109, 110, 27, 91, 109, 100, 27, 91, 109, 108, 27, 91, 109, 121, 27, 91, 109, 32, 27, 91, 109, 105, 27, 91, 109, 110, 27, 91, 109, 116, 27, 91, 109, 101, 27, 91, 109, 114, 27, 91, 109, 97, 27, 91, 109, 99, 27, 91, 109, 116, 27, 91, 109, 105, 27, 91, 109, 118, 27, 91, 109, 101, 27, 91, 109, 32, 27, 91, 109, 115, 27, 91, 109, 104, 27, 91, 109, 101, 27, 91, 109, 108, 27, 91, 109, 108, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 27, 91, 50, 48, 59, 49, 72, 27, 91, 109, 27, 91, 52, 56, 59, 53, 59, 54, 109, 226, 139, 138, 27, 91, 52, 56, 59, 53, 59, 54, 109, 62, 27, 91, 109, 32, 27, 91, 51, 56, 59, 53, 59, 51, 109, 126, 27, 91, 51, 56, 59, 53, 59, 51, 109, 47, 27, 91, 51, 56, 59, 53, 59, 51, 109, 99, 27, 91, 51, 56, 59, 53, 59, 51, 109, 47, 27, 91, 51, 56, 59, 53, 59, 51, 109, 109, 27, 91, 51, 56, 59, 53, 59, 51, 109, 111, 27, 91, 51, 56, 59, 53, 59, 51, 109, 115, 27, 91, 51, 56, 59, 53, 59, 51, 109, 97, 27, 91, 51, 56, 59, 53, 59, 51, 109, 105, 27, 91, 51, 56, 59, 53, 59, 51, 109, 99, 27, 91, 109, 32, 27, 91, 109, 111, 27, 91, 109, 110, 27, 91, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 109, 109, 27, 91, 51, 56, 59, 53, 59, 50, 109, 97, 27, 91, 51, 56, 59, 53, 59, 50, 109, 105, 27, 91, 51, 56, 59, 53, 59, 50, 109, 110, 27, 91, 109, 32, 27, 91, 109, 226, 168, 175, 27, 91, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 32, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 49, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 57, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 58, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 52, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 48, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 58, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 48, 27, 91, 51, 56, 59, 53, 59, 50, 52, 48, 109, 48, 13, 27, 91, 50, 52, 67]; diff --git a/src/tests/fakes.rs b/src/tests/fakes.rs new file mode 100644 index 00000000..a9893dcc --- /dev/null +++ b/src/tests/fakes.rs @@ -0,0 +1,168 @@ +use ::std::time::Duration; +use ::nix::pty::Winsize; +use ::std::os::unix::io::RawFd; +use ::std::io::{Read, Write}; +use ::std::collections::HashMap; +use ::std::sync::{Arc, Mutex}; + +use crate::os_input_output::OsApi; +use crate::tests::possible_inputs::{Bytes, get_possible_inputs}; + +#[derive(Clone)] +pub enum IoEvent { + Kill(RawFd), + SetTerminalSizeUsingFd(RawFd, u16, u16), + IntoRawMode(RawFd), + TcDrain(RawFd), +} + +pub struct FakeStdinReader { + pub input_chars: Bytes, +} + +impl FakeStdinReader { + pub fn new(input_chars: Vec) -> Self { + let bytes = Bytes::new().content(input_chars); + FakeStdinReader { + input_chars: bytes, + } + } +} + +impl Read for FakeStdinReader { + fn read(&mut self, buf: &mut [u8]) -> Result { + ::std::thread::sleep(Duration::from_millis(1000)); // TODO: adjust duration + let read_position = self.input_chars.read_position; + buf[0] = self.input_chars.content[read_position]; + self.input_chars.set_read_position(read_position + 1); + Ok(1) + } +} + +#[derive(Clone, Default)] +pub struct FakeStdoutWriter { + output_buffer: Arc>>, + pub output_frames: Arc>>>, +} + +impl Write for FakeStdoutWriter { + fn write(&mut self, buf: &[u8]) -> Result { + let mut bytes_written = 0; + let mut output_buffer = self.output_buffer.lock().unwrap(); + for byte in buf { + bytes_written += 1; + output_buffer.push(*byte); + } + Ok(bytes_written) + } + fn flush(&mut self) -> Result<(), std::io::Error> { + let mut output_buffer = self.output_buffer.lock().unwrap(); + let mut output_frames = self.output_frames.lock().unwrap(); + let new_frame = output_buffer.drain(..).collect(); + output_frames.push(new_frame); + Ok(()) + } +} + +#[derive(Clone)] +pub struct FakeInputOutput { + read_buffers: Arc>>, + input_to_add: Arc>>>, + stdin_writes: Arc>>>, + pub stdout_writer: FakeStdoutWriter, // stdout_writer.output is already an arc/mutex + io_events: Arc>>, + win_sizes: Arc>>, + possible_inputs: HashMap, +} + +impl FakeInputOutput { + pub fn new(winsize: Winsize) -> Self { + let mut win_sizes = HashMap::new(); + win_sizes.insert(0 , winsize); // 0 is the current terminal + FakeInputOutput { + read_buffers: Arc::new(Mutex::new(HashMap::new())), + stdin_writes: Arc::new(Mutex::new(HashMap::new())), + input_to_add: Arc::new(Mutex::new(None)), + stdout_writer: FakeStdoutWriter::default(), + io_events: Arc::new(Mutex::new(vec![])), + win_sizes: Arc::new(Mutex::new(win_sizes)), + possible_inputs: get_possible_inputs(), + } + } + pub fn add_terminal_input(&mut self, input: &[u8]) { + self.input_to_add = Arc::new(Mutex::new(Some(input.to_vec()))); + } + pub fn add_terminal(&mut self, fd: RawFd) { + self.stdin_writes.lock().unwrap().insert(fd, vec![]); + } +} + +impl OsApi for FakeInputOutput { + fn get_terminal_size_using_fd(&self, pid: RawFd) -> Winsize { + let win_sizes = self.win_sizes.lock().unwrap(); + let winsize = win_sizes.get(&pid).unwrap(); + *winsize + } + fn set_terminal_size_using_fd(&mut self, pid: RawFd, cols: u16, rows: u16) { + let terminal_input = self.possible_inputs.get(&cols).expect(&format!("could not find input for size {:?}", cols)); + self.read_buffers.lock().unwrap().insert(pid, terminal_input.clone()); + self.io_events.lock().unwrap().push(IoEvent::SetTerminalSizeUsingFd(pid, cols, rows)); + } + fn into_raw_mode(&mut self, pid: RawFd) { + self.io_events.lock().unwrap().push(IoEvent::IntoRawMode(pid)); + } + fn spawn_terminal(&mut self) -> (RawFd, RawFd) { + let next_terminal_id = { self.read_buffers.lock().unwrap().keys().len() as RawFd + 1 }; + self.add_terminal(next_terminal_id); + (next_terminal_id as i32, next_terminal_id + 1000) // secondary number is arbitrary here + } + fn read_from_tty_stdout(&mut self, pid: RawFd, buf: &mut [u8]) -> Result { + let mut read_buffers = self.read_buffers.lock().unwrap(); + let mut bytes_read = 0; + if let Some(bytes) = read_buffers.get_mut(&pid) { + for i in bytes.read_position..bytes.content.len() { + bytes_read += 1; + buf[i] = bytes.content[i]; + } + if bytes_read > bytes.read_position { + bytes.set_read_position(bytes_read); + } + } + Ok(bytes_read) + } + fn write_to_tty_stdin(&mut self, pid: RawFd, buf: &mut [u8]) -> Result { + let mut stdin_writes = self.stdin_writes.lock().unwrap(); + let write_buffer = stdin_writes.get_mut(&pid).unwrap(); + let mut bytes_written = 0; + for byte in buf { + bytes_written += 1; + write_buffer.push(*byte); + } + Ok(bytes_written) + } + fn tcdrain(&mut self, pid: RawFd) -> Result<(), nix::Error> { + self.io_events.lock().unwrap().push(IoEvent::TcDrain(pid)); + Ok(()) + } + fn box_clone(&self) -> Box { + Box::new((*self).clone()) + } + fn get_stdin_reader(&self) -> Box { + let mut input_chars = vec![0, 1, 2]; + if let Some(input_to_add) = self.input_to_add.lock().unwrap().as_ref() { + for byte in input_to_add { + input_chars.push(*byte); + } + } + input_chars.push(17); // ctrl-q (quit) + let reader = FakeStdinReader::new(input_chars); + Box::new(reader) + } + fn get_stdout_writer(&self) -> Box { + Box::new(self.stdout_writer.clone()) + } + fn kill(&mut self, fd: RawFd) -> Result<(), nix::Error> { + self.io_events.lock().unwrap().push(IoEvent::Kill(fd)); + Ok(()) + } +} diff --git a/src/tests/integration.rs b/src/tests/integration.rs new file mode 100644 index 00000000..6acbf1aa --- /dev/null +++ b/src/tests/integration.rs @@ -0,0 +1,99 @@ +use ::nix::pty::Winsize; +use ::insta::assert_snapshot; + +use crate::{start, TerminalOutput}; +use crate::tests::fakes::{FakeInputOutput}; + +pub fn get_fake_os_input () -> FakeInputOutput { + let fake_win_size = Winsize { + ws_col: 121, + ws_row: 20, + ws_xpixel: 0, + ws_ypixel: 0, + }; + FakeInputOutput::new(fake_win_size) +} + +#[test] +pub fn starts_with_one_terminal () { + let mut fake_input_output = get_fake_os_input(); + fake_input_output.add_terminal_input(&[17]); // quit (ctrl-q) + start(Box::new(fake_input_output.clone())); + + let output_frames = fake_input_output.stdout_writer.output_frames.lock().unwrap(); + let mut vte_parser = vte::Parser::new(); + let main_pid = 0; + let x = 0; + let fake_win_size = Winsize { // TODO: combine with above + ws_col: 121, + ws_row: 20, + ws_xpixel: 0, + ws_ypixel: 0, + }; + let mut terminal_output = TerminalOutput::new(main_pid, fake_win_size, x); + + for frame in output_frames.iter() { + for byte in frame.iter() { + vte_parser.advance(&mut terminal_output, *byte); + } + let output_lines = terminal_output.read_buffer_as_lines(); + let cursor_position_in_last_line = terminal_output.cursor_position_in_last_line(); + let mut snapshot = String::new(); + for (line_index, line) in output_lines.iter().enumerate() { + for (character_index, terminal_character) in line.iter().enumerate() { + if line_index == output_lines.len() - 1 && character_index == cursor_position_in_last_line { + snapshot.push('█'); + } else { + snapshot.push(terminal_character.character); + } + } + if line_index != output_lines.len() - 1 { + snapshot.push('\n'); + } + } + assert_snapshot!(snapshot); + } +} + +#[test] +pub fn split_terminals_vertically() { + // TODO: this test is a little flaky - there's some sort of race condition that makes the + // second terminal in the split appear blank sometimes - fix this + let mut fake_input_output = get_fake_os_input(); + fake_input_output.add_terminal_input(&[14, 17]); // split-vertically and quit (ctrl-n + ctrl-q) + start(Box::new(fake_input_output.clone())); + + let output_frames = fake_input_output.stdout_writer.output_frames.lock().unwrap(); + let mut vte_parser = vte::Parser::new(); + let main_pid = 0; + let x = 0; + let fake_win_size = Winsize { // TODO: combine with above + ws_col: 121, + ws_row: 20, + ws_xpixel: 0, + ws_ypixel: 0, + }; + let mut terminal_output = TerminalOutput::new(main_pid, fake_win_size, x); + + for frame in output_frames.iter() { + for byte in frame.iter() { + vte_parser.advance(&mut terminal_output, *byte); + } + let output_lines = terminal_output.read_buffer_as_lines(); + let cursor_position_in_last_line = terminal_output.cursor_position_in_last_line(); + let mut snapshot = String::new(); + for (line_index, line) in output_lines.iter().enumerate() { + for (character_index, terminal_character) in line.iter().enumerate() { + if line_index == output_lines.len() - 1 && character_index == cursor_position_in_last_line { + snapshot.push('█'); + } else { + snapshot.push(terminal_character.character); + } + } + if line_index != output_lines.len() - 1 { + snapshot.push('\n'); + } + } + assert_snapshot!(snapshot); + } +} diff --git a/src/tests/mod.rs b/src/tests/mod.rs new file mode 100644 index 00000000..15c2ef0c --- /dev/null +++ b/src/tests/mod.rs @@ -0,0 +1,4 @@ +pub mod integration; +pub mod possible_inputs; +pub mod binary_inputs; +pub mod fakes; diff --git a/src/tests/possible_inputs.rs b/src/tests/possible_inputs.rs new file mode 100644 index 00000000..5f1ef874 --- /dev/null +++ b/src/tests/possible_inputs.rs @@ -0,0 +1,33 @@ +use std::collections::HashMap; +use crate::tests::binary_inputs::{COL_121, COL_60}; + +#[derive(Clone)] +pub struct Bytes { + pub content: Vec, + pub read_position: usize, +} + +impl Bytes { + pub fn new() -> Self { + Bytes { + content: vec![], + read_position: 0 + } + } + pub fn content(mut self, content: Vec) -> Self { + self.content = content; + self + } + pub fn set_read_position(&mut self, read_position: usize) { + self.read_position = read_position; + } +} + +pub fn get_possible_inputs () -> HashMap { // the key is the column count for this terminal input + let mut possible_inputs = HashMap::new(); + let col_60_bytes = Bytes::new().content(Vec::from(COL_60)); + let col_121_bytes = Bytes::new().content(Vec::from(COL_121)); + possible_inputs.insert(121, col_121_bytes); + possible_inputs.insert(60, col_60_bytes); + possible_inputs +} diff --git a/src/tests/snapshots/mosaic__tests__integration__split_terminals_vertically-2.snap b/src/tests/snapshots/mosaic__tests__integration__split_terminals_vertically-2.snap new file mode 100644 index 00000000..20d74b27 --- /dev/null +++ b/src/tests/snapshots/mosaic__tests__integration__split_terminals_vertically-2.snap @@ -0,0 +1,24 @@ +--- +source: src/tests/integration.rs +expression: snapshot +--- + + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ +Welcome to fish, the friendly interactive shell │ + │ + │ +⋊> ~/c/mosaic on main ⨯ │ diff --git a/src/tests/snapshots/mosaic__tests__integration__split_terminals_vertically-3.snap b/src/tests/snapshots/mosaic__tests__integration__split_terminals_vertically-3.snap new file mode 100644 index 00000000..a110ee36 --- /dev/null +++ b/src/tests/snapshots/mosaic__tests__integration__split_terminals_vertically-3.snap @@ -0,0 +1,24 @@ +--- +source: src/tests/integration.rs +expression: snapshot +--- + + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ +Welcome to fish, the friendly interactive shell │ + │ + │Welcome to fish, the friendly interactive shell +⋊> ~/c/mosaic on main ⨯ │⋊> ~/c/mosaic on main ⨯ █ 19:40:00 diff --git a/src/tests/snapshots/mosaic__tests__integration__split_terminals_vertically-4.snap b/src/tests/snapshots/mosaic__tests__integration__split_terminals_vertically-4.snap new file mode 100644 index 00000000..a0e55f1a --- /dev/null +++ b/src/tests/snapshots/mosaic__tests__integration__split_terminals_vertically-4.snap @@ -0,0 +1,24 @@ +--- +source: src/tests/integration.rs +expression: snapshot +--- + + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ +Welcome to fish, the friendly interactive shell │ + │ + │Welcome to fish, the friendly interactive shell +⋊> ~/c/mosaic on main ⨯ │⋊> ~/c/mosaic on main ⨯ 19:40:00 +Bye from Mosaic! diff --git a/src/tests/snapshots/mosaic__tests__integration__split_terminals_vertically.snap b/src/tests/snapshots/mosaic__tests__integration__split_terminals_vertically.snap new file mode 100644 index 00000000..ed307b43 --- /dev/null +++ b/src/tests/snapshots/mosaic__tests__integration__split_terminals_vertically.snap @@ -0,0 +1,24 @@ +--- +source: src/tests/integration.rs +expression: snapshot +--- + + + + + + + + + + + + + + + + + + +Welcome to fish, the friendly interactive shell +⋊> ~/c/mosaic on main ⨯ █ 10:47:03 diff --git a/src/tests/snapshots/mosaic__tests__integration__starts_with_one_terminal-2.snap b/src/tests/snapshots/mosaic__tests__integration__starts_with_one_terminal-2.snap new file mode 100644 index 00000000..a4898030 --- /dev/null +++ b/src/tests/snapshots/mosaic__tests__integration__starts_with_one_terminal-2.snap @@ -0,0 +1,24 @@ +--- +source: src/tests/integration.rs +expression: snapshot +--- + + + + + + + + + + + + + + + + + +Welcome to fish, the friendly interactive shell +⋊> ~/c/mosaic on main ⨯ 10:47:03 +Bye from Mosaic! diff --git a/src/tests/snapshots/mosaic__tests__integration__starts_with_one_terminal.snap b/src/tests/snapshots/mosaic__tests__integration__starts_with_one_terminal.snap new file mode 100644 index 00000000..ed307b43 --- /dev/null +++ b/src/tests/snapshots/mosaic__tests__integration__starts_with_one_terminal.snap @@ -0,0 +1,24 @@ +--- +source: src/tests/integration.rs +expression: snapshot +--- + + + + + + + + + + + + + + + + + + +Welcome to fish, the friendly interactive shell +⋊> ~/c/mosaic on main ⨯ █ 10:47:03