altui_core/backend/
test.rs1use crate::{
2 backend::Backend,
3 buffer::{Buffer, Cell},
4 layout::Rect,
5};
6use std::{fmt::Write, io};
7use unicode_width::UnicodeWidthStr;
8
9#[derive(Debug)]
11pub struct TestBackend {
12 width: u16,
13 buffer: Buffer,
14 height: u16,
15 cursor: bool,
16 pos: (u16, u16),
17}
18
19fn buffer_view(buffer: &Buffer) -> String {
21 let mut view = String::with_capacity(buffer.content.len() + buffer.area.height as usize * 3);
22 for cells in buffer.content.chunks(buffer.area.width as usize) {
23 let mut overwritten = vec![];
24 let mut skip: usize = 0;
25 view.push('"');
26 for (x, c) in cells.iter().enumerate() {
27 if skip == 0 {
28 view.push_str(&c.symbol);
29 } else {
30 overwritten.push((x, &c.symbol))
31 }
32 skip = std::cmp::max(skip, c.symbol.width()).saturating_sub(1);
33 }
34 view.push('"');
35 if !overwritten.is_empty() {
36 write!(
37 &mut view,
38 " Hidden by multi-width symbols: {:?}",
39 overwritten
40 )
41 .unwrap();
42 }
43 view.push('\n');
44 }
45 view
46}
47
48impl TestBackend {
49 pub fn new(width: u16, height: u16) -> TestBackend {
50 TestBackend {
51 width,
52 height,
53 buffer: Buffer::empty(Rect::new(0, 0, width, height)),
54 cursor: false,
55 pos: (0, 0),
56 }
57 }
58
59 pub fn buffer(&self) -> &Buffer {
60 &self.buffer
61 }
62
63 pub fn resize(&mut self, width: u16, height: u16) {
64 self.buffer.resize(Rect::new(0, 0, width, height));
65 self.width = width;
66 self.height = height;
67 }
68
69 pub fn assert_buffer(&self, expected: &Buffer) {
70 assert_eq!(expected.area, self.buffer.area);
71 let diff = expected.diff(&self.buffer);
72 if diff.is_empty() {
73 return;
74 }
75
76 let mut debug_info = String::from("Buffers are not equal");
77 debug_info.push('\n');
78 debug_info.push_str("Expected:");
79 debug_info.push('\n');
80 let expected_view = buffer_view(expected);
81 debug_info.push_str(&expected_view);
82 debug_info.push('\n');
83 debug_info.push_str("Got:");
84 debug_info.push('\n');
85 let view = buffer_view(&self.buffer);
86 debug_info.push_str(&view);
87 debug_info.push('\n');
88
89 debug_info.push_str("Diff:");
90 debug_info.push('\n');
91 let nice_diff = diff
92 .iter()
93 .enumerate()
94 .map(|(i, (x, y, cell))| {
95 let expected_cell = expected.get(*x, *y);
96 format!(
97 "{}: at ({}, {}) expected {:?} got {:?}",
98 i, x, y, expected_cell, cell
99 )
100 })
101 .collect::<Vec<String>>()
102 .join("\n");
103 debug_info.push_str(&nice_diff);
104 panic!("{}", debug_info);
105 }
106}
107
108impl Backend for TestBackend {
109 fn draw<'a, I>(&mut self, content: I) -> Result<(), io::Error>
110 where
111 I: Iterator<Item = (u16, u16, &'a Cell)>,
112 {
113 for (x, y, c) in content {
114 let cell = self.buffer.get_mut(x, y);
115 *cell = c.clone();
116 }
117 Ok(())
118 }
119
120 fn hide_cursor(&mut self) -> Result<(), io::Error> {
121 self.cursor = false;
122 Ok(())
123 }
124
125 fn show_cursor(&mut self) -> Result<(), io::Error> {
126 self.cursor = true;
127 Ok(())
128 }
129
130 fn get_cursor(&mut self) -> Result<(u16, u16), io::Error> {
131 Ok(self.pos)
132 }
133
134 fn set_cursor(&mut self, x: u16, y: u16) -> Result<(), io::Error> {
135 self.pos = (x, y);
136 Ok(())
137 }
138
139 fn clear(&mut self) -> Result<(), io::Error> {
140 self.buffer.reset();
141 Ok(())
142 }
143
144 fn size(&self) -> Result<Rect, io::Error> {
145 Ok(Rect::new(0, 0, self.width, self.height))
146 }
147
148 fn flush(&mut self) -> Result<(), io::Error> {
149 Ok(())
150 }
151}