use super::plugin_thread_main; use crate::screen::ScreenInstruction; use crate::{channels::SenderWithContext, thread_bus::Bus, ServerInstruction}; use insta::assert_snapshot; use std::collections::BTreeMap; use std::path::PathBuf; use tempfile::tempdir; use wasmtime::Engine; use zellij_utils::data::{ BareKey, Event, InputMode, KeyWithModifier, PermissionStatus, PermissionType, PluginCapabilities, }; use zellij_utils::errors::ErrorContext; use zellij_utils::input::keybinds::Keybinds; use zellij_utils::input::layout::{ Layout, PluginAlias, PluginUserConfiguration, RunPlugin, RunPluginLocation, RunPluginOrAlias, }; use zellij_utils::input::permission::PermissionCache; use zellij_utils::input::plugins::PluginAliases; use zellij_utils::ipc::ClientAttributes; use zellij_utils::lazy_static::lazy_static; use zellij_utils::pane_size::Size; use crate::background_jobs::BackgroundJob; use crate::pty_writer::PtyWriteInstruction; use std::env::set_var; use std::sync::{Arc, Mutex}; use crate::{plugins::PluginInstruction, pty::PtyInstruction}; use zellij_utils::channels::{self, ChannelWithContext, Receiver}; macro_rules! log_actions_in_thread { ( $arc_mutex_log:expr, $exit_event:path, $receiver:expr, $exit_after_count:expr ) => { std::thread::Builder::new() .name("logger thread".to_string()) .spawn({ let log = $arc_mutex_log.clone(); let mut exit_event_count = 0; move || loop { let (event, _err_ctx) = $receiver .recv() .expect("failed to receive event on channel"); match event { $exit_event(..) => { exit_event_count += 1; log.lock().unwrap().push(event); if exit_event_count == $exit_after_count { break; } }, _ => { log.lock().unwrap().push(event); }, } } }) .unwrap() }; } macro_rules! log_actions_in_thread_struct { ( $arc_mutex_log:expr, $exit_event:path, $receiver:expr, $exit_after_count:expr ) => { std::thread::Builder::new() .name("logger thread".to_string()) .spawn({ let log = $arc_mutex_log.clone(); let mut exit_event_count = 0; move || loop { let (event, _err_ctx) = $receiver .recv() .expect("failed to receive event on channel"); match event { $exit_event { .. } => { exit_event_count += 1; log.lock().unwrap().push(event); if exit_event_count == $exit_after_count { break; } }, _ => { log.lock().unwrap().push(event); }, } } }) .unwrap() }; } macro_rules! grant_permissions_and_log_actions_in_thread { ( $arc_mutex_log:expr, $exit_event:path, $receiver:expr, $exit_after_count:expr, $permission_type:expr, $cache_path:expr, $plugin_thread_sender:expr, $client_id:expr ) => { std::thread::Builder::new() .name("fake_screen_thread".to_string()) .spawn({ let log = $arc_mutex_log.clone(); let mut exit_event_count = 0; let cache_path = $cache_path.clone(); let plugin_thread_sender = $plugin_thread_sender.clone(); move || loop { let (event, _err_ctx) = $receiver .recv() .expect("failed to receive event on channel"); match event { $exit_event(..) => { exit_event_count += 1; log.lock().unwrap().push(event); if exit_event_count == $exit_after_count { break; } }, ScreenInstruction::RequestPluginPermissions(_, plugin_permission) => { if plugin_permission.permissions.contains($permission_type) { let _ = plugin_thread_sender.send( PluginInstruction::PermissionRequestResult( 0, Some($client_id), plugin_permission.permissions, PermissionStatus::Granted, Some(cache_path.clone()), ), ); } else { let _ = plugin_thread_sender.send( PluginInstruction::PermissionRequestResult( 0, Some($client_id), plugin_permission.permissions, PermissionStatus::Denied, Some(cache_path.clone()), ), ); } }, _ => { log.lock().unwrap().push(event); }, } } }) .unwrap() }; } macro_rules! deny_permissions_and_log_actions_in_thread { ( $arc_mutex_log:expr, $exit_event:path, $receiver:expr, $exit_after_count:expr, $permission_type:expr, $cache_path:expr, $plugin_thread_sender:expr, $client_id:expr ) => { std::thread::Builder::new() .name("fake_screen_thread".to_string()) .spawn({ let log = $arc_mutex_log.clone(); let mut exit_event_count = 0; let cache_path = $cache_path.clone(); let plugin_thread_sender = $plugin_thread_sender.clone(); move || loop { let (event, _err_ctx) = $receiver .recv() .expect("failed to receive event on channel"); match event { $exit_event(..) => { exit_event_count += 1; log.lock().unwrap().push(event); if exit_event_count == $exit_after_count { break; } }, ScreenInstruction::RequestPluginPermissions(_, plugin_permission) => { let _ = plugin_thread_sender.send( PluginInstruction::PermissionRequestResult( 0, Some($client_id), plugin_permission.permissions, PermissionStatus::Denied, Some(cache_path.clone()), ), ); break; }, _ => { log.lock().unwrap().push(event); }, } } }) .unwrap() }; } macro_rules! grant_permissions_and_log_actions_in_thread_naked_variant { ( $arc_mutex_log:expr, $exit_event:path, $receiver:expr, $exit_after_count:expr, $permission_type:expr, $cache_path:expr, $plugin_thread_sender:expr, $client_id:expr ) => { std::thread::Builder::new() .name("fake_screen_thread".to_string()) .spawn({ let log = $arc_mutex_log.clone(); let mut exit_event_count = 0; let cache_path = $cache_path.clone(); let plugin_thread_sender = $plugin_thread_sender.clone(); move || loop { let (event, _err_ctx) = $receiver .recv() .expect("failed to receive event on channel"); match event { $exit_event => { exit_event_count += 1; log.lock().unwrap().push(event); if exit_event_count == $exit_after_count { break; } }, ScreenInstruction::RequestPluginPermissions(_, plugin_permission) => { if plugin_permission.permissions.contains($permission_type) { let _ = plugin_thread_sender.send( PluginInstruction::PermissionRequestResult( 0, Some($client_id), plugin_permission.permissions, PermissionStatus::Granted, Some(cache_path.clone()), ), ); } else { let _ = plugin_thread_sender.send( PluginInstruction::PermissionRequestResult( 0, Some($client_id), plugin_permission.permissions, PermissionStatus::Denied, Some(cache_path.clone()), ), ); } }, _ => { log.lock().unwrap().push(event); }, } } }) .unwrap() }; } macro_rules! grant_permissions_and_log_actions_in_thread_struct_variant { ( $arc_mutex_log:expr, $exit_event:path, $receiver:expr, $exit_after_count:expr, $permission_type:expr, $cache_path:expr, $plugin_thread_sender:expr, $client_id:expr ) => { std::thread::Builder::new() .name("fake_screen_thread".to_string()) .spawn({ let log = $arc_mutex_log.clone(); let mut exit_event_count = 0; let cache_path = $cache_path.clone(); let plugin_thread_sender = $plugin_thread_sender.clone(); move || loop { let (event, _err_ctx) = $receiver .recv() .expect("failed to receive event on channel"); match event { $exit_event { .. } => { exit_event_count += 1; log.lock().unwrap().push(event); if exit_event_count == $exit_after_count { break; } }, ScreenInstruction::RequestPluginPermissions(_, plugin_permission) => { if plugin_permission.permissions.contains($permission_type) { let _ = plugin_thread_sender.send( PluginInstruction::PermissionRequestResult( 0, Some($client_id), plugin_permission.permissions, PermissionStatus::Granted, Some(cache_path.clone()), ), ); } else { let _ = plugin_thread_sender.send( PluginInstruction::PermissionRequestResult( 0, Some($client_id), plugin_permission.permissions, PermissionStatus::Denied, Some(cache_path.clone()), ), ); } }, _ => { log.lock().unwrap().push(event); }, } } }) .unwrap() }; } fn create_plugin_thread( zellij_cwd: Option, ) -> ( SenderWithContext, Receiver<(ScreenInstruction, ErrorContext)>, Box, ) { let zellij_cwd = zellij_cwd.unwrap_or_else(|| PathBuf::from(".")); let initiating_client_id = 1; let (to_server, _server_receiver): ChannelWithContext = channels::bounded(50); let to_server = SenderWithContext::new(to_server); let (to_screen, screen_receiver): ChannelWithContext = channels::unbounded(); let to_screen = SenderWithContext::new(to_screen); let (to_plugin, plugin_receiver): ChannelWithContext = channels::unbounded(); let to_plugin = SenderWithContext::new(to_plugin); let (to_pty, _pty_receiver): ChannelWithContext = channels::unbounded(); let to_pty = SenderWithContext::new(to_pty); let (to_pty_writer, _pty_writer_receiver): ChannelWithContext = channels::unbounded(); let to_pty_writer = SenderWithContext::new(to_pty_writer); let (to_background_jobs, _background_jobs_receiver): ChannelWithContext = channels::unbounded(); let to_background_jobs = SenderWithContext::new(to_background_jobs); let plugin_bus = Bus::new( vec![plugin_receiver], Some(&to_screen), Some(&to_pty), Some(&to_plugin), Some(&to_server), Some(&to_pty_writer), Some(&to_background_jobs), None, ) .should_silently_fail(); let engine = Engine::new(wasmtime::Config::new().strategy(wasmtime::Strategy::Winch)).unwrap(); let data_dir = PathBuf::from(tempdir().unwrap().path()); let default_shell = PathBuf::from("."); let plugin_capabilities = PluginCapabilities::default(); let client_attributes = ClientAttributes::default(); let default_shell_action = None; // TODO: change me let mut plugin_aliases = PluginAliases::default(); plugin_aliases.aliases.insert( "fixture_plugin_for_tests".to_owned(), RunPlugin::from_url(&format!( "file:{}/../target/e2e-data/plugins/fixture-plugin-for-tests.wasm", std::env::var_os("CARGO_MANIFEST_DIR") .unwrap() .to_string_lossy() )) .unwrap(), ); let plugin_thread = std::thread::Builder::new() .name("plugin_thread".to_string()) .spawn(move || { set_var("ZELLIJ_SESSION_NAME", "zellij-test"); plugin_thread_main( plugin_bus, engine, data_dir, Box::new(Layout::default()), None, default_shell, zellij_cwd, plugin_capabilities, client_attributes, default_shell_action, Box::new(plugin_aliases), InputMode::Normal, Keybinds::default(), Default::default(), initiating_client_id, ) .expect("TEST") }) .unwrap(); let teardown = { let to_plugin = to_plugin.clone(); move || { let _ = to_pty.send(PtyInstruction::Exit); let _ = to_pty_writer.send(PtyWriteInstruction::Exit); let _ = to_screen.send(ScreenInstruction::Exit); let _ = to_server.send(ServerInstruction::KillSession); let _ = to_plugin.send(PluginInstruction::Exit); let _ = plugin_thread.join(); } }; (to_plugin, screen_receiver, Box::new(teardown)) } fn create_plugin_thread_with_server_receiver( zellij_cwd: Option, ) -> ( SenderWithContext, Receiver<(ServerInstruction, ErrorContext)>, Receiver<(ScreenInstruction, ErrorContext)>, Box, ) { let zellij_cwd = zellij_cwd.unwrap_or_else(|| PathBuf::from(".")); let (to_server, server_receiver): ChannelWithContext = channels::bounded(50); let to_server = SenderWithContext::new(to_server); let (to_screen, screen_receiver): ChannelWithContext = channels::unbounded(); let to_screen = SenderWithContext::new(to_screen); let (to_plugin, plugin_receiver): ChannelWithContext = channels::unbounded(); let to_plugin = SenderWithContext::new(to_plugin); let (to_pty, _pty_receiver): ChannelWithContext = channels::unbounded(); let to_pty = SenderWithContext::new(to_pty); let (to_pty_writer, _pty_writer_receiver): ChannelWithContext = channels::unbounded(); let to_pty_writer = SenderWithContext::new(to_pty_writer); let (to_background_jobs, _background_jobs_receiver): ChannelWithContext = channels::unbounded(); let to_background_jobs = SenderWithContext::new(to_background_jobs); let plugin_bus = Bus::new( vec![plugin_receiver], Some(&to_screen), Some(&to_pty), Some(&to_plugin), Some(&to_server), Some(&to_pty_writer), Some(&to_background_jobs), None, ) .should_silently_fail(); let engine = Engine::new(wasmtime::Config::new().strategy(wasmtime::Strategy::Winch)).unwrap(); let data_dir = PathBuf::from(tempdir().unwrap().path()); let default_shell = PathBuf::from("."); let plugin_capabilities = PluginCapabilities::default(); let client_attributes = ClientAttributes::default(); let default_shell_action = None; // TODO: change me let initiating_client_id = 1; let plugin_thread = std::thread::Builder::new() .name("plugin_thread".to_string()) .spawn(move || { set_var("ZELLIJ_SESSION_NAME", "zellij-test"); plugin_thread_main( plugin_bus, engine, data_dir, Box::new(Layout::default()), None, default_shell, zellij_cwd, plugin_capabilities, client_attributes, default_shell_action, Box::new(PluginAliases::default()), InputMode::Normal, Keybinds::default(), Default::default(), initiating_client_id, ) .expect("TEST"); }) .unwrap(); let teardown = { let to_plugin = to_plugin.clone(); move || { let _ = to_pty.send(PtyInstruction::Exit); let _ = to_pty_writer.send(PtyWriteInstruction::Exit); let _ = to_screen.send(ScreenInstruction::Exit); let _ = to_server.send(ServerInstruction::KillSession); let _ = to_plugin.send(PluginInstruction::Exit); let _ = plugin_thread.join(); } }; ( to_plugin, server_receiver, screen_receiver, Box::new(teardown), ) } fn create_plugin_thread_with_pty_receiver( zellij_cwd: Option, ) -> ( SenderWithContext, Receiver<(PtyInstruction, ErrorContext)>, Receiver<(ScreenInstruction, ErrorContext)>, Box, ) { let zellij_cwd = zellij_cwd.unwrap_or_else(|| PathBuf::from(".")); let (to_server, _server_receiver): ChannelWithContext = channels::bounded(50); let to_server = SenderWithContext::new(to_server); let (to_screen, screen_receiver): ChannelWithContext = channels::unbounded(); let to_screen = SenderWithContext::new(to_screen); let (to_plugin, plugin_receiver): ChannelWithContext = channels::unbounded(); let to_plugin = SenderWithContext::new(to_plugin); let (to_pty, pty_receiver): ChannelWithContext = channels::unbounded(); let to_pty = SenderWithContext::new(to_pty); let (to_pty_writer, _pty_writer_receiver): ChannelWithContext = channels::unbounded(); let to_pty_writer = SenderWithContext::new(to_pty_writer); let (to_background_jobs, _background_jobs_receiver): ChannelWithContext = channels::unbounded(); let to_background_jobs = SenderWithContext::new(to_background_jobs); let plugin_bus = Bus::new( vec![plugin_receiver], Some(&to_screen), Some(&to_pty), Some(&to_plugin), Some(&to_server), Some(&to_pty_writer), Some(&to_background_jobs), None, ) .should_silently_fail(); let engine = Engine::new(wasmtime::Config::new().strategy(wasmtime::Strategy::Winch)).unwrap(); let data_dir = PathBuf::from(tempdir().unwrap().path()); let default_shell = PathBuf::from("."); let plugin_capabilities = PluginCapabilities::default(); let client_attributes = ClientAttributes::default(); let default_shell_action = None; // TODO: change me let initiating_client_id = 1; let plugin_thread = std::thread::Builder::new() .name("plugin_thread".to_string()) .spawn(move || { set_var("ZELLIJ_SESSION_NAME", "zellij-test"); plugin_thread_main( plugin_bus, engine, data_dir, Box::new(Layout::default()), None, default_shell, zellij_cwd, plugin_capabilities, client_attributes, default_shell_action, Box::new(PluginAliases::default()), InputMode::Normal, Keybinds::default(), Default::default(), initiating_client_id, ) .expect("TEST") }) .unwrap(); let teardown = { let to_plugin = to_plugin.clone(); move || { let _ = to_pty.send(PtyInstruction::Exit); let _ = to_pty_writer.send(PtyWriteInstruction::Exit); let _ = to_screen.send(ScreenInstruction::Exit); let _ = to_server.send(ServerInstruction::KillSession); let _ = to_plugin.send(PluginInstruction::Exit); let _ = plugin_thread.join(); } }; (to_plugin, pty_receiver, screen_receiver, Box::new(teardown)) } fn create_plugin_thread_with_background_jobs_receiver( zellij_cwd: Option, ) -> ( SenderWithContext, Receiver<(BackgroundJob, ErrorContext)>, Receiver<(ScreenInstruction, ErrorContext)>, Box, ) { let zellij_cwd = zellij_cwd.unwrap_or_else(|| PathBuf::from(".")); let (to_server, _server_receiver): ChannelWithContext = channels::bounded(50); let to_server = SenderWithContext::new(to_server); let (to_screen, screen_receiver): ChannelWithContext = channels::unbounded(); let to_screen = SenderWithContext::new(to_screen); let (to_plugin, plugin_receiver): ChannelWithContext = channels::unbounded(); let to_plugin = SenderWithContext::new(to_plugin); let (to_pty, _pty_receiver): ChannelWithContext = channels::unbounded(); let to_pty = SenderWithContext::new(to_pty); let (to_pty_writer, _pty_writer_receiver): ChannelWithContext = channels::unbounded(); let to_pty_writer = SenderWithContext::new(to_pty_writer); let (to_background_jobs, background_jobs_receiver): ChannelWithContext = channels::unbounded(); let to_background_jobs = SenderWithContext::new(to_background_jobs); let plugin_bus = Bus::new( vec![plugin_receiver], Some(&to_screen), Some(&to_pty), Some(&to_plugin), Some(&to_server), Some(&to_pty_writer), Some(&to_background_jobs), None, ) .should_silently_fail(); let engine = Engine::new(wasmtime::Config::new().strategy(wasmtime::Strategy::Winch)).unwrap(); let data_dir = PathBuf::from(tempdir().unwrap().path()); let default_shell = PathBuf::from("."); let plugin_capabilities = PluginCapabilities::default(); let client_attributes = ClientAttributes::default(); let default_shell_action = None; // TODO: change me let initiating_client_id = 1; let plugin_thread = std::thread::Builder::new() .name("plugin_thread".to_string()) .spawn(move || { set_var("ZELLIJ_SESSION_NAME", "zellij-test"); plugin_thread_main( plugin_bus, engine, data_dir, Box::new(Layout::default()), None, default_shell, zellij_cwd, plugin_capabilities, client_attributes, default_shell_action, Box::new(PluginAliases::default()), InputMode::Normal, Keybinds::default(), Default::default(), initiating_client_id, ) .expect("TEST") }) .unwrap(); let teardown = { let to_plugin = to_plugin.clone(); move || { let _ = to_pty.send(PtyInstruction::Exit); let _ = to_pty_writer.send(PtyWriteInstruction::Exit); let _ = to_screen.send(ScreenInstruction::Exit); let _ = to_server.send(ServerInstruction::KillSession); let _ = to_plugin.send(PluginInstruction::Exit); let _ = to_background_jobs.send(BackgroundJob::Exit); let _ = plugin_thread.join(); } }; ( to_plugin, background_jobs_receiver, screen_receiver, Box::new(teardown), ) } lazy_static! { static ref PLUGIN_FIXTURE: String = format!( // to populate this file, make sure to run the build-e2e CI job // (or compile the fixture plugin and copy the resulting .wasm blob to the below location) "{}/../target/e2e-data/plugins/fixture-plugin-for-tests.wasm", std::env::var_os("CARGO_MANIFEST_DIR") .unwrap() .to_string_lossy() ); } #[test] #[ignore] pub fn load_new_plugin_from_hd() { // here we load our fixture plugin into the plugin thread, and then send it an update message // expecting tha thte plugin will log the received event and render it later after the update // message (this is what the fixture plugin does) // we then listen on our mock screen receiver to make sure we got a PluginBytes instruction // that contains said render, and assert against it let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(None); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::PluginBytes, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::InputReceived, )])); // will be cached and sent to the plugin once it's loaded screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let plugin_bytes_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::PluginBytes(plugin_render_assets) = i { for plugin_render_asset in plugin_render_assets { let plugin_id = plugin_render_asset.plugin_id; let client_id = plugin_render_asset.client_id; let plugin_bytes = plugin_render_asset.bytes.clone(); let plugin_bytes = String::from_utf8_lossy(plugin_bytes.as_slice()).to_string(); if plugin_bytes.contains("InputReceived") { return Some((plugin_id, client_id, plugin_bytes)); } } } None }); assert_snapshot!(format!("{:#?}", plugin_bytes_event)); } #[test] #[ignore] pub fn load_new_plugin_with_plugin_alias() { // here we load our fixture plugin into the plugin thread, and then send it an update message // expecting tha thte plugin will log the received event and render it later after the update // message (this is what the fixture plugin does) // we then listen on our mock screen receiver to make sure we got a PluginBytes instruction // that contains said render, and assert against it let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(None); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::Alias(PluginAlias { name: "fixture_plugin_for_tests".to_owned(), configuration: Default::default(), run_plugin: None, ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::PluginBytes, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::InputReceived, )])); // will be cached and sent to the plugin once it's loaded screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let plugin_bytes_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::PluginBytes(plugin_render_assets) = i { for plugin_render_asset in plugin_render_assets { let plugin_id = plugin_render_asset.plugin_id; let client_id = plugin_render_asset.client_id; let plugin_bytes = plugin_render_asset.bytes.clone(); let plugin_bytes = String::from_utf8_lossy(plugin_bytes.as_slice()).to_string(); if plugin_bytes.contains("InputReceived") { return Some((plugin_id, client_id, plugin_bytes)); } } } None }); assert_snapshot!(format!("{:#?}", plugin_bytes_event)); } #[test] #[ignore] pub fn plugin_workers() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(None); let plugin_should_float = Some(false); let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::PluginBytes, screen_receiver, 2, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); // we send a SystemClipboardFailure to trigger the custom handler in the fixture plugin that // will send a message to the worker and in turn back to the plugin to be rendered, so we know // that this cycle is working std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::SystemClipboardFailure, )])); // will be cached and sent to the plugin once it's loaded screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let plugin_bytes_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::PluginBytes(plugin_render_assets) = i { for plugin_render_asset in plugin_render_assets { let plugin_id = plugin_render_asset.plugin_id; let client_id = plugin_render_asset.client_id; let plugin_bytes = plugin_render_asset.bytes.clone(); let plugin_bytes = String::from_utf8_lossy(plugin_bytes.as_slice()).to_string(); if plugin_bytes.contains("Payload from worker") { return Some((plugin_id, client_id, plugin_bytes)); } } } None }); assert_snapshot!(format!("{:#?}", plugin_bytes_event)); } #[test] #[ignore] pub fn plugin_workers_persist_state() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(None); let plugin_should_float = Some(false); let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::PluginBytes, screen_receiver, 4, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); // we send a SystemClipboardFailure to trigger the custom handler in the fixture plugin that // will send a message to the worker and in turn back to the plugin to be rendered, so we know // that this cycle is working // we do this a second time so that the worker will log the first message on its own state and // then send us the "received 2 messages" indication we check for below, letting us know it // managed to persist its own state and act upon it //std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::SystemClipboardFailure, )])); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::SystemClipboardFailure, )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let plugin_bytes_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::PluginBytes(plugin_render_assets) = i { for plugin_render_asset in plugin_render_assets { let plugin_bytes = plugin_render_asset.bytes.clone(); let plugin_id = plugin_render_asset.plugin_id; let client_id = plugin_render_asset.client_id; let plugin_bytes = String::from_utf8_lossy(plugin_bytes.as_slice()).to_string(); if plugin_bytes.contains("received 2 messages") { return Some((plugin_id, client_id, plugin_bytes)); } } } None }); assert_snapshot!(format!("{:#?}", plugin_bytes_event)); } #[test] #[ignore] pub fn can_subscribe_to_hd_events() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::PluginBytes, screen_receiver, 2, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); // extra long time because we only start the fs watcher on plugin load std::thread::sleep(std::time::Duration::from_millis(5000)); std::fs::OpenOptions::new() .create(true) .write(true) .open(PathBuf::from(temp_folder.path()).join("test1")) .unwrap(); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let plugin_bytes_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::PluginBytes(plugin_render_assets) = i { for plugin_render_asset in plugin_render_assets { let plugin_id = plugin_render_asset.plugin_id; let client_id = plugin_render_asset.client_id; let plugin_bytes = plugin_render_asset.bytes.clone(); let plugin_bytes = String::from_utf8_lossy(plugin_bytes.as_slice()).to_string(); if plugin_bytes.contains("FileSystemCreate") { return Some((plugin_id, client_id, plugin_bytes)); } } } None }); assert!(plugin_bytes_event.is_some()); } #[test] #[ignore] pub fn switch_to_mode_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::ChangeMode, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('a'))), // this triggers a SwitchToMode(Tab) command in the fixture // plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let switch_to_mode_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::ChangeMode(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", switch_to_mode_event)); } #[test] #[ignore] pub fn switch_to_mode_plugin_command_permission_denied() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = deny_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::ChangeMode, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('a'))), // this triggers a SwitchToMode(Tab) command in the fixture // plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let switch_to_mode_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::ChangeMode(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", switch_to_mode_event)); } #[test] #[ignore] pub fn new_tabs_with_layout_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::NewTab, screen_receiver, 2, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('b'))), // this triggers a new_tabs_with_layout command in the fixture // plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let first_new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::NewTab(..) = i { Some(i.clone()) } else { None } }) .clone(); let second_new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .rev() .find_map(|i| { if let ScreenInstruction::NewTab(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", first_new_tab_event)); assert_snapshot!(format!("{:#?}", second_new_tab_event)); } #[test] #[ignore] pub fn new_tab_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::NewTab, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('c'))), // this triggers a new_tab command in the fixture // plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::NewTab(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn go_to_next_tab_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::SwitchTabNext, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('d'))), // this triggers the event in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::SwitchTabNext(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn go_to_previous_tab_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::SwitchTabPrev, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('e'))), // this triggers the event in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::SwitchTabPrev(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn resize_focused_pane_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::Resize, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('f'))), // this triggers the event in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::Resize(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn resize_focused_pane_with_direction_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::Resize, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('g'))), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::Resize(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn focus_next_pane_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::FocusNextPane, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('h'))), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::FocusNextPane(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn focus_previous_pane_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::FocusPreviousPane, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('i'))), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::FocusPreviousPane(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn move_focus_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::MoveFocusLeft, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('j'))), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::MoveFocusLeft(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn move_focus_or_tab_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::MoveFocusLeftOrPreviousTab, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('k'))), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::MoveFocusLeftOrPreviousTab(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn edit_scrollback_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::EditScrollback, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('m'))), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::EditScrollback(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn write_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::WriteCharacter, screen_receiver, 1, &PermissionType::WriteToStdin, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('n'))), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::WriteCharacter(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn write_chars_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::WriteCharacter, screen_receiver, 1, &PermissionType::WriteToStdin, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('o'))), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::WriteCharacter(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn toggle_tab_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::ToggleTab, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('p'))), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::ToggleTab(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn move_pane_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::MovePane, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('q'))), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::MovePane(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn move_pane_with_direction_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::MovePaneLeft, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('r'))), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::MovePaneLeft(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn clear_screen_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::ClearScreen, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('s'))), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::ClearScreen(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn scroll_up_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::ScrollUp, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('t'))), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::ScrollUp(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn scroll_down_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::ScrollDown, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('u'))), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::ScrollDown(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn scroll_to_top_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::ScrollToTop, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('v'))), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::ScrollToTop(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn scroll_to_bottom_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::ScrollToBottom, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('w'))), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::ScrollToBottom(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn page_scroll_up_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::PageScrollUp, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('x'))), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::PageScrollUp(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn page_scroll_down_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::PageScrollDown, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('y'))), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::PageScrollDown(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn toggle_focus_fullscreen_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::ToggleActiveTerminalFullscreen, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('z'))), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::ToggleActiveTerminalFullscreen(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn toggle_pane_frames_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread_naked_variant!( received_screen_instructions, ScreenInstruction::TogglePaneFrames, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('1'))), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::TogglePaneFrames = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn toggle_pane_embed_or_eject_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::TogglePaneEmbedOrFloating, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('2'))), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::TogglePaneEmbedOrFloating(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn undo_rename_pane_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::UndoRenamePane, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('3'))), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::UndoRenamePane(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn close_focus_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::CloseFocusedPane, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('4'))), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::CloseFocusedPane(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn toggle_active_tab_sync_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::ToggleActiveSyncTab, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('5'))), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::ToggleActiveSyncTab(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn close_focused_tab_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::CloseTab, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('6'))), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::CloseTab(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn undo_rename_tab_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::UndoRenameTab, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('7'))), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::UndoRenameTab(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn previous_swap_layout_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::PreviousSwapLayout, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('a')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::PreviousSwapLayout(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn next_swap_layout_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::NextSwapLayout, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('b')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::NextSwapLayout(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn go_to_tab_name_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::GoToTabName, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('c')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::GoToTabName(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn focus_or_create_tab_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::GoToTabName, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('d')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::GoToTabName(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn go_to_tab() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::GoToTab, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('e')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::GoToTab(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn start_or_reload_plugin() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::StartOrReloadPluginPane, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('f')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::StartOrReloadPluginPane(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn quit_zellij_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, server_receiver, screen_receiver, teardown) = create_plugin_thread_with_server_receiver(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_server_instruction = Arc::new(Mutex::new(vec![])); let server_thread = log_actions_in_thread!( received_server_instruction, ServerInstruction::ClientExit, server_receiver, 1 ); let received_screen_instructions = Arc::new(Mutex::new(vec![])); let _screen_thread = grant_permissions_and_log_actions_in_thread_naked_variant!( received_screen_instructions, ScreenInstruction::Exit, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('8'))), // this triggers the enent in the fixture plugin )])); server_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_server_instruction .lock() .unwrap() .iter() .find_map(|i| { if let ServerInstruction::ClientExit(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn detach_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, server_receiver, screen_receiver, teardown) = create_plugin_thread_with_server_receiver(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_server_instruction = Arc::new(Mutex::new(vec![])); let server_thread = log_actions_in_thread!( received_server_instruction, ServerInstruction::DetachSession, server_receiver, 1 ); let received_screen_instructions = Arc::new(Mutex::new(vec![])); let _screen_thread = grant_permissions_and_log_actions_in_thread_naked_variant!( received_screen_instructions, ScreenInstruction::Exit, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('l'))), // this triggers the enent in the fixture plugin )])); server_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_server_instruction .lock() .unwrap() .iter() .find_map(|i| { if let ServerInstruction::DetachSession(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn open_file_floating_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, pty_receiver, screen_receiver, teardown) = create_plugin_thread_with_pty_receiver(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_pty_instructions = Arc::new(Mutex::new(vec![])); let pty_thread = log_actions_in_thread!( received_pty_instructions, PtyInstruction::SpawnTerminal, pty_receiver, 1 ); let received_screen_instructions = Arc::new(Mutex::new(vec![])); let _screen_thread = grant_permissions_and_log_actions_in_thread_naked_variant!( received_screen_instructions, ScreenInstruction::Exit, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('h')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); pty_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_pty_instructions .lock() .unwrap() .iter() .find_map(|i| { if let PtyInstruction::SpawnTerminal(..) = i { Some(i.clone()) } else { None } }) .clone(); // we do the replace below to avoid the randomness of the temporary folder in the snapshot // while still testing it assert_snapshot!( format!("{:#?}", new_tab_event).replace(&format!("{:?}", temp_folder.path()), "\"CWD\"") ); } #[test] #[ignore] pub fn open_file_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, pty_receiver, screen_receiver, teardown) = create_plugin_thread_with_pty_receiver(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_pty_instructions = Arc::new(Mutex::new(vec![])); let pty_thread = log_actions_in_thread!( received_pty_instructions, PtyInstruction::SpawnTerminal, pty_receiver, 1 ); let received_screen_instructions = Arc::new(Mutex::new(vec![])); let _screen_thread = grant_permissions_and_log_actions_in_thread_naked_variant!( received_screen_instructions, ScreenInstruction::Exit, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('g')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); pty_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_pty_instructions .lock() .unwrap() .iter() .find_map(|i| { if let PtyInstruction::SpawnTerminal(..) = i { Some(i.clone()) } else { None } }) .clone(); // we do the replace below to avoid the randomness of the temporary folder in the snapshot // while still testing it assert_snapshot!( format!("{:#?}", new_tab_event).replace(&format!("{:?}", temp_folder.path()), "\"CWD\"") ); } #[test] #[ignore] pub fn open_file_with_line_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, pty_receiver, screen_receiver, teardown) = create_plugin_thread_with_pty_receiver(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_pty_instructions = Arc::new(Mutex::new(vec![])); let pty_thread = log_actions_in_thread!( received_pty_instructions, PtyInstruction::SpawnTerminal, pty_receiver, 1 ); let received_screen_instructions = Arc::new(Mutex::new(vec![])); let _screen_thread = grant_permissions_and_log_actions_in_thread_naked_variant!( received_screen_instructions, ScreenInstruction::Exit, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('i')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); pty_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_pty_instructions .lock() .unwrap() .iter() .find_map(|i| { if let PtyInstruction::SpawnTerminal(..) = i { Some(i.clone()) } else { None } }) .clone(); // we do the replace below to avoid the randomness of the temporary folder in the snapshot // while still testing it assert_snapshot!( format!("{:#?}", new_tab_event).replace(&format!("{:?}", temp_folder.path()), "\"CWD\"") ); } #[test] #[ignore] pub fn open_file_with_line_floating_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, pty_receiver, screen_receiver, teardown) = create_plugin_thread_with_pty_receiver(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_pty_instructions = Arc::new(Mutex::new(vec![])); let pty_thread = log_actions_in_thread!( received_pty_instructions, PtyInstruction::SpawnTerminal, pty_receiver, 1 ); let received_screen_instructions = Arc::new(Mutex::new(vec![])); let _screen_thread = grant_permissions_and_log_actions_in_thread_naked_variant!( received_screen_instructions, ScreenInstruction::Exit, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('j')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); pty_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_pty_instructions .lock() .unwrap() .iter() .find_map(|i| { if let PtyInstruction::SpawnTerminal(..) = i { Some(i.clone()) } else { None } }) .clone(); // we do the replace below to avoid the randomness of the temporary folder in the snapshot // while still testing it assert_snapshot!( format!("{:#?}", new_tab_event).replace(&format!("{:?}", temp_folder.path()), "\"CWD\"") ); } #[test] #[ignore] pub fn open_terminal_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, pty_receiver, screen_receiver, teardown) = create_plugin_thread_with_pty_receiver(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_pty_instructions = Arc::new(Mutex::new(vec![])); let pty_thread = log_actions_in_thread!( received_pty_instructions, PtyInstruction::SpawnTerminal, pty_receiver, 1 ); let received_screen_instructions = Arc::new(Mutex::new(vec![])); let _screen_thread = grant_permissions_and_log_actions_in_thread_naked_variant!( received_screen_instructions, ScreenInstruction::Exit, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('k')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); pty_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_pty_instructions .lock() .unwrap() .iter() .find_map(|i| { if let PtyInstruction::SpawnTerminal(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn open_terminal_floating_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, pty_receiver, screen_receiver, teardown) = create_plugin_thread_with_pty_receiver(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_pty_instructions = Arc::new(Mutex::new(vec![])); let pty_thread = log_actions_in_thread!( received_pty_instructions, PtyInstruction::SpawnTerminal, pty_receiver, 1 ); let received_screen_instructions = Arc::new(Mutex::new(vec![])); let _screen_thread = grant_permissions_and_log_actions_in_thread_naked_variant!( received_screen_instructions, ScreenInstruction::Exit, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('l')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); pty_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_pty_instructions .lock() .unwrap() .iter() .find_map(|i| { if let PtyInstruction::SpawnTerminal(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn open_command_pane_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, pty_receiver, screen_receiver, teardown) = create_plugin_thread_with_pty_receiver(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_pty_instructions = Arc::new(Mutex::new(vec![])); let pty_thread = log_actions_in_thread!( received_pty_instructions, PtyInstruction::SpawnTerminal, pty_receiver, 1 ); let received_screen_instructions = Arc::new(Mutex::new(vec![])); let _screen_thread = grant_permissions_and_log_actions_in_thread_naked_variant!( received_screen_instructions, ScreenInstruction::Exit, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('m')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); pty_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_pty_instructions .lock() .unwrap() .iter() .find_map(|i| { if let PtyInstruction::SpawnTerminal(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn open_command_pane_floating_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, pty_receiver, screen_receiver, teardown) = create_plugin_thread_with_pty_receiver(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_pty_instructions = Arc::new(Mutex::new(vec![])); let pty_thread = log_actions_in_thread!( received_pty_instructions, PtyInstruction::SpawnTerminal, pty_receiver, 1 ); let received_screen_instructions = Arc::new(Mutex::new(vec![])); let _screen_thread = grant_permissions_and_log_actions_in_thread_naked_variant!( received_screen_instructions, ScreenInstruction::Exit, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('n')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); pty_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_pty_instructions .lock() .unwrap() .iter() .find_map(|i| { if let PtyInstruction::SpawnTerminal(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn switch_to_tab_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::GoToTab, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('o')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::GoToTab(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn hide_self_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::SuppressPane, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('p')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::SuppressPane(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn show_self_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::FocusPaneWithId, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('q')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::FocusPaneWithId(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn close_terminal_pane_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::ClosePane, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('r')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::ClosePane(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn close_plugin_pane_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::ClosePane, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('s')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::ClosePane(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn focus_terminal_pane_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::FocusPaneWithId, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('t')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::FocusPaneWithId(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn focus_plugin_pane_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::FocusPaneWithId, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('u')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::FocusPaneWithId(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn rename_terminal_pane_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::RenamePane, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('v')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::RenamePane(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn rename_plugin_pane_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::RenamePane, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('w')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::RenamePane(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn rename_tab_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::RenameTab, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('x')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::RenameTab(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn send_configuration_to_plugins() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let mut configuration = BTreeMap::new(); configuration.insert( "fake_config_key_1".to_owned(), "fake_config_value_1".to_owned(), ); configuration.insert( "fake_config_key_2".to_owned(), "fake_config_value_2".to_owned(), ); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: PluginUserConfiguration::new(configuration), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::GoToTabName, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('z')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); // here we make sure we received a rename_tab event with the title being the stringified // (Debug) configuration we sent to the fixture plugin to make sure it got there properly let go_to_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::GoToTabName(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", go_to_tab_event)); } #[test] #[ignore] pub fn request_plugin_permissions() { let temp_folder = tempdir().unwrap(); let plugin_host_folder = PathBuf::from(temp_folder.path()); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = log_actions_in_thread!( received_screen_instructions, ScreenInstruction::RequestPluginPermissions, screen_receiver, 1 ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('1')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::RequestPluginPermissions(_, plugin_permission) = i { Some(plugin_permission.permissions.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn granted_permission_request_result() { let temp_folder = tempdir().unwrap(); let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; // here we create a fake screen thread that will send a PermissionStatus::Granted // message for every permission request it gets let screen_thread = std::thread::Builder::new() .name("fake_screen_thread".to_string()) .spawn({ let cache_path = cache_path.clone(); let plugin_thread_sender = plugin_thread_sender.clone(); move || loop { let (event, _err_ctx) = screen_receiver .recv() .expect("failed to receive event on channel"); match event { ScreenInstruction::RequestPluginPermissions(_, plugin_permission) => { let _ = plugin_thread_sender.send(PluginInstruction::PermissionRequestResult( 0, Some(client_id), plugin_permission.permissions, PermissionStatus::Granted, Some(cache_path.clone()), )); break; }, ScreenInstruction::Exit => { break; }, _ => {}, } } }) .unwrap(); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin.clone(), tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('1')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); teardown(); let permission_cache = PermissionCache::from_path_or_default(Some(cache_path)); let mut permissions = permission_cache .get_permissions(PathBuf::from(&*PLUGIN_FIXTURE).display().to_string()) .clone(); let permissions = permissions.as_mut().map(|p| { let mut permissions = p.clone(); permissions.sort_unstable(); permissions }); assert_snapshot!(format!("{:#?}", permissions)); } #[test] #[ignore] pub fn denied_permission_request_result() { let temp_folder = tempdir().unwrap(); let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; // here we create a fake screen thread that will send a PermissionStatus::Granted // message for every permission request it gets let screen_thread = std::thread::Builder::new() .name("fake_screen_thread".to_string()) .spawn({ let cache_path = cache_path.clone(); let plugin_thread_sender = plugin_thread_sender.clone(); move || loop { let (event, _err_ctx) = screen_receiver .recv() .expect("failed to receive event on channel"); match event { ScreenInstruction::RequestPluginPermissions(_, plugin_permission) => { let _ = plugin_thread_sender.send(PluginInstruction::PermissionRequestResult( 0, Some(client_id), plugin_permission.permissions, PermissionStatus::Denied, Some(cache_path.clone()), )); break; }, ScreenInstruction::Exit => { break; }, _ => {}, } } }) .unwrap(); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin.clone(), tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('1')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); teardown(); let permission_cache = PermissionCache::from_path_or_default(Some(cache_path)); let permissions = permission_cache.get_permissions(PathBuf::from(&*PLUGIN_FIXTURE).display().to_string()); assert_snapshot!(format!("{:#?}", permissions)); } #[test] #[ignore] pub fn run_command_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, background_jobs_receiver, screen_receiver, teardown) = create_plugin_thread_with_background_jobs_receiver(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_background_jobs_instructions = Arc::new(Mutex::new(vec![])); let background_jobs_thread = log_actions_in_thread!( received_background_jobs_instructions, BackgroundJob::RunCommand, background_jobs_receiver, 1 ); let received_screen_instructions = Arc::new(Mutex::new(vec![])); let _screen_thread = grant_permissions_and_log_actions_in_thread_naked_variant!( received_screen_instructions, ScreenInstruction::Exit, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('2')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); background_jobs_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_background_job = received_background_jobs_instructions .lock() .unwrap() .iter() .find_map(|i| { if let BackgroundJob::RunCommand(..) = i { Some(i.clone()) } else { None } }) .clone(); assert!(format!("{:#?}", new_background_job).contains("user_value_1")); } #[test] #[ignore] pub fn run_command_with_env_vars_and_cwd_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, background_jobs_receiver, screen_receiver, teardown) = create_plugin_thread_with_background_jobs_receiver(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_background_jobs_instructions = Arc::new(Mutex::new(vec![])); let background_jobs_thread = log_actions_in_thread!( received_background_jobs_instructions, BackgroundJob::RunCommand, background_jobs_receiver, 1 ); let received_screen_instructions = Arc::new(Mutex::new(vec![])); let _screen_thread = grant_permissions_and_log_actions_in_thread_naked_variant!( received_screen_instructions, ScreenInstruction::Exit, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('3')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); background_jobs_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_background_jobs_instructions .lock() .unwrap() .iter() .find_map(|i| { if let BackgroundJob::RunCommand(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn web_request_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, background_jobs_receiver, screen_receiver, teardown) = create_plugin_thread_with_background_jobs_receiver(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_background_jobs_instructions = Arc::new(Mutex::new(vec![])); let background_jobs_thread = log_actions_in_thread!( received_background_jobs_instructions, BackgroundJob::WebRequest, background_jobs_receiver, 1 ); let received_screen_instructions = Arc::new(Mutex::new(vec![])); let _screen_thread = grant_permissions_and_log_actions_in_thread_naked_variant!( received_screen_instructions, ScreenInstruction::Exit, screen_receiver, 1, &PermissionType::WebAccess, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('4')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); background_jobs_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_background_jobs_instructions .lock() .unwrap() .iter() .find_map(|i| { if let BackgroundJob::WebRequest(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", new_tab_event)); } #[test] #[ignore] pub fn unblock_input_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::PluginBytes, screen_receiver, 1, &PermissionType::ReadCliPipes, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::CliPipe { pipe_id: "input_pipe_id".to_owned(), name: "message_name".to_owned(), payload: Some("message_payload".to_owned()), plugin: None, // broadcast args: None, configuration: None, floating: None, pane_id_to_replace: None, pane_title: None, cwd: None, skip_cache: false, cli_client_id: client_id, }); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let plugin_bytes_events = received_screen_instructions .lock() .unwrap() .iter() .rev() .find_map(|i| { if let ScreenInstruction::PluginBytes(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", plugin_bytes_events)); } #[test] #[ignore] pub fn block_input_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::PluginBytes, screen_receiver, 1, &PermissionType::ReadCliPipes, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); // extra long time because we only start the fs watcher on plugin load std::thread::sleep(std::time::Duration::from_millis(5000)); let _ = plugin_thread_sender.send(PluginInstruction::CliPipe { pipe_id: "input_pipe_id".to_owned(), name: "message_name_block".to_owned(), payload: Some("message_payload".to_owned()), plugin: None, // broadcast args: None, configuration: None, floating: None, pane_id_to_replace: None, pane_title: None, cwd: None, skip_cache: false, cli_client_id: client_id, }); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let plugin_bytes_events = received_screen_instructions .lock() .unwrap() .iter() .rev() .find_map(|i| { if let ScreenInstruction::PluginBytes(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", plugin_bytes_events)); } #[test] #[ignore] pub fn pipe_output_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, server_receiver, screen_receiver, teardown) = create_plugin_thread_with_server_receiver(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let _screen_thread = grant_permissions_and_log_actions_in_thread_naked_variant!( received_screen_instructions, ScreenInstruction::Exit, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let received_server_instruction = Arc::new(Mutex::new(vec![])); let server_thread = log_actions_in_thread!( received_server_instruction, ServerInstruction::CliPipeOutput, server_receiver, 1 ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::CliPipe { pipe_id: "input_pipe_id".to_owned(), name: "pipe_output".to_owned(), payload: Some("message_payload".to_owned()), plugin: None, // broadcast args: None, configuration: None, floating: None, pane_id_to_replace: None, pane_title: None, cwd: None, skip_cache: false, cli_client_id: client_id, }); std::thread::sleep(std::time::Duration::from_millis(500)); teardown(); server_thread.join().unwrap(); // this might take a while if the cache is cold let plugin_bytes_events = received_server_instruction .lock() .unwrap() .iter() .rev() .find_map(|i| { if let ServerInstruction::CliPipeOutput(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", plugin_bytes_events)); } #[test] #[ignore] pub fn pipe_message_to_plugin_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::PluginBytes, screen_receiver, 2, &PermissionType::ReadCliPipes, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::CliPipe { pipe_id: "input_pipe_id".to_owned(), name: "pipe_message_to_plugin".to_owned(), payload: Some("payload_sent_to_self".to_owned()), plugin: None, // broadcast args: None, configuration: None, floating: None, pane_id_to_replace: None, pane_title: None, cwd: None, skip_cache: false, cli_client_id: client_id, }); std::thread::sleep(std::time::Duration::from_millis(500)); teardown(); screen_thread.join().unwrap(); // this might take a while if the cache is cold let plugin_bytes_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::PluginBytes(plugin_render_assets) = i { for plugin_render_asset in plugin_render_assets { let plugin_id = plugin_render_asset.plugin_id; let client_id = plugin_render_asset.client_id; let plugin_bytes = plugin_render_asset.bytes.clone(); let plugin_bytes = String::from_utf8_lossy(plugin_bytes.as_slice()).to_string(); if plugin_bytes.contains("Payload from self:") { return Some((plugin_id, client_id, plugin_bytes)); } } } None }); assert_snapshot!(format!("{:#?}", plugin_bytes_event)); } #[test] #[ignore] pub fn switch_session_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, server_receiver, screen_receiver, teardown) = create_plugin_thread_with_server_receiver(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let _screen_thread = grant_permissions_and_log_actions_in_thread_naked_variant!( received_screen_instructions, ScreenInstruction::Exit, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let received_server_instruction = Arc::new(Mutex::new(vec![])); let server_thread = log_actions_in_thread!( received_server_instruction, ServerInstruction::SwitchSession, server_receiver, 1 ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('5')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); std::thread::sleep(std::time::Duration::from_millis(500)); teardown(); server_thread.join().unwrap(); // this might take a while if the cache is cold let switch_session_event = received_server_instruction .lock() .unwrap() .iter() .rev() .find_map(|i| { if let ServerInstruction::SwitchSession(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", switch_session_event)); } #[test] #[ignore] pub fn switch_session_with_layout_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, server_receiver, screen_receiver, teardown) = create_plugin_thread_with_server_receiver(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let _screen_thread = grant_permissions_and_log_actions_in_thread_naked_variant!( received_screen_instructions, ScreenInstruction::Exit, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let received_server_instruction = Arc::new(Mutex::new(vec![])); let server_thread = log_actions_in_thread!( received_server_instruction, ServerInstruction::SwitchSession, server_receiver, 1 ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('7')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); std::thread::sleep(std::time::Duration::from_millis(500)); teardown(); server_thread.join().unwrap(); // this might take a while if the cache is cold let switch_session_event = received_server_instruction .lock() .unwrap() .iter() .rev() .find_map(|i| { if let ServerInstruction::SwitchSession(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", switch_session_event)); } #[test] #[ignore] pub fn switch_session_with_layout_and_cwd_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, server_receiver, screen_receiver, teardown) = create_plugin_thread_with_server_receiver(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let _screen_thread = grant_permissions_and_log_actions_in_thread_naked_variant!( received_screen_instructions, ScreenInstruction::Exit, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let received_server_instruction = Arc::new(Mutex::new(vec![])); let server_thread = log_actions_in_thread!( received_server_instruction, ServerInstruction::SwitchSession, server_receiver, 1 ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('9')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); std::thread::sleep(std::time::Duration::from_millis(500)); teardown(); server_thread.join().unwrap(); // this might take a while if the cache is cold let switch_session_event = received_server_instruction .lock() .unwrap() .iter() .rev() .find_map(|i| { if let ServerInstruction::SwitchSession(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", switch_session_event)); } #[test] #[ignore] pub fn disconnect_other_clients_plugins_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, server_receiver, screen_receiver, teardown) = create_plugin_thread_with_server_receiver(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let _screen_thread = grant_permissions_and_log_actions_in_thread_naked_variant!( received_screen_instructions, ScreenInstruction::Exit, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let received_server_instruction = Arc::new(Mutex::new(vec![])); let server_thread = log_actions_in_thread!( received_server_instruction, ServerInstruction::DisconnectAllClientsExcept, server_receiver, 1 ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('6')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); std::thread::sleep(std::time::Duration::from_millis(500)); teardown(); server_thread.join().unwrap(); // this might take a while if the cache is cold let switch_session_event = received_server_instruction .lock() .unwrap() .iter() .rev() .find_map(|i| { if let ServerInstruction::DisconnectAllClientsExcept(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", switch_session_event)); } #[test] #[ignore] pub fn reconfigure_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, server_receiver, screen_receiver, teardown) = create_plugin_thread_with_server_receiver(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let _screen_thread = grant_permissions_and_log_actions_in_thread_naked_variant!( received_screen_instructions, ScreenInstruction::Exit, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let received_server_instruction = Arc::new(Mutex::new(vec![])); let server_thread = log_actions_in_thread_struct!( received_server_instruction, ServerInstruction::Reconfigure, server_receiver, 1 ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('0')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); std::thread::sleep(std::time::Duration::from_millis(500)); teardown(); server_thread.join().unwrap(); // this might take a while if the cache is cold let reconfigure_event = received_server_instruction .lock() .unwrap() .iter() .rev() .find_map(|i| { if let ServerInstruction::Reconfigure { .. } = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", reconfigure_event)); } #[test] #[ignore] pub fn run_plugin_in_specific_cwd() { // note that this test might sometimes fail when run alone without the rest of the suite due to // timing issues let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, server_receiver, screen_receiver, teardown) = create_plugin_thread_with_server_receiver(Some(plugin_host_folder.clone())); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let plugin_initial_cwd = plugin_host_folder.join("custom_plugin_cwd"); let _ = std::fs::create_dir_all(&plugin_initial_cwd); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), initial_cwd: Some(plugin_initial_cwd.clone()), }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let _screen_thread = grant_permissions_and_log_actions_in_thread_naked_variant!( received_screen_instructions, ScreenInstruction::Exit, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let received_server_instruction = Arc::new(Mutex::new(vec![])); let server_thread = log_actions_in_thread!( received_server_instruction, ServerInstruction::ClientExit, server_receiver, 1 ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('8')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin )])); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('8'))), // this sends this quit command so tha the test exits cleanly )])); teardown(); server_thread.join().unwrap(); // this might take a while if the cache is cold assert!( std::fs::read_dir(plugin_initial_cwd) .unwrap() .map(|d| d.unwrap().path().to_string_lossy().to_string()) .collect::>() .join(",") .contains("hi-from-plugin.txt"), "File written into plugin initial cwd" ); } #[test] #[ignore] pub fn hide_pane_with_id_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::SuppressPane, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('a')).with_alt_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let suppress_pane_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::SuppressPane(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", suppress_pane_event)); } #[test] #[ignore] pub fn show_pane_with_id_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::FocusPaneWithId, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('b')).with_alt_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let focus_pane_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::FocusPaneWithId(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", focus_pane_event)); } #[test] #[ignore] pub fn open_command_pane_background_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, pty_receiver, screen_receiver, teardown) = create_plugin_thread_with_pty_receiver(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_pty_instructions = Arc::new(Mutex::new(vec![])); let pty_thread = log_actions_in_thread!( received_pty_instructions, PtyInstruction::SpawnTerminal, pty_receiver, 1 ); let received_screen_instructions = Arc::new(Mutex::new(vec![])); let _screen_thread = grant_permissions_and_log_actions_in_thread_naked_variant!( received_screen_instructions, ScreenInstruction::Exit, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('c')).with_alt_modifier()), // this triggers the enent in the fixture plugin )])); pty_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let new_tab_event = received_pty_instructions .lock() .unwrap() .iter() .find_map(|i| { if let PtyInstruction::SpawnTerminal(..) = i { Some(i.clone()) } else { None } }) .clone(); // we do the replace below to avoid the randomness of the temporary folder in the snapshot // while still testing it assert_snapshot!( format!("{:#?}", new_tab_event).replace(&format!("{:?}", temp_folder.path()), "\"CWD\"") ); } #[test] #[ignore] pub fn rerun_command_pane_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::RerunCommandPane, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('d')).with_alt_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let rerun_command_pane_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::RerunCommandPane(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", rerun_command_pane_event)); } #[test] #[ignore] pub fn resize_pane_with_id_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::ResizePaneWithId, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('e')).with_alt_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let rerun_command_pane_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::ResizePaneWithId(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", rerun_command_pane_event)); } #[test] #[ignore] pub fn edit_scrollback_for_pane_with_id_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::EditScrollbackForPaneWithId, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('f')).with_alt_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let rerun_command_pane_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::EditScrollbackForPaneWithId(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", rerun_command_pane_event)); } #[test] #[ignore] pub fn write_to_pane_id_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::WriteToPaneId, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('g')).with_alt_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let rerun_command_pane_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::WriteToPaneId(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", rerun_command_pane_event)); } #[test] #[ignore] pub fn write_chars_to_pane_id_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::WriteToPaneId, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('h')).with_alt_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let rerun_command_pane_event = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::WriteToPaneId(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", rerun_command_pane_event)); } #[test] #[ignore] pub fn move_pane_with_pane_id_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::MovePaneWithPaneId, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('i')).with_alt_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let screen_instruction = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::MovePaneWithPaneId(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", screen_instruction)); } #[test] #[ignore] pub fn move_pane_with_pane_id_in_direction_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::MovePaneWithPaneIdInDirection, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('j')).with_alt_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let screen_instruction = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::MovePaneWithPaneIdInDirection(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", screen_instruction)); } #[test] #[ignore] pub fn clear_screen_for_pane_id_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::ClearScreenForPaneId, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('k')).with_alt_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let screen_instruction = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::ClearScreenForPaneId(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", screen_instruction)); } #[test] #[ignore] pub fn scroll_up_in_pane_id_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::ScrollUpInPaneId, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('l')).with_alt_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let screen_instruction = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::ScrollUpInPaneId(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", screen_instruction)); } #[test] #[ignore] pub fn scroll_down_in_pane_id_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::ScrollDownInPaneId, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('m')).with_alt_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let screen_instruction = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::ScrollDownInPaneId(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", screen_instruction)); } #[test] #[ignore] pub fn scroll_to_top_in_pane_id_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::ScrollToTopInPaneId, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('n')).with_alt_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let screen_instruction = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::ScrollToTopInPaneId(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", screen_instruction)); } #[test] #[ignore] pub fn scroll_to_bottom_in_pane_id_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::ScrollToBottomInPaneId, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('o')).with_alt_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let screen_instruction = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::ScrollToBottomInPaneId(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", screen_instruction)); } #[test] #[ignore] pub fn page_scroll_up_in_pane_id_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::PageScrollUpInPaneId, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('p')).with_alt_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let screen_instruction = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::PageScrollUpInPaneId(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", screen_instruction)); } #[test] #[ignore] pub fn page_scroll_down_in_pane_id_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::PageScrollDownInPaneId, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('q')).with_alt_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let screen_instruction = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::PageScrollDownInPaneId(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", screen_instruction)); } #[test] #[ignore] pub fn toggle_pane_id_fullscreen_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::TogglePaneIdFullscreen, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('r')).with_alt_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let screen_instruction = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::TogglePaneIdFullscreen(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", screen_instruction)); } #[test] #[ignore] pub fn toggle_pane_embed_or_eject_for_pane_id_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::TogglePaneEmbedOrEjectForPaneId, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('s')).with_alt_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let screen_instruction = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::TogglePaneEmbedOrEjectForPaneId(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", screen_instruction)); } #[test] #[ignore] pub fn close_tab_with_index_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread!( received_screen_instructions, ScreenInstruction::CloseTabWithIndex, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('t')).with_alt_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let screen_instruction = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::CloseTabWithIndex(..) = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", screen_instruction)); } #[test] #[ignore] pub fn break_panes_to_new_tab_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread_struct_variant!( received_screen_instructions, ScreenInstruction::BreakPanesToNewTab, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('u')).with_alt_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let screen_instruction = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::BreakPanesToNewTab { .. } = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", screen_instruction)); } #[test] #[ignore] pub fn break_panes_to_tab_with_index_plugin_command() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory let plugin_host_folder = PathBuf::from(temp_folder.path()); let cache_path = plugin_host_folder.join("permissions_test.kdl"); let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(Some(plugin_host_folder)); let plugin_should_float = Some(false); let plugin_title = Some("test_plugin".to_owned()); let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: false, location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), configuration: Default::default(), ..Default::default() }); let tab_index = 1; let client_id = 1; let size = Size { cols: 121, rows: 20, }; let received_screen_instructions = Arc::new(Mutex::new(vec![])); let screen_thread = grant_permissions_and_log_actions_in_thread_struct_variant!( received_screen_instructions, ScreenInstruction::BreakPanesToTabWithIndex, screen_receiver, 1, &PermissionType::ChangeApplicationState, cache_path, plugin_thread_sender, client_id ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, false, plugin_title, run_plugin, tab_index, None, client_id, size, None, false, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( None, Some(client_id), Event::Key(KeyWithModifier::new(BareKey::Char('v')).with_alt_modifier()), // this triggers the enent in the fixture plugin )])); screen_thread.join().unwrap(); // this might take a while if the cache is cold teardown(); let screen_instruction = received_screen_instructions .lock() .unwrap() .iter() .find_map(|i| { if let ScreenInstruction::BreakPanesToTabWithIndex { .. } = i { Some(i.clone()) } else { None } }) .clone(); assert_snapshot!(format!("{:#?}", screen_instruction)); }