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