mirror of
https://github.com/wez/wezterm.git
synced 2024-12-23 13:21:38 +03:00
start building out unit tests
This commit is contained in:
parent
0eb4dd44b3
commit
a55395d7c9
@ -24,7 +24,7 @@ pub enum AnsiColor {
|
||||
White,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
#[derive(Debug, Clone, Copy, Default, Eq, PartialEq)]
|
||||
pub struct RgbColor {
|
||||
pub red: u8,
|
||||
pub green: u8,
|
||||
@ -33,7 +33,7 @@ pub struct RgbColor {
|
||||
|
||||
impl RgbColor {}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||
pub enum ColorAttribute {
|
||||
Foreground,
|
||||
Background,
|
||||
|
@ -10,11 +10,19 @@ pub mod color;
|
||||
mod csi;
|
||||
use self::csi::*;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
||||
/// The response we given when queries for device attributes.
|
||||
/// This particular string says "we are a VT102".
|
||||
/// TODO: Consider VT220 extended response which can advertise
|
||||
/// certain feature sets.
|
||||
const DEVICE_IDENT: &[u8] = b"\x1b[?6c";
|
||||
pub const DEVICE_IDENT: &[u8] = b"\x1b[?6c";
|
||||
|
||||
pub const CSI: &[u8] = b"\x1b[";
|
||||
pub const OSC: &[u8] = b"\x1b]";
|
||||
pub const ST: &[u8] = b"\x1b\\";
|
||||
pub const DCS: &[u8] = b"\x1bP";
|
||||
|
||||
bitflags! {
|
||||
#[derive(Default)]
|
||||
@ -39,7 +47,7 @@ pub enum KeyCode {
|
||||
Shift,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||
pub struct CellAttributes {
|
||||
attributes: u16,
|
||||
pub foreground: color::ColorAttribute,
|
||||
@ -142,12 +150,18 @@ impl Default for CellAttributes {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||
pub struct Cell {
|
||||
chars: [u8; 8],
|
||||
pub attrs: CellAttributes,
|
||||
}
|
||||
|
||||
impl Default for Cell {
|
||||
fn default() -> Cell {
|
||||
Cell::from_char(' ', &CellAttributes::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl Cell {
|
||||
#[inline]
|
||||
pub fn chars(&self) -> &[u8] {
|
||||
@ -168,6 +182,12 @@ impl Cell {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<char> for Cell {
|
||||
fn from(c: char) -> Cell {
|
||||
Cell::from_char(c, &CellAttributes::default())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Line {
|
||||
pub cells: Vec<Cell>,
|
||||
@ -223,6 +243,12 @@ impl Line {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for Line {
|
||||
fn from(s: &str) -> Line {
|
||||
Line::from_text(s, &CellAttributes::default())
|
||||
}
|
||||
}
|
||||
|
||||
/// Holds the model of a screen. This can either be the primary screen
|
||||
/// which includes lines of scrollback text, or the alternate screen
|
||||
/// which holds no scrollback. The intent is to have one instance of
|
||||
@ -307,6 +333,12 @@ impl Screen {
|
||||
self.lines[line_idx].dirty = false;
|
||||
}
|
||||
|
||||
/// Returns a slice over the visible lines in the screen (no scrollback)
|
||||
fn visible_lines(&self) -> &[Line] {
|
||||
let line_idx = self.lines.len() - self.physical_rows;
|
||||
&self.lines[line_idx..line_idx + self.physical_rows]
|
||||
}
|
||||
|
||||
/// Set a cell. the x and y coordinates are relative to the visible screeen
|
||||
/// origin. 0,0 is the top left.
|
||||
pub fn set_cell(&mut self, x: usize, y: usize, c: char, attr: &CellAttributes) {
|
||||
@ -324,13 +356,13 @@ impl Screen {
|
||||
let width = cells.len();
|
||||
// if the line isn't wide enough, pad it out with the default attributes
|
||||
if x >= width {
|
||||
cells.resize(x + 1, Cell::from_char(' ', &CellAttributes::default()));
|
||||
cells.resize(x + 1, Cell::default());
|
||||
}
|
||||
cells[x] = Cell::from_char(c, attr);
|
||||
}
|
||||
|
||||
pub fn clear_line(&mut self, y: usize, cols: std::ops::Range<usize>) {
|
||||
let blank = Cell::from_char(' ', &CellAttributes::default());
|
||||
let blank = Cell::default();
|
||||
let line_idx = (self.lines.len() - self.physical_rows) + y;
|
||||
let line = self.line_mut(line_idx);
|
||||
let max_col = line.cells.len();
|
||||
@ -881,13 +913,23 @@ impl vte::Perform for TerminalState {
|
||||
}
|
||||
CSIAction::DeleteLines(n) => {
|
||||
let top = self.cursor_y;
|
||||
println!("execute delete {} lines with scroll up {} {}", n, top, top+n);
|
||||
self.screen_mut().scroll_up(top, top+n, n);
|
||||
println!(
|
||||
"execute delete {} lines with scroll up {} {}",
|
||||
n,
|
||||
top,
|
||||
top + n
|
||||
);
|
||||
self.screen_mut().scroll_up(top, top + n, n);
|
||||
}
|
||||
CSIAction::InsertLines(n) => {
|
||||
let top = self.cursor_y;
|
||||
println!("execute insert {} lines with scroll down {} {}", n, top, top+n);
|
||||
self.screen_mut().scroll_down(top, top+n, n);
|
||||
println!(
|
||||
"execute insert {} lines with scroll down {} {}",
|
||||
n,
|
||||
top,
|
||||
top + n
|
||||
);
|
||||
self.screen_mut().scroll_down(top, top + n, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
121
src/term/test/mod.rs
Normal file
121
src/term/test/mod.rs
Normal file
@ -0,0 +1,121 @@
|
||||
//! Various tests of the terminal model and escape sequence
|
||||
//! processing routines.
|
||||
|
||||
use super::*;
|
||||
|
||||
fn set_mode(term: &mut Terminal, mode: &str, enable: bool) {
|
||||
term.advance_bytes(CSI);
|
||||
term.advance_bytes(mode);
|
||||
term.advance_bytes(if enable { b"h" } else { b"l" });
|
||||
}
|
||||
|
||||
fn cup(term: &mut Terminal, row: isize, col: isize) {
|
||||
term.advance_bytes(CSI);
|
||||
term.advance_bytes(format!("{};{}H", row, col));
|
||||
}
|
||||
|
||||
fn erase_in_display(term: &mut Terminal, erase: DisplayErase) {
|
||||
term.advance_bytes(CSI);
|
||||
let num = match erase {
|
||||
DisplayErase::Below => 0,
|
||||
DisplayErase::Above => 1,
|
||||
DisplayErase::All => 2,
|
||||
DisplayErase::SavedLines => 3,
|
||||
};
|
||||
term.advance_bytes(format!("{}J", num));
|
||||
}
|
||||
|
||||
fn erase_in_line(term: &mut Terminal, erase: LineErase) {
|
||||
term.advance_bytes(CSI);
|
||||
let num = match erase {
|
||||
LineErase::ToRight => 0,
|
||||
LineErase::ToLeft => 1,
|
||||
LineErase::All => 2,
|
||||
};
|
||||
term.advance_bytes(format!("{}K", num));
|
||||
}
|
||||
|
||||
/// Asserts that the visible lines of the terminal have the
|
||||
/// same cell contents. The cells must exactly match.
|
||||
fn assert_visible_lines(term: &Terminal, expect_lines: &[Line]) {
|
||||
let screen = term.screen();
|
||||
let lines = screen.visible_lines();
|
||||
|
||||
assert!(
|
||||
lines.len() == expect_lines.len(),
|
||||
"expectation has wrong number of lines"
|
||||
);
|
||||
|
||||
let mut expect_iter = expect_lines.iter();
|
||||
|
||||
for (idx, line) in lines.iter().enumerate() {
|
||||
let expect = expect_iter.next().unwrap();
|
||||
|
||||
assert!(
|
||||
expect.cells == line.cells,
|
||||
"line {} was {:?} but expected {:?}",
|
||||
idx,
|
||||
line.cells,
|
||||
expect.cells
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Asserts that the visible lines of the terminal have the
|
||||
/// same character contents as the expected lines.
|
||||
/// The other cell attributes are not compared; this is
|
||||
/// a convenience for writing visually understandable tests.
|
||||
fn assert_visible_contents(term: &Terminal, expect_lines: &[&str]) {
|
||||
let screen = term.screen();
|
||||
let lines = screen.visible_lines();
|
||||
|
||||
assert!(
|
||||
lines.len() == expect_lines.len(),
|
||||
"expectation has wrong number of lines"
|
||||
);
|
||||
|
||||
let mut expect_iter = expect_lines.iter();
|
||||
|
||||
for (idx, line) in lines.iter().enumerate() {
|
||||
let expect = expect_iter.next().unwrap();
|
||||
let line_str = line.as_str();
|
||||
|
||||
assert!(
|
||||
&line_str == expect,
|
||||
"line {} was {:?} but expected {:?}",
|
||||
idx,
|
||||
line_str,
|
||||
expect
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic_output() {
|
||||
let mut term = Terminal::new(5, 10, 0);
|
||||
|
||||
cup(&mut term, 2, 2);
|
||||
term.advance_bytes("hello, world!");
|
||||
assert_visible_contents(
|
||||
&term,
|
||||
&[
|
||||
" ",
|
||||
" hello, wo",
|
||||
"rld! ",
|
||||
" ",
|
||||
" ",
|
||||
],
|
||||
);
|
||||
|
||||
erase_in_display(&mut term, DisplayErase::Above);
|
||||
assert_visible_contents(
|
||||
&term,
|
||||
&[
|
||||
" ",
|
||||
" ",
|
||||
"rld! ",
|
||||
" ",
|
||||
" ",
|
||||
],
|
||||
);
|
||||
}
|
Loading…
Reference in New Issue
Block a user