@@ -151,13 +151,126 @@ fn test_pipe() {
151
151
let wc_cmd = "wc" ;
152
152
assert ! ( run_cmd!( ls | $wc_cmd) . is_ok( ) ) ;
153
153
154
- // test pipefail
155
- assert ! ( run_cmd!( false | true ) . is_err( ) ) ;
156
- assert ! ( run_fun!( false | true ) . is_err( ) ) ;
157
- assert ! ( run_fun!( ignore false | true ) . is_ok( ) ) ;
158
- set_pipefail ( false ) ;
159
- assert ! ( run_fun!( false | true ) . is_ok( ) ) ;
160
- set_pipefail ( true ) ;
154
+ // test `ignore` command and pipefail mode
155
+ // FIXME: make set_pipefail() thread safe, then move this to a separate test_ignore_and_pipefail()
156
+ struct TestCase {
157
+ /// Run the test case, returning whether the result `.is_ok()`.
158
+ code : fn ( ) -> bool ,
159
+ /// Stringified version of `code`, for identifying assertion failures.
160
+ code_str : & ' static str ,
161
+ /// Do we expect `.is_ok()` when pipefail is on?
162
+ expected_ok_pipefail_on : bool ,
163
+ /// Do we expect `.is_ok()` when pipefail is off?
164
+ expected_ok_pipefail_off : bool ,
165
+ }
166
+ /// Make a function for [TestCase::code].
167
+ ///
168
+ /// Usage: `code!((macro!(command)).extra)`
169
+ /// - `(macro!(command)).extra` is an expression of type CmdResult
170
+ macro_rules! code {
171
+ ( ( $macro: tt $bang: tt ( $( $command: tt) +) ) $( $after: tt) * ) => {
172
+ || $macro$bang( $( $command) +) $( $after) * . is_ok( )
173
+ } ;
174
+ }
175
+ /// Make a string for [TestCase::code_str].
176
+ ///
177
+ /// Usage: `code_str!((macro!(command)).extra)`
178
+ /// - `(macro!(command)).extra` is an expression of type CmdResult
179
+ macro_rules! code_str {
180
+ ( ( $macro: tt $bang: tt ( $( $command: tt) +) ) $( $after: tt) * ) => {
181
+ stringify!( $macro$bang( $( $command) +) $( $after) * . is_ok( ) )
182
+ } ;
183
+ }
184
+ /// Make a [TestCase].
185
+ /// Usage: `test_case!(true/false, true/false, (macro!(command)).extra)`
186
+ /// - the first `true/false` is TestCase::expected_ok_pipefail_on
187
+ /// - the second `true/false` is TestCase::expected_ok_pipefail_off
188
+ /// - `(macro!(command)).extra` is an expression of type CmdResult
189
+ macro_rules! test_case {
190
+ ( $expected_ok_pipefail_on: expr, $expected_ok_pipefail_off: expr, ( $macro: tt $bang: tt ( $( $command: tt) +) ) $( $after: tt) * ) => {
191
+ TestCase {
192
+ code: code!( ( $macro $bang ( $( $command) +) ) $( $after) * ) ,
193
+ code_str: code_str!( ( $macro $bang ( $( $command) +) ) $( $after) * ) ,
194
+ expected_ok_pipefail_on: $expected_ok_pipefail_on,
195
+ expected_ok_pipefail_off: $expected_ok_pipefail_off,
196
+ }
197
+ } ;
198
+ }
199
+ /// Generate test cases for the given entry point.
200
+ /// For each test case, every entry point should yield the same results.
201
+ macro_rules! test_cases_for_entry_point {
202
+ ( ( $macro: tt $bang: tt ( ...) ) $( $after: tt) * ) => {
203
+ & [
204
+ // Use result of last command in pipeline, if all others exit successfully.
205
+ test_case!( true , true , ( $macro $bang ( true ) ) $( $after) * ) ,
206
+ test_case!( false , false , ( $macro $bang ( false ) ) $( $after) * ) ,
207
+ test_case!( true , true , ( $macro $bang ( true | true ) ) $( $after) * ) ,
208
+ test_case!( false , false , ( $macro $bang ( true | false ) ) $( $after) * ) ,
209
+ // Use failure of other commands, if pipefail is on.
210
+ test_case!( false , true , ( $macro $bang ( false | true ) ) $( $after) * ) ,
211
+ // Use failure of last command in pipeline.
212
+ test_case!( false , false , ( $macro $bang ( false | false ) ) $( $after) * ) ,
213
+ // Ignore all failures, when using `ignore` command.
214
+ test_case!( true , true , ( $macro $bang ( ignore true ) ) $( $after) * ) ,
215
+ test_case!( true , true , ( $macro $bang ( ignore false ) ) $( $after) * ) ,
216
+ test_case!( true , true , ( $macro $bang ( ignore true | true ) ) $( $after) * ) ,
217
+ test_case!( true , true , ( $macro $bang ( ignore true | false ) ) $( $after) * ) ,
218
+ test_case!( true , true , ( $macro $bang ( ignore false | true ) ) $( $after) * ) ,
219
+ test_case!( true , true , ( $macro $bang ( ignore false | false ) ) $( $after) * ) ,
220
+ ]
221
+ } ;
222
+ }
223
+
224
+ let test_cases: & [ & [ TestCase ] ] = & [
225
+ test_cases_for_entry_point ! ( ( run_cmd!( ...) ) ) ,
226
+ test_cases_for_entry_point ! ( ( run_fun!( ...) ) . map( |_stdout| ( ) ) ) ,
227
+ test_cases_for_entry_point ! ( ( spawn!( ...) ) . unwrap( ) . wait( ) ) ,
228
+ test_cases_for_entry_point ! ( ( spawn_with_output!( ...) ) . unwrap( ) . wait_with_all( ) . 0 ) ,
229
+ test_cases_for_entry_point ! ( ( spawn_with_output!( ...) )
230
+ . unwrap( )
231
+ . wait_with_output( )
232
+ . map( |_stdout| ( ) ) ) ,
233
+ test_cases_for_entry_point ! ( ( spawn_with_output!( ...) )
234
+ . unwrap( )
235
+ . wait_with_raw_output( & mut vec![ ] ) ) ,
236
+ // FIXME: wait_with_pipe() is currently busted
237
+ // test_cases_for_entry_point!((spawn_with_output!(...))
238
+ // .unwrap()
239
+ // .wait_with_pipe(&mut |_stdout| {})),
240
+ ] ;
241
+
242
+ macro_rules! check_eq {
243
+ ( $left: expr, $right: expr, $( $rest: tt) +) => { {
244
+ let left = $left;
245
+ let right = $right;
246
+ if left != right {
247
+ eprintln!( "assertion failed ({} != {}): {}" , left, right, format!( $( $rest) +) ) ;
248
+ false
249
+ } else {
250
+ true
251
+ }
252
+ } } ;
253
+ }
254
+
255
+ let mut ok = true ;
256
+ for case in test_cases. iter ( ) . flat_map ( |items| items. iter ( ) ) {
257
+ ok &= check_eq ! (
258
+ ( case. code) ( ) ,
259
+ case. expected_ok_pipefail_on,
260
+ "{} when pipefail is on" ,
261
+ case. code_str
262
+ ) ;
263
+ set_pipefail ( false ) ;
264
+ ok &= check_eq ! (
265
+ ( case. code) ( ) ,
266
+ case. expected_ok_pipefail_off,
267
+ "{} when pipefail is off" ,
268
+ case. code_str
269
+ ) ;
270
+ set_pipefail ( true ) ;
271
+ }
272
+
273
+ assert ! ( ok) ;
161
274
}
162
275
163
276
#[ test]
0 commit comments