test: simplify tab integration tests (#1728)

* wip

* refactor existing tests

* rename methods
This commit is contained in:
Thomas Linford 2022-09-15 20:35:36 +02:00 committed by GitHub
parent 65d12c4b9b
commit 480086e3d4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -11,7 +11,9 @@ use crate::{
};
use std::convert::TryInto;
use std::path::PathBuf;
use zellij_utils::channels::Receiver;
use zellij_utils::envs::set_session_name;
use zellij_utils::errors::ErrorContext;
use zellij_utils::input::layout::LayoutTemplate;
use zellij_utils::ipc::IpcReceiverWithContext;
use zellij_utils::pane_size::{Size, SizeInPixels};
@ -104,6 +106,69 @@ impl ServerOsApi for FakeInputOutput {
}
}
struct MockPtyInstructionBus {
output: Arc<Mutex<Vec<String>>>,
pty_writer_sender: SenderWithContext<PtyWriteInstruction>,
pty_writer_receiver: Arc<Receiver<(PtyWriteInstruction, ErrorContext)>>,
handle: Option<std::thread::JoinHandle<()>>,
}
impl MockPtyInstructionBus {
fn new() -> Self {
let output = Arc::new(Mutex::new(vec![]));
let (pty_writer_sender, pty_writer_receiver): ChannelWithContext<PtyWriteInstruction> =
channels::unbounded();
let pty_writer_sender = SenderWithContext::new(pty_writer_sender);
let pty_writer_receiver = Arc::new(pty_writer_receiver);
Self {
output,
pty_writer_sender,
pty_writer_receiver,
handle: None,
}
}
fn start(&mut self) {
let output = self.output.clone();
let pty_writer_receiver = self.pty_writer_receiver.clone();
let handle = std::thread::Builder::new()
.name("pty_writer".to_string())
.spawn({
move || loop {
let (event, _err_ctx) = pty_writer_receiver
.recv()
.expect("failed to receive event on channel");
match event {
PtyWriteInstruction::Write(msg, _) => output
.lock()
.unwrap()
.push(String::from_utf8_lossy(&msg).to_string()),
PtyWriteInstruction::Exit => break,
}
}
})
.unwrap();
self.handle = Some(handle);
}
fn exit(&mut self) {
self.pty_writer_sender
.send(PtyWriteInstruction::Exit)
.unwrap();
let handle = self.handle.take().unwrap();
handle.join().unwrap();
}
fn pty_write_sender(&self) -> SenderWithContext<PtyWriteInstruction> {
self.pty_writer_sender.clone()
}
fn clone_output(&self) -> Vec<String> {
self.output.lock().unwrap().clone()
}
}
// TODO: move to shared thingy with other test file
fn create_new_tab(size: Size, default_mode: ModeInfo) -> Tab {
set_session_name("test".into());
@ -1793,32 +1858,14 @@ fn pane_in_sgr_button_event_tracking_mouse_mode() {
};
let client_id = 1;
let messages_to_pty_writer = Arc::new(Mutex::new(vec![]));
let (to_pty_writer, pty_writer_receiver): ChannelWithContext<PtyWriteInstruction> =
channels::unbounded();
let to_pty_writer = SenderWithContext::new(to_pty_writer);
let mut tab = create_new_tab_with_mock_pty_writer(size, ModeInfo::default(), to_pty_writer);
let mut pty_instruction_bus = MockPtyInstructionBus::new();
let mut tab = create_new_tab_with_mock_pty_writer(
size,
ModeInfo::default(),
pty_instruction_bus.pty_write_sender(),
);
pty_instruction_bus.start();
// TODO: note that this thread does not die when the test dies
// it only dies once all the test process exits... not a biggy if we have only a handful of
// these, but otherwise we might want to think of a better way to handle this
let _pty_writer_thread = std::thread::Builder::new()
.name("pty_writer".to_string())
.spawn({
// TODO: kill this thread
let messages_to_pty_writer = messages_to_pty_writer.clone();
move || loop {
let (event, _err_ctx) = pty_writer_receiver
.recv()
.expect("failed to receive event on channel");
if let PtyWriteInstruction::Write(msg, _) = event {
messages_to_pty_writer
.lock()
.unwrap()
.push(String::from_utf8_lossy(&msg).to_string());
}
}
});
let sgr_mouse_mode_any_button = String::from("\u{1b}[?1002;1006h"); // button event tracking (1002) with SGR encoding (1006)
tab.handle_pty_bytes(1, sgr_mouse_mode_any_button.as_bytes().to_vec());
tab.handle_left_click(&Position::new(5, 71), client_id);
@ -1832,9 +1879,11 @@ fn pane_in_sgr_button_event_tracking_mouse_mode() {
tab.handle_middle_mouse_release(&Position::new(7, 75), client_id);
tab.handle_scrollwheel_up(&Position::new(5, 71), 1, client_id);
tab.handle_scrollwheel_down(&Position::new(5, 71), 1, client_id);
std::thread::sleep(std::time::Duration::from_millis(100)); // give time for messages to arrive
pty_instruction_bus.exit();
assert_eq!(
*messages_to_pty_writer.lock().unwrap(),
pty_instruction_bus.clone_output(),
vec![
"\u{1b}[<0;71;5M".to_string(), // SGR left click
"\u{1b}[<32;72;9M".to_string(), // SGR left click (hold)
@ -1859,32 +1908,14 @@ fn pane_in_sgr_normal_event_tracking_mouse_mode() {
};
let client_id = 1;
let messages_to_pty_writer = Arc::new(Mutex::new(vec![]));
let (to_pty_writer, pty_writer_receiver): ChannelWithContext<PtyWriteInstruction> =
channels::unbounded();
let to_pty_writer = SenderWithContext::new(to_pty_writer);
let mut tab = create_new_tab_with_mock_pty_writer(size, ModeInfo::default(), to_pty_writer);
let mut pty_instruction_bus = MockPtyInstructionBus::new();
let mut tab = create_new_tab_with_mock_pty_writer(
size,
ModeInfo::default(),
pty_instruction_bus.pty_write_sender(),
);
pty_instruction_bus.start();
// TODO: note that this thread does not die when the test dies
// it only dies once all the test process exits... not a biggy if we have only a handful of
// these, but otherwise we might want to think of a better way to handle this
let _pty_writer_thread = std::thread::Builder::new()
.name("pty_writer".to_string())
.spawn({
// TODO: kill this thread
let messages_to_pty_writer = messages_to_pty_writer.clone();
move || loop {
let (event, _err_ctx) = pty_writer_receiver
.recv()
.expect("failed to receive event on channel");
if let PtyWriteInstruction::Write(msg, _) = event {
messages_to_pty_writer
.lock()
.unwrap()
.push(String::from_utf8_lossy(&msg).to_string());
}
}
});
let sgr_mouse_mode_any_button = String::from("\u{1b}[?1000;1006h"); // normal event tracking (1000) with sgr encoding (1006)
tab.handle_pty_bytes(1, sgr_mouse_mode_any_button.as_bytes().to_vec());
tab.handle_left_click(&Position::new(5, 71), client_id);
@ -1898,9 +1929,11 @@ fn pane_in_sgr_normal_event_tracking_mouse_mode() {
tab.handle_middle_mouse_release(&Position::new(7, 75), client_id);
tab.handle_scrollwheel_up(&Position::new(5, 71), 1, client_id);
tab.handle_scrollwheel_down(&Position::new(5, 71), 1, client_id);
std::thread::sleep(std::time::Duration::from_millis(100)); // give time for messages to arrive
pty_instruction_bus.exit();
assert_eq!(
*messages_to_pty_writer.lock().unwrap(),
pty_instruction_bus.clone_output(),
vec![
"\u{1b}[<0;71;5M".to_string(), // SGR left click
// no hold event here, as hold events are not reported in normal mode
@ -1925,32 +1958,14 @@ fn pane_in_utf8_button_event_tracking_mouse_mode() {
};
let client_id = 1;
let messages_to_pty_writer = Arc::new(Mutex::new(vec![]));
let (to_pty_writer, pty_writer_receiver): ChannelWithContext<PtyWriteInstruction> =
channels::unbounded();
let to_pty_writer = SenderWithContext::new(to_pty_writer);
let mut tab = create_new_tab_with_mock_pty_writer(size, ModeInfo::default(), to_pty_writer);
let mut pty_instruction_bus = MockPtyInstructionBus::new();
let mut tab = create_new_tab_with_mock_pty_writer(
size,
ModeInfo::default(),
pty_instruction_bus.pty_write_sender(),
);
pty_instruction_bus.start();
// TODO: note that this thread does not die when the test dies
// it only dies once all the test process exits... not a biggy if we have only a handful of
// these, but otherwise we might want to think of a better way to handle this
let _pty_writer_thread = std::thread::Builder::new()
.name("pty_writer".to_string())
.spawn({
// TODO: kill this thread
let messages_to_pty_writer = messages_to_pty_writer.clone();
move || loop {
let (event, _err_ctx) = pty_writer_receiver
.recv()
.expect("failed to receive event on channel");
if let PtyWriteInstruction::Write(msg, _) = event {
messages_to_pty_writer
.lock()
.unwrap()
.push(String::from_utf8_lossy(&msg).to_string());
}
}
});
let sgr_mouse_mode_any_button = String::from("\u{1b}[?1002;1005h"); // button event tracking (1002) with utf8 encoding (1005)
tab.handle_pty_bytes(1, sgr_mouse_mode_any_button.as_bytes().to_vec());
tab.handle_left_click(&Position::new(5, 71), client_id);
@ -1964,9 +1979,11 @@ fn pane_in_utf8_button_event_tracking_mouse_mode() {
tab.handle_middle_mouse_release(&Position::new(7, 75), client_id);
tab.handle_scrollwheel_up(&Position::new(5, 71), 1, client_id);
tab.handle_scrollwheel_down(&Position::new(5, 71), 1, client_id);
std::thread::sleep(std::time::Duration::from_millis(100)); // give time for messages to arrive
pty_instruction_bus.exit();
assert_eq!(
*messages_to_pty_writer.lock().unwrap(),
pty_instruction_bus.clone_output(),
vec![
"\u{1b}[M g%".to_string(), // utf8 left click
"\u{1b}[M@h)".to_string(), // utf8 left click (hold)
@ -1991,32 +2008,14 @@ fn pane_in_utf8_normal_event_tracking_mouse_mode() {
};
let client_id = 1;
let messages_to_pty_writer = Arc::new(Mutex::new(vec![]));
let (to_pty_writer, pty_writer_receiver): ChannelWithContext<PtyWriteInstruction> =
channels::unbounded();
let to_pty_writer = SenderWithContext::new(to_pty_writer);
let mut tab = create_new_tab_with_mock_pty_writer(size, ModeInfo::default(), to_pty_writer);
let mut pty_instruction_bus = MockPtyInstructionBus::new();
let mut tab = create_new_tab_with_mock_pty_writer(
size,
ModeInfo::default(),
pty_instruction_bus.pty_write_sender(),
);
pty_instruction_bus.start();
// TODO: note that this thread does not die when the test dies
// it only dies once all the test process exits... not a biggy if we have only a handful of
// these, but otherwise we might want to think of a better way to handle this
let _pty_writer_thread = std::thread::Builder::new()
.name("pty_writer".to_string())
.spawn({
// TODO: kill this thread
let messages_to_pty_writer = messages_to_pty_writer.clone();
move || loop {
let (event, _err_ctx) = pty_writer_receiver
.recv()
.expect("failed to receive event on channel");
if let PtyWriteInstruction::Write(msg, _) = event {
messages_to_pty_writer
.lock()
.unwrap()
.push(String::from_utf8_lossy(&msg).to_string());
}
}
});
let sgr_mouse_mode_any_button = String::from("\u{1b}[?1000;1005h"); // normal event tracking (1000) with sgr encoding (1006)
tab.handle_pty_bytes(1, sgr_mouse_mode_any_button.as_bytes().to_vec());
tab.handle_left_click(&Position::new(5, 71), client_id);
@ -2030,9 +2029,11 @@ fn pane_in_utf8_normal_event_tracking_mouse_mode() {
tab.handle_middle_mouse_release(&Position::new(7, 75), client_id);
tab.handle_scrollwheel_up(&Position::new(5, 71), 1, client_id);
tab.handle_scrollwheel_down(&Position::new(5, 71), 1, client_id);
std::thread::sleep(std::time::Duration::from_millis(100)); // give time for messages to arrive
pty_instruction_bus.exit();
assert_eq!(
*messages_to_pty_writer.lock().unwrap(),
pty_instruction_bus.clone_output(),
vec![
"\u{1b}[M g%".to_string(), // utf8 left click
// no hold event here, as hold events are not reported in normal mode
@ -2058,43 +2059,23 @@ fn pane_bracketed_paste_ignored_when_not_in_bracketed_paste_mode() {
};
let client_id: u16 = 1;
let messages_to_pty_writer = Arc::new(Mutex::new(vec![]));
let (to_pty_writer, pty_writer_receiver): ChannelWithContext<PtyWriteInstruction> =
channels::unbounded();
let to_pty_writer = SenderWithContext::new(to_pty_writer);
let mut tab =
create_new_tab_with_mock_pty_writer(size, ModeInfo::default(), to_pty_writer.clone());
let mut pty_instruction_bus = MockPtyInstructionBus::new();
let mut tab = create_new_tab_with_mock_pty_writer(
size,
ModeInfo::default(),
pty_instruction_bus.pty_write_sender(),
);
pty_instruction_bus.start();
let _pty_writer_thread = std::thread::Builder::new()
.name("pty_writer".to_string())
.spawn({
let messages_to_pty_writer = messages_to_pty_writer.clone();
move || loop {
let (event, _err_ctx) = pty_writer_receiver
.recv()
.expect("failed to receive event on channel");
match event {
PtyWriteInstruction::Write(msg, _) => messages_to_pty_writer
.lock()
.unwrap()
.push(String::from_utf8_lossy(&msg).to_string()),
PtyWriteInstruction::Exit => break,
}
}
});
let bracketed_paste_start = vec![27, 91, 50, 48, 48, 126]; // \u{1b}[200~
let bracketed_paste_end = vec![27, 91, 50, 48, 49, 126]; // \u{1b}[201
tab.write_to_active_terminal(bracketed_paste_start, client_id);
tab.write_to_active_terminal("test".as_bytes().to_vec(), client_id);
tab.write_to_active_terminal(bracketed_paste_end, client_id);
to_pty_writer.send(PtyWriteInstruction::Exit).unwrap();
pty_instruction_bus.exit();
std::thread::sleep(std::time::Duration::from_millis(100)); // give time for messages to arrive
assert_eq!(
*messages_to_pty_writer.lock().unwrap(),
vec!["", "test", ""]
);
assert_eq!(pty_instruction_bus.clone_output(), vec!["", "test", ""]);
}
#[test]
@ -2106,30 +2087,13 @@ fn pane_faux_scrolling_in_alternate_mode() {
let client_id: u16 = 1;
let lines_to_scroll = 3;
let messages_to_pty_writer = Arc::new(Mutex::new(vec![]));
let (to_pty_writer, pty_writer_receiver): ChannelWithContext<PtyWriteInstruction> =
channels::unbounded();
let to_pty_writer = SenderWithContext::new(to_pty_writer);
let mut tab =
create_new_tab_with_mock_pty_writer(size, ModeInfo::default(), to_pty_writer.clone());
let _pty_writer_thread = std::thread::Builder::new()
.name("pty_writer".to_string())
.spawn({
let messages_to_pty_writer = messages_to_pty_writer.clone();
move || loop {
let (event, _err_ctx) = pty_writer_receiver
.recv()
.expect("failed to receive event on channel");
match event {
PtyWriteInstruction::Write(msg, _) => messages_to_pty_writer
.lock()
.unwrap()
.push(String::from_utf8_lossy(&msg).to_string()),
PtyWriteInstruction::Exit => break,
}
}
});
let mut pty_instruction_bus = MockPtyInstructionBus::new();
let mut tab = create_new_tab_with_mock_pty_writer(
size,
ModeInfo::default(),
pty_instruction_bus.pty_write_sender(),
);
pty_instruction_bus.start();
let enable_alternate_screen = String::from("\u{1b}[?1049h"); // CSI ? 1049 h -> switch to the Alternate Screen Buffer
let set_application_mode = String::from("\u{1b}[?1h");
@ -2148,9 +2112,7 @@ fn pane_faux_scrolling_in_alternate_mode() {
tab.handle_scrollwheel_up(&Position::new(1, 1), lines_to_scroll, client_id);
tab.handle_scrollwheel_down(&Position::new(1, 1), lines_to_scroll, client_id);
to_pty_writer.send(PtyWriteInstruction::Exit).unwrap();
std::thread::sleep(std::time::Duration::from_millis(100)); // give time for messages to arrive
pty_instruction_bus.exit();
let mut expected: Vec<&str> = Vec::new();
expected.append(&mut vec!["\u{1b}[A"; lines_to_scroll]);
@ -2158,5 +2120,5 @@ fn pane_faux_scrolling_in_alternate_mode() {
expected.append(&mut vec!["\u{1b}OA"; lines_to_scroll]);
expected.append(&mut vec!["\u{1b}OB"; lines_to_scroll]);
assert_eq!(*messages_to_pty_writer.lock().unwrap(), expected);
assert_eq!(pty_instruction_bus.clone_output(), expected);
}