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 for &(ref name, ref context) in &self.context { 486 writeln!(f, "{}=`{}`", name, context)?; 487 } 488 output_fmt(&self.output, f) 489 } 490 } 491 492 impl fmt::Debug for Assert { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result493 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 494 f.debug_struct("Assert") 495 .field("output", &self.output) 496 .finish() 497 } 498 } 499 500 /// Used by [`Assert::code`] to convert `Self` into the needed 501 /// [`predicates_core::Predicate<i32>`]. 502 /// 503 /// # Examples 504 /// 505 /// ```rust,no_run 506 /// use assert_cmd::prelude::*; 507 /// 508 /// use std::process::Command; 509 /// use predicates::prelude::*; 510 /// 511 /// Command::cargo_bin("bin_fixture") 512 /// .unwrap() 513 /// .env("exit", "42") 514 /// .assert() 515 /// .code(predicate::eq(42)); 516 /// 517 /// // which can be shortened to: 518 /// Command::cargo_bin("bin_fixture") 519 /// .unwrap() 520 /// .env("exit", "42") 521 /// .assert() 522 /// .code(42); 523 /// ``` 524 pub trait IntoCodePredicate<P> 525 where 526 P: predicates_core::Predicate<i32>, 527 { 528 /// The type of the predicate being returned. 529 type Predicate; 530 531 /// Convert to a predicate for testing a program's exit code. into_code(self) -> P532 fn into_code(self) -> P; 533 } 534 535 impl<P> IntoCodePredicate<P> for P 536 where 537 P: predicates_core::Predicate<i32>, 538 { 539 type Predicate = P; 540 into_code(self) -> Self::Predicate541 fn into_code(self) -> Self::Predicate { 542 self 543 } 544 } 545 546 /// Keep `predicates` concrete Predicates out of our public API. 547 /// [predicates_core::Predicate] used by [`IntoCodePredicate`] for code. 548 /// 549 /// # Example 550 /// 551 /// ```rust,no_run 552 /// use assert_cmd::prelude::*; 553 /// 554 /// use std::process::Command; 555 /// 556 /// Command::cargo_bin("bin_fixture") 557 /// .unwrap() 558 /// .env("exit", "42") 559 /// .assert() 560 /// .code(42); 561 /// ``` 562 #[derive(Debug)] 563 pub struct EqCodePredicate(predicates::ord::EqPredicate<i32>); 564 565 impl EqCodePredicate { new(value: i32) -> Self566 pub(crate) fn new(value: i32) -> Self { 567 let pred = predicates::ord::eq(value); 568 EqCodePredicate(pred) 569 } 570 } 571 572 impl predicates_core::reflection::PredicateReflection for EqCodePredicate { parameters<'a>( &'a self, ) -> Box<dyn Iterator<Item = predicates_core::reflection::Parameter<'a>> + 'a>573 fn parameters<'a>( 574 &'a self, 575 ) -> Box<dyn Iterator<Item = predicates_core::reflection::Parameter<'a>> + 'a> { 576 self.0.parameters() 577 } 578 579 /// Nested `Predicate`s of the current `Predicate`. children<'a>( &'a self, ) -> Box<dyn Iterator<Item = predicates_core::reflection::Child<'a>> + 'a>580 fn children<'a>( 581 &'a self, 582 ) -> Box<dyn Iterator<Item = predicates_core::reflection::Child<'a>> + 'a> { 583 self.0.children() 584 } 585 } 586 587 impl predicates_core::Predicate<i32> for EqCodePredicate { eval(&self, item: &i32) -> bool588 fn eval(&self, item: &i32) -> bool { 589 self.0.eval(item) 590 } 591 find_case<'a>( &'a self, expected: bool, variable: &i32, ) -> Option<predicates_core::reflection::Case<'a>>592 fn find_case<'a>( 593 &'a self, 594 expected: bool, 595 variable: &i32, 596 ) -> Option<predicates_core::reflection::Case<'a>> { 597 self.0.find_case(expected, variable) 598 } 599 } 600 601 impl fmt::Display for EqCodePredicate { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result602 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 603 self.0.fmt(f) 604 } 605 } 606 607 impl IntoCodePredicate<EqCodePredicate> for i32 { 608 type Predicate = EqCodePredicate; 609 into_code(self) -> Self::Predicate610 fn into_code(self) -> Self::Predicate { 611 Self::Predicate::new(self) 612 } 613 } 614 615 /// Keep `predicates` concrete Predicates out of our public API. 616 /// [predicates_core::Predicate] used by [`IntoCodePredicate`] for iterables of codes. 617 /// 618 /// # Example 619 /// 620 /// ```rust,no_run 621 /// use assert_cmd::prelude::*; 622 /// 623 /// use std::process::Command; 624 /// 625 /// Command::cargo_bin("bin_fixture") 626 /// .unwrap() 627 /// .env("exit", "42") 628 /// .assert() 629 /// .code(&[2, 42] as &[i32]); 630 /// ``` 631 #[derive(Debug)] 632 pub struct InCodePredicate(predicates::iter::InPredicate<i32>); 633 634 impl InCodePredicate { new<I: IntoIterator<Item = i32>>(value: I) -> Self635 pub(crate) fn new<I: IntoIterator<Item = i32>>(value: I) -> Self { 636 let pred = predicates::iter::in_iter(value); 637 InCodePredicate(pred) 638 } 639 } 640 641 impl predicates_core::reflection::PredicateReflection for InCodePredicate { parameters<'a>( &'a self, ) -> Box<dyn Iterator<Item = predicates_core::reflection::Parameter<'a>> + 'a>642 fn parameters<'a>( 643 &'a self, 644 ) -> Box<dyn Iterator<Item = predicates_core::reflection::Parameter<'a>> + 'a> { 645 self.0.parameters() 646 } 647 648 /// Nested `Predicate`s of the current `Predicate`. children<'a>( &'a self, ) -> Box<dyn Iterator<Item = predicates_core::reflection::Child<'a>> + 'a>649 fn children<'a>( 650 &'a self, 651 ) -> Box<dyn Iterator<Item = predicates_core::reflection::Child<'a>> + 'a> { 652 self.0.children() 653 } 654 } 655 656 impl predicates_core::Predicate<i32> for InCodePredicate { eval(&self, item: &i32) -> bool657 fn eval(&self, item: &i32) -> bool { 658 self.0.eval(item) 659 } 660 find_case<'a>( &'a self, expected: bool, variable: &i32, ) -> Option<predicates_core::reflection::Case<'a>>661 fn find_case<'a>( 662 &'a self, 663 expected: bool, 664 variable: &i32, 665 ) -> Option<predicates_core::reflection::Case<'a>> { 666 self.0.find_case(expected, variable) 667 } 668 } 669 670 impl fmt::Display for InCodePredicate { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result671 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 672 self.0.fmt(f) 673 } 674 } 675 676 impl IntoCodePredicate<InCodePredicate> for Vec<i32> { 677 type Predicate = InCodePredicate; 678 into_code(self) -> Self::Predicate679 fn into_code(self) -> Self::Predicate { 680 Self::Predicate::new(self) 681 } 682 } 683 684 impl IntoCodePredicate<InCodePredicate> for &'static [i32] { 685 type Predicate = InCodePredicate; 686 into_code(self) -> Self::Predicate687 fn into_code(self) -> Self::Predicate { 688 Self::Predicate::new(self.iter().cloned()) 689 } 690 } 691 692 /// Used by [`Assert::stdout`] and [`Assert::stderr`] to convert Self 693 /// into the needed [`predicates_core::Predicate<[u8]>`]. 694 /// 695 /// # Examples 696 /// 697 /// ```rust,no_run 698 /// use assert_cmd::prelude::*; 699 /// 700 /// use std::process::Command; 701 /// use predicates::prelude::*; 702 /// 703 /// Command::cargo_bin("bin_fixture") 704 /// .unwrap() 705 /// .env("stdout", "hello") 706 /// .env("stderr", "world") 707 /// .assert() 708 /// .stdout(predicate::str::diff("hello\n").from_utf8()); 709 /// 710 /// // which can be shortened to: 711 /// Command::cargo_bin("bin_fixture") 712 /// .unwrap() 713 /// .env("stdout", "hello") 714 /// .env("stderr", "world") 715 /// .assert() 716 /// .stdout("hello\n"); 717 /// ``` 718 pub trait IntoOutputPredicate<P> 719 where 720 P: predicates_core::Predicate<[u8]>, 721 { 722 /// The type of the predicate being returned. 723 type Predicate; 724 725 /// Convert to a predicate for testing a path. into_output(self) -> P726 fn into_output(self) -> P; 727 } 728 729 impl<P> IntoOutputPredicate<P> for P 730 where 731 P: predicates_core::Predicate<[u8]>, 732 { 733 type Predicate = P; 734 into_output(self) -> Self::Predicate735 fn into_output(self) -> Self::Predicate { 736 self 737 } 738 } 739 740 /// Keep `predicates` concrete Predicates out of our public API. 741 /// [predicates_core::Predicate] used by [`IntoOutputPredicate`] for bytes. 742 /// 743 /// # Example 744 /// 745 /// ```rust,no_run 746 /// use assert_cmd::prelude::*; 747 /// 748 /// use std::process::Command; 749 /// 750 /// Command::cargo_bin("bin_fixture") 751 /// .unwrap() 752 /// .env("stdout", "hello") 753 /// .env("stderr", "world") 754 /// .assert() 755 /// .stderr(b"world\n" as &[u8]); 756 /// ``` 757 #[derive(Debug)] 758 pub struct BytesContentOutputPredicate(Cow<'static, [u8]>); 759 760 impl BytesContentOutputPredicate { new(value: &'static [u8]) -> Self761 pub(crate) fn new(value: &'static [u8]) -> Self { 762 BytesContentOutputPredicate(Cow::from(value)) 763 } 764 from_vec(value: Vec<u8>) -> Self765 pub(crate) fn from_vec(value: Vec<u8>) -> Self { 766 BytesContentOutputPredicate(Cow::from(value)) 767 } 768 } 769 770 impl predicates_core::reflection::PredicateReflection for BytesContentOutputPredicate {} 771 772 impl predicates_core::Predicate<[u8]> for BytesContentOutputPredicate { eval(&self, item: &[u8]) -> bool773 fn eval(&self, item: &[u8]) -> bool { 774 self.0.as_ref() == item 775 } 776 find_case( &self, expected: bool, variable: &[u8], ) -> Option<predicates_core::reflection::Case>777 fn find_case( 778 &self, 779 expected: bool, 780 variable: &[u8], 781 ) -> Option<predicates_core::reflection::Case> { 782 let actual = self.eval(variable); 783 if expected == actual { 784 Some(predicates_core::reflection::Case::new(Some(self), actual)) 785 } else { 786 None 787 } 788 } 789 } 790 791 impl fmt::Display for BytesContentOutputPredicate { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result792 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 793 predicates::ord::eq(self.0.as_ref()).fmt(f) 794 } 795 } 796 797 impl IntoOutputPredicate<BytesContentOutputPredicate> for Vec<u8> { 798 type Predicate = BytesContentOutputPredicate; 799 into_output(self) -> Self::Predicate800 fn into_output(self) -> Self::Predicate { 801 Self::Predicate::from_vec(self) 802 } 803 } 804 805 impl IntoOutputPredicate<BytesContentOutputPredicate> for &'static [u8] { 806 type Predicate = BytesContentOutputPredicate; 807 into_output(self) -> Self::Predicate808 fn into_output(self) -> Self::Predicate { 809 Self::Predicate::new(self) 810 } 811 } 812 813 /// Keep `predicates` concrete Predicates out of our public API. 814 /// [predicates_core::Predicate] used by [`IntoOutputPredicate`] for [`str`]. 815 /// 816 /// # Example 817 /// 818 /// ```rust,no_run 819 /// use assert_cmd::prelude::*; 820 /// 821 /// use std::process::Command; 822 /// 823 /// Command::cargo_bin("bin_fixture") 824 /// .unwrap() 825 /// .env("stdout", "hello") 826 /// .env("stderr", "world") 827 /// .assert() 828 /// .stderr("world\n"); 829 /// ``` 830 /// 831 /// [`str`]: https://doc.rust-lang.org/std/primitive.str.html 832 #[derive(Debug, Clone)] 833 pub struct StrContentOutputPredicate( 834 predicates::str::Utf8Predicate<predicates::str::DifferencePredicate>, 835 ); 836 837 impl StrContentOutputPredicate { from_str(value: &'static str) -> Self838 pub(crate) fn from_str(value: &'static str) -> Self { 839 let pred = predicates::str::diff(value).from_utf8(); 840 StrContentOutputPredicate(pred) 841 } 842 from_string(value: String) -> Self843 pub(crate) fn from_string(value: String) -> Self { 844 let pred = predicates::str::diff(value).from_utf8(); 845 StrContentOutputPredicate(pred) 846 } 847 } 848 849 impl predicates_core::reflection::PredicateReflection for StrContentOutputPredicate { parameters<'a>( &'a self, ) -> Box<dyn Iterator<Item = predicates_core::reflection::Parameter<'a>> + 'a>850 fn parameters<'a>( 851 &'a self, 852 ) -> Box<dyn Iterator<Item = predicates_core::reflection::Parameter<'a>> + 'a> { 853 self.0.parameters() 854 } 855 856 /// Nested `Predicate`s of the current `Predicate`. children<'a>( &'a self, ) -> Box<dyn Iterator<Item = predicates_core::reflection::Child<'a>> + 'a>857 fn children<'a>( 858 &'a self, 859 ) -> Box<dyn Iterator<Item = predicates_core::reflection::Child<'a>> + 'a> { 860 self.0.children() 861 } 862 } 863 864 impl predicates_core::Predicate<[u8]> for StrContentOutputPredicate { eval(&self, item: &[u8]) -> bool865 fn eval(&self, item: &[u8]) -> bool { 866 self.0.eval(item) 867 } 868 find_case<'a>( &'a self, expected: bool, variable: &[u8], ) -> Option<predicates_core::reflection::Case<'a>>869 fn find_case<'a>( 870 &'a self, 871 expected: bool, 872 variable: &[u8], 873 ) -> Option<predicates_core::reflection::Case<'a>> { 874 self.0.find_case(expected, variable) 875 } 876 } 877 878 impl fmt::Display for StrContentOutputPredicate { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result879 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 880 self.0.fmt(f) 881 } 882 } 883 884 impl IntoOutputPredicate<StrContentOutputPredicate> for String { 885 type Predicate = StrContentOutputPredicate; 886 into_output(self) -> Self::Predicate887 fn into_output(self) -> Self::Predicate { 888 Self::Predicate::from_string(self) 889 } 890 } 891 892 impl IntoOutputPredicate<StrContentOutputPredicate> for &'static str { 893 type Predicate = StrContentOutputPredicate; 894 into_output(self) -> Self::Predicate895 fn into_output(self) -> Self::Predicate { 896 Self::Predicate::from_str(self) 897 } 898 } 899 900 // Keep `predicates` concrete Predicates out of our public API. 901 /// [predicates_core::Predicate] used by [`IntoOutputPredicate`] for 902 /// [`Predicate<str>`][predicates_core::Predicate]. 903 /// 904 /// # Example 905 /// 906 /// ```rust,no_run 907 /// use assert_cmd::prelude::*; 908 /// 909 /// use std::process::Command; 910 /// use predicates::prelude::*; 911 /// 912 /// Command::cargo_bin("bin_fixture") 913 /// .unwrap() 914 /// .env("stdout", "hello") 915 /// .env("stderr", "world") 916 /// .assert() 917 /// .stderr(predicate::str::diff("world\n")); 918 /// ``` 919 #[derive(Debug, Clone)] 920 pub struct StrOutputPredicate<P: predicates_core::Predicate<str>>( 921 predicates::str::Utf8Predicate<P>, 922 ); 923 924 impl<P> StrOutputPredicate<P> 925 where 926 P: predicates_core::Predicate<str>, 927 { new(pred: P) -> Self928 pub(crate) fn new(pred: P) -> Self { 929 let pred = pred.from_utf8(); 930 StrOutputPredicate(pred) 931 } 932 } 933 934 impl<P> predicates_core::reflection::PredicateReflection for StrOutputPredicate<P> 935 where 936 P: predicates_core::Predicate<str>, 937 { parameters<'a>( &'a self, ) -> Box<dyn Iterator<Item = predicates_core::reflection::Parameter<'a>> + 'a>938 fn parameters<'a>( 939 &'a self, 940 ) -> Box<dyn Iterator<Item = predicates_core::reflection::Parameter<'a>> + 'a> { 941 self.0.parameters() 942 } 943 944 /// Nested `Predicate`s of the current `Predicate`. children<'a>( &'a self, ) -> Box<dyn Iterator<Item = predicates_core::reflection::Child<'a>> + 'a>945 fn children<'a>( 946 &'a self, 947 ) -> Box<dyn Iterator<Item = predicates_core::reflection::Child<'a>> + 'a> { 948 self.0.children() 949 } 950 } 951 952 impl<P> predicates_core::Predicate<[u8]> for StrOutputPredicate<P> 953 where 954 P: predicates_core::Predicate<str>, 955 { eval(&self, item: &[u8]) -> bool956 fn eval(&self, item: &[u8]) -> bool { 957 self.0.eval(item) 958 } 959 find_case<'a>( &'a self, expected: bool, variable: &[u8], ) -> Option<predicates_core::reflection::Case<'a>>960 fn find_case<'a>( 961 &'a self, 962 expected: bool, 963 variable: &[u8], 964 ) -> Option<predicates_core::reflection::Case<'a>> { 965 self.0.find_case(expected, variable) 966 } 967 } 968 969 impl<P> fmt::Display for StrOutputPredicate<P> 970 where 971 P: predicates_core::Predicate<str>, 972 { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result973 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 974 self.0.fmt(f) 975 } 976 } 977 978 impl<P> IntoOutputPredicate<StrOutputPredicate<P>> for P 979 where 980 P: predicates_core::Predicate<str>, 981 { 982 type Predicate = StrOutputPredicate<P>; 983 into_output(self) -> Self::Predicate984 fn into_output(self) -> Self::Predicate { 985 Self::Predicate::new(self) 986 } 987 } 988 989 /// [`Assert`] represented as a [`Result`]. 990 /// 991 /// Produced by the `try_` variants the [`Assert`] methods. 992 /// 993 /// # Example 994 /// 995 /// ```rust 996 /// use assert_cmd::prelude::*; 997 /// 998 /// use std::process::Command; 999 /// 1000 /// let result = Command::new("echo") 1001 /// .assert() 1002 /// .try_success(); 1003 /// assert!(result.is_ok()); 1004 /// ``` 1005 /// 1006 /// [`Result`]: std::result::Result 1007 pub type AssertResult = Result<Assert, AssertError>; 1008 1009 /// [`Assert`] error (see [`AssertResult`]). 1010 #[derive(Debug)] 1011 pub struct AssertError { 1012 assert: Assert, 1013 reason: AssertReason, 1014 } 1015 1016 #[derive(Debug)] 1017 enum AssertReason { 1018 UnexpectedFailure { actual_code: Option<i32> }, 1019 UnexpectedSuccess, 1020 UnexpectedCompletion, 1021 CommandInterrupted, 1022 UnexpectedReturnCode { case_tree: CaseTree }, 1023 UnexpectedStdout { case_tree: CaseTree }, 1024 UnexpectedStderr { case_tree: CaseTree }, 1025 } 1026 1027 impl AssertError { 1028 #[track_caller] panic<T>(self) -> T1029 fn panic<T>(self) -> T { 1030 panic!("{}", self) 1031 } 1032 } 1033 1034 impl Error for AssertError {} 1035 1036 impl fmt::Display for AssertError { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1037 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1038 match &self.reason { 1039 AssertReason::UnexpectedFailure { actual_code } => writeln!( 1040 f, 1041 "Unexpected failure.\ncode-{}\nstderr=```{}```", 1042 actual_code.map_or("<interrupted>".to_owned(), |actual_code| actual_code 1043 .to_string()), 1044 DebugBytes::new(&self.assert.output.stderr), 1045 ), 1046 AssertReason::UnexpectedSuccess => { 1047 writeln!(f, "Unexpected success") 1048 } 1049 AssertReason::UnexpectedCompletion => { 1050 writeln!(f, "Unexpected completion") 1051 } 1052 AssertReason::CommandInterrupted => { 1053 writeln!(f, "Command interrupted") 1054 } 1055 AssertReason::UnexpectedReturnCode { case_tree } => { 1056 writeln!(f, "Unexpected return code, failed {}", case_tree) 1057 } 1058 AssertReason::UnexpectedStdout { case_tree } => { 1059 writeln!(f, "Unexpected stdout, failed {}", case_tree) 1060 } 1061 AssertReason::UnexpectedStderr { case_tree } => { 1062 writeln!(f, "Unexpected stderr, failed {}", case_tree) 1063 } 1064 }?; 1065 write!(f, "{}", self.assert) 1066 } 1067 } 1068 1069 struct CaseTree(predicates_tree::CaseTree); 1070 1071 impl fmt::Display for CaseTree { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1072 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1073 <predicates_tree::CaseTree as fmt::Display>::fmt(&self.0, f) 1074 } 1075 } 1076 1077 // Work around `Debug` not being implemented for `predicates_tree::CaseTree`. 1078 impl fmt::Debug for CaseTree { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1079 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1080 <predicates_tree::CaseTree as fmt::Display>::fmt(&self.0, f) 1081 } 1082 } 1083 1084 #[cfg(test)] 1085 mod test { 1086 use super::*; 1087 1088 use predicates::prelude::*; 1089 1090 // Since IntoCodePredicate exists solely for conversion, test it under that scenario to ensure 1091 // it works as expected. convert_code<I, P>(pred: I) -> P where I: IntoCodePredicate<P>, P: predicates_core::Predicate<i32>,1092 fn convert_code<I, P>(pred: I) -> P 1093 where 1094 I: IntoCodePredicate<P>, 1095 P: predicates_core::Predicate<i32>, 1096 { 1097 pred.into_code() 1098 } 1099 1100 #[test] into_code_from_pred()1101 fn into_code_from_pred() { 1102 let pred = convert_code(predicate::eq(10)); 1103 assert!(pred.eval(&10)); 1104 } 1105 1106 #[test] into_code_from_i32()1107 fn into_code_from_i32() { 1108 let pred = convert_code(10); 1109 assert!(pred.eval(&10)); 1110 } 1111 1112 #[test] into_code_from_vec()1113 fn into_code_from_vec() { 1114 let pred = convert_code(vec![3, 10]); 1115 assert!(pred.eval(&10)); 1116 } 1117 1118 #[test] into_code_from_array()1119 fn into_code_from_array() { 1120 let pred = convert_code(&[3, 10] as &[i32]); 1121 assert!(pred.eval(&10)); 1122 } 1123 1124 // Since IntoOutputPredicate exists solely for conversion, test it under that scenario to ensure 1125 // it works as expected. convert_output<I, P>(pred: I) -> P where I: IntoOutputPredicate<P>, P: predicates_core::Predicate<[u8]>,1126 fn convert_output<I, P>(pred: I) -> P 1127 where 1128 I: IntoOutputPredicate<P>, 1129 P: predicates_core::Predicate<[u8]>, 1130 { 1131 pred.into_output() 1132 } 1133 1134 #[test] into_output_from_pred()1135 fn into_output_from_pred() { 1136 let pred = convert_output(predicate::eq(b"Hello" as &[u8])); 1137 assert!(pred.eval(b"Hello" as &[u8])); 1138 } 1139 1140 #[test] into_output_from_bytes()1141 fn into_output_from_bytes() { 1142 let pred = convert_output(b"Hello" as &[u8]); 1143 assert!(pred.eval(b"Hello" as &[u8])); 1144 } 1145 1146 #[test] into_output_from_vec()1147 fn into_output_from_vec() { 1148 let pred = convert_output(vec![b'H', b'e', b'l', b'l', b'o']); 1149 assert!(pred.eval(b"Hello" as &[u8])); 1150 } 1151 1152 #[test] into_output_from_str()1153 fn into_output_from_str() { 1154 let pred = convert_output("Hello"); 1155 assert!(pred.eval(b"Hello" as &[u8])); 1156 } 1157 } 1158