1
+ use crate :: { assert_not_contains, handle_failed_output} ;
1
2
use std:: ffi:: OsStr ;
2
3
use std:: io:: Write ;
3
4
use std:: ops:: { Deref , DerefMut } ;
4
5
use std:: process:: { Command as StdCommand , ExitStatus , Output , Stdio } ;
5
6
7
+ /// This is a custom command wrapper that simplifies working with commands
8
+ /// and makes it easier to ensure that we check the exit status of executed
9
+ /// processes.
6
10
#[ derive( Debug ) ]
7
11
pub struct Command {
8
12
cmd : StdCommand ,
@@ -11,16 +15,39 @@ pub struct Command {
11
15
12
16
impl Command {
13
17
pub fn new < S : AsRef < OsStr > > ( program : S ) -> Self {
14
- Self {
15
- cmd : StdCommand :: new ( program) ,
16
- stdin : None ,
17
- }
18
+ Self { cmd : StdCommand :: new ( program) , stdin : None }
18
19
}
19
20
20
21
pub fn set_stdin ( & mut self , stdin : Box < [ u8 ] > ) {
21
22
self . stdin = Some ( stdin) ;
22
23
}
23
24
25
+ /// Run the constructed command and assert that it is successfully run.
26
+ #[ track_caller]
27
+ pub fn run ( & mut self ) -> CompletedProcess {
28
+ let caller_location = std:: panic:: Location :: caller ( ) ;
29
+ let caller_line_number = caller_location. line ( ) ;
30
+
31
+ let output = self . command_output ( ) ;
32
+ if !output. status ( ) . success ( ) {
33
+ handle_failed_output ( & self , output, caller_line_number) ;
34
+ }
35
+ output
36
+ }
37
+
38
+ /// Run the constructed command and assert that it does not successfully run.
39
+ #[ track_caller]
40
+ pub fn run_fail ( & mut self ) -> CompletedProcess {
41
+ let caller_location = std:: panic:: Location :: caller ( ) ;
42
+ let caller_line_number = caller_location. line ( ) ;
43
+
44
+ let output = self . command_output ( ) ;
45
+ if output. status ( ) . success ( ) {
46
+ handle_failed_output ( & self , output, caller_line_number) ;
47
+ }
48
+ output
49
+ }
50
+
24
51
#[ track_caller]
25
52
pub ( crate ) fn command_output ( & mut self ) -> CompletedProcess {
26
53
// let's make sure we piped all the input and outputs
@@ -59,6 +86,8 @@ impl DerefMut for Command {
59
86
}
60
87
61
88
/// Represents the result of an executed process.
89
+ /// The various `assert_` helper methods should preferably be used for
90
+ /// checking the contents of stdout/stderr.
62
91
pub struct CompletedProcess {
63
92
output : Output ,
64
93
}
@@ -76,16 +105,47 @@ impl CompletedProcess {
76
105
self . output . status
77
106
}
78
107
108
+ /// Checks that trimmed `stdout` matches trimmed `content`.
109
+ #[ track_caller]
110
+ pub fn assert_stdout_equals < S : AsRef < str > > ( self , content : S ) -> Self {
111
+ assert_eq ! ( self . stdout_utf8( ) . trim( ) , content. as_ref( ) . trim( ) ) ;
112
+ self
113
+ }
114
+
79
115
#[ track_caller]
80
- pub fn assert_exit_code ( & self , code : i32 ) {
116
+ pub fn assert_stdout_not_contains < S : AsRef < str > > ( self , needle : S ) -> Self {
117
+ assert_not_contains ( & self . stdout_utf8 ( ) , needle. as_ref ( ) ) ;
118
+ self
119
+ }
120
+
121
+ /// Checks that trimmed `stderr` matches trimmed `content`.
122
+ #[ track_caller]
123
+ pub fn assert_stderr_equals < S : AsRef < str > > ( self , content : S ) -> Self {
124
+ assert_eq ! ( self . stderr_utf8( ) . trim( ) , content. as_ref( ) . trim( ) ) ;
125
+ self
126
+ }
127
+
128
+ #[ track_caller]
129
+ pub fn assert_stderr_contains < S : AsRef < str > > ( self , needle : S ) -> Self {
130
+ assert ! ( self . stderr_utf8( ) . contains( needle. as_ref( ) ) ) ;
131
+ self
132
+ }
133
+
134
+ #[ track_caller]
135
+ pub fn assert_stderr_not_contains < S : AsRef < str > > ( self , needle : S ) -> Self {
136
+ assert_not_contains ( & self . stdout_utf8 ( ) , needle. as_ref ( ) ) ;
137
+ self
138
+ }
139
+
140
+ #[ track_caller]
141
+ pub fn assert_exit_code ( self , code : i32 ) -> Self {
81
142
assert ! ( self . output. status. code( ) == Some ( code) ) ;
143
+ self
82
144
}
83
145
}
84
146
85
147
impl From < Output > for CompletedProcess {
86
148
fn from ( output : Output ) -> Self {
87
- Self {
88
- output
89
- }
149
+ Self { output }
90
150
}
91
151
}
0 commit comments