1use event_listener::Event;
6use futures::AsyncWrite;
7use std::io::Write;
8use std::pin::Pin;
9use std::sync::{Arc, Mutex};
10use std::task::{Context, Poll};
11
12#[derive(Default, Debug)]
16pub struct TestBuffers {
17 pub stdout: TestBuffer,
18 pub stderr: TestBuffer,
19}
20
21#[derive(Clone, Default, Debug)]
25pub struct TestBuffer {
26 inner: Arc<Mutex<Vec<u8>>>,
27 event: Arc<Event>,
28}
29
30impl TestBuffers {
31 pub fn into_stdio(self) -> (Vec<u8>, Vec<u8>) {
34 let stdout = self.stdout.into_inner();
35 let stderr = self.stderr.into_inner();
36 (stdout, stderr)
37 }
38
39 pub fn into_strings(self) -> (String, String) {
41 let stdout = self.stdout.into_string();
42 let stderr = self.stderr.into_string();
43 (stdout, stderr)
44 }
45
46 pub fn into_stdout(self) -> Vec<u8> {
49 self.stdout.into_inner()
50 }
51
52 pub fn into_stdout_str(self) -> String {
54 self.stdout.into_string()
55 }
56
57 pub fn into_stderr(self) -> Vec<u8> {
60 self.stderr.into_inner()
61 }
62
63 pub fn into_stderr_str(self) -> String {
65 self.stderr.into_string()
66 }
67}
68
69impl TestBuffer {
70 pub fn into_inner(self) -> Vec<u8> {
72 std::mem::take(&mut *self.inner.lock().unwrap())
73 }
74
75 pub fn into_string(self) -> String {
77 String::from_utf8(self.into_inner()).expect("Valid unicode on output string")
78 }
79
80 pub async fn wait_ready(&self) {
84 self.event.listen().await;
85 }
86}
87
88impl Write for TestBuffer {
89 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
90 self.event.notify(usize::MAX);
91 self.inner.lock().unwrap().write(buf)
92 }
93
94 fn flush(&mut self) -> std::io::Result<()> {
95 self.inner.lock().unwrap().flush()
96 }
97}
98
99impl AsyncWrite for TestBuffer {
100 fn poll_write(
101 self: Pin<&mut Self>,
102 _cx: &mut Context<'_>,
103 buf: &[u8],
104 ) -> Poll<std::io::Result<usize>> {
105 let size = self.inner.lock().unwrap().write(buf);
106 Poll::Ready(size)
107 }
108
109 fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
110 match self.inner.lock().unwrap().flush() {
111 Ok(_) => Poll::Ready(Ok(())),
112 Err(e) => Poll::Ready(Err(e)),
113 }
114 }
115
116 fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
117 Poll::Ready(Ok(()))
118 }
119}