From 3383d2689be3ddbe4ff7609d0f5e655f4d82745b Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Sat, 15 Feb 2020 12:09:31 +0200 Subject: Add: add support for "and" and "but" keywords --- src/ast.rs | 6 ++++-- src/steps.rs | 24 +++++++++++++++++++----- subplot.md | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 7 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index f59d9f4..9ae92c6 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -164,6 +164,7 @@ fn extract_scenario(e: &[Element]) -> Result<(Option, usize)> { Element::Snippet(_) => Err(Error::scenario_before_heading()), Element::Heading(title, level) => { let mut scen = Scenario::new(&title); + let mut prevkind = StepKind::Given; for (i, item) in e.iter().enumerate().skip(1) { match item { Element::Heading(_, level2) => { @@ -181,8 +182,9 @@ fn extract_scenario(e: &[Element]) -> Result<(Option, usize)> { } Element::Snippet(text) => { for line in parse_scenario_snippet(&text) { - let step = ScenarioStep::new_from_str(line)?; + let step = ScenarioStep::new_from_str(line, prevkind)?; scen.add(&step); + prevkind = step.kind(); } } } @@ -532,7 +534,7 @@ pub fn scenario_snippet(bindings: &Bindings, snippet: &str) -> Block { // Typeset a single scenario step as a sequence of Pandoc AST Inlines. fn step(bindings: &Bindings, text: &str) -> Vec { - let step = ScenarioStep::new_from_str(text); + let step = ScenarioStep::new_from_str(text, StepKind::Given); if step.is_err() { eprintln!("Could not parse step: {}", text); return error_msg(&format!("Could not parse step: {}", text)); diff --git a/src/steps.rs b/src/steps.rs index 66ab453..ccf7694 100644 --- a/src/steps.rs +++ b/src/steps.rs @@ -37,13 +37,18 @@ impl ScenarioStep { } /// Construct a step from a line in a scenario. - pub fn new_from_str(text: &str) -> Result { + /// + /// If the step uses the "and" or "but" keyword, use the default + /// step kind instead. + pub fn new_from_str(text: &str, default: StepKind) -> Result { let mut words = text.split_whitespace(); let kind = match words.next() { Some("given") => StepKind::Given, Some("when") => StepKind::When, Some("then") => StepKind::Then, + Some("and") => default, + Some("but") => default, _ => return Err(Error::UnknownStepKind), }; @@ -99,28 +104,37 @@ mod test { #[test] fn parses_given() { - let step = ScenarioStep::new_from_str("given I am Tomjon").unwrap(); + let step = ScenarioStep::new_from_str("given I am Tomjon", StepKind::Then).unwrap(); assert_eq!(step.kind(), StepKind::Given); assert_eq!(step.text(), "I am Tomjon"); } #[test] fn parses_given_with_extra_spaces() { - let step = ScenarioStep::new_from_str(" given I am Tomjon ").unwrap(); + let step = + ScenarioStep::new_from_str(" given I am Tomjon ", StepKind::When).unwrap(); assert_eq!(step.kind(), StepKind::Given); assert_eq!(step.text(), "I am Tomjon"); } #[test] fn parses_when() { - let step = ScenarioStep::new_from_str("when I declare myself king").unwrap(); + let step = + ScenarioStep::new_from_str("when I declare myself king", StepKind::Given).unwrap(); assert_eq!(step.kind(), StepKind::When); assert_eq!(step.text(), "I declare myself king"); } #[test] fn parses_then() { - let step = ScenarioStep::new_from_str("then everyone accepts it").unwrap(); + let step = ScenarioStep::new_from_str("then everyone accepts it", StepKind::Given).unwrap(); + assert_eq!(step.kind(), StepKind::Then); + assert_eq!(step.text(), "everyone accepts it"); + } + + #[test] + fn parses_and() { + let step = ScenarioStep::new_from_str("and everyone accepts it", StepKind::Then).unwrap(); assert_eq!(step.kind(), StepKind::Then); assert_eq!(step.text(), "everyone accepts it"); } diff --git a/subplot.md b/subplot.md index 59e9736..a2b17b8 100644 --- a/subplot.md +++ b/subplot.md @@ -503,8 +503,12 @@ then bar was done function: precond_foo - when: I do bar function: do_bar +- when: I do foobar + function: do_foobar - then: bar was done function: bar_was_done +- then: foobar was done + function: foobar_was_done ~~~ ### Python functions (f.py) @@ -512,10 +516,15 @@ then bar was done ~~~{.file #f.py .python .numberLines} def precond_foo(ctx): ctx['bar_done'] = False + ctx['foobar_done'] = False def do_bar(ctx): ctx['bar_done'] = True def bar_was_done(ctx): assert_eq(ctx['bar_done'], True) +def do_foobar(ctx): + ctx['foobar_done'] = True +def foobar_was_done(ctx): + assert_eq(ctx['foobar_done'], True) ~~~ @@ -544,6 +553,56 @@ then program finished successfully ~~~ +Keywords +----------------------------------------------------------------------------- + +Subplot supports the keywords **given**, **when**, and **then**, and +the aliases **and** and **but**. The aliases stand for the same +(effective) keyword as the previous step in the scenario. This chapter +has scenarios to check the keywords and aliases in various +combinations. + +### All the keywords + +~~~scenario +given file allkeywords.md +given file b.yaml +given file f.py +when I run sp-docgen allkeywords.md -o foo.pdf +then file foo.pdf exists +when I run sp-codegen --run allkeywords.md -o test.py +then scenario "All keywords" was run +then step "given precondition foo" was run +then step "when I do bar" was run +then step "then bar was done" was run +then program finished successfully +~~~ + +~~~{.file #allkeywords.md .markdown .numberLines} +--- +title: All the keywords scenario +bindings: b.yaml +functions: f.py +... + +# All keywords + +This uses all the keywords. + +```scenario +given precondition foo +when I do bar +and I do foobar +then bar was done +but foobar was done +``` +~~~ + + +### Repeated keywords + +### + Empty lines in scenarios ----------------------------------------------------------------------------- -- cgit v1.2.1