1 extern crate tempdir;
2 extern crate which;
3
4 use std::env;
5 use std::ffi::{OsStr, OsString};
6 use std::fs;
7 use std::io;
8 use std::path::{Path, PathBuf};
9 use tempdir::TempDir;
10
11 struct TestFixture {
12 /// Temp directory.
13 pub tempdir: TempDir,
14 /// $PATH
15 pub paths: OsString,
16 /// Binaries created in $PATH
17 pub bins: Vec<PathBuf>,
18 }
19
20 const SUBDIRS: &'static [&'static str] = &["a", "b", "c"];
21 const BIN_NAME: &'static str = "bin";
22
23 #[cfg(unix)]
mk_bin(dir: &Path, path: &str, extension: &str) -> io::Result<PathBuf>24 fn mk_bin(dir: &Path, path: &str, extension: &str) -> io::Result<PathBuf> {
25 use std::os::unix::fs::OpenOptionsExt;
26 let bin = dir.join(path).with_extension(extension);
27 fs::OpenOptions::new()
28 .write(true)
29 .create(true)
30 .mode(0o666 | (libc::S_IXUSR as u32))
31 .open(&bin)
32 .and_then(|_f| bin.canonicalize())
33 }
34
touch(dir: &Path, path: &str, extension: &str) -> io::Result<PathBuf>35 fn touch(dir: &Path, path: &str, extension: &str) -> io::Result<PathBuf> {
36 let b = dir.join(path).with_extension(extension);
37 fs::File::create(&b).and_then(|_f| b.canonicalize())
38 }
39
40 #[cfg(windows)]
mk_bin(dir: &Path, path: &str, extension: &str) -> io::Result<PathBuf>41 fn mk_bin(dir: &Path, path: &str, extension: &str) -> io::Result<PathBuf> {
42 touch(dir, path, extension)
43 }
44
45 impl TestFixture {
46 // tmp/a/bin
47 // tmp/a/bin.exe
48 // tmp/a/bin.cmd
49 // tmp/b/bin
50 // tmp/b/bin.exe
51 // tmp/b/bin.cmd
52 // tmp/c/bin
53 // tmp/c/bin.exe
54 // tmp/c/bin.cmd
new() -> TestFixture55 pub fn new() -> TestFixture {
56 let tempdir = TempDir::new("which_tests").unwrap();
57 let mut builder = fs::DirBuilder::new();
58 builder.recursive(true);
59 let mut paths = vec![];
60 let mut bins = vec![];
61 for d in SUBDIRS.iter() {
62 let p = tempdir.path().join(d);
63 builder.create(&p).unwrap();
64 bins.push(mk_bin(&p, &BIN_NAME, "").unwrap());
65 bins.push(mk_bin(&p, &BIN_NAME, "exe").unwrap());
66 bins.push(mk_bin(&p, &BIN_NAME, "cmd").unwrap());
67 paths.push(p);
68 }
69 TestFixture {
70 tempdir: tempdir,
71 paths: env::join_paths(paths).unwrap(),
72 bins: bins,
73 }
74 }
75
76 #[allow(dead_code)]
touch(&self, path: &str, extension: &str) -> io::Result<PathBuf>77 pub fn touch(&self, path: &str, extension: &str) -> io::Result<PathBuf> {
78 touch(self.tempdir.path(), &path, &extension)
79 }
80
mk_bin(&self, path: &str, extension: &str) -> io::Result<PathBuf>81 pub fn mk_bin(&self, path: &str, extension: &str) -> io::Result<PathBuf> {
82 mk_bin(self.tempdir.path(), &path, &extension)
83 }
84 }
85
_which<T: AsRef<OsStr>>(f: &TestFixture, path: T) -> which::Result<which::CanonicalPath>86 fn _which<T: AsRef<OsStr>>(f: &TestFixture, path: T) -> which::Result<which::CanonicalPath> {
87 which::CanonicalPath::new_in(path, Some(f.paths.clone()), f.tempdir.path())
88 }
89
_which_all<T: AsRef<OsStr>>( f: &TestFixture, path: T, ) -> which::Result<impl Iterator<Item = which::Result<which::CanonicalPath>>>90 fn _which_all<T: AsRef<OsStr>>(
91 f: &TestFixture,
92 path: T,
93 ) -> which::Result<impl Iterator<Item = which::Result<which::CanonicalPath>>> {
94 which::CanonicalPath::all_in(path, Some(f.paths.clone()), f.tempdir.path().to_path_buf())
95 }
96
97 #[test]
98 #[cfg(unix)]
it_works()99 fn it_works() {
100 use std::process::Command;
101 let result = which::Path::new("rustc");
102 assert!(result.is_ok());
103
104 let which_result = Command::new("which").arg("rustc").output();
105
106 assert_eq!(
107 String::from(result.unwrap().to_str().unwrap()),
108 String::from_utf8(which_result.unwrap().stdout)
109 .unwrap()
110 .trim()
111 );
112 }
113
114 #[test]
115 #[cfg(unix)]
test_which()116 fn test_which() {
117 let f = TestFixture::new();
118 assert_eq!(_which(&f, &BIN_NAME).unwrap(), f.bins[0])
119 }
120
121 #[test]
122 #[cfg(windows)]
test_which()123 fn test_which() {
124 let f = TestFixture::new();
125 assert_eq!(_which(&f, &BIN_NAME).unwrap(), f.bins[1])
126 }
127
128 #[test]
129 #[cfg(unix)]
test_which_extension()130 fn test_which_extension() {
131 let f = TestFixture::new();
132 let b = Path::new(&BIN_NAME).with_extension("");
133 assert_eq!(_which(&f, &b).unwrap(), f.bins[0])
134 }
135
136 #[test]
137 #[cfg(windows)]
test_which_extension()138 fn test_which_extension() {
139 let f = TestFixture::new();
140 let b = Path::new(&BIN_NAME).with_extension("cmd");
141 assert_eq!(_which(&f, &b).unwrap(), f.bins[2])
142 }
143
144 #[test]
test_which_not_found()145 fn test_which_not_found() {
146 let f = TestFixture::new();
147 assert!(_which(&f, "a").is_err());
148 }
149
150 #[test]
test_which_second()151 fn test_which_second() {
152 let f = TestFixture::new();
153 let b = f.mk_bin("b/another", env::consts::EXE_EXTENSION).unwrap();
154 assert_eq!(_which(&f, "another").unwrap(), b);
155 }
156
157 #[test]
test_which_all()158 fn test_which_all() {
159 let f = TestFixture::new();
160 let actual = _which_all(&f, BIN_NAME)
161 .unwrap()
162 .map(|c| c.unwrap())
163 .collect::<Vec<_>>();
164 let mut expected = f
165 .bins
166 .iter()
167 .map(|p| p.canonicalize().unwrap())
168 .collect::<Vec<_>>();
169 #[cfg(windows)]
170 {
171 expected.retain(|p| p.extension().map(|ext| ext == "exe" || ext == "cmd") == Some(true));
172 }
173 #[cfg(not(windows))]
174 {
175 expected.retain(|p| p.file_name().unwrap() == BIN_NAME);
176 }
177 assert_eq!(actual, expected);
178 }
179
180 #[test]
181 #[cfg(unix)]
test_which_absolute()182 fn test_which_absolute() {
183 let f = TestFixture::new();
184 assert_eq!(
185 _which(&f, &f.bins[3]).unwrap(),
186 f.bins[3].canonicalize().unwrap()
187 );
188 }
189
190 #[test]
191 #[cfg(windows)]
test_which_absolute()192 fn test_which_absolute() {
193 let f = TestFixture::new();
194 assert_eq!(
195 _which(&f, &f.bins[4]).unwrap(),
196 f.bins[4].canonicalize().unwrap()
197 );
198 }
199
200 #[test]
201 #[cfg(windows)]
test_which_absolute_path_case()202 fn test_which_absolute_path_case() {
203 // Test that an absolute path with an uppercase extension
204 // is accepted.
205 let f = TestFixture::new();
206 let p = &f.bins[4];
207 assert_eq!(_which(&f, &p).unwrap(), f.bins[4].canonicalize().unwrap());
208 }
209
210 #[test]
211 #[cfg(unix)]
test_which_absolute_extension()212 fn test_which_absolute_extension() {
213 let f = TestFixture::new();
214 // Don't append EXE_EXTENSION here.
215 let b = f.bins[3].parent().unwrap().join(&BIN_NAME);
216 assert_eq!(_which(&f, &b).unwrap(), f.bins[3].canonicalize().unwrap());
217 }
218
219 #[test]
220 #[cfg(windows)]
test_which_absolute_extension()221 fn test_which_absolute_extension() {
222 let f = TestFixture::new();
223 // Don't append EXE_EXTENSION here.
224 let b = f.bins[4].parent().unwrap().join(&BIN_NAME);
225 assert_eq!(_which(&f, &b).unwrap(), f.bins[4].canonicalize().unwrap());
226 }
227
228 #[test]
229 #[cfg(unix)]
test_which_relative()230 fn test_which_relative() {
231 let f = TestFixture::new();
232 assert_eq!(
233 _which(&f, "b/bin").unwrap(),
234 f.bins[3].canonicalize().unwrap()
235 );
236 }
237
238 #[test]
239 #[cfg(windows)]
test_which_relative()240 fn test_which_relative() {
241 let f = TestFixture::new();
242 assert_eq!(
243 _which(&f, "b/bin").unwrap(),
244 f.bins[4].canonicalize().unwrap()
245 );
246 }
247
248 #[test]
249 #[cfg(unix)]
test_which_relative_extension()250 fn test_which_relative_extension() {
251 // test_which_relative tests a relative path without an extension,
252 // so test a relative path with an extension here.
253 let f = TestFixture::new();
254 let b = Path::new("b/bin").with_extension(env::consts::EXE_EXTENSION);
255 assert_eq!(_which(&f, &b).unwrap(), f.bins[3].canonicalize().unwrap());
256 }
257
258 #[test]
259 #[cfg(windows)]
test_which_relative_extension()260 fn test_which_relative_extension() {
261 // test_which_relative tests a relative path without an extension,
262 // so test a relative path with an extension here.
263 let f = TestFixture::new();
264 let b = Path::new("b/bin").with_extension("cmd");
265 assert_eq!(_which(&f, &b).unwrap(), f.bins[5].canonicalize().unwrap());
266 }
267
268 #[test]
269 #[cfg(windows)]
test_which_relative_extension_case()270 fn test_which_relative_extension_case() {
271 // Test that a relative path with an uppercase extension
272 // is accepted.
273 let f = TestFixture::new();
274 let b = Path::new("b/bin").with_extension("EXE");
275 assert_eq!(_which(&f, &b).unwrap(), f.bins[4].canonicalize().unwrap());
276 }
277
278 #[test]
279 #[cfg(unix)]
test_which_relative_leading_dot()280 fn test_which_relative_leading_dot() {
281 let f = TestFixture::new();
282 assert_eq!(
283 _which(&f, "./b/bin").unwrap(),
284 f.bins[3].canonicalize().unwrap()
285 );
286 }
287
288 #[test]
289 #[cfg(windows)]
test_which_relative_leading_dot()290 fn test_which_relative_leading_dot() {
291 let f = TestFixture::new();
292 assert_eq!(
293 _which(&f, "./b/bin").unwrap(),
294 f.bins[4].canonicalize().unwrap()
295 );
296 }
297
298 #[test]
299 #[cfg(unix)]
test_which_non_executable()300 fn test_which_non_executable() {
301 // Shouldn't return non-executable files.
302 let f = TestFixture::new();
303 f.touch("b/another", "").unwrap();
304 assert!(_which(&f, "another").is_err());
305 }
306
307 #[test]
308 #[cfg(unix)]
test_which_absolute_non_executable()309 fn test_which_absolute_non_executable() {
310 // Shouldn't return non-executable files, even if given an absolute path.
311 let f = TestFixture::new();
312 let b = f.touch("b/another", "").unwrap();
313 assert!(_which(&f, &b).is_err());
314 }
315
316 #[test]
317 #[cfg(unix)]
test_which_relative_non_executable()318 fn test_which_relative_non_executable() {
319 // Shouldn't return non-executable files.
320 let f = TestFixture::new();
321 f.touch("b/another", "").unwrap();
322 assert!(_which(&f, "b/another").is_err());
323 }
324
325 #[test]
test_failure()326 fn test_failure() {
327 let f = TestFixture::new();
328
329 let run = || -> which::Result<PathBuf> {
330 let p = _which(&f, "./b/bin")?;
331 Ok(p.into_path_buf())
332 };
333
334 let _ = run();
335 }
336