mirror of
https://github.com/sharkdp/fd
synced 2024-10-04 14:59:15 +00:00
Re-write integration tests in Rust (#67)
* Rewrite integration tests in Rust. * Improve failure output for integration tests. * Move TestEnv to separate module. * Remove old integration tests script. * Re-add integration test for subdirectory.
This commit is contained in:
parent
00b57b50ae
commit
6f22957cdc
|
@ -33,9 +33,6 @@ matrix:
|
|||
rust: 1.16.0
|
||||
env: TARGET=x86_64-unknown-linux-musl
|
||||
|
||||
after_success:
|
||||
- bash tests/test.sh
|
||||
|
||||
notifications:
|
||||
email:
|
||||
on_success: never
|
||||
|
|
67
Cargo.lock
generated
67
Cargo.lock
generated
|
@ -5,9 +5,11 @@ dependencies = [
|
|||
"ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.26.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"diff 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ignore 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -33,6 +35,11 @@ dependencies = [
|
|||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "0.9.1"
|
||||
|
@ -54,11 +61,29 @@ dependencies = [
|
|||
"vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "conv"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "custom_derive"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "diff"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.5"
|
||||
|
@ -115,6 +140,23 @@ name = "log"
|
|||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "magenta"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"magenta-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "magenta-sys"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "1.0.1"
|
||||
|
@ -131,6 +173,15 @@ dependencies = [
|
|||
"libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.3.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "0.2.2"
|
||||
|
@ -162,6 +213,14 @@ name = "strsim"
|
|||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "tempdir"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "term_size"
|
||||
version = "0.3.0"
|
||||
|
@ -247,9 +306,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699"
|
||||
"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6"
|
||||
"checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159"
|
||||
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
|
||||
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
|
||||
"checksum clap 2.26.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2267a8fdd4dce6956ba6649e130f62fb279026e5e84b92aa939ac8f85ce3f9f0"
|
||||
"checksum conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299"
|
||||
"checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97"
|
||||
"checksum custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9"
|
||||
"checksum diff 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0a515461b6c8c08419850ced27bc29e86166dcdcde8fbe76f8b1f0589bb49472"
|
||||
"checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344"
|
||||
"checksum globset 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "feeb1b6840809ef5efcf7a4a990bc4e1b7ee3df8cf9e2379a75aeb2ba42ac9c3"
|
||||
"checksum ignore 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b3fcaf2365eb14b28ec7603c98c06cc531f19de9eb283d89a3dff8417c8c99f5"
|
||||
|
@ -257,12 +320,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf"
|
||||
"checksum libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)" = "2370ca07ec338939e356443dac2296f581453c35fe1e3a3ed06023c49435f915"
|
||||
"checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b"
|
||||
"checksum magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf0336886480e671965f794bc9b6fce88503563013d1bfb7a502c81fe3ac527"
|
||||
"checksum magenta-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40d014c7011ac470ae28e2f76a02bfea4a8480f73e701353b49ad7a8d75f4699"
|
||||
"checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4"
|
||||
"checksum num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aec53c34f2d0247c5ca5d32cca1478762f301740468ee9ee6dcb7a0dd7a0c584"
|
||||
"checksum rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "eb250fd207a4729c976794d03db689c9be1d634ab5a1c9da9492a13d8fecbcdf"
|
||||
"checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b"
|
||||
"checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db"
|
||||
"checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7"
|
||||
"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
|
||||
"checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6"
|
||||
"checksum term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2b6b55df3198cc93372e85dd2ed817f0e38ce8cc0f22eb32391bfad9c4bf209"
|
||||
"checksum textwrap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f728584ea33b0ad19318e20557cb0a39097751dbb07171419673502f848c7af6"
|
||||
"checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14"
|
||||
|
|
|
@ -29,4 +29,8 @@ ignore = "0.2"
|
|||
num_cpus = "1.6.2"
|
||||
|
||||
[build-dependencies]
|
||||
clap = "2.26.0"
|
||||
clap = "2.26.0"
|
||||
|
||||
[dev-dependencies]
|
||||
diff = "0.1"
|
||||
tempdir = "0.3"
|
254
tests/test.sh
254
tests/test.sh
|
@ -1,254 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
|
||||
fd="${SCRIPT_DIR}/../target/debug/fd"
|
||||
|
||||
MKTEMP_TEMPLATE="fd-tests.XXXXXXXXXX"
|
||||
|
||||
# Stabilize sort
|
||||
export LC_ALL="C"
|
||||
export LC_CTYPE="UTF-8"
|
||||
|
||||
export reset='\x1b[0m'
|
||||
export bold='\x1b[01m'
|
||||
export green='\x1b[32;01m'
|
||||
export red='\x1b[31;01m'
|
||||
|
||||
set -eou pipefail
|
||||
|
||||
suite() {
|
||||
echo
|
||||
echo -e "${bold}$1${reset}"
|
||||
echo
|
||||
}
|
||||
|
||||
expect() {
|
||||
expected_output="$1"
|
||||
shift
|
||||
|
||||
tmp_expected="$(mktemp -t "$MKTEMP_TEMPLATE")"
|
||||
tmp_output="$(mktemp -t "$MKTEMP_TEMPLATE")"
|
||||
|
||||
echo "$expected_output" > "$tmp_expected"
|
||||
|
||||
# Use python instead of sed here (for this to work on macOS)
|
||||
"$fd" "$@" | python -c 'import sys; sys.stdout.write(sys.stdin.read().replace("\0", "NULL\n"))' | sort -f > "$tmp_output"
|
||||
|
||||
echo -ne " ${bold}▶${reset} Testing 'fd $*' ... "
|
||||
|
||||
if diff -q "$tmp_expected" "$tmp_output" > /dev/null; then
|
||||
echo -e "${green}✓ okay${reset}"
|
||||
|
||||
rm -f "$tmp_expected" "$tmp_output"
|
||||
else
|
||||
echo -e "${red}❌FAILED${reset}"
|
||||
|
||||
echo -ne "\nShowing diff between ${red}expected${reset} and "
|
||||
echo -e "${green}actual${reset} output:\n"
|
||||
|
||||
diff -C3 --label expected --label actual \
|
||||
"$tmp_expected" "$tmp_output" || true
|
||||
|
||||
rm -f "$tmp_expected" "$tmp_output"
|
||||
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
root=$(mktemp -d -t "$MKTEMP_TEMPLATE")
|
||||
|
||||
cd "$root"
|
||||
|
||||
# Setup test environment
|
||||
|
||||
mkdir -p one/two/three
|
||||
|
||||
touch a.foo
|
||||
touch one/b.foo
|
||||
touch one/two/c.foo
|
||||
touch one/two/C.Foo2
|
||||
touch one/two/three/d.foo
|
||||
mkdir one/two/three/directory_foo
|
||||
touch ignored.foo
|
||||
touch .hidden.foo
|
||||
ln -s one/two symlink
|
||||
|
||||
echo "ignored.foo" > .ignore
|
||||
|
||||
|
||||
# Run the tests
|
||||
|
||||
suite "Simple tests"
|
||||
expect "a.foo" a.foo
|
||||
expect "one/b.foo" b.foo
|
||||
expect "one/two/three/d.foo" d.foo
|
||||
expect "a.foo
|
||||
one/b.foo
|
||||
one/two/c.foo
|
||||
one/two/C.Foo2
|
||||
one/two/three/d.foo
|
||||
one/two/three/directory_foo" foo
|
||||
expect "a.foo
|
||||
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" # run 'fd' without arguments
|
||||
|
||||
suite "Explicit root path"
|
||||
expect "one/b.foo
|
||||
one/two/c.foo
|
||||
one/two/C.Foo2
|
||||
one/two/three/d.foo
|
||||
one/two/three/directory_foo" foo one
|
||||
expect "one/two/three/d.foo
|
||||
one/two/three/directory_foo" foo one/two/three
|
||||
(
|
||||
cd one/two
|
||||
expect "../../a.foo
|
||||
../b.foo
|
||||
c.foo
|
||||
C.Foo2
|
||||
three/d.foo
|
||||
three/directory_foo" foo ../../
|
||||
)
|
||||
|
||||
suite "Regex searches"
|
||||
expect "a.foo
|
||||
one/b.foo
|
||||
one/two/c.foo
|
||||
one/two/C.Foo2" '[a-c].foo'
|
||||
expect "a.foo
|
||||
one/b.foo
|
||||
one/two/c.foo" --case-sensitive '[a-c].foo'
|
||||
|
||||
|
||||
|
||||
suite "Smart case"
|
||||
expect "one/two/c.foo
|
||||
one/two/C.Foo2" c.foo
|
||||
expect "one/two/C.Foo2" C.Foo
|
||||
expect "one/two/C.Foo2" Foo
|
||||
|
||||
|
||||
suite "Case-sensitivity (--case-sensitive)"
|
||||
expect "one/two/c.foo" --case-sensitive c.foo
|
||||
expect "one/two/C.Foo2" --case-sensitive C.Foo
|
||||
|
||||
|
||||
suite "Full path search (--full-path)"
|
||||
expect "one/two/three/d.foo
|
||||
one/two/three/directory_foo" --full-path 'three.*foo'
|
||||
expect "a.foo" --full-path '^a\.foo$'
|
||||
|
||||
|
||||
suite "Hidden files (--hidden)"
|
||||
expect ".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" --hidden foo
|
||||
|
||||
|
||||
suite "Ignored files (--no-ignore)"
|
||||
expect "a.foo
|
||||
ignored.foo
|
||||
one/b.foo
|
||||
one/two/c.foo
|
||||
one/two/C.Foo2
|
||||
one/two/three/d.foo
|
||||
one/two/three/directory_foo" --no-ignore foo
|
||||
|
||||
expect ".hidden.foo
|
||||
a.foo
|
||||
ignored.foo
|
||||
one/b.foo
|
||||
one/two/c.foo
|
||||
one/two/C.Foo2
|
||||
one/two/three/d.foo
|
||||
one/two/three/directory_foo" --hidden --no-ignore foo
|
||||
|
||||
|
||||
suite "Symlinks (--follow)"
|
||||
expect "one/two/c.foo
|
||||
one/two/C.Foo2
|
||||
symlink/c.foo
|
||||
symlink/C.Foo2" --follow c.foo
|
||||
|
||||
suite "Null separator (--print0)"
|
||||
expect "a.fooNULL
|
||||
one/b.fooNULL
|
||||
one/two/C.Foo2NULL
|
||||
one/two/c.fooNULL
|
||||
one/two/three/d.fooNULL
|
||||
one/two/three/directory_fooNULL" --print0 foo
|
||||
|
||||
|
||||
suite "Maximum depth (--max-depth)"
|
||||
expect "a.foo
|
||||
one
|
||||
one/b.foo
|
||||
one/two
|
||||
one/two/c.foo
|
||||
one/two/C.Foo2
|
||||
one/two/three
|
||||
symlink" --max-depth 3
|
||||
expect "a.foo
|
||||
one
|
||||
one/b.foo
|
||||
one/two
|
||||
symlink" --max-depth 2
|
||||
expect "a.foo
|
||||
one
|
||||
symlink" --max-depth 1
|
||||
|
||||
abs_path=$(python -c "import os; print(os.path.realpath('$root'))")
|
||||
|
||||
suite "Absolute paths (--absolute-path)"
|
||||
expect "$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" --absolute-path foo
|
||||
expect "$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" foo "$abs_path"
|
||||
|
||||
|
||||
suite "File type filter (--type)"
|
||||
expect "a.foo
|
||||
one/b.foo
|
||||
one/two/c.foo
|
||||
one/two/C.Foo2
|
||||
one/two/three/d.foo" --type f
|
||||
expect "one
|
||||
one/two
|
||||
one/two/three
|
||||
one/two/three/directory_foo" --type d
|
||||
expect "symlink" --type s
|
||||
|
||||
|
||||
suite "File extension (--extension)"
|
||||
expect "a.foo
|
||||
one/b.foo
|
||||
one/two/c.foo
|
||||
one/two/three/d.foo" --extension foo
|
||||
expect "a.foo
|
||||
one/b.foo
|
||||
one/two/c.foo
|
||||
one/two/three/d.foo" --extension .foo
|
||||
expect "one/two/C.Foo2" --extension foo2
|
||||
|
||||
# All done
|
||||
echo
|
169
tests/testenv/mod.rs
Normal file
169
tests/testenv/mod.rs
Normal file
|
@ -0,0 +1,169 @@
|
|||
use std;
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::io;
|
||||
use std::io::Write;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process;
|
||||
|
||||
#[cfg(unix)]
|
||||
use std::os::unix;
|
||||
|
||||
#[cfg(windows)]
|
||||
use std::os::windows;
|
||||
|
||||
extern crate diff;
|
||||
extern crate tempdir;
|
||||
|
||||
use self::tempdir::TempDir;
|
||||
|
||||
/// Environment for the integration tests.
|
||||
pub struct TestEnv {
|
||||
/// Temporary working directory.
|
||||
temp_dir: TempDir,
|
||||
|
||||
/// Path to the *fd* executable.
|
||||
fd_exe: PathBuf,
|
||||
}
|
||||
|
||||
/// Create the working directory and the test files.
|
||||
fn create_working_directory() -> Result<TempDir, io::Error> {
|
||||
let temp_dir = TempDir::new("fd-tests")?;
|
||||
|
||||
{
|
||||
let root = temp_dir.path();
|
||||
|
||||
fs::create_dir_all(root.join("one/two/three"))?;
|
||||
|
||||
fs::File::create(root.join("a.foo"))?;
|
||||
fs::File::create(root.join("one/b.foo"))?;
|
||||
fs::File::create(root.join("one/two/c.foo"))?;
|
||||
fs::File::create(root.join("one/two/C.Foo2"))?;
|
||||
fs::File::create(root.join("one/two/three/d.foo"))?;
|
||||
fs::create_dir(root.join("one/two/three/directory_foo"))?;
|
||||
fs::File::create(root.join("ignored.foo"))?;
|
||||
fs::File::create(root.join(".hidden.foo"))?;
|
||||
|
||||
#[cfg(unix)]
|
||||
unix::fs::symlink(root.join("one/two"), root.join("symlink"))?;
|
||||
|
||||
#[cfg(windows)]
|
||||
windows::fs::symlink_dir(root.join("one/two"), root.join("symlink"))?;
|
||||
|
||||
fs::File::create(root.join(".ignore"))?.write_all(b"ignored.foo")?;
|
||||
}
|
||||
|
||||
Ok(temp_dir)
|
||||
}
|
||||
|
||||
/// Find the *fd* executable.
|
||||
fn find_fd_exe() -> PathBuf {
|
||||
// Tests exe is in target/debug/deps, the *fd* exe is in target/debug
|
||||
let root = env::current_exe().expect("tests executable")
|
||||
.parent().expect("tests executable directory")
|
||||
.parent().expect("fd executable directory")
|
||||
.to_path_buf();
|
||||
|
||||
let exe_name = if cfg!(windows) { "fd.exe" } else { "fd" };
|
||||
|
||||
root.join(exe_name)
|
||||
}
|
||||
|
||||
/// Format an error message for when *fd* did not exit successfully.
|
||||
fn format_exit_error(args: &[&str], output: &process::Output) -> String {
|
||||
format!(
|
||||
"`fd {}` did not exit successfully.\nstdout:\n---\n{}---\nstderr:\n---\n{}---",
|
||||
args.join(" "),
|
||||
String::from_utf8_lossy(&output.stdout),
|
||||
String::from_utf8_lossy(&output.stderr))
|
||||
}
|
||||
|
||||
/// Format an error message for when the output of *fd* did not match the expected output.
|
||||
fn format_output_error(args: &[&str], expected: &str, actual: &str) -> String {
|
||||
// Generate diff text.
|
||||
let diff_text =
|
||||
diff::lines(expected, actual)
|
||||
.into_iter()
|
||||
.map(|diff| {
|
||||
match diff {
|
||||
diff::Result::Left(l) => format!("-{}", l),
|
||||
diff::Result::Both(l, _) => format!(" {}", l),
|
||||
diff::Result::Right(r) => format!("+{}", r),
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
|
||||
format!(
|
||||
concat!(
|
||||
"`fd {}` did not produce the expected output.\n",
|
||||
"Showing diff between expected and actual:\n{}\n"),
|
||||
args.join(" "),
|
||||
diff_text)
|
||||
}
|
||||
|
||||
/// Normalize the output for comparison.
|
||||
fn normalize_output(s: &str, trim_left: bool) -> String {
|
||||
// Split into lines and normalize separators.
|
||||
let mut lines = s
|
||||
.replace('\0', "NULL\n")
|
||||
.lines()
|
||||
.map(|line| {
|
||||
let line = if trim_left { line.trim_left() } else { line };
|
||||
line.replace('/', &std::path::MAIN_SEPARATOR.to_string())
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Sort ignoring case.
|
||||
lines.sort_by_key(|s| s.to_lowercase());
|
||||
|
||||
lines.join("\n")
|
||||
}
|
||||
|
||||
impl TestEnv {
|
||||
pub fn new() -> TestEnv {
|
||||
let temp_dir = create_working_directory().expect("working directory");
|
||||
let fd_exe = find_fd_exe();
|
||||
|
||||
TestEnv {
|
||||
temp_dir: temp_dir,
|
||||
fd_exe: fd_exe,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the root directory for the tests.
|
||||
pub fn root(&self) -> PathBuf {
|
||||
self.temp_dir.path().to_path_buf()
|
||||
}
|
||||
|
||||
/// Assert that calling *fd* with the specified arguments produces the expected output.
|
||||
pub fn assert_output(&self, args: &[&str], expected: &str) {
|
||||
self.assert_output_subdirectory(".", args, expected)
|
||||
}
|
||||
|
||||
/// Assert that calling *fd* in the specified path under the root working directory,
|
||||
/// and with the specified arguments produces the expected output.
|
||||
pub fn assert_output_subdirectory<P: AsRef<Path>>(&self, path: P, args: &[&str], expected: &str) {
|
||||
// Setup *fd* command.
|
||||
let mut cmd = process::Command::new(&self.fd_exe);
|
||||
cmd.current_dir(self.temp_dir.path().join(path));
|
||||
cmd.args(args);
|
||||
|
||||
// Run *fd*.
|
||||
let output = cmd.output().expect("fd output");
|
||||
|
||||
// Check for exit status.
|
||||
if !output.status.success() {
|
||||
panic!(format_exit_error(args, &output));
|
||||
}
|
||||
|
||||
// Normalize both expected and actual output.
|
||||
let expected = normalize_output(expected, true);
|
||||
let actual = normalize_output(&String::from_utf8_lossy(&output.stdout), false);
|
||||
|
||||
// Compare actual output to expected output.
|
||||
if expected != actual {
|
||||
panic!(format_output_error(args, &expected, &actual));
|
||||
}
|
||||
}
|
||||
}
|
327
tests/tests.rs
Normal file
327
tests/tests.rs
Normal file
|
@ -0,0 +1,327 @@
|
|||
//! Integration tests for the CLI interface of fd.
|
||||
|
||||
#![allow(dead_code, unused_imports)]
|
||||
|
||||
mod testenv;
|
||||
|
||||
use testenv::TestEnv;
|
||||
|
||||
/// Simple tests
|
||||
#[test]
|
||||
fn test_simple() {
|
||||
let te = TestEnv::new();
|
||||
|
||||
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"],
|
||||
"a.foo
|
||||
one/b.foo
|
||||
one/two/c.foo
|
||||
one/two/C.Foo2
|
||||
one/two/three/d.foo
|
||||
one/two/three/directory_foo");
|
||||
|
||||
te.assert_output(
|
||||
&[],
|
||||
"a.foo
|
||||
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");
|
||||
}
|
||||
|
||||
/// Explicit root path
|
||||
// TODO: Fails on windows
|
||||
#[cfg_attr(windows, ignore)]
|
||||
#[test]
|
||||
fn test_explicit_root_path() {
|
||||
let te = TestEnv::new();
|
||||
|
||||
te.assert_output(
|
||||
&["foo", "one"],
|
||||
"one/b.foo
|
||||
one/two/c.foo
|
||||
one/two/C.Foo2
|
||||
one/two/three/d.foo
|
||||
one/two/three/directory_foo");
|
||||
|
||||
te.assert_output(
|
||||
&["foo", "one/two/three"],
|
||||
"one/two/three/d.foo
|
||||
one/two/three/directory_foo");
|
||||
|
||||
te.assert_output_subdirectory(
|
||||
"one/two",
|
||||
&["foo", "../../"],
|
||||
"../../a.foo
|
||||
../b.foo
|
||||
c.foo
|
||||
C.Foo2
|
||||
three/d.foo
|
||||
three/directory_foo");
|
||||
}
|
||||
|
||||
/// Regex searches
|
||||
#[test]
|
||||
fn test_regex_searches() {
|
||||
let te = TestEnv::new();
|
||||
|
||||
te.assert_output(
|
||||
&["[a-c].foo"],
|
||||
"a.foo
|
||||
one/b.foo
|
||||
one/two/c.foo
|
||||
one/two/C.Foo2");
|
||||
|
||||
te.assert_output(
|
||||
&["--case-sensitive", "[a-c].foo"],
|
||||
"a.foo
|
||||
one/b.foo
|
||||
one/two/c.foo");
|
||||
}
|
||||
|
||||
/// Smart case
|
||||
#[test]
|
||||
fn test_smart_case() {
|
||||
let te = TestEnv::new();
|
||||
|
||||
te.assert_output(
|
||||
&["c.foo"],
|
||||
"one/two/c.foo
|
||||
one/two/C.Foo2");
|
||||
|
||||
te.assert_output(
|
||||
&["C.Foo"],
|
||||
"one/two/C.Foo2");
|
||||
|
||||
te.assert_output(
|
||||
&["Foo"],
|
||||
"one/two/C.Foo2");
|
||||
}
|
||||
|
||||
/// Case sensitivity (--case-sensitive)
|
||||
#[test]
|
||||
fn test_case_sensitive() {
|
||||
let te = TestEnv::new();
|
||||
|
||||
te.assert_output(
|
||||
&["--case-sensitive", "c.foo"],
|
||||
"one/two/c.foo");
|
||||
|
||||
te.assert_output(
|
||||
&["--case-sensitive", "C.Foo"],
|
||||
"one/two/C.Foo2");
|
||||
}
|
||||
|
||||
/// Full path search (--full-path)
|
||||
#[test]
|
||||
fn test_full_path() {
|
||||
let te = TestEnv::new();
|
||||
|
||||
te.assert_output(
|
||||
&["--full-path", "three.*foo"],
|
||||
"one/two/three/d.foo
|
||||
one/two/three/directory_foo");
|
||||
|
||||
te.assert_output(
|
||||
&["--full-path", "^a\\.foo"],
|
||||
"a.foo");
|
||||
}
|
||||
|
||||
/// Hidden files (--hidden)
|
||||
#[test]
|
||||
fn test_hidden() {
|
||||
let te = TestEnv::new();
|
||||
|
||||
te.assert_output(
|
||||
&["--hidden", "foo"],
|
||||
".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");
|
||||
}
|
||||
|
||||
/// Ignored files (--no-ignore)
|
||||
#[test]
|
||||
fn test_no_ignore() {
|
||||
let te = TestEnv::new();
|
||||
|
||||
te.assert_output(
|
||||
&["--no-ignore", "foo"],
|
||||
"a.foo
|
||||
ignored.foo
|
||||
one/b.foo
|
||||
one/two/c.foo
|
||||
one/two/C.Foo2
|
||||
one/two/three/d.foo
|
||||
one/two/three/directory_foo");
|
||||
|
||||
te.assert_output(
|
||||
&["--hidden", "--no-ignore", "foo"],
|
||||
".hidden.foo
|
||||
a.foo
|
||||
ignored.foo
|
||||
one/b.foo
|
||||
one/two/c.foo
|
||||
one/two/C.Foo2
|
||||
one/two/three/d.foo
|
||||
one/two/three/directory_foo");
|
||||
}
|
||||
|
||||
/// Symlinks (--follow)
|
||||
#[test]
|
||||
fn test_follow() {
|
||||
let te = TestEnv::new();
|
||||
|
||||
te.assert_output(
|
||||
&["--follow", "c.foo"],
|
||||
"one/two/c.foo
|
||||
one/two/C.Foo2
|
||||
symlink/c.foo
|
||||
symlink/C.Foo2");
|
||||
}
|
||||
|
||||
/// Null separator (--print0)
|
||||
#[test]
|
||||
fn test_print0() {
|
||||
let te = TestEnv::new();
|
||||
|
||||
te.assert_output(
|
||||
&["--print0", "foo"],
|
||||
"a.fooNULL
|
||||
one/b.fooNULL
|
||||
one/two/C.Foo2NULL
|
||||
one/two/c.fooNULL
|
||||
one/two/three/d.fooNULL
|
||||
one/two/three/directory_fooNULL");
|
||||
}
|
||||
|
||||
/// Maximum depth (--max-depth)
|
||||
#[test]
|
||||
fn test_max_depth() {
|
||||
let te = TestEnv::new();
|
||||
|
||||
te.assert_output(
|
||||
&["--max-depth", "3"],
|
||||
"a.foo
|
||||
one
|
||||
one/b.foo
|
||||
one/two
|
||||
one/two/c.foo
|
||||
one/two/C.Foo2
|
||||
one/two/three
|
||||
symlink");
|
||||
|
||||
te.assert_output(
|
||||
&["--max-depth", "2"],
|
||||
"a.foo
|
||||
one
|
||||
one/b.foo
|
||||
one/two
|
||||
symlink");
|
||||
|
||||
te.assert_output(
|
||||
&["--max-depth", "1"],
|
||||
"a.foo
|
||||
one
|
||||
symlink");
|
||||
}
|
||||
|
||||
/// Absolute paths (--absolute-path)
|
||||
// TODO: fails on windows
|
||||
#[cfg_attr(windows, ignore)]
|
||||
#[test]
|
||||
fn test_absolute_path() {
|
||||
let te = TestEnv::new();
|
||||
|
||||
let abs_path = te.root()
|
||||
.canonicalize().expect("absolute path")
|
||||
.to_str().expect("string")
|
||||
.to_string();
|
||||
|
||||
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
|
||||
)
|
||||
);
|
||||
|
||||
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
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/// File type filter (--type)
|
||||
#[test]
|
||||
fn test_type() {
|
||||
let te = TestEnv::new();
|
||||
|
||||
te.assert_output(
|
||||
&["--type", "f"],
|
||||
"a.foo
|
||||
one/b.foo
|
||||
one/two/c.foo
|
||||
one/two/C.Foo2
|
||||
one/two/three/d.foo");
|
||||
|
||||
te.assert_output(
|
||||
&["--type", "d"],
|
||||
"one
|
||||
one/two
|
||||
one/two/three
|
||||
one/two/three/directory_foo");
|
||||
|
||||
te.assert_output(
|
||||
&["--type", "s"],
|
||||
"symlink");
|
||||
}
|
||||
|
||||
/// File extension (--extension)
|
||||
#[test]
|
||||
fn test_extension() {
|
||||
let te = TestEnv::new();
|
||||
|
||||
te.assert_output(
|
||||
&["--extension", "foo"],
|
||||
"a.foo
|
||||
one/b.foo
|
||||
one/two/c.foo
|
||||
one/two/three/d.foo");
|
||||
|
||||
te.assert_output(
|
||||
&["--extension", ".foo"],
|
||||
"a.foo
|
||||
one/b.foo
|
||||
one/two/c.foo
|
||||
one/two/three/d.foo");
|
||||
|
||||
te.assert_output(
|
||||
&["--extension", "foo2"],
|
||||
"one/two/C.Foo2");
|
||||
}
|
Loading…
Reference in a new issue