| extern crate tempdir; |
| extern crate which; |
| |
| #[cfg(feature = "regex")] |
| use regex::Regex; |
| use std::ffi::{OsStr, OsString}; |
| use std::fs; |
| use std::io; |
| use std::path::{Path, PathBuf}; |
| use std::{env, vec}; |
| use tempdir::TempDir; |
| |
| struct TestFixture { |
| /// Temp directory. |
| pub tempdir: TempDir, |
| /// $PATH |
| pub paths: OsString, |
| /// Binaries created in $PATH |
| pub bins: Vec<PathBuf>, |
| } |
| |
| const SUBDIRS: &'static [&'static str] = &["a", "b", "c"]; |
| const BIN_NAME: &'static str = "bin"; |
| |
| #[cfg(unix)] |
| fn mk_bin(dir: &Path, path: &str, extension: &str) -> io::Result<PathBuf> { |
| use std::os::unix::fs::OpenOptionsExt; |
| let bin = dir.join(path).with_extension(extension); |
| fs::OpenOptions::new() |
| .write(true) |
| .create(true) |
| .mode(0o666 | (libc::S_IXUSR as u32)) |
| .open(&bin) |
| .and_then(|_f| bin.canonicalize()) |
| } |
| |
| fn touch(dir: &Path, path: &str, extension: &str) -> io::Result<PathBuf> { |
| let b = dir.join(path).with_extension(extension); |
| fs::File::create(&b).and_then(|_f| b.canonicalize()) |
| } |
| |
| #[cfg(windows)] |
| fn mk_bin(dir: &Path, path: &str, extension: &str) -> io::Result<PathBuf> { |
| touch(dir, path, extension) |
| } |
| |
| impl TestFixture { |
| // tmp/a/bin |
| // tmp/a/bin.exe |
| // tmp/a/bin.cmd |
| // tmp/b/bin |
| // tmp/b/bin.exe |
| // tmp/b/bin.cmd |
| // tmp/c/bin |
| // tmp/c/bin.exe |
| // tmp/c/bin.cmd |
| pub fn new() -> TestFixture { |
| let tempdir = TempDir::new("which_tests").unwrap(); |
| let mut builder = fs::DirBuilder::new(); |
| builder.recursive(true); |
| let mut paths = vec![]; |
| let mut bins = vec![]; |
| for d in SUBDIRS.iter() { |
| let p = tempdir.path().join(d); |
| builder.create(&p).unwrap(); |
| bins.push(mk_bin(&p, &BIN_NAME, "").unwrap()); |
| bins.push(mk_bin(&p, &BIN_NAME, "exe").unwrap()); |
| bins.push(mk_bin(&p, &BIN_NAME, "cmd").unwrap()); |
| paths.push(p); |
| } |
| TestFixture { |
| tempdir: tempdir, |
| paths: env::join_paths(paths).unwrap(), |
| bins: bins, |
| } |
| } |
| |
| #[allow(dead_code)] |
| pub fn touch(&self, path: &str, extension: &str) -> io::Result<PathBuf> { |
| touch(self.tempdir.path(), &path, &extension) |
| } |
| |
| pub fn mk_bin(&self, path: &str, extension: &str) -> io::Result<PathBuf> { |
| mk_bin(self.tempdir.path(), &path, &extension) |
| } |
| } |
| |
| fn _which<T: AsRef<OsStr>>(f: &TestFixture, path: T) -> which::Result<which::CanonicalPath> { |
| which::CanonicalPath::new_in(path, Some(f.paths.clone()), f.tempdir.path()) |
| } |
| |
| fn _which_all<T: AsRef<OsStr>>( |
| f: &TestFixture, |
| path: T, |
| ) -> which::Result<impl Iterator<Item = which::Result<which::CanonicalPath>>> { |
| which::CanonicalPath::all_in(path, Some(f.paths.clone()), f.tempdir.path().to_path_buf()) |
| } |
| |
| #[test] |
| #[cfg(unix)] |
| fn it_works() { |
| use std::process::Command; |
| let result = which::Path::new("rustc"); |
| assert!(result.is_ok()); |
| |
| let which_result = Command::new("which").arg("rustc").output(); |
| |
| assert_eq!( |
| String::from(result.unwrap().to_str().unwrap()), |
| String::from_utf8(which_result.unwrap().stdout) |
| .unwrap() |
| .trim() |
| ); |
| } |
| |
| #[test] |
| #[cfg(unix)] |
| fn test_which() { |
| let f = TestFixture::new(); |
| assert_eq!(_which(&f, &BIN_NAME).unwrap(), f.bins[0]) |
| } |
| |
| #[test] |
| #[cfg(windows)] |
| fn test_which() { |
| let f = TestFixture::new(); |
| assert_eq!(_which(&f, &BIN_NAME).unwrap(), f.bins[1]) |
| } |
| |
| #[test] |
| #[cfg(all(unix, feature = "regex"))] |
| fn test_which_re_in_with_matches() { |
| let f = TestFixture::new(); |
| f.mk_bin("a/bin_0", "").unwrap(); |
| f.mk_bin("b/bin_1", "").unwrap(); |
| let re = Regex::new(r"bin_\d").unwrap(); |
| |
| let result: Vec<PathBuf> = which::which_re_in(re, Some(f.paths)) |
| .unwrap() |
| .into_iter() |
| .collect(); |
| |
| let temp = f.tempdir; |
| |
| assert_eq!( |
| result, |
| vec![temp.path().join("a/bin_0"), temp.path().join("b/bin_1")] |
| ) |
| } |
| |
| #[test] |
| #[cfg(all(unix, feature = "regex"))] |
| fn test_which_re_in_without_matches() { |
| let f = TestFixture::new(); |
| let re = Regex::new(r"bi[^n]").unwrap(); |
| |
| let result: Vec<PathBuf> = which::which_re_in(re, Some(f.paths)) |
| .unwrap() |
| .into_iter() |
| .collect(); |
| |
| assert_eq!(result, Vec::<PathBuf>::new()) |
| } |
| |
| #[test] |
| #[cfg(all(unix, feature = "regex"))] |
| fn test_which_re_accepts_owned_and_borrow() { |
| which::which_re(Regex::new(r".").unwrap()); |
| which::which_re(&Regex::new(r".").unwrap()); |
| which::which_re_in(Regex::new(r".").unwrap(), Some("pth")); |
| which::which_re_in(&Regex::new(r".").unwrap(), Some("pth")); |
| } |
| |
| #[test] |
| #[cfg(unix)] |
| fn test_which_extension() { |
| let f = TestFixture::new(); |
| let b = Path::new(&BIN_NAME).with_extension(""); |
| assert_eq!(_which(&f, &b).unwrap(), f.bins[0]) |
| } |
| |
| #[test] |
| #[cfg(windows)] |
| fn test_which_extension() { |
| let f = TestFixture::new(); |
| let b = Path::new(&BIN_NAME).with_extension("cmd"); |
| assert_eq!(_which(&f, &b).unwrap(), f.bins[2]) |
| } |
| |
| #[test] |
| fn test_which_not_found() { |
| let f = TestFixture::new(); |
| assert!(_which(&f, "a").is_err()); |
| } |
| |
| #[test] |
| fn test_which_second() { |
| let f = TestFixture::new(); |
| let b = f.mk_bin("b/another", env::consts::EXE_EXTENSION).unwrap(); |
| assert_eq!(_which(&f, "another").unwrap(), b); |
| } |
| |
| #[test] |
| fn test_which_all() { |
| let f = TestFixture::new(); |
| let actual = _which_all(&f, BIN_NAME) |
| .unwrap() |
| .map(|c| c.unwrap()) |
| .collect::<Vec<_>>(); |
| let mut expected = f |
| .bins |
| .iter() |
| .map(|p| p.canonicalize().unwrap()) |
| .collect::<Vec<_>>(); |
| #[cfg(windows)] |
| { |
| expected.retain(|p| p.extension().map(|ext| ext == "exe" || ext == "cmd") == Some(true)); |
| } |
| #[cfg(not(windows))] |
| { |
| expected.retain(|p| p.file_name().unwrap() == BIN_NAME); |
| } |
| assert_eq!(actual, expected); |
| } |
| |
| #[test] |
| #[cfg(unix)] |
| fn test_which_absolute() { |
| let f = TestFixture::new(); |
| assert_eq!( |
| _which(&f, &f.bins[3]).unwrap(), |
| f.bins[3].canonicalize().unwrap() |
| ); |
| } |
| |
| #[test] |
| #[cfg(windows)] |
| fn test_which_absolute() { |
| let f = TestFixture::new(); |
| assert_eq!( |
| _which(&f, &f.bins[4]).unwrap(), |
| f.bins[4].canonicalize().unwrap() |
| ); |
| } |
| |
| #[test] |
| #[cfg(windows)] |
| fn test_which_absolute_path_case() { |
| // Test that an absolute path with an uppercase extension |
| // is accepted. |
| let f = TestFixture::new(); |
| let p = &f.bins[4]; |
| assert_eq!(_which(&f, &p).unwrap(), f.bins[4].canonicalize().unwrap()); |
| } |
| |
| #[test] |
| #[cfg(unix)] |
| fn test_which_absolute_extension() { |
| let f = TestFixture::new(); |
| // Don't append EXE_EXTENSION here. |
| let b = f.bins[3].parent().unwrap().join(&BIN_NAME); |
| assert_eq!(_which(&f, &b).unwrap(), f.bins[3].canonicalize().unwrap()); |
| } |
| |
| #[test] |
| #[cfg(windows)] |
| fn test_which_absolute_extension() { |
| let f = TestFixture::new(); |
| // Don't append EXE_EXTENSION here. |
| let b = f.bins[4].parent().unwrap().join(&BIN_NAME); |
| assert_eq!(_which(&f, &b).unwrap(), f.bins[4].canonicalize().unwrap()); |
| } |
| |
| #[test] |
| #[cfg(unix)] |
| fn test_which_relative() { |
| let f = TestFixture::new(); |
| assert_eq!( |
| _which(&f, "b/bin").unwrap(), |
| f.bins[3].canonicalize().unwrap() |
| ); |
| } |
| |
| #[test] |
| #[cfg(windows)] |
| fn test_which_relative() { |
| let f = TestFixture::new(); |
| assert_eq!( |
| _which(&f, "b/bin").unwrap(), |
| f.bins[4].canonicalize().unwrap() |
| ); |
| } |
| |
| #[test] |
| #[cfg(unix)] |
| fn test_which_relative_extension() { |
| // test_which_relative tests a relative path without an extension, |
| // so test a relative path with an extension here. |
| let f = TestFixture::new(); |
| let b = Path::new("b/bin").with_extension(env::consts::EXE_EXTENSION); |
| assert_eq!(_which(&f, &b).unwrap(), f.bins[3].canonicalize().unwrap()); |
| } |
| |
| #[test] |
| #[cfg(windows)] |
| fn test_which_relative_extension() { |
| // test_which_relative tests a relative path without an extension, |
| // so test a relative path with an extension here. |
| let f = TestFixture::new(); |
| let b = Path::new("b/bin").with_extension("cmd"); |
| assert_eq!(_which(&f, &b).unwrap(), f.bins[5].canonicalize().unwrap()); |
| } |
| |
| #[test] |
| #[cfg(windows)] |
| fn test_which_relative_extension_case() { |
| // Test that a relative path with an uppercase extension |
| // is accepted. |
| let f = TestFixture::new(); |
| let b = Path::new("b/bin").with_extension("EXE"); |
| assert_eq!(_which(&f, &b).unwrap(), f.bins[4].canonicalize().unwrap()); |
| } |
| |
| #[test] |
| #[cfg(unix)] |
| fn test_which_relative_leading_dot() { |
| let f = TestFixture::new(); |
| assert_eq!( |
| _which(&f, "./b/bin").unwrap(), |
| f.bins[3].canonicalize().unwrap() |
| ); |
| } |
| |
| #[test] |
| #[cfg(windows)] |
| fn test_which_relative_leading_dot() { |
| let f = TestFixture::new(); |
| assert_eq!( |
| _which(&f, "./b/bin").unwrap(), |
| f.bins[4].canonicalize().unwrap() |
| ); |
| } |
| |
| #[test] |
| #[cfg(unix)] |
| fn test_which_non_executable() { |
| // Shouldn't return non-executable files. |
| let f = TestFixture::new(); |
| f.touch("b/another", "").unwrap(); |
| assert!(_which(&f, "another").is_err()); |
| } |
| |
| #[test] |
| #[cfg(unix)] |
| fn test_which_absolute_non_executable() { |
| // Shouldn't return non-executable files, even if given an absolute path. |
| let f = TestFixture::new(); |
| let b = f.touch("b/another", "").unwrap(); |
| assert!(_which(&f, &b).is_err()); |
| } |
| |
| #[test] |
| #[cfg(unix)] |
| fn test_which_relative_non_executable() { |
| // Shouldn't return non-executable files. |
| let f = TestFixture::new(); |
| f.touch("b/another", "").unwrap(); |
| assert!(_which(&f, "b/another").is_err()); |
| } |
| |
| #[test] |
| fn test_failure() { |
| let f = TestFixture::new(); |
| |
| let run = || -> which::Result<PathBuf> { |
| let p = _which(&f, "./b/bin")?; |
| Ok(p.into_path_buf()) |
| }; |
| |
| let _ = run(); |
| } |