Skip to main content

nu_test_support/playground/
director.rs

1use super::EnvironmentVariable;
2use super::nu_process::*;
3use std::ffi::OsString;
4use std::fmt;
5use std::fmt::Write;
6
7#[derive(Default, Debug)]
8pub struct Director {
9    pub cwd: Option<OsString>,
10    pub environment_vars: Vec<EnvironmentVariable>,
11    pub config: Option<OsString>,
12    pub pipeline: Option<Vec<String>>,
13    pub executable: Option<NuProcess>,
14}
15
16impl Director {
17    pub fn and_then(&mut self, commands: &str) -> &mut Self {
18        let commands = commands.to_string();
19
20        if let Some(ref mut pipeline) = self.pipeline {
21            pipeline.push(commands);
22        } else {
23            self.pipeline = Some(vec![commands]);
24        }
25
26        self
27    }
28
29    pub fn pipeline(&self, commands: &str) -> Self {
30        let mut director = Director {
31            pipeline: if commands.is_empty() {
32                None
33            } else {
34                Some(vec![commands.to_string()])
35            },
36            ..Default::default()
37        };
38
39        let mut process = NuProcess {
40            environment_vars: self.environment_vars.clone(),
41            ..Default::default()
42        };
43
44        if let Some(working_directory) = &self.cwd {
45            process.cwd(working_directory);
46        }
47
48        process.arg("--no-history");
49        if let Some(config_file) = self.config.as_ref() {
50            process.args(&[
51                "--config",
52                config_file.to_str().expect("failed to convert."),
53            ]);
54        }
55        process.args(&["--log-level", "info"]);
56
57        director.executable = Some(process);
58        director
59    }
60
61    pub fn executable(&self) -> Option<&NuProcess> {
62        if let Some(binary) = &self.executable {
63            Some(binary)
64        } else {
65            None
66        }
67    }
68}
69
70impl Executable for Director {
71    fn execute(&mut self) -> Result<Outcome, NuError> {
72        use std::process::Stdio;
73
74        match self.executable() {
75            Some(binary) => {
76                let mut commands = String::new();
77                if let Some(pipelines) = &self.pipeline {
78                    for pipeline in pipelines {
79                        if !commands.is_empty() {
80                            commands.push_str("| ");
81                        }
82                        let _ = writeln!(commands, "{pipeline}");
83                    }
84                }
85
86                let process = binary
87                    .construct()
88                    .stdout(Stdio::piped())
89                    // .stdin(Stdio::piped())
90                    .stderr(Stdio::piped())
91                    .arg("-c")
92                    .arg(commands)
93                    .spawn()
94                    .expect("It should be possible to run tests");
95
96                process
97                    .wait_with_output()
98                    .map_err(|_| {
99                        let reason = format!(
100                            "could not execute process {} ({})",
101                            binary, "No execution took place"
102                        );
103
104                        NuError {
105                            desc: reason,
106                            exit: None,
107                            output: None,
108                        }
109                    })
110                    .and_then(|process| {
111                        let out =
112                            Outcome::new(&read_std(&process.stdout), &read_std(&process.stderr));
113
114                        match process.status.success() {
115                            true => Ok(out),
116                            false => Err(NuError {
117                                desc: String::new(),
118                                exit: Some(process.status),
119                                output: Some(out),
120                            }),
121                        }
122                    })
123            }
124            None => Err(NuError {
125                desc: String::from("err"),
126                exit: None,
127                output: None,
128            }),
129        }
130    }
131}
132
133impl fmt::Display for Director {
134    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135        write!(f, "director")
136    }
137}
138
139fn read_std(std: &[u8]) -> Vec<u8> {
140    let out = String::from_utf8_lossy(std);
141    let out = out.lines().collect::<Vec<_>>().join("\n");
142    let out = out.replace("\r\n", "");
143    out.replace('\n', "").into_bytes()
144}