Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
后端镜像
rust镜像
Ripgrep
提交
f83cd63b
R
Ripgrep
项目概览
后端镜像
/
rust镜像
/
Ripgrep
通知
0
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
Ripgrep
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
f83cd63b
编写于
9月 09, 2016
作者:
A
Andrew Gallant
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Add integration tests.
上级
9a4527d1
变更
7
隐藏空白更改
内联
并排
Showing
7 changed file
with
819 addition
and
52 deletion
+819
-52
Cargo.toml
Cargo.toml
+4
-0
src/args.rs
src/args.rs
+4
-15
src/search.rs
src/search.rs
+26
-27
src/search_buffer.rs
src/search_buffer.rs
+9
-10
tests/hay.rs
tests/hay.rs
+24
-0
tests/tests.rs
tests/tests.rs
+563
-0
tests/workdir.rs
tests/workdir.rs
+189
-0
未找到文件。
Cargo.toml
浏览文件 @
f83cd63b
...
...
@@ -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"
...
...
src/args.rs
浏览文件 @
f83cd63b
...
...
@@ -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
();
...
...
src/search.rs
浏览文件 @
f83cd63b
...
...
@@ -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
);
...
...
src/search_buffer.rs
浏览文件 @
f83cd63b
...
...
@@ -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
);
...
...
tests/hay.rs
0 → 100644
浏览文件 @
f83cd63b
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
\"
);
}
"
;
tests/tests.rs
0 → 100644
浏览文件 @
f83cd63b
/*!
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
()
\n
blab
\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
\x00
bar
\n
foo
\x00
baz
\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
\x00
bar
\n
foo
\x00
baz
\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
\x00
bar
\n
foo
\x00
baz
\n
"
);
}
#[test]
fn
binary_search_no_mmap
()
{
let
wd
=
WorkDir
::
new
(
"binary_search_no_mmap"
);
wd
.create
(
"file"
,
"foo
\x00
bar
\n
foo
\x00
baz
\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
\n
foo
\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
());
}
tests/workdir.rs
0 → 100644
浏览文件 @
f83cd63b
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\n
Did your search end up with no results?"
.to_string
()
}
else
{
""
.to_string
()
};
panic!
(
"
\n\n
==========
\n
\
command failed but expected success!
\
{}
\
\n\n
command: {:?}
\
\n
cwd: {}
\
\n\n
status: {}
\
\n\n
stdout: {}
\
\n\n
stderr: {}
\
\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\n
cwd: {}
\
\n\n
status: {}
\
\n\n
stdout: {}
\n\n
stderr: {}
\
\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
())
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录