From 6f22957cdc4fe2f9d36a405eba32d64a6351814f Mon Sep 17 00:00:00 2001 From: Matthias Reitinger Date: Wed, 4 Oct 2017 23:19:30 +0200 Subject: [PATCH] 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. --- .travis.yml | 3 - Cargo.lock | 67 +++++++++ Cargo.toml | 6 +- tests/test.sh | 254 --------------------------------- tests/testenv/mod.rs | 169 ++++++++++++++++++++++ tests/tests.rs | 327 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 568 insertions(+), 258 deletions(-) delete mode 100755 tests/test.sh create mode 100644 tests/testenv/mod.rs create mode 100644 tests/tests.rs diff --git a/.travis.yml b/.travis.yml index 8d653ea..1793fef 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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 diff --git a/Cargo.lock b/Cargo.lock index 703c1f4..e178c57 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml index f7f76e9..49fe36b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,4 +29,8 @@ ignore = "0.2" num_cpus = "1.6.2" [build-dependencies] -clap = "2.26.0" \ No newline at end of file +clap = "2.26.0" + +[dev-dependencies] +diff = "0.1" +tempdir = "0.3" \ No newline at end of file diff --git a/tests/test.sh b/tests/test.sh deleted file mode 100755 index 80a98e9..0000000 --- a/tests/test.sh +++ /dev/null @@ -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 diff --git a/tests/testenv/mod.rs b/tests/testenv/mod.rs new file mode 100644 index 0000000..418bf13 --- /dev/null +++ b/tests/testenv/mod.rs @@ -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 { + 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::>() + .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::>(); + + // 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>(&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)); + } + } +} diff --git a/tests/tests.rs b/tests/tests.rs new file mode 100644 index 0000000..86550e2 --- /dev/null +++ b/tests/tests.rs @@ -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"); +}