Move termsize test into separate file

This commit is contained in:
Johannes Altmanninger 2024-03-23 17:22:52 +01:00
parent 99ffa4567a
commit 5c5ab4f179
3 changed files with 97 additions and 86 deletions

View File

@ -3,8 +3,6 @@ use crate::common::assert_sync;
use crate::env::{EnvMode, EnvVar, Environment};
use crate::flog::FLOG;
use crate::parser::Parser;
#[cfg(test)]
use crate::tests::prelude::*;
use crate::wchar::prelude::*;
use crate::wutil::fish_wcstoi;
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
@ -83,7 +81,8 @@ impl Termsize {
}
}
struct TermsizeData {
/// Exposed for testing.
pub(crate) struct TermsizeData {
// The last termsize returned by TIOCGWINSZ, or none if none.
last_from_tty: Option<Termsize>,
// The last termsize seen from the environment (COLUMNS/LINES), or none if none.
@ -94,7 +93,7 @@ struct TermsizeData {
}
impl TermsizeData {
const fn defaults() -> Self {
pub(crate) const fn defaults() -> Self {
Self {
last_from_tty: None,
last_from_env: None,
@ -126,14 +125,17 @@ impl TermsizeData {
/// SIGWINCH.
pub struct TermsizeContainer {
// Our lock-protected data.
data: Mutex<TermsizeData>,
/// Exposed for testing.
pub(crate) data: Mutex<TermsizeData>,
// An indication that we are currently in the process of setting COLUMNS and LINES, and so do
// not react to any changes.
setting_env_vars: AtomicBool,
/// Exposed for testing.
pub(crate) setting_env_vars: AtomicBool,
/// A function used for accessing the termsize from the tty. This is only exposed for testing.
tty_size_reader: fn() -> Option<Termsize>,
/// Exposed for testing.
pub(crate) tty_size_reader: fn() -> Option<Termsize>,
}
impl TermsizeContainer {
@ -203,7 +205,8 @@ impl TermsizeContainer {
}
/// Note that COLUMNS and/or LINES global variables changed.
fn handle_columns_lines_var_change(&self, vars: &dyn Environment) {
/// Exposed for testing.
pub(crate) fn handle_columns_lines_var_change(&self, vars: &dyn Environment) {
// Do nothing if we are the ones setting it.
if self.setting_env_vars.load(Ordering::Relaxed) {
return;
@ -270,81 +273,3 @@ pub fn termsize_update(parser: &Parser) -> Termsize {
pub fn termsize_invalidate_tty() {
TermsizeContainer::invalidate_tty();
}
#[test]
#[serial]
fn test_termsize() {
test_init();
let env_global = EnvMode::GLOBAL;
let parser = Parser::principal_parser();
let vars = parser.vars();
// Use a static variable so we can pretend we're the kernel exposing a terminal size.
static STUBBY_TERMSIZE: Mutex<Option<Termsize>> = Mutex::new(None);
fn stubby_termsize() -> Option<Termsize> {
*STUBBY_TERMSIZE.lock().unwrap()
}
let ts = TermsizeContainer {
data: Mutex::new(TermsizeData::defaults()),
setting_env_vars: AtomicBool::new(false),
tty_size_reader: stubby_termsize,
};
// Initially default value.
assert_eq!(ts.last(), Termsize::defaults());
// Haha we change the value, it doesn't even know.
*STUBBY_TERMSIZE.lock().unwrap() = Some(Termsize {
width: 42,
height: 84,
});
assert_eq!(ts.last(), Termsize::defaults());
// Ok let's tell it. But it still doesn't update right away.
TermsizeContainer::handle_winch();
assert_eq!(ts.last(), Termsize::defaults());
// Ok now we tell it to update.
ts.updating(parser);
assert_eq!(ts.last(), Termsize::new(42, 84));
assert_eq!(vars.get(L!("COLUMNS")).unwrap().as_string(), "42");
assert_eq!(vars.get(L!("LINES")).unwrap().as_string(), "84");
// Wow someone set COLUMNS and LINES to a weird value.
// Now the tty's termsize doesn't matter.
vars.set_one(L!("COLUMNS"), env_global, L!("75").to_owned());
vars.set_one(L!("LINES"), env_global, L!("150").to_owned());
ts.handle_columns_lines_var_change(parser.vars());
assert_eq!(ts.last(), Termsize::new(75, 150));
assert_eq!(vars.get(L!("COLUMNS")).unwrap().as_string(), "75");
assert_eq!(vars.get(L!("LINES")).unwrap().as_string(), "150");
vars.set_one(L!("COLUMNS"), env_global, L!("33").to_owned());
ts.handle_columns_lines_var_change(parser.vars());
assert_eq!(ts.last(), Termsize::new(33, 150));
// Oh it got SIGWINCH, now the tty matters again.
TermsizeContainer::handle_winch();
assert_eq!(ts.last(), Termsize::new(33, 150));
assert_eq!(ts.updating(parser), stubby_termsize().unwrap());
assert_eq!(vars.get(L!("COLUMNS")).unwrap().as_string(), "42");
assert_eq!(vars.get(L!("LINES")).unwrap().as_string(), "84");
// Test initialize().
vars.set_one(L!("COLUMNS"), env_global, L!("83").to_owned());
vars.set_one(L!("LINES"), env_global, L!("38").to_owned());
ts.initialize(vars);
assert_eq!(ts.last(), Termsize::new(83, 38));
// initialize() even beats the tty reader until a sigwinch.
let ts2 = TermsizeContainer {
data: Mutex::new(TermsizeData::defaults()),
setting_env_vars: AtomicBool::new(false),
tty_size_reader: stubby_termsize,
};
ts.initialize(parser.vars());
ts2.updating(parser);
assert_eq!(ts.last(), Termsize::new(83, 38));
TermsizeContainer::handle_winch();
assert_eq!(ts2.updating(parser), stubby_termsize().unwrap());
}

View File

@ -20,6 +20,7 @@ mod redirection;
mod screen;
mod std;
mod string_escape;
mod termsize;
mod threads;
mod tokenizer;
mod topic_monitor;

85
src/tests/termsize.rs Normal file
View File

@ -0,0 +1,85 @@
use crate::env::{EnvMode, Environment};
use crate::parser::Parser;
use crate::termsize::*;
use crate::tests::prelude::*;
use crate::wchar::prelude::*;
use std::sync::atomic::AtomicBool;
use std::sync::Mutex;
#[test]
#[serial]
fn test_termsize() {
test_init();
let env_global = EnvMode::GLOBAL;
let parser = Parser::principal_parser();
let vars = parser.vars();
// Use a static variable so we can pretend we're the kernel exposing a terminal size.
static STUBBY_TERMSIZE: Mutex<Option<Termsize>> = Mutex::new(None);
fn stubby_termsize() -> Option<Termsize> {
*STUBBY_TERMSIZE.lock().unwrap()
}
let ts = TermsizeContainer {
data: Mutex::new(TermsizeData::defaults()),
setting_env_vars: AtomicBool::new(false),
tty_size_reader: stubby_termsize,
};
// Initially default value.
assert_eq!(ts.last(), Termsize::defaults());
// Haha we change the value, it doesn't even know.
*STUBBY_TERMSIZE.lock().unwrap() = Some(Termsize {
width: 42,
height: 84,
});
assert_eq!(ts.last(), Termsize::defaults());
// Ok let's tell it. But it still doesn't update right away.
TermsizeContainer::handle_winch();
assert_eq!(ts.last(), Termsize::defaults());
// Ok now we tell it to update.
ts.updating(parser);
assert_eq!(ts.last(), Termsize::new(42, 84));
assert_eq!(vars.get(L!("COLUMNS")).unwrap().as_string(), "42");
assert_eq!(vars.get(L!("LINES")).unwrap().as_string(), "84");
// Wow someone set COLUMNS and LINES to a weird value.
// Now the tty's termsize doesn't matter.
vars.set_one(L!("COLUMNS"), env_global, L!("75").to_owned());
vars.set_one(L!("LINES"), env_global, L!("150").to_owned());
ts.handle_columns_lines_var_change(parser.vars());
assert_eq!(ts.last(), Termsize::new(75, 150));
assert_eq!(vars.get(L!("COLUMNS")).unwrap().as_string(), "75");
assert_eq!(vars.get(L!("LINES")).unwrap().as_string(), "150");
vars.set_one(L!("COLUMNS"), env_global, L!("33").to_owned());
ts.handle_columns_lines_var_change(parser.vars());
assert_eq!(ts.last(), Termsize::new(33, 150));
// Oh it got SIGWINCH, now the tty matters again.
TermsizeContainer::handle_winch();
assert_eq!(ts.last(), Termsize::new(33, 150));
assert_eq!(ts.updating(parser), stubby_termsize().unwrap());
assert_eq!(vars.get(L!("COLUMNS")).unwrap().as_string(), "42");
assert_eq!(vars.get(L!("LINES")).unwrap().as_string(), "84");
// Test initialize().
vars.set_one(L!("COLUMNS"), env_global, L!("83").to_owned());
vars.set_one(L!("LINES"), env_global, L!("38").to_owned());
ts.initialize(vars);
assert_eq!(ts.last(), Termsize::new(83, 38));
// initialize() even beats the tty reader until a sigwinch.
let ts2 = TermsizeContainer {
data: Mutex::new(TermsizeData::defaults()),
setting_env_vars: AtomicBool::new(false),
tty_size_reader: stubby_termsize,
};
ts.initialize(parser.vars());
ts2.updating(parser);
assert_eq!(ts.last(), Termsize::new(83, 38));
TermsizeContainer::handle_winch();
assert_eq!(ts2.updating(parser), stubby_termsize().unwrap());
}