Skip to content

Commit

Permalink
Implement writer::AssertNormalized (#182)
Browse files Browse the repository at this point in the history
  • Loading branch information
ilslv authored Dec 8, 2021
1 parent b783208 commit 8949168
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 5 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ All user visible changes to `cucumber` crate will be documented in this file. Th
- Support for [Cucumber Expressions] via `#[given(expr = ...)]`, `#[when(expr = ...)]` and `#[then(expr = ...)]` syntax. ([#157])
- Support for custom parameters in [Cucumber Expressions] via `#[derive(cucumber::Parameter)]` macro. ([#168])
- Merging tags from `Feature` and `Rule` with `Scenario` when filtering with `--tags` CLI option. ([#166])
- `writer::AssertNormalized` forcing `Normalized` implementation. ([#182])

### Fixed

Expand All @@ -54,6 +55,7 @@ All user visible changes to `cucumber` crate will be documented in this file. Th
[#168]: /../../pull/168
[#172]: /../../pull/172
[#178]: /../../pull/178
[#182]: /../../pull/182
[cef3d480]: /../../commit/cef3d480579190425461ddb04a1248675248351e
[rev]: /../../commit/rev-full
[0110-1]: https://llg.cubic.org/docs/junit
Expand Down
24 changes: 23 additions & 1 deletion src/writer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ pub use self::junit::JUnit;
pub use self::{
basic::{Basic, Coloring},
fail_on_skipped::FailOnSkipped,
normalize::{Normalize, Normalized},
normalize::{AssertNormalized, Normalize, Normalized},
repeat::Repeat,
summarize::{Summarizable, Summarize},
tee::Tee,
Expand Down Expand Up @@ -133,6 +133,24 @@ pub trait Failure<World>: Writer<World> {
/// Extension of [`Writer`] allowing its normalization and summarization.
#[sealed]
pub trait Ext: Sized {
/// Asserts this [`Writer`] being [`Normalized`].
///
/// Technically is no-op, only forcing the [`Writer`] to become
/// [`Normalized`] despite it actually doesn't represent the one.
///
/// If you need a real normalization, use [`normalized()`] instead.
///
/// > ⚠️ __WARNING__: Should be used only in case you are absolutely sure,
/// > that incoming events will be emitted in a
/// > [`Normalized`] order.
/// > For example, in case [`max_concurrent_scenarios()`][1]
/// > is set to `1`.
///
/// [`normalized()`]: Ext::normalized
/// [1]: crate::runner::Basic::max_concurrent_scenarios()
#[must_use]
fn assert_normalized(self) -> AssertNormalized<Self>;

/// Wraps this [`Writer`] into a [`Normalize`]d version.
///
/// See [`Normalize`] for more information.
Expand Down Expand Up @@ -227,6 +245,10 @@ pub trait Ext: Sized {

#[sealed]
impl<T> Ext for T {
fn assert_normalized(self) -> AssertNormalized<Self> {
AssertNormalized::new(self)
}

fn normalized<W>(self) -> Normalize<W, Self> {
Normalize::new(self)
}
Expand Down
86 changes: 85 additions & 1 deletion src/writer/normalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use linked_hash_map::LinkedHashMap;

use crate::{
event::{self, Metadata},
parser, writer, Event, Writer,
parser, writer, Event, World, Writer,
};

/// Wrapper for a [`Writer`] implementation for outputting events corresponding
Expand Down Expand Up @@ -189,6 +189,90 @@ pub trait Normalized {}

impl<World, Writer> Normalized for Normalize<World, Writer> {}

/// Wrapper for a [`Writer`] asserting it being [`Normalized`].
///
/// Technically is no-op, only forcing the [`Writer`] to become [`Normalized`]
/// despite it actually doesn't represent the one.
///
/// > ⚠️ __WARNING__: Should be used only in case you are absolutely sure, that
/// > incoming events will be emitted in a [`Normalized`] order.
/// > For example, in case [`max_concurrent_scenarios()`][1] is
/// > set to `1`.
///
/// [1]: crate::runner::Basic::max_concurrent_scenarios
#[derive(Debug, Deref)]
pub struct AssertNormalized<W: ?Sized>(W);

impl<Writer> AssertNormalized<Writer> {
/// Creates a new no-op [`AssertNormalized`] wrapper forcing [`Normalized`]
/// implementation.
///
/// > ⚠️ __WARNING__: Should be used only in case you are absolutely sure,
/// > that incoming events will be emitted in a
/// > [`Normalized`] order.
/// > For example, in case [`max_concurrent_scenarios()`][1]
/// > is set to `1`.
///
/// [1]: crate::runner::Basic::max_concurrent_scenarios
#[must_use]
pub const fn new(writer: Writer) -> Self {
Self(writer)
}
}

#[async_trait(?Send)]
impl<W: World, Wr: Writer<W> + ?Sized> Writer<W> for AssertNormalized<Wr> {
type Cli = Wr::Cli;

async fn handle_event(
&mut self,
event: parser::Result<Event<event::Cucumber<W>>>,
cli: &Self::Cli,
) {
self.0.handle_event(event, cli).await;
}
}

#[async_trait(?Send)]
impl<'val, W, Wr, Val> writer::Arbitrary<'val, W, Val> for AssertNormalized<Wr>
where
W: World,
Val: 'val,
Wr: writer::Arbitrary<'val, W, Val> + ?Sized,
{
async fn write(&mut self, val: Val)
where
'val: 'async_trait,
{
self.0.write(val).await;
}
}

impl<W, Wr> writer::Failure<W> for AssertNormalized<Wr>
where
Wr: writer::Failure<W>,
Self: Writer<W>,
{
fn failed_steps(&self) -> usize {
self.0.failed_steps()
}

fn parsing_errors(&self) -> usize {
self.0.parsing_errors()
}

fn hook_errors(&self) -> usize {
self.0.hook_errors()
}
}

impl<Wr: writer::NonTransforming> writer::NonTransforming
for AssertNormalized<Wr>
{
}

impl<Writer> Normalized for AssertNormalized<Writer> {}

/// Normalization queue for incoming events.
///
/// We use [`LinkedHashMap`] everywhere throughout this module to ensure FIFO
Expand Down
7 changes: 4 additions & 3 deletions src/writer/summarize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

//! [`Writer`]-wrapper for collecting a summary of execution.
use std::{array, borrow::Cow, collections::HashMap, sync::Arc};
use std::{borrow::Cow, collections::HashMap, sync::Arc};

use async_trait::async_trait;
use derive_more::Deref;
Expand Down Expand Up @@ -501,7 +501,7 @@ impl Styles {
/// Formats [`Stats`] for a terminal output.
#[must_use]
pub fn format_stats(&self, stats: Stats) -> Cow<'static, str> {
let formatted = array::IntoIter::new([
let formatted = [
(stats.passed > 0)
.then(|| self.bold(self.ok(format!("{} passed", stats.passed))))
.unwrap_or_default(),
Expand All @@ -517,7 +517,8 @@ impl Styles {
self.bold(self.err(format!("{} failed", stats.failed)))
})
.unwrap_or_default(),
])
]
.into_iter()
.filter(|s| !s.is_empty())
.join(&self.bold(", "));

Expand Down

0 comments on commit 8949168

Please sign in to comment.