mirror of
https://github.com/BurntSushi/ripgrep.git
synced 2025-05-19 01:30:21 -07:00
Add integration tests.
This commit is contained in:
parent
9a4527d107
commit
f83cd63b11
@ -18,6 +18,10 @@ bench = false
|
|||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
name = "rg"
|
name = "rg"
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "integration"
|
||||||
|
path = "tests/tests.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
crossbeam = "0.2"
|
crossbeam = "0.2"
|
||||||
docopt = "0.6"
|
docopt = "0.6"
|
||||||
|
19
src/args.rs
19
src/args.rs
@ -109,10 +109,6 @@ Less common options:
|
|||||||
-L, --follow
|
-L, --follow
|
||||||
Follow symlinks.
|
Follow symlinks.
|
||||||
|
|
||||||
--line-terminator ARG
|
|
||||||
The byte to use for a line terminator. Escape sequences may be used.
|
|
||||||
[default: \\n]
|
|
||||||
|
|
||||||
--mmap
|
--mmap
|
||||||
Search using memory maps when possible. This is enabled by default
|
Search using memory maps when possible. This is enabled by default
|
||||||
when ripgrep thinks it will be faster. (Note that mmap searching
|
when ripgrep thinks it will be faster. (Note that mmap searching
|
||||||
@ -174,7 +170,6 @@ pub struct RawArgs {
|
|||||||
flag_ignore_case: bool,
|
flag_ignore_case: bool,
|
||||||
flag_invert_match: bool,
|
flag_invert_match: bool,
|
||||||
flag_line_number: bool,
|
flag_line_number: bool,
|
||||||
flag_line_terminator: String,
|
|
||||||
flag_literal: bool,
|
flag_literal: bool,
|
||||||
flag_mmap: bool,
|
flag_mmap: bool,
|
||||||
flag_no_heading: bool,
|
flag_no_heading: bool,
|
||||||
@ -248,7 +243,9 @@ impl RawArgs {
|
|||||||
};
|
};
|
||||||
let paths =
|
let paths =
|
||||||
if self.arg_path.is_empty() {
|
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()]
|
vec![Path::new("./").to_path_buf()]
|
||||||
} else {
|
} else {
|
||||||
vec![Path::new("-").to_path_buf()]
|
vec![Path::new("-").to_path_buf()]
|
||||||
@ -277,15 +274,6 @@ impl RawArgs {
|
|||||||
if mmap {
|
if mmap {
|
||||||
debug!("will try to use memory maps");
|
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 =
|
let glob_overrides =
|
||||||
if self.flag_glob.is_empty() {
|
if self.flag_glob.is_empty() {
|
||||||
None
|
None
|
||||||
@ -309,6 +297,7 @@ impl RawArgs {
|
|||||||
} else {
|
} else {
|
||||||
self.flag_color == "always"
|
self.flag_color == "always"
|
||||||
};
|
};
|
||||||
|
let eol = b'\n';
|
||||||
let mut with_filename = self.flag_with_filename;
|
let mut with_filename = self.flag_with_filename;
|
||||||
if !with_filename {
|
if !with_filename {
|
||||||
with_filename = paths.len() > 1 || paths[0].is_dir();
|
with_filename = paths.len() > 1 || paths[0].is_dir();
|
||||||
|
@ -695,8 +695,7 @@ mod tests {
|
|||||||
|
|
||||||
use super::{InputBuffer, Searcher, start_of_previous_lines};
|
use super::{InputBuffer, Searcher, start_of_previous_lines};
|
||||||
|
|
||||||
lazy_static! {
|
const SHERLOCK: &'static str = "\
|
||||||
static ref SHERLOCK: &'static str = "\
|
|
||||||
For the Doctor Watsons of this world, as opposed to the Sherlock
|
For the Doctor Watsons of this world, as opposed to the Sherlock
|
||||||
Holmeses, success in the province of detective work must always
|
Holmeses, success in the province of detective work must always
|
||||||
be, to a very large extent, the result of luck. Sherlock Holmes
|
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,
|
but Doctor Watson has to have it taken out for him and dusted,
|
||||||
and exhibited clearly, with a label attached.\
|
and exhibited clearly, with a label attached.\
|
||||||
";
|
";
|
||||||
static ref CODE: &'static str = "\
|
|
||||||
|
const CODE: &'static str = "\
|
||||||
extern crate snap;
|
extern crate snap;
|
||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
@ -719,7 +719,6 @@ fn main() {
|
|||||||
io::copy(&mut rdr, &mut wtr).expect(\"I/O operation failed\");
|
io::copy(&mut rdr, &mut wtr).expect(\"I/O operation failed\");
|
||||||
}
|
}
|
||||||
";
|
";
|
||||||
}
|
|
||||||
|
|
||||||
fn hay(s: &str) -> io::Cursor<Vec<u8>> {
|
fn hay(s: &str) -> io::Cursor<Vec<u8>> {
|
||||||
io::Cursor::new(s.to_string().into_bytes())
|
io::Cursor::new(s.to_string().into_bytes())
|
||||||
@ -874,7 +873,7 @@ fn main() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn basic_search1() {
|
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!(2, count);
|
||||||
assert_eq!(out, "\
|
assert_eq!(out, "\
|
||||||
/baz.rs:For the Doctor Watsons of this world, as opposed to the Sherlock
|
/baz.rs:For the Doctor Watsons of this world, as opposed to the Sherlock
|
||||||
@ -901,7 +900,7 @@ fn main() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn line_numbers() {
|
fn line_numbers() {
|
||||||
let (count, out) = search_smallcap(
|
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!(2, count);
|
||||||
assert_eq!(out, "\
|
assert_eq!(out, "\
|
||||||
/baz.rs:1:For the Doctor Watsons of this world, as opposed to the Sherlock
|
/baz.rs:1:For the Doctor Watsons of this world, as opposed to the Sherlock
|
||||||
@ -912,7 +911,7 @@ fn main() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn count() {
|
fn count() {
|
||||||
let (count, out) = search_smallcap(
|
let (count, out) = search_smallcap(
|
||||||
"Sherlock", &*SHERLOCK, |s| s.count(true));
|
"Sherlock", SHERLOCK, |s| s.count(true));
|
||||||
assert_eq!(2, count);
|
assert_eq!(2, count);
|
||||||
assert_eq!(out, "/baz.rs:2\n");
|
assert_eq!(out, "/baz.rs:2\n");
|
||||||
}
|
}
|
||||||
@ -920,7 +919,7 @@ fn main() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn invert_match() {
|
fn invert_match() {
|
||||||
let (count, out) = search_smallcap(
|
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!(4, count);
|
||||||
assert_eq!(out, "\
|
assert_eq!(out, "\
|
||||||
/baz.rs:Holmeses, success in the province of detective work must always
|
/baz.rs:Holmeses, success in the province of detective work must always
|
||||||
@ -932,7 +931,7 @@ fn main() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn invert_match_line_numbers() {
|
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)
|
s.invert_match(true).line_number(true)
|
||||||
});
|
});
|
||||||
assert_eq!(4, count);
|
assert_eq!(4, count);
|
||||||
@ -946,7 +945,7 @@ fn main() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn invert_match_count() {
|
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)
|
s.invert_match(true).count(true)
|
||||||
});
|
});
|
||||||
assert_eq!(4, count);
|
assert_eq!(4, count);
|
||||||
@ -955,7 +954,7 @@ fn main() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn before_context_one1() {
|
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)
|
s.line_number(true).before_context(1)
|
||||||
});
|
});
|
||||||
assert_eq!(2, count);
|
assert_eq!(2, count);
|
||||||
@ -968,7 +967,7 @@ fn main() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn before_context_invert_one1() {
|
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)
|
s.line_number(true).before_context(1).invert_match(true)
|
||||||
});
|
});
|
||||||
assert_eq!(4, count);
|
assert_eq!(4, count);
|
||||||
@ -984,7 +983,7 @@ fn main() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn before_context_invert_one2() {
|
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)
|
s.line_number(true).before_context(1).invert_match(true)
|
||||||
});
|
});
|
||||||
assert_eq!(3, count);
|
assert_eq!(3, count);
|
||||||
@ -999,7 +998,7 @@ fn main() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn before_context_two1() {
|
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)
|
s.line_number(true).before_context(2)
|
||||||
});
|
});
|
||||||
assert_eq!(2, count);
|
assert_eq!(2, count);
|
||||||
@ -1012,7 +1011,7 @@ fn main() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn before_context_two2() {
|
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)
|
s.line_number(true).before_context(2)
|
||||||
});
|
});
|
||||||
assert_eq!(1, count);
|
assert_eq!(1, count);
|
||||||
@ -1026,7 +1025,7 @@ fn main() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn before_context_two3() {
|
fn before_context_two3() {
|
||||||
let (count, out) = search_smallcap(
|
let (count, out) = search_smallcap(
|
||||||
"success|attached", &*SHERLOCK, |s| {
|
"success|attached", SHERLOCK, |s| {
|
||||||
s.line_number(true).before_context(2)
|
s.line_number(true).before_context(2)
|
||||||
});
|
});
|
||||||
assert_eq!(2, count);
|
assert_eq!(2, count);
|
||||||
@ -1042,7 +1041,7 @@ fn main() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn before_context_two4() {
|
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)
|
s.line_number(true).before_context(2)
|
||||||
});
|
});
|
||||||
assert_eq!(3, count);
|
assert_eq!(3, count);
|
||||||
@ -1059,7 +1058,7 @@ fn main() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn before_context_two5() {
|
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)
|
s.line_number(true).before_context(2)
|
||||||
});
|
});
|
||||||
assert_eq!(2, count);
|
assert_eq!(2, count);
|
||||||
@ -1076,7 +1075,7 @@ fn main() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn before_context_three1() {
|
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)
|
s.line_number(true).before_context(3)
|
||||||
});
|
});
|
||||||
assert_eq!(2, count);
|
assert_eq!(2, count);
|
||||||
@ -1089,7 +1088,7 @@ fn main() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn after_context_one1() {
|
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)
|
s.line_number(true).after_context(1)
|
||||||
});
|
});
|
||||||
assert_eq!(2, count);
|
assert_eq!(2, count);
|
||||||
@ -1103,7 +1102,7 @@ fn main() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn after_context_invert_one1() {
|
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)
|
s.line_number(true).after_context(1).invert_match(true)
|
||||||
});
|
});
|
||||||
assert_eq!(4, count);
|
assert_eq!(4, count);
|
||||||
@ -1118,7 +1117,7 @@ fn main() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn after_context_invert_one2() {
|
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)
|
s.line_number(true).after_context(1).invert_match(true)
|
||||||
});
|
});
|
||||||
assert_eq!(3, count);
|
assert_eq!(3, count);
|
||||||
@ -1134,7 +1133,7 @@ fn main() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn after_context_two1() {
|
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)
|
s.line_number(true).after_context(2)
|
||||||
});
|
});
|
||||||
assert_eq!(2, count);
|
assert_eq!(2, count);
|
||||||
@ -1149,7 +1148,7 @@ fn main() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn after_context_two2() {
|
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)
|
s.line_number(true).after_context(2)
|
||||||
});
|
});
|
||||||
assert_eq!(1, count);
|
assert_eq!(1, count);
|
||||||
@ -1162,7 +1161,7 @@ fn main() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn after_context_two3() {
|
fn after_context_two3() {
|
||||||
let (count, out) = search_smallcap(
|
let (count, out) = search_smallcap(
|
||||||
"success|attached", &*SHERLOCK, |s| {
|
"success|attached", SHERLOCK, |s| {
|
||||||
s.line_number(true).after_context(2)
|
s.line_number(true).after_context(2)
|
||||||
});
|
});
|
||||||
assert_eq!(2, count);
|
assert_eq!(2, count);
|
||||||
@ -1177,7 +1176,7 @@ fn main() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn after_context_three1() {
|
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)
|
s.line_number(true).after_context(3)
|
||||||
});
|
});
|
||||||
assert_eq!(2, count);
|
assert_eq!(2, count);
|
||||||
@ -1194,7 +1193,7 @@ fn main() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn before_after_context_two1() {
|
fn before_after_context_two1() {
|
||||||
let (count, out) = search(
|
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)
|
s.line_number(true).after_context(2).before_context(2)
|
||||||
});
|
});
|
||||||
assert_eq!(2, count);
|
assert_eq!(2, count);
|
||||||
|
@ -151,8 +151,7 @@ mod tests {
|
|||||||
|
|
||||||
use super::BufferSearcher;
|
use super::BufferSearcher;
|
||||||
|
|
||||||
lazy_static! {
|
const SHERLOCK: &'static str = "\
|
||||||
static ref SHERLOCK: &'static str = "\
|
|
||||||
For the Doctor Watsons of this world, as opposed to the Sherlock
|
For the Doctor Watsons of this world, as opposed to the Sherlock
|
||||||
Holmeses, success in the province of detective work must always
|
Holmeses, success in the province of detective work must always
|
||||||
be, to a very large extent, the result of luck. Sherlock Holmes
|
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,
|
but Doctor Watson has to have it taken out for him and dusted,
|
||||||
and exhibited clearly, with a label attached.\
|
and exhibited clearly, with a label attached.\
|
||||||
";
|
";
|
||||||
static ref CODE: &'static str = "\
|
|
||||||
|
const CODE: &'static str = "\
|
||||||
extern crate snap;
|
extern crate snap;
|
||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
@ -175,7 +175,6 @@ fn main() {
|
|||||||
io::copy(&mut rdr, &mut wtr).expect(\"I/O operation failed\");
|
io::copy(&mut rdr, &mut wtr).expect(\"I/O operation failed\");
|
||||||
}
|
}
|
||||||
";
|
";
|
||||||
}
|
|
||||||
|
|
||||||
fn matcher(pat: &str) -> Grep {
|
fn matcher(pat: &str) -> Grep {
|
||||||
GrepBuilder::new(pat).build().unwrap()
|
GrepBuilder::new(pat).build().unwrap()
|
||||||
@ -205,7 +204,7 @@ fn main() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn basic_search() {
|
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!(2, count);
|
||||||
assert_eq!(out, "\
|
assert_eq!(out, "\
|
||||||
/baz.rs:For the Doctor Watsons of this world, as opposed to the Sherlock
|
/baz.rs:For the Doctor Watsons of this world, as opposed to the Sherlock
|
||||||
@ -233,7 +232,7 @@ fn main() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn line_numbers() {
|
fn line_numbers() {
|
||||||
let (count, out) = search(
|
let (count, out) = search(
|
||||||
"Sherlock", &*SHERLOCK, |s| s.line_number(true));
|
"Sherlock", SHERLOCK, |s| s.line_number(true));
|
||||||
assert_eq!(2, count);
|
assert_eq!(2, count);
|
||||||
assert_eq!(out, "\
|
assert_eq!(out, "\
|
||||||
/baz.rs:1:For the Doctor Watsons of this world, as opposed to the Sherlock
|
/baz.rs:1:For the Doctor Watsons of this world, as opposed to the Sherlock
|
||||||
@ -244,7 +243,7 @@ fn main() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn count() {
|
fn count() {
|
||||||
let (count, out) = search(
|
let (count, out) = search(
|
||||||
"Sherlock", &*SHERLOCK, |s| s.count(true));
|
"Sherlock", SHERLOCK, |s| s.count(true));
|
||||||
assert_eq!(2, count);
|
assert_eq!(2, count);
|
||||||
assert_eq!(out, "/baz.rs:2\n");
|
assert_eq!(out, "/baz.rs:2\n");
|
||||||
}
|
}
|
||||||
@ -252,7 +251,7 @@ fn main() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn invert_match() {
|
fn invert_match() {
|
||||||
let (count, out) = search(
|
let (count, out) = search(
|
||||||
"Sherlock", &*SHERLOCK, |s| s.invert_match(true));
|
"Sherlock", SHERLOCK, |s| s.invert_match(true));
|
||||||
assert_eq!(4, count);
|
assert_eq!(4, count);
|
||||||
assert_eq!(out, "\
|
assert_eq!(out, "\
|
||||||
/baz.rs:Holmeses, success in the province of detective work must always
|
/baz.rs:Holmeses, success in the province of detective work must always
|
||||||
@ -264,7 +263,7 @@ fn main() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn invert_match_line_numbers() {
|
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)
|
s.invert_match(true).line_number(true)
|
||||||
});
|
});
|
||||||
assert_eq!(4, count);
|
assert_eq!(4, count);
|
||||||
@ -278,7 +277,7 @@ fn main() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn invert_match_count() {
|
fn invert_match_count() {
|
||||||
let (count, out) = search("Sherlock", &*SHERLOCK, |s| {
|
let (count, out) = search("Sherlock", SHERLOCK, |s| {
|
||||||
s.invert_match(true).count(true)
|
s.invert_match(true).count(true)
|
||||||
});
|
});
|
||||||
assert_eq!(4, count);
|
assert_eq!(4, count);
|
||||||
|
24
tests/hay.rs
Normal file
24
tests/hay.rs
Normal file
@ -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\");
|
||||||
|
}
|
||||||
|
";
|
563
tests/tests.rs
Normal file
563
tests/tests.rs
Normal file
@ -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);
|
||||||
|
assert_eq!(lines, "foo\x00bar\nfoo\x00baz\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn binary_search_no_mmap() {
|
||||||
|
let wd = WorkDir::new("binary_search_no_mmap");
|
||||||
|
wd.create("file", "foo\x00bar\nfoo\x00baz\n");
|
||||||
|
let mut cmd = wd.command();
|
||||||
|
cmd.arg("-a").arg("--no-mmap").arg("foo").arg("file");
|
||||||
|
let lines: String = wd.stdout(&mut cmd);
|
||||||
|
assert_eq!(lines, "foo\nfoo\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn files() {
|
||||||
|
let wd = WorkDir::new("files");
|
||||||
|
wd.create("file", "");
|
||||||
|
wd.create_dir("dir");
|
||||||
|
wd.create("dir/file", "");
|
||||||
|
|
||||||
|
let mut cmd = wd.command();
|
||||||
|
cmd.arg("--files");
|
||||||
|
let lines: String = wd.stdout(&mut cmd);
|
||||||
|
assert_eq!(lines, "./file\n./dir/file\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn type_list() {
|
||||||
|
let wd = WorkDir::new("type_list");
|
||||||
|
|
||||||
|
let mut cmd = wd.command();
|
||||||
|
cmd.arg("--type-list");
|
||||||
|
let lines: String = wd.stdout(&mut cmd);
|
||||||
|
// This can change over time, so just make sure we print something.
|
||||||
|
assert!(!lines.is_empty());
|
||||||
|
}
|
189
tests/workdir.rs
Normal file
189
tests/workdir.rs
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
use std::env;
|
||||||
|
use std::error;
|
||||||
|
use std::fmt;
|
||||||
|
use std::fs::{self, File};
|
||||||
|
use std::io::{self, Write};
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::process;
|
||||||
|
use std::str::FromStr;
|
||||||
|
use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering};
|
||||||
|
use std::thread;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
static TEST_DIR: &'static str = "ripgrep-tests";
|
||||||
|
static NEXT_ID: AtomicUsize = ATOMIC_USIZE_INIT;
|
||||||
|
|
||||||
|
/// WorkDir represents a directory in which tests are run.
|
||||||
|
///
|
||||||
|
/// Directories are created from a global atomic counter to avoid duplicates.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct WorkDir {
|
||||||
|
/// The directory in which this test executable is running.
|
||||||
|
root: PathBuf,
|
||||||
|
/// The directory in which the test should run. If a test needs to create
|
||||||
|
/// files, they should go in here.
|
||||||
|
dir: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WorkDir {
|
||||||
|
/// Create a new test working directory with the given name. The name
|
||||||
|
/// does not need to be distinct for each invocation, but should correspond
|
||||||
|
/// to a logical grouping of tests.
|
||||||
|
pub fn new(name: &str) -> WorkDir {
|
||||||
|
let id = NEXT_ID.fetch_add(1, Ordering::SeqCst);
|
||||||
|
let root = env::current_exe().unwrap()
|
||||||
|
.parent().expect("executable's directory").to_path_buf();
|
||||||
|
let dir = root.join(TEST_DIR).join(name).join(&format!("{}", id));
|
||||||
|
nice_err(&dir, repeat(|| fs::create_dir_all(&dir)));
|
||||||
|
WorkDir {
|
||||||
|
root: root,
|
||||||
|
dir: dir,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new file with the given name and contents in this directory.
|
||||||
|
pub fn create<P: AsRef<Path>>(&self, name: P, contents: &str) {
|
||||||
|
let path = self.dir.join(name);
|
||||||
|
let mut file = nice_err(&path, File::create(&path));
|
||||||
|
nice_err(&path, file.write_all(contents.as_bytes()));
|
||||||
|
nice_err(&path, file.flush());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove a file with the given name from this directory.
|
||||||
|
pub fn remove<P: AsRef<Path>>(&self, name: P) {
|
||||||
|
let path = self.dir.join(name);
|
||||||
|
nice_err(&path, fs::remove_file(&path));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new directory with the given path (and any directories above
|
||||||
|
/// it) inside this directory.
|
||||||
|
pub fn create_dir<P: AsRef<Path>>(&self, path: P) {
|
||||||
|
let path = self.dir.join(path);
|
||||||
|
nice_err(&path, repeat(|| fs::create_dir_all(&path)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new command that is set to use the ripgrep executable in
|
||||||
|
/// this working directory.
|
||||||
|
pub fn command(&self) -> process::Command {
|
||||||
|
let mut cmd = process::Command::new(&self.bin());
|
||||||
|
cmd.current_dir(&self.dir);
|
||||||
|
cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the path to the ripgrep executable.
|
||||||
|
pub fn bin(&self) -> PathBuf {
|
||||||
|
self.root.join("rg")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the path to this directory.
|
||||||
|
pub fn path(&self) -> &Path {
|
||||||
|
&self.dir
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a directory symlink to the src with the given target name
|
||||||
|
/// in this directory.
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
pub fn link<S: AsRef<Path>, T: AsRef<Path>>(&self, src: S, target: T) {
|
||||||
|
use std::os::unix::fs::symlink;
|
||||||
|
let src = self.dir.join(src);
|
||||||
|
let target = self.dir.join(target);
|
||||||
|
let _ = fs::remove_file(&target);
|
||||||
|
nice_err(&target, symlink(&src, &target));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub fn link<S: AsRef<Path>, T: AsRef<Path>>(&self, src: S, target: T) {
|
||||||
|
use std::os::windows::fs::symlink_dir;
|
||||||
|
let src = self.dir.join(src);
|
||||||
|
let target = self.dir.join(target);
|
||||||
|
let _ = fs::remove_dir(&target);
|
||||||
|
nice_err(&target, symlink_dir(&src, &target));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Runs and captures the stdout of the given command.
|
||||||
|
///
|
||||||
|
/// If the return type could not be created from a string, then this
|
||||||
|
/// panics.
|
||||||
|
pub fn stdout<E: fmt::Debug, T: FromStr<Err=E>>(
|
||||||
|
&self,
|
||||||
|
cmd: &mut process::Command,
|
||||||
|
) -> T {
|
||||||
|
let o = self.output(cmd);
|
||||||
|
let stdout = String::from_utf8_lossy(&o.stdout);
|
||||||
|
match stdout.parse() {
|
||||||
|
Ok(t) => t,
|
||||||
|
Err(err) => {
|
||||||
|
panic!("could not convert from string: {:?}\n\n{}", err, stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the output of a command. If the command failed, then this panics.
|
||||||
|
pub fn output(&self, cmd: &mut process::Command) -> process::Output {
|
||||||
|
let o = cmd.output().unwrap();
|
||||||
|
if !o.status.success() {
|
||||||
|
let suggest =
|
||||||
|
if o.stderr.is_empty() {
|
||||||
|
"\n\nDid your search end up with no results?".to_string()
|
||||||
|
} else {
|
||||||
|
"".to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
panic!("\n\n==========\n\
|
||||||
|
command failed but expected success!\
|
||||||
|
{}\
|
||||||
|
\n\ncommand: {:?}\
|
||||||
|
\ncwd: {}\
|
||||||
|
\n\nstatus: {}\
|
||||||
|
\n\nstdout: {}\
|
||||||
|
\n\nstderr: {}\
|
||||||
|
\n\n==========\n",
|
||||||
|
suggest, cmd, self.dir.display(), o.status,
|
||||||
|
String::from_utf8_lossy(&o.stdout),
|
||||||
|
String::from_utf8_lossy(&o.stderr));
|
||||||
|
}
|
||||||
|
o
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Runs the given command and asserts that it resulted in an error exit
|
||||||
|
/// code.
|
||||||
|
pub fn assert_err(&self, cmd: &mut process::Command) {
|
||||||
|
let o = cmd.output().unwrap();
|
||||||
|
if o.status.success() {
|
||||||
|
panic!("\n\n===== {:?} =====\n\
|
||||||
|
command succeeded but expected failure!\
|
||||||
|
\n\ncwd: {}\
|
||||||
|
\n\nstatus: {}\
|
||||||
|
\n\nstdout: {}\n\nstderr: {}\
|
||||||
|
\n\n=====\n",
|
||||||
|
cmd, self.dir.display(), o.status,
|
||||||
|
String::from_utf8_lossy(&o.stdout),
|
||||||
|
String::from_utf8_lossy(&o.stderr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nice_err<P: AsRef<Path>, T, E: error::Error>(
|
||||||
|
path: P,
|
||||||
|
res: Result<T, E>,
|
||||||
|
) -> T {
|
||||||
|
match res {
|
||||||
|
Ok(t) => t,
|
||||||
|
Err(err) => {
|
||||||
|
panic!("{}: {:?}", path.as_ref().display(), err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn repeat<F: FnMut() -> io::Result<()>>(mut f: F) -> io::Result<()> {
|
||||||
|
let mut last_err = None;
|
||||||
|
for _ in 0..10 {
|
||||||
|
if let Err(err) = f() {
|
||||||
|
last_err = Some(err);
|
||||||
|
thread::sleep(Duration::from_millis(500));
|
||||||
|
} else {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(last_err.unwrap())
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user