1use std::ffi::OsString;
2use std::path::PathBuf;
3
4use temp_testdir::TempDir;
5
6pub mod case;
7pub mod cmd;
8pub mod error;
9
10#[derive(Debug, Clone)]
11pub struct Tester {
12 pub md_file_path: PathBuf,
13 pub cargo_bin_alias: Option<String>,
14 pub cargo_bin_name: Option<String>,
15 pub envs: Vec<(OsString, OsString)>,
16}
17
18impl Tester {
19 pub fn new(md_file_path: impl Into<PathBuf>) -> Self {
20 Self {
21 md_file_path: md_file_path.into(),
22 cargo_bin_alias: None,
23 cargo_bin_name: None,
24 envs: Vec::new(),
25 }
26 }
27
28 pub fn with_cargo_bin_alias(mut self, alias: impl Into<String>) -> Self {
29 self.cargo_bin_alias = Some(alias.into());
30 self
31 }
32
33 pub fn with_cargo_bin_name(mut self, cargo_bin_name: impl Into<String>) -> Self {
34 self.cargo_bin_name = Some(cargo_bin_name.into());
35 self
36 }
37
38 pub fn with_env(mut self, key: impl Into<OsString>, val: impl Into<OsString>) -> Self {
39 self.envs.push((key.into(), val.into()));
40 self
41 }
42
43 pub fn with_envs(mut self, vars: impl IntoIterator<Item = (impl Into<OsString>, impl Into<OsString>)>) -> Self {
44 for (key, val) in vars {
45 self.envs.push((key.into(), val.into()));
46 }
47 self
48 }
49
50 pub fn run(self) -> error::Result<()> {
51 let sections = case::parse_markdown_tests(
52 self.md_file_path,
53 self.cargo_bin_alias,
54 self.cargo_bin_name,
55 Some(self.envs),
56 )?;
57
58 for section in sections {
59 let test_dir = TempDir::default();
60 let mut completed_tests = Vec::new();
61
62 log::debug!("\n# {}", section.title);
63
64 for test_case in section.cases {
65 let test_case = test_case.with_test_dir(test_dir.as_os_str());
66
67 log::debug!("Testing: {:?}", test_case.commands);
68 test_case.run()?;
69 completed_tests.push(test_case);
70 }
71
72 drop(completed_tests);
74 }
75 Ok(())
76 }
77}