diff --git a/crates/cargo-test-support/src/lib.rs b/crates/cargo-test-support/src/lib.rs index 17e01d14de1..36fa9d2dabc 100644 --- a/crates/cargo-test-support/src/lib.rs +++ b/crates/cargo-test-support/src/lib.rs @@ -70,20 +70,36 @@ pub mod tools; struct FileBuilder { path: PathBuf, body: String, + executable: bool, } impl FileBuilder { - pub fn new(path: PathBuf, body: &str) -> FileBuilder { + pub fn new(path: PathBuf, body: &str, executable: bool) -> FileBuilder { FileBuilder { path, body: body.to_string(), + executable: executable, } } - fn mk(&self) { + fn mk(&mut self) { + if self.executable { + self.path.set_extension(env::consts::EXE_EXTENSION); + } + self.dirname().mkdir_p(); fs::write(&self.path, &self.body) .unwrap_or_else(|e| panic!("could not create file {}: {}", self.path.display(), e)); + + #[cfg(unix)] + if self.executable { + use std::os::unix::fs::PermissionsExt; + + let mut perms = fs::metadata(&self.path).unwrap().permissions(); + let mode = perms.mode(); + perms.set_mode(mode | 0o111); + fs::set_permissions(&self.path, perms).unwrap(); + } } fn dirname(&self) -> &Path { @@ -122,11 +138,16 @@ impl SymlinkBuilder { } #[cfg(windows)] - fn mk(&self) { + fn mk(&mut self) { self.dirname().mkdir_p(); if self.src_is_dir { t!(os::windows::fs::symlink_dir(&self.dst, &self.src)); } else { + if let Some(ext) = self.dst.extension() { + if ext == env::consts::EXE_EXTENSION { + self.src.set_extension(ext); + } + } t!(os::windows::fs::symlink_file(&self.dst, &self.src)); } } @@ -177,13 +198,22 @@ impl ProjectBuilder { /// Adds a file to the project. pub fn file>(mut self, path: B, body: &str) -> Self { - self._file(path.as_ref(), body); + self._file(path.as_ref(), body, false); self } - fn _file(&mut self, path: &Path, body: &str) { - self.files - .push(FileBuilder::new(self.root.root().join(path), body)); + /// Adds an executable file to the project. + pub fn executable>(mut self, path: B, body: &str) -> Self { + self._file(path.as_ref(), body, true); + self + } + + fn _file(&mut self, path: &Path, body: &str, executable: bool) { + self.files.push(FileBuilder::new( + self.root.root().join(path), + body, + executable, + )); } /// Adds a symlink to a file to the project. @@ -219,13 +249,17 @@ impl ProjectBuilder { let manifest_path = self.root.root().join("Cargo.toml"); if !self.no_manifest && self.files.iter().all(|fb| fb.path != manifest_path) { - self._file(Path::new("Cargo.toml"), &basic_manifest("foo", "0.0.1")) + self._file( + Path::new("Cargo.toml"), + &basic_manifest("foo", "0.0.1"), + false, + ) } let past = time::SystemTime::now() - Duration::new(1, 0); let ftime = filetime::FileTime::from_system_time(past); - for file in self.files.iter() { + for file in self.files.iter_mut() { file.mk(); if is_coarse_mtime() { // Place the entire project 1 second in the past to ensure @@ -237,7 +271,7 @@ impl ProjectBuilder { } } - for symlink in self.symlinks.iter() { + for symlink in self.symlinks.iter_mut() { symlink.mk(); } @@ -316,7 +350,7 @@ impl Project { /// Changes the contents of an existing file. pub fn change_file(&self, path: &str, body: &str) { - FileBuilder::new(self.root().join(path), body).mk() + FileBuilder::new(self.root().join(path), body, false).mk() } /// Creates a `ProcessBuilder` to run a program in the project diff --git a/tests/testsuite/cargo_command.rs b/tests/testsuite/cargo_command.rs index 492f4c0aae9..7be5ccf25a0 100644 --- a/tests/testsuite/cargo_command.rs +++ b/tests/testsuite/cargo_command.rs @@ -1,63 +1,16 @@ //! Tests for custom cargo commands and other global command features. use std::env; -use std::fs::{self, File}; +use std::fs; use std::io::Read; use std::path::{Path, PathBuf}; use std::process::Stdio; use std::str; use cargo_test_support::cargo_process; -use cargo_test_support::paths::{self, CargoPathExt}; +use cargo_test_support::paths; use cargo_test_support::registry::Package; -use cargo_test_support::{basic_bin_manifest, basic_manifest, cargo_exe, project, Project}; - -#[cfg_attr(windows, allow(dead_code))] -enum FakeKind<'a> { - Executable, - Symlink { target: &'a Path }, -} - -/// Adds an empty file with executable flags (and platform-dependent suffix). -// -// TODO: move this to `Project` if other cases using this emerge. -fn fake_file(proj: Project, dir: &Path, name: &str, kind: &FakeKind<'_>) -> Project { - let path = proj - .root() - .join(dir) - .join(&format!("{}{}", name, env::consts::EXE_SUFFIX)); - path.parent().unwrap().mkdir_p(); - match *kind { - FakeKind::Executable => { - File::create(&path).unwrap(); - make_executable(&path); - } - FakeKind::Symlink { target } => { - make_symlink(&path, target); - } - } - return proj; - - #[cfg(unix)] - fn make_executable(p: &Path) { - use std::os::unix::prelude::*; - - let mut perms = fs::metadata(p).unwrap().permissions(); - let mode = perms.mode(); - perms.set_mode(mode | 0o111); - fs::set_permissions(p, perms).unwrap(); - } - #[cfg(windows)] - fn make_executable(_: &Path) {} - #[cfg(unix)] - fn make_symlink(p: &Path, t: &Path) { - ::std::os::unix::fs::symlink(t, p).expect("Failed to create symlink"); - } - #[cfg(windows)] - fn make_symlink(_: &Path, _: &Path) { - panic!("Not supported") - } -} +use cargo_test_support::{basic_bin_manifest, basic_manifest, cargo_exe, project}; fn path() -> Vec { env::split_paths(&env::var_os("PATH").unwrap_or_default()).collect() @@ -91,13 +44,9 @@ fn list_aliases_with_descriptions() { #[cargo_test] fn list_command_looks_at_path() { - let proj = project().build(); - let proj = fake_file( - proj, - Path::new("path-test"), - "cargo-1", - &FakeKind::Executable, - ); + let proj = project() + .executable(Path::new("path-test").join("cargo-1"), "") + .build(); let mut path = path(); path.push(proj.root().join("path-test")); @@ -114,19 +63,11 @@ fn list_command_looks_at_path() { ); } -// Windows and symlinks don't currently mix well. -#[cfg(unix)] #[cargo_test] fn list_command_resolves_symlinks() { - let proj = project().build(); - let proj = fake_file( - proj, - Path::new("path-test"), - "cargo-2", - &FakeKind::Symlink { - target: &cargo_exe(), - }, - ); + let proj = project() + .symlink(cargo_exe(), Path::new("path-test").join("cargo-2")) + .build(); let mut path = path(); path.push(proj.root().join("path-test"));