• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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