display/testutil/
mockcrossterm.rs

1use crossterm::style::{Attribute, Attributes, Color, Colors};
2
3use crate::{
4	testutil::{MockableTui, State},
5	ColorMode,
6	DisplayError,
7	Size,
8};
9
10/// A mocked version of `CrossTerm`, useful for testing.
11#[derive(Debug)]
12pub struct CrossTerm {
13	attributes: Attributes,
14	color_mode: ColorMode,
15	colors: Colors,
16	dirty: bool,
17	output: Vec<String>,
18	position: (u16, u16),
19	size: Size,
20	state: State,
21}
22
23impl MockableTui for CrossTerm {
24	#[inline]
25	fn get_color_mode(&self) -> ColorMode {
26		self.color_mode
27	}
28
29	#[inline]
30	fn reset(&mut self) -> Result<(), DisplayError> {
31		self.attributes = Attributes::from(Attribute::Reset);
32		self.colors = Colors::new(Color::Reset, Color::Reset);
33		self.output.clear();
34		self.state = State::Normal;
35		Ok(())
36	}
37
38	#[inline]
39	fn flush(&mut self) -> Result<(), DisplayError> {
40		self.dirty = false;
41		Ok(())
42	}
43
44	#[inline]
45	fn print(&mut self, s: &str) -> Result<(), DisplayError> {
46		self.output.push(String::from(s));
47		Ok(())
48	}
49
50	#[inline]
51	fn set_color(&mut self, colors: Colors) -> Result<(), DisplayError> {
52		self.colors = colors;
53		Ok(())
54	}
55
56	#[inline]
57	fn set_dim(&mut self, dim: bool) -> Result<(), DisplayError> {
58		if dim {
59			self.attributes.set(Attribute::Dim);
60		}
61		else {
62			self.attributes.set(Attribute::NormalIntensity);
63		}
64		Ok(())
65	}
66
67	#[inline]
68	fn set_underline(&mut self, dim: bool) -> Result<(), DisplayError> {
69		if dim {
70			self.attributes.set(Attribute::Underlined);
71		}
72		else {
73			self.attributes.set(Attribute::NoUnderline);
74		}
75		Ok(())
76	}
77
78	#[inline]
79	fn set_reverse(&mut self, dim: bool) -> Result<(), DisplayError> {
80		if dim {
81			self.attributes.set(Attribute::Reverse);
82		}
83		else {
84			self.attributes.set(Attribute::NoReverse);
85		}
86		Ok(())
87	}
88
89	#[inline]
90	fn get_size(&self) -> Size {
91		self.size
92	}
93
94	#[inline]
95	fn move_to_column(&mut self, x: u16) -> Result<(), DisplayError> {
96		self.position.0 = x;
97		Ok(())
98	}
99
100	#[inline]
101	fn move_next_line(&mut self) -> Result<(), DisplayError> {
102		self.output.push(String::from("\n"));
103		self.position.0 = 0;
104		self.position.1 += 1;
105		Ok(())
106	}
107
108	#[inline]
109	fn start(&mut self) -> Result<(), DisplayError> {
110		self.state = State::Normal;
111		Ok(())
112	}
113
114	#[inline]
115	fn end(&mut self) -> Result<(), DisplayError> {
116		self.state = State::Ended;
117		Ok(())
118	}
119}
120
121impl CrossTerm {
122	/// Create a new mocked version of `CrossTerm`.
123	#[inline]
124	#[must_use]
125	pub fn new() -> Self {
126		Self {
127			attributes: Attributes::from(Attribute::Reset),
128			color_mode: ColorMode::FourBit,
129			colors: Colors::new(Color::Reset, Color::Reset),
130			dirty: true,
131			output: vec![],
132			position: (0, 0),
133			size: Size::new(10, 10),
134			state: State::New,
135		}
136	}
137
138	/// Get a representation of the rendered output.
139	#[inline]
140	#[must_use]
141	pub const fn get_output(&self) -> &Vec<String> {
142		&self.output
143	}
144
145	/// Get the current state.
146	#[inline]
147	#[must_use]
148	pub const fn get_state(&self) -> State {
149		self.state
150	}
151
152	/// Are colors enabled.
153	#[inline]
154	#[must_use]
155	pub fn is_colors_enabled(&self, colors: Colors) -> bool {
156		self.colors == colors
157	}
158
159	/// Does the current style attributes contained dimmed.
160	#[inline]
161	#[must_use]
162	pub const fn is_dimmed(&self) -> bool {
163		self.attributes.has(Attribute::Dim)
164	}
165
166	/// Does the current style attributes contained reverse.
167	#[inline]
168	#[must_use]
169	pub const fn is_reverse(&self) -> bool {
170		self.attributes.has(Attribute::Reverse)
171	}
172
173	/// Does the current style attributes contained underlined.
174	#[inline]
175	#[must_use]
176	pub const fn is_underline(&self) -> bool {
177		self.attributes.has(Attribute::Underlined)
178	}
179
180	/// Update the size.
181	#[inline]
182	pub fn set_size(&mut self, size: Size) {
183		self.size = size;
184	}
185
186	/// Get the current cursor position.
187	#[inline]
188	#[must_use]
189	pub const fn get_position(&self) -> (u16, u16) {
190		self.position
191	}
192
193	/// Has the output been flushed.
194	#[inline]
195	#[must_use]
196	pub const fn is_dirty(&self) -> bool {
197		self.dirty
198	}
199}