1+ use crate :: { assert_not_contains, handle_failed_output} ;
12use std:: ffi:: OsStr ;
23use std:: io:: Write ;
34use std:: ops:: { Deref , DerefMut } ;
45use std:: process:: { Command as StdCommand , ExitStatus , Output , Stdio } ;
56
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.
610#[ derive( Debug ) ]
711pub struct Command {
812 cmd : StdCommand ,
@@ -11,16 +15,39 @@ pub struct Command {
1115
1216impl Command {
1317 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 }
1819 }
1920
2021 pub fn set_stdin ( & mut self , stdin : Box < [ u8 ] > ) {
2122 self . stdin = Some ( stdin) ;
2223 }
2324
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+
2451 #[ track_caller]
2552 pub ( crate ) fn command_output ( & mut self ) -> CompletedProcess {
2653 // let's make sure we piped all the input and outputs
@@ -59,6 +86,8 @@ impl DerefMut for Command {
5986}
6087
6188/// 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.
6291pub struct CompletedProcess {
6392 output : Output ,
6493}
@@ -76,16 +105,47 @@ impl CompletedProcess {
76105 self . output . status
77106 }
78107
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+
79115 #[ 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 {
81142 assert ! ( self . output. status. code( ) == Some ( code) ) ;
143+ self
82144 }
83145}
84146
85147impl From < Output > for CompletedProcess {
86148 fn from ( output : Output ) -> Self {
87- Self {
88- output
89- }
149+ Self { output }
90150 }
91151}
0 commit comments