From af85c9d415e7b39867d433a4e74a9dde78b73c2f Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 7 Oct 2021 16:04:26 -0500 Subject: [PATCH 1/2] chore: Bump MSRV --- .github/workflows/ci.yml | 6 +++--- .github/workflows/rust-next.yml | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e30e84c..adda2fb 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.46.0" + name: "Check MSRV: 1.54.0" needs: smoke runs-on: ubuntu-latest steps: @@ -78,7 +78,7 @@ jobs: - name: Install Rust uses: actions-rs/toolchain@v1 with: - toolchain: 1.46.0 # MSRV + toolchain: 1.54.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.46.0 # MSRV + toolchain: 1.54.0 # MSRV profile: minimal override: true components: clippy diff --git a/.github/workflows/rust-next.yml b/.github/workflows/rust-next.yml index b2464e5..21d50cf 100644 --- a/.github/workflows/rust-next.yml +++ b/.github/workflows/rust-next.yml @@ -66,9 +66,9 @@ jobs: strategy: matrix: rust: - - 1.46.0 # MSRV + - 1.54.0 # MSRV - stable - continue-on-error: ${{ matrix.rust != '1.46.0' }} # MSRV + continue-on-error: ${{ matrix.rust != '1.54.0' }} # MSRV runs-on: ubuntu-latest steps: - name: Checkout repository From 0b1629f26546d1d49d85331c9d2ec6b5d4fae681 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 7 Oct 2021 16:17:58 -0500 Subject: [PATCH 2/2] feat: Color support --- Cargo.toml | 10 ++++++---- examples/failure.rs | 10 ++++++++++ src/assert.rs | 8 +++++++- src/color.rs | 48 +++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 3 +++ src/output.rs | 43 ++++++++++++++++++++++++++++------------ 6 files changed, 105 insertions(+), 17 deletions(-) create mode 100644 examples/failure.rs create mode 100644 src/color.rs diff --git a/Cargo.toml b/Cargo.toml index dfd2215..1e45170 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,10 +12,6 @@ categories = ["development-tools::testing"] keywords = ["cli", "test", "assert", "command", "duct"] edition = "2018" -[badges] -codecov = { repository = "assert-rs/assert_cmd" } -maintenance = { status = "passively-maintained" } - [package.metadata.release] pre-release-replacements = [ {file="CHANGELOG.md", search="Unreleased", replace="{{version}}", min=1}, @@ -25,6 +21,10 @@ pre-release-replacements = [ {file="CHANGELOG.md", search="", replace="\n[Unreleased]: https://github.com/assert-rs/assert_cmd/compare/{{tag_name}}...HEAD", exactly=1}, ] +[features] +color = ["yansi", "concolor-control/std", "predicates/color"] +color-auto = ["color", "concolor-control/auto"] + [[bin]] name = "bin_fixture" @@ -35,6 +35,8 @@ predicates-tree = "1.0" doc-comment = "0.3" wait-timeout = "0.2.0" bstr = "0.2.14" +yansi = { version = "0.5.0", optional = true } +concolor-control = { version = "0.0.7", optional = true } [dev-dependencies] escargot = "0.5" diff --git a/examples/failure.rs b/examples/failure.rs new file mode 100644 index 0000000..d6678a5 --- /dev/null +++ b/examples/failure.rs @@ -0,0 +1,10 @@ +use assert_cmd::prelude::*; + +use std::process::Command; + +fn main() { + Command::new("ls") + .args(["non-existent"]) + .assert() + .code(&[3, 42] as &[i32]); +} diff --git a/src/assert.rs b/src/assert.rs index 6d323d8..dbf1c4c 100644 --- a/src/assert.rs +++ b/src/assert.rs @@ -482,8 +482,14 @@ impl Assert { impl fmt::Display for Assert { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let palette = crate::Palette::current(); for &(ref name, ref context) in &self.context { - writeln!(f, "{}=`{}`", name, context)?; + writeln!( + f, + "{}=`{}`", + palette.key.paint(name), + palette.value.paint(context) + )?; } output_fmt(&self.output, f) } diff --git a/src/color.rs b/src/color.rs new file mode 100644 index 0000000..92d6736 --- /dev/null +++ b/src/color.rs @@ -0,0 +1,48 @@ +#[derive(Copy, Clone, Debug, Default)] +pub(crate) struct Palette { + pub(crate) key: styled::Style, + pub(crate) value: styled::Style, +} + +impl Palette { + #[cfg(feature = "color")] + pub(crate) fn current() -> Self { + if concolor_control::get(concolor_control::Stream::Either).ansi_color() { + Self { + key: styled::Style(yansi::Style::new(yansi::Color::Blue).bold()), + value: styled::Style(yansi::Style::new(yansi::Color::Yellow).bold()), + } + } else { + Self::default() + } + } + + #[cfg(not(feature = "color"))] + pub(crate) fn current() -> Self { + Self::default() + } +} + +#[cfg(feature = "color")] +mod styled { + #[derive(Copy, Clone, Debug, Default)] + pub(crate) struct Style(pub(crate) yansi::Style); + + impl Style { + pub(crate) fn paint(self, item: T) -> impl std::fmt::Display { + self.0.paint(item) + } + } +} + +#[cfg(not(feature = "color"))] +mod styled { + #[derive(Copy, Clone, Debug, Default)] + pub(crate) struct Style; + + impl Style { + pub(crate) fn paint(self, item: T) -> impl std::fmt::Display { + item + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 71efdc8..f6a8052 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -144,4 +144,7 @@ pub mod prelude { pub use crate::cmd::Command; +mod color; +use color::Palette; + doc_comment::doctest!("../README.md"); diff --git a/src/output.rs b/src/output.rs index 90c4f08..0d1097e 100644 --- a/src/output.rs +++ b/src/output.rs @@ -4,7 +4,6 @@ use bstr::ByteSlice; use std::error::Error; use std::fmt; use std::process; -use std::str; /// Converts a type to an [`OutputResult`]. /// @@ -242,15 +241,22 @@ impl Error for OutputError {} impl fmt::Display for OutputError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let palette = crate::Palette::current(); if let Some(ref cmd) = self.cmd { - writeln!(f, "command=`{}`", cmd)?; + writeln!( + f, + "{}={}", + palette.key.paint("command"), + palette.value.paint(cmd) + )?; } if let Some(ref stdin) = self.stdin { - if let Ok(stdin) = str::from_utf8(stdin) { - writeln!(f, "stdin=```{}```", stdin)?; - } else { - writeln!(f, "stdin=```{:?}```", stdin)?; - } + writeln!( + f, + "{}={}", + palette.key.paint("stdin"), + palette.value.paint(DebugBytes::new(stdin)) + )?; } write!(f, "{}", self.cause) } @@ -283,17 +289,30 @@ impl fmt::Display for Output { } pub(crate) fn output_fmt(output: &process::Output, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let palette = crate::Palette::current(); if let Some(code) = output.status.code() { - writeln!(f, "code={}", code)?; + writeln!( + f, + "{}={}", + palette.key.paint("code"), + palette.value.paint(code) + )?; } else { - writeln!(f, "code=")?; + writeln!( + f, + "{}={}", + palette.key.paint("code"), + palette.value.paint("") + )?; } write!( f, - "stdout=```{}```\nstderr=```{}```\n", - DebugBytes::new(&output.stdout), - DebugBytes::new(&output.stderr), + "{}={}\n{}={}\n", + palette.key.paint("stdout"), + palette.value.paint(DebugBytes::new(&output.stdout)), + palette.key.paint("stderr"), + palette.value.paint(DebugBytes::new(&output.stderr)), )?; Ok(()) }