diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1fe629b..e30e84c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -69,7 +69,7 @@ jobs: - name: No-default features run: cargo test --workspace --no-default-features msrv: - name: "Check MSRV: 1.44.0" + name: "Check MSRV: 1.46.0" needs: smoke runs-on: ubuntu-latest steps: @@ -78,7 +78,7 @@ jobs: - name: Install Rust uses: actions-rs/toolchain@v1 with: - toolchain: 1.44.0 # MSRV + toolchain: 1.46.0 # MSRV profile: minimal override: true - uses: Swatinem/rust-cache@v1 @@ -133,7 +133,7 @@ jobs: - name: Install Rust uses: actions-rs/toolchain@v1 with: - toolchain: 1.44.0 # MSRV + toolchain: 1.46.0 # MSRV profile: minimal override: true components: clippy diff --git a/.github/workflows/rust-next.yml b/.github/workflows/rust-next.yml index 0c048a7..b2464e5 100644 --- a/.github/workflows/rust-next.yml +++ b/.github/workflows/rust-next.yml @@ -66,9 +66,9 @@ jobs: strategy: matrix: rust: - - 1.44.0 # MSRV + - 1.46.0 # MSRV - stable - continue-on-error: ${{ matrix.rust != '1.44.0' }} # MSRV + continue-on-error: ${{ matrix.rust != '1.46.0' }} # MSRV runs-on: ubuntu-latest steps: - name: Checkout repository diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cfbcba..f818fab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] - ReleaseDate +#### Fixes + +- Show caller for panic, rather than `assert_cmd` + ## [2.0.0] - 2021-08-05 ### Breaking Changes diff --git a/src/assert.rs b/src/assert.rs index 7899914..6d323d8 100644 --- a/src/assert.rs +++ b/src/assert.rs @@ -66,100 +66,6 @@ impl<'c> OutputAssertExt for &'c mut process::Command { } } -/// [`Assert`] represented as a [`Result`]. -/// -/// Produced by the `try_` variants the [`Assert`] methods. -/// -/// # Example -/// -/// ```rust -/// use assert_cmd::prelude::*; -/// -/// use std::process::Command; -/// -/// let result = Command::new("echo") -/// .assert() -/// .try_success(); -/// assert!(result.is_ok()); -/// ``` -/// -/// [`Result`]: std::result::Result -pub type AssertResult = Result; - -/// [`Assert`] error (see [`AssertResult`]). -#[derive(Debug)] -pub struct AssertError { - assert: Assert, - reason: AssertReason, -} - -#[derive(Debug)] -enum AssertReason { - UnexpectedFailure { actual_code: Option }, - UnexpectedSuccess, - UnexpectedCompletion, - CommandInterrupted, - UnexpectedReturnCode { case_tree: CaseTree }, - UnexpectedStdout { case_tree: CaseTree }, - UnexpectedStderr { case_tree: CaseTree }, -} - -struct CaseTree(predicates_tree::CaseTree); - -impl fmt::Display for CaseTree { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - ::fmt(&self.0, f) - } -} - -// Work around `Debug` not being implemented for `predicates_tree::CaseTree`. -impl fmt::Debug for CaseTree { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - ::fmt(&self.0, f) - } -} - -impl AssertError { - fn panic(self) -> T { - panic!("{}", self.to_string()) - } -} - -impl Error for AssertError {} - -impl fmt::Display for AssertError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match &self.reason { - AssertReason::UnexpectedFailure { actual_code } => writeln!( - f, - "Unexpected failure.\ncode-{}\nstderr=```{}```", - actual_code.map_or("".to_owned(), |actual_code| actual_code - .to_string()), - DebugBytes::new(&self.assert.output.stderr), - ), - AssertReason::UnexpectedSuccess => { - writeln!(f, "Unexpected success") - } - AssertReason::UnexpectedCompletion => { - writeln!(f, "Unexpected completion") - } - AssertReason::CommandInterrupted => { - writeln!(f, "Command interrupted") - } - AssertReason::UnexpectedReturnCode { case_tree } => { - writeln!(f, "Unexpected return code, failed {}", case_tree) - } - AssertReason::UnexpectedStdout { case_tree } => { - writeln!(f, "Unexpected stdout, failed {}", case_tree) - } - AssertReason::UnexpectedStderr { case_tree } => { - writeln!(f, "Unexpected stderr, failed {}", case_tree) - } - }?; - write!(f, "{}", self.assert) - } -} - /// Assert the state of an [`Output`]. /// /// Create an `Assert` through the [`OutputAssertExt`] trait. @@ -245,6 +151,7 @@ impl Assert { /// .assert() /// .success(); /// ``` + #[track_caller] pub fn success(self) -> Self { self.try_success().unwrap_or_else(AssertError::panic) } @@ -273,6 +180,7 @@ impl Assert { /// .assert() /// .failure(); /// ``` + #[track_caller] pub fn failure(self) -> Self { self.try_failure().unwrap_or_else(AssertError::panic) } @@ -286,6 +194,7 @@ impl Assert { } /// Ensure the command aborted before returning a code. + #[track_caller] pub fn interrupted(self) -> Self { self.try_interrupted().unwrap_or_else(AssertError::panic) } @@ -346,6 +255,7 @@ impl Assert { /// .code(&[2, 42] as &[i32]); /// ``` /// + #[track_caller] pub fn code(self, pred: I) -> Self where I: IntoCodePredicate

