1use crate::buffer::Buffer;
2use crate::context::Context;
3use crate::event::{Event, KeyCode, KeyEvent, KeyModifiers, MouseButton, MouseEvent, MouseKind};
4use crate::layout;
5use crate::rect::Rect;
6use crate::style::Theme;
7
8pub struct EventBuilder {
9 events: Vec<Event>,
10}
11
12impl EventBuilder {
13 pub fn new() -> Self {
14 Self { events: Vec::new() }
15 }
16
17 pub fn key(mut self, c: char) -> Self {
18 self.events.push(Event::Key(KeyEvent {
19 code: KeyCode::Char(c),
20 modifiers: KeyModifiers::NONE,
21 }));
22 self
23 }
24
25 pub fn key_code(mut self, code: KeyCode) -> Self {
26 self.events.push(Event::Key(KeyEvent {
27 code,
28 modifiers: KeyModifiers::NONE,
29 }));
30 self
31 }
32
33 pub fn key_with(mut self, code: KeyCode, modifiers: KeyModifiers) -> Self {
34 self.events.push(Event::Key(KeyEvent { code, modifiers }));
35 self
36 }
37
38 pub fn click(mut self, x: u32, y: u32) -> Self {
39 self.events.push(Event::Mouse(MouseEvent {
40 kind: MouseKind::Down(MouseButton::Left),
41 x,
42 y,
43 modifiers: KeyModifiers::NONE,
44 }));
45 self
46 }
47
48 pub fn scroll_up(mut self, x: u32, y: u32) -> Self {
49 self.events.push(Event::Mouse(MouseEvent {
50 kind: MouseKind::ScrollUp,
51 x,
52 y,
53 modifiers: KeyModifiers::NONE,
54 }));
55 self
56 }
57
58 pub fn scroll_down(mut self, x: u32, y: u32) -> Self {
59 self.events.push(Event::Mouse(MouseEvent {
60 kind: MouseKind::ScrollDown,
61 x,
62 y,
63 modifiers: KeyModifiers::NONE,
64 }));
65 self
66 }
67
68 pub fn paste(mut self, text: impl Into<String>) -> Self {
69 self.events.push(Event::Paste(text.into()));
70 self
71 }
72
73 pub fn resize(mut self, width: u32, height: u32) -> Self {
74 self.events.push(Event::Resize(width, height));
75 self
76 }
77
78 pub fn build(self) -> Vec<Event> {
79 self.events
80 }
81}
82
83impl Default for EventBuilder {
84 fn default() -> Self {
85 Self::new()
86 }
87}
88
89pub struct TestBackend {
90 buffer: Buffer,
91 width: u32,
92 height: u32,
93}
94
95impl TestBackend {
96 pub fn new(width: u32, height: u32) -> Self {
97 let area = Rect::new(0, 0, width, height);
98 Self {
99 buffer: Buffer::empty(area),
100 width,
101 height,
102 }
103 }
104
105 pub fn render(&mut self, f: impl FnOnce(&mut Context)) {
107 let mut ctx = Context::new(
108 Vec::new(),
109 self.width,
110 self.height,
111 0,
112 0,
113 0,
114 Vec::new(),
115 Vec::new(),
116 Vec::new(),
117 false,
118 Theme::dark(),
119 None,
120 );
121 f(&mut ctx);
122 let mut tree = layout::build_tree(&ctx.commands);
123 let area = Rect::new(0, 0, self.width, self.height);
124 layout::compute(&mut tree, area);
125 self.buffer.reset();
126 layout::render(&tree, &mut self.buffer);
127 }
128
129 pub fn render_with_events(
131 &mut self,
132 events: Vec<Event>,
133 focus_index: usize,
134 prev_focus_count: usize,
135 f: impl FnOnce(&mut Context),
136 ) {
137 let mut ctx = Context::new(
138 events,
139 self.width,
140 self.height,
141 0,
142 focus_index,
143 prev_focus_count,
144 Vec::new(),
145 Vec::new(),
146 Vec::new(),
147 false,
148 Theme::dark(),
149 None,
150 );
151 ctx.process_focus_keys();
152 f(&mut ctx);
153 let mut tree = layout::build_tree(&ctx.commands);
154 let area = Rect::new(0, 0, self.width, self.height);
155 layout::compute(&mut tree, area);
156 self.buffer.reset();
157 layout::render(&tree, &mut self.buffer);
158 }
159
160 pub fn run_with_events(&mut self, events: Vec<Event>, f: impl FnOnce(&mut crate::Context)) {
161 self.render_with_events(events, 0, 0, f);
162 }
163
164 pub fn line(&self, y: u32) -> String {
166 let mut s = String::new();
167 for x in 0..self.width {
168 s.push_str(&self.buffer.get(x, y).symbol);
169 }
170 s.trim_end().to_string()
171 }
172
173 pub fn assert_line(&self, y: u32, expected: &str) {
175 let line = self.line(y);
176 assert_eq!(
177 line, expected,
178 "Line {y}: expected {expected:?}, got {line:?}"
179 );
180 }
181
182 pub fn assert_line_contains(&self, y: u32, expected: &str) {
184 let line = self.line(y);
185 assert!(
186 line.contains(expected),
187 "Line {y}: expected to contain {expected:?}, got {line:?}"
188 );
189 }
190
191 pub fn assert_contains(&self, expected: &str) {
193 for y in 0..self.height {
194 if self.line(y).contains(expected) {
195 return;
196 }
197 }
198 let mut all_lines = String::new();
199 for y in 0..self.height {
200 all_lines.push_str(&format!("{}: {}\n", y, self.line(y)));
201 }
202 panic!("Buffer does not contain {expected:?}.\nBuffer:\n{all_lines}");
203 }
204
205 pub fn buffer(&self) -> &Buffer {
206 &self.buffer
207 }
208
209 pub fn width(&self) -> u32 {
210 self.width
211 }
212
213 pub fn height(&self) -> u32 {
214 self.height
215 }
216}