1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
use crate::testing::Regex;
use std::{
io::{self, BufRead, BufReader},
ops::{Deref, DerefMut},
process::{ChildStderr, ChildStdout},
};
#[derive(Debug)]
pub struct Stdout(BufReader<ChildStdout>);
#[derive(Debug)]
pub struct Stderr(BufReader<ChildStderr>);
pub trait OutputStream<R>: DerefMut<Target = BufReader<R>>
where
R: io::Read,
{
fn expect_line(&mut self, expected_line: &str) {
let mut actual_line = String::new();
self.read_line(&mut actual_line)
.unwrap_or_else(|e| panic!("error reading line from {}: {}", stringify!($name), e));
assert_eq!(expected_line, actual_line.trim_end_matches('\n'));
}
fn expect_regex<T>(&mut self, regex: T)
where
T: Into<Regex>,
{
let regex: Regex = regex.into();
let mut line = String::new();
self.read_line(&mut line)
.unwrap_or_else(|e| panic!("error reading line from {}: {}", stringify!($name), e));
assert!(
regex.is_match(line.trim_end_matches('\n')),
"regex {:?} did not match line: {:?}",
regex,
line
);
}
}
macro_rules! impl_output_stream {
($name:tt, $inner:ty) => {
impl $name {
pub(super) fn new(stream: $inner) -> $name {
$name(BufReader::new(stream))
}
}
impl Deref for $name {
type Target = BufReader<$inner>;
fn deref(&self) -> &BufReader<$inner> {
&self.0
}
}
impl DerefMut for $name {
fn deref_mut(&mut self) -> &mut BufReader<$inner> {
&mut self.0
}
}
impl OutputStream<$inner> for $name {}
};
}
impl_output_stream!(Stdout, ChildStdout);
impl_output_stream!(Stderr, ChildStderr);