From 82eaf76293e6d88969fb5a99eb8717306f69d9df Mon Sep 17 00:00:00 2001 From: Russell Mull Date: Wed, 14 Oct 2020 14:37:29 -0700 Subject: [PATCH] Bring back the scenario filter cli option Fixes: #67 --- Cargo.toml | 1 + src/cli.rs | 36 ++++++++++++++++++++++++++++++++++++ src/cucumber.rs | 31 +++++++++++++++++++++++++++++++ src/lib.rs | 1 + src/runner.rs | 12 +++++++++++- 5 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 src/cli.rs diff --git a/Cargo.toml b/Cargo.toml index 408c9e84..20968847 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ thiserror = "1.0.20" termcolor = "1.1.0" textwrap = { version = "0.12.1", features = ["terminal_size"] } pathdiff = "0.2.0" +clap = "2.33" [[test]] name = "cucumber_builder" diff --git a/src/cli.rs b/src/cli.rs new file mode 100644 index 00000000..6ed34387 --- /dev/null +++ b/src/cli.rs @@ -0,0 +1,36 @@ +use clap::{App, Arg}; + +#[derive(Default)] +pub struct CliOptions { + pub scenario_filter: Option, + pub nocapture: bool, +} + +pub fn make_app() -> CliOptions { + let matches = App::new("cucumber") + .version(env!("CARGO_PKG_VERSION")) + .author("Brendan Molloy ") + .about("Run the tests, pet a dog!") + .arg( + Arg::with_name("filter") + .short("e") + .long("expression") + .value_name("regex") + .help("Regex to select scenarios from") + .takes_value(true), + ) + .arg( + Arg::with_name("nocapture") + .long("nocapture") + .help("Use this flag to disable suppression of output from tests"), + ) + .get_matches(); + + let nocapture = matches.is_present("nocapture"); + let scenario_filter = matches.value_of("filter").map(|v| v.to_string()); + + CliOptions { + nocapture, + scenario_filter, + } +} diff --git a/src/cucumber.rs b/src/cucumber.rs index 48f486f6..eb0e1d32 100644 --- a/src/cucumber.rs +++ b/src/cucumber.rs @@ -7,6 +7,7 @@ // except according to those terms. use futures::StreamExt; +use regex::Regex; use crate::steps::Steps; use crate::{EventHandler, World}; @@ -17,14 +18,19 @@ pub struct Cucumber { steps: Steps, features: Vec, event_handler: Box, + /// If `Some`, enforce an upper bound on the amount /// of time a step is allowed to execute. /// If `Some`, also avoid indefinite locks during /// step clean-up handling (i.e. to recover panic info) step_timeout: Option, + /// If true, capture stdout and stderr content /// during tests. enable_capture: bool, + + /// If given, filters the scenario which are run + scenario_filter: Option, } impl Default for Cucumber { @@ -35,6 +41,7 @@ impl Default for Cucumber { event_handler: Box::new(crate::output::BasicOutput::default()), step_timeout: None, enable_capture: true, + scenario_filter: None, } } } @@ -56,6 +63,7 @@ impl Cucumber { event_handler: Box::new(event_handler), step_timeout: None, enable_capture: true, + scenario_filter: None, } } @@ -112,12 +120,35 @@ impl Cucumber { self } + pub fn scenario_regex(mut self, regex: &str) -> Self { + let regex = Regex::new(regex).expect("Error compiling scenario regex"); + self.scenario_filter = Some(regex); + self + } + + /// Call this to incorporate command line options into the configuration. + pub fn cli(self) -> Self { + let opts = crate::cli::make_app(); + let mut s = self; + + if let Some(re) = opts.scenario_filter { + s = s.scenario_regex(&re); + } + + if opts.nocapture { + s = s.enable_capture(false); + } + + s + } + pub async fn run(mut self) { let runner = crate::runner::Runner::new( self.steps.steps, std::rc::Rc::new(self.features), self.step_timeout, self.enable_capture, + self.scenario_filter, ); let mut stream = runner.run(); diff --git a/src/lib.rs b/src/lib.rs index 59e91a0b..a344cfd7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,6 +17,7 @@ pub use gherkin; #[macro_use] mod macros; +mod cli; mod collection; mod cucumber; pub mod event; diff --git a/src/runner.rs b/src/runner.rs index 8cf710af..f3358525 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -14,6 +14,7 @@ use std::sync::{Arc, TryLockError}; use async_stream::stream; use futures::{Future, Stream, StreamExt}; +use regex::Regex; use crate::collection::StepsCollection; use crate::event::*; @@ -48,6 +49,7 @@ pub(crate) struct Runner { features: Rc>, step_timeout: Option, enable_capture: bool, + scenario_filter: Option, } impl Runner { @@ -57,12 +59,14 @@ impl Runner { features: Rc>, step_timeout: Option, enable_capture: bool, + scenario_filter: Option, ) -> Rc> { Rc::new(Runner { functions, features, step_timeout, enable_capture, + scenario_filter, }) } @@ -195,6 +199,13 @@ impl Runner { yield FeatureEvent::Starting; for scenario in feature.scenarios.iter() { + // If regex filter fails, skip the scenario + if let Some(ref regex) = self.scenario_filter { + if !regex.is_match(&scenario.name) { + continue; + } + } + let examples = ExampleValues::from_examples(&scenario.examples); for example_values in examples { let this = Rc::clone(&self); @@ -356,7 +367,6 @@ impl Runner { yield CucumberEvent::Starting; let features = self.features.iter().cloned().map(Rc::new).collect::>(); - for feature in features.into_iter() { let this = Rc::clone(&self); let mut stream = this.run_feature(Rc::clone(&feature));