fd/tests/tests.rs

2003 lines
51 KiB
Rust
Raw Normal View History

mod testenv;
2018-02-21 21:41:52 +01:00
use std::fs;
use std::io::Write;
use std::path::Path;
use std::time::{Duration, SystemTime};
use test_case::test_case;
2021-08-08 14:13:32 +02:00
use normpath::PathExt;
2020-04-03 21:24:11 +02:00
use regex::escape;
use crate::testenv::TestEnv;
2020-05-01 11:22:30 +02:00
static DEFAULT_DIRS: &[&str] = &["one/two/three", "one/two/three/directory_foo"];
Add multiple path support (#182) * Adding support for multiple paths. (panic) - Started adding multiple file support - fd panics with multiple files right now * Moved the ctrlc handler to main. - Moved the ctrlc handler to main so we can search multiple files * Tests now allow custom directory setup - TestEnv::new() now takes two arguments, the directories to create and the files to create inside those directories. * rust-fmt changes * rust-fmt changes * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Removed commented code in testenv * Refactored walk::scan to accept the path buffer vector. Using the ParallelWalker allows for multithreaded searching of multiple directories * Moved ctrlc handler back into walker, it is only called once from main now. * Moved the colored output check back to it's original place * Removing shell-escape, not sure how it got added... * Added test for `fd 'a.foo' test1` to show that a.foo is only found in the test1 and not the test2 direcotry * Removing side effect from walk::scan, `dir_vec` is no longer a mutable reference and an iterator is being used instead. * Running rustfmt to format code correctly
2017-12-06 23:52:23 +01:00
2020-05-01 11:22:30 +02:00
static DEFAULT_FILES: &[&str] = &[
Add multiple path support (#182) * Adding support for multiple paths. (panic) - Started adding multiple file support - fd panics with multiple files right now * Moved the ctrlc handler to main. - Moved the ctrlc handler to main so we can search multiple files * Tests now allow custom directory setup - TestEnv::new() now takes two arguments, the directories to create and the files to create inside those directories. * rust-fmt changes * rust-fmt changes * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Removed commented code in testenv * Refactored walk::scan to accept the path buffer vector. Using the ParallelWalker allows for multithreaded searching of multiple directories * Moved ctrlc handler back into walker, it is only called once from main now. * Moved the colored output check back to it's original place * Removing shell-escape, not sure how it got added... * Added test for `fd 'a.foo' test1` to show that a.foo is only found in the test1 and not the test2 direcotry * Removing side effect from walk::scan, `dir_vec` is no longer a mutable reference and an iterator is being used instead. * Running rustfmt to format code correctly
2017-12-06 23:52:23 +01:00
"a.foo",
"one/b.foo",
"one/two/c.foo",
"one/two/C.Foo2",
"one/two/three/d.foo",
2018-02-21 21:41:52 +01:00
"fdignored.foo",
Add multiple path support (#182) * Adding support for multiple paths. (panic) - Started adding multiple file support - fd panics with multiple files right now * Moved the ctrlc handler to main. - Moved the ctrlc handler to main so we can search multiple files * Tests now allow custom directory setup - TestEnv::new() now takes two arguments, the directories to create and the files to create inside those directories. * rust-fmt changes * rust-fmt changes * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Removed commented code in testenv * Refactored walk::scan to accept the path buffer vector. Using the ParallelWalker allows for multithreaded searching of multiple directories * Moved ctrlc handler back into walker, it is only called once from main now. * Moved the colored output check back to it's original place * Removing shell-escape, not sure how it got added... * Added test for `fd 'a.foo' test1` to show that a.foo is only found in the test1 and not the test2 direcotry * Removing side effect from walk::scan, `dir_vec` is no longer a mutable reference and an iterator is being used instead. * Running rustfmt to format code correctly
2017-12-06 23:52:23 +01:00
"gitignored.foo",
".hidden.foo",
"e1 e2",
];
2021-08-08 23:32:13 +02:00
#[allow(clippy::let_and_return)]
fn get_absolute_root_path(env: &TestEnv) -> String {
2018-05-14 18:39:47 +02:00
let path = env
.test_root()
2021-08-08 14:13:32 +02:00
.normalize()
.expect("absolute path")
2021-08-08 14:13:32 +02:00
.as_path()
.to_str()
.expect("string")
.to_string();
#[cfg(windows)]
let path = path.trim_start_matches(r"\\?\").to_string();
path
}
#[cfg(test)]
fn get_test_env_with_abs_path(dirs: &[&'static str], files: &[&'static str]) -> (TestEnv, String) {
let env = TestEnv::new(dirs, files);
let root_path = get_absolute_root_path(&env);
(env, root_path)
}
#[cfg(test)]
fn create_file_with_size<P: AsRef<Path>>(path: P, size_in_bytes: usize) {
let content = "#".repeat(size_in_bytes);
let mut f = fs::File::create::<P>(path).unwrap();
2020-04-03 10:37:53 +02:00
f.write_all(content.as_bytes()).unwrap();
}
/// Simple test
#[test]
fn test_simple() {
Add multiple path support (#182) * Adding support for multiple paths. (panic) - Started adding multiple file support - fd panics with multiple files right now * Moved the ctrlc handler to main. - Moved the ctrlc handler to main so we can search multiple files * Tests now allow custom directory setup - TestEnv::new() now takes two arguments, the directories to create and the files to create inside those directories. * rust-fmt changes * rust-fmt changes * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Removed commented code in testenv * Refactored walk::scan to accept the path buffer vector. Using the ParallelWalker allows for multithreaded searching of multiple directories * Moved ctrlc handler back into walker, it is only called once from main now. * Moved the colored output check back to it's original place * Removing shell-escape, not sure how it got added... * Added test for `fd 'a.foo' test1` to show that a.foo is only found in the test1 and not the test2 direcotry * Removing side effect from walk::scan, `dir_vec` is no longer a mutable reference and an iterator is being used instead. * Running rustfmt to format code correctly
2017-12-06 23:52:23 +01:00
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
2021-10-17 05:12:56 +02:00
te.assert_output(&["a.foo"], "./a.foo");
te.assert_output(&["b.foo"], "./one/b.foo");
te.assert_output(&["d.foo"], "./one/two/three/d.foo");
te.assert_output(
&["foo"],
2021-10-17 05:12:56 +02:00
"./a.foo
./one/b.foo
./one/two/c.foo
./one/two/C.Foo2
./one/two/three/d.foo
./one/two/three/directory_foo",
2017-10-12 08:01:51 +02:00
);
}
/// Test each pattern type with an empty pattern.
#[test]
fn test_empty_pattern() {
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
2021-10-17 05:12:56 +02:00
let expected = "./a.foo
./e1 e2
./one
./one/b.foo
./one/two
./one/two/c.foo
./one/two/C.Foo2
./one/two/three
./one/two/three/d.foo
./one/two/three/directory_foo
./symlink";
2020-05-01 11:22:30 +02:00
te.assert_output(&["--regex"], expected);
te.assert_output(&["--fixed-strings"], expected);
te.assert_output(&["--glob"], expected);
}
Add multiple path support (#182) * Adding support for multiple paths. (panic) - Started adding multiple file support - fd panics with multiple files right now * Moved the ctrlc handler to main. - Moved the ctrlc handler to main so we can search multiple files * Tests now allow custom directory setup - TestEnv::new() now takes two arguments, the directories to create and the files to create inside those directories. * rust-fmt changes * rust-fmt changes * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Removed commented code in testenv * Refactored walk::scan to accept the path buffer vector. Using the ParallelWalker allows for multithreaded searching of multiple directories * Moved ctrlc handler back into walker, it is only called once from main now. * Moved the colored output check back to it's original place * Removing shell-escape, not sure how it got added... * Added test for `fd 'a.foo' test1` to show that a.foo is only found in the test1 and not the test2 direcotry * Removing side effect from walk::scan, `dir_vec` is no longer a mutable reference and an iterator is being used instead. * Running rustfmt to format code correctly
2017-12-06 23:52:23 +01:00
/// Test multiple directory searches
#[test]
fn test_multi_file() {
let dirs = &["test1", "test2"];
let files = &["test1/a.foo", "test1/b.foo", "test2/a.foo"];
let te = TestEnv::new(dirs, files);
te.assert_output(
&["a.foo", "test1", "test2"],
"test1/a.foo
test2/a.foo",
);
te.assert_output(
&["", "test1", "test2"],
"test1/a.foo
test2/a.foo
test1/b.foo",
);
te.assert_output(&["a.foo", "test1"], "test1/a.foo");
te.assert_output(&["b.foo", "test1", "test2"], "test1/b.foo");
}
/// Test search over multiple directory with missing
#[test]
fn test_multi_file_with_missing() {
let dirs = &["real"];
let files = &["real/a.foo", "real/b.foo"];
let te = TestEnv::new(dirs, files);
2020-05-19 15:37:38 +02:00
te.assert_output(&["a.foo", "real", "fake"], "real/a.foo");
te.assert_error(
&["a.foo", "real", "fake"],
"[fd error]: Search path 'fake' is not a directory.",
);
te.assert_output(
&["", "real", "fake"],
"real/a.foo
real/b.foo",
);
te.assert_output(
&["", "real", "fake1", "fake2"],
"real/a.foo
real/b.foo",
);
te.assert_error(
&["", "real", "fake1", "fake2"],
"[fd error]: Search path 'fake1' is not a directory.
[fd error]: Search path 'fake2' is not a directory.",
);
te.assert_failure_with_error(
&["", "fake1", "fake2"],
"[fd error]: Search path 'fake1' is not a directory.
[fd error]: Search path 'fake2' is not a directory.
[fd error]: No valid search paths given.",
);
}
/// Explicit root path
#[test]
fn test_explicit_root_path() {
Add multiple path support (#182) * Adding support for multiple paths. (panic) - Started adding multiple file support - fd panics with multiple files right now * Moved the ctrlc handler to main. - Moved the ctrlc handler to main so we can search multiple files * Tests now allow custom directory setup - TestEnv::new() now takes two arguments, the directories to create and the files to create inside those directories. * rust-fmt changes * rust-fmt changes * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Removed commented code in testenv * Refactored walk::scan to accept the path buffer vector. Using the ParallelWalker allows for multithreaded searching of multiple directories * Moved ctrlc handler back into walker, it is only called once from main now. * Moved the colored output check back to it's original place * Removing shell-escape, not sure how it got added... * Added test for `fd 'a.foo' test1` to show that a.foo is only found in the test1 and not the test2 direcotry * Removing side effect from walk::scan, `dir_vec` is no longer a mutable reference and an iterator is being used instead. * Running rustfmt to format code correctly
2017-12-06 23:52:23 +01:00
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
te.assert_output(
&["foo", "one"],
"one/b.foo
one/two/c.foo
one/two/C.Foo2
one/two/three/d.foo
2017-10-12 08:01:51 +02:00
one/two/three/directory_foo",
);
te.assert_output(
&["foo", "one/two/three"],
"one/two/three/d.foo
2017-10-12 08:01:51 +02:00
one/two/three/directory_foo",
);
te.assert_output_subdirectory(
"one/two",
&["foo", "../../"],
"../../a.foo
../../one/b.foo
../../one/two/c.foo
../../one/two/C.Foo2
../../one/two/three/d.foo
../../one/two/three/directory_foo",
2017-10-12 08:01:51 +02:00
);
te.assert_output_subdirectory(
"one/two/three",
&["", ".."],
"../c.foo
../C.Foo2
../three
../three/d.foo
../three/directory_foo",
);
}
/// Regex searches
#[test]
fn test_regex_searches() {
Add multiple path support (#182) * Adding support for multiple paths. (panic) - Started adding multiple file support - fd panics with multiple files right now * Moved the ctrlc handler to main. - Moved the ctrlc handler to main so we can search multiple files * Tests now allow custom directory setup - TestEnv::new() now takes two arguments, the directories to create and the files to create inside those directories. * rust-fmt changes * rust-fmt changes * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Removed commented code in testenv * Refactored walk::scan to accept the path buffer vector. Using the ParallelWalker allows for multithreaded searching of multiple directories * Moved ctrlc handler back into walker, it is only called once from main now. * Moved the colored output check back to it's original place * Removing shell-escape, not sure how it got added... * Added test for `fd 'a.foo' test1` to show that a.foo is only found in the test1 and not the test2 direcotry * Removing side effect from walk::scan, `dir_vec` is no longer a mutable reference and an iterator is being used instead. * Running rustfmt to format code correctly
2017-12-06 23:52:23 +01:00
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
te.assert_output(
&["[a-c].foo"],
2021-10-17 05:12:56 +02:00
"./a.foo
./one/b.foo
./one/two/c.foo
./one/two/C.Foo2",
2017-10-12 08:01:51 +02:00
);
te.assert_output(
&["--case-sensitive", "[a-c].foo"],
2021-10-17 05:12:56 +02:00
"./a.foo
./one/b.foo
./one/two/c.foo",
2017-10-12 08:01:51 +02:00
);
}
/// Smart case
#[test]
fn test_smart_case() {
Add multiple path support (#182) * Adding support for multiple paths. (panic) - Started adding multiple file support - fd panics with multiple files right now * Moved the ctrlc handler to main. - Moved the ctrlc handler to main so we can search multiple files * Tests now allow custom directory setup - TestEnv::new() now takes two arguments, the directories to create and the files to create inside those directories. * rust-fmt changes * rust-fmt changes * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Removed commented code in testenv * Refactored walk::scan to accept the path buffer vector. Using the ParallelWalker allows for multithreaded searching of multiple directories * Moved ctrlc handler back into walker, it is only called once from main now. * Moved the colored output check back to it's original place * Removing shell-escape, not sure how it got added... * Added test for `fd 'a.foo' test1` to show that a.foo is only found in the test1 and not the test2 direcotry * Removing side effect from walk::scan, `dir_vec` is no longer a mutable reference and an iterator is being used instead. * Running rustfmt to format code correctly
2017-12-06 23:52:23 +01:00
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
te.assert_output(
&["c.foo"],
2021-10-17 05:12:56 +02:00
"./one/two/c.foo
./one/two/C.Foo2",
2017-10-12 08:01:51 +02:00
);
2021-10-17 05:12:56 +02:00
te.assert_output(&["C.Foo"], "./one/two/C.Foo2");
2021-10-17 05:12:56 +02:00
te.assert_output(&["Foo"], "./one/two/C.Foo2");
// Only literal uppercase chars should trigger case sensitivity.
te.assert_output(
&["\\Ac"],
2021-10-17 05:12:56 +02:00
"./one/two/c.foo
./one/two/C.Foo2",
);
2021-10-17 05:12:56 +02:00
te.assert_output(&["\\AC"], "./one/two/C.Foo2");
}
/// Case sensitivity (--case-sensitive)
#[test]
fn test_case_sensitive() {
Add multiple path support (#182) * Adding support for multiple paths. (panic) - Started adding multiple file support - fd panics with multiple files right now * Moved the ctrlc handler to main. - Moved the ctrlc handler to main so we can search multiple files * Tests now allow custom directory setup - TestEnv::new() now takes two arguments, the directories to create and the files to create inside those directories. * rust-fmt changes * rust-fmt changes * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Removed commented code in testenv * Refactored walk::scan to accept the path buffer vector. Using the ParallelWalker allows for multithreaded searching of multiple directories * Moved ctrlc handler back into walker, it is only called once from main now. * Moved the colored output check back to it's original place * Removing shell-escape, not sure how it got added... * Added test for `fd 'a.foo' test1` to show that a.foo is only found in the test1 and not the test2 direcotry * Removing side effect from walk::scan, `dir_vec` is no longer a mutable reference and an iterator is being used instead. * Running rustfmt to format code correctly
2017-12-06 23:52:23 +01:00
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
2021-10-17 05:12:56 +02:00
te.assert_output(&["--case-sensitive", "c.foo"], "./one/two/c.foo");
2021-10-17 05:12:56 +02:00
te.assert_output(&["--case-sensitive", "C.Foo"], "./one/two/C.Foo2");
2017-10-12 01:21:44 +02:00
te.assert_output(
&["--ignore-case", "--case-sensitive", "C.Foo"],
2021-10-17 05:12:56 +02:00
"./one/two/C.Foo2",
2017-10-12 08:01:51 +02:00
);
2017-10-12 01:21:44 +02:00
}
/// Case insensitivity (--ignore-case)
#[test]
fn test_case_insensitive() {
Add multiple path support (#182) * Adding support for multiple paths. (panic) - Started adding multiple file support - fd panics with multiple files right now * Moved the ctrlc handler to main. - Moved the ctrlc handler to main so we can search multiple files * Tests now allow custom directory setup - TestEnv::new() now takes two arguments, the directories to create and the files to create inside those directories. * rust-fmt changes * rust-fmt changes * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Removed commented code in testenv * Refactored walk::scan to accept the path buffer vector. Using the ParallelWalker allows for multithreaded searching of multiple directories * Moved ctrlc handler back into walker, it is only called once from main now. * Moved the colored output check back to it's original place * Removing shell-escape, not sure how it got added... * Added test for `fd 'a.foo' test1` to show that a.foo is only found in the test1 and not the test2 direcotry * Removing side effect from walk::scan, `dir_vec` is no longer a mutable reference and an iterator is being used instead. * Running rustfmt to format code correctly
2017-12-06 23:52:23 +01:00
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
2017-10-12 01:21:44 +02:00
te.assert_output(
&["--ignore-case", "C.Foo"],
2021-10-17 05:12:56 +02:00
"./one/two/c.foo
./one/two/C.Foo2",
2017-10-12 08:01:51 +02:00
);
2017-10-12 01:21:44 +02:00
te.assert_output(
&["--case-sensitive", "--ignore-case", "C.Foo"],
2021-10-17 05:12:56 +02:00
"./one/two/c.foo
./one/two/C.Foo2",
2017-10-12 08:01:51 +02:00
);
}
/// Glob-based searches (--glob)
#[test]
fn test_glob_searches() {
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
te.assert_output(
&["--glob", "*.foo"],
2021-10-17 05:12:56 +02:00
"./a.foo
./one/b.foo
./one/two/c.foo
./one/two/three/d.foo",
);
te.assert_output(
&["--glob", "[a-c].foo"],
2021-10-17 05:12:56 +02:00
"./a.foo
./one/b.foo
./one/two/c.foo",
);
te.assert_output(
&["--glob", "[a-c].foo*"],
2021-10-17 05:12:56 +02:00
"./a.foo
./one/b.foo
./one/two/C.Foo2
./one/two/c.foo",
);
}
/// Glob-based searches (--glob) in combination with full path searches (--full-path)
2019-09-15 15:58:26 +02:00
#[cfg(not(windows))] // TODO: make this work on Windows
#[test]
fn test_full_path_glob_searches() {
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
te.assert_output(
2019-09-15 15:58:26 +02:00
&["--glob", "--full-path", "**/one/**/*.foo"],
2021-10-17 05:12:56 +02:00
"./one/b.foo
./one/two/c.foo
./one/two/three/d.foo",
);
te.assert_output(
&["--glob", "--full-path", "**/one/*/*.foo"],
2021-10-17 05:12:56 +02:00
" ./one/two/c.foo",
);
te.assert_output(
&["--glob", "--full-path", "**/one/*/*/*.foo"],
2021-10-17 05:12:56 +02:00
" ./one/two/three/d.foo",
);
}
#[test]
fn test_smart_case_glob_searches() {
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
te.assert_output(
&["--glob", "c.foo*"],
2021-10-17 05:12:56 +02:00
"./one/two/C.Foo2
./one/two/c.foo",
);
2021-10-17 05:12:56 +02:00
te.assert_output(&["--glob", "C.Foo*"], "./one/two/C.Foo2");
}
/// Glob-based searches (--glob) in combination with --case-sensitive
#[test]
fn test_case_sensitive_glob_searches() {
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
2021-10-17 05:12:56 +02:00
te.assert_output(&["--glob", "--case-sensitive", "c.foo*"], "./one/two/c.foo");
}
/// Glob-based searches (--glob) in combination with --extension
#[test]
fn test_glob_searches_with_extension() {
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
te.assert_output(
&["--glob", "--extension", "foo2", "[a-z].*"],
2021-10-17 05:12:56 +02:00
"./one/two/C.Foo2",
);
}
2019-09-15 15:48:34 +02:00
/// Make sure that --regex overrides --glob
#[test]
fn test_regex_overrides_glob() {
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
2021-10-17 05:12:56 +02:00
te.assert_output(&["--glob", "--regex", "Foo2$"], "./one/two/C.Foo2");
2019-09-15 15:48:34 +02:00
}
/// Full path search (--full-path)
#[test]
fn test_full_path() {
Add multiple path support (#182) * Adding support for multiple paths. (panic) - Started adding multiple file support - fd panics with multiple files right now * Moved the ctrlc handler to main. - Moved the ctrlc handler to main so we can search multiple files * Tests now allow custom directory setup - TestEnv::new() now takes two arguments, the directories to create and the files to create inside those directories. * rust-fmt changes * rust-fmt changes * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Removed commented code in testenv * Refactored walk::scan to accept the path buffer vector. Using the ParallelWalker allows for multithreaded searching of multiple directories * Moved ctrlc handler back into walker, it is only called once from main now. * Moved the colored output check back to it's original place * Removing shell-escape, not sure how it got added... * Added test for `fd 'a.foo' test1` to show that a.foo is only found in the test1 and not the test2 direcotry * Removing side effect from walk::scan, `dir_vec` is no longer a mutable reference and an iterator is being used instead. * Running rustfmt to format code correctly
2017-12-06 23:52:23 +01:00
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
let root = te.system_root();
let prefix = escape(&root.to_string_lossy());
te.assert_output(
&[
"--full-path",
&format!("^{prefix}.*three.*foo$", prefix = prefix),
],
2021-10-17 05:12:56 +02:00
"./one/two/three/d.foo
./one/two/three/directory_foo",
2017-10-12 08:01:51 +02:00
);
}
/// Hidden files (--hidden)
#[test]
fn test_hidden() {
Add multiple path support (#182) * Adding support for multiple paths. (panic) - Started adding multiple file support - fd panics with multiple files right now * Moved the ctrlc handler to main. - Moved the ctrlc handler to main so we can search multiple files * Tests now allow custom directory setup - TestEnv::new() now takes two arguments, the directories to create and the files to create inside those directories. * rust-fmt changes * rust-fmt changes * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Removed commented code in testenv * Refactored walk::scan to accept the path buffer vector. Using the ParallelWalker allows for multithreaded searching of multiple directories * Moved ctrlc handler back into walker, it is only called once from main now. * Moved the colored output check back to it's original place * Removing shell-escape, not sure how it got added... * Added test for `fd 'a.foo' test1` to show that a.foo is only found in the test1 and not the test2 direcotry * Removing side effect from walk::scan, `dir_vec` is no longer a mutable reference and an iterator is being used instead. * Running rustfmt to format code correctly
2017-12-06 23:52:23 +01:00
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
te.assert_output(
&["--hidden", "foo"],
2021-10-17 05:12:56 +02:00
"./.hidden.foo
./a.foo
./one/b.foo
./one/two/c.foo
./one/two/C.Foo2
./one/two/three/d.foo
./one/two/three/directory_foo",
2017-10-12 08:01:51 +02:00
);
}
/// Hidden file attribute on Windows
#[cfg(windows)]
#[test]
fn test_hidden_file_attribute() {
use std::os::windows::fs::OpenOptionsExt;
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
// https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfileattributesa
const FILE_ATTRIBUTE_HIDDEN: u32 = 2;
fs::OpenOptions::new()
.create(true)
.write(true)
.attributes(FILE_ATTRIBUTE_HIDDEN)
.open(te.test_root().join("hidden-file.txt"))
.unwrap();
2021-10-17 05:12:56 +02:00
te.assert_output(&["--hidden", "hidden-file.txt"], "./hidden-file.txt");
te.assert_output(&["hidden-file.txt"], "");
}
/// Ignored files (--no-ignore)
#[test]
fn test_no_ignore() {
Add multiple path support (#182) * Adding support for multiple paths. (panic) - Started adding multiple file support - fd panics with multiple files right now * Moved the ctrlc handler to main. - Moved the ctrlc handler to main so we can search multiple files * Tests now allow custom directory setup - TestEnv::new() now takes two arguments, the directories to create and the files to create inside those directories. * rust-fmt changes * rust-fmt changes * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Removed commented code in testenv * Refactored walk::scan to accept the path buffer vector. Using the ParallelWalker allows for multithreaded searching of multiple directories * Moved ctrlc handler back into walker, it is only called once from main now. * Moved the colored output check back to it's original place * Removing shell-escape, not sure how it got added... * Added test for `fd 'a.foo' test1` to show that a.foo is only found in the test1 and not the test2 direcotry * Removing side effect from walk::scan, `dir_vec` is no longer a mutable reference and an iterator is being used instead. * Running rustfmt to format code correctly
2017-12-06 23:52:23 +01:00
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
te.assert_output(
&["--no-ignore", "foo"],
2021-10-17 05:12:56 +02:00
"./a.foo
./fdignored.foo
./gitignored.foo
./one/b.foo
./one/two/c.foo
./one/two/C.Foo2
./one/two/three/d.foo
./one/two/three/directory_foo",
2017-10-12 08:01:51 +02:00
);
te.assert_output(
&["--hidden", "--no-ignore", "foo"],
2021-10-17 05:12:56 +02:00
"./.hidden.foo
./a.foo
./fdignored.foo
./gitignored.foo
./one/b.foo
./one/two/c.foo
./one/two/C.Foo2
./one/two/three/d.foo
./one/two/three/directory_foo",
);
}
2018-03-26 00:15:01 +02:00
/// .gitignore and .fdignore
2018-02-21 21:41:52 +01:00
#[test]
2018-03-26 00:15:01 +02:00
fn test_gitignore_and_fdignore() {
2018-02-21 21:41:52 +01:00
let files = &[
"ignored-by-nothing",
"ignored-by-fdignore",
"ignored-by-gitignore",
"ignored-by-both",
];
let te = TestEnv::new(&[], files);
fs::File::create(te.test_root().join(".fdignore"))
.unwrap()
.write_all(b"ignored-by-fdignore\nignored-by-both")
.unwrap();
fs::File::create(te.test_root().join(".gitignore"))
.unwrap()
.write_all(b"ignored-by-gitignore\nignored-by-both")
.unwrap();
2021-10-17 05:12:56 +02:00
te.assert_output(&["ignored"], "./ignored-by-nothing");
2018-02-21 21:41:52 +01:00
te.assert_output(
&["--no-ignore-vcs", "ignored"],
2021-10-17 05:12:56 +02:00
"./ignored-by-nothing
./ignored-by-gitignore",
2018-02-21 21:41:52 +01:00
);
te.assert_output(
&["--no-ignore", "ignored"],
2021-10-17 05:12:56 +02:00
"./ignored-by-nothing
./ignored-by-fdignore
./ignored-by-gitignore
./ignored-by-both",
2018-02-21 21:41:52 +01:00
);
}
2021-08-28 04:04:53 +02:00
/// Ignore parent ignore files (--no-ignore-parent)
#[test]
fn test_no_ignore_parent() {
let dirs = &["inner"];
let files = &[
"inner/parent-ignored",
"inner/child-ignored",
"inner/not-ignored",
];
let te = TestEnv::new(dirs, files);
// Ignore 'parent-ignored' in root
fs::File::create(te.test_root().join(".gitignore"))
.unwrap()
.write_all(b"parent-ignored")
.unwrap();
// Ignore 'child-ignored' in inner
fs::File::create(te.test_root().join("inner/.gitignore"))
.unwrap()
.write_all(b"child-ignored")
.unwrap();
2021-10-17 05:12:56 +02:00
te.assert_output_subdirectory("inner", &[], "./not-ignored");
2021-08-28 04:04:53 +02:00
te.assert_output_subdirectory(
"inner",
&["--no-ignore-parent"],
2021-10-17 05:12:56 +02:00
"./parent-ignored
./not-ignored",
2021-08-28 04:04:53 +02:00
);
}
/// Ignore parent ignore files (--no-ignore-parent) with an inner git repo
#[test]
fn test_no_ignore_parent_inner_git() {
let dirs = &["inner"];
let files = &[
"inner/parent-ignored",
"inner/child-ignored",
"inner/not-ignored",
];
let te = TestEnv::new(dirs, files);
// Make the inner folder also appear as a git repo
fs::create_dir_all(te.test_root().join("inner/.git")).unwrap();
// Ignore 'parent-ignored' in root
fs::File::create(te.test_root().join(".gitignore"))
.unwrap()
.write_all(b"parent-ignored")
.unwrap();
// Ignore 'child-ignored' in inner
fs::File::create(te.test_root().join("inner/.gitignore"))
.unwrap()
.write_all(b"child-ignored")
.unwrap();
te.assert_output_subdirectory(
"inner",
&[],
2021-10-17 05:12:56 +02:00
"./not-ignored
./parent-ignored",
2021-08-28 04:04:53 +02:00
);
te.assert_output_subdirectory(
"inner",
&["--no-ignore-parent"],
2021-10-17 05:12:56 +02:00
"./not-ignored
./parent-ignored",
2021-08-28 04:04:53 +02:00
);
}
2018-03-26 00:15:01 +02:00
/// Precedence of .fdignore files
2018-02-21 21:41:52 +01:00
#[test]
fn test_custom_ignore_precedence() {
let dirs = &["inner"];
let files = &["inner/foo"];
let te = TestEnv::new(dirs, files);
// Ignore 'foo' via .gitignore
fs::File::create(te.test_root().join("inner/.gitignore"))
.unwrap()
.write_all(b"foo")
.unwrap();
// Whitelist 'foo' via .fdignore
fs::File::create(te.test_root().join(".fdignore"))
.unwrap()
.write_all(b"!foo")
.unwrap();
2021-10-17 05:12:56 +02:00
te.assert_output(&["foo"], "./inner/foo");
2018-02-21 21:41:52 +01:00
2021-10-17 05:12:56 +02:00
te.assert_output(&["--no-ignore-vcs", "foo"], "./inner/foo");
2018-02-21 21:41:52 +01:00
2021-10-17 05:12:56 +02:00
te.assert_output(&["--no-ignore", "foo"], "./inner/foo");
2018-02-21 21:41:52 +01:00
}
/// VCS ignored files (--no-ignore-vcs)
#[test]
fn test_no_ignore_vcs() {
Add multiple path support (#182) * Adding support for multiple paths. (panic) - Started adding multiple file support - fd panics with multiple files right now * Moved the ctrlc handler to main. - Moved the ctrlc handler to main so we can search multiple files * Tests now allow custom directory setup - TestEnv::new() now takes two arguments, the directories to create and the files to create inside those directories. * rust-fmt changes * rust-fmt changes * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Removed commented code in testenv * Refactored walk::scan to accept the path buffer vector. Using the ParallelWalker allows for multithreaded searching of multiple directories * Moved ctrlc handler back into walker, it is only called once from main now. * Moved the colored output check back to it's original place * Removing shell-escape, not sure how it got added... * Added test for `fd 'a.foo' test1` to show that a.foo is only found in the test1 and not the test2 direcotry * Removing side effect from walk::scan, `dir_vec` is no longer a mutable reference and an iterator is being used instead. * Running rustfmt to format code correctly
2017-12-06 23:52:23 +01:00
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
te.assert_output(
&["--no-ignore-vcs", "foo"],
2021-10-17 05:12:56 +02:00
"./a.foo
./gitignored.foo
./one/b.foo
./one/two/c.foo
./one/two/C.Foo2
./one/two/three/d.foo
./one/two/three/directory_foo",
2017-10-12 08:01:51 +02:00
);
}
2018-03-26 00:15:01 +02:00
/// Custom ignore files (--ignore-file)
#[test]
fn test_custom_ignore_files() {
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
// Ignore 'C.Foo2' and everything in 'three'.
fs::File::create(te.test_root().join("custom.ignore"))
.unwrap()
.write_all(b"C.Foo2\nthree")
.unwrap();
te.assert_output(
&["--ignore-file", "custom.ignore", "foo"],
2021-10-17 05:12:56 +02:00
"./a.foo
./one/b.foo
./one/two/c.foo",
2018-03-26 00:15:01 +02:00
);
}
/// Ignored files with ripgrep aliases (-u / -uu)
#[test]
fn test_no_ignore_aliases() {
Add multiple path support (#182) * Adding support for multiple paths. (panic) - Started adding multiple file support - fd panics with multiple files right now * Moved the ctrlc handler to main. - Moved the ctrlc handler to main so we can search multiple files * Tests now allow custom directory setup - TestEnv::new() now takes two arguments, the directories to create and the files to create inside those directories. * rust-fmt changes * rust-fmt changes * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Removed commented code in testenv * Refactored walk::scan to accept the path buffer vector. Using the ParallelWalker allows for multithreaded searching of multiple directories * Moved ctrlc handler back into walker, it is only called once from main now. * Moved the colored output check back to it's original place * Removing shell-escape, not sure how it got added... * Added test for `fd 'a.foo' test1` to show that a.foo is only found in the test1 and not the test2 direcotry * Removing side effect from walk::scan, `dir_vec` is no longer a mutable reference and an iterator is being used instead. * Running rustfmt to format code correctly
2017-12-06 23:52:23 +01:00
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
te.assert_output(
&["-u", "foo"],
2021-10-17 05:12:56 +02:00
"./a.foo
./fdignored.foo
./gitignored.foo
./one/b.foo
./one/two/c.foo
./one/two/C.Foo2
./one/two/three/d.foo
./one/two/three/directory_foo",
2017-10-12 08:01:51 +02:00
);
te.assert_output(
&["-uu", "foo"],
2021-10-17 05:12:56 +02:00
"./.hidden.foo
./a.foo
./fdignored.foo
./gitignored.foo
./one/b.foo
./one/two/c.foo
./one/two/C.Foo2
./one/two/three/d.foo
./one/two/three/directory_foo",
2017-10-12 08:01:51 +02:00
);
}
/// Symlinks (--follow)
#[test]
fn test_follow() {
Add multiple path support (#182) * Adding support for multiple paths. (panic) - Started adding multiple file support - fd panics with multiple files right now * Moved the ctrlc handler to main. - Moved the ctrlc handler to main so we can search multiple files * Tests now allow custom directory setup - TestEnv::new() now takes two arguments, the directories to create and the files to create inside those directories. * rust-fmt changes * rust-fmt changes * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Removed commented code in testenv * Refactored walk::scan to accept the path buffer vector. Using the ParallelWalker allows for multithreaded searching of multiple directories * Moved ctrlc handler back into walker, it is only called once from main now. * Moved the colored output check back to it's original place * Removing shell-escape, not sure how it got added... * Added test for `fd 'a.foo' test1` to show that a.foo is only found in the test1 and not the test2 direcotry * Removing side effect from walk::scan, `dir_vec` is no longer a mutable reference and an iterator is being used instead. * Running rustfmt to format code correctly
2017-12-06 23:52:23 +01:00
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
te.assert_output(
&["--follow", "c.foo"],
2021-10-17 05:12:56 +02:00
"./one/two/c.foo
./one/two/C.Foo2
./symlink/c.foo
./symlink/C.Foo2",
2017-10-12 08:01:51 +02:00
);
}
// File system boundaries (--one-file-system)
2019-11-14 22:27:53 +01:00
// Limited to Unix because, to the best of my knowledge, there is no easy way to test a use case
// file systems mounted into the tree on Windows.
// Not limiting depth causes massive delay under Darwin, see BurntSushi/ripgrep#1429
2019-11-14 22:27:53 +01:00
#[test]
#[cfg(unix)]
fn test_file_system_boundaries() {
// Helper function to get the device ID for a given path
// Inspired by https://github.com/BurntSushi/ripgrep/blob/8892bf648cfec111e6e7ddd9f30e932b0371db68/ignore/src/walk.rs#L1693
fn device_num(path: impl AsRef<Path>) -> u64 {
use std::os::unix::fs::MetadataExt;
path.as_ref().metadata().map(|md| md.dev()).unwrap()
}
2019-11-14 22:27:53 +01:00
// Can't simulate file system boundaries
let te = TestEnv::new(&[], &[]);
let dev_null = Path::new("/dev/null");
// /dev/null should exist in all sane Unixes. Skip if it doesn't exist for some reason.
// Also skip should it be on the same device as the root partition for some reason.
if !dev_null.is_file() || device_num(dev_null) == device_num("/") {
return;
}
2019-11-14 22:27:53 +01:00
te.assert_output(
&["--full-path", "--max-depth", "2", "^/dev/null$", "/"],
"/dev/null",
);
te.assert_output(
&[
"--one-file-system",
"--full-path",
"--max-depth",
"2",
"^/dev/null$",
"/",
],
2019-11-14 22:27:53 +01:00
"",
);
}
#[test]
fn test_follow_broken_symlink() {
let mut te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
te.create_broken_symlink("broken_symlink")
.expect("Failed to create broken symlink.");
2020-02-28 13:33:15 +01:00
te.assert_output(
&["symlink"],
2021-10-17 05:12:56 +02:00
"./broken_symlink
./symlink",
2020-02-28 13:33:15 +01:00
);
te.assert_output(
&["--type", "symlink", "symlink"],
2021-10-17 05:12:56 +02:00
"./broken_symlink
./symlink",
2020-02-28 13:33:15 +01:00
);
te.assert_output(&["--type", "file", "symlink"], "");
te.assert_output(
&["--follow", "--type", "symlink", "symlink"],
2021-10-17 05:12:56 +02:00
"./broken_symlink",
2020-02-28 13:33:15 +01:00
);
te.assert_output(&["--follow", "--type", "file", "symlink"], "");
}
/// Null separator (--print0)
#[test]
fn test_print0() {
Add multiple path support (#182) * Adding support for multiple paths. (panic) - Started adding multiple file support - fd panics with multiple files right now * Moved the ctrlc handler to main. - Moved the ctrlc handler to main so we can search multiple files * Tests now allow custom directory setup - TestEnv::new() now takes two arguments, the directories to create and the files to create inside those directories. * rust-fmt changes * rust-fmt changes * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Removed commented code in testenv * Refactored walk::scan to accept the path buffer vector. Using the ParallelWalker allows for multithreaded searching of multiple directories * Moved ctrlc handler back into walker, it is only called once from main now. * Moved the colored output check back to it's original place * Removing shell-escape, not sure how it got added... * Added test for `fd 'a.foo' test1` to show that a.foo is only found in the test1 and not the test2 direcotry * Removing side effect from walk::scan, `dir_vec` is no longer a mutable reference and an iterator is being used instead. * Running rustfmt to format code correctly
2017-12-06 23:52:23 +01:00
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
te.assert_output(
&["--print0", "foo"],
2021-10-17 05:12:56 +02:00
"./a.fooNULL
./one/b.fooNULL
./one/two/C.Foo2NULL
./one/two/c.fooNULL
./one/two/three/d.fooNULL
./one/two/three/directory_fooNULL",
2017-10-12 08:01:51 +02:00
);
}
/// Maximum depth (--max-depth)
#[test]
fn test_max_depth() {
Add multiple path support (#182) * Adding support for multiple paths. (panic) - Started adding multiple file support - fd panics with multiple files right now * Moved the ctrlc handler to main. - Moved the ctrlc handler to main so we can search multiple files * Tests now allow custom directory setup - TestEnv::new() now takes two arguments, the directories to create and the files to create inside those directories. * rust-fmt changes * rust-fmt changes * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Removed commented code in testenv * Refactored walk::scan to accept the path buffer vector. Using the ParallelWalker allows for multithreaded searching of multiple directories * Moved ctrlc handler back into walker, it is only called once from main now. * Moved the colored output check back to it's original place * Removing shell-escape, not sure how it got added... * Added test for `fd 'a.foo' test1` to show that a.foo is only found in the test1 and not the test2 direcotry * Removing side effect from walk::scan, `dir_vec` is no longer a mutable reference and an iterator is being used instead. * Running rustfmt to format code correctly
2017-12-06 23:52:23 +01:00
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
te.assert_output(
&["--max-depth", "3"],
2021-10-17 05:12:56 +02:00
"./a.foo
./e1 e2
./one
./one/b.foo
./one/two
./one/two/c.foo
./one/two/C.Foo2
./one/two/three
./symlink",
2017-10-12 08:01:51 +02:00
);
te.assert_output(
&["--max-depth", "2"],
2021-10-17 05:12:56 +02:00
"./a.foo
./e1 e2
./one
./one/b.foo
./one/two
./symlink",
2017-10-12 08:01:51 +02:00
);
te.assert_output(
&["--max-depth", "1"],
2021-10-17 05:12:56 +02:00
"./a.foo
./e1 e2
./one
./symlink",
2017-10-12 08:01:51 +02:00
);
}
/// Minimum depth (--min-depth)
#[test]
fn test_min_depth() {
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
te.assert_output(
&["--min-depth", "3"],
2021-10-17 05:12:56 +02:00
"./one/two/c.foo
./one/two/C.Foo2
./one/two/three
./one/two/three/d.foo
./one/two/three/directory_foo",
);
te.assert_output(
&["--min-depth", "4"],
2021-10-17 05:12:56 +02:00
"./one/two/three/d.foo
./one/two/three/directory_foo",
);
}
/// Exact depth (--exact-depth)
#[test]
fn test_exact_depth() {
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
te.assert_output(
&["--exact-depth", "3"],
2021-10-17 05:12:56 +02:00
"./one/two/c.foo
./one/two/C.Foo2
./one/two/three",
);
}
2020-10-25 08:16:01 +01:00
/// Pruning (--prune)
#[test]
fn test_prune() {
let dirs = &["foo/bar", "bar/foo", "baz"];
let files = &[
2021-10-17 05:12:56 +02:00
"./foo/foo.file",
"./foo/bar/foo.file",
"./bar/foo.file",
"./bar/foo/foo.file",
"./baz/foo.file",
2020-10-25 08:16:01 +01:00
];
let te = TestEnv::new(dirs, files);
te.assert_output(
&["foo"],
2021-10-17 05:12:56 +02:00
"./foo
./foo/foo.file
./foo/bar/foo.file
./bar/foo.file
./bar/foo
./bar/foo/foo.file
./baz/foo.file",
2020-10-25 08:16:01 +01:00
);
te.assert_output(
&["--prune", "foo"],
2021-10-17 05:12:56 +02:00
"./foo
./bar/foo
./bar/foo.file
./baz/foo.file",
2020-10-25 08:16:01 +01:00
);
}
/// Absolute paths (--absolute-path)
#[test]
fn test_absolute_path() {
let (te, abs_path) = get_test_env_with_abs_path(DEFAULT_DIRS, DEFAULT_FILES);
te.assert_output(
&["--absolute-path"],
&format!(
"{abs_path}/a.foo
2017-10-26 09:18:06 +02:00
{abs_path}/e1 e2
{abs_path}/one
{abs_path}/one/b.foo
{abs_path}/one/two
{abs_path}/one/two/c.foo
{abs_path}/one/two/C.Foo2
{abs_path}/one/two/three
{abs_path}/one/two/three/d.foo
{abs_path}/one/two/three/directory_foo
{abs_path}/symlink",
abs_path = &abs_path
),
);
te.assert_output(
&["--absolute-path", "foo"],
&format!(
"{abs_path}/a.foo
{abs_path}/one/b.foo
{abs_path}/one/two/c.foo
{abs_path}/one/two/C.Foo2
{abs_path}/one/two/three/d.foo
{abs_path}/one/two/three/directory_foo",
abs_path = &abs_path
2017-10-12 08:01:51 +02:00
),
);
2018-03-25 19:00:46 +02:00
}
/// Show absolute paths if the path argument is absolute
#[test]
fn test_implicit_absolute_path() {
let (te, abs_path) = get_test_env_with_abs_path(DEFAULT_DIRS, DEFAULT_FILES);
te.assert_output(
&["foo", &abs_path],
&format!(
"{abs_path}/a.foo
{abs_path}/one/b.foo
{abs_path}/one/two/c.foo
{abs_path}/one/two/C.Foo2
{abs_path}/one/two/three/d.foo
{abs_path}/one/two/three/directory_foo",
abs_path = &abs_path
2017-10-12 08:01:51 +02:00
),
);
}
/// Absolute paths should be normalized
#[test]
fn test_normalized_absolute_path() {
let (te, abs_path) = get_test_env_with_abs_path(DEFAULT_DIRS, DEFAULT_FILES);
te.assert_output_subdirectory(
"one",
&["--absolute-path", "foo", ".."],
&format!(
"{abs_path}/a.foo
{abs_path}/one/b.foo
{abs_path}/one/two/c.foo
{abs_path}/one/two/C.Foo2
{abs_path}/one/two/three/d.foo
{abs_path}/one/two/three/directory_foo",
abs_path = &abs_path
),
);
}
/// File type filter (--type)
#[test]
fn test_type() {
Add multiple path support (#182) * Adding support for multiple paths. (panic) - Started adding multiple file support - fd panics with multiple files right now * Moved the ctrlc handler to main. - Moved the ctrlc handler to main so we can search multiple files * Tests now allow custom directory setup - TestEnv::new() now takes two arguments, the directories to create and the files to create inside those directories. * rust-fmt changes * rust-fmt changes * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Removed commented code in testenv * Refactored walk::scan to accept the path buffer vector. Using the ParallelWalker allows for multithreaded searching of multiple directories * Moved ctrlc handler back into walker, it is only called once from main now. * Moved the colored output check back to it's original place * Removing shell-escape, not sure how it got added... * Added test for `fd 'a.foo' test1` to show that a.foo is only found in the test1 and not the test2 direcotry * Removing side effect from walk::scan, `dir_vec` is no longer a mutable reference and an iterator is being used instead. * Running rustfmt to format code correctly
2017-12-06 23:52:23 +01:00
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
te.assert_output(
&["--type", "f"],
2021-10-17 05:12:56 +02:00
"./a.foo
./e1 e2
./one/b.foo
./one/two/c.foo
./one/two/C.Foo2
./one/two/three/d.foo",
2017-10-12 08:01:51 +02:00
);
2021-10-17 05:12:56 +02:00
te.assert_output(&["--type", "f", "e1"], "./e1 e2");
te.assert_output(
&["--type", "d"],
2021-10-17 05:12:56 +02:00
"./one
./one/two
./one/two/three
./one/two/three/directory_foo",
2017-10-12 08:01:51 +02:00
);
te.assert_output(
&["--type", "d", "--type", "l"],
2021-10-17 05:12:56 +02:00
"./one
./one/two
./one/two/three
./one/two/three/directory_foo
./symlink",
);
2021-10-17 05:12:56 +02:00
te.assert_output(&["--type", "l"], "./symlink");
}
2018-03-25 17:49:47 +02:00
/// Test `--type executable`
#[cfg(unix)]
#[test]
fn test_type_executable() {
use std::os::unix::fs::OpenOptionsExt;
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
fs::OpenOptions::new()
.create(true)
.write(true)
.mode(0o777)
.open(te.test_root().join("executable-file.sh"))
.unwrap();
2021-10-17 05:12:56 +02:00
te.assert_output(&["--type", "executable"], "./executable-file.sh");
2018-03-25 17:49:47 +02:00
te.assert_output(
&["--type", "executable", "--type", "directory"],
2021-10-17 05:12:56 +02:00
"./executable-file.sh
./one
./one/two
./one/two/three
./one/two/three/directory_foo",
2018-03-25 17:49:47 +02:00
);
}
/// Test `--type empty`
#[test]
fn test_type_empty() {
let te = TestEnv::new(&["dir_empty", "dir_nonempty"], &[]);
create_file_with_size(te.test_root().join("0_bytes.foo"), 0);
create_file_with_size(te.test_root().join("5_bytes.foo"), 5);
create_file_with_size(te.test_root().join("dir_nonempty").join("2_bytes.foo"), 2);
te.assert_output(
&["--type", "empty"],
2021-10-17 05:12:56 +02:00
"./0_bytes.foo
./dir_empty",
);
te.assert_output(
&["--type", "empty", "--type", "file", "--type", "directory"],
2021-10-17 05:12:56 +02:00
"./0_bytes.foo
./dir_empty",
);
2021-10-17 05:12:56 +02:00
te.assert_output(&["--type", "empty", "--type", "file"], "./0_bytes.foo");
2021-10-17 05:12:56 +02:00
te.assert_output(&["--type", "empty", "--type", "directory"], "./dir_empty");
}
/// File extension (--extension)
#[test]
fn test_extension() {
Add multiple path support (#182) * Adding support for multiple paths. (panic) - Started adding multiple file support - fd panics with multiple files right now * Moved the ctrlc handler to main. - Moved the ctrlc handler to main so we can search multiple files * Tests now allow custom directory setup - TestEnv::new() now takes two arguments, the directories to create and the files to create inside those directories. * rust-fmt changes * rust-fmt changes * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Removed commented code in testenv * Refactored walk::scan to accept the path buffer vector. Using the ParallelWalker allows for multithreaded searching of multiple directories * Moved ctrlc handler back into walker, it is only called once from main now. * Moved the colored output check back to it's original place * Removing shell-escape, not sure how it got added... * Added test for `fd 'a.foo' test1` to show that a.foo is only found in the test1 and not the test2 direcotry * Removing side effect from walk::scan, `dir_vec` is no longer a mutable reference and an iterator is being used instead. * Running rustfmt to format code correctly
2017-12-06 23:52:23 +01:00
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
te.assert_output(
&["--extension", "foo"],
2021-10-17 05:12:56 +02:00
"./a.foo
./one/b.foo
./one/two/c.foo
./one/two/three/d.foo",
2017-10-12 08:01:51 +02:00
);
te.assert_output(
&["--extension", ".foo"],
2021-10-17 05:12:56 +02:00
"./a.foo
./one/b.foo
./one/two/c.foo
./one/two/three/d.foo",
2017-10-12 08:01:51 +02:00
);
te.assert_output(
&["--extension", ".foo", "--extension", "foo2"],
2021-10-17 05:12:56 +02:00
"./a.foo
./one/b.foo
./one/two/c.foo
./one/two/three/d.foo
./one/two/C.Foo2",
);
2021-10-17 05:12:56 +02:00
te.assert_output(&["--extension", ".foo", "a"], "./a.foo");
2021-10-17 05:12:56 +02:00
te.assert_output(&["--extension", "foo2"], "./one/two/C.Foo2");
let te2 = TestEnv::new(&[], &["spam.bar.baz", "egg.bar.baz", "yolk.bar.baz.sig"]);
te2.assert_output(
&["--extension", ".bar.baz"],
2021-10-17 05:12:56 +02:00
"./spam.bar.baz
./egg.bar.baz",
);
2021-10-17 05:12:56 +02:00
te2.assert_output(&["--extension", "sig"], "./yolk.bar.baz.sig");
2021-10-17 05:12:56 +02:00
te2.assert_output(&["--extension", "bar.baz.sig"], "./yolk.bar.baz.sig");
let te3 = TestEnv::new(&[], &["latin1.e\u{301}xt", "smiley.☻"]);
2021-10-17 05:12:56 +02:00
te3.assert_output(&["--extension", ""], "./smiley.☻");
2021-10-17 05:12:56 +02:00
te3.assert_output(&["--extension", ".e\u{301}xt"], "./latin1.e\u{301}xt");
let te4 = TestEnv::new(&[], &[".hidden", "test.hidden"]);
2021-10-17 05:12:56 +02:00
te4.assert_output(&["--hidden", "--extension", ".hidden"], "./test.hidden");
}
/// No file extension (test for the pattern provided in the --help text)
#[test]
fn test_no_extension() {
let te = TestEnv::new(
DEFAULT_DIRS,
&["a.foo", "aa", "one/b.foo", "one/bb", "one/two/three/d"],
);
te.assert_output(
&["^[^.]+$"],
2021-10-17 05:12:56 +02:00
"./aa
./one
./one/bb
./one/two
./one/two/three
./one/two/three/d
./one/two/three/directory_foo
./symlink",
);
te.assert_output(
&["^[^.]+$", "--type", "file"],
2021-10-17 05:12:56 +02:00
"./aa
./one/bb
./one/two/three/d",
);
}
/// Symlink as search directory
#[test]
fn test_symlink_as_root() {
let mut te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
te.create_broken_symlink("broken_symlink")
.expect("Failed to create broken symlink.");
// From: http://pubs.opengroup.org/onlinepubs/9699919799/functions/getcwd.html
// The getcwd() function shall place an absolute pathname of the current working directory in
// the array pointed to by buf, and return buf. The pathname shall contain no components that
// are dot or dot-dot, or are symbolic links.
//
// Key points:
// 1. The path of the current working directory of a Unix process cannot contain symlinks.
// 2. The path of the current working directory of a Windows process can contain symlinks.
//
// More:
// 1. On Windows, symlinks are resolved after the ".." component.
// 2. On Unix, symlinks are resolved immediately as encountered.
let parent_parent = if cfg!(windows) { ".." } else { "../.." };
te.assert_output_subdirectory(
"symlink",
2017-10-26 21:13:56 +02:00
&["", parent_parent],
&format!(
"{dir}/a.foo
{dir}/broken_symlink
2017-10-26 09:18:06 +02:00
{dir}/e1 e2
{dir}/one
{dir}/one/b.foo
{dir}/one/two
{dir}/one/two/c.foo
{dir}/one/two/C.Foo2
{dir}/one/two/three
{dir}/one/two/three/d.foo
{dir}/one/two/three/directory_foo
{dir}/symlink",
dir = &parent_parent
),
);
}
#[test]
fn test_symlink_and_absolute_path() {
let (te, abs_path) = get_test_env_with_abs_path(DEFAULT_DIRS, DEFAULT_FILES);
2021-08-08 14:13:32 +02:00
let expected_path = if cfg!(windows) { "symlink" } else { "one/two" };
te.assert_output_subdirectory(
"symlink",
&["--absolute-path"],
&format!(
2021-08-08 14:13:32 +02:00
"{abs_path}/{expected_path}/c.foo
{abs_path}/{expected_path}/C.Foo2
{abs_path}/{expected_path}/three
{abs_path}/{expected_path}/three/d.foo
{abs_path}/{expected_path}/three/directory_foo",
abs_path = &abs_path,
expected_path = expected_path
),
);
}
#[test]
fn test_symlink_as_absolute_root() {
let (te, abs_path) = get_test_env_with_abs_path(DEFAULT_DIRS, DEFAULT_FILES);
te.assert_output(
&["", &format!("{abs_path}/symlink", abs_path = abs_path)],
&format!(
"{abs_path}/symlink/c.foo
{abs_path}/symlink/C.Foo2
{abs_path}/symlink/three
{abs_path}/symlink/three/d.foo
{abs_path}/symlink/three/directory_foo",
abs_path = &abs_path
),
);
}
#[test]
fn test_symlink_and_full_path() {
let (te, abs_path) = get_test_env_with_abs_path(DEFAULT_DIRS, DEFAULT_FILES);
let root = te.system_root();
let prefix = escape(&root.to_string_lossy());
2021-08-08 14:13:32 +02:00
let expected_path = if cfg!(windows) { "symlink" } else { "one/two" };
te.assert_output_subdirectory(
"symlink",
&[
"--absolute-path",
"--full-path",
&format!("^{prefix}.*three", prefix = prefix),
],
&format!(
2021-08-08 14:13:32 +02:00
"{abs_path}/{expected_path}/three
{abs_path}/{expected_path}/three/d.foo
{abs_path}/{expected_path}/three/directory_foo",
abs_path = &abs_path,
expected_path = expected_path
),
);
}
#[test]
fn test_symlink_and_full_path_abs_path() {
let (te, abs_path) = get_test_env_with_abs_path(DEFAULT_DIRS, DEFAULT_FILES);
let root = te.system_root();
let prefix = escape(&root.to_string_lossy());
te.assert_output(
&[
"--full-path",
&format!("^{prefix}.*symlink.*three", prefix = prefix),
&format!("{abs_path}/symlink", abs_path = abs_path),
],
&format!(
"{abs_path}/symlink/three
{abs_path}/symlink/three/d.foo
{abs_path}/symlink/three/directory_foo",
abs_path = &abs_path
),
);
}
/// Exclude patterns (--exclude)
#[test]
fn test_excludes() {
Add multiple path support (#182) * Adding support for multiple paths. (panic) - Started adding multiple file support - fd panics with multiple files right now * Moved the ctrlc handler to main. - Moved the ctrlc handler to main so we can search multiple files * Tests now allow custom directory setup - TestEnv::new() now takes two arguments, the directories to create and the files to create inside those directories. * rust-fmt changes * rust-fmt changes * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Moving code around, no need to do everything in one big loop - PathDisplay was never actually used for anything, removed it during refactor of main - Removed redundant logic for absolute paths - Moved code placed needlessly inside a loop in the last commit outside of that loop. * Removed commented code in testenv * Refactored walk::scan to accept the path buffer vector. Using the ParallelWalker allows for multithreaded searching of multiple directories * Moved ctrlc handler back into walker, it is only called once from main now. * Moved the colored output check back to it's original place * Removing shell-escape, not sure how it got added... * Added test for `fd 'a.foo' test1` to show that a.foo is only found in the test1 and not the test2 direcotry * Removing side effect from walk::scan, `dir_vec` is no longer a mutable reference and an iterator is being used instead. * Running rustfmt to format code correctly
2017-12-06 23:52:23 +01:00
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
te.assert_output(
&["--exclude", "*.foo"],
2021-10-17 05:12:56 +02:00
"./one
./one/two
./one/two/C.Foo2
./one/two/three
./one/two/three/directory_foo
./e1 e2
./symlink",
);
te.assert_output(
&["--exclude", "*.foo", "--exclude", "*.Foo2"],
2021-10-17 05:12:56 +02:00
"./one
./one/two
./one/two/three
./one/two/three/directory_foo
./e1 e2
./symlink",
);
te.assert_output(
&["--exclude", "*.foo", "--exclude", "*.Foo2", "foo"],
2021-10-17 05:12:56 +02:00
"./one/two/three/directory_foo",
);
te.assert_output(
&["--exclude", "one/two", "foo"],
2021-10-17 05:12:56 +02:00
"./a.foo
./one/b.foo",
);
te.assert_output(
&["--exclude", "one/**/*.foo"],
2021-10-17 05:12:56 +02:00
"./a.foo
./e1 e2
./one
./one/two
./one/two/C.Foo2
./one/two/three
./one/two/three/directory_foo
./symlink",
);
}
2017-10-26 09:18:06 +02:00
/// Shell script execution (--exec)
#[test]
fn test_exec() {
let (te, abs_path) = get_test_env_with_abs_path(DEFAULT_DIRS, DEFAULT_FILES);
2017-10-26 09:18:06 +02:00
// TODO Windows tests: D:file.txt \file.txt \\server\share\file.txt ...
2017-10-26 09:18:06 +02:00
if !cfg!(windows) {
te.assert_output(
&["--absolute-path", "foo", "--exec", "echo"],
2017-10-26 09:18:06 +02:00
&format!(
"{abs_path}/a.foo
{abs_path}/one/b.foo
{abs_path}/one/two/C.Foo2
{abs_path}/one/two/c.foo
{abs_path}/one/two/three/d.foo
{abs_path}/one/two/three/directory_foo",
abs_path = &abs_path
),
);
te.assert_output(
&["foo", "--exec", "echo", "{}"],
2021-10-17 05:12:56 +02:00
"./a.foo
./one/b.foo
./one/two/C.Foo2
./one/two/c.foo
./one/two/three/d.foo
./one/two/three/directory_foo",
2017-10-26 09:18:06 +02:00
);
te.assert_output(
&["foo", "--exec", "echo", "{.}"],
2017-10-26 09:18:06 +02:00
"a
one/b
one/two/C
one/two/c
one/two/three/d
one/two/three/directory_foo",
);
te.assert_output(
&["foo", "--exec", "echo", "{/}"],
2017-10-26 09:18:06 +02:00
"a.foo
b.foo
C.Foo2
c.foo
d.foo
directory_foo",
);
te.assert_output(
&["foo", "--exec", "echo", "{/.}"],
2017-10-26 09:18:06 +02:00
"a
b
C
c
d
directory_foo",
);
te.assert_output(
&["foo", "--exec", "echo", "{//}"],
2017-10-26 09:18:06 +02:00
".
2021-10-17 05:12:56 +02:00
./one
./one/two
./one/two
./one/two/three
./one/two/three",
2017-10-26 09:18:06 +02:00
);
2021-10-17 05:12:56 +02:00
te.assert_output(&["e1", "--exec", "printf", "%s.%s\n"], "./e1 e2.");
2017-10-26 09:18:06 +02:00
}
}
2018-02-10 15:19:53 +01:00
#[test]
fn test_exec_batch() {
let (te, abs_path) = get_test_env_with_abs_path(DEFAULT_DIRS, DEFAULT_FILES);
let te = te.normalize_line(true);
// TODO Test for windows
if !cfg!(windows) {
te.assert_output(
&["--absolute-path", "foo", "--exec-batch", "echo"],
&format!(
"{abs_path}/a.foo {abs_path}/one/b.foo {abs_path}/one/two/C.Foo2 {abs_path}/one/two/c.foo {abs_path}/one/two/three/d.foo {abs_path}/one/two/three/directory_foo",
abs_path = &abs_path
),
);
te.assert_output(
&["foo", "--exec-batch", "echo", "{}"],
2021-10-17 05:12:56 +02:00
"./a.foo ./one/b.foo ./one/two/C.Foo2 ./one/two/c.foo ./one/two/three/d.foo ./one/two/three/directory_foo",
);
te.assert_output(
&["foo", "--exec-batch", "echo", "{/}"],
"a.foo b.foo C.Foo2 c.foo d.foo directory_foo",
);
te.assert_output(
&["no_match", "--exec-batch", "echo", "Matched: ", "{/}"],
"",
);
te.assert_failure_with_error(
&["foo", "--exec-batch", "echo", "{}", "{}"],
"[fd error]: Only one placeholder allowed for batch commands",
);
te.assert_failure_with_error(
&["foo", "--exec-batch", "echo", "{/}", ";", "-x", "echo"],
"error: The argument '--exec <cmd>' cannot be used with '--exec-batch <cmd>'",
);
te.assert_failure_with_error(
&["foo", "--exec-batch"],
"error: The argument '--exec-batch <cmd>' requires a value but none was supplied",
);
te.assert_failure_with_error(
&["foo", "--exec-batch", "echo {}"],
"[fd error]: First argument of exec-batch is expected to be a fixed executable",
);
}
}
2021-10-22 08:05:13 +02:00
#[test]
fn test_exec_batch_with_limit() {
// TODO Test for windows
if cfg!(windows) {
return;
}
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
te.assert_output(
&["foo", "--batch-size", "0", "--exec-batch", "echo", "{}"],
"./a.foo ./one/b.foo ./one/two/C.Foo2 ./one/two/c.foo ./one/two/three/d.foo ./one/two/three/directory_foo",
2021-10-22 08:05:13 +02:00
);
let output = te.assert_success_and_get_output(
".",
&["foo", "--batch-size=2", "--exec-batch", "echo", "{}"],
);
let stdout = String::from_utf8_lossy(&output.stdout);
for line in stdout.lines() {
assert_eq!(2, line.split_whitespace().count());
}
let mut paths: Vec<_> = stdout
.lines()
.flat_map(|line| line.split_whitespace())
.collect();
paths.sort_unstable();
assert_eq!(
&paths,
&[
"./a.foo",
"./one/b.foo",
"./one/two/C.Foo2",
"./one/two/c.foo",
"./one/two/three/d.foo",
"./one/two/three/directory_foo"
2021-10-22 08:05:13 +02:00
],
);
}
/// Shell script execution (--exec) with a custom --path-separator
#[test]
fn test_exec_with_separator() {
let (te, abs_path) = get_test_env_with_abs_path(DEFAULT_DIRS, DEFAULT_FILES);
te.assert_output(
&[
"--path-separator=#",
"--absolute-path",
"foo",
"--exec",
"echo",
],
&format!(
"{abs_path}#a.foo
{abs_path}#one#b.foo
{abs_path}#one#two#C.Foo2
{abs_path}#one#two#c.foo
{abs_path}#one#two#three#d.foo
{abs_path}#one#two#three#directory_foo",
abs_path = abs_path.replace(std::path::MAIN_SEPARATOR, "#"),
),
);
te.assert_output(
&["--path-separator=#", "foo", "--exec", "echo", "{}"],
2021-10-17 05:12:56 +02:00
".#a.foo
.#one#b.foo
.#one#two#C.Foo2
.#one#two#c.foo
.#one#two#three#d.foo
.#one#two#three#directory_foo",
);
te.assert_output(
&["--path-separator=#", "foo", "--exec", "echo", "{.}"],
"a
one#b
one#two#C
one#two#c
one#two#three#d
one#two#three#directory_foo",
);
te.assert_output(
&["--path-separator=#", "foo", "--exec", "echo", "{/}"],
"a.foo
b.foo
C.Foo2
c.foo
d.foo
directory_foo",
);
te.assert_output(
&["--path-separator=#", "foo", "--exec", "echo", "{/.}"],
"a
b
C
c
d
directory_foo",
);
te.assert_output(
&["--path-separator=#", "foo", "--exec", "echo", "{//}"],
".
2021-10-17 05:12:56 +02:00
.#one
.#one#two
.#one#two
.#one#two#three
.#one#two#three",
);
te.assert_output(
&["--path-separator=#", "e1", "--exec", "printf", "%s.%s\n"],
2021-10-17 05:12:56 +02:00
".#e1 e2.",
);
}
/// Non-zero exit code (--quiet)
#[test]
fn test_quiet() {
let dirs = &[];
let files = &["a.foo", "b.foo"];
let te = TestEnv::new(dirs, files);
te.assert_output(&["-q"], "");
te.assert_output(&["--quiet"], "");
te.assert_output(&["--has-results"], "");
te.assert_failure_with_error(&["--quiet", "c.foo"], "")
}
2018-02-10 15:19:53 +01:00
/// Literal search (--fixed-strings)
#[test]
fn test_fixed_strings() {
let dirs = &["test1", "test2"];
let files = &["test1/a.foo", "test1/a_foo", "test2/Download (1).tar.gz"];
let te = TestEnv::new(dirs, files);
// Regex search, dot is treated as "any character"
te.assert_output(
&["a.foo"],
2021-10-17 05:12:56 +02:00
"./test1/a.foo
./test1/a_foo",
2018-02-10 15:19:53 +01:00
);
// Literal search, dot is treated as character
2021-10-17 05:12:56 +02:00
te.assert_output(&["--fixed-strings", "a.foo"], "./test1/a.foo");
2018-02-10 15:19:53 +01:00
// Regex search, parens are treated as group
te.assert_output(&["download (1)"], "");
// Literal search, parens are treated as characters
te.assert_output(
&["--fixed-strings", "download (1)"],
2021-10-17 05:12:56 +02:00
"./test2/Download (1).tar.gz",
2018-02-10 15:19:53 +01:00
);
// Combine with --case-sensitive
te.assert_output(&["--fixed-strings", "--case-sensitive", "download (1)"], "");
}
/// Filenames with invalid UTF-8 sequences
2018-02-25 23:45:59 +01:00
#[cfg(target_os = "linux")]
#[test]
fn test_invalid_utf8() {
use std::ffi::OsStr;
use std::os::unix::ffi::OsStrExt;
let dirs = &["test1"];
let files = &[];
let te = TestEnv::new(dirs, files);
fs::File::create(
te.test_root()
.join(OsStr::from_bytes(b"test1/test_\xFEinvalid.txt")),
2018-09-27 23:01:38 +02:00
)
.unwrap();
te.assert_output(&["", "test1/"], "test1/test_<74>invalid.txt");
te.assert_output(&["invalid", "test1/"], "test1/test_<74>invalid.txt");
// Should not be found under a different extension
te.assert_output(&["-e", "zip", "", "test1/"], "");
}
2018-04-29 22:10:30 +02:00
/// Filtering for file size (--size)
#[test]
fn test_size() {
2018-04-29 22:10:30 +02:00
let te = TestEnv::new(&[], &[]);
2018-04-29 22:10:30 +02:00
create_file_with_size(te.test_root().join("0_bytes.foo"), 0);
create_file_with_size(te.test_root().join("11_bytes.foo"), 11);
create_file_with_size(te.test_root().join("30_bytes.foo"), 30);
create_file_with_size(te.test_root().join("3_kilobytes.foo"), 3 * 1000);
create_file_with_size(te.test_root().join("4_kibibytes.foo"), 4 * 1024);
// Zero and non-zero sized files.
te.assert_output(
2018-04-29 22:10:30 +02:00
&["", "--size", "+0B"],
2021-10-17 05:12:56 +02:00
"./0_bytes.foo
./11_bytes.foo
./30_bytes.foo
./3_kilobytes.foo
./4_kibibytes.foo",
);
// Zero sized files.
2021-10-17 05:12:56 +02:00
te.assert_output(&["", "--size", "-0B"], "./0_bytes.foo");
te.assert_output(&["", "--size", "0B"], "./0_bytes.foo");
te.assert_output(&["", "--size=0B"], "./0_bytes.foo");
te.assert_output(&["", "-S", "0B"], "./0_bytes.foo");
// Files with 2 bytes or more.
te.assert_output(
2018-04-29 22:10:30 +02:00
&["", "--size", "+2B"],
2021-10-17 05:12:56 +02:00
"./11_bytes.foo
./30_bytes.foo
./3_kilobytes.foo
./4_kibibytes.foo",
);
// Files with 2 bytes or less.
2021-10-17 05:12:56 +02:00
te.assert_output(&["", "--size", "-2B"], "./0_bytes.foo");
// Files with size between 1 byte and 11 bytes.
2021-10-17 05:12:56 +02:00
te.assert_output(&["", "--size", "+1B", "--size", "-11B"], "./11_bytes.foo");
// Files with size equal 11 bytes.
2021-10-17 05:12:56 +02:00
te.assert_output(&["", "--size", "11B"], "./11_bytes.foo");
// Files with size between 1 byte and 30 bytes.
te.assert_output(
2018-04-29 22:10:30 +02:00
&["", "--size", "+1B", "--size", "-30B"],
2021-10-17 05:12:56 +02:00
"./11_bytes.foo
./30_bytes.foo",
);
2018-04-29 22:10:30 +02:00
// Combine with a search pattern
2021-10-17 05:12:56 +02:00
te.assert_output(
&["^11_", "--size", "+1B", "--size", "-30B"],
"./11_bytes.foo",
);
2018-04-29 22:10:30 +02:00
// Files with size between 12 and 30 bytes.
2021-10-17 05:12:56 +02:00
te.assert_output(&["", "--size", "+12B", "--size", "-30B"], "./30_bytes.foo");
// Files with size between 31 and 100 bytes.
2018-04-29 22:10:30 +02:00
te.assert_output(&["", "--size", "+31B", "--size", "-100B"], "");
// Files with size between 3 kibibytes and 5 kibibytes.
2021-10-17 05:12:56 +02:00
te.assert_output(
&["", "--size", "+3ki", "--size", "-5ki"],
"./4_kibibytes.foo",
);
// Files with size between 3 kilobytes and 5 kilobytes.
te.assert_output(
2018-04-29 22:10:30 +02:00
&["", "--size", "+3k", "--size", "-5k"],
2021-10-17 05:12:56 +02:00
"./3_kilobytes.foo
./4_kibibytes.foo",
);
2018-04-29 22:10:30 +02:00
// Files with size greater than 3 kilobytes and less than 3 kibibytes.
2021-10-17 05:12:56 +02:00
te.assert_output(
&["", "--size", "+3k", "--size", "-3ki"],
"./3_kilobytes.foo",
);
2018-04-29 22:10:30 +02:00
// Files with size equal 4 kibibytes.
2021-10-17 05:12:56 +02:00
te.assert_output(
&["", "--size", "+4ki", "--size", "-4ki"],
"./4_kibibytes.foo",
);
te.assert_output(&["", "--size", "4ki"], "./4_kibibytes.foo");
}
#[cfg(test)]
fn create_file_with_modified<P: AsRef<Path>>(path: P, duration_in_secs: u64) {
let st = SystemTime::now() - Duration::from_secs(duration_in_secs);
let ft = filetime::FileTime::from_system_time(st);
fs::File::create(&path).expect("creation failed");
filetime::set_file_times(&path, ft, ft).expect("time modification failed");
}
#[cfg(test)]
fn remove_symlink<P: AsRef<Path>>(path: P) {
#[cfg(unix)]
fs::remove_file(path).expect("remove symlink");
// On Windows, symlinks remember whether they point to files or directories, so try both
#[cfg(windows)]
fs::remove_file(path.as_ref())
.or_else(|_| fs::remove_dir(path.as_ref()))
.expect("remove symlink");
}
#[test]
fn test_modified_relative() {
let te = TestEnv::new(&[], &[]);
remove_symlink(te.test_root().join("symlink"));
create_file_with_modified(te.test_root().join("foo_0_now"), 0);
create_file_with_modified(te.test_root().join("bar_1_min"), 60);
create_file_with_modified(te.test_root().join("foo_10_min"), 600);
create_file_with_modified(te.test_root().join("bar_1_h"), 60 * 60);
create_file_with_modified(te.test_root().join("foo_2_h"), 2 * 60 * 60);
create_file_with_modified(te.test_root().join("bar_1_day"), 24 * 60 * 60);
te.assert_output(
&["", "--changed-within", "15min"],
2021-10-17 05:12:56 +02:00
"./foo_0_now
./bar_1_min
./foo_10_min",
);
te.assert_output(
2018-10-27 15:34:10 +02:00
&["", "--change-older-than", "15min"],
2021-10-17 05:12:56 +02:00
"./bar_1_h
./foo_2_h
./bar_1_day",
);
te.assert_output(
&["foo", "--changed-within", "12h"],
2021-10-17 05:12:56 +02:00
"./foo_0_now
./foo_10_min
./foo_2_h",
);
}
#[cfg(test)]
fn change_file_modified<P: AsRef<Path>>(path: P, iso_date: &str) {
let st = humantime::parse_rfc3339(iso_date).expect("invalid date");
let ft = filetime::FileTime::from_system_time(st);
filetime::set_file_times(path, ft, ft).expect("time modification failde");
}
#[test]
fn test_modified_absolute() {
let te = TestEnv::new(&[], &["15mar2018", "30dec2017"]);
remove_symlink(te.test_root().join("symlink"));
change_file_modified(te.test_root().join("15mar2018"), "2018-03-15T12:00:00Z");
change_file_modified(te.test_root().join("30dec2017"), "2017-12-30T23:59:00Z");
te.assert_output(
2018-10-27 15:34:10 +02:00
&["", "--change-newer-than", "2018-01-01 00:00:00"],
2021-10-17 05:12:56 +02:00
"./15mar2018",
);
te.assert_output(
&["", "--changed-before", "2018-01-01 00:00:00"],
2021-10-17 05:12:56 +02:00
"./30dec2017",
);
}
2019-04-14 17:03:18 +02:00
#[test]
fn test_custom_path_separator() {
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
te.assert_output(
&["foo", "one", "--path-separator", "="],
"one=b.foo
one=two=c.foo
one=two=C.Foo2
one=two=three=d.foo
one=two=three=directory_foo",
);
}
#[test]
fn test_base_directory() {
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
te.assert_output(
&["--base-directory", "one"],
2021-10-17 05:12:56 +02:00
"./b.foo
./two
./two/c.foo
./two/C.Foo2
./two/three
./two/three/d.foo
./two/three/directory_foo",
);
2020-01-01 12:04:58 +01:00
te.assert_output(
&["--base-directory", "one/two", "foo"],
2021-10-17 05:12:56 +02:00
"./c.foo
./C.Foo2
./three/d.foo
./three/directory_foo",
);
// Explicit root path
te.assert_output(
&["--base-directory", "one", "foo", "two"],
"two/c.foo
two/C.Foo2
two/three/d.foo
two/three/directory_foo",
);
// Ignore base directory when absolute path is used
let (te, abs_path) = get_test_env_with_abs_path(DEFAULT_DIRS, DEFAULT_FILES);
let abs_base_dir = &format!("{abs_path}/one/two", abs_path = &abs_path);
te.assert_output(
&["--base-directory", abs_base_dir, "foo", &abs_path],
&format!(
"{abs_path}/a.foo
{abs_path}/one/b.foo
{abs_path}/one/two/c.foo
{abs_path}/one/two/C.Foo2
{abs_path}/one/two/three/d.foo
{abs_path}/one/two/three/directory_foo",
abs_path = &abs_path
),
);
}
#[test]
fn test_max_results() {
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
// Unrestricted
te.assert_output(
&["--max-results=0", "c.foo"],
2021-10-17 05:12:56 +02:00
"./one/two/C.Foo2
./one/two/c.foo",
);
// Limited to two results
te.assert_output(
&["--max-results=2", "c.foo"],
2021-10-17 05:12:56 +02:00
"./one/two/C.Foo2
./one/two/c.foo",
);
// Limited to one result. We could find either C.Foo2 or c.foo
2020-04-09 17:21:40 +02:00
let assert_just_one_result_with_option = |option| {
let output = te.assert_success_and_get_output(".", &[option, "c.foo"]);
let stdout = String::from_utf8_lossy(&output.stdout)
.trim()
.replace(&std::path::MAIN_SEPARATOR.to_string(), "/");
2021-10-17 05:12:56 +02:00
assert!(stdout == "./one/two/C.Foo2" || stdout == "./one/two/c.foo");
2020-04-09 17:21:40 +02:00
};
assert_just_one_result_with_option("--max-results=1");
assert_just_one_result_with_option("-1");
}
/// Filenames with non-utf8 paths are passed to the executed program unchanged
///
/// Note:
/// - the test is disabled on Darwin/OSX, since it coerces file names to UTF-8,
/// even when the requested file name is not valid UTF-8.
/// - the test is currently disabled on Windows because I'm not sure how to create
/// invalid UTF-8 files on Windows
#[cfg(all(unix, not(target_os = "macos")))]
#[test]
fn test_exec_invalid_utf8() {
use std::ffi::OsStr;
use std::os::unix::ffi::OsStrExt;
let dirs = &["test1"];
let files = &[];
let te = TestEnv::new(dirs, files);
fs::File::create(
te.test_root()
.join(OsStr::from_bytes(b"test1/test_\xFEinvalid.txt")),
)
.unwrap();
te.assert_output_raw(
&["", "test1/", "--exec", "echo", "{}"],
b"test1/test_\xFEinvalid.txt\n",
);
te.assert_output_raw(
&["", "test1/", "--exec", "echo", "{/}"],
b"test_\xFEinvalid.txt\n",
);
te.assert_output_raw(&["", "test1/", "--exec", "echo", "{//}"], b"test1\n");
te.assert_output_raw(
&["", "test1/", "--exec", "echo", "{.}"],
b"test1/test_\xFEinvalid\n",
);
te.assert_output_raw(
&["", "test1/", "--exec", "echo", "{/.}"],
b"test_\xFEinvalid\n",
);
}
2020-04-15 23:08:15 +02:00
#[test]
fn test_list_details() {
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
// Make sure we can execute 'fd --list-details' without any errors.
te.assert_success_and_get_output(".", &["--list-details"]);
}
/// Make sure that fd fails if numeric arguments can not be parsed
#[test]
fn test_number_parsing_errors() {
let te = TestEnv::new(&[], &[]);
te.assert_failure(&["--threads=a"]);
te.assert_failure(&["-j", ""]);
te.assert_failure(&["--threads=0"]);
te.assert_failure(&["--min-depth=a"]);
te.assert_failure(&["--max-depth=a"]);
te.assert_failure(&["--maxdepth=a"]);
te.assert_failure(&["--exact-depth=a"]);
te.assert_failure(&["--max-buffer-time=a"]);
te.assert_failure(&["--max-results=a"]);
}
#[test_case("--hidden", &["--no-hidden"] ; "hidden")]
#[test_case("--no-ignore", &["--ignore"] ; "no-ignore")]
#[test_case("--no-ignore-vcs", &["--ignore-vcs"] ; "no-ignore-vcs")]
#[test_case("--follow", &["--no-follow"] ; "follow")]
#[test_case("--absolute-path", &["--relative-path"] ; "absolute-path")]
#[test_case("-u", &["--ignore"] ; "u")]
#[test_case("-uu", &["--ignore", "--no-hidden"] ; "uu")]
fn test_opposing(flag: &str, opposing_flags: &[&str]) {
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
let mut flags = vec![flag];
flags.extend_from_slice(opposing_flags);
let out_no_flags = te.assert_success_and_get_output(".", &[]);
let out_opposing_flags = te.assert_success_and_get_output(".", &flags);
assert_eq!(
out_no_flags,
out_opposing_flags,
"{} should override {}",
opposing_flags.join(" "),
flag
);
}
/// Print error if search pattern starts with a dot and --hidden is not set
/// (Unix only, hidden files on Windows work differently)
#[test]
#[cfg(unix)]
fn test_error_if_hidden_not_set_and_pattern_starts_with_dot() {
let te = TestEnv::new(&[], &[".gitignore", ".whatever", "non-hidden"]);
te.assert_failure(&["^\\.gitignore"]);
te.assert_failure(&["--glob", ".gitignore"]);
2021-10-17 05:12:56 +02:00
te.assert_output(&["--hidden", "^\\.gitignore"], "./.gitignore");
te.assert_output(&["--hidden", "--glob", ".gitignore"], "./.gitignore");
te.assert_output(&[".gitignore"], "");
}
#[test]
fn test_strip_cwd_prefix() {
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
te.assert_output(
&["--strip-cwd-prefix", "."],
2021-10-17 06:21:52 +02:00
"a.foo
e1 e2
one
one/b.foo
one/two
one/two/c.foo
one/two/C.Foo2
one/two/three
one/two/three/d.foo
one/two/three/directory_foo
symlink",
);
}