[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.
This commit is contained in:
parent
55739aa786
commit
00f7d06151
@ -76,6 +76,7 @@ futures = "0.3"
|
|||||||
futures-timer = "3.0"
|
futures-timer = "3.0"
|
||||||
async-std = "1.12"
|
async-std = "1.12"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
serial_test = "2.0.0"
|
||||||
|
|
||||||
#
|
#
|
||||||
# Examples
|
# Examples
|
||||||
|
@ -207,13 +207,18 @@ impl From<Handle> for ScreenBufferCursor {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use serial_test::serial;
|
||||||
use super::{
|
use super::{
|
||||||
move_down, move_left, move_right, move_to, move_to_column, move_to_next_line,
|
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,
|
move_to_previous_line, move_to_row, move_up, position, restore_position, save_position,
|
||||||
};
|
};
|
||||||
|
use crate::terminal::sys::temp_screen_buffer;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[serial]
|
||||||
fn test_move_to_winapi() {
|
fn test_move_to_winapi() {
|
||||||
|
let _test_screen = temp_screen_buffer().unwrap();
|
||||||
|
|
||||||
let (saved_x, saved_y) = position().unwrap();
|
let (saved_x, saved_y) = position().unwrap();
|
||||||
|
|
||||||
move_to(saved_x + 1, saved_y + 1).unwrap();
|
move_to(saved_x + 1, saved_y + 1).unwrap();
|
||||||
@ -224,14 +229,20 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[serial]
|
||||||
fn test_move_right_winapi() {
|
fn test_move_right_winapi() {
|
||||||
|
let _test_screen = temp_screen_buffer().unwrap();
|
||||||
|
|
||||||
let (saved_x, saved_y) = position().unwrap();
|
let (saved_x, saved_y) = position().unwrap();
|
||||||
move_right(1).unwrap();
|
move_right(1).unwrap();
|
||||||
assert_eq!(position().unwrap(), (saved_x + 1, saved_y));
|
assert_eq!(position().unwrap(), (saved_x + 1, saved_y));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[serial]
|
||||||
fn test_move_left_winapi() {
|
fn test_move_left_winapi() {
|
||||||
|
let _test_screen = temp_screen_buffer().unwrap();
|
||||||
|
|
||||||
move_to(2, 0).unwrap();
|
move_to(2, 0).unwrap();
|
||||||
|
|
||||||
move_left(2).unwrap();
|
move_left(2).unwrap();
|
||||||
@ -240,7 +251,10 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[serial]
|
||||||
fn test_move_up_winapi() {
|
fn test_move_up_winapi() {
|
||||||
|
let _test_screen = temp_screen_buffer().unwrap();
|
||||||
|
|
||||||
move_to(0, 2).unwrap();
|
move_to(0, 2).unwrap();
|
||||||
|
|
||||||
move_up(2).unwrap();
|
move_up(2).unwrap();
|
||||||
@ -249,7 +263,10 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[serial]
|
||||||
fn test_move_to_next_line_winapi() {
|
fn test_move_to_next_line_winapi() {
|
||||||
|
let _test_screen = temp_screen_buffer().unwrap();
|
||||||
|
|
||||||
move_to(0, 2).unwrap();
|
move_to(0, 2).unwrap();
|
||||||
|
|
||||||
move_to_next_line(2).unwrap();
|
move_to_next_line(2).unwrap();
|
||||||
@ -258,7 +275,10 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[serial]
|
||||||
fn test_move_to_previous_line_winapi() {
|
fn test_move_to_previous_line_winapi() {
|
||||||
|
let _test_screen = temp_screen_buffer().unwrap();
|
||||||
|
|
||||||
move_to(0, 2).unwrap();
|
move_to(0, 2).unwrap();
|
||||||
|
|
||||||
move_to_previous_line(2).unwrap();
|
move_to_previous_line(2).unwrap();
|
||||||
@ -267,7 +287,10 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[serial]
|
||||||
fn test_move_to_column_winapi() {
|
fn test_move_to_column_winapi() {
|
||||||
|
let _test_screen = temp_screen_buffer().unwrap();
|
||||||
|
|
||||||
move_to(0, 2).unwrap();
|
move_to(0, 2).unwrap();
|
||||||
|
|
||||||
move_to_column(12).unwrap();
|
move_to_column(12).unwrap();
|
||||||
@ -276,7 +299,10 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[serial]
|
||||||
fn test_move_to_row_winapi() {
|
fn test_move_to_row_winapi() {
|
||||||
|
let _test_screen = temp_screen_buffer().unwrap();
|
||||||
|
|
||||||
move_to(0, 2).unwrap();
|
move_to(0, 2).unwrap();
|
||||||
|
|
||||||
move_to_row(5).unwrap();
|
move_to_row(5).unwrap();
|
||||||
@ -285,7 +311,10 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[serial]
|
||||||
fn test_move_down_winapi() {
|
fn test_move_down_winapi() {
|
||||||
|
let _test_screen = temp_screen_buffer().unwrap();
|
||||||
|
|
||||||
move_to(0, 0).unwrap();
|
move_to(0, 0).unwrap();
|
||||||
|
|
||||||
move_down(2).unwrap();
|
move_down(2).unwrap();
|
||||||
@ -294,7 +323,10 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[serial]
|
||||||
fn test_save_restore_position_winapi() {
|
fn test_save_restore_position_winapi() {
|
||||||
|
let _test_screen = temp_screen_buffer().unwrap();
|
||||||
|
|
||||||
let (saved_x, saved_y) = position().unwrap();
|
let (saved_x, saved_y) = position().unwrap();
|
||||||
|
|
||||||
save_position().unwrap();
|
save_position().unwrap();
|
||||||
|
@ -380,6 +380,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
mod serde_tests {
|
mod serde_tests {
|
||||||
|
@ -15,6 +15,10 @@ pub(crate) use self::windows::{
|
|||||||
clear, disable_raw_mode, enable_raw_mode, window_size, is_raw_mode_enabled, scroll_down,
|
clear, disable_raw_mode, enable_raw_mode, window_size, is_raw_mode_enabled, scroll_down,
|
||||||
scroll_up, set_size, set_window_title, size,
|
scroll_up, set_size, set_window_title, size,
|
||||||
};
|
};
|
||||||
|
#[cfg(all(windows, test))]
|
||||||
|
pub(crate) use self::windows::{
|
||||||
|
temp_screen_buffer,
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
mod windows;
|
mod windows;
|
||||||
|
@ -351,21 +351,54 @@ fn clear_winapi(
|
|||||||
Ok(())
|
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<ScreenBuffer> {
|
||||||
|
let alternate_screen = ScreenBuffer::create()?;
|
||||||
|
alternate_screen.show().unwrap();
|
||||||
|
Ok(alternate_screen)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::{ffi::OsString, os::windows::ffi::OsStringExt};
|
use std::{ffi::OsString, os::windows::ffi::OsStringExt};
|
||||||
|
|
||||||
use crossterm_winapi::ScreenBuffer;
|
use crossterm_winapi::ScreenBuffer;
|
||||||
|
use serial_test::serial;
|
||||||
use winapi::um::wincon::GetConsoleTitleW;
|
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]
|
#[test]
|
||||||
fn test_resize_winapi() {
|
#[serial]
|
||||||
|
fn test_resize_winapi_20_21() {
|
||||||
|
let _test_screen = temp_screen_buffer().unwrap();
|
||||||
|
|
||||||
let (width, height) = size().unwrap();
|
let (width, height) = size().unwrap();
|
||||||
|
|
||||||
set_size(30, 30).unwrap();
|
// The values 20 and 21 are arbitrary and different from each other
|
||||||
assert_eq!((30, 30), size().unwrap());
|
// 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
|
// reset to previous size
|
||||||
set_size(width, height).unwrap();
|
set_size(width, height).unwrap();
|
||||||
@ -420,7 +453,10 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[serial]
|
||||||
fn test_set_title_winapi() {
|
fn test_set_title_winapi() {
|
||||||
|
let _test_screen = temp_screen_buffer().unwrap();
|
||||||
|
|
||||||
let test_title = "this is a crossterm test title";
|
let test_title = "this is a crossterm test title";
|
||||||
set_window_title(test_title).unwrap();
|
set_window_title(test_title).unwrap();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user