1 extern crate assert_cmd;
2 extern crate predicates;
3
4 use assert_cmd::prelude::*;
5 use assert_fs::prelude::*;
6 use predicates::prelude::*;
7 use std::process::Command;
8
9 #[cfg(unix)]
10 use std::os::unix::fs;
11
12 #[test]
test_runs_okay()13 fn test_runs_okay() {
14 cmd().assert().success();
15 }
16
17 #[test]
test_list_empty_directory()18 fn test_list_empty_directory() {
19 cmd()
20 .arg("--ignore-config")
21 .arg(tempdir().path())
22 .assert()
23 .stdout(predicate::eq(""));
24 }
25
26 #[test]
test_list_almost_all_empty_directory()27 fn test_list_almost_all_empty_directory() {
28 let matched = "";
29 cmd()
30 .arg("--almost-all")
31 .arg("--ignore-config")
32 .arg(tempdir().path())
33 .assert()
34 .stdout(predicate::eq(matched));
35
36 cmd()
37 .arg("-A")
38 .arg("--ignore-config")
39 .arg(tempdir().path())
40 .assert()
41 .stdout(predicate::eq(matched));
42 }
43
44 #[test]
test_list_all_empty_directory()45 fn test_list_all_empty_directory() {
46 let matched = "\\.\n\\.\\.\n$";
47 cmd()
48 .arg("--all")
49 .arg("--ignore-config")
50 .arg(tempdir().path())
51 .assert()
52 .stdout(predicate::str::is_match(matched).unwrap());
53
54 cmd()
55 .arg("-a")
56 .arg("--ignore-config")
57 .arg(tempdir().path())
58 .assert()
59 .stdout(predicate::str::is_match(matched).unwrap());
60 }
61
62 #[test]
test_list_populated_directory()63 fn test_list_populated_directory() {
64 let dir = tempdir();
65 dir.child("one").touch().unwrap();
66 dir.child("two").touch().unwrap();
67 cmd()
68 .arg("--ignore-config")
69 .arg(dir.path())
70 .assert()
71 .stdout(predicate::str::is_match("one\ntwo\n$").unwrap());
72 }
73
74 #[test]
test_list_almost_all_populated_directory()75 fn test_list_almost_all_populated_directory() {
76 let dir = tempdir();
77 dir.child("one").touch().unwrap();
78 dir.child("two").touch().unwrap();
79 cmd()
80 .arg("--almost-all")
81 .arg("--ignore-config")
82 .arg(dir.path())
83 .assert()
84 .stdout(predicate::str::is_match("one\ntwo\n$").unwrap());
85 }
86
87 #[test]
test_list_all_populated_directory()88 fn test_list_all_populated_directory() {
89 let dir = tempdir();
90 dir.child("one").touch().unwrap();
91 dir.child("two").touch().unwrap();
92 cmd()
93 .arg("--all")
94 .arg("--ignore-config")
95 .arg(dir.path())
96 .assert()
97 .stdout(predicate::str::is_match("\\.\n\\.\\.\none\ntwo\n$").unwrap());
98 }
99
100 #[test]
test_almost_sort_with_folder()101 fn test_almost_sort_with_folder() {
102 let tmp = tempdir();
103 tmp.child("z").create_dir_all().unwrap();
104 tmp.child("z/a").touch().unwrap();
105
106 cmd()
107 .current_dir(tmp.path())
108 .arg("-a")
109 .arg("--ignore-config")
110 .arg("z")
111 .assert()
112 .stdout(predicate::str::is_match("\\.\n\\.\\.\na\n$").unwrap());
113 }
114
115 #[test]
test_list_inode_populated_directory()116 fn test_list_inode_populated_directory() {
117 let dir = tempdir();
118 dir.child("one").touch().unwrap();
119 dir.child("two").touch().unwrap();
120
121 #[cfg(windows)]
122 let matched = "- one\n\\- two\n$";
123 #[cfg(unix)]
124 let matched = "\\d+ +one\n\\d+ +two\n$";
125
126 cmd()
127 .arg("--inode")
128 .arg("--ignore-config")
129 .arg(dir.path())
130 .assert()
131 .stdout(predicate::str::is_match(matched).unwrap());
132 cmd()
133 .arg("-i")
134 .arg("--ignore-config")
135 .arg(dir.path())
136 .assert()
137 .stdout(predicate::str::is_match(matched).unwrap());
138 }
139
140 #[test]
test_list_block_inode_populated_directory_without_long()141 fn test_list_block_inode_populated_directory_without_long() {
142 let dir = tempdir();
143 dir.child("one").touch().unwrap();
144 dir.child("two").touch().unwrap();
145
146 #[cfg(windows)]
147 let matched = "- one\n\\- two\n$";
148 #[cfg(unix)]
149 let matched = "\\d+ +one\n\\d+ +two\n$";
150
151 cmd()
152 .arg("--blocks")
153 .arg("inode,name")
154 .arg("--ignore-config")
155 .arg(dir.path())
156 .assert()
157 .stdout(predicate::str::is_match(matched).unwrap());
158 }
159
160 #[test]
test_list_block_inode_populated_directory_with_long()161 fn test_list_block_inode_populated_directory_with_long() {
162 let dir = tempdir();
163 dir.child("one").touch().unwrap();
164 dir.child("two").touch().unwrap();
165
166 #[cfg(windows)]
167 let matched = "- one\n\\- two\n$";
168 #[cfg(unix)]
169 let matched = "\\d+ +one\n\\d+ +two\n$";
170
171 cmd()
172 .arg("--long")
173 .arg("--blocks")
174 .arg("inode,name")
175 .arg("--ignore-config")
176 .arg(dir.path())
177 .assert()
178 .stdout(predicate::str::is_match(matched).unwrap());
179 }
180
181 #[test]
test_list_inode_with_long_ok()182 fn test_list_inode_with_long_ok() {
183 let dir = tempdir();
184 cmd()
185 .arg("-i")
186 .arg("-l")
187 .arg("--ignore-config")
188 .arg(dir.path())
189 .assert()
190 .success();
191 }
192
193 #[cfg(unix)]
194 #[test]
test_list_broken_link_ok()195 fn test_list_broken_link_ok() {
196 let dir = tempdir();
197 let broken_link = dir.path().join("broken-softlink");
198 let matched = "No such file or directory";
199 fs::symlink("not-existed-file", &broken_link).unwrap();
200
201 cmd()
202 .arg(&broken_link)
203 .arg("--ignore-config")
204 .assert()
205 .stderr(predicate::str::contains(matched).not());
206
207 cmd()
208 .arg("-l")
209 .arg("--ignore-config")
210 .arg(broken_link)
211 .assert()
212 .stderr(predicate::str::contains(matched).not());
213 }
214 #[cfg(unix)]
215 #[test]
test_nosymlink_on_non_long()216 fn test_nosymlink_on_non_long() {
217 let dir = tempdir();
218 dir.child("target").touch().unwrap();
219 let link = dir.path().join("link");
220 let link_icon = "⇒";
221 fs::symlink("target", &link).unwrap();
222
223 cmd()
224 .arg("-l")
225 .arg("--ignore-config")
226 .arg(&link)
227 .assert()
228 .stdout(predicate::str::contains(link_icon));
229
230 cmd()
231 .arg("--ignore-config")
232 .arg(&link)
233 .assert()
234 .stdout(predicate::str::contains(link_icon).not());
235 }
236
237 #[cfg(unix)]
238 #[test]
test_dereference_link_right_type_and_no_link()239 fn test_dereference_link_right_type_and_no_link() {
240 let dir = tempdir();
241 dir.child("target").touch().unwrap();
242 let link = dir.path().join("link");
243 let file_type = ".rw";
244 let link_icon = "⇒";
245 fs::symlink("target", &link).unwrap();
246
247 cmd()
248 .arg("-l")
249 .arg("--dereference")
250 .arg("--ignore-config")
251 .arg(&link)
252 .assert()
253 .stdout(predicate::str::starts_with(file_type))
254 .stdout(predicate::str::contains(link_icon).not());
255
256 cmd()
257 .arg("-l")
258 .arg("-L")
259 .arg("--ignore-config")
260 .arg(link)
261 .assert()
262 .stdout(predicate::str::starts_with(file_type))
263 .stdout(predicate::str::contains(link_icon).not());
264 }
265
266 #[cfg(unix)]
267 #[test]
test_show_folder_content_of_symlink()268 fn test_show_folder_content_of_symlink() {
269 let dir = tempdir();
270 dir.child("target").child("inside").touch().unwrap();
271 let link = dir.path().join("link");
272 fs::symlink("target", &link).unwrap();
273
274 cmd()
275 .arg("--ignore-config")
276 .arg(link)
277 .assert()
278 .stdout(predicate::str::starts_with("link").not())
279 .stdout(predicate::str::starts_with("inside"));
280 }
281
282 #[cfg(unix)]
283 #[test]
test_no_show_folder_content_of_symlink_for_long()284 fn test_no_show_folder_content_of_symlink_for_long() {
285 let dir = tempdir();
286 dir.child("target").child("inside").touch().unwrap();
287 let link = dir.path().join("link");
288 fs::symlink("target", &link).unwrap();
289
290 cmd()
291 .arg("-l")
292 .arg("--ignore-config")
293 .arg(link)
294 .assert()
295 .stdout(predicate::str::starts_with("lrw"))
296 .stdout(predicate::str::contains("⇒"));
297
298 cmd()
299 .arg("-l")
300 .arg("--ignore-config")
301 .arg(dir.path().join("link/"))
302 .assert()
303 .stdout(predicate::str::starts_with(".rw"))
304 .stdout(predicate::str::contains("⇒").not());
305 }
306
307 #[cfg(unix)]
308 #[test]
test_show_folder_of_symlink_for_long_multi()309 fn test_show_folder_of_symlink_for_long_multi() {
310 let dir = tempdir();
311 dir.child("target").child("inside").touch().unwrap();
312 let link = dir.path().join("link");
313 fs::symlink("target", &link).unwrap();
314
315 cmd()
316 .arg("-l")
317 .arg("--ignore-config")
318 .arg(dir.path().join("link/"))
319 .arg(dir.path().join("link"))
320 .assert()
321 .stdout(predicate::str::starts_with("lrw"))
322 .stdout(predicate::str::contains("link:").not()) // do not show dir content when no /
323 .stdout(predicate::str::contains("link/:"));
324 }
325
326 #[test]
test_version_sort()327 fn test_version_sort() {
328 let dir = tempdir();
329 dir.child("0.3.7").touch().unwrap();
330 dir.child("0.11.5").touch().unwrap();
331 dir.child("11a").touch().unwrap();
332 dir.child("0.2").touch().unwrap();
333 dir.child("0.11").touch().unwrap();
334 dir.child("1").touch().unwrap();
335 dir.child("11").touch().unwrap();
336 dir.child("2").touch().unwrap();
337 dir.child("22").touch().unwrap();
338 cmd()
339 .arg("-v")
340 .arg("--ignore-config")
341 .arg(dir.path())
342 .assert()
343 .stdout(
344 predicate::str::is_match("0.2\n0.3.7\n0.11\n0.11.5\n1\n2\n11\n11a\n22\n$").unwrap(),
345 );
346 }
347
348 #[test]
test_version_sort_overwrite_by_timesort()349 fn test_version_sort_overwrite_by_timesort() {
350 let dir = tempdir();
351 dir.child("2").touch().unwrap();
352 dir.child("11").touch().unwrap();
353 cmd()
354 .arg("-v")
355 .arg("-t")
356 .arg("--ignore-config")
357 .arg(dir.path())
358 .assert()
359 .stdout(predicate::str::is_match("11\n2\n$").unwrap());
360 }
361
362 #[test]
test_version_sort_overwrite_by_sizesort()363 fn test_version_sort_overwrite_by_sizesort() {
364 use std::fs::File;
365 use std::io::Write;
366 let dir = tempdir();
367 dir.child("2").touch().unwrap();
368 let larger = dir.path().join("11");
369 let mut larger_file = File::create(larger).unwrap();
370 writeln!(larger_file, "this is larger").unwrap();
371 cmd()
372 .arg("-v")
373 .arg("-S")
374 .arg("--ignore-config")
375 .arg(dir.path())
376 .assert()
377 .stdout(predicate::str::is_match("11\n2\n$").unwrap());
378 }
379
380 #[cfg(target_os = "linux")]
bad_utf8(tmp: &std::path::Path, pre: &str, suf: &str) -> String381 fn bad_utf8(tmp: &std::path::Path, pre: &str, suf: &str) -> String {
382 let mut fname = format!("{}/{}", tmp.display(), pre).into_bytes();
383 fname.reserve(2 + suf.len());
384 fname.push(0xa7);
385 fname.push(0xfd);
386 fname.extend(suf.as_bytes());
387 unsafe { String::from_utf8_unchecked(fname) }
388 }
389
390 #[test]
391 #[cfg(target_os = "linux")]
test_bad_utf_8_extension()392 fn test_bad_utf_8_extension() {
393 use std::fs::File;
394 let tmp = tempdir();
395 let fname = bad_utf8(tmp.path(), "bad.extension", "");
396 File::create(fname).expect("failed to create file");
397
398 cmd()
399 .arg(tmp.path())
400 .assert()
401 .stdout(predicate::str::is_match("bad.extension\u{fffd}\u{fffd}\n$").unwrap());
402 }
403
404 #[test]
405 #[cfg(target_os = "linux")]
test_bad_utf_8_name()406 fn test_bad_utf_8_name() {
407 use std::fs::File;
408 let tmp = tempdir();
409 let fname = bad_utf8(tmp.path(), "bad-name", ".ext");
410 File::create(fname).expect("failed to create file");
411
412 cmd()
413 .arg(tmp.path())
414 .assert()
415 .stdout(predicate::str::is_match("bad-name\u{fffd}\u{fffd}.ext\n$").unwrap());
416 }
417
418 #[test]
test_tree()419 fn test_tree() {
420 let tmp = tempdir();
421 tmp.child("one").touch().unwrap();
422 tmp.child("one.d").create_dir_all().unwrap();
423 tmp.child("one.d/two").touch().unwrap();
424
425 cmd()
426 .arg(tmp.path())
427 .arg("--tree")
428 .assert()
429 .stdout(predicate::str::is_match("├── one\n└── one.d\n └── two\n$").unwrap());
430 }
431
432 #[test]
test_tree_all_not_show_self()433 fn test_tree_all_not_show_self() {
434 let tmp = tempdir();
435 tmp.child("one").touch().unwrap();
436 tmp.child("one.d").create_dir_all().unwrap();
437 tmp.child("one.d/two").touch().unwrap();
438 tmp.child("one.d/.hidden").touch().unwrap();
439
440 cmd()
441 .arg(tmp.path())
442 .arg("--tree")
443 .arg("--all")
444 .assert()
445 .stdout(
446 predicate::str::is_match("├── one\n└── one.d\n ├── .hidden\n └── two\n$").unwrap(),
447 );
448 }
449
450 #[test]
test_tree_d()451 fn test_tree_d() {
452 let tmp = tempdir();
453 tmp.child("one").touch().unwrap();
454 tmp.child("two").touch().unwrap();
455 tmp.child("one.d").create_dir_all().unwrap();
456 tmp.child("one.d/one").touch().unwrap();
457 tmp.child("one.d/one.d").create_dir_all().unwrap();
458 tmp.child("two.d").create_dir_all().unwrap();
459
460 cmd()
461 .arg(tmp.path())
462 .arg("--tree")
463 .arg("-d")
464 .assert()
465 .stdout(predicate::str::is_match("├── one.d\n│ └── one.d\n└── two.d\n$").unwrap());
466 }
467
cmd() -> Command468 fn cmd() -> Command {
469 Command::cargo_bin(env!("CARGO_PKG_NAME")).unwrap()
470 }
471
tempdir() -> assert_fs::TempDir472 fn tempdir() -> assert_fs::TempDir {
473 assert_fs::TempDir::new().unwrap()
474 }
475
476 #[cfg(unix)]
477 #[test]
test_lower_case_name_icon_match()478 fn test_lower_case_name_icon_match() {
479 let dir = tempdir();
480 dir.child(".trash").touch().unwrap();
481 let test_file = dir.path().join(".trash");
482
483 cmd()
484 .arg("--icon")
485 .arg("always")
486 .arg("--ignore-config")
487 .arg(test_file)
488 .assert()
489 .stdout(predicate::str::contains("\u{f1f8}"));
490 }
491
492 #[cfg(unix)]
493 #[test]
test_upper_case_name_icon_match()494 fn test_upper_case_name_icon_match() {
495 let dir = tempdir();
496 dir.child(".TRASH").touch().unwrap();
497 let test_file = dir.path().join(".TRASH");
498
499 cmd()
500 .arg("--icon")
501 .arg("always")
502 .arg("--ignore-config")
503 .arg(test_file)
504 .assert()
505 .stdout(predicate::str::contains("\u{f1f8}"));
506 }
507
508 #[cfg(unix)]
509 #[test]
test_lower_case_ext_icon_match()510 fn test_lower_case_ext_icon_match() {
511 let dir = tempdir();
512 dir.child("test.7z").touch().unwrap();
513 let test_file = dir.path().join("test.7z");
514
515 cmd()
516 .arg("--icon")
517 .arg("always")
518 .arg("--ignore-config")
519 .arg(test_file)
520 .assert()
521 .stdout(predicate::str::contains("\u{f410}"));
522 }
523
524 #[cfg(unix)]
525 #[test]
test_upper_case_ext_icon_match()526 fn test_upper_case_ext_icon_match() {
527 let dir = tempdir();
528 dir.child("test.7Z").touch().unwrap();
529 let test_file = dir.path().join("test.7Z");
530
531 cmd()
532 .arg("--icon")
533 .arg("always")
534 .arg("--ignore-config")
535 .arg(test_file)
536 .assert()
537 .stdout(predicate::str::contains("\u{f410}"));
538 }
539