1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
45use event_listener::Event;
6use futures::AsyncWrite;
7use std::cell::RefCell;
8use std::io::Write;
9use std::pin::Pin;
10use std::rc::Rc;
11use std::task::{Context, Poll};
1213/// Provides shared memory buffers (in the form of [`TestBuffer`]s for stdout
14/// and stderr that can be used with implementations of [`crate::ToolIO`] to
15/// test input and output behaviour at runtime.
16#[derive(Default, Debug)]
17pub struct TestBuffers {
18pub stdout: TestBuffer,
19pub stderr: TestBuffer,
20}
2122/// Provides a shared memory buffer that can be cloned that can be used with
23/// implementations of [`crate::ToolIO`] to test input and output behaviour
24/// at runtime.
25#[derive(Clone, Default, Debug)]
26pub struct TestBuffer {
27 inner: Rc<RefCell<Vec<u8>>>,
28 event: Rc<Event>,
29}
3031impl TestBuffers {
32/// Destroy `self` and return the standard output and error buffers as byte
33 /// arrays.
34pub fn into_stdio(self) -> (Vec<u8>, Vec<u8>) {
35let stdout = self.stdout.into_inner();
36let stderr = self.stderr.into_inner();
37 (stdout, stderr)
38 }
3940/// Destroy `self` and return the standard output and error buffers as strings.
41pub fn into_strings(self) -> (String, String) {
42let stdout = self.stdout.into_string();
43let stderr = self.stderr.into_string();
44 (stdout, stderr)
45 }
4647/// Destroy `self` and return the standard output buffer as a byte
48 /// array.
49pub fn into_stdout(self) -> Vec<u8> {
50self.stdout.into_inner()
51 }
5253/// Destroy `self` and return the standard output buffer as a string.
54pub fn into_stdout_str(self) -> String {
55self.stdout.into_string()
56 }
5758/// Destroy `self` and return the standard error buffer as a byte
59 /// array.
60pub fn into_stderr(self) -> Vec<u8> {
61self.stderr.into_inner()
62 }
6364/// Destroy `self` and return the standard error buffer as a string.
65pub fn into_stderr_str(self) -> String {
66self.stderr.into_string()
67 }
68}
6970impl TestBuffer {
71/// Destroys self and returns the inner buffer as a vector.
72pub fn into_inner(self) -> Vec<u8> {
73self.inner.take().into()
74 }
7576/// Destroys self and returns the inner buffer as a string.
77pub fn into_string(self) -> String {
78 String::from_utf8(self.into_inner()).expect("Valid unicode on output string")
79 }
8081/// Waits for the buffer to be written to. This will not return immediately if data is already
82 /// present so this should be called *after* calling `into_inner` or `into_string` and not
83 /// finding the desired results.
84pub async fn wait_ready(&self) {
85self.event.listen().await;
86 }
87}
8889impl Write for TestBuffer {
90fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
91self.event.notify(usize::MAX);
92self.inner.borrow_mut().write(buf)
93 }
9495fn flush(&mut self) -> std::io::Result<()> {
96self.inner.borrow_mut().flush()
97 }
98}
99100impl AsyncWrite for TestBuffer {
101fn poll_write(
102self: Pin<&mut Self>,
103 _cx: &mut Context<'_>,
104 buf: &[u8],
105 ) -> Poll<std::io::Result<usize>> {
106let size = self.inner.borrow_mut().write(buf);
107 Poll::Ready(size)
108 }
109110fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
111match self.inner.borrow_mut().flush() {
112Ok(_) => Poll::Ready(Ok(())),
113Err(e) => Poll::Ready(Err(e)),
114 }
115 }
116117fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
118 Poll::Ready(Ok(()))
119 }
120}