From 00f7d061518ab1fd76fe7b691cd42cac53ff4c87 Mon Sep 17 00:00:00 2001 From: Dave Date: Sat, 5 Aug 2023 06:36:42 -0700 Subject: [PATCH] [testing] serial testing perserving terminal (#791) This change does two things: - add the serial_test crate to run selected tests serial rather than in parallel. This is done because they use global state so running them in parallel leads to race conditions and flaky results (sometimes they pass, sometimes they fail). Running them serialy avoids this flakiness. - create a screen buffer within the test. This avoids changing the terminal (screen buffer) which is running the test. for example, a test that changes the terminal size to 20 x 20 can leave the developer running the test with a resized terminal. Creating a separate screen buffer for the test avoids this. --- Cargo.toml | 1 + src/cursor/sys/windows.rs | 32 +++++++++++++++++++++++++++ src/style/types/color.rs | 1 + src/terminal/sys.rs | 4 ++++ src/terminal/sys/windows.rs | 44 +++++++++++++++++++++++++++++++++---- 5 files changed, 78 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1e55be7..7263300 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -76,6 +76,7 @@ futures = "0.3" futures-timer = "3.0" async-std = "1.12" serde_json = "1.0" +serial_test = "2.0.0" # # Examples diff --git a/src/cursor/sys/windows.rs b/src/cursor/sys/windows.rs index 68eadd2..496b6ba 100644 --- a/src/cursor/sys/windows.rs +++ b/src/cursor/sys/windows.rs @@ -207,13 +207,18 @@ impl From for ScreenBufferCursor { #[cfg(test)] mod tests { + use serial_test::serial; use super::{ move_down, move_left, move_right, move_to, move_to_column, move_to_next_line, move_to_previous_line, move_to_row, move_up, position, restore_position, save_position, }; + use crate::terminal::sys::temp_screen_buffer; #[test] + #[serial] fn test_move_to_winapi() { + let _test_screen = temp_screen_buffer().unwrap(); + let (saved_x, saved_y) = position().unwrap(); move_to(saved_x + 1, saved_y + 1).unwrap(); @@ -224,14 +229,20 @@ mod tests { } #[test] + #[serial] fn test_move_right_winapi() { + let _test_screen = temp_screen_buffer().unwrap(); + let (saved_x, saved_y) = position().unwrap(); move_right(1).unwrap(); assert_eq!(position().unwrap(), (saved_x + 1, saved_y)); } #[test] + #[serial] fn test_move_left_winapi() { + let _test_screen = temp_screen_buffer().unwrap(); + move_to(2, 0).unwrap(); move_left(2).unwrap(); @@ -240,7 +251,10 @@ mod tests { } #[test] + #[serial] fn test_move_up_winapi() { + let _test_screen = temp_screen_buffer().unwrap(); + move_to(0, 2).unwrap(); move_up(2).unwrap(); @@ -249,7 +263,10 @@ mod tests { } #[test] + #[serial] fn test_move_to_next_line_winapi() { + let _test_screen = temp_screen_buffer().unwrap(); + move_to(0, 2).unwrap(); move_to_next_line(2).unwrap(); @@ -258,7 +275,10 @@ mod tests { } #[test] + #[serial] fn test_move_to_previous_line_winapi() { + let _test_screen = temp_screen_buffer().unwrap(); + move_to(0, 2).unwrap(); move_to_previous_line(2).unwrap(); @@ -267,7 +287,10 @@ mod tests { } #[test] + #[serial] fn test_move_to_column_winapi() { + let _test_screen = temp_screen_buffer().unwrap(); + move_to(0, 2).unwrap(); move_to_column(12).unwrap(); @@ -276,7 +299,10 @@ mod tests { } #[test] + #[serial] fn test_move_to_row_winapi() { + let _test_screen = temp_screen_buffer().unwrap(); + move_to(0, 2).unwrap(); move_to_row(5).unwrap(); @@ -285,7 +311,10 @@ mod tests { } #[test] + #[serial] fn test_move_down_winapi() { + let _test_screen = temp_screen_buffer().unwrap(); + move_to(0, 0).unwrap(); move_down(2).unwrap(); @@ -294,7 +323,10 @@ mod tests { } #[test] + #[serial] fn test_save_restore_position_winapi() { + let _test_screen = temp_screen_buffer().unwrap(); + let (saved_x, saved_y) = position().unwrap(); save_position().unwrap(); diff --git a/src/style/types/color.rs b/src/style/types/color.rs index 6c42c07..21dbce4 100644 --- a/src/style/types/color.rs +++ b/src/style/types/color.rs @@ -380,6 +380,7 @@ mod tests { } } + #[cfg(test)] #[cfg(feature = "serde")] mod serde_tests { diff --git a/src/terminal/sys.rs b/src/terminal/sys.rs index 47e80a5..206fee5 100644 --- a/src/terminal/sys.rs +++ b/src/terminal/sys.rs @@ -15,6 +15,10 @@ pub(crate) use self::windows::{ clear, disable_raw_mode, enable_raw_mode, window_size, is_raw_mode_enabled, scroll_down, scroll_up, set_size, set_window_title, size, }; +#[cfg(all(windows, test))] +pub(crate) use self::windows::{ + temp_screen_buffer, +}; #[cfg(windows)] mod windows; diff --git a/src/terminal/sys/windows.rs b/src/terminal/sys/windows.rs index 7ce9257..f02e2b3 100644 --- a/src/terminal/sys/windows.rs +++ b/src/terminal/sys/windows.rs @@ -351,21 +351,54 @@ fn clear_winapi( Ok(()) } +#[cfg(test)] +// Create a new screen buffer to avoid changing the terminal the test +// is running within. +pub fn temp_screen_buffer() -> std::io::Result { + let alternate_screen = ScreenBuffer::create()?; + alternate_screen.show().unwrap(); + Ok(alternate_screen) +} + #[cfg(test)] mod tests { use std::{ffi::OsString, os::windows::ffi::OsStringExt}; use crossterm_winapi::ScreenBuffer; + use serial_test::serial; use winapi::um::wincon::GetConsoleTitleW; - use super::{scroll_down, scroll_up, set_size, set_window_title, size}; + use super::{scroll_down, scroll_up, set_size, set_window_title, size, temp_screen_buffer}; #[test] - fn test_resize_winapi() { + #[serial] + fn test_resize_winapi_20_21() { + let _test_screen = temp_screen_buffer().unwrap(); + let (width, height) = size().unwrap(); - set_size(30, 30).unwrap(); - assert_eq!((30, 30), size().unwrap()); + // The values 20 and 21 are arbitrary and different from each other + // just to see they're not crossed over. + set_size(20, 21).unwrap(); + assert_eq!((20, 21), size().unwrap()); + + // reset to previous size + set_size(width, height).unwrap(); + assert_eq!((width, height), size().unwrap()); + } + + // This is similar to test_resize_winapi_20_21() above. This verifies that + // another test of similar functionality runs independently (that a testing + // race condition has been addressed). + #[test] + #[serial] + fn test_resize_winapi_30_31() { + let _test_screen = temp_screen_buffer().unwrap(); + + let (width, height) = size().unwrap(); + + set_size(30, 31).unwrap(); + assert_eq!((30, 31), size().unwrap()); // reset to previous size set_size(width, height).unwrap(); @@ -420,7 +453,10 @@ mod tests { } #[test] + #[serial] fn test_set_title_winapi() { + let _test_screen = temp_screen_buffer().unwrap(); + let test_title = "this is a crossterm test title"; set_window_title(test_title).unwrap();