summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Gallant <jamslam@gmail.com>2016-09-09 22:58:30 -0400
committerAndrew Gallant <jamslam@gmail.com>2016-09-09 22:58:30 -0400
commitf83cd63b11f3fa6e85cd5bb0f803a69fa05efa84 (patch)
tree6f2a426b7e0e1ea92844cc915a38972585608319
parent9a4527d1076cfec4d3856a40d73b1b82ea1033aa (diff)
Add integration tests.
-rw-r--r--Cargo.toml4
-rw-r--r--src/args.rs19
-rw-r--r--src/search.rs53
-rw-r--r--src/search_buffer.rs19
-rw-r--r--tests/hay.rs24
-rw-r--r--tests/tests.rs563
-rw-r--r--tests/workdir.rs189
7 files changed, 819 insertions, 52 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 3bf5477e..29586bc1 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -18,6 +18,10 @@ bench = false
path = "src/main.rs"
name = "rg"
+[[test]]
+name = "integration"
+path = "tests/tests.rs"
+
[dependencies]
crossbeam = "0.2"
docopt = "0.6"
diff --git a/src/args.rs b/src/args.rs
index d6a9657f..ea7299fe 100644
--- a/src/args.rs
+++ b/src/args.rs
@@ -109,10 +109,6 @@ Less common options:
-L, --follow
Follow symlinks.
- --line-terminator ARG
- The byte to use for a line terminator. Escape sequences may be used.
- [default: \\n]
-
--mmap
Search using memory maps when possible. This is enabled by default
when ripgrep thinks it will be faster. (Note that mmap searching
@@ -174,7 +170,6 @@ pub struct RawArgs {
flag_ignore_case: bool,
flag_invert_match: bool,
flag_line_number: bool,
- flag_line_terminator: String,
flag_literal: bool,
flag_mmap: bool,
flag_no_heading: bool,
@@ -248,7 +243,9 @@ impl RawArgs {
};
let paths =
if self.arg_path.is_empty() {
- if sys::stdin_is_atty() {
+ if sys::stdin_is_atty()
+ || self.flag_files
+ || self.flag_type_list {
vec![Path::new("./").to_path_buf()]
} else {
vec![Path::new("-").to_path_buf()]
@@ -277,15 +274,6 @@ impl RawArgs {
if mmap {
debug!("will try to use memory maps");
}
- let eol = {
- let eol = unescape(&self.flag_line_terminator);
- if eol.is_empty() {
- errored!("Empty line terminator is not allowed.");
- } else if eol.len() > 1 {
- errored!("Line terminators are limited to exactly 1 byte.");
- }
- eol[0]
- };
let glob_overrides =
if self.flag_glob.is_empty() {
None
@@ -309,6 +297,7 @@ impl RawArgs {
} else {
self.flag_color == "always"
};
+ let eol = b'\n';
let mut with_filename = self.flag_with_filename;
if !with_filename {
with_filename = paths.len() > 1 || paths[0].is_dir();
diff --git a/src/search.rs b/src/search.rs
index 523d1e4d..027bd0d3 100644
--- a/src/search.rs
+++ b/src/search.rs
@@ -695,8 +695,7 @@ mod tests {
use super::{InputBuffer, Searcher, start_of_previous_lines};
- lazy_static! {
- static ref SHERLOCK: &'static str = "\
+ const SHERLOCK: &'static str = "\
For the Doctor Watsons of this world, as opposed to the Sherlock
Holmeses, success in the province of detective work must always
be, to a very large extent, the result of luck. Sherlock Holmes
@@ -704,7 +703,8 @@ can extract a clew from a wisp of straw or a flake of cigar ash;
but Doctor Watson has to have it taken out for him and dusted,
and exhibited clearly, with a label attached.\
";
- static ref CODE: &'static str = "\
+
+ const CODE: &'static str = "\
extern crate snap;
use std::io;
@@ -719,7 +719,6 @@ fn main() {
io::copy(&mut rdr, &mut wtr).expect(\"I/O operation failed\");
}
";
- }
fn hay(s: &str) -> io::Cursor<Vec<u8>> {
io::Cursor::new(s.to_string().into_bytes())
@@ -874,7 +873,7 @@ fn main() {
#[test]
fn basic_search1() {
- let (count, out) = search_smallcap("Sherlock", &*SHERLOCK, |s|s);
+ let (count, out) = search_smallcap("Sherlock", SHERLOCK, |s|s);
assert_eq!(2, count);
assert_eq!(out, "\
/baz.rs:For the Doctor Watsons of this world, as opposed to the Sherlock
@@ -901,7 +900,7 @@ fn main() {
#[test]
fn line_numbers() {
let (count, out) = search_smallcap(
- "Sherlock", &*SHERLOCK, |s| s.line_number(true));
+ "Sherlock", SHERLOCK, |s| s.line_number(true));
assert_eq!(2, count);
assert_eq!(out, "\
/baz.rs:1:For the Doctor Watsons of this world, as opposed to the Sherlock
@@ -912,7 +911,7 @@ fn main() {
#[test]
fn count() {
let (count, out) = search_smallcap(
- "Sherlock", &*SHERLOCK, |s| s.count(true));
+ "Sherlock", SHERLOCK, |s| s.count(true));
assert_eq!(2, count);
assert_eq!(out, "/baz.rs:2\n");
}
@@ -920,7 +919,7 @@ fn main() {
#[test]
fn invert_match() {
let (count, out) = search_smallcap(
- "Sherlock", &*SHERLOCK, |s| s.invert_match(true));
+ "Sherlock", SHERLOCK, |s| s.invert_match(true));
assert_eq!(4, count);
assert_eq!(out, "\
/baz.rs:Holmeses, success in the province of detective work must always
@@ -932,7 +931,7 @@ fn main() {
#[test]
fn invert_match_line_numbers() {
- let (count, out) = search_smallcap("Sherlock", &*SHERLOCK, |s| {
+ let (count, out) = search_smallcap("Sherlock", SHERLOCK, |s| {
s.invert_match(true).line_number(true)
});
assert_eq!(4, count);
@@ -946,7 +945,7 @@ fn main() {
#[test]
fn invert_match_count() {
- let (count, out) = search_smallcap("Sherlock", &*SHERLOCK, |s| {
+ let (count, out) = search_smallcap("Sherlock", SHERLOCK, |s| {
s.invert_match(true).count(true)
});
assert_eq!(4, count);
@@ -955,7 +954,7 @@ fn main() {
#[test]
fn before_context_one1() {
- let (count, out) = search_smallcap("Sherlock", &*SHERLOCK, |s| {
+ let (count, out) = search_smallcap("Sherlock", SHERLOCK, |s| {
s.line_number(true).before_context(1)
});
assert_eq!(2, count);
@@ -968,7 +967,7 @@ fn main() {
#[test]
fn before_context_invert_one1() {
- let (count, out) = search_smallcap("Sherlock", &*SHERLOCK, |s| {
+ let (count, out) = search_smallcap("Sherlock", SHERLOCK, |s| {
s.line_number(true).before_context(1).invert_match(true)
});
assert_eq!(4, count);
@@ -984,7 +983,7 @@ fn main() {
#[test]
fn before_context_invert_one2() {
- let (count, out) = search_smallcap(" a ", &*SHERLOCK, |s| {
+ let (count, out) = search_smallcap(" a ", SHERLOCK, |s| {
s.line_number(true).before_context(1).invert_match(true)
});
assert_eq!(3, count);
@@ -999,7 +998,7 @@ fn main() {
#[test]
fn before_context_two1() {
- let (count, out) = search_smallcap("Sherlock", &*SHERLOCK, |s| {
+ let (count, out) = search_smallcap("Sherlock", SHERLOCK, |s| {
s.line_number(true).before_context(2)
});
assert_eq!(2, count);
@@ -1012,7 +1011,7 @@ fn main() {
#[test]
fn before_context_two2() {
- let (count, out) = search_smallcap("dusted", &*SHERLOCK, |s| {
+ let (count, out) = search_smallcap("dusted", SHERLOCK, |s| {
s.line_number(true).before_context(2)
});
assert_eq!(1, count);
@@ -1026,7 +1025,7 @@ fn main() {
#[test]
fn before_context_two3() {
let (count, out) = search_smallcap(
- "success|attached", &*SHERLOCK, |s| {
+ "success|attached", SHERLOCK, |s| {
s.line_number(true).before_context(2)
});
assert_eq!(2, count);
@@ -1042,7 +1041,7 @@ fn main() {
#[test]
fn before_context_two4() {
- let (count, out) = search("stdin", &*CODE, |s| {
+ let (count, out) = search("stdin", CODE, |s| {
s.line_number(true).before_context(2)
});
assert_eq!(3, count);
@@ -1059,7 +1058,7 @@ fn main() {
#[test]
fn before_context_two5() {
- let (count, out) = search("stdout", &*CODE, |s| {
+ let (count, out) = search("stdout", CODE, |s| {
s.line_number(true).before_context(2)
});
assert_eq!(2, count);
@@ -1076,7 +1075,7 @@ fn main() {
#[test]
fn before_context_three1() {
- let (count, out) = search_smallcap("Sherlock", &*SHERLOCK, |s| {
+ let (count, out) = search_smallcap("Sherlock", SHERLOCK, |s| {
s.line_number(true).before_context(3)
});
assert_eq!(2, count);
@@ -1089,7 +1088,7 @@ fn main() {
#[test]
fn after_context_one1() {
- let (count, out) = search_smallcap("Sherlock", &*SHERLOCK, |s| {
+ let (count, out) = search_smallcap("Sherlock", SHERLOCK, |s| {
s.line_number(true).after_context(1)
});
assert_eq!(2, count);
@@ -1103,7 +1102,7 @@ fn main() {
#[test]
fn after_context_invert_one1() {
- let (count, out) = search_smallcap("Sherlock", &*SHERLOCK, |s| {
+ let (count, out) = search_smallcap("Sherlock", SHERLOCK, |s| {
s.line_number(true).after_context(1).invert_match(true)
});
assert_eq!(4, count);
@@ -1118,7 +1117,7 @@ fn main() {
#[test]
fn after_context_invert_one2() {
- let (count, out) = search_smallcap(" a ", &*SHERLOCK, |s| {
+ let (count, out) = search_smallcap(" a ", SHERLOCK, |s| {
s.line_number(true).after_context(1).invert_match(true)
});
assert_eq!(3, count);
@@ -1134,7 +1133,7 @@ fn main() {
#[test]
fn after_context_two1() {
- let (count, out) = search_smallcap("Sherlock", &*SHERLOCK, |s| {
+ let (count, out) = search_smallcap("Sherlock", SHERLOCK, |s| {
s.line_number(true).after_context(2)
});
assert_eq!(2, count);
@@ -1149,7 +1148,7 @@ fn main() {
#[test]
fn after_context_two2() {
- let (count, out) = search_smallcap("dusted", &*SHERLOCK, |s| {
+ let (count, out) = search_smallcap("dusted", SHERLOCK, |s| {
s.line_number(true).after_context(2)
});
assert_eq!(1, count);
@@ -1162,7 +1161,7 @@ fn main() {
#[test]
fn after_context_two3() {
let (count, out) = search_smallcap(
- "success|attached", &*SHERLOCK, |s| {
+ "success|attached", SHERLOCK, |s| {
s.line_number(true).after_context(2)
});
assert_eq!(2, count);
@@ -1177,7 +1176,7 @@ fn main() {
#[test]
fn after_context_three1() {
- let (count, out) = search_smallcap("Sherlock", &*SHERLOCK, |s| {
+ let (count, out) = search_smallcap("Sherlock", SHERLOCK, |s| {
s.line_number(true).after_context(3)
});
assert_eq!(2, count);
@@ -1194,7 +1193,7 @@ fn main() {
#[test]
fn before_after_context_two1() {
let (count, out) = search(
- r"fn main|let mut rdr", &*CODE, |s| {
+ r"fn main|let mut rdr", CODE, |s| {
s.line_number(true).after_context(2).before_context(2)
});
assert_eq!(2, count);
diff --git a/src/search_buffer.rs b/src/search_buffer.rs
index 23578de9..fc8cd3a1 100644
--- a/src/search_buffer.rs
+++ b/src/search_buffer.rs
@@ -151,8 +151,7 @@ mod tests {
use super::BufferSearcher;
- lazy_static! {
- static ref SHERLOCK: &'static str = "\
+ const SHERLOCK: &'static str = "\
For the Doctor Watsons of this world, as opposed to the Sherlock
Holmeses, success in the province of detective work must always
be, to a very large extent, the result of luck. Sherlock Holmes
@@ -160,7 +159,8 @@ can extract a clew from a wisp of straw or a flake of cigar ash;
but Doctor Watson has to have it taken out for him and dusted,
and exhibited clearly, with a label attached.\
";
- static ref CODE: &'static str = "\
+
+ const CODE: &'static str = "\
extern crate snap;
use std::io;
@@ -175,7 +175,6 @@ fn main() {
io::copy(&mut rdr, &mut wtr).expect(\"I/O operation failed\");
}
";
- }
fn matcher(pat: &str) -> Grep {
GrepBuilder::new(pat).build().unwrap()
@@ -205,7 +204,7 @@ fn main() {
#[test]
fn basic_search() {
- let (count, out) = search("Sherlock", &*SHERLOCK, |s|s);
+ let (count, out) = search("Sherlock", SHERLOCK, |s|s);
assert_eq!(2, count);
assert_eq!(out, "\
/baz.rs:For the Doctor Watsons of this world, as opposed to the Sherlock
@@ -233,7 +232,7 @@ fn main() {
#[test]
fn line_numbers() {
let (count, out) = search(
- "Sherlock", &*SHERLOCK, |s| s.line_number(true));
+ "Sherlock", SHERLOCK, |s| s.line_number(true));
assert_eq!(2, count);
assert_eq!(out, "\
/baz.rs:1:For the Doctor Watsons of this world, as opposed to the Sherlock
@@ -244,7 +243,7 @@ fn main() {
#[test]
fn count() {
let (count, out) = search(
- "Sherlock", &*SHERLOCK, |s| s.count(true));
+ "Sherlock", SHERLOCK, |s| s.count(true));
assert_eq!(2, count);
assert_eq!(out, "/baz.rs:2\n");
}
@@ -252,7 +251,7 @@ fn main() {
#[test]
fn invert_match() {
let (count, out) = search(
- "Sherlock", &*SHERLOCK, |s| s.invert_match(true));
+ "Sherlock", SHERLOCK, |s| s.invert_match(true));
assert_eq!(4, count);
assert_eq!(out, "\
/baz.rs:Holmeses, success in the province of detective work must always
@@ -264,7 +263,7 @@ fn main() {
#[test]
fn invert_match_line_numbers() {
- let (count, out) = search("Sherlock", &*SHERLOCK, |s| {
+ let (count, out) = search("Sherlock", SHERLOCK, |s| {
s.invert_match(true).line_number(true)
});
assert_eq!(4, count);
@@ -278,7 +277,7 @@ fn main() {
#[test]
fn invert_match_count() {
- let (count, out) = search("Sherlock", &*SHERLOCK, |s| {
+ let (count, out) = search("Sherlock", SHERLOCK, |s| {
s.invert_match(true).count(true)
});
assert_eq!(4, count);
diff --git a/tests/hay.rs b/tests/hay.rs
new file mode 100644
index 00000000..74d2f6cc
--- /dev/null
+++ b/tests/hay.rs
@@ -0,0 +1,24 @@
+pub const SHERLOCK: &'static str = "\
+For the Doctor Watsons of this world, as opposed to the Sherlock
+Holmeses, success in the province of detective work must always
+be, to a very large extent, the result of luck. Sherlock Holmes
+can extract a clew from a wisp of straw or a flake of cigar ash;
+but Doctor Watson has to have it taken out for him and dusted,
+and exhibited clearly, with a label attached.
+";
+
+pub const CODE: &'static str = "\
+extern crate snap;
+
+use std::io;
+
+fn main() {
+ let stdin = io::stdin();
+ let stdout = io::stdout();
+
+ // Wrap the stdin reader in a Snappy reader.
+ let mut rdr = snap::Reader::new(stdin.lock());
+ let mut wtr = stdout.lock();
+ io::copy(&mut rdr, &mut wtr).expect(\"I/O operation failed\");
+}
+";
diff --git a/tests/tests.rs b/tests/tests.rs
new file mode 100644
index 00000000..608f3572
--- /dev/null
+++ b/tests/tests.rs
@@ -0,0 +1,563 @@
+/*!
+This module contains *integration* tests. Their purpose is to test the CLI
+interface. Namely, that passing a flag does what it says on the tin.
+
+Tests for more fine grained behavior (like the search or the globber) should be
+unit tests in their respective modules.
+*/
+
+#![allow(dead_code, unused_imports)]
+
+use std::process::Command;
+
+use workdir::WorkDir;
+
+mod hay;
+mod workdir;
+
+macro_rules! sherlock {
+ ($name:ident, $fun:expr) => {
+ sherlock!($name, "Sherlock", $fun);
+ };
+ ($name:ident, $query:expr, $fun:expr) => {
+ sherlock!($name, $query, "sherlock", $fun);
+ };
+ ($name:ident, $query:expr, $path:expr, $fun:expr) => {
+ #[test]
+ fn $name() {
+ let wd = WorkDir::new(stringify!($name));
+ wd.create("sherlock", hay::SHERLOCK);
+ let mut cmd = wd.command();
+ cmd.arg($query).arg($path);
+ $fun(wd, cmd);
+ }
+ };
+}
+
+sherlock!(single_file, |wd: WorkDir, mut cmd| {
+ let lines: String = wd.stdout(&mut cmd);
+ let expected = "\
+For the Doctor Watsons of this world, as opposed to the Sherlock
+be, to a very large extent, the result of luck. Sherlock Holmes
+";
+ assert_eq!(lines, expected);
+});
+
+sherlock!(dir, "Sherlock", ".", |wd: WorkDir, mut cmd| {
+ let lines: String = wd.stdout(&mut cmd);
+ let expected = "\
+sherlock:For the Doctor Watsons of this world, as opposed to the Sherlock
+sherlock:be, to a very large extent, the result of luck. Sherlock Holmes
+";
+ assert_eq!(lines, expected);
+});
+
+sherlock!(line_numbers, |wd: WorkDir, mut cmd: Command| {
+ cmd.arg("-n");
+ let lines: String = wd.stdout(&mut cmd);
+ let expected = "\
+1:For the Doctor Watsons of this world, as opposed to the Sherlock
+3:be, to a very large extent, the result of luck. Sherlock Holmes
+";
+ assert_eq!(lines, expected);
+});
+
+sherlock!(columns, |wd: WorkDir, mut cmd: Command| {
+ cmd.arg("--column");
+ let lines: String = wd.stdout(&mut cmd);
+ let expected = "\
+57:For the Doctor Watsons of this world, as opposed to the Sherlock
+49:be, to a very large extent, the result of luck. Sherlock Holmes
+";
+ assert_eq!(lines, expected);
+});
+
+sherlock!(with_filename, |wd: WorkDir, mut cmd: Command| {
+ cmd.arg("-H");
+ let lines: String = wd.stdout(&mut cmd);
+ let expected = "\
+sherlock:For the Doctor Watsons of this world, as opposed to the Sherlock
+sherlock:be, to a very large extent, the result of luck. Sherlock Holmes
+";
+ assert_eq!(lines, expected);
+});
+
+sherlock!(with_heading, |wd: WorkDir, mut cmd: Command| {
+ // This forces the issue since --with-filename is disabled by default
+ // when searching one fil.e
+ cmd.arg("--with-filename").arg("--heading");
+ let lines: String = wd.stdout(&mut cmd);
+ let expected = "\
+sherlock
+For the Doctor Watsons of this world, as opposed to the Sherlock
+be, to a very large extent, the result of luck. Sherlock Holmes
+";
+ assert_eq!(lines, expected);
+});
+
+sherlock!(with_heading_default, "Sherlock", ".",
+|wd: WorkDir, mut cmd: Command| {
+ // Search two or more and get --with-filename enabled by default.
+ // Use -j1 to get deterministic results.
+ wd.create("foo", "Sherlock Holmes lives on Baker Street.");
+ cmd.arg("-j1").arg("--heading");
+ let lines: String = wd.stdout(&mut cmd);
+ let expected = "\
+foo
+Sherlock Holmes lives on Baker Street.
+
+sherlock
+For the Doctor Watsons of this world, as opposed to the Sherlock
+be, to a very large extent, the result of luck. Sherlock Holmes
+";
+ assert_eq!(lines, expected);
+});
+
+sherlock!(inverted, |wd: WorkDir, mut cmd: Command| {
+ cmd.arg("-v");
+ let lines: String = wd.stdout(&mut cmd);
+ let expected = "\
+Holmeses, success in the province of detective work must always
+can extract a clew from a wisp of straw or a flake of cigar ash;
+but Doctor Watson has to have it taken out for him and dusted,
+and exhibited clearly, with a label attached.
+";
+ assert_eq!(lines, expected);
+});
+
+sherlock!(inverted_line_numbers, |wd: WorkDir, mut cmd: Command| {
+ cmd.arg("-n").arg("-v");
+ let lines: String = wd.stdout(&mut cmd);
+ let expected = "\
+2:Holmeses, success in the province of detective work must always
+4:can extract a clew from a wisp of straw or a flake of cigar ash;
+5:but Doctor Watson has to have it taken out for him and dusted,
+6:and exhibited clearly, with a label attached.
+";
+ assert_eq!(lines, expected);
+});
+
+sherlock!(case_insensitive, "sherlock", |wd: WorkDir, mut cmd: Command| {
+ cmd.arg("-i");
+ let lines: String = wd.stdout(&mut cmd);
+ let expected = "\
+For the Doctor Watsons of this world, as opposed to the Sherlock
+be, to a very large extent, the result of luck. Sherlock Holmes
+";
+ assert_eq!(lines, expected);
+});
+
+sherlock!(word, "as", |wd: WorkDir, mut cmd: Command| {
+ cmd.arg("-w");
+ let lines: String = wd.stdout(&mut cmd);
+ let expected = "\
+For the Doctor Watsons of this world, as opposed to the Sherlock
+";
+ assert_eq!(lines, expected);
+});
+
+sherlock!(literal, "()", "file", |wd: WorkDir, mut cmd: Command| {
+ wd.create("file", "blib\n()\nblab\n");
+ cmd.arg("-Q");
+ let lines: String = wd.stdout(&mut cmd);
+ assert_eq!(lines, "()\n");
+});
+
+sherlock!(quiet, |wd: WorkDir, mut cmd: Command| {
+ cmd.arg("-q");
+ let lines: String = wd.stdout(&mut cmd);
+ assert!(lines.is_empty());
+});
+
+sherlock!(replace, |wd: WorkDir, mut cmd: Command| {
+ cmd.arg("-r").arg("FooBar");
+ let lines: String = wd.stdout(&mut cmd);
+ let expected = "\
+For the Doctor Watsons of this world, as opposed to the FooBar
+be, to a very large extent, the result of luck. FooBar Holmes
+";
+ assert_eq!(lines, expected);
+});
+
+sherlock!(replace_groups, "([A-Z][a-z]+) ([A-Z][a-z]+)",
+|wd: WorkDir, mut cmd: Command| {
+ cmd.arg("-r").arg("$2, $1");
+ let lines: String = wd.stdout(&mut cmd);
+ let expected = "\
+For the Watsons, Doctor of this world, as opposed to the Sherlock
+be, to a very large extent, the result of luck. Holmes, Sherlock
+but Watson, Doctor has to have it taken out for him and dusted,
+";
+ assert_eq!(lines, expected);
+});
+
+sherlock!(replace_named_groups, "(?P<first>[A-Z][a-z]+) (?P<last>[A-Z][a-z]+)",
+|wd: WorkDir, mut cmd: Command| {
+ cmd.arg("-r").arg("$last, $first");
+ let lines: String = wd.stdout(&mut cmd);
+ let expected = "\
+For the Watsons, Doctor of this world, as opposed to the Sherlock
+be, to a very large extent, the result of luck. Holmes, Sherlock
+but Watson, Doctor has to have it taken out for him and dusted,
+";
+ assert_eq!(lines, expected);
+});
+
+sherlock!(file_types, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| {
+ wd.create("file.py", "Sherlock");
+ wd.create("file.rs", "Sherlock");
+ cmd.arg("-t").arg("rust");
+ let lines: String = wd.stdout(&mut cmd);
+ assert_eq!(lines, "file.rs:Sherlock\n");
+});
+
+sherlock!(file_types_negate, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| {
+ wd.remove("sherlock");
+ wd.create("file.py", "Sherlock");
+ wd.create("file.rs", "Sherlock");
+ cmd.arg("-T").arg("rust");
+ let lines: String = wd.stdout(&mut cmd);
+ assert_eq!(lines, "file.py:Sherlock\n");
+});
+
+sherlock!(file_type_clear, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| {
+ wd.create("file.py", "Sherlock");
+ wd.create("file.rs", "Sherlock");
+ cmd.arg("--type-clear").arg("rust").arg("-t").arg("rust");
+ wd.assert_err(&mut cmd);
+});
+
+sherlock!(file_type_add, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| {
+ wd.create("file.py", "Sherlock");
+ wd.create("file.rs", "Sherlock");
+ wd.create("file.wat", "Sherlock");
+ cmd.arg("--type-add").arg("wat:*.wat").arg("-t").arg("wat");
+ let lines: String = wd.stdout(&mut cmd);
+ assert_eq!(lines, "file.wat:Sherlock\n");
+});
+
+sherlock!(glob, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| {
+ wd.create("file.py", "Sherlock");
+ wd.create("file.rs", "Sherlock");
+ cmd.arg("-g").arg("*.rs");
+ let lines: String = wd.stdout(&mut cmd);
+ assert_eq!(lines, "file.rs:Sherlock\n");
+});
+
+sherlock!(glob_negate, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| {
+ wd.remove("sherlock");
+ wd.create("file.py", "Sherlock");
+ wd.create("file.rs", "Sherlock");
+ cmd.arg("-g").arg("!*.rs");
+ let lines: String = wd.stdout(&mut cmd);
+ assert_eq!(lines, "file.py:Sherlock\n");
+});
+
+sherlock!(after_context, |wd: WorkDir, mut cmd: Command| {
+ cmd.arg("-A").arg("1");
+ let lines: String = wd.stdout(&mut cmd);
+ let expected = "\
+For the Doctor Watsons of this world, as opposed to the Sherlock
+Holmeses, success in the province of detective work must always
+be, to a very large extent, the result of luck. Sherlock Holmes
+can extract a clew from a wisp of straw or a flake of cigar ash;
+";
+ assert_eq!(lines, expected);
+});
+
+sherlock!(after_context_line_numbers, |wd: WorkDir, mut cmd: Command| {
+ cmd.arg("-A").arg("1").arg("-n");
+ let lines: String = wd.stdout(&mut cmd);
+ let expected = "\
+1:For the Doctor Watsons of this world, as opposed to the Sherlock
+2-Holmeses, success in the province of detective work must always
+3:be, to a very large extent, the result of luck. Sherlock Holmes
+4-can extract a clew from a wisp of straw or a flake of cigar ash;
+";
+ assert_eq!(lines, expected);
+});
+
+sherlock!(before_context, |wd: WorkDir, mut cmd: Command| {
+ cmd.arg("-B").arg("1");
+ let lines: String = wd.stdout(&mut cmd);
+ let expected = "\
+For the Doctor Watsons of this world, as opposed to the Sherlock
+Holmeses, success in the province of detective work must always
+be, to a very large extent, the result of luck. Sherlock Holmes
+";
+ assert_eq!(lines, expected);
+});
+
+sherlock!(before_context_line_numbers, |wd: WorkDir, mut cmd: Command| {
+ cmd.arg("-B").arg("1").arg("-n");
+ let lines: String = wd.stdout(&mut cmd);
+ let expected = "\
+1:For the Doctor Watsons of this world, as opposed to the Sherlock
+2-Holmeses, success in the province of detective work must always
+3:be, to a very large extent, the result of luck. Sherlock Holmes
+";
+ assert_eq!(lines, expected);
+});
+
+sherlock!(context, "world|attached", |wd: WorkDir, mut cmd: Command| {
+ cmd.arg("-C").arg("1");
+ let lines: String = wd.stdout(&mut cmd);
+ let expected = "\
+For the Doctor Watsons of this world, as opposed to the Sherlock
+Holmeses, success in the province of detective work must always
+--
+but Doctor Watson has to have it taken out for him and dusted,
+and exhibited clearly, with a label attached.
+";
+ assert_eq!(lines, expected);
+});
+
+sherlock!(context_line_numbers, "world|attached",
+|wd: WorkDir, mut cmd: Command| {
+ cmd.arg("-C").arg("1").arg("-n");
+ let lines: String = wd.stdout(&mut cmd);
+ let expected = "\
+1:For the Doctor Watsons of this world, as opposed to the Sherlock
+2-Holmeses, success in the province of detective work must always
+--
+5-but Doctor Watson has to have it taken out for him and dusted,
+6:and exhibited clearly, with a label attached.
+";
+ assert_eq!(lines, expected);
+});
+
+sherlock!(ignore_hidden, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| {
+ wd.remove("sherlock");
+ wd.create(".sherlock", hay::SHERLOCK);
+ wd.assert_err(&mut cmd);
+});
+
+sherlock!(no_ignore_hidden, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| {
+ wd.remove("sherlock");
+ wd.create(".sherlock", hay::SHERLOCK);
+
+ cmd.arg("--hidden");
+ let lines: String = wd.stdout(&mut cmd);
+ let expected = "\
+.sherlock:For the Doctor Watsons of this world, as opposed to the Sherlock
+.sherlock:be, to a very large extent, the result of luck. Sherlock Holmes
+";
+ assert_eq!(lines, expected);
+});
+
+sherlock!(ignore_git, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| {
+ wd.create(".gitignore", "sherlock\n");
+ wd.assert_err(&mut cmd);
+});
+
+sherlock!(ignore_ripgrep, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| {
+ wd.create(".rgignore", "sherlock\n");
+ wd.assert_err(&mut cmd);
+});
+
+sherlock!(no_ignore, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| {
+ wd.create(".gitignore", "sherlock\n");
+ cmd.arg("--no-ignore");
+ let lines: String = wd.stdout(&mut cmd);
+ let expected = "\
+sherlock:For the Doctor Watsons of this world, as opposed to the Sherlock
+sherlock:be, to a very large extent, the result of luck. Sherlock Holmes
+";
+ assert_eq!(lines, expected);
+});
+
+sherlock!(ignore_git_parent, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| {
+ wd.remove("sherlock");
+ wd.create(".gitignore", "sherlock\n");
+ wd.create_dir(".git");
+ wd.create_dir("foo");
+ wd.create("foo/sherlock", hay::SHERLOCK);
+ // Even though we search in foo/, which has no .gitignore, ripgrep will
+ // search parent directories and respect the gitignore files found.
+ cmd.current_dir(wd.path().join("foo"));
+ wd.assert_err(&mut cmd);
+});
+
+sherlock!(ignore_git_parent_stop, "Sherlock", ".",
+|wd: WorkDir, mut cmd: Command| {
+ // This tests that searching parent directories for .gitignore files stops
+ // after it sees a .git directory. To test this, we create this directory
+ // hierarchy:
+ //
+ // .gitignore (contains `sherlock`)
+ // foo/
+ // .git
+ // bar/
+ // sherlock
+ //
+ // And we perform the search inside `foo/bar/`. ripgrep will stop looking
+ // for .gitignore files after it sees `foo/.git/`, and therefore not
+ // respect the top-level `.gitignore` containing `sherlock`.
+ wd.remove("sherlock");
+ wd.create(".gitignore", "sherlock\n");
+ wd.create_dir("foo");
+ wd.create_dir("foo/.git");
+ wd.create_dir("foo/bar");
+ wd.create("foo/bar/sherlock", hay::SHERLOCK);
+ cmd.current_dir(wd.path().join("foo").join("bar"));
+
+ let lines: String = wd.stdout(&mut cmd);
+ let expected = "\
+sherlock:For the Doctor Watsons of this world, as opposed to the Sherlock
+sherlock:be, to a very large extent, the result of luck. Sherlock Holmes
+";
+ assert_eq!(lines, expected);
+});
+
+sherlock!(ignore_ripgrep_parent_no_stop, "Sherlock", ".",
+|wd: WorkDir, mut cmd: Command| {
+ // This is like the `ignore_git_parent_stop` test, except it checks that
+ // ripgrep *doesn't* stop checking for .rgignore files.
+ wd.remove("sherlock");
+ wd.create(".rgignore", "sherlock\n");
+ wd.create_dir("foo");
+ wd.create_dir("foo/.git");
+ wd.create_dir("foo/bar");
+ wd.create("foo/bar/sherlock", hay::SHERLOCK);
+ cmd.current_dir(wd.path().join("foo").join("bar"));
+ // The top-level .rgignore applies.
+ wd.assert_err(&mut cmd);
+});
+
+sherlock!(no_parent_ignore_git, "Sherlock", ".",
+|wd: WorkDir, mut cmd: Command| {
+ // Set up a directory hierarchy like this:
+ //
+ // .gitignore
+ // foo/
+ // .gitignore
+ // sherlock
+ // watson
+ //
+ // Where `.gitignore` contains `sherlock` and `foo/.gitignore` contains
+ // `watson`.
+ //
+ // Now *do the search* from the foo directory. By default, ripgrep will
+ // search parent directories for .gitignore files. The --no-ignore-parent
+ // flag should prevent that. At the same time, the `foo/.gitignore` file
+ // will still be respected (since the search is happening in `foo/`).
+ //
+ // In other words, we should only see results from `sherlock`, not from
+ // `watson`.
+ wd.remove("sherlock");
+ wd.create(".gitignore", "sherlock\n");
+ wd.create_dir("foo");
+ wd.create("foo/.gitignore", "watson\n");
+ wd.create("foo/sherlock", hay::SHERLOCK);
+ wd.create("foo/watson", hay::SHERLOCK);
+ cmd.current_dir(wd.path().join("foo"));
+ cmd.arg("--no-ignore-parent");
+
+ let lines: String = wd.stdout(&mut cmd);
+ let expected = "\
+sherlock:For the Doctor Watsons of this world, as opposed to the Sherlock
+sherlock:be, to a very large extent, the result of luck. Sherlock Holmes
+";
+ assert_eq!(lines, expected);
+});
+
+sherlock!(symlink_nofollow, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| {
+ wd.remove("sherlock");
+ wd.create_dir("foo");
+ wd.create_dir("foo/bar");
+ wd.link("foo/baz", "foo/bar/baz");
+ wd.create_dir("foo/baz");
+ wd.create("foo/baz/sherlock", hay::SHERLOCK);
+ cmd.current_dir(wd.path().join("foo/bar"));
+ wd.assert_err(&mut cmd);
+});
+
+sherlock!(symlink_follow, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| {
+ wd.remove("sherlock");
+ wd.create_dir("foo");
+ wd.create_dir("foo/bar");
+ wd.create_dir("foo/baz");
+ wd.create("foo/baz/sherlock", hay::SHERLOCK);
+ wd.link("foo/baz", "foo/bar/baz");
+ cmd.arg("-L");
+ cmd.current_dir(wd.path().join("foo/bar"));
+
+ let lines: String = wd.stdout(&mut cmd);
+ if cfg!(windows) {
+ let expected = "\
+baz\\sherlock:For the Doctor Watsons of this world, as opposed to the Sherlock
+baz\\sherlock:be, to a very large extent, the result of luck. Sherlock Holmes
+";
+ assert_eq!(lines, expected);
+ } else {
+ let expected = "\
+baz/sherlock:For the Doctor Watsons of this world, as opposed to the Sherlock
+baz/sherlock:be, to a very large extent, the result of luck. Sherlock Holmes
+";
+ assert_eq!(lines, expected);
+ }
+});
+
+#[test]
+fn binary_nosearch() {
+ let wd = WorkDir::new("binary_nosearch");
+ wd.create("file", "foo\x00bar\nfoo\x00baz\n");
+ let mut cmd = wd.command();
+ cmd.arg("foo").arg("file");
+ wd.assert_err(&mut cmd);
+}
+
+// The following two tests show a discrepancy in search results between
+// searching with memory mapped files and stream searching. Stream searching
+// uses a heuristic (that GNU grep also uses) where NUL bytes are replaced with
+// the EOL terminator, which tends to avoid allocating large amounts of memory
+// for really long "lines." The memory map searcher has no need to worry about
+// such things, and more than that, it would be pretty hard for it to match
+// the semantics of streaming search in this case.
+//
+// Binary files with lots of NULs aren't really part of the use case of ripgrep
+// (or any other grep-like tool for that matter), so we shouldn't feel too bad
+// about it.
+#[test]
+fn binary_search_mmap() {
+ let wd = WorkDir::new("binary_search_mmap");
+ wd.create("file", "foo\x00bar\nfoo\x00baz\n");
+ let mut cmd = wd.command();
+ cmd.arg("-a").arg("--mmap").arg("foo").arg("file");
+ let lines: String = wd.stdout(&mut cmd);</