Skip to content

Commit 14dbe1c

Browse files
committed
Clean up tests, restructure csm into lib+bin crate
1 parent 5f6c704 commit 14dbe1c

8 files changed

Lines changed: 140 additions & 152 deletions

File tree

Cargo.lock

Lines changed: 5 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ tar = "0.4.44"
2626

2727
[dev-dependencies]
2828
assert_cmd = "2.0"
29+
clap_builder = "4.5.51"
2930
predicates = { version = "3.0", features = ["regex"] }
3031
regex = "1.12.2"
3132
temp-env = "0.3.6"

src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pub mod csmrc;
2+
pub mod env;
3+
pub mod init;
4+
pub mod micromamba;
5+
pub mod robot;
6+
pub mod shell;

src/main.rs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
mod csmrc;
2-
mod env;
3-
mod init;
4-
mod micromamba;
5-
mod robot;
6-
mod shell;
7-
8-
use crate::csmrc::Config;
1+
use csm::csmrc::Config;
2+
use csm::env;
3+
use csm::init;
4+
use csm::robot;
5+
use csm::shell;
6+
97
use clap::{CommandFactory, Parser, Subcommand};
108
use log::{LevelFilter, debug, error, info, warn};
119
use std::fmt;

tests/common.rs

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,21 @@
22

33
use assert_cmd::cargo::{self, cargo_bin_cmd};
44
use assert_cmd::cmd::Command;
5+
use std::io::Write;
56
use std::path::PathBuf;
6-
use tempfile::{Builder, TempDir};
7+
use std::{env, fs, io};
8+
use tempfile::{Builder, NamedTempFile, TempDir};
79

810
#[derive(Debug)]
911
pub enum Error {
1012
Which(which::Error),
11-
IO(std::io::Error),
13+
IO(io::Error),
1214
Regex(regex::Error),
1315
GenericError(String),
1416
}
1517

16-
impl From<std::io::Error> for Error {
17-
fn from(err: std::io::Error) -> Self {
18+
impl From<io::Error> for Error {
19+
fn from(err: io::Error) -> Self {
1820
Self::IO(err)
1921
}
2022
}
@@ -64,7 +66,7 @@ impl Csm {
6466
command
6567
}
6668

67-
pub fn ext_command(&self, bin: PathBuf) -> Command {
69+
pub fn ext_command(&self, bin: &str) -> Command {
6870
let mut command = Command::new(bin);
6971
self.prepare_command(&mut command);
7072

@@ -76,7 +78,7 @@ impl Csm {
7678
.to_string_lossy()
7779
.replace("\\", "/");
7880
let separator = if cfg!(windows) { ";" } else { ":" };
79-
let path = match std::env::var("PATH") {
81+
let path = match env::var("PATH") {
8082
Ok(path) => format!("{}{}{}", path, separator, csm_bin_dir),
8183
Err(_) => csm_bin_dir,
8284
};
@@ -85,8 +87,48 @@ impl Csm {
8587
command
8688
}
8789

88-
pub fn write_csmrc(&self, config: &str) -> Result<(), std::io::Error> {
89-
std::fs::write(self.home_dir.path().join(".csmrc"), config)
90+
/// Similar to `ext_command`, but stores a script in a temporary file
91+
/// (outside of the temporary home directory).
92+
///
93+
/// This primarily exists because when reading from stdin, PowerShell will
94+
/// by default insist on displaying its prompt and name banner, unlike every
95+
/// other shell in existence.
96+
pub fn run_script(&self, bin: &str, script: &str, suffix: &str) -> io::Result<ScriptCommand> {
97+
let mut tmpfile = NamedTempFile::with_suffix(suffix)?;
98+
writeln!(tmpfile, "{}", script)?;
99+
let mut cmd = self.ext_command(bin);
100+
cmd.arg(tmpfile.path());
101+
Ok(ScriptCommand {
102+
command: cmd,
103+
_tmpfile: tmpfile,
104+
})
105+
}
106+
107+
pub fn write_csmrc(&self, config: &str) -> Result<(), io::Error> {
108+
fs::write(self.home_dir.path().join(".csmrc"), config)
109+
}
110+
}
111+
112+
/// This exists only to make sure that the tmpfile doesn't get dropped
113+
/// prematurely from Csm.run_script(). The tmpfile will get dropped when the
114+
/// reference to it goes away - so we need a way to keep the reference around
115+
/// with the Command that we return.
116+
pub struct ScriptCommand {
117+
pub command: Command,
118+
_tmpfile: NamedTempFile,
119+
}
120+
121+
impl std::ops::Deref for ScriptCommand {
122+
type Target = Command;
123+
124+
fn deref(&self) -> &Self::Target {
125+
&self.command
126+
}
127+
}
128+
129+
impl std::ops::DerefMut for ScriptCommand {
130+
fn deref_mut(&mut self) -> &mut Self::Target {
131+
&mut self.command
90132
}
91133
}
92134

tests/env.rs

Lines changed: 32 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ mod common;
33
use common::Error;
44

55
use predicates::prelude::*;
6-
use which::which;
76

87
/// Create an environment with `csm env create`.
98
fn csm_env_create(csm: &mut common::Csm, name: &str) -> Result<(), Error> {
@@ -167,29 +166,29 @@ fn csm_env_activate_deactivate_bash() -> Result<(), Error> {
167166
let _ = csm_env_create(&mut csm, "csm_env_activate_bash");
168167

169168
// activate
170-
csm.ext_command(which("bash")?)
171-
.arg("-c")
172-
.arg(
173-
"eval \"$(csm init bash --code)\" &&\
169+
csm.run_script(
170+
"bash",
171+
"eval \"$(csm init bash --code)\" &&\
174172
csm env activate -n csm_env_activate_bash &&\
175173
robot --version",
176-
)
177-
.assert()
178-
.code(251)
179-
.stdout(predicate::str::is_match("^Robot Framework")?);
174+
".sh",
175+
)?
176+
.assert()
177+
.code(251)
178+
.stdout(predicate::str::is_match("^Robot Framework")?);
180179

181180
// deactivate
182-
csm.ext_command(which("bash")?)
183-
.arg("-c")
184-
.arg(
185-
"eval \"$(csm init bash --code)\" &&\
181+
csm.run_script(
182+
"bash",
183+
"eval \"$(csm init bash --code)\" &&\
186184
csm env activate -n csm_env_activate_bash &&\
187185
csm env deactivate &&\
188186
robot --version",
189-
)
190-
.assert()
191-
.failure()
192-
.stderr(predicate::str::contains("command not found"));
187+
".sh",
188+
)?
189+
.assert()
190+
.failure()
191+
.stderr(predicate::str::contains("command not found"));
193192
Ok(())
194193
}
195194

@@ -202,29 +201,28 @@ fn csm_env_activate_deactivate_powershell() -> Result<(), Error> {
202201
let _ = csm_env_create(&mut csm, "csm_env_activate_bash");
203202

204203
// activate
205-
csm.ext_command(which("pwsh")?)
206-
.arg("-c")
207-
.arg(format!(
208-
"csm init powershell --code | Out-String | Invoke-Expression &&\
204+
csm.run_script(
205+
"pwsh",
206+
"csm init powershell --code | Out-String | Invoke-Expression &&\
209207
csm env activate -n csm_env_activate_bash &&\
210208
robot --version",
211-
))
212-
.assert()
213-
.stdout(predicate::str::is_match("^Robot Framework")?);
209+
".ps1",
210+
)?
211+
.assert()
212+
.stdout(predicate::str::is_match("^Robot Framework")?);
214213

215214
// deactivate
216-
csm.ext_command(which("pwsh")?)
217-
.arg("-c")
218-
.arg(format!(
219-
"csm init powershell --code | Out-String | Invoke-Expression &&\
215+
csm.run_script(
216+
"pwsh",
217+
"csm init powershell --code | Out-String | Invoke-Expression &&\
220218
csm env activate -n csm_env_activate_bash &&\
221219
csm env deactivate &&\
222220
robot --version",
223-
))
224-
.assert()
225-
.failure()
226-
.stderr(predicate::str::contains(
227-
"not recognized as a name of a cmdlet",
228-
));
221+
".ps1",
222+
)?
223+
.assert()
224+
.stderr(predicate::str::contains(
225+
"not recognized as a name of a cmdlet",
226+
));
229227
Ok(())
230228
}

0 commit comments

Comments
 (0)