1 //! [`Output`][Output] assertions. 2 //! 3 //! [Output]: https://doc.rust-lang.org/std/process/struct.Output.html 4 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::dump_buffer; 13 use crate::output::output_fmt; 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`]: https://doc.rust-lang.org/std/process/struct.Output.html 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`]: https://doc.rust-lang.org/std/process/struct.Output.html 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 = self.output().unwrap(); 60 Assert::new(output).append_context("command", format!("{:?}", self)) 61 } 62 } 63 64 /// Assert the state of an [`Output`]. 65 /// 66 /// Create an `Assert` through the [`OutputAssertExt`] trait. 67 /// 68 /// # Examples 69 /// 70 /// ```rust,no_run 71 /// use assert_cmd::prelude::*; 72 /// 73 /// use std::process::Command; 74 /// 75 /// let mut cmd = Command::cargo_bin("bin_fixture") 76 /// .unwrap(); 77 /// cmd.assert() 78 /// .success(); 79 /// ``` 80 /// 81 /// [`Output`]: https://doc.rust-lang.org/std/process/struct.Output.html 82 /// [`OutputAssertExt`]: trait.OutputAssertExt.html 83 pub struct Assert { 84 output: process::Output, 85 context: Vec<(&'static str, Box<dyn fmt::Display>)>, 86 } 87 88 impl Assert { 89 /// Create an `Assert` for a given [`Output`]. 90 /// 91 /// [`Output`]: https://doc.rust-lang.org/std/process/struct.Output.html new(output: process::Output) -> Self92 pub fn new(output: process::Output) -> Self { 93 Self { 94 output, 95 context: vec![], 96 } 97 } 98 99 /// Clarify failures with additional context. 100 /// 101 /// # Examples 102 /// 103 /// ```rust,no_run 104 /// use assert_cmd::prelude::*; 105 /// 106 /// use std::process::Command; 107 /// 108 /// Command::cargo_bin("bin_fixture") 109 /// .unwrap() 110 /// .assert() 111 /// .append_context("main", "no args") 112 /// .success(); 113 /// ``` append_context<D>(mut self, name: &'static str, context: D) -> Self where D: fmt::Display + 'static,114 pub fn append_context<D>(mut self, name: &'static str, context: D) -> Self 115 where 116 D: fmt::Display + 'static, 117 { 118 self.context.push((name, Box::new(context))); 119 self 120 } 121 122 /// Access the contained [`Output`]. 123 /// 124 /// [`Output`]: https://doc.rust-lang.org/std/process/struct.Output.html get_output(&self) -> &process::Output125 pub fn get_output(&self) -> &process::Output { 126 &self.output 127 } 128 129 /// Ensure the command succeeded. 130 /// 131 /// # Examples 132 /// 133 /// ```rust,no_run 134 /// use assert_cmd::prelude::*; 135 /// 136 /// use std::process::Command; 137 /// 138 /// Command::cargo_bin("bin_fixture") 139 /// .unwrap() 140 /// .assert() 141 /// .success(); 142 /// ``` success(self) -> Self143 pub fn success(self) -> Self { 144 if !self.output.status.success() { 145 let actual_code = self.output.status.code().unwrap_or_else(|| { 146 panic!( 147 "Unexpected failure.\ncode=<interrupted>\nstderr=```{}```\n{}", 148 dump_buffer(&self.output.stderr), 149 self 150 ) 151 }); 152 panic!( 153 "Unexpected failure.\ncode-{}\nstderr=```{}```\n{}", 154 actual_code, 155 dump_buffer(&self.output.stderr), 156 self 157 ); 158 } 159 self 160 } 161 162 /// Ensure the command failed. 163 /// 164 /// # Examples 165 /// 166 /// ```rust,no_run 167 /// use assert_cmd::prelude::*; 168 /// 169 /// use std::process::Command; 170 /// 171 /// Command::cargo_bin("bin_fixture") 172 /// .unwrap() 173 /// .env("exit", "1") 174 /// .assert() 175 /// .failure(); 176 /// ``` failure(self) -> Self177 pub fn failure(self) -> Self { 178 if self.output.status.success() { 179 panic!("Unexpected success\n{}", self); 180 } 181 self 182 } 183 184 /// Ensure the command aborted before returning a code. interrupted(self) -> Self185 pub fn interrupted(self) -> Self { 186 if self.output.status.code().is_some() { 187 panic!("Unexpected completion\n{}", self); 188 } 189 self 190 } 191 192 /// Ensure the command returned the expected code. 193 /// 194 /// This uses [`IntoCodePredicate`] to provide short-hands for common cases. 195 /// 196 /// See [`predicates`] for more predicates. 197 /// 198 /// # Examples 199 /// 200 /// Accepting a predicate: 201 /// ```rust,no_run 202 /// use assert_cmd::prelude::*; 203 /// 204 /// use std::process::Command; 205 /// use predicates::prelude::*; 206 /// 207 /// Command::cargo_bin("bin_fixture") 208 /// .unwrap() 209 /// .env("exit", "42") 210 /// .assert() 211 /// .code(predicate::eq(42)); 212 /// ``` 213 /// 214 /// Accepting an exit code: 215 /// ```rust,no_run 216 /// use assert_cmd::prelude::*; 217 /// 218 /// use std::process::Command; 219 /// 220 /// Command::cargo_bin("bin_fixture") 221 /// .unwrap() 222 /// .env("exit", "42") 223 /// .assert() 224 /// .code(42); 225 /// ``` 226 /// 227 /// Accepting multiple exit codes: 228 /// ```rust,no_run 229 /// use assert_cmd::prelude::*; 230 /// 231 /// use std::process::Command; 232 /// 233 /// Command::cargo_bin("bin_fixture") 234 /// .unwrap() 235 /// .env("exit", "42") 236 /// .assert() 237 /// .code(&[2, 42] as &[i32]); 238 /// ``` 239 /// 240 /// [`predicates`]: https://docs.rs/predicates 241 /// [`IntoCodePredicate`]: trait.IntoCodePredicate.html code<I, P>(self, pred: I) -> Self where I: IntoCodePredicate<P>, P: predicates_core::Predicate<i32>,242 pub fn code<I, P>(self, pred: I) -> Self 243 where 244 I: IntoCodePredicate<P>, 245 P: predicates_core::Predicate<i32>, 246 { 247 self.code_impl(&pred.into_code()) 248 } 249 code_impl(self, pred: &dyn predicates_core::Predicate<i32>) -> Self250 fn code_impl(self, pred: &dyn predicates_core::Predicate<i32>) -> Self { 251 let actual_code = self 252 .output 253 .status 254 .code() 255 .unwrap_or_else(|| panic!("Command interrupted\n{}", self)); 256 if let Some(case) = pred.find_case(false, &actual_code) { 257 panic!("Unexpected return code, failed {}\n{}", case.tree(), self); 258 } 259 self 260 } 261 262 /// Ensure the command wrote the expected data to `stdout`. 263 /// 264 /// This uses [`IntoOutputPredicate`] to provide short-hands for common cases. 265 /// 266 /// See [`predicates`] for more predicates. 267 /// 268 /// # Examples 269 /// 270 /// Accepting a bytes predicate: 271 /// ```rust,no_run 272 /// use assert_cmd::prelude::*; 273 /// 274 /// use std::process::Command; 275 /// use predicates::prelude::*; 276 /// 277 /// Command::cargo_bin("bin_fixture") 278 /// .unwrap() 279 /// .env("stdout", "hello") 280 /// .env("stderr", "world") 281 /// .assert() 282 /// .stdout(predicate::eq(b"hello\n" as &[u8])); 283 /// ``` 284 /// 285 /// Accepting a `str` predicate: 286 /// ```rust,no_run 287 /// use assert_cmd::prelude::*; 288 /// 289 /// use std::process::Command; 290 /// use predicates::prelude::*; 291 /// 292 /// Command::cargo_bin("bin_fixture") 293 /// .unwrap() 294 /// .env("stdout", "hello") 295 /// .env("stderr", "world") 296 /// .assert() 297 /// .stdout(predicate::str::similar("hello\n")); 298 /// ``` 299 /// 300 /// Accepting bytes: 301 /// ```rust,no_run 302 /// use assert_cmd::prelude::*; 303 /// 304 /// use std::process::Command; 305 /// 306 /// Command::cargo_bin("bin_fixture") 307 /// .unwrap() 308 /// .env("stdout", "hello") 309 /// .env("stderr", "world") 310 /// .assert() 311 /// .stdout(b"hello\n" as &[u8]); 312 /// ``` 313 /// 314 /// Accepting a `str`: 315 /// ```rust,no_run 316 /// use assert_cmd::prelude::*; 317 /// 318 /// use std::process::Command; 319 /// 320 /// Command::cargo_bin("bin_fixture") 321 /// .unwrap() 322 /// .env("stdout", "hello") 323 /// .env("stderr", "world") 324 /// .assert() 325 /// .stdout("hello\n"); 326 /// ``` 327 /// 328 /// [`predicates`]: https://docs.rs/predicates 329 /// [`IntoOutputPredicate`]: trait.IntoOutputPredicate.html stdout<I, P>(self, pred: I) -> Self where I: IntoOutputPredicate<P>, P: predicates_core::Predicate<[u8]>,330 pub fn stdout<I, P>(self, pred: I) -> Self 331 where 332 I: IntoOutputPredicate<P>, 333 P: predicates_core::Predicate<[u8]>, 334 { 335 self.stdout_impl(&pred.into_output()) 336 } 337 stdout_impl(self, pred: &dyn predicates_core::Predicate<[u8]>) -> Self338 fn stdout_impl(self, pred: &dyn predicates_core::Predicate<[u8]>) -> Self { 339 { 340 let actual = &self.output.stdout; 341 if let Some(case) = pred.find_case(false, &actual) { 342 panic!("Unexpected stdout, failed {}\n{}", case.tree(), self); 343 } 344 } 345 self 346 } 347 348 /// Ensure the command wrote the expected data to `stderr`. 349 /// 350 /// This uses [`IntoOutputPredicate`] to provide short-hands for common cases. 351 /// 352 /// See [`predicates`] for more predicates. 353 /// 354 /// # Examples 355 /// 356 /// Accepting a bytes predicate: 357 /// ```rust,no_run 358 /// use assert_cmd::prelude::*; 359 /// 360 /// use std::process::Command; 361 /// use predicates::prelude::*; 362 /// 363 /// Command::cargo_bin("bin_fixture") 364 /// .unwrap() 365 /// .env("stdout", "hello") 366 /// .env("stderr", "world") 367 /// .assert() 368 /// .stderr(predicate::eq(b"world\n" as &[u8])); 369 /// ``` 370 /// 371 /// Accepting a `str` predicate: 372 /// ```rust,no_run 373 /// use assert_cmd::prelude::*; 374 /// 375 /// use std::process::Command; 376 /// use predicates::prelude::*; 377 /// 378 /// Command::cargo_bin("bin_fixture") 379 /// .unwrap() 380 /// .env("stdout", "hello") 381 /// .env("stderr", "world") 382 /// .assert() 383 /// .stderr(predicate::str::similar("world\n")); 384 /// ``` 385 /// 386 /// Accepting bytes: 387 /// ```rust,no_run 388 /// use assert_cmd::prelude::*; 389 /// 390 /// use std::process::Command; 391 /// 392 /// Command::cargo_bin("bin_fixture") 393 /// .unwrap() 394 /// .env("stdout", "hello") 395 /// .env("stderr", "world") 396 /// .assert() 397 /// .stderr(b"world\n" as &[u8]); 398 /// ``` 399 /// 400 /// Accepting a `str`: 401 /// ```rust,no_run 402 /// use assert_cmd::prelude::*; 403 /// 404 /// use std::process::Command; 405 /// 406 /// Command::cargo_bin("bin_fixture") 407 /// .unwrap() 408 /// .env("stdout", "hello") 409 /// .env("stderr", "world") 410 /// .assert() 411 /// .stderr("world\n"); 412 /// ``` 413 /// 414 /// [`predicates`]: https://docs.rs/predicates 415 /// [`IntoOutputPredicate`]: trait.IntoOutputPredicate.html stderr<I, P>(self, pred: I) -> Self where I: IntoOutputPredicate<P>, P: predicates_core::Predicate<[u8]>,416 pub fn stderr<I, P>(self, pred: I) -> Self 417 where 418 I: IntoOutputPredicate<P>, 419 P: predicates_core::Predicate<[u8]>, 420 { 421 self.stderr_impl(&pred.into_output()) 422 } 423 stderr_impl(self, pred: &dyn predicates_core::Predicate<[u8]>) -> Self424 fn stderr_impl(self, pred: &dyn predicates_core::Predicate<[u8]>) -> Self { 425 { 426 let actual = &self.output.stderr; 427 if let Some(case) = pred.find_case(false, &actual) { 428 panic!("Unexpected stderr, failed {}\n\n{}", case.tree(), self); 429 } 430 } 431 self 432 } 433 } 434 435 impl fmt::Display for Assert { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result436 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 437 for &(ref name, ref context) in &self.context { 438 writeln!(f, "{}=`{}`", name, context)?; 439 } 440 output_fmt(&self.output, f) 441 } 442 } 443 444 impl fmt::Debug for Assert { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result445 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 446 f.debug_struct("Assert") 447 .field("output", &self.output) 448 .finish() 449 } 450 } 451 452 /// Used by [`Assert::code`] to convert `Self` into the needed 453 /// [`Predicate<i32>`]. 454 /// 455 /// # Examples 456 /// 457 /// ```rust,no_run 458 /// use assert_cmd::prelude::*; 459 /// 460 /// use std::process::Command; 461 /// use predicates::prelude::*; 462 /// 463 /// Command::cargo_bin("bin_fixture") 464 /// .unwrap() 465 /// .env("exit", "42") 466 /// .assert() 467 /// .code(predicate::eq(42)); 468 /// 469 /// // which can be shortened to: 470 /// Command::cargo_bin("bin_fixture") 471 /// .unwrap() 472 /// .env("exit", "42") 473 /// .assert() 474 /// .code(42); 475 /// ``` 476 /// 477 /// [`Assert::code`]: struct.Assert.html#method.code 478 /// [`Predicate<i32>`]: https://docs.rs/predicates-core/1.0.0/predicates_core/trait.Predicate.html 479 pub trait IntoCodePredicate<P> 480 where 481 P: predicates_core::Predicate<i32>, 482 { 483 /// The type of the predicate being returned. 484 type Predicate; 485 486 /// Convert to a predicate for testing a program's exit code. into_code(self) -> P487 fn into_code(self) -> P; 488 } 489 490 impl<P> IntoCodePredicate<P> for P 491 where 492 P: predicates_core::Predicate<i32>, 493 { 494 type Predicate = P; 495 into_code(self) -> Self::Predicate496 fn into_code(self) -> Self::Predicate { 497 self 498 } 499 } 500 501 // Keep `predicates` concrete Predicates out of our public API. 502 /// [Predicate] used by [`IntoCodePredicate`] for code. 503 /// 504 /// # Example 505 /// 506 /// ```rust,no_run 507 /// use assert_cmd::prelude::*; 508 /// 509 /// use std::process::Command; 510 /// 511 /// Command::cargo_bin("bin_fixture") 512 /// .unwrap() 513 /// .env("exit", "42") 514 /// .assert() 515 /// .code(42); 516 /// ``` 517 /// 518 /// [`IntoCodePredicate`]: trait.IntoCodePredicate.html 519 /// [Predicate]: https://docs.rs/predicates-core/1.0.0/predicates_core/trait.Predicate.html 520 #[derive(Debug)] 521 pub struct EqCodePredicate(predicates::ord::EqPredicate<i32>); 522 523 impl EqCodePredicate { new(value: i32) -> Self524 pub(crate) fn new(value: i32) -> Self { 525 let pred = predicates::ord::eq(value); 526 EqCodePredicate(pred) 527 } 528 } 529 530 impl predicates_core::reflection::PredicateReflection for EqCodePredicate { parameters<'a>( &'a self, ) -> Box<dyn Iterator<Item = predicates_core::reflection::Parameter<'a>> + 'a>531 fn parameters<'a>( 532 &'a self, 533 ) -> Box<dyn Iterator<Item = predicates_core::reflection::Parameter<'a>> + 'a> { 534 self.0.parameters() 535 } 536 537 /// Nested `Predicate`s of the current `Predicate`. children<'a>( &'a self, ) -> Box<dyn Iterator<Item = predicates_core::reflection::Child<'a>> + 'a>538 fn children<'a>( 539 &'a self, 540 ) -> Box<dyn Iterator<Item = predicates_core::reflection::Child<'a>> + 'a> { 541 self.0.children() 542 } 543 } 544 545 impl predicates_core::Predicate<i32> for EqCodePredicate { eval(&self, item: &i32) -> bool546 fn eval(&self, item: &i32) -> bool { 547 self.0.eval(item) 548 } 549 find_case<'a>( &'a self, expected: bool, variable: &i32, ) -> Option<predicates_core::reflection::Case<'a>>550 fn find_case<'a>( 551 &'a self, 552 expected: bool, 553 variable: &i32, 554 ) -> Option<predicates_core::reflection::Case<'a>> { 555 self.0.find_case(expected, variable) 556 } 557 } 558 559 impl fmt::Display for EqCodePredicate { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result560 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 561 self.0.fmt(f) 562 } 563 } 564 565 impl IntoCodePredicate<EqCodePredicate> for i32 { 566 type Predicate = EqCodePredicate; 567 into_code(self) -> Self::Predicate568 fn into_code(self) -> Self::Predicate { 569 Self::Predicate::new(self) 570 } 571 } 572 573 // Keep `predicates` concrete Predicates out of our public API. 574 /// [Predicate] used by [`IntoCodePredicate`] for iterables of codes. 575 /// 576 /// # Example 577 /// 578 /// ```rust,no_run 579 /// use assert_cmd::prelude::*; 580 /// 581 /// use std::process::Command; 582 /// 583 /// Command::cargo_bin("bin_fixture") 584 /// .unwrap() 585 /// .env("exit", "42") 586 /// .assert() 587 /// .code(&[2, 42] as &[i32]); 588 /// ``` 589 /// 590 /// [`IntoCodePredicate`]: trait.IntoCodePredicate.html 591 /// [Predicate]: https://docs.rs/predicates-core/1.0.0/predicates_core/trait.Predicate.html 592 #[derive(Debug)] 593 pub struct InCodePredicate(predicates::iter::InPredicate<i32>); 594 595 impl InCodePredicate { new<I: IntoIterator<Item = i32>>(value: I) -> Self596 pub(crate) fn new<I: IntoIterator<Item = i32>>(value: I) -> Self { 597 let pred = predicates::iter::in_iter(value); 598 InCodePredicate(pred) 599 } 600 } 601 602 impl predicates_core::reflection::PredicateReflection for InCodePredicate { parameters<'a>( &'a self, ) -> Box<dyn Iterator<Item = predicates_core::reflection::Parameter<'a>> + 'a>603 fn parameters<'a>( 604 &'a self, 605 ) -> Box<dyn Iterator<Item = predicates_core::reflection::Parameter<'a>> + 'a> { 606 self.0.parameters() 607 } 608 609 /// Nested `Predicate`s of the current `Predicate`. children<'a>( &'a self, ) -> Box<dyn Iterator<Item = predicates_core::reflection::Child<'a>> + 'a>610 fn children<'a>( 611 &'a self, 612 ) -> Box<dyn Iterator<Item = predicates_core::reflection::Child<'a>> + 'a> { 613 self.0.children() 614 } 615 } 616 617 impl predicates_core::Predicate<i32> for InCodePredicate { eval(&self, item: &i32) -> bool618 fn eval(&self, item: &i32) -> bool { 619 self.0.eval(item) 620 } 621 find_case<'a>( &'a self, expected: bool, variable: &i32, ) -> Option<predicates_core::reflection::Case<'a>>622 fn find_case<'a>( 623 &'a self, 624 expected: bool, 625 variable: &i32, 626 ) -> Option<predicates_core::reflection::Case<'a>> { 627 self.0.find_case(expected, variable) 628 } 629 } 630 631 impl fmt::Display for InCodePredicate { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result632 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 633 self.0.fmt(f) 634 } 635 } 636 637 impl IntoCodePredicate<InCodePredicate> for Vec<i32> { 638 type Predicate = InCodePredicate; 639 into_code(self) -> Self::Predicate640 fn into_code(self) -> Self::Predicate { 641 Self::Predicate::new(self) 642 } 643 } 644 645 impl IntoCodePredicate<InCodePredicate> for &'static [i32] { 646 type Predicate = InCodePredicate; 647 into_code(self) -> Self::Predicate648 fn into_code(self) -> Self::Predicate { 649 Self::Predicate::new(self.iter().cloned()) 650 } 651 } 652 653 /// Used by [`Assert::stdout`] and [`Assert::stderr`] to convert Self 654 /// into the needed [`Predicate<[u8]>`]. 655 /// 656 /// # Examples 657 /// 658 /// ```rust,no_run 659 /// use assert_cmd::prelude::*; 660 /// 661 /// use std::process::Command; 662 /// use predicates::prelude::*; 663 /// 664 /// Command::cargo_bin("bin_fixture") 665 /// .unwrap() 666 /// .env("stdout", "hello") 667 /// .env("stderr", "world") 668 /// .assert() 669 /// .stdout(predicate::str::similar("hello\n").from_utf8()); 670 /// 671 /// // which can be shortened to: 672 /// Command::cargo_bin("bin_fixture") 673 /// .unwrap() 674 /// .env("stdout", "hello") 675 /// .env("stderr", "world") 676 /// .assert() 677 /// .stdout("hello\n"); 678 /// ``` 679 /// 680 /// [`Assert::stdout`]: struct.Assert.html#method.stdout 681 /// [`Assert::stderr`]: struct.Assert.html#method.stderr 682 /// [`Predicate<[u8]>`]: https://docs.rs/predicates-core/1.0.0/predicates_core/trait.Predicate.html 683 pub trait IntoOutputPredicate<P> 684 where 685 P: predicates_core::Predicate<[u8]>, 686 { 687 /// The type of the predicate being returned. 688 type Predicate; 689 690 /// Convert to a predicate for testing a path. into_output(self) -> P691 fn into_output(self) -> P; 692 } 693 694 impl<P> IntoOutputPredicate<P> for P 695 where 696 P: predicates_core::Predicate<[u8]>, 697 { 698 type Predicate = P; 699 into_output(self) -> Self::Predicate700 fn into_output(self) -> Self::Predicate { 701 self 702 } 703 } 704 705 // Keep `predicates` concrete Predicates out of our public API. 706 /// [Predicate] used by [`IntoOutputPredicate`] for bytes. 707 /// 708 /// # Example 709 /// 710 /// ```rust,no_run 711 /// use assert_cmd::prelude::*; 712 /// 713 /// use std::process::Command; 714 /// 715 /// Command::cargo_bin("bin_fixture") 716 /// .unwrap() 717 /// .env("stdout", "hello") 718 /// .env("stderr", "world") 719 /// .assert() 720 /// .stderr(b"world\n" as &[u8]); 721 /// ``` 722 /// 723 /// [`IntoOutputPredicate`]: trait.IntoOutputPredicate.html 724 /// [Predicate]: https://docs.rs/predicates-core/1.0.0/predicates_core/trait.Predicate.html 725 #[derive(Debug)] 726 pub struct BytesContentOutputPredicate(predicates::ord::EqPredicate<&'static [u8]>); 727 728 impl BytesContentOutputPredicate { new(value: &'static [u8]) -> Self729 pub(crate) fn new(value: &'static [u8]) -> Self { 730 let pred = predicates::ord::eq(value); 731 BytesContentOutputPredicate(pred) 732 } 733 } 734 735 impl predicates_core::reflection::PredicateReflection for BytesContentOutputPredicate { parameters<'a>( &'a self, ) -> Box<dyn Iterator<Item = predicates_core::reflection::Parameter<'a>> + 'a>736 fn parameters<'a>( 737 &'a self, 738 ) -> Box<dyn Iterator<Item = predicates_core::reflection::Parameter<'a>> + 'a> { 739 self.0.parameters() 740 } 741 742 /// Nested `Predicate`s of the current `Predicate`. children<'a>( &'a self, ) -> Box<dyn Iterator<Item = predicates_core::reflection::Child<'a>> + 'a>743 fn children<'a>( 744 &'a self, 745 ) -> Box<dyn Iterator<Item = predicates_core::reflection::Child<'a>> + 'a> { 746 self.0.children() 747 } 748 } 749 750 impl predicates_core::Predicate<[u8]> for BytesContentOutputPredicate { eval(&self, item: &[u8]) -> bool751 fn eval(&self, item: &[u8]) -> bool { 752 self.0.eval(item) 753 } 754 find_case<'a>( &'a self, expected: bool, variable: &[u8], ) -> Option<predicates_core::reflection::Case<'a>>755 fn find_case<'a>( 756 &'a self, 757 expected: bool, 758 variable: &[u8], 759 ) -> Option<predicates_core::reflection::Case<'a>> { 760 self.0.find_case(expected, variable) 761 } 762 } 763 764 impl fmt::Display for BytesContentOutputPredicate { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result765 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 766 self.0.fmt(f) 767 } 768 } 769 770 impl IntoOutputPredicate<BytesContentOutputPredicate> for &'static [u8] { 771 type Predicate = BytesContentOutputPredicate; 772 into_output(self) -> Self::Predicate773 fn into_output(self) -> Self::Predicate { 774 Self::Predicate::new(self) 775 } 776 } 777 778 // Keep `predicates` concrete Predicates out of our public API. 779 /// [Predicate] used by [`IntoOutputPredicate`] for [`str`]. 780 /// 781 /// # Example 782 /// 783 /// ```rust,no_run 784 /// use assert_cmd::prelude::*; 785 /// 786 /// use std::process::Command; 787 /// 788 /// Command::cargo_bin("bin_fixture") 789 /// .unwrap() 790 /// .env("stdout", "hello") 791 /// .env("stderr", "world") 792 /// .assert() 793 /// .stderr("world\n"); 794 /// ``` 795 /// 796 /// [`IntoOutputPredicate`]: trait.IntoOutputPredicate.html 797 /// [Predicate]: https://docs.rs/predicates-core/1.0.0/predicates_core/trait.Predicate.html 798 /// [`str`]: https://doc.rust-lang.org/std/primitive.str.html 799 #[derive(Debug, Clone)] 800 pub struct StrContentOutputPredicate( 801 predicates::str::Utf8Predicate<predicates::str::DifferencePredicate>, 802 ); 803 804 impl StrContentOutputPredicate { from_str(value: &'static str) -> Self805 pub(crate) fn from_str(value: &'static str) -> Self { 806 let pred = predicates::str::similar(value).from_utf8(); 807 StrContentOutputPredicate(pred) 808 } 809 from_string(value: String) -> Self810 pub(crate) fn from_string(value: String) -> Self { 811 let pred = predicates::str::similar(value).from_utf8(); 812 StrContentOutputPredicate(pred) 813 } 814 } 815 816 impl predicates_core::reflection::PredicateReflection for StrContentOutputPredicate { parameters<'a>( &'a self, ) -> Box<dyn Iterator<Item = predicates_core::reflection::Parameter<'a>> + 'a>817 fn parameters<'a>( 818 &'a self, 819 ) -> Box<dyn Iterator<Item = predicates_core::reflection::Parameter<'a>> + 'a> { 820 self.0.parameters() 821 } 822 823 /// Nested `Predicate`s of the current `Predicate`. children<'a>( &'a self, ) -> Box<dyn Iterator<Item = predicates_core::reflection::Child<'a>> + 'a>824 fn children<'a>( 825 &'a self, 826 ) -> Box<dyn Iterator<Item = predicates_core::reflection::Child<'a>> + 'a> { 827 self.0.children() 828 } 829 } 830 831 impl predicates_core::Predicate<[u8]> for StrContentOutputPredicate { eval(&self, item: &[u8]) -> bool832 fn eval(&self, item: &[u8]) -> bool { 833 self.0.eval(item) 834 } 835 find_case<'a>( &'a self, expected: bool, variable: &[u8], ) -> Option<predicates_core::reflection::Case<'a>>836 fn find_case<'a>( 837 &'a self, 838 expected: bool, 839 variable: &[u8], 840 ) -> Option<predicates_core::reflection::Case<'a>> { 841 self.0.find_case(expected, variable) 842 } 843 } 844 845 impl fmt::Display for StrContentOutputPredicate { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result846 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 847 self.0.fmt(f) 848 } 849 } 850 851 impl IntoOutputPredicate<StrContentOutputPredicate> for String { 852 type Predicate = StrContentOutputPredicate; 853 into_output(self) -> Self::Predicate854 fn into_output(self) -> Self::Predicate { 855 Self::Predicate::from_string(self) 856 } 857 } 858 859 impl IntoOutputPredicate<StrContentOutputPredicate> for &'static str { 860 type Predicate = StrContentOutputPredicate; 861 into_output(self) -> Self::Predicate862 fn into_output(self) -> Self::Predicate { 863 Self::Predicate::from_str(self) 864 } 865 } 866 867 // Keep `predicates` concrete Predicates out of our public API. 868 /// [Predicate] used by [`IntoOutputPredicate`] for [`Predicate<str>`]. 869 /// 870 /// # Example 871 /// 872 /// ```rust,no_run 873 /// use assert_cmd::prelude::*; 874 /// 875 /// use std::process::Command; 876 /// use predicates::prelude::*; 877 /// 878 /// Command::cargo_bin("bin_fixture") 879 /// .unwrap() 880 /// .env("stdout", "hello") 881 /// .env("stderr", "world") 882 /// .assert() 883 /// .stderr(predicate::str::similar("world\n")); 884 /// ``` 885 /// 886 /// [`IntoOutputPredicate`]: trait.IntoOutputPredicate.html 887 /// [Predicate]: https://docs.rs/predicates-core/1.0.0/predicates_core/trait.Predicate.html 888 #[derive(Debug, Clone)] 889 pub struct StrOutputPredicate<P: predicates_core::Predicate<str>>( 890 predicates::str::Utf8Predicate<P>, 891 ); 892 893 impl<P> StrOutputPredicate<P> 894 where 895 P: predicates_core::Predicate<str>, 896 { new(pred: P) -> Self897 pub(crate) fn new(pred: P) -> Self { 898 let pred = pred.from_utf8(); 899 StrOutputPredicate(pred) 900 } 901 } 902 903 impl<P> predicates_core::reflection::PredicateReflection for StrOutputPredicate<P> 904 where 905 P: predicates_core::Predicate<str>, 906 { parameters<'a>( &'a self, ) -> Box<dyn Iterator<Item = predicates_core::reflection::Parameter<'a>> + 'a>907 fn parameters<'a>( 908 &'a self, 909 ) -> Box<dyn Iterator<Item = predicates_core::reflection::Parameter<'a>> + 'a> { 910 self.0.parameters() 911 } 912 913 /// Nested `Predicate`s of the current `Predicate`. children<'a>( &'a self, ) -> Box<dyn Iterator<Item = predicates_core::reflection::Child<'a>> + 'a>914 fn children<'a>( 915 &'a self, 916 ) -> Box<dyn Iterator<Item = predicates_core::reflection::Child<'a>> + 'a> { 917 self.0.children() 918 } 919 } 920 921 impl<P> predicates_core::Predicate<[u8]> for StrOutputPredicate<P> 922 where 923 P: predicates_core::Predicate<str>, 924 { eval(&self, item: &[u8]) -> bool925 fn eval(&self, item: &[u8]) -> bool { 926 self.0.eval(item) 927 } 928 find_case<'a>( &'a self, expected: bool, variable: &[u8], ) -> Option<predicates_core::reflection::Case<'a>>929 fn find_case<'a>( 930 &'a self, 931 expected: bool, 932 variable: &[u8], 933 ) -> Option<predicates_core::reflection::Case<'a>> { 934 self.0.find_case(expected, variable) 935 } 936 } 937 938 impl<P> fmt::Display for StrOutputPredicate<P> 939 where 940 P: predicates_core::Predicate<str>, 941 { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result942 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 943 self.0.fmt(f) 944 } 945 } 946 947 impl<P> IntoOutputPredicate<StrOutputPredicate<P>> for P 948 where 949 P: predicates_core::Predicate<str>, 950 { 951 type Predicate = StrOutputPredicate<P>; 952 into_output(self) -> Self::Predicate953 fn into_output(self) -> Self::Predicate { 954 Self::Predicate::new(self) 955 } 956 } 957 958 #[cfg(test)] 959 mod test { 960 use super::*; 961 962 use predicates::prelude::*; 963 964 // Since IntoCodePredicate exists solely for conversion, test it under that scenario to ensure 965 // it works as expected. convert_code<I, P>(pred: I) -> P where I: IntoCodePredicate<P>, P: predicates_core::Predicate<i32>,966 fn convert_code<I, P>(pred: I) -> P 967 where 968 I: IntoCodePredicate<P>, 969 P: predicates_core::Predicate<i32>, 970 { 971 pred.into_code() 972 } 973 974 #[test] into_code_from_pred()975 fn into_code_from_pred() { 976 let pred = convert_code(predicate::eq(10)); 977 assert!(pred.eval(&10)); 978 } 979 980 #[test] into_code_from_i32()981 fn into_code_from_i32() { 982 let pred = convert_code(10); 983 assert!(pred.eval(&10)); 984 } 985 986 #[test] into_code_from_vec()987 fn into_code_from_vec() { 988 let pred = convert_code(vec![3, 10]); 989 assert!(pred.eval(&10)); 990 } 991 992 #[test] into_code_from_array()993 fn into_code_from_array() { 994 let pred = convert_code(&[3, 10] as &[i32]); 995 assert!(pred.eval(&10)); 996 } 997 998 // Since IntoOutputPredicate exists solely for conversion, test it under that scenario to ensure 999 // it works as expected. convert_output<I, P>(pred: I) -> P where I: IntoOutputPredicate<P>, P: predicates_core::Predicate<[u8]>,1000 fn convert_output<I, P>(pred: I) -> P 1001 where 1002 I: IntoOutputPredicate<P>, 1003 P: predicates_core::Predicate<[u8]>, 1004 { 1005 pred.into_output() 1006 } 1007 1008 #[test] into_output_from_pred()1009 fn into_output_from_pred() { 1010 let pred = convert_output(predicate::eq(b"Hello" as &[u8])); 1011 assert!(pred.eval(b"Hello" as &[u8])); 1012 } 1013 1014 #[test] into_output_from_bytes()1015 fn into_output_from_bytes() { 1016 let pred = convert_output(b"Hello" as &[u8]); 1017 assert!(pred.eval(b"Hello" as &[u8])); 1018 } 1019 1020 #[test] into_output_from_str()1021 fn into_output_from_str() { 1022 let pred = convert_output("Hello"); 1023 assert!(pred.eval(b"Hello" as &[u8])); 1024 } 1025 } 1026