1 //! [`std::process::Output`] assertions. 2 3 use std::borrow::Cow; 4 use std::error::Error; 5 use std::fmt; 6 use std::process; 7 use std::str; 8 9 use predicates::str::PredicateStrExt; 10 use predicates_tree::CaseTreeExt; 11 12 use crate::output::output_fmt; 13 use crate::output::DebugBytes; 14 15 /// Assert the state of an [`Output`]. 16 /// 17 /// # Examples 18 /// 19 /// ```rust,no_run 20 /// use assert_cmd::prelude::*; 21 /// 22 /// use std::process::Command; 23 /// 24 /// let mut cmd = Command::cargo_bin("bin_fixture") 25 /// .unwrap(); 26 /// cmd.assert() 27 /// .success(); 28 /// ``` 29 /// 30 /// [`Output`]: std::process::Output 31 pub trait OutputAssertExt { 32 /// Wrap with an interface for that provides assertions on the [`Output`]. 33 /// 34 /// # Examples 35 /// 36 /// ```rust,no_run 37 /// use assert_cmd::prelude::*; 38 /// 39 /// use std::process::Command; 40 /// 41 /// let mut cmd = Command::cargo_bin("bin_fixture") 42 /// .unwrap(); 43 /// cmd.assert() 44 /// .success(); 45 /// ``` 46 /// 47 /// [`Output`]: std::process::Output assert(self) -> Assert48 fn assert(self) -> Assert; 49 } 50 51 impl OutputAssertExt for process::Output { assert(self) -> Assert52 fn assert(self) -> Assert { 53 Assert::new(self) 54 } 55 } 56 57 impl<'c> OutputAssertExt for &'c mut process::Command { assert(self) -> Assert58 fn assert(self) -> Assert { 59 let output = match self.output() { 60 Ok(output) => output, 61 Err(err) => { 62 panic!("Failed to spawn {:?}: {}", self, err); 63 } 64 }; 65 Assert::new(output).append_context("command", format!("{:?}", self)) 66 } 67 } 68 69 /// Assert the state of an [`Output`]. 70 /// 71 /// Create an `Assert` through the [`OutputAssertExt`] trait. 72 /// 73 /// # Examples 74 /// 75 /// ```rust,no_run 76 /// use assert_cmd::prelude::*; 77 /// 78 /// use std::process::Command; 79 /// 80 /// let mut cmd = Command::cargo_bin("bin_fixture") 81 /// .unwrap(); 82 /// cmd.assert() 83 /// .success(); 84 /// ``` 85 /// 86 /// [`Output`]: std::process::Output 87 pub struct Assert { 88 output: process::Output, 89 context: Vec<(&'static str, Box<dyn fmt::Display + Send + Sync>)>, 90 } 91 92 impl Assert { 93 /// Create an `Assert` for a given [`Output`]. 94 /// 95 /// [`Output`]: std::process::Output new(output: process::Output) -> Self96 pub fn new(output: process::Output) -> Self { 97 Self { 98 output, 99 context: vec![], 100 } 101 } 102 into_error(self, reason: AssertReason) -> AssertError103 fn into_error(self, reason: AssertReason) -> AssertError { 104 AssertError { 105 assert: self, 106 reason, 107 } 108 } 109 110 /// Clarify failures with additional context. 111 /// 112 /// # Examples 113 /// 114 /// ```rust,no_run 115 /// use assert_cmd::prelude::*; 116 /// 117 /// use std::process::Command; 118 /// 119 /// Command::cargo_bin("bin_fixture") 120 /// .unwrap() 121 /// .assert() 122 /// .append_context("main", "no args") 123 /// .success(); 124 /// ``` append_context<D>(mut self, name: &'static str, context: D) -> Self where D: fmt::Display + Send + Sync + 'static,125 pub fn append_context<D>(mut self, name: &'static str, context: D) -> Self 126 where 127 D: fmt::Display + Send + Sync + 'static, 128 { 129 self.context.push((name, Box::new(context))); 130 self 131 } 132 133 /// Access the contained [`Output`]. 134 /// 135 /// [`Output`]: std::process::Output get_output(&self) -> &process::Output136 pub fn get_output(&self) -> &process::Output { 137 &self.output 138 } 139 140 /// Ensure the command succeeded. 141 /// 142 /// # Examples 143 /// 144 /// ```rust,no_run 145 /// use assert_cmd::prelude::*; 146 /// 147 /// use std::process::Command; 148 /// 149 /// Command::cargo_bin("bin_fixture") 150 /// .unwrap() 151 /// .assert() 152 /// .success(); 153 /// ``` 154 #[track_caller] success(self) -> Self155 pub fn success(self) -> Self { 156 self.try_success().unwrap_or_else(AssertError::panic) 157 } 158 159 /// `try_` variant of [`Assert::success`]. try_success(self) -> AssertResult160 pub fn try_success(self) -> AssertResult { 161 if !self.output.status.success() { 162 let actual_code = self.output.status.code(); 163 return Err(self.into_error(AssertReason::UnexpectedFailure { actual_code })); 164 } 165 Ok(self) 166 } 167 168 /// Ensure the command failed. 169 /// 170 /// # Examples 171 /// 172 /// ```rust,no_run 173 /// use assert_cmd::prelude::*; 174 /// 175 /// use std::process::Command; 176 /// 177 /// Command::cargo_bin("bin_fixture") 178 /// .unwrap() 179 /// .env("exit", "1") 180 /// .assert() 181 /// .failure(); 182 /// ``` 183 #[track_caller] failure(self) -> Self184 pub fn failure(self) -> Self { 185 self.try_failure().unwrap_or_else(AssertError::panic) 186 } 187 188 /// Variant of [`Assert::failure`] that returns an [`AssertResult`]. try_failure(self) -> AssertResult189 pub fn try_failure(self) -> AssertResult { 190 if self.output.status.success() { 191 return Err(self.into_error(AssertReason::UnexpectedSuccess)); 192 } 193 Ok(self) 194 } 195 196 /// Ensure the command aborted before returning a code. 197 #[track_caller] interrupted(self) -> Self198 pub fn interrupted(self) -> Self { 199 self.try_interrupted().unwrap_or_else(AssertError::panic) 200 } 201 202 /// Variant of [`Assert::interrupted`] that returns an [`AssertResult`]. try_interrupted(self) -> AssertResult203 pub fn try_interrupted(self) -> AssertResult { 204 if self.output.status.code().is_some() { 205 return Err(self.into_error(AssertReason::UnexpectedCompletion)); 206 } 207 Ok(self) 208 } 209 210 /// Ensure the command returned the expected code. 211 /// 212 /// This uses [`IntoCodePredicate`] to provide short-hands for common cases. 213 /// 214 /// See [`predicates`] for more predicates. 215 /// 216 /// # Examples 217 /// 218 /// Accepting a predicate: 219 /// ```rust,no_run 220 /// use assert_cmd::prelude::*; 221 /// 222 /// use std::process::Command; 223 /// use predicates::prelude::*; 224 /// 225 /// Command::cargo_bin("bin_fixture") 226 /// .unwrap() 227 /// .env("exit", "42") 228 /// .assert() 229 /// .code(predicate::eq(42)); 230 /// ``` 231 /// 232 /// Accepting an exit code: 233 /// ```rust,no_run 234 /// use assert_cmd::prelude::*; 235 /// 236 /// use std::process::Command; 237 /// 238 /// Command::cargo_bin("bin_fixture") 239 /// .unwrap() 240 /// .env("exit", "42") 241 /// .assert() 242 /// .code(42); 243 /// ``` 244 /// 245 /// Accepting multiple exit codes: 246 /// ```rust,no_run 247 /// use assert_cmd::prelude::*; 248 /// 249 /// use std::process::Command; 250 /// 251 /// Command::cargo_bin("bin_fixture") 252 /// .unwrap() 253 /// .env("exit", "42") 254 /// .assert() 255 /// .code(&[2, 42] as &[i32]); 256 /// ``` 257 /// 258 #[track_caller] code<I, P>(self, pred: I) -> Self where I: IntoCodePredicate<P>, P: predicates_core::Predicate<i32>,259 pub fn code<I, P>(self, pred: I) -> Self 260 where 261 I: IntoCodePredicate<P>, 262 P: predicates_core::Predicate<i32>, 263 { 264 self.try_code(pred).unwrap_or_else(AssertError::panic) 265 } 266 267 /// Variant of [`Assert::code`] that returns an [`AssertResult`]. try_code<I, P>(self, pred: I) -> AssertResult where I: IntoCodePredicate<P>, P: predicates_core::Predicate<i32>,268 pub fn try_code<I, P>(self, pred: I) -> AssertResult 269 where 270 I: IntoCodePredicate<P>, 271 P: predicates_core::Predicate<i32>, 272 { 273 self.code_impl(&pred.into_code()) 274 } 275 code_impl(self, pred: &dyn predicates_core::Predicate<i32>) -> AssertResult276 fn code_impl(self, pred: &dyn predicates_core::Predicate<i32>) -> AssertResult { 277 let actual_code = if let Some(actual_code) = self.output.status.code() { 278 actual_code 279 } else { 280 return Err(self.into_error(AssertReason::CommandInterrupted)); 281 }; 282 if let Some(case) = pred.find_case(false, &actual_code) { 283 return Err(self.into_error(AssertReason::UnexpectedReturnCode { 284 case_tree: CaseTree(case.tree()), 285 })); 286 } 287 Ok(self) 288 } 289 290 /// Ensure the command wrote the expected data to `stdout`. 291 /// 292 /// This uses [`IntoOutputPredicate`] to provide short-hands for common cases. 293 /// 294 /// See [`predicates`] for more predicates. 295 /// 296 /// # Examples 297 /// 298 /// Accepting a bytes predicate: 299 /// ```rust,no_run 300 /// use assert_cmd::prelude::*; 301 /// 302 /// use std::process::Command; 303 /// use predicates::prelude::*; 304 /// 305 /// Command::cargo_bin("bin_fixture") 306 /// .unwrap() 307 /// .env("stdout", "hello") 308 /// .env("stderr", "world") 309 /// .assert() 310 /// .stdout(predicate::eq(b"hello\n" as &[u8])); 311 /// ``` 312 /// 313 /// Accepting a `str` predicate: 314 /// ```rust,no_run 315 /// use assert_cmd::prelude::*; 316 /// 317 /// use std::process::Command; 318 /// use predicates::prelude::*; 319 /// 320 /// Command::cargo_bin("bin_fixture") 321 /// .unwrap() 322 /// .env("stdout", "hello") 323 /// .env("stderr", "world") 324 /// .assert() 325 /// .stdout(predicate::str::diff("hello\n")); 326 /// ``` 327 /// 328 /// Accepting bytes: 329 /// ```rust,no_run 330 /// use assert_cmd::prelude::*; 331 /// 332 /// use std::process::Command; 333 /// 334 /// Command::cargo_bin("bin_fixture") 335 /// .unwrap() 336 /// .env("stdout", "hello") 337 /// .env("stderr", "world") 338 /// .assert() 339 /// .stdout(b"hello\n" as &[u8]); 340 /// ``` 341 /// 342 /// Accepting a `str`: 343 /// ```rust,no_run 344 /// use assert_cmd::prelude::*; 345 /// 346 /// use std::process::Command; 347 /// 348 /// Command::cargo_bin("bin_fixture") 349 /// .unwrap() 350 /// .env("stdout", "hello") 351 /// .env("stderr", "world") 352 /// .assert() 353 /// .stdout("hello\n"); 354 /// ``` 355 /// 356 #[track_caller] stdout<I, P>(self, pred: I) -> Self where I: IntoOutputPredicate<P>, P: predicates_core::Predicate<[u8]>,357 pub fn stdout<I, P>(self, pred: I) -> Self 358 where 359 I: IntoOutputPredicate<P>, 360 P: predicates_core::Predicate<[u8]>, 361 { 362 self.try_stdout(pred).unwrap_or_else(AssertError::panic) 363 } 364 365 /// Variant of [`Assert::stdout`] that returns an [`AssertResult`]. try_stdout<I, P>(self, pred: I) -> AssertResult where I: IntoOutputPredicate<P>, P: predicates_core::Predicate<[u8]>,366 pub fn try_stdout<I, P>(self, pred: I) -> AssertResult 367 where 368 I: IntoOutputPredicate<P>, 369 P: predicates_core::Predicate<[u8]>, 370 { 371 self.stdout_impl(&pred.into_output()) 372 } 373 stdout_impl(self, pred: &dyn predicates_core::Predicate<[u8]>) -> AssertResult374 fn stdout_impl(self, pred: &dyn predicates_core::Predicate<[u8]>) -> AssertResult { 375 { 376 let actual = &self.output.stdout; 377 if let Some(case) = pred.find_case(false, actual) { 378 return Err(self.into_error(AssertReason::UnexpectedStdout { 379 case_tree: CaseTree(case.tree()), 380 })); 381 } 382 } 383 Ok(self) 384 } 385 386 /// Ensure the command wrote the expected data to `stderr`. 387 /// 388 /// This uses [`IntoOutputPredicate`] to provide short-hands for common cases. 389 /// 390 /// See [`predicates`] for more predicates. 391 /// 392 /// # Examples 393 /// 394 /// Accepting a bytes predicate: 395 /// ```rust,no_run 396 /// use assert_cmd::prelude::*; 397 /// 398 /// use std::process::Command; 399 /// use predicates::prelude::*; 400 /// 401 /// Command::cargo_bin("bin_fixture") 402 /// .unwrap() 403 /// .env("stdout", "hello") 404 /// .env("stderr", "world") 405 /// .assert() 406 /// .stderr(predicate::eq(b"world\n" as &[u8])); 407 /// ``` 408 /// 409 /// Accepting a `str` predicate: 410 /// ```rust,no_run 411 /// use assert_cmd::prelude::*; 412 /// 413 /// use std::process::Command; 414 /// use predicates::prelude::*; 415 /// 416 /// Command::cargo_bin("bin_fixture") 417 /// .unwrap() 418 /// .env("stdout", "hello") 419 /// .env("stderr", "world") 420 /// .assert() 421 /// .stderr(predicate::str::diff("world\n")); 422 /// ``` 423 /// 424 /// Accepting bytes: 425 /// ```rust,no_run 426 /// use assert_cmd::prelude::*; 427 /// 428 /// use std::process::Command; 429 /// 430 /// Command::cargo_bin("bin_fixture") 431 /// .unwrap() 432 /// .env("stdout", "hello") 433 /// .env("stderr", "world") 434 /// .assert() 435 /// .stderr(b"world\n" as &[u8]); 436 /// ``` 437 /// 438 /// Accepting a `str`: 439 /// ```rust,no_run 440 /// use assert_cmd::prelude::*; 441 /// 442 /// use std::process::Command; 443 /// 444 /// Command::cargo_bin("bin_fixture") 445 /// .unwrap() 446 /// .env("stdout", "hello") 447 /// .env("stderr", "world") 448 /// .assert() 449 /// .stderr("world\n"); 450 /// ``` 451 /// 452 #[track_caller] stderr<I, P>(self, pred: I) -> Self where I: IntoOutputPredicate<P>, P: predicates_core::Predicate<[u8]>,453 pub fn stderr<I, P>(self, pred: I) -> Self 454 where 455 I: IntoOutputPredicate<P>, 456 P: predicates_core::Predicate<[u8]>, 457 { 458 self.try_stderr(pred).unwrap_or_else(AssertError::panic) 459 } 460 461 /// Variant of [`Assert::stderr`] that returns an [`AssertResult`]. try_stderr<I, P>(self, pred: I) -> AssertResult where I: IntoOutputPredicate<P>, P: predicates_core::Predicate<[u8]>,462 pub fn try_stderr<I, P>(self, pred: I) -> AssertResult 463 where 464 I: IntoOutputPredicate<P>, 465 P: predicates_core::Predicate<[u8]>, 466 { 467 self.stderr_impl(&pred.into_output()) 468 } 469 stderr_impl(self, pred: &dyn predicates_core::Predicate<[u8]>) -> AssertResult470 fn stderr_impl(self, pred: &dyn predicates_core::Predicate<[u8]>) -> AssertResult { 471 { 472 let actual = &self.output.stderr; 473 if let Some(case) = pred.find_case(false, actual) { 474 return Err(self.into_error(AssertReason::UnexpectedStderr { 475 case_tree: CaseTree(case.tree()), 476 })); 477 } 478 } 479 Ok(self) 480 } 481 } 482 483 impl fmt::Display for Assert { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result484 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 485 let palette = crate::Palette::current(); 486 for &(ref name, ref context) in &self.context { 487 writeln!( 488 f, 489 "{}=`{}`", 490 palette.key.paint(name), 491 palette.value.paint(context) 492 )?; 493 } 494 output_fmt(&self.output, f) 495 } 496 } 497 498 impl fmt::Debug for Assert { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result499 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 500 f.debug_struct("Assert") 501 .field("output", &self.output) 502 .finish() 503 } 504 } 505 506 /// Used by [`Assert::code`] to convert `Self` into the needed 507 /// [`predicates_core::Predicate<i32>`]. 508 /// 509 /// # Examples 510 /// 511 /// ```rust,no_run 512 /// use assert_cmd::prelude::*; 513 /// 514 /// use std::process::Command; 515 /// use predicates::prelude::*; 516 /// 517 /// Command::cargo_bin("bin_fixture") 518 /// .unwrap() 519 /// .env("exit", "42") 520 /// .assert() 521 /// .code(predicate::eq(42)); 522 /// 523 /// // which can be shortened to: 524 /// Command::cargo_bin("bin_fixture") 525 /// .unwrap() 526 /// .env("exit", "42") 527 /// .assert() 528 /// .code(42); 529 /// ``` 530 pub trait IntoCodePredicate<P> 531 where 532 P: predicates_core::Predicate<i32>, 533 { 534 /// The type of the predicate being returned. 535 type Predicate; 536 537 /// Convert to a predicate for testing a program's exit code. into_code(self) -> P538 fn into_code(self) -> P; 539 } 540 541 impl<P> IntoCodePredicate<P> for P 542 where 543 P: predicates_core::Predicate<i32>, 544 { 545 type Predicate = P; 546 into_code(self) -> Self::Predicate547 fn into_code(self) -> Self::Predicate { 548 self 549 } 550 } 551 552 /// Keep `predicates` concrete Predicates out of our public API. 553 /// [predicates_core::Predicate] used by [`IntoCodePredicate`] for code. 554 /// 555 /// # Example 556 /// 557 /// ```rust,no_run 558 /// use assert_cmd::prelude::*; 559 /// 560 /// use std::process::Command; 561 /// 562 /// Command::cargo_bin("bin_fixture") 563 /// .unwrap() 564 /// .env("exit", "42") 565 /// .assert() 566 /// .code(42); 567 /// ``` 568 #[derive(Debug)] 569 pub struct EqCodePredicate(predicates::ord::EqPredicate<i32>); 570 571 impl EqCodePredicate { new(value: i32) -> Self572 pub(crate) fn new(value: i32) -> Self { 573 let pred = predicates::ord::eq(value); 574 EqCodePredicate(pred) 575 } 576 } 577 578 impl predicates_core::reflection::PredicateReflection for EqCodePredicate { parameters<'a>( &'a self, ) -> Box<dyn Iterator<Item = predicates_core::reflection::Parameter<'a>> + 'a>579 fn parameters<'a>( 580 &'a self, 581 ) -> Box<dyn Iterator<Item = predicates_core::reflection::Parameter<'a>> + 'a> { 582 self.0.parameters() 583 } 584 585 /// Nested `Predicate`s of the current `Predicate`. children<'a>( &'a self, ) -> Box<dyn Iterator<Item = predicates_core::reflection::Child<'a>> + 'a>586 fn children<'a>( 587 &'a self, 588 ) -> Box<dyn Iterator<Item = predicates_core::reflection::Child<'a>> + 'a> { 589 self.0.children() 590 } 591 } 592 593 impl predicates_core::Predicate<i32> for EqCodePredicate { eval(&self, item: &i32) -> bool594 fn eval(&self, item: &i32) -> bool { 595 self.0.eval(item) 596 } 597 find_case<'a>( &'a self, expected: bool, variable: &i32, ) -> Option<predicates_core::reflection::Case<'a>>598 fn find_case<'a>( 599 &'a self, 600 expected: bool, 601 variable: &i32, 602 ) -> Option<predicates_core::reflection::Case<'a>> { 603 self.0.find_case(expected, variable) 604 } 605 } 606 607 impl fmt::Display for EqCodePredicate { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result608 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 609 self.0.fmt(f) 610 } 611 } 612 613 impl IntoCodePredicate<EqCodePredicate> for i32 { 614 type Predicate = EqCodePredicate; 615 into_code(self) -> Self::Predicate616 fn into_code(self) -> Self::Predicate { 617 Self::Predicate::new(self) 618 } 619 } 620 621 /// Keep `predicates` concrete Predicates out of our public API. 622 /// [predicates_core::Predicate] used by [`IntoCodePredicate`] for iterables of codes. 623 /// 624 /// # Example 625 /// 626 /// ```rust,no_run 627 /// use assert_cmd::prelude::*; 628 /// 629 /// use std::process::Command; 630 /// 631 /// Command::cargo_bin("bin_fixture") 632 /// .unwrap() 633 /// .env("exit", "42") 634 /// .assert() 635 /// .code(&[2, 42] as &[i32]); 636 /// ``` 637 #[derive(Debug)] 638 pub struct InCodePredicate(predicates::iter::InPredicate<i32>); 639 640 impl InCodePredicate { new<I: IntoIterator<Item = i32>>(value: I) -> Self641 pub(crate) fn new<I: IntoIterator<Item = i32>>(value: I) -> Self { 642 let pred = predicates::iter::in_iter(value); 643 InCodePredicate(pred) 644 } 645 } 646 647 impl predicates_core::reflection::PredicateReflection for InCodePredicate { parameters<'a>( &'a self, ) -> Box<dyn Iterator<Item = predicates_core::reflection::Parameter<'a>> + 'a>648 fn parameters<'a>( 649 &'a self, 650 ) -> Box<dyn Iterator<Item = predicates_core::reflection::Parameter<'a>> + 'a> { 651 self.0.parameters() 652 } 653 654 /// Nested `Predicate`s of the current `Predicate`. children<'a>( &'a self, ) -> Box<dyn Iterator<Item = predicates_core::reflection::Child<'a>> + 'a>655 fn children<'a>( 656 &'a self, 657 ) -> Box<dyn Iterator<Item = predicates_core::reflection::Child<'a>> + 'a> { 658 self.0.children() 659 } 660 } 661 662 impl predicates_core::Predicate<i32> for InCodePredicate { eval(&self, item: &i32) -> bool663 fn eval(&self, item: &i32) -> bool { 664 self.0.eval(item) 665 } 666 find_case<'a>( &'a self, expected: bool, variable: &i32, ) -> Option<predicates_core::reflection::Case<'a>>667 fn find_case<'a>( 668 &'a self, 669 expected: bool, 670 variable: &i32, 671 ) -> Option<predicates_core::reflection::Case<'a>> { 672 self.0.find_case(expected, variable) 673 } 674 } 675 676 impl fmt::Display for InCodePredicate { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result677 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 678 self.0.fmt(f) 679 } 680 } 681 682 impl IntoCodePredicate<InCodePredicate> for Vec<i32> { 683 type Predicate = InCodePredicate; 684 into_code(self) -> Self::Predicate685 fn into_code(self) -> Self::Predicate { 686 Self::Predicate::new(self) 687 } 688 } 689 690 impl IntoCodePredicate<InCodePredicate> for &'static [i32] { 691 type Predicate = InCodePredicate; 692 into_code(self) -> Self::Predicate693 fn into_code(self) -> Self::Predicate { 694 Self::Predicate::new(self.iter().cloned()) 695 } 696 } 697 698 /// Used by [`Assert::stdout`] and [`Assert::stderr`] to convert Self 699 /// into the needed [`predicates_core::Predicate<[u8]>`]. 700 /// 701 /// # Examples 702 /// 703 /// ```rust,no_run 704 /// use assert_cmd::prelude::*; 705 /// 706 /// use std::process::Command; 707 /// use predicates::prelude::*; 708 /// 709 /// Command::cargo_bin("bin_fixture") 710 /// .unwrap() 711 /// .env("stdout", "hello") 712 /// .env("stderr", "world") 713 /// .assert() 714 /// .stdout(predicate::str::diff("hello\n").from_utf8()); 715 /// 716 /// // which can be shortened to: 717 /// Command::cargo_bin("bin_fixture") 718 /// .unwrap() 719 /// .env("stdout", "hello") 720 /// .env("stderr", "world") 721 /// .assert() 722 /// .stdout("hello\n"); 723 /// ``` 724 pub trait IntoOutputPredicate<P> 725 where 726 P: predicates_core::Predicate<[u8]>, 727 { 728 /// The type of the predicate being returned. 729 type Predicate; 730 731 /// Convert to a predicate for testing a path. into_output(self) -> P732 fn into_output(self) -> P; 733 } 734 735 impl<P> IntoOutputPredicate<P> for P 736 where 737 P: predicates_core::Predicate<[u8]>, 738 { 739 type Predicate = P; 740 into_output(self) -> Self::Predicate741 fn into_output(self) -> Self::Predicate { 742 self 743 } 744 } 745 746 /// Keep `predicates` concrete Predicates out of our public API. 747 /// [predicates_core::Predicate] used by [`IntoOutputPredicate`] for bytes. 748 /// 749 /// # Example 750 /// 751 /// ```rust,no_run 752 /// use assert_cmd::prelude::*; 753 /// 754 /// use std::process::Command; 755 /// 756 /// Command::cargo_bin("bin_fixture") 757 /// .unwrap() 758 /// .env("stdout", "hello") 759 /// .env("stderr", "world") 760 /// .assert() 761 /// .stderr(b"world\n" as &[u8]); 762 /// ``` 763 #[derive(Debug)] 764 pub struct BytesContentOutputPredicate(Cow<'static, [u8]>); 765 766 impl BytesContentOutputPredicate { new(value: &'static [u8]) -> Self767 pub(crate) fn new(value: &'static [u8]) -> Self { 768 BytesContentOutputPredicate(Cow::from(value)) 769 } 770 from_vec(value: Vec<u8>) -> Self771 pub(crate) fn from_vec(value: Vec<u8>) -> Self { 772 BytesContentOutputPredicate(Cow::from(value)) 773 } 774 } 775 776 impl predicates_core::reflection::PredicateReflection for BytesContentOutputPredicate {} 777 778 impl predicates_core::Predicate<[u8]> for BytesContentOutputPredicate { eval(&self, item: &[u8]) -> bool779 fn eval(&self, item: &[u8]) -> bool { 780 self.0.as_ref() == item 781 } 782 find_case( &self, expected: bool, variable: &[u8], ) -> Option<predicates_core::reflection::Case>783 fn find_case( 784 &self, 785 expected: bool, 786 variable: &[u8], 787 ) -> Option<predicates_core::reflection::Case> { 788 let actual = self.eval(variable); 789 if expected == actual { 790 Some(predicates_core::reflection::Case::new(Some(self), actual)) 791 } else { 792 None 793 } 794 } 795 } 796 797 impl fmt::Display for BytesContentOutputPredicate { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result798 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 799 predicates::ord::eq(self.0.as_ref()).fmt(f) 800 } 801 } 802 803 impl IntoOutputPredicate<BytesContentOutputPredicate> for Vec<u8> { 804 type Predicate = BytesContentOutputPredicate; 805 into_output(self) -> Self::Predicate806 fn into_output(self) -> Self::Predicate { 807 Self::Predicate::from_vec(self) 808 } 809 } 810 811 impl IntoOutputPredicate<BytesContentOutputPredicate> for &'static [u8] { 812 type Predicate = BytesContentOutputPredicate; 813 into_output(self) -> Self::Predicate814 fn into_output(self) -> Self::Predicate { 815 Self::Predicate::new(self) 816 } 817 } 818 819 /// Keep `predicates` concrete Predicates out of our public API. 820 /// [predicates_core::Predicate] used by [`IntoOutputPredicate`] for [`str`]. 821 /// 822 /// # Example 823 /// 824 /// ```rust,no_run 825 /// use assert_cmd::prelude::*; 826 /// 827 /// use std::process::Command; 828 /// 829 /// Command::cargo_bin("bin_fixture") 830 /// .unwrap() 831 /// .env("stdout", "hello") 832 /// .env("stderr", "world") 833 /// .assert() 834 /// .stderr("world\n"); 835 /// ``` 836 /// 837 /// [`str`]: https://doc.rust-lang.org/std/primitive.str.html 838 #[derive(Debug, Clone)] 839 pub struct StrContentOutputPredicate( 840 predicates::str::Utf8Predicate<predicates::str::DifferencePredicate>, 841 ); 842 843 impl StrContentOutputPredicate { from_str(value: &'static str) -> Self844 pub(crate) fn from_str(value: &'static str) -> Self { 845 let pred = predicates::str::diff(value).from_utf8(); 846 StrContentOutputPredicate(pred) 847 } 848 from_string(value: String) -> Self849 pub(crate) fn from_string(value: String) -> Self { 850 let pred = predicates::str::diff(value).from_utf8(); 851 StrContentOutputPredicate(pred) 852 } 853 } 854 855 impl predicates_core::reflection::PredicateReflection for StrContentOutputPredicate { parameters<'a>( &'a self, ) -> Box<dyn Iterator<Item = predicates_core::reflection::Parameter<'a>> + 'a>856 fn parameters<'a>( 857 &'a self, 858 ) -> Box<dyn Iterator<Item = predicates_core::reflection::Parameter<'a>> + 'a> { 859 self.0.parameters() 860 } 861 862 /// Nested `Predicate`s of the current `Predicate`. children<'a>( &'a self, ) -> Box<dyn Iterator<Item = predicates_core::reflection::Child<'a>> + 'a>863 fn children<'a>( 864 &'a self, 865 ) -> Box<dyn Iterator<Item = predicates_core::reflection::Child<'a>> + 'a> { 866 self.0.children() 867 } 868 } 869 870 impl predicates_core::Predicate<[u8]> for StrContentOutputPredicate { eval(&self, item: &[u8]) -> bool871 fn eval(&self, item: &[u8]) -> bool { 872 self.0.eval(item) 873 } 874 find_case<'a>( &'a self, expected: bool, variable: &[u8], ) -> Option<predicates_core::reflection::Case<'a>>875 fn find_case<'a>( 876 &'a self, 877 expected: bool, 878 variable: &[u8], 879 ) -> Option<predicates_core::reflection::Case<'a>> { 880 self.0.find_case(expected, variable) 881 } 882 } 883 884 impl fmt::Display for StrContentOutputPredicate { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result885 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 886 self.0.fmt(f) 887 } 888 } 889 890 impl IntoOutputPredicate<StrContentOutputPredicate> for String { 891 type Predicate = StrContentOutputPredicate; 892 into_output(self) -> Self::Predicate893 fn into_output(self) -> Self::Predicate { 894 Self::Predicate::from_string(self) 895 } 896 } 897 898 impl IntoOutputPredicate<StrContentOutputPredicate> for &'static str { 899 type Predicate = StrContentOutputPredicate; 900 into_output(self) -> Self::Predicate901 fn into_output(self) -> Self::Predicate { 902 Self::Predicate::from_str(self) 903 } 904 } 905 906 // Keep `predicates` concrete Predicates out of our public API. 907 /// [predicates_core::Predicate] used by [`IntoOutputPredicate`] for 908 /// [`Predicate<str>`][predicates_core::Predicate]. 909 /// 910 /// # Example 911 /// 912 /// ```rust,no_run 913 /// use assert_cmd::prelude::*; 914 /// 915 /// use std::process::Command; 916 /// use predicates::prelude::*; 917 /// 918 /// Command::cargo_bin("bin_fixture") 919 /// .unwrap() 920 /// .env("stdout", "hello") 921 /// .env("stderr", "world") 922 /// .assert() 923 /// .stderr(predicate::str::diff("world\n")); 924 /// ``` 925 #[derive(Debug, Clone)] 926 pub struct StrOutputPredicate<P: predicates_core::Predicate<str>>( 927 predicates::str::Utf8Predicate<P>, 928 ); 929 930 impl<P> StrOutputPredicate<P> 931 where 932 P: predicates_core::Predicate<str>, 933 { new(pred: P) -> Self934 pub(crate) fn new(pred: P) -> Self { 935 let pred = pred.from_utf8(); 936 StrOutputPredicate(pred) 937 } 938 } 939 940 impl<P> predicates_core::reflection::PredicateReflection for StrOutputPredicate<P> 941 where 942 P: predicates_core::Predicate<str>, 943 { parameters<'a>( &'a self, ) -> Box<dyn Iterator<Item = predicates_core::reflection::Parameter<'a>> + 'a>944 fn parameters<'a>( 945 &'a self, 946 ) -> Box<dyn Iterator<Item = predicates_core::reflection::Parameter<'a>> + 'a> { 947 self.0.parameters() 948 } 949 950 /// Nested `Predicate`s of the current `Predicate`. children<'a>( &'a self, ) -> Box<dyn Iterator<Item = predicates_core::reflection::Child<'a>> + 'a>951 fn children<'a>( 952 &'a self, 953 ) -> Box<dyn Iterator<Item = predicates_core::reflection::Child<'a>> + 'a> { 954 self.0.children() 955 } 956 } 957 958 impl<P> predicates_core::Predicate<[u8]> for StrOutputPredicate<P> 959 where 960 P: predicates_core::Predicate<str>, 961 { eval(&self, item: &[u8]) -> bool962 fn eval(&self, item: &[u8]) -> bool { 963 self.0.eval(item) 964 } 965 find_case<'a>( &'a self, expected: bool, variable: &[u8], ) -> Option<predicates_core::reflection::Case<'a>>966 fn find_case<'a>( 967 &'a self, 968 expected: bool, 969 variable: &[u8], 970 ) -> Option<predicates_core::reflection::Case<'a>> { 971 self.0.find_case(expected, variable) 972 } 973 } 974 975 impl<P> fmt::Display for StrOutputPredicate<P> 976 where 977 P: predicates_core::Predicate<str>, 978 { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result979 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 980 self.0.fmt(f) 981 } 982 } 983 984 impl<P> IntoOutputPredicate<StrOutputPredicate<P>> for P 985 where 986 P: predicates_core::Predicate<str>, 987 { 988 type Predicate = StrOutputPredicate<P>; 989 into_output(self) -> Self::Predicate990 fn into_output(self) -> Self::Predicate { 991 Self::Predicate::new(self) 992 } 993 } 994 995 /// [`Assert`] represented as a [`Result`]. 996 /// 997 /// Produced by the `try_` variants the [`Assert`] methods. 998 /// 999 /// # Example 1000 /// 1001 /// ```rust 1002 /// use assert_cmd::prelude::*; 1003 /// 1004 /// use std::process::Command; 1005 /// 1006 /// let result = Command::new("echo") 1007 /// .assert() 1008 /// .try_success(); 1009 /// assert!(result.is_ok()); 1010 /// ``` 1011 /// 1012 /// [`Result`]: std::result::Result 1013 pub type AssertResult = Result<Assert, AssertError>; 1014 1015 /// [`Assert`] error (see [`AssertResult`]). 1016 #[derive(Debug)] 1017 pub struct AssertError { 1018 assert: Assert, 1019 reason: AssertReason, 1020 } 1021 1022 #[derive(Debug)] 1023 enum AssertReason { 1024 UnexpectedFailure { actual_code: Option<i32> }, 1025 UnexpectedSuccess, 1026 UnexpectedCompletion, 1027 CommandInterrupted, 1028 UnexpectedReturnCode { case_tree: CaseTree }, 1029 UnexpectedStdout { case_tree: CaseTree }, 1030 UnexpectedStderr { case_tree: CaseTree }, 1031 } 1032 1033 impl AssertError { 1034 #[track_caller] panic<T>(self) -> T1035 fn panic<T>(self) -> T { 1036 panic!("{}", self) 1037 } 1038 } 1039 1040 impl Error for AssertError {} 1041 1042 impl fmt::Display for AssertError { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1043 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1044 match &self.reason { 1045 AssertReason::UnexpectedFailure { actual_code } => writeln!( 1046 f, 1047 "Unexpected failure.\ncode-{}\nstderr=```{}```", 1048 actual_code.map_or("<interrupted>".to_owned(), |actual_code| actual_code 1049 .to_string()), 1050 DebugBytes::new(&self.assert.output.stderr), 1051 ), 1052 AssertReason::UnexpectedSuccess => { 1053 writeln!(f, "Unexpected success") 1054 } 1055 AssertReason::UnexpectedCompletion => { 1056 writeln!(f, "Unexpected completion") 1057 } 1058 AssertReason::CommandInterrupted => { 1059 writeln!(f, "Command interrupted") 1060 } 1061 AssertReason::UnexpectedReturnCode { case_tree } => { 1062 writeln!(f, "Unexpected return code, failed {}", case_tree) 1063 } 1064 AssertReason::UnexpectedStdout { case_tree } => { 1065 writeln!(f, "Unexpected stdout, failed {}", case_tree) 1066 } 1067 AssertReason::UnexpectedStderr { case_tree } => { 1068 writeln!(f, "Unexpected stderr, failed {}", case_tree) 1069 } 1070 }?; 1071 write!(f, "{}", self.assert) 1072 } 1073 } 1074 1075 struct CaseTree(predicates_tree::CaseTree); 1076 1077 impl fmt::Display for CaseTree { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1078 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1079 <predicates_tree::CaseTree as fmt::Display>::fmt(&self.0, f) 1080 } 1081 } 1082 1083 // Work around `Debug` not being implemented for `predicates_tree::CaseTree`. 1084 impl fmt::Debug for CaseTree { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1085 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1086 <predicates_tree::CaseTree as fmt::Display>::fmt(&self.0, f) 1087 } 1088 } 1089 1090 #[cfg(test)] 1091 mod test { 1092 use super::*; 1093 1094 use predicates::prelude::*; 1095 1096 // Since IntoCodePredicate exists solely for conversion, test it under that scenario to ensure 1097 // it works as expected. convert_code<I, P>(pred: I) -> P where I: IntoCodePredicate<P>, P: predicates_core::Predicate<i32>,1098 fn convert_code<I, P>(pred: I) -> P 1099 where 1100 I: IntoCodePredicate<P>, 1101 P: predicates_core::Predicate<i32>, 1102 { 1103 pred.into_code() 1104 } 1105 1106 #[test] into_code_from_pred()1107 fn into_code_from_pred() { 1108 let pred = convert_code(predicate::eq(10)); 1109 assert!(pred.eval(&10)); 1110 } 1111 1112 #[test] into_code_from_i32()1113 fn into_code_from_i32() { 1114 let pred = convert_code(10); 1115 assert!(pred.eval(&10)); 1116 } 1117 1118 #[test] into_code_from_vec()1119 fn into_code_from_vec() { 1120 let pred = convert_code(vec![3, 10]); 1121 assert!(pred.eval(&10)); 1122 } 1123 1124 #[test] into_code_from_array()1125 fn into_code_from_array() { 1126 let pred = convert_code(&[3, 10] as &[i32]); 1127 assert!(pred.eval(&10)); 1128 } 1129 1130 // Since IntoOutputPredicate exists solely for conversion, test it under that scenario to ensure 1131 // it works as expected. convert_output<I, P>(pred: I) -> P where I: IntoOutputPredicate<P>, P: predicates_core::Predicate<[u8]>,1132 fn convert_output<I, P>(pred: I) -> P 1133 where 1134 I: IntoOutputPredicate<P>, 1135 P: predicates_core::Predicate<[u8]>, 1136 { 1137 pred.into_output() 1138 } 1139 1140 #[test] into_output_from_pred()1141 fn into_output_from_pred() { 1142 let pred = convert_output(predicate::eq(b"Hello" as &[u8])); 1143 assert!(pred.eval(b"Hello" as &[u8])); 1144 } 1145 1146 #[test] into_output_from_bytes()1147 fn into_output_from_bytes() { 1148 let pred = convert_output(b"Hello" as &[u8]); 1149 assert!(pred.eval(b"Hello" as &[u8])); 1150 } 1151 1152 #[test] into_output_from_vec()1153 fn into_output_from_vec() { 1154 let pred = convert_output(vec![b'H', b'e', b'l', b'l', b'o']); 1155 assert!(pred.eval(b"Hello" as &[u8])); 1156 } 1157 1158 #[test] into_output_from_str()1159 fn into_output_from_str() { 1160 let pred = convert_output("Hello"); 1161 assert!(pred.eval(b"Hello" as &[u8])); 1162 } 1163 } 1164