hojicha_core/testing/
test_backend.rs1use std::io::{self, Write};
4use std::sync::{Arc, Mutex};
5
6#[derive(Clone)]
8pub struct TestBackend {
9 output: Arc<Mutex<Vec<u8>>>,
10 lines: Arc<Mutex<Vec<String>>>,
11}
12
13impl TestBackend {
14 pub fn new() -> Self {
16 Self {
17 output: Arc::new(Mutex::new(Vec::new())),
18 lines: Arc::new(Mutex::new(Vec::new())),
19 }
20 }
21
22 pub fn get_output(&self) -> Vec<u8> {
24 self.output.lock().unwrap().clone()
25 }
26
27 pub fn get_output_string(&self) -> String {
29 String::from_utf8_lossy(&self.get_output()).to_string()
30 }
31
32 pub fn get_lines(&self) -> Vec<String> {
34 self.lines.lock().unwrap().clone()
35 }
36
37 pub fn contains(&self, text: &str) -> bool {
39 self.get_output_string().contains(text)
40 }
41
42 pub fn clear(&self) {
44 self.output.lock().unwrap().clear();
45 self.lines.lock().unwrap().clear();
46 }
47}
48
49impl Write for TestBackend {
50 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
51 let mut output = self.output.lock().unwrap();
52 output.extend_from_slice(buf);
53
54 if let Ok(s) = std::str::from_utf8(buf) {
56 let mut lines = self.lines.lock().unwrap();
57 for line in s.lines() {
58 lines.push(line.to_string());
59 }
60 }
61
62 Ok(buf.len())
63 }
64
65 fn flush(&mut self) -> io::Result<()> {
66 Ok(())
67 }
68}
69
70impl Default for TestBackend {
71 fn default() -> Self {
72 Self::new()
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79
80 #[test]
81 fn test_backend_capture() {
82 let mut backend = TestBackend::new();
83
84 write!(backend, "Hello, ").unwrap();
85 write!(backend, "World!").unwrap();
86
87 assert_eq!(backend.get_output_string(), "Hello, World!");
88 assert!(backend.contains("World"));
89 }
90
91 #[test]
92 fn test_backend_lines() {
93 let mut backend = TestBackend::new();
94
95 writeln!(backend, "Line 1").unwrap();
96 writeln!(backend, "Line 2").unwrap();
97
98 let lines = backend.get_lines();
99 assert_eq!(lines.len(), 2);
100 assert_eq!(lines[0], "Line 1");
101 assert_eq!(lines[1], "Line 2");
102 }
103}