diff options
author | Aram Drevekenin <aram@poor.dev> | 2021-06-30 11:27:35 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-06-30 11:27:35 +0200 |
commit | ed4fd2a8e77df304539ca7f445a78039028eaa8a (patch) | |
tree | ae48b03370b11f3f0987676584724463ac83460d /zellij-server/src/unit | |
parent | 974edc2c98abf22b29598480c41f2505edef4dd1 (diff) |
chore(tests): move all integration tests to be either unit or e2e tests - remove old testing infra (#589)
* tests(integration): move basic integration tests to be unit tests
* fix(tests): silently fail threadbus for tests
* tests(unit): move compatibility tests to become unit tests for grid
* tests(unit): move close_pane tests to become unit tests for grid
* tests(e2e): move basic layout test to e2e
* tests(unit): move move_focus tests to be unit tests
* tests(unit): move resize_down tests to be unit tests
* tests(unit): move resize_left tests to be unit tests
* tests(unit): move resize_right tests to be unit tests
* tests(unit): move resize_up tests to be unit tests
* tests(infra): remove unused infra
* style(fmt): make rustfmt happy
* debug
* debug
* debug
* debug
* chore(test): shift volume mounting around because github actions is a special child
Diffstat (limited to 'zellij-server/src/unit')
-rw-r--r-- | zellij-server/src/unit/screen_tests.rs | 255 | ||||
-rw-r--r-- | zellij-server/src/unit/tab_tests.rs | 11840 |
2 files changed, 12095 insertions, 0 deletions
diff --git a/zellij-server/src/unit/screen_tests.rs b/zellij-server/src/unit/screen_tests.rs new file mode 100644 index 000000000..da52c5850 --- /dev/null +++ b/zellij-server/src/unit/screen_tests.rs @@ -0,0 +1,255 @@ +use super::{Screen, ScreenInstruction}; +use crate::zellij_tile::data::{InputMode, ModeInfo, Palette}; +use crate::{ + os_input_output::{AsyncReader, Pid, ServerOsApi}, + thread_bus::Bus, + SessionState, +}; +use std::sync::{Arc, RwLock}; +use zellij_utils::pane_size::PositionAndSize; + +use std::os::unix::io::RawFd; +use std::path::PathBuf; + +use zellij_utils::ipc::ClientAttributes; +use zellij_utils::nix; + +use zellij_utils::{ + errors::ErrorContext, + interprocess::local_socket::LocalSocketStream, + ipc::{ClientToServerMsg, ServerToClientMsg}, +}; + +#[derive(Clone)] +struct FakeInputOutput {} + +impl ServerOsApi for FakeInputOutput { + fn set_terminal_size_using_fd(&self, _fd: RawFd, _cols: u16, _rows: u16) { + // noop + } + fn spawn_terminal(&self, _file_to_open: Option<PathBuf>) -> (RawFd, Pid) { + unimplemented!() + } + fn read_from_tty_stdout(&self, _fd: RawFd, _buf: &mut [u8]) -> Result<usize, nix::Error> { + unimplemented!() + } + fn async_file_reader(&self, _fd: RawFd) -> Box<dyn AsyncReader> { + unimplemented!() + } + fn write_to_tty_stdin(&self, _fd: RawFd, _buf: &[u8]) -> Result<usize, nix::Error> { + unimplemented!() + } + fn tcdrain(&self, _fd: RawFd) -> Result<(), nix::Error> { + unimplemented!() + } + fn box_clone(&self) -> Box<dyn ServerOsApi> { + Box::new((*self).clone()) + } + fn kill(&self, _pid: Pid) -> Result<(), nix::Error> { + unimplemented!() + } + fn recv_from_client(&self) -> (ClientToServerMsg, ErrorContext) { + unimplemented!() + } + fn send_to_client(&self, _msg: ServerToClientMsg) { + unimplemented!() + } + fn add_client_sender(&self) { + unimplemented!() + } + fn send_to_temp_client(&self, _msg: ServerToClientMsg) { + unimplemented!() + } + fn remove_client_sender(&self) { + unimplemented!() + } + fn update_receiver(&mut self, _stream: LocalSocketStream) { + unimplemented!() + } + fn load_palette(&self) -> Palette { + unimplemented!() + } +} + +fn create_new_screen(position_and_size: PositionAndSize) -> Screen { + let mut bus: Bus<ScreenInstruction> = Bus::empty(); + let fake_os_input = FakeInputOutput {}; + bus.os_input = Some(Box::new(fake_os_input)); + let mut client_attributes = ClientAttributes::default(); + client_attributes.position_and_size = position_and_size; + let max_panes = None; + let mode_info = ModeInfo::default(); + let input_mode = InputMode::Normal; + let session_state = Arc::new(RwLock::new(SessionState::Attached)); + Screen::new( + bus, + &client_attributes, + max_panes, + mode_info, + input_mode, + session_state, + ) +} + +#[test] +fn open_new_tab() { + let position_and_size = PositionAndSize { + cols: 121, + rows: 20, + x: 0, + y: 0, + ..Default::default() + }; + let mut screen = create_new_screen(position_and_size); + + screen.new_tab(1); + screen.new_tab(2); + + assert_eq!(screen.tabs.len(), 2, "Screen now has two tabs"); + assert_eq!( + screen.get_active_tab().unwrap().position, + 1, + "Active tab switched to new tab" + ); +} + +#[test] +pub fn switch_to_prev_tab() { + let position_and_size = PositionAndSize { + cols: 121, + rows: 20, + x: 0, + y: 0, + ..Default::default() + }; + let mut screen = create_new_screen(position_and_size); + + screen.new_tab(1); + screen.new_tab(2); + screen.switch_tab_prev(); + + assert_eq!( + screen.get_active_tab().unwrap().position, + 0, + "Active tab switched to previous tab" + ); +} + +#[test] +pub fn switch_to_next_tab() { + let position_and_size = PositionAndSize { + cols: 121, + rows: 20, + x: 0, + y: 0, + ..Default::default() + }; + let mut screen = create_new_screen(position_and_size); + + screen.new_tab(1); + screen.new_tab(2); + screen.switch_tab_prev(); + screen.switch_tab_next(); + + assert_eq!( + screen.get_active_tab().unwrap().position, + 1, + "Active tab switched to next tab" + ); +} + +#[test] +pub fn close_tab() { + let position_and_size = PositionAndSize { + cols: 121, + rows: 20, + x: 0, + y: 0, + ..Default::default() + }; + let mut screen = create_new_screen(position_and_size); + + screen.new_tab(1); + screen.new_tab(2); + screen.close_tab(); + + assert_eq!(screen.tabs.len(), 1, "Only one tab left"); + assert_eq!( + screen.get_active_tab().unwrap().position, + 0, + "Active tab switched to previous tab" + ); +} + +#[test] +pub fn close_the_middle_tab() { + let position_and_size = PositionAndSize { + cols: 121, + rows: 20, + x: 0, + y: 0, + ..Default::default() + }; + let mut screen = create_new_screen(position_and_size); + + screen.new_tab(1); + screen.new_tab(2); + screen.new_tab(3); + screen.switch_tab_prev(); + screen.close_tab(); + + assert_eq!(screen.tabs.len(), 2, "Two tabs left"); + assert_eq!( + screen.get_active_tab().unwrap().position, + 0, + "Active tab switched to previous tab" + ); +} + +#[test] +fn move_focus_left_at_left_screen_edge_changes_tab() { + let position_and_size = PositionAndSize { + cols: 121, + rows: 20, + x: 0, + y: 0, + ..Default::default() + }; + let mut screen = create_new_screen(position_and_size); + + screen.new_tab(1); + screen.new_tab(2); + screen.new_tab(3); + screen.switch_tab_prev(); + screen.move_focus_left_or_previous_tab(); + + assert_eq!( + screen.get_active_tab().unwrap().position, + 0, + "Active tab switched to previous" + ); +} + +#[test] +fn move_focus_right_at_right_screen_edge_changes_tab() { + let position_and_size = PositionAndSize { + cols: 121, + rows: 20, + x: 0, + y: 0, + ..Default::default() + }; + let mut screen = create_new_screen(position_and_size); + + screen.new_tab(1); + screen.new_tab(2); + screen.new_tab(3); + screen.switch_tab_prev(); + screen.move_focus_right_or_next_tab(); + + assert_eq!( + screen.get_active_tab().unwrap().position, + 2, + "Active tab switched to next" + ); +} diff --git a/zellij-server/src/unit/tab_tests.rs b/zellij-server/src/unit/tab_tests.rs new file mode 100644 index 000000000..87c3be718 --- /dev/null +++ b/zellij-server/src/unit/tab_tests.rs @@ -0,0 +1,11840 @@ +use super::Tab; +use crate::zellij_tile::data::{InputMode, ModeInfo, Palette}; +use crate::{ + os_input_output::{AsyncReader, Pid, ServerOsApi}, + panes::PaneId, + thread_bus::ThreadSenders, + SessionState, +}; +use std::sync::{Arc, RwLock}; +use zellij_utils::pane_size::PositionAndSize; + +use std::os::unix::io::RawFd; +use std::path::PathBuf; + +use zellij_utils::nix; + +use zellij_utils::{ + errors::ErrorContext, + interprocess::local_socket::LocalSocketStream, + ipc::{ClientToServerMsg, ServerToClientMsg}, +}; + +struct FakeInputOutput {} + +impl ServerOsApi for FakeInputOutput { + fn set_terminal_size_using_fd(&self, _fd: RawFd, _cols: u16, _rows: u16) { + // noop + } + fn spawn_terminal(&self, _file_to_open: Option<PathBuf>) -> (RawFd, Pid) { + unimplemented!() + } + fn read_from_tty_stdout(&self, _fd: RawFd, _buf: &mut [u8]) -> Result<usize, nix::Error> { + unimplemented!() + } + fn async_file_reader(&self, _fd: RawFd) -> Box<dyn AsyncReader> { + unimplemented!() + } + fn write_to_tty_stdin(&self, _fd: RawFd, _buf: &[u8]) -> Result<usize, nix::Error> { + unimplemented!() + } + fn tcdrain(&self, _fd: RawFd) -> Result<(), nix::Error> { + unimplemented!() + } + fn box_clone(&self) -> Box<dyn ServerOsApi> { + unimplemented!() + } + fn kill(&self, _pid: Pid) -> Result<(), nix::Error> { + unimplemented!() + } + fn recv_from_client(&self) -> (ClientToServerMsg, ErrorContext) { + unimplemented!() + } + fn send_to_client(&self, _msg: ServerToClientMsg) { + unimplemented!() + } + fn add_client_sender(&self) { + unimplemented!() + } + fn send_to_temp_client(&self, _msg: ServerToClientMsg) { + unimplemented!() + } + fn remove_client_sender(&self) { + unimplemented!() + } + fn update_receiver(&mut self, _stream: LocalSocketStream) { + unimplemented!() + } + fn load_palette(&self) -> Palette { + unimplemented!() + } +} + +fn create_new_tab(position_and_size: PositionAndSize) -> Tab { + let index = 0; + let position = 0; + let name = String::new(); + let os_api = Box::new(FakeInputOutput {}); + let senders = ThreadSenders::default().silently_fail_on_send(); + let max_panes = None; + let first_pane_id = Some(PaneId::Terminal(1)); + let mode_info = ModeInfo::default(); + let input_mode = InputMode::Normal; + let colors = Palette::default(); + let session_state = Arc::new(RwLock::new(SessionState::Attached)); + Tab::new( + index, + position, + name, + &position_and_size, + os_api, + senders, + max_panes, + first_pane_id, + mode_info, + input_mode, + colors, + session_state, + ) +} + +#[test] +fn split_panes_vertically() { + let position_and_size = PositionAndSize { + cols: 121, + rows: 20, + x: 0, + y: 0, + ..Default::default() + }; + let mut tab = create_new_tab(position_and_size); + let new_pane_id = PaneId::Terminal(2); + tab.vertical_split(new_pane_id); + assert_eq!(tab.panes.len(), 2, "The tab has two panes"); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(1)) + .unwrap() + .position_and_size() + .x, + 0, + "first pane x position" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(1)) + .unwrap() + .position_and_size() + .y, + 0, + "first pane y position" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(1)) + .unwrap() + .position_and_size() + .cols, + 60, + "first pane column count" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(1)) + .unwrap() + .position_and_size() + .rows, + 20, + "first pane row count" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(2)) + .unwrap() + .position_and_size() + .x, + 61, + "second pane x position" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(2)) + .unwrap() + .position_and_size() + .y, + 0, + "second pane y position" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(2)) + .unwrap() + .position_and_size() + .cols, + 60, + "second pane column count" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(2)) + .unwrap() + .position_and_size() + .rows, + 20, + "second pane row count" + ); +} + +#[test] +fn split_panes_horizontally() { + let position_and_size = PositionAndSize { + cols: 121, + rows: 20, + x: 0, + y: 0, + ..Default::default() + }; + let mut tab = create_new_tab(position_and_size); + let new_pane_id = PaneId::Terminal(2); + tab.horizontal_split(new_pane_id); + assert_eq!(tab.panes.len(), 2, "The tab has two panes"); + + assert_eq!( + tab.panes + .get(&PaneId::Terminal(1)) + .unwrap() + .position_and_size() + .x, + 0, + "first pane x position" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(1)) + .unwrap() + .position_and_size() + .y, + 0, + "first pane y position" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(1)) + .unwrap() + .position_and_size() + .cols, + 121, + "first pane column count" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(1)) + .unwrap() + .position_and_size() + .rows, + 10, + "first pane row count" + ); + + assert_eq!( + tab.panes + .get(&PaneId::Terminal(2)) + .unwrap() + .position_and_size() + .x, + 0, + "second pane x position" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(2)) + .unwrap() + .position_and_size() + .y, + 11, + "second pane y position" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(2)) + .unwrap() + .position_and_size() + .cols, + 121, + "second pane column count" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(2)) + .unwrap() + .position_and_size() + .rows, + 9, + "second pane row count" + ); +} + +#[test] +fn split_largest_pane() { + let position_and_size = PositionAndSize { + cols: 121, + rows: 20, + x: 0, + y: 0, + ..Default::default() + }; + let mut tab = create_new_tab(position_and_size); + for i in 2..5 { + let new_pane_id = PaneId::Terminal(i); + tab.new_pane(new_pane_id); + } + assert_eq!(tab.panes.len(), 4, "The tab has four panes"); + + assert_eq!( + tab.panes + .get(&PaneId::Terminal(1)) + .unwrap() + .position_and_size() + .x, + 0, + "first pane x position" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(1)) + .unwrap() + .position_and_size() + .y, + 0, + "first pane y position" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(1)) + .unwrap() + .position_and_size() + .cols, + 60, + "first pane column count" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(1)) + .unwrap() + .position_and_size() + .rows, + 10, + "first pane row count" + ); + + assert_eq!( + tab.panes + .get(&PaneId::Terminal(2)) + .unwrap() + .position_and_size() + .x, + 61, + "second pane x position" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(2)) + .unwrap() + .position_and_size() + .y, + 0, + "second pane y position" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(2)) + .unwrap() + .position_and_size() + .cols, + 60, + "second pane column count" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(2)) + .unwrap() + .position_and_size() + .rows, + 10, + "second pane row count" + ); + + assert_eq!( + tab.panes + .get(&PaneId::Terminal(3)) + .unwrap() + .position_and_size() + .x, + 0, + "third pane x position" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(3)) + .unwrap() + .position_and_size() + .y, + 11, + "third pane y position" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(3)) + .unwrap() + .position_and_size() + .cols, + 60, + "third pane column count" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(3)) + .unwrap() + .position_and_size() + .rows, + 9, + "third pane row count" + ); + + assert_eq!( + tab.panes + .get(&PaneId::Terminal(4)) + .unwrap() + .position_and_size() + .x, + 61, + "fourth pane x position" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(4)) + .unwrap() + .position_and_size() + .y, + 11, + "fourth pane y position" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(4)) + .unwrap() + .position_and_size() + .cols, + 60, + "fourth pane column count" + ); + assert_eq!( + tab.panes + .get(&PaneId::Terminal(4)) + .unwrap() + .position_and_size() + .rows, + 9, + "fourth pane row count" + ); +} + +#[test] +pub fn cannot_split_panes_vertically_when_active_terminal_is_too_small() { + let position_and_size = PositionAndSize { + cols: 8, + rows: 20, + x: 0, + y: 0, + ..Default::default() + }; + let mut tab = create_new_tab(position_and_size); + tab.vertical_split(PaneId::Terminal(2)); + assert_eq!(tab.panes.len(), 1, "Tab still has only one pane"); +} + +#[test] +pub fn cannot_split_panes_vertically_when_active_pane_is_too_small() { + let position_and_size = PositionAndSize { + cols: 8, + rows: 20, + x: 0, + y: 0, + ..Default::default() + }; + let mut tab = create_new_tab(position_and_size); + tab.vertical_split(PaneId::Terminal(2)); + assert_eq!(tab.panes.len(), 1, "Tab still has only one pane"); +} + +#[test] +pub fn cannot_split_panes_horizontally_when_active_pane_is_too_small() { + let position_and_size = PositionAndSize { + cols: 121, + rows: 4, + x: 0, + y: 0, + ..Default::default() + }; + let mut tab = create_new_tab(position_and_size); + tab.horizontal_split(PaneId::Terminal(2)); + assert_eq!(tab.panes.len(), 1, "Tab still has only one pane"); +} + +#[test] +pub fn cannot_split_largest_pane_when_there_is_no_room() { + let position_and_size = PositionAndSize { + cols: 8, + rows: 4, + x: 0, + y: 0, + ..Default::default() + }; + let mut tab = create_new_tab(position_and_size); + tab.new_pane(PaneId::Terminal(2)); + assert_eq!(tab.panes.len(), 1, "Tab still has only one pane"); +} + +#[test] +pub fn toggle_focused_pane_fullscreen() { + let position_and_size = PositionAndSize { + cols: 121, + rows: 20, + x: 0, + y: 0, + ..Default::default() + }; + let mut tab = create_new_tab(position_and_size); + for i in 2..5 { + let new_pane_id = PaneId::Terminal(i); + tab.new_pane(new_pane_id); + } + tab.toggle_active_pane_fullscreen(); + assert_eq!( + tab.panes.get(&PaneId::Terminal(4)).unwrap().x(), + 0, + "Pane x is on screen edge" + ); + assert_eq!( + tab.panes.get(&PaneId::Terminal(4)).unwrap().y(), + 0, + "Pane y is on screen edge" + ); + assert_eq!( + tab.panes.get(&PaneId::Terminal(4)).unwrap().columns(), + 121, + "Pane cols match fullscreen cols" + ); + assert_eq!( + tab.panes.get(&PaneId::Terminal(4)).unwrap().rows(), + 20, + "Pane rows match fullscreen rows" + ); + tab.toggle_active_pane_fullscreen(); + assert_eq!( + tab.panes.get(&PaneId::Terminal(4)).unwrap().x(), + 61, + "Pane x is on screen edge" + ); + assert_eq!( + tab.panes.get(&PaneId::Terminal(4)).unwrap().y(), + 11, + "Pane y is on screen edge" + ); + assert_eq!( + tab.panes.get(&PaneId::Terminal(4)).unwrap().columns(), + 60, + "Pane cols match fullscreen cols" + ); + assert_eq!( + tab.panes.get(&PaneId::Terminal(4)).unwrap().rows(), + 9, + "Pane rows match fullscreen rows" + ); + // we don't test if all other panes are hidden because this logic is done in the render + // function and we already test that in the e2e tests +} + +#[test] +pub fn move_focus_is_disabled_in_fullscreen() { + let position_and_size = PositionAndSize { + cols: 121, + rows: 20, + x: 0, + y: 0, + ..Default::default() + }; + let mut tab = create_new_tab(position_and_size); + for i in 2..5 { + let new_pane_id = PaneId::Terminal(i); + tab.new_pane(new_pane_id); + } + tab.toggle_active_pane_fullscreen(); + tab.move_focus_left(); + assert_eq!( + tab.panes.get(&PaneId::Terminal(4)).unwrap().x(), + 0, + "Pane x is on screen edge" + ); + assert_eq!( + tab.panes.get(&PaneId::Terminal(4)).unwrap().y(), + 0, + "Pane y is on screen edge" + ); + assert_eq!( + tab.panes.get(&PaneId::Terminal(4)).unwrap().columns(), + 121, + "Pane cols match fullscreen cols" + ); + assert_eq!( + tab.panes.get(&PaneId::Terminal(4)).unwrap().rows(), + 20, + "Pane rows match fullscreen rows" + ); |