, @@ -443,6 +353,7 @@ impl Assert { /// .stdout("hello\n"); /// ``` /// + #[track_caller] pub fn stdout(self, pred: I) -> Self where I: IntoOutputPredicate

, @@ -538,6 +449,7 @@ impl Assert { /// .stderr("world\n"); /// ``` /// + #[track_caller] pub fn stderr(self, pred: I) -> Self where I: IntoOutputPredicate

, @@ -1074,6 +986,101 @@ where } } +/// [`Assert`] represented as a [`Result`]. +/// +/// Produced by the `try_` variants the [`Assert`] methods. +/// +/// # Example +/// +/// ```rust +/// use assert_cmd::prelude::*; +/// +/// use std::process::Command; +/// +/// let result = Command::new("echo") +/// .assert() +/// .try_success(); +/// assert!(result.is_ok()); +/// ``` +/// +/// [`Result`]: std::result::Result +pub type AssertResult = Result; + +/// [`Assert`] error (see [`AssertResult`]). +#[derive(Debug)] +pub struct AssertError { + assert: Assert, + reason: AssertReason, +} + +#[derive(Debug)] +enum AssertReason { + UnexpectedFailure { actual_code: Option }, + UnexpectedSuccess, + UnexpectedCompletion, + CommandInterrupted, + UnexpectedReturnCode { case_tree: CaseTree }, + UnexpectedStdout { case_tree: CaseTree }, + UnexpectedStderr { case_tree: CaseTree }, +} + +impl AssertError { + #[track_caller] + fn panic(self) -> T { + panic!("{}", self) + } +} + +impl Error for AssertError {} + +impl fmt::Display for AssertError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match &self.reason { + AssertReason::UnexpectedFailure { actual_code } => writeln!( + f, + "Unexpected failure.\ncode-{}\nstderr=```{}```", + actual_code.map_or("".to_owned(), |actual_code| actual_code + .to_string()), + DebugBytes::new(&self.assert.output.stderr), + ), + AssertReason::UnexpectedSuccess => { + writeln!(f, "Unexpected success") + } + AssertReason::UnexpectedCompletion => { + writeln!(f, "Unexpected completion") + } + AssertReason::CommandInterrupted => { + writeln!(f, "Command interrupted") + } + AssertReason::UnexpectedReturnCode { case_tree } => { + writeln!(f, "Unexpected return code, failed {}", case_tree) + } + AssertReason::UnexpectedStdout { case_tree } => { + writeln!(f, "Unexpected stdout, failed {}", case_tree) + } + AssertReason::UnexpectedStderr { case_tree } => { + writeln!(f, "Unexpected stderr, failed {}", case_tree) + } + }?; + write!(f, "{}", self.assert) + } +} + +struct CaseTree(predicates_tree::CaseTree); + +impl fmt::Display for CaseTree { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ::fmt(&self.0, f) + } +} + +// Work around `Debug` not being implemented for `predicates_tree::CaseTree`. +impl fmt::Debug for CaseTree { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ::fmt(&self.0, f) + } +} + #[cfg(test)] mod test { use super::*;