1use std::process::{Command, Output};
6
7use derive_builder::Builder;
8use libtest_mimic::Failed;
9
10fn command_err(msg: String, output: Output) -> Result<(String, String), Failed> {
12 let mut err = msg;
13 err.push_str(&format!(
14 "\nstdout: \"{}\"",
15 &String::from_utf8(output.stdout)?
16 ));
17 err.push_str(&format!(
18 "\nstderr: \"{}\"",
19 &String::from_utf8(output.stderr)?
20 ));
21 Err(err.into())
22}
23
24#[derive(Builder, Default)]
27#[builder(setter(strip_option))]
28pub struct TestCommand<'a> {
29 program: &'a str,
31 #[builder(default)]
33 args: Option<&'a [&'a str]>,
34 #[builder(default)]
36 expected_rc: Option<i32>,
37 #[builder(default)]
39 expected_stdout: Option<&'a str>,
40 #[builder(default)]
42 expected_stderr: Option<&'a str>,
43}
44
45impl TestCommand<'_> {
46 pub fn test_result(&self) -> Result<(String, String), Failed> {
50 let output = if let Some(args) = self.args {
51 Command::new(self.program).args(args).output()?
52 } else {
53 Command::new(self.program).output()?
54 };
55 if let Some(exp_rc) = self.expected_rc {
57 match output.status.code() {
58 Some(errno) => {
59 if errno != exp_rc {
60 return command_err(
61 format!(
62 "Unexpected errno from {} {:?}\n got: {}, expected: {}",
63 self.program, self.args, errno, exp_rc
64 ),
65 output,
66 );
67 }
68 }
69 None => {
70 return command_err(format!("{} terminated by signal", self.program), output)
71 }
72 }
73 }
74 let stdout = String::from_utf8(output.stdout.clone())?;
76 if let Some(exp_stdout) = self.expected_stdout {
77 if !stdout.contains(exp_stdout) {
78 return command_err(
79 format!("Unexpected stdout, wanted: \"{exp_stdout}\""),
80 output,
81 );
82 }
83 }
84 let stderr = String::from_utf8(output.stderr.clone())?;
86 if let Some(exp_stderr) = self.expected_stderr {
87 if !stderr.contains(exp_stderr) {
88 return command_err(
89 format!("Unexpected stderr, wanted: \"{exp_stderr}\""),
90 output,
91 );
92 }
93 }
94 Ok((stdout, stderr))
95 }
96
97 pub fn test(&self) -> Result<(), Failed> {
99 match self.test_result() {
100 Ok(_) => Ok(()),
101 Err(e) => Err(e),
102 }
103 }
104}