#[cfg(any(feature = "process", feature = "request"))]
mod gate;
pub mod test_env;
#[cfg(feature = "fs")]
pub mod test_fs;
#[cfg(feature = "process")]
pub mod test_process;
#[cfg(feature = "request")]
pub mod test_request;
use crate::Platform;
use crate::TestEnv;
#[cfg(unix)]
pub const ROOT: &str = "/";
#[cfg(windows)]
pub const ROOT: &str = "C:\\";
pub struct TestPlatform {
pub env: TestEnv,
#[cfg(feature = "fs")]
pub fs: crate::TestFs,
#[cfg(feature = "process")]
pub process: crate::TestProcess,
#[cfg(feature = "request")]
pub request: crate::TestRequest,
}
impl TestPlatform {
pub fn with_env(mut self, env: TestEnv) -> Self {
#[cfg(feature = "fs")]
self.fs.set_env(env.shared().clone());
#[cfg(feature = "process")]
self.process.set_env(env.shared().clone());
#[cfg(feature = "request")]
self.request.set_env(env.shared().clone());
self.env = env;
self
}
#[cfg(feature = "fs")]
pub fn with_fs(mut self, mut fs: crate::TestFs) -> Self {
fs.set_env(self.env.shared().clone());
self.fs = fs;
self
}
#[cfg(feature = "process")]
pub fn with_process(mut self, mut process: crate::TestProcess) -> Self {
process.set_env(self.env.shared().clone());
self.process = process;
self
}
#[cfg(feature = "request")]
pub fn with_request(mut self, mut request: crate::TestRequest) -> Self {
request.set_env(self.env.shared().clone());
self.request = request;
self
}
}
impl Platform for TestPlatform {
fn env(&self) -> &(impl crate::Env + use<>) {
&self.env
}
#[cfg(feature = "fs")]
fn fs(&self) -> &(impl crate::Fs + use<>) {
&self.fs
}
#[cfg(feature = "process")]
fn process(&self) -> &(impl crate::Process + use<>) {
&self.process
}
#[cfg(feature = "request")]
fn request(&self) -> &(impl crate::Request + use<>) {
&self.request
}
}
pub fn test_platform() -> TestPlatform {
TestPlatform {
env: TestEnv::new(),
#[cfg(feature = "fs")]
fs: crate::TestFs::new(),
#[cfg(feature = "process")]
process: crate::TestProcess::new(),
#[cfg(feature = "request")]
request: crate::TestRequest::new(),
}
.with_env(TestEnv::new())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Env;
#[cfg(all(unix, any(feature = "fs", feature = "process")))]
const HOME: &str = "/home";
#[cfg(all(windows, any(feature = "fs", feature = "process")))]
const HOME: &str = "C:\\home";
#[cfg(feature = "request")]
fn reqwest_env(https_proxy: &str) -> crate::request::ReqwestEnv {
crate::request::ReqwestEnv::new(&[("HTTPS_PROXY".to_string(), https_proxy.to_string())])
}
mod test_platform {
use super::*;
mod with_env {
use super::*;
#[test]
fn with_env_should_set_custom_test_environment() {
let test_env = TestEnv::new()
.with_args(vec!["arg1", "arg2"])
.with_current_dir("/home")
.with_current_exe("/tmp/project/app")
.with_home_dir("/home/user")
.with_tmp_dir("/tmp")
.with_vars(vec![("KEY1", "value1"), ("KEY2", "value2")]);
let p = test_platform().with_env(test_env);
let e = p.env();
assert_eq!(e.args().collect::<Vec<_>>(), &["arg1", "arg2"]);
assert_eq!(e.current_dir(), std::path::Path::new("/home"));
assert_eq!(e.set_current_dir("/tmp"), std::path::Path::new("/home"));
assert_eq!(e.current_dir(), std::path::Path::new("/tmp"));
assert_eq!(e.current_exe(), std::path::Path::new("/tmp/project/app"));
assert_eq!(e.home_dir(), std::path::Path::new("/home/user"));
assert_eq!(e.tmp_dir(), std::path::Path::new("/tmp"));
assert_eq!(e.var("KEY1").as_deref(), Some("value1"));
assert_eq!(e.var("KEY2").as_deref(), Some("value2"));
assert_eq!(e.var("NON_EXISTENT_KEY"), None);
assert_eq!(e.set_var("NON_EXISTENT_KEY", "value"), None);
assert_eq!(e.remove_var("NON_EXISTENT_KEY"), Some("value".to_string()));
assert_eq!(e.set_var("KEY1", "new_value"), Some("value1".to_string()));
assert_eq!(
e.vars().collect::<Vec<_>>(),
vec![
("KEY1".to_string(), "new_value".to_string()),
("KEY2".to_string(), "value2".to_string())
]
);
}
#[cfg(feature = "request")]
#[test]
fn with_env_should_pass_proxy_variables_to_request() {
let test_env = TestEnv::new().with_vars(vec![("HTTPS_PROXY", "http://proxy")]);
let test_platform = test_platform().with_env(test_env);
assert_eq!(
test_platform.request.clients.reqwest_env(),
reqwest_env("http://proxy")
);
}
#[cfg(feature = "fs")]
#[test]
fn with_env_should_set_current_dir_of_fs() {
use crate::Fs;
let test_platform = test_platform().with_fs(crate::TestFs::new());
let test_platform = test_platform.with_env(TestEnv::new().with_current_dir(HOME));
test_platform.fs().create_dir_all(HOME).unwrap();
assert_eq!(
test_platform.fs().canonicalize(".").unwrap(),
std::path::Path::new(HOME)
);
}
#[cfg(feature = "process")]
#[test]
fn with_env_should_set_current_dir_of_process() {
let test_platform = test_platform()
.with_process(crate::TestProcess::new())
.with_env(TestEnv::new().with_current_dir(HOME));
assert_eq!(
test_platform.process.current_dir(),
std::path::Path::new(HOME)
);
}
#[cfg(feature = "process")]
#[test]
fn with_env_should_not_record_vars_as_process_changes() {
use crate::CommandExt;
let test_platform =
test_platform().with_env(TestEnv::new().with_vars(vec![("KEY", "value")]));
test_platform.process.set_output(
"git",
crate::CommandOutput {
status: Some(0),
..Default::default()
},
);
std::process::Command::new("git")
.run(test_platform.process())
.unwrap();
assert_eq!(test_platform.process.call_details()[0].vars, []);
}
}
#[cfg(feature = "process")]
mod with_process {
use super::*;
#[test]
fn with_process_should_take_current_dir_of_env() {
let test_platform = test_platform()
.with_env(TestEnv::new().with_current_dir(HOME))
.with_process(crate::TestProcess::new());
assert_eq!(
test_platform.process.current_dir(),
std::path::Path::new(HOME)
);
}
}
#[cfg(feature = "request")]
mod with_request {
use super::*;
#[test]
fn with_request_should_pass_proxy_variables_of_env() {
let test_env = TestEnv::new().with_vars(vec![("HTTPS_PROXY", "http://proxy")]);
let test_platform = test_platform()
.with_env(test_env)
.with_request(crate::TestRequest::new());
assert_eq!(
test_platform.request.clients.reqwest_env(),
reqwest_env("http://proxy")
);
}
}
#[cfg(feature = "fs")]
mod with_fs {
use super::*;
use crate::Fs;
#[test]
fn with_fs_should_set_custom_test_filesystem() {
let test_fs = crate::TestFs::new();
let test_platform = test_platform().with_fs(test_fs);
test_platform.env().set_current_dir("/tmp");
test_platform.fs().create_dir_all("/tmp").unwrap();
test_platform.fs().write("/tmp/file.txt", "hello").unwrap();
assert_eq!(
test_platform.fs().read("/tmp/file.txt").unwrap(),
vec![b'h', b'e', b'l', b'l', b'o'],
);
assert_eq!(
test_platform.fs().read_to_string("/tmp/file.txt").unwrap(),
"hello",
);
}
#[test]
fn with_fs_should_take_current_dir_of_env() {
let test_platform = test_platform().with_env(TestEnv::new().with_current_dir(HOME));
let test_platform = test_platform.with_fs(crate::TestFs::new());
test_platform.fs().create_dir_all(HOME).unwrap();
assert_eq!(
test_platform.fs().canonicalize(".").unwrap(),
std::path::Path::new(HOME)
);
}
}
mod platform {
use super::*;
mod env {
use super::*;
#[test]
fn env_set_var_should_update_env() {
let test_platform = test_platform();
test_platform.env().set_var("KEY", "value");
assert_eq!(test_platform.env.var("KEY").as_deref(), Some("value"));
}
#[cfg(all(feature = "fs", feature = "process"))]
#[test]
fn env_set_current_dir_should_update_fs_and_process() {
use crate::Fs;
let test_platform = test_platform();
test_platform.fs().create_dir_all("/tmp").unwrap();
#[cfg(unix)]
const CURRENT_DIR: &str = "/tmp";
#[cfg(windows)]
const CURRENT_DIR: &str = "C:\\tmp";
test_platform.env().set_current_dir(CURRENT_DIR);
assert_eq!(
test_platform.fs().canonicalize(".").unwrap(),
std::path::Path::new(CURRENT_DIR)
);
assert_eq!(
test_platform.env.current_dir(),
std::path::Path::new(CURRENT_DIR)
);
assert_eq!(
test_platform.process.current_dir(),
std::path::Path::new(CURRENT_DIR)
);
}
#[cfg(all(feature = "fs", feature = "process"))]
#[test]
fn env_set_current_dir_relative_should_pass_resolved_dir_to_fs_and_process() {
use crate::Fs;
let test_platform =
test_platform().with_env(TestEnv::new().with_current_dir(HOME));
test_platform.fs().create_dir_all(HOME).unwrap();
let expected = std::path::Path::new(HOME).join("a");
test_platform.fs().create_dir_all("a").unwrap();
test_platform.env().set_current_dir("b/../a/.");
assert_eq!(test_platform.env.current_dir(), expected);
assert_eq!(test_platform.fs().canonicalize(".").unwrap(), expected);
assert_eq!(test_platform.process.current_dir(), expected);
}
#[cfg(feature = "process")]
#[test]
fn env_set_and_remove_var_should_be_applied_to_commands() {
use crate::CommandExt;
let test_platform = test_platform();
test_platform.process.set_output(
"git",
crate::CommandOutput {
status: Some(0),
..Default::default()
},
);
test_platform.env().set_var("SET", "value");
test_platform.env().remove_var("REMOVED");
std::process::Command::new("git")
.run(test_platform.process())
.unwrap();
assert_eq!(
test_platform.process.call_details()[0].vars,
[
("SET".to_string(), Some("value".to_string())),
("REMOVED".to_string(), None)
]
);
}
#[cfg(feature = "request")]
#[test]
fn env_set_and_remove_var_should_update_request_proxy_variables() {
let test_platform = test_platform();
test_platform.env().set_var("HTTPS_PROXY", "http://proxy");
let set = test_platform.request.clients.reqwest_env();
test_platform.env().remove_var("HTTPS_PROXY");
assert_eq!(set, reqwest_env("http://proxy"));
assert_eq!(
test_platform.request.clients.reqwest_env(),
crate::request::ReqwestEnv::default()
);
}
#[cfg(feature = "fs")]
#[test]
fn env_set_current_dir_should_be_seen_by_platform_shared_in_arc() {
use crate::Fs;
use std::sync::Arc;
let platform =
Arc::new(test_platform().with_env(TestEnv::new().with_current_dir(HOME)));
platform.fs().create_dir_all("a").unwrap();
let shared = platform.clone();
std::thread::spawn(move || shared.env().set_current_dir("a"))
.join()
.unwrap();
assert_eq!(
platform.fs().canonicalize(".").unwrap(),
std::path::Path::new(HOME).join("a")
);
}
}
}
}
}