use std::mem;
use derive_more::with_trait::Deref;
use crate::{Event, World, Writer, event, parser, writer};
pub type FilterEvent<W> =
fn(&parser::Result<Event<event::Cucumber<W>>>) -> bool;
#[derive(Debug, Deref)]
pub struct Repeat<W, Wr, F = FilterEvent<W>> {
#[deref]
writer: Wr,
filter: F,
events: Vec<parser::Result<Event<event::Cucumber<W>>>>,
}
impl<World, Wr: Clone, F: Clone> Clone for Repeat<World, Wr, F> {
fn clone(&self) -> Self {
Self {
writer: self.writer.clone(),
filter: self.filter.clone(),
events: self.events.clone(),
}
}
}
impl<W, Wr, F> Writer<W> for Repeat<W, Wr, F>
where
W: World,
Wr: Writer<W> + writer::NonTransforming,
F: Fn(&parser::Result<Event<event::Cucumber<W>>>) -> bool,
{
type Cli = Wr::Cli;
async fn handle_event(
&mut self,
event: parser::Result<Event<event::Cucumber<W>>>,
cli: &Self::Cli,
) {
if (self.filter)(&event) {
self.events.push(event.clone());
}
let is_finished =
matches!(event.as_deref(), Ok(event::Cucumber::Finished));
self.writer.handle_event(event, cli).await;
if is_finished {
for ev in mem::take(&mut self.events) {
self.writer.handle_event(ev, cli).await;
}
}
}
}
#[warn(clippy::missing_trait_methods)]
impl<W, Wr, Val, F> writer::Arbitrary<W, Val> for Repeat<W, Wr, F>
where
W: World,
Wr: writer::Arbitrary<W, Val> + writer::NonTransforming,
F: Fn(&parser::Result<Event<event::Cucumber<W>>>) -> bool,
{
async fn write(&mut self, val: Val) {
self.writer.write(val).await;
}
}
#[warn(clippy::missing_trait_methods)]
impl<W, Wr, F> writer::Stats<W> for Repeat<W, Wr, F>
where
Wr: writer::Stats<W> + writer::NonTransforming,
Self: Writer<W>,
{
fn passed_steps(&self) -> usize {
self.writer.passed_steps()
}
fn skipped_steps(&self) -> usize {
self.writer.skipped_steps()
}
fn failed_steps(&self) -> usize {
self.writer.failed_steps()
}
fn retried_steps(&self) -> usize {
self.writer.retried_steps()
}
fn parsing_errors(&self) -> usize {
self.writer.parsing_errors()
}
fn hook_errors(&self) -> usize {
self.writer.hook_errors()
}
fn execution_has_failed(&self) -> bool {
self.writer.execution_has_failed()
}
}
#[warn(clippy::missing_trait_methods)]
impl<W, Wr: writer::Normalized, F> writer::Normalized for Repeat<W, Wr, F> {}
#[warn(clippy::missing_trait_methods)]
impl<W, Wr, F> writer::Summarizable for Repeat<W, Wr, F> {}
impl<W, Wr, F> Repeat<W, Wr, F> {
#[must_use]
pub const fn new(writer: Wr, filter: F) -> Self {
Self { writer, filter, events: Vec::new() }
}
}
impl<W, Wr> Repeat<W, Wr> {
#[must_use]
pub fn skipped(writer: Wr) -> Self {
use event::{
Cucumber, Feature, RetryableScenario, Rule, Scenario, Step,
};
Self {
writer,
filter: |ev| {
matches!(
ev.as_deref(),
Ok(Cucumber::Feature(
_,
Feature::Rule(
_,
Rule::Scenario(
_,
RetryableScenario {
event: Scenario::Step(_, Step::Skipped)
| Scenario::Background(
_,
Step::Skipped
),
..
}
)
) | Feature::Scenario(
_,
RetryableScenario {
event: Scenario::Step(_, Step::Skipped)
| Scenario::Background(_, Step::Skipped),
..
}
)
)),
)
},
events: Vec::new(),
}
}
#[must_use]
pub fn failed(writer: Wr) -> Self {
use event::{
Cucumber, Feature, Hook, RetryableScenario, Rule, Scenario, Step,
};
Self {
writer,
filter: |ev| {
matches!(
ev.as_deref(),
Ok(Cucumber::Feature(
_,
Feature::Rule(
_,
Rule::Scenario(
_,
RetryableScenario {
event: Scenario::Step(_, Step::Failed(..))
| Scenario::Background(
_,
Step::Failed(..),
)
| Scenario::Hook(_, Hook::Failed(..)),
..
}
)
) | Feature::Scenario(
_,
RetryableScenario {
event: Scenario::Step(_, Step::Failed(..))
| Scenario::Background(_, Step::Failed(..))
| Scenario::Hook(_, Hook::Failed(..)),
..
},
)
)) | Err(_),
)
},
events: Vec::new(),
}
}
#[must_use]
pub fn inner_writer(&self) -> &Wr {
&self.writer
}
}