diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 2cb26e7c..d06be3e4 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -8,6 +8,6 @@ updates: - package-ecosystem: github-actions directory: / - labels: ["enhancement", "github_actions", "k::dependencies"] + labels: ["enhancement", "github_actions", "k::dependencies", "k::toolchain"] schedule: interval: daily diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index 1c1c088d..f4a9dde7 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -15,7 +15,7 @@ jobs: cargo-audit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@v1 with: toolchain: stable diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 035eb92c..a68f656a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,14 +21,7 @@ jobs: ################ pr: - if: ${{ github.event_name == 'pull_request' - && needs.clippy.result == 'success' - && needs.feature.result == 'success' - && needs.msrv.result == 'success' - && needs.rustdoc.result == 'success' - && needs.rustfmt.result == 'success' - && needs.test.result == 'success' - && needs.test-book.result == 'success' }} + if: ${{ always() && github.event_name == 'pull_request' }} needs: - clippy - feature @@ -39,7 +32,13 @@ jobs: - test-book runs-on: ubuntu-latest steps: - - run: true + - run: ${{ needs.clippy.result == 'success' + && needs.feature.result == 'success' + && needs.msrv.result == 'success' + && needs.rustdoc.result == 'success' + && needs.rustfmt.result == 'success' + && needs.test.result == 'success' + && needs.test-book.result == 'success' }} @@ -51,7 +50,7 @@ jobs: clippy: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@v1 with: toolchain: stable @@ -62,7 +61,7 @@ jobs: rustfmt: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@v1 with: toolchain: nightly @@ -91,7 +90,7 @@ jobs: - tracing runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@v1 with: toolchain: nightly @@ -113,14 +112,14 @@ jobs: strategy: fail-fast: false matrix: - msrv: ["1.87.0"] + msrv: ["1.88.0"] crate: - cucumber-codegen - cucumber os: ["ubuntu", "macOS", "windows"] runs-on: ${{ matrix.os }}-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@v1 with: toolchain: nightly @@ -143,7 +142,7 @@ jobs: os: ["ubuntu", "macOS", "windows"] runs-on: ${{ matrix.os }}-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@v1 with: toolchain: ${{ matrix.toolchain }} @@ -164,7 +163,7 @@ jobs: os: ["ubuntu", "macOS", "windows"] runs-on: ${{ matrix.os }}-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@v1 with: toolchain: stable @@ -188,14 +187,18 @@ jobs: - cucumber runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@v1 with: toolchain: nightly + # TODO: Use `deps=yes` always once new version of `anstyle-parse` crate + # is released. - run: make cargo.doc crate=${{ matrix.crate }} private=yes docsrs=yes open=no + deps=${{ (matrix.crate == 'cucumber' && 'no') + || 'yes' }} env: RUSTFLAGS: -D warnings @@ -212,7 +215,7 @@ jobs: needs: ["release-github"] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@v1 with: toolchain: stable @@ -238,7 +241,7 @@ jobs: - test-book runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Parse release version id: release @@ -290,7 +293,7 @@ jobs: needs: ["test-book"] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: peaceiris/actions-mdbook@v2 - run: make book.build diff --git a/CHANGELOG.md b/CHANGELOG.md index ada5d03d..cc889a6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,14 +6,29 @@ All user visible changes to `cucumber` crate will be documented in this file. Th -## [0.22.0] · 2024-??-?? (unreleased) -[0.22.0]: /../../tree/v0.22.0 +## [0.22.1] · 2025-12-23 +[0.22.1]: https://github.com/cucumber-rs/cucumber/tree/v0.22.1 -[Diff](/../../compare/v0.21.1...v0.22.0) | [Milestone](/../../milestone/28) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.22.0...v0.22.1) | [Milestone](https://github.com/cucumber-rs/cucumber/milestone/31) + +### Fixed + +- Incorrectly disallowed spaces inside placeholders for `Examples`. ([#388], [#387]) + +[#387]: https://github.com/cucumber-rs/cucumber/issues/387 +[#388]: https://github.com/cucumber-rs/cucumber/pull/388 + + + + +## [0.22.0] · 2025-12-12 +[0.22.0]: https://github.com/cucumber-rs/cucumber/tree/v0.22.0 + +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.21.1...v0.22.0) | [Milestone](https://github.com/cucumber-rs/cucumber/milestone/28) ### BC Breaks -- Bumped up [MSRV] to 1.87 to get rid of `once_cell` crate, for `#[expect]` attribute usage, and because of migration to 2024 edition. ([4010c1ad], [f1307038], [b46930c3], [9705253b], [0c7dfc3c]) +- Bumped up [MSRV] to 1.88 to get rid of `once_cell` crate, for `#[expect]` attribute usage, and because of migration to 2024 edition. ([4010c1ad], [f1307038], [b46930c3], [9705253b], [0c7dfc3c], [a4cbd3d2]) - Replaced `Arc` with `PartialEq`/`Hash` pointer-optimized `Source` in `event`s: ([#352]) - `Source` in `event::Cucumber::Feature`. - `Source` in `event::Feature::Rule`. @@ -26,41 +41,50 @@ All user visible changes to `cucumber` crate will be documented in this file. Th - `event::Scenario::background_step_started()`, `event::Scenario::background_step_passed()` and `event::Scenario::background_step_skipped()`. - Kept only currently executed row of `Examples` table in expanded `Scenario Outline`s. ([#371], [#369]) +### Added + +- `CUCUMBER_FILTER_TAGS` environment variable support. ([#372]) + ### Fixed - Performance degradation on large `.feature` files. ([#352], [#331]) +- `clippy::trivial_regex` lint triggering on `#[given]`/`#[when]`/`#[then]` steps without regular expression. ([81acba84], [#384]) -[#331]: /../../issues/331 -[#352]: /../../pull/352 -[#369]: /../../issues/369 -[#371]: /../../pull/371 -[0c7dfc3c]: /../../commit/0c7dfc3c80f0f58ce9a52f252485d1d14e6eb0ed -[4010c1ad]: /../../commit/4010c1ad6a53d6b7f0b28cefea73c8c13e880e9f -[9705253b]: /../../commit/9705253bda5caadfe3eea91f50420222158dd944 -[b46930c3]: /../../commit/b46930c32ef5ae490df8063905144a45de27eda1 -[f1307038]: /../../commit/f1307038cb6b1e38c1cc259a0e09fb583033d0cf +[#331]: https://github.com/cucumber-rs/cucumber/issues/331 +[#352]: https://github.com/cucumber-rs/cucumber/pull/352 +[#369]: https://github.com/cucumber-rs/cucumber/issues/369 +[#371]: https://github.com/cucumber-rs/cucumber/pull/371 +[#372]: https://github.com/cucumber-rs/cucumber/pull/372 +[#384]: https://github.com/cucumber-rs/cucumber/issues/384 +[0c7dfc3c]: https://github.com/cucumber-rs/cucumber/commit/0c7dfc3c80f0f58ce9a52f252485d1d14e6eb0ed +[4010c1ad]: https://github.com/cucumber-rs/cucumber/commit/4010c1ad6a53d6b7f0b28cefea73c8c13e880e9f +[81acba84]: https://github.com/cucumber-rs/cucumber/commit/81acba84697a5b04c45e2c5d5446f1ffbe289632 +[9705253b]: https://github.com/cucumber-rs/cucumber/commit/9705253bda5caadfe3eea91f50420222158dd944 +[a4cbd3d2]: https://github.com/cucumber-rs/cucumber/commit/a4cbd3d282fe8e01f05609eabea6410c0e2b46a3 +[b46930c3]: https://github.com/cucumber-rs/cucumber/commit/b46930c32ef5ae490df8063905144a45de27eda1 +[f1307038]: https://github.com/cucumber-rs/cucumber/commit/f1307038cb6b1e38c1cc259a0e09fb583033d0cf ## [0.21.1] · 2024-06-16 -[0.21.1]: /../../tree/v0.21.1 +[0.21.1]: https://github.com/cucumber-rs/cucumber/tree/v0.21.1 -[Diff](/../../compare/v0.21.0...v0.21.1) | [Milestone](/../../milestone/29) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.21.0...v0.21.1) | [Milestone](https://github.com/cucumber-rs/cucumber/milestone/29) ### Fixed - Wrong case of statuses reported in `writer::Json`. ([#335]) -[#335]: /../../pull/335 +[#335]: https://github.com/cucumber-rs/cucumber/pull/335 ## [0.21.0] · 2024-04-22 -[0.21.0]: /../../tree/v0.21.0 +[0.21.0]: https://github.com/cucumber-rs/cucumber/tree/v0.21.0 -[Diff](/../../compare/v0.20.2...v0.21.0) | [Milestone](/../../milestone/26) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.20.2...v0.21.0) | [Milestone](https://github.com/cucumber-rs/cucumber/milestone/26) ### BC Breaks @@ -71,49 +95,49 @@ All user visible changes to `cucumber` crate will be documented in this file. Th - Possible truncation of long output messages. ([#333], [#332]) -[#324]: /../../pull/324 -[#332]: /../../issues/332 -[#333]: /../../pull/333 +[#324]: https://github.com/cucumber-rs/cucumber/pull/324 +[#332]: https://github.com/cucumber-rs/cucumber/issues/332 +[#333]: https://github.com/cucumber-rs/cucumber/pull/333 ## [0.20.2] · 2023-12-04 -[0.20.2]: /../../tree/v0.20.2 +[0.20.2]: https://github.com/cucumber-rs/cucumber/tree/v0.20.2 -[Diff](/../../compare/v0.20.1...v0.20.2) | [Milestone](/../../milestone/27) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.20.1...v0.20.2) | [Milestone](https://github.com/cucumber-rs/cucumber/milestone/27) ### Fixed - Ignored verbosity when printing `World` on hook/background step failure. ([#313]) -[#313]: /../../pull/313 +[#313]: https://github.com/cucumber-rs/cucumber/pull/313 ## [0.20.1] · 2023-10-16 -[0.20.1]: /../../tree/v0.20.1 +[0.20.1]: https://github.com/cucumber-rs/cucumber/tree/v0.20.1 -[Diff](/../../compare/v0.20.0...v0.20.1) | [Milestone](/../../milestone/25) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.20.0...v0.20.1) | [Milestone](https://github.com/cucumber-rs/cucumber/milestone/25) ### Fixed - Incorrect terminal width detection when its height is low. ([#298]) - Incorrect terminal lines clearing in interactive mode. ([#300], [#302], [#299]) -[#298]: /../../pull/298 -[#299]: /../../issues/299 -[#300]: /../../pull/300 -[#302]: /../../pull/302 +[#298]: https://github.com/cucumber-rs/cucumber/pull/298 +[#299]: https://github.com/cucumber-rs/cucumber/issues/299 +[#300]: https://github.com/cucumber-rs/cucumber/pull/300 +[#302]: https://github.com/cucumber-rs/cucumber/pull/302 ## [0.20.0] · 2023-07-10 -[0.20.0]: /../../tree/v0.20.0 +[0.20.0]: https://github.com/cucumber-rs/cucumber/tree/v0.20.0 -[Diff](/../../compare/v0.19.1...v0.20.0) | [Milestone](/../../milestone/24) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.19.1...v0.20.0) | [Milestone](https://github.com/cucumber-rs/cucumber/milestone/24) ### BC Breaks @@ -131,36 +155,36 @@ All user visible changes to `cucumber` crate will be documented in this file. Th - Clearing lines that are wrapped because of terminal width. ([#272], [#273]) -[#213]: /../../issues/213 -[#258]: /../../pull/258 -[#261]: /../../pull/261 -[#264]: /../../issues/264 -[#265]: /../../pull/265 -[#272]: /../../discussions/272 -[#273]: /../../pull/273 -[#288]: /../../pull/288 +[#213]: https://github.com/cucumber-rs/cucumber/issues/213 +[#258]: https://github.com/cucumber-rs/cucumber/pull/258 +[#261]: https://github.com/cucumber-rs/cucumber/pull/261 +[#264]: https://github.com/cucumber-rs/cucumber/issues/264 +[#265]: https://github.com/cucumber-rs/cucumber/pull/265 +[#272]: https://github.com/cucumber-rs/cucumber/discussions/272 +[#273]: https://github.com/cucumber-rs/cucumber/pull/273 +[#288]: https://github.com/cucumber-rs/cucumber/pull/288 ## [0.19.1] · 2022-12-29 -[0.19.1]: /../../tree/v0.19.1 +[0.19.1]: https://github.com/cucumber-rs/cucumber/tree/v0.19.1 -[Diff](/../../compare/v0.19.0...v0.19.1) | [Milestone](/../../milestone/23) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.19.0...v0.19.1) | [Milestone](https://github.com/cucumber-rs/cucumber/milestone/23) ### Fixed - Using autodetect for colors on `color=always|never` CLI options. ([#253]) -[#253]: /../../pull/253 +[#253]: https://github.com/cucumber-rs/cucumber/pull/253 ## [0.19.0] · 2022-12-16 -[0.19.0]: /../../tree/v0.19.0 +[0.19.0]: https://github.com/cucumber-rs/cucumber/tree/v0.19.0 -[Diff](/../../compare/v0.18.0...v0.19.0) | [Milestone](/../../milestone/22) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.18.0...v0.19.0) | [Milestone](https://github.com/cucumber-rs/cucumber/milestone/22) ### BC Breaks @@ -184,17 +208,17 @@ All user visible changes to `cucumber` crate will be documented in this file. Th - `@serial` `Scenario`s continue running after failure when `--fail-fast()` CLI option is specified. ([#252]) -[#251]: /../../pull/251 -[#252]: /../../pull/252 -[56456e66]: /../../commit/56456e666be41b4190f62fecaf727042ed69c15a +[#251]: https://github.com/cucumber-rs/cucumber/pull/251 +[#252]: https://github.com/cucumber-rs/cucumber/pull/252 +[56456e66]: https://github.com/cucumber-rs/cucumber/commit/56456e666be41b4190f62fecaf727042ed69c15a ## [0.18.0] · 2022-12-07 -[0.18.0]: /../../tree/v0.18.0 +[0.18.0]: https://github.com/cucumber-rs/cucumber/tree/v0.18.0 -[Diff](/../../compare/v0.17.0...v0.18.0) | [Milestone](/../../milestone/21) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.17.0...v0.18.0) | [Milestone](https://github.com/cucumber-rs/cucumber/milestone/21) ### BC Breaks @@ -204,16 +228,16 @@ All user visible changes to `cucumber` crate will be documented in this file. Th - Not panicking on `fail_on_skipped()` with retries. ([#250], [#249]) -[#249]: /../../issues/249 -[#250]: /../../pull/250 +[#249]: https://github.com/cucumber-rs/cucumber/issues/249 +[#250]: https://github.com/cucumber-rs/cucumber/pull/250 ## [0.17.0] · 2022-11-23 -[0.17.0]: /../../tree/v0.17.0 +[0.17.0]: https://github.com/cucumber-rs/cucumber/tree/v0.17.0 -[Diff](/../../compare/v0.16.0...v0.17.0) | [Milestone](/../../milestone/20) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.16.0...v0.17.0) | [Milestone](https://github.com/cucumber-rs/cucumber/milestone/20) ### BC Breaks @@ -223,17 +247,17 @@ All user visible changes to `cucumber` crate will be documented in this file. Th - Uncaught panics of user code, when they happen before first poll of the returned `Future`s. ([#246]) -[#245]: /../../discussions/245 -[#246]: /../../pull/246 +[#245]: https://github.com/cucumber-rs/cucumber/discussions/245 +[#246]: https://github.com/cucumber-rs/cucumber/pull/246 [0170-1]: https://docs.rs/cucumber/0.17.0/cucumber/struct.Cucumber.html#method.after ## [0.16.0] · 2022-11-09 -[0.16.0]: /../../tree/v0.16.0 +[0.16.0]: https://github.com/cucumber-rs/cucumber/tree/v0.16.0 -[Diff](/../../compare/v0.15.3...v0.16.0) | [Milestone](/../../milestone/19) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.15.3...v0.16.0) | [Milestone](https://github.com/cucumber-rs/cucumber/milestone/19) ### BC Breaks @@ -247,31 +271,31 @@ All user visible changes to `cucumber` crate will be documented in this file. Th - `--fail-fast` CLI option causing execution to hang. ([#242], [#241]) -[#241]: /../../issues/241 -[#242]: /../../pull/242 -[7f52d4a5]: /../../commit/7f52d4a5faa3b69bec6c7fb765b50455cf7802aa +[#241]: https://github.com/cucumber-rs/cucumber/issues/241 +[#242]: https://github.com/cucumber-rs/cucumber/pull/242 +[7f52d4a5]: https://github.com/cucumber-rs/cucumber/commit/7f52d4a5faa3b69bec6c7fb765b50455cf7802aa ## [0.15.3] · 2022-11-01 -[0.15.3]: /../../tree/v0.15.3 +[0.15.3]: https://github.com/cucumber-rs/cucumber/tree/v0.15.3 -[Diff](/../../compare/v0.15.2...v0.15.3) | [Milestone](/../../milestone/18) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.15.2...v0.15.3) | [Milestone](https://github.com/cucumber-rs/cucumber/milestone/18) ### Added - `Clone` implementations to all public types where possible. ([#238]) -[#238]: /../../pull/238 +[#238]: https://github.com/cucumber-rs/cucumber/pull/238 ## [0.15.2] · 2022-10-25 -[0.15.2]: /../../tree/v0.15.2 +[0.15.2]: https://github.com/cucumber-rs/cucumber/tree/v0.15.2 -[Diff](/../../compare/v0.15.1...v0.15.2) | [Milestone](/../../milestone/17) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.15.1...v0.15.2) | [Milestone](https://github.com/cucumber-rs/cucumber/milestone/17) ### Changed @@ -282,8 +306,8 @@ All user visible changes to `cucumber` crate will be documented in this file. Th - Parsing error on a `Feature` having comment and tag simultaneously. ([4cad49f8], [cucumber-rs/gherkin#37], [cucumber-rs/gherkin#35]) - `@retry`, `@serial` and `@allow.skipped` tags semantics inheritance. ([#237]) -[#237]: /../../pull/237 -[4cad49f8]: /../../commit/4cad49f8d8f5d0458dcb538aa044a5fff1e6fa10 +[#237]: https://github.com/cucumber-rs/cucumber/pull/237 +[4cad49f8]: https://github.com/cucumber-rs/cucumber/commit/4cad49f8d8f5d0458dcb538aa044a5fff1e6fa10 [cucumber-rs/gherkin#35]: https://github.com/cucumber-rs/gherkin/issues/35 [cucumber-rs/gherkin#37]: https://github.com/cucumber-rs/gherkin/pull/37 @@ -291,53 +315,53 @@ All user visible changes to `cucumber` crate will be documented in this file. Th ## [0.15.1] · 2022-10-12 -[0.15.1]: /../../tree/v0.15.1 +[0.15.1]: https://github.com/cucumber-rs/cucumber/tree/v0.15.1 -[Diff](/../../compare/v0.15.0...v0.15.1) | [Milestone](/../../milestone/16) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.15.0...v0.15.1) | [Milestone](https://github.com/cucumber-rs/cucumber/milestone/16) ### Fixed - Conflicting [`Id`][0151-1]s of CLI options. ([#232], [#231]) -[#231]: /../../issues/231 -[#232]: /../../pull/232 +[#231]: https://github.com/cucumber-rs/cucumber/issues/231 +[#232]: https://github.com/cucumber-rs/cucumber/pull/232 [0151-1]: https://docs.rs/clap/latest/clap/struct.Id.html ## [0.15.0] · 2022-10-05 -[0.15.0]: /../../tree/v0.15.0 +[0.15.0]: https://github.com/cucumber-rs/cucumber/tree/v0.15.0 -[Diff](/../../compare/v0.14.2...v0.15.0) | [Milestone](/../../milestone/15) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.14.2...v0.15.0) | [Milestone](https://github.com/cucumber-rs/cucumber/milestone/15) ### BC Breaks - Upgraded [`clap`] crate to 4.0 version. ([#230]) -[#230]: /../../pull/230 +[#230]: https://github.com/cucumber-rs/cucumber/pull/230 ## [0.14.2] · 2022-09-19 -[0.14.2]: /../../tree/v0.14.2 +[0.14.2]: https://github.com/cucumber-rs/cucumber/tree/v0.14.2 -[Diff](/../../compare/v0.14.1...v0.14.2) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.14.1...v0.14.2) ### Fixed - `#[derive(World)]` macro being unhygienic regarding custom `Result` types. ([186af8b1]) -[186af8b1]: /../../commit/186af8b1de37275b308897e2e30d6982830b0278 +[186af8b1]: https://github.com/cucumber-rs/cucumber/commit/186af8b1de37275b308897e2e30d6982830b0278 ## [0.14.1] · 2022-09-12 -[0.14.1]: /../../tree/v0.14.1 +[0.14.1]: https://github.com/cucumber-rs/cucumber/tree/v0.14.1 -[Diff](/../../compare/v0.14.0...v0.14.1) | [Milestone](/../../milestone/14) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.14.0...v0.14.1) | [Milestone](https://github.com/cucumber-rs/cucumber/milestone/14) ### Changed @@ -351,18 +375,18 @@ All user visible changes to `cucumber` crate will be documented in this file. Th - `junit-report` crate to 0.8 version to fix [RUSTSEC-2022-0048]. ([#229], [#226]) -[#226]: /../../issues/226 -[#229]: /../../pull/229 -[ad0bb22f]: /../../commit/ad0bb22f9234099985cb1966f92ccefbc97060fb +[#226]: https://github.com/cucumber-rs/cucumber/issues/226 +[#229]: https://github.com/cucumber-rs/cucumber/pull/229 +[ad0bb22f]: https://github.com/cucumber-rs/cucumber/commit/ad0bb22f9234099985cb1966f92ccefbc97060fb [RUSTSEC-2022-0048]: https://rustsec.org/advisories/RUSTSEC-2022-0048.html ## [0.14.0] · 2022-09-08 -[0.14.0]: /../../tree/v0.14.0 +[0.14.0]: https://github.com/cucumber-rs/cucumber/tree/v0.14.0 -[Diff](/../../compare/v0.13.0...v0.14.0) | [Milestone](/../../milestone/13) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.13.0...v0.14.0) | [Milestone](https://github.com/cucumber-rs/cucumber/milestone/13) ### BC Breaks @@ -391,56 +415,56 @@ All user visible changes to `cucumber` crate will be documented in this file. Th - Provided default CLI options are now global (allowed to be specified after custom subcommands). ([#216], [#215]) - Stripped `CARGO_MANIFEST_DIR` from output paths whenever is possible. ([#221]) -[#212]: /../../issues/212 -[#215]: /../../issues/215 -[#216]: /../../pull/216 -[#217]: /../../issues/217 -[#219]: /../../pull/219 -[#220]: /../../pull/220 -[#221]: /../../pull/221 -[#223]: /../../pull/223 -[8ad5cc86]: /../../commit/8ad5cc866bb9d6b49470790e3b0dd40690f63a09 -[cf055ac0]: /../../commit/cf055ac06c7b72f572882ce15d6a60da92ad60a0 -[fbd08ec2]: /../../commit/fbd08ec24dbd036c89f5f0af4d936b616790a166 +[#212]: https://github.com/cucumber-rs/cucumber/issues/212 +[#215]: https://github.com/cucumber-rs/cucumber/issues/215 +[#216]: https://github.com/cucumber-rs/cucumber/pull/216 +[#217]: https://github.com/cucumber-rs/cucumber/issues/217 +[#219]: https://github.com/cucumber-rs/cucumber/pull/219 +[#220]: https://github.com/cucumber-rs/cucumber/pull/220 +[#221]: https://github.com/cucumber-rs/cucumber/pull/221 +[#223]: https://github.com/cucumber-rs/cucumber/pull/223 +[8ad5cc86]: https://github.com/cucumber-rs/cucumber/commit/8ad5cc866bb9d6b49470790e3b0dd40690f63a09 +[cf055ac0]: https://github.com/cucumber-rs/cucumber/commit/cf055ac06c7b72f572882ce15d6a60da92ad60a0 +[fbd08ec2]: https://github.com/cucumber-rs/cucumber/commit/fbd08ec24dbd036c89f5f0af4d936b616790a166 [0140-1]: book/src/output/intellij.md ## [0.13.0] · 2022-03-29 -[0.13.0]: /../../tree/v0.13.0 +[0.13.0]: https://github.com/cucumber-rs/cucumber/tree/v0.13.0 -[Diff](/../../compare/v0.12.2...v0.13.0) | [Milestone](/../../milestone/12) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.12.2...v0.13.0) | [Milestone](https://github.com/cucumber-rs/cucumber/milestone/12) ### BC Breaks - Upgraded [`gherkin`] crate to 0.12 version. ([#211]) -[#211]: /../../pull/211 +[#211]: https://github.com/cucumber-rs/cucumber/pull/211 ## [0.12.2] · 2022-03-28 -[0.12.2]: /../../tree/v0.12.2 +[0.12.2]: https://github.com/cucumber-rs/cucumber/tree/v0.12.2 -[Diff](/../../compare/v0.12.1...v0.12.2) | [Milestone](/../../milestone/10) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.12.1...v0.12.2) | [Milestone](https://github.com/cucumber-rs/cucumber/milestone/10) ### Changed - [`Cucumber::after`][0122-1] now gets the `World` instance even if some `Step` or a `Hook` before it has failed. ([#209], [#207]) -[#207]: /../../issues/207 -[#209]: /../../pull/209 +[#207]: https://github.com/cucumber-rs/cucumber/issues/207 +[#209]: https://github.com/cucumber-rs/cucumber/pull/209 [0122-1]: https://docs.rs/cucumber/0.12.2/cucumber/struct.Cucumber.html#method.after ## [0.12.1] · 2022-03-09 -[0.12.1]: /../../tree/v0.12.1 +[0.12.1]: https://github.com/cucumber-rs/cucumber/tree/v0.12.1 -[Diff](/../../compare/v0.12.0...v0.12.1) | [Milestone](/../../milestone/11) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.12.0...v0.12.1) | [Milestone](https://github.com/cucumber-rs/cucumber/milestone/11) ### Security updated @@ -452,9 +476,9 @@ All user visible changes to `cucumber` crate will be documented in this file. Th ## [0.12.0] · 2022-02-10 -[0.12.0]: /../../tree/v0.12.0 +[0.12.0]: https://github.com/cucumber-rs/cucumber/tree/v0.12.0 -[Diff](/../../compare/v0.11.3...v0.12.0) | [Milestone](/../../milestone/9) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.11.3...v0.12.0) | [Milestone](https://github.com/cucumber-rs/cucumber/milestone/9) ### BC Breaks @@ -469,47 +493,47 @@ All user visible changes to `cucumber` crate will be documented in this file. Th - Book examples failing on Windows. ([#202], [#200]) - `{string}` parameter in [Cucumber Expressions] returning its enclosing quotes. ([cucumber-rs/cucumber-expressions#7]) -[#200]: /../../issues/200 -[#202]: /../../pull/202 -[#204]: /../../pull/204 +[#200]: https://github.com/cucumber-rs/cucumber/issues/200 +[#202]: https://github.com/cucumber-rs/cucumber/pull/202 +[#204]: https://github.com/cucumber-rs/cucumber/pull/204 [cucumber-rs/cucumber-expressions#7]: https://github.com/cucumber-rs/cucumber-expressions/issues/7 ## [0.11.3] · 2022-01-31 -[0.11.3]: /../../tree/v0.11.3 +[0.11.3]: https://github.com/cucumber-rs/cucumber/tree/v0.11.3 -[Diff](/../../compare/v0.11.2...v0.11.3) | [Milestone](/../../milestone/8) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.11.2...v0.11.3) | [Milestone](https://github.com/cucumber-rs/cucumber/milestone/8) ### Fixed - `parser::Basic` skipping files named `.feature`. ([#201]) -[#201]: /../../pull/201 +[#201]: https://github.com/cucumber-rs/cucumber/pull/201 ## [0.11.2] · 2022-01-19 -[0.11.2]: /../../tree/v0.11.2 +[0.11.2]: https://github.com/cucumber-rs/cucumber/tree/v0.11.2 -[Diff](/../../compare/v0.11.1...v0.11.2) | [Milestone](/../../milestone/7) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.11.1...v0.11.2) | [Milestone](https://github.com/cucumber-rs/cucumber/milestone/7) ### Fixed - Skipped `Background` steps not failing in `writer::FailOnSkipped`. ([#199], [#198]) -[#198]: /../../issues/198 -[#199]: /../../pull/199 +[#198]: https://github.com/cucumber-rs/cucumber/issues/198 +[#199]: https://github.com/cucumber-rs/cucumber/pull/199 ## [0.11.1] · 2022-01-07 -[0.11.1]: /../../tree/v0.11.1 +[0.11.1]: https://github.com/cucumber-rs/cucumber/tree/v0.11.1 -[Diff](/../../compare/v0.11.0...v0.11.1) | [Milestone](/../../milestone/6) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.11.0...v0.11.1) | [Milestone](https://github.com/cucumber-rs/cucumber/milestone/6) ### Added @@ -519,16 +543,16 @@ All user visible changes to `cucumber` crate will be documented in this file. Th - Optimized `runner::Basic` to not wait the whole batch to complete before executing next `Scenario`s. ([#195]) -[#195]: /../../pull/195 -[#196]: /../../pull/196 +[#195]: https://github.com/cucumber-rs/cucumber/pull/195 +[#196]: https://github.com/cucumber-rs/cucumber/pull/196 ## [0.11.0] · 2022-01-03 -[0.11.0]: /../../tree/v0.11.0 +[0.11.0]: https://github.com/cucumber-rs/cucumber/tree/v0.11.0 -[Diff](/../../compare/v0.10.2...v0.11.0) | [Milestone](/../../milestone/3) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.10.2...v0.11.0) | [Milestone](https://github.com/cucumber-rs/cucumber/milestone/3) ### BC Breaks @@ -570,29 +594,29 @@ All user visible changes to `cucumber` crate will be documented in this file. Th - Docstring and name expansion in `Scenario Outline`. ([#178], [#172]) - `writer::Summarized` ignoring `Coloring` options. ([#189], [#186]) -[#147]: /../../pull/147 -[#151]: /../../pull/151 -[#155]: /../../issues/155 -[#157]: /../../pull/157 -[#159]: /../../pull/159 -[#160]: /../../pull/160 -[#162]: /../../pull/162 -[#163]: /../../pull/163 -[#164]: /../../issues/164 -[#165]: /../../pull/165 -[#166]: /../../pull/166 -[#168]: /../../pull/168 -[#172]: /../../issues/172 -[#178]: /../../pull/178 -[#181]: /../../pull/181 -[#182]: /../../pull/182 -[#186]: /../../issues/186 -[#188]: /../../pull/188 -[#189]: /../../pull/189 -[#192]: /../../issues/192 -[#193]: /../../pull/193 -[cef3d480]: /../../commit/cef3d480579190425461ddb04a1248675248351e -[e2a41ab0]: /../../commit/e2a41ab0a4398fe26075f0b066cc67e6e8a19e6c +[#147]: https://github.com/cucumber-rs/cucumber/pull/147 +[#151]: https://github.com/cucumber-rs/cucumber/pull/151 +[#155]: https://github.com/cucumber-rs/cucumber/issues/155 +[#157]: https://github.com/cucumber-rs/cucumber/pull/157 +[#159]: https://github.com/cucumber-rs/cucumber/pull/159 +[#160]: https://github.com/cucumber-rs/cucumber/pull/160 +[#162]: https://github.com/cucumber-rs/cucumber/pull/162 +[#163]: https://github.com/cucumber-rs/cucumber/pull/163 +[#164]: https://github.com/cucumber-rs/cucumber/issues/164 +[#165]: https://github.com/cucumber-rs/cucumber/pull/165 +[#166]: https://github.com/cucumber-rs/cucumber/pull/166 +[#168]: https://github.com/cucumber-rs/cucumber/pull/168 +[#172]: https://github.com/cucumber-rs/cucumber/issues/172 +[#178]: https://github.com/cucumber-rs/cucumber/pull/178 +[#181]: https://github.com/cucumber-rs/cucumber/pull/181 +[#182]: https://github.com/cucumber-rs/cucumber/pull/182 +[#186]: https://github.com/cucumber-rs/cucumber/issues/186 +[#188]: https://github.com/cucumber-rs/cucumber/pull/188 +[#189]: https://github.com/cucumber-rs/cucumber/pull/189 +[#192]: https://github.com/cucumber-rs/cucumber/issues/192 +[#193]: https://github.com/cucumber-rs/cucumber/pull/193 +[cef3d480]: https://github.com/cucumber-rs/cucumber/commit/cef3d480579190425461ddb04a1248675248351e +[e2a41ab0]: https://github.com/cucumber-rs/cucumber/commit/e2a41ab0a4398fe26075f0b066cc67e6e8a19e6c [0110-1]: https://llg.cubic.org/docs/junit [0110-2]: https://github.com/cucumber/cucumber-json-schema @@ -600,37 +624,37 @@ All user visible changes to `cucumber` crate will be documented in this file. Th ## [0.10.2] · 2021-11-03 -[0.10.2]: /../../tree/v0.10.2 +[0.10.2]: https://github.com/cucumber-rs/cucumber/tree/v0.10.2 -[Diff](/../../compare/v0.10.1...v0.10.2) | [Milestone](/../../milestone/5) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.10.1...v0.10.2) | [Milestone](https://github.com/cucumber-rs/cucumber/milestone/5) ### Fixed - Multiple `WorldInit` derivers conflicting implementations in a single module. ([#150]) -[#150]: /../../pull/150 +[#150]: https://github.com/cucumber-rs/cucumber/pull/150 ## [0.10.1] · 2021-10-29 -[0.10.1]: /../../tree/v0.10.1 +[0.10.1]: https://github.com/cucumber-rs/cucumber/tree/v0.10.1 -[Diff](/../../compare/v0.10.0...v0.10.1) | [Milestone](/../../milestone/4) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.10.0...v0.10.1) | [Milestone](https://github.com/cucumber-rs/cucumber/milestone/4) ### Fixed - Console output hanging because of executing wrong `Concurrent` `Scenario`s. ([#146]) -[#146]: /../../pull/146 +[#146]: https://github.com/cucumber-rs/cucumber/pull/146 ## [0.10.0] · 2021-10-26 -[0.10.0]: /../../tree/v0.10.0 +[0.10.0]: https://github.com/cucumber-rs/cucumber/tree/v0.10.0 -[Diff](/../../compare/v0.9.0...v0.10.0) | [Milestone](/../../milestone/2) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.9.0...v0.10.0) | [Milestone](https://github.com/cucumber-rs/cucumber/milestone/2) ### BC Breaks @@ -652,21 +676,21 @@ All user visible changes to `cucumber` crate will be documented in this file. Th - Error on a step matching multiple step functions ([#143]). - `timestamps` Cargo feature that enables collecting of timestamps for all the happened events during tests execution (useful for `Writer`s which format requires them) ([#145]). -[#128]: /../../pull/128 -[#136]: /../../pull/136 -[#137]: /../../pull/137 -[#142]: /../../pull/142 -[#143]: /../../pull/143 -[#144]: /../../pull/144 -[#145]: /../../pull/145 +[#128]: https://github.com/cucumber-rs/cucumber/pull/128 +[#136]: https://github.com/cucumber-rs/cucumber/pull/136 +[#137]: https://github.com/cucumber-rs/cucumber/pull/137 +[#142]: https://github.com/cucumber-rs/cucumber/pull/142 +[#143]: https://github.com/cucumber-rs/cucumber/pull/143 +[#144]: https://github.com/cucumber-rs/cucumber/pull/144 +[#145]: https://github.com/cucumber-rs/cucumber/pull/145 ## [0.9.0] · 2021-07-19 -[0.9.0]: /../../tree/v0.9.0 +[0.9.0]: https://github.com/cucumber-rs/cucumber/tree/v0.9.0 -[Diff](/../../compare/v0.8.4...v0.9.0) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.8.4...v0.9.0) ### BC Breaks @@ -685,9 +709,9 @@ All user visible changes to `cucumber` crate will be documented in this file. Th ## [0.8.4] · 2021-02-18 -[0.8.4]: /../../tree/v0.8.4 +[0.8.4]: https://github.com/cucumber-rs/cucumber/tree/v0.8.4 -[Diff](/../../compare/v0.8.3...v0.8.4) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.8.3...v0.8.4) ### Added @@ -698,9 +722,9 @@ All user visible changes to `cucumber` crate will be documented in this file. Th ## [0.8.3] · 2021-02-09 -[0.8.3]: /../../tree/v0.8.3 +[0.8.3]: https://github.com/cucumber-rs/cucumber/tree/v0.8.3 -[Diff](/../../compare/v0.8.2...v0.8.3) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.8.2...v0.8.3) ### Changed @@ -710,9 +734,9 @@ All user visible changes to `cucumber` crate will be documented in this file. Th ## [0.8.2] · 2021-01-30 -[0.8.2]: /../../tree/v0.8.2 +[0.8.2]: https://github.com/cucumber-rs/cucumber/tree/v0.8.2 -[Diff](/../../compare/v0.8.1...v0.8.2) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.8.1...v0.8.2) ### Added @@ -723,9 +747,9 @@ All user visible changes to `cucumber` crate will be documented in this file. Th ## [0.8.1] · 2021-01-30 -[0.8.1]: /../../tree/v0.8.1 +[0.8.1]: https://github.com/cucumber-rs/cucumber/tree/v0.8.1 -[Diff](/../../compare/v0.8.0...v0.8.1) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.8.0...v0.8.1) ### Added @@ -735,9 +759,9 @@ All user visible changes to `cucumber` crate will be documented in this file. Th ## [0.8.0] · 2021-01-18 -[0.8.0]: /../../tree/v0.8.0 +[0.8.0]: https://github.com/cucumber-rs/cucumber/tree/v0.8.0 -[Diff](/../../compare/v0.7.3...v0.8.0) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.7.3...v0.8.0) ### Added @@ -752,31 +776,31 @@ All user visible changes to `cucumber` crate will be documented in this file. Th - Filtering of tests by tag. ([#67]) - Removed unnecessary dependent traits from `World` trait. -[#67]: /../../issues/67 -[#81]: /../../pull/81 -[#91]: /../../issues/91 +[#67]: https://github.com/cucumber-rs/cucumber/issues/67 +[#81]: https://github.com/cucumber-rs/cucumber/pull/81 +[#91]: https://github.com/cucumber-rs/cucumber/issues/91 ## [0.7.3] · 2020-09-20 -[0.7.3]: /../../tree/v0.7.3 +[0.7.3]: https://github.com/cucumber-rs/cucumber/tree/v0.7.3 -[Diff](/../../compare/v0.7.2...v0.7.3) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.7.2...v0.7.3) ### Fixed - Fix missing `mut` in `t!` macro for regexes — thanks [@stefanpieck](https://github.com/stefanpieck)! ([#68]) -[#68]: /../../issues/68 +[#68]: https://github.com/cucumber-rs/cucumber/issues/68 ## [0.7.2] · 2020-09-14 -[0.7.2]: /../../tree/v0.7.2 +[0.7.2]: https://github.com/cucumber-rs/cucumber/tree/v0.7.2 -[Diff](/../../compare/v0.7.1...v0.7.2) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.7.1...v0.7.2) ### Added @@ -786,9 +810,9 @@ All user visible changes to `cucumber` crate will be documented in this file. Th ## [0.7.1] · 2020-09-09 -[0.7.1]: /../../tree/v0.7.1 +[0.7.1]: https://github.com/cucumber-rs/cucumber/tree/v0.7.1 -[Diff](/../../compare/v0.7.0...v0.7.1) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.7.0...v0.7.1) ### Fixed @@ -798,9 +822,9 @@ All user visible changes to `cucumber` crate will be documented in this file. Th ## [0.7.0] · 2020-09-07 -[0.7.0]: /../../tree/v0.7.0 +[0.7.0]: https://github.com/cucumber-rs/cucumber/tree/v0.7.0 -[Diff](/../../compare/v0.6.8...v0.7.0) +[Diff](https://github.com/cucumber-rs/cucumber/compare/v0.6.8...v0.7.0) ### BC Breaks diff --git a/Cargo.toml b/Cargo.toml index d970a94c..81facd3a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "cucumber" -version = "0.21.1" +version = "0.22.1" edition = "2024" -rust-version = "1.87" +rust-version = "1.88" description = """\ Cucumber testing framework for Rust, with async support. \ Fully native, no external test runners or dependencies.\ @@ -64,12 +64,12 @@ timestamps = [] tracing = ["dep:crossbeam-utils", "dep:tracing", "dep:tracing-subscriber"] [dependencies] -clap = { version = "4.3.2", features = ["derive", "wrap_help"] } +clap = { version = "4.3.2", features = ["derive", "env", "wrap_help"] } console = "0.16" derive_more = { version = "2.0", features = ["as_ref", "debug", "deref", "deref_mut", "display", "error", "from", "from_str", "into"] } either = "1.6" futures = "0.3.17" -gherkin = "0.14" +gherkin = "0.15" globwalk = "0.9" humantime = "2.1" itertools = "0.14" @@ -82,8 +82,8 @@ smart-default = "0.7.1" # "macros" feature dependencies. anyhow = { version = "1.0.58", optional = true } -cucumber-codegen = { version = "=0.21.1", path = "./codegen", optional = true } -cucumber-expressions = { version = "0.4", features = ["into-regex"], optional = true } +cucumber-codegen = { version = "=0.22.1", path = "./codegen", optional = true } +cucumber-expressions = { version = "0.5", features = ["into-regex"], optional = true } inventory = { version = "0.3", optional = true } # "output-json" and/or "libtest" features dependencies. @@ -103,7 +103,8 @@ tracing = { version = "0.1", optional = true } tracing-subscriber = { version = "0.3.16", optional = true } [dev-dependencies] -rand = "0.9" +rand = "0.10" +serial_test = "3.0" tempfile = "3.2" tokio = { version = "1.40", features = ["macros", "rt-multi-thread", "sync", "time"] } diff --git a/LICENSE-MIT b/LICENSE-MIT index ff40298e..3cabd022 100644 --- a/LICENSE-MIT +++ b/LICENSE-MIT @@ -1,4 +1,4 @@ -Copyright (c) 2018-2025 Brendan Molloy , +Copyright (c) 2018-2026 Brendan Molloy , Ilya Solovyiov , Kai Ren diff --git a/Makefile b/Makefile index c4ba459b..f91605ce 100644 --- a/Makefile +++ b/Makefile @@ -43,7 +43,7 @@ test: test.cargo # # Usage: # make cargo.doc [crate=] -# [private=(yes|no)] [docsrs=(no|yes)] +# [private=(yes|no)] [deps=(yes|no)] [docsrs=(no|yes)] # [open=(yes|no)] [clean=(no|yes)] cargo.doc: @@ -55,6 +55,7 @@ endif $(if $(call eq,$(crate),),--workspace,-p $(crate)) \ --all-features \ $(if $(call eq,$(private),no),,--document-private-items) \ + $(if $(call eq,$(deps),no),--no-deps,) \ $(if $(call eq,$(open),no),,--open) diff --git a/README.md b/README.md index dcc2f444..2dfab280 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Cucumber testing framework for Rust =================================== [![crates.io](https://img.shields.io/crates/v/cucumber.svg?maxAge=2592000 "crates.io")](https://crates.io/crates/cucumber) -[![Rust 1.87+](https://img.shields.io/badge/rustc-1.87+-lightgray.svg "Rust 1.87+")](https://blog.rust-lang.org/2025/05/15/Rust-1.87.0) +[![Rust 1.88+](https://img.shields.io/badge/rustc-1.88+-lightgray.svg "Rust 1.88+")](https://blog.rust-lang.org/2025/06/26/Rust-1.88.0) [![Unsafe Forbidden](https://img.shields.io/badge/unsafe-forbidden-success.svg "Unsafe forbidden")](https://github.com/rust-secure-code/safety-dance)\ [![CI](https://github.com/cucumber-rs/cucumber/actions/workflows/ci.yml/badge.svg?branch=main "CI")](https://github.com/cucumber-rs/cucumber/actions?query=workflow%3ACI+branch%3Amain) [![Rust docs](https://docs.rs/cucumber/badge.svg "Rust docs")](https://docs.rs/cucumber) @@ -10,7 +10,7 @@ Cucumber testing framework for Rust An implementation of the [Cucumber] testing framework for Rust. Fully native, no external test runners or dependencies. - Book ([current][1] | [edge][2]) -- [Changelog](https://github.com/cucumber-rs/cucumber/blob/main/CHANGELOG.md) +- [Changelog](https://github.com/cucumber-rs/cucumber/blob/v0.22.1/CHANGELOG.md) @@ -113,8 +113,8 @@ The full gamut of Cucumber's [Gherkin] language is implemented by the [`gherkin` This project is licensed under either of - * Apache License, Version 2.0 ([LICENSE-APACHE](https://github.com/cucumber-rs/cucumber/blob/main/LICENSE-APACHE) or ) - * MIT license ([LICENSE-MIT](https://github.com/cucumber-rs/cucumber/blob/main/LICENSE-MIT) or ) + * Apache License, Version 2.0 ([LICENSE-APACHE](https://github.com/cucumber-rs/cucumber/blob/v0.22.1/LICENSE-APACHE) or ) + * MIT license ([LICENSE-MIT](https://github.com/cucumber-rs/cucumber/blob/v0.22.1/LICENSE-MIT) or ) at your option. diff --git a/book/book.toml b/book/book.toml index f94485a3..8fb4bb05 100644 --- a/book/book.toml +++ b/book/book.toml @@ -2,7 +2,6 @@ title = "Cucumber Rust Book" description = "User guide for Cucumber Rust" language = "en" -multilingual = false authors = [ "Olga Gaponenko (@alvskar)", "Ilya Solovyiov (@ilslv)", diff --git a/book/src/cli.md b/book/src/cli.md index cd949a88..38be11d5 100644 --- a/book/src/cli.md +++ b/book/src/cli.md @@ -17,14 +17,16 @@ Usage: cucumber [OPTIONS] Options: -n, --name Regex to filter scenarios by their name - + [aliases: scenario-name] -t, --tags Tag expression to filter scenarios by. - + Note: Tags from Feature, Rule and Scenario are merged together on filtering, so be careful about conflicting tags on different levels. + [env: CUCUMBER_FILTER_TAGS=] + -i, --input Glob pattern to look for feature files with. If not specified, looks for `*.feature` files in the path configured in the test runner @@ -33,7 +35,7 @@ Options: --fail-fast Run tests until the first failure - + [aliases: ff] --retry @@ -41,7 +43,7 @@ Options: --retry-after Delay between each scenario retry attempt. - + Duration is represented in a human-readable format like `12min5s`. Supported suffixes: - `nsec`, `ns` — nanoseconds. @@ -55,12 +57,12 @@ Options: -v... Verbosity of an output. - + `-v` is default verbosity, `-vv` additionally outputs world on failed steps, `-vvv` additionally outputs step's doc string (if present). --color Coloring policy for a console output - + [default: auto] -h, --help @@ -235,7 +237,7 @@ struct Smoke { #[tokio::main] async fn main() { let opts = cli::Opts::<_, _, _, CustomOpts>::parsed(); - + let pre_pause = if let Some(SubCommand::Smoke(Smoke { pre_pause })) = opts.custom.command { diff --git a/book/src/output/intellij.md b/book/src/output/intellij.md index 7040d5d7..65b2a025 100644 --- a/book/src/output/intellij.md +++ b/book/src/output/intellij.md @@ -5,7 +5,7 @@ IntelliJ Rust (`libtest`) integration Example below is set up to output with the default [`writer::Basic`] if there is no `--format=json` option, or with [`writer::Libtest`] otherwise. ```toml -cucumber = { version = "0.20", features = ["libtest"] } +cucumber = { version = "0.22", features = ["libtest"] } ``` ```rust # extern crate cucumber; diff --git a/book/src/output/json.md b/book/src/output/json.md index f955e728..d7799870 100644 --- a/book/src/output/json.md +++ b/book/src/output/json.md @@ -5,7 +5,7 @@ Cucumber JSON format This requires `output-json` feature to be enabled in `Cargo.toml`: ```toml -cucumber = { version = "0.20", features = ["output-json"] } +cucumber = { version = "0.22", features = ["output-json"] } ``` And configuring output to [`writer::Json`]: diff --git a/book/src/output/junit.md b/book/src/output/junit.md index da00d6cf..cf6edb4c 100644 --- a/book/src/output/junit.md +++ b/book/src/output/junit.md @@ -5,7 +5,7 @@ JUnit XML report This requires `output-junit` feature to be enabled in `Cargo.toml`: ```toml -cucumber = { version = "0.20", features = ["output-junit"] } +cucumber = { version = "0.22", features = ["output-junit"] } ``` And configuring output to [`writer::JUnit`]: diff --git a/book/src/quickstart.md b/book/src/quickstart.md index 31d93379..1c873d9e 100644 --- a/book/src/quickstart.md +++ b/book/src/quickstart.md @@ -8,7 +8,7 @@ To start, let's create a directory called `tests/` in the root of the project an Add this to `Cargo.toml`: ```toml [dev-dependencies] -cucumber = "0.20" +cucumber = "0.22" futures = "0.3" [[test]] @@ -37,7 +37,7 @@ To enable testing of our `simple.feature`, let's add this code to `example.rs`: # use cucumber::{World, given}; -// These `Cat` definitions would normally be inside your project's code, +// These `Cat` definitions would normally be inside your project's code, // not test code, but we create them here for the show case. #[derive(Debug, Default)] struct Cat { @@ -51,7 +51,7 @@ impl Cat { } // `World` is your shared, likely mutable state. -// Cucumber constructs it via `Default::default()` for each scenario. +// Cucumber constructs it via `Default::default()` for each scenario. #[derive(Debug, Default, World)] pub struct AnimalWorld { cat: Cat, @@ -88,7 +88,7 @@ fn main() { > # > #[derive(Debug, World)] > // Accepts both sync/async and fallible/infallible functions. -> #[world(init = Self::new)] +> #[world(init = Self::new)] > pub struct AnimalWorld { > cat: Cat, > } @@ -103,7 +103,7 @@ fn main() { > # fn main() {} > ``` -If we run this, we should see an output like this: +If we run this, we should see an output like this: ![record](rec/quickstart_simple_1.gif) A checkmark `✔` next to the `Given a hungry cat` [step] means that it has been matched, executed and passed. @@ -161,7 +161,7 @@ fn feed_cat(world: &mut AnimalWorld) { # } ``` -Once we run the tests again, we see that two lines are green now and the next one is marked as not yet implemented: +Once we run the tests again, we see that two lines are green now and the next one is marked as not yet implemented: ![record](rec/quickstart_simple_2.gif) Finally, how do we check our result? We expect that this will cause some change in the cat and that the cat will no longer be hungry since it has been fed. The `then` [step] matcher follows to assert this, as our [feature] says: @@ -211,7 +211,7 @@ fn cat_is_fed(world: &mut AnimalWorld) { # } ``` -Once we run the tests, now we see all steps being accounted for and the whole [scenario] passing: +Once we run the tests, now we see all steps being accounted for and the whole [scenario] passing: ![record](rec/quickstart_simple_3.gif) > __TIP__: In addition to assertions, we may also return a `Result<()>` from a [step] matching function. Returning `Err` will cause the [step] to fail. This lets using the `?` operator for more concise step implementations just like in [unit tests](https://doc.rust-lang.org/rust-by-example/testing/unit_testing.html#tests-and-). @@ -261,7 +261,7 @@ fn cat_is_fed(world: &mut AnimalWorld) { # } ``` -And see the test failing: +And see the test failing: ![record](rec/quickstart_simple_fail.gif) > __TIP__: By default, unlike [unit tests](https://doc.rust-lang.org/cargo/commands/cargo-test.html#test-options), failed [step]s don't terminate the execution instantly, and the whole test suite is executed regardless of them. Use `--fail-fast` [CLI] option to stop execution on first failure. @@ -332,7 +332,7 @@ fn hungry_cat(world: &mut AnimalWorld, state: String) { > __NOTE__: We surround the regex with `^..$` to ensure an __exact__ match. This is much more useful when adding more and more [step]s, so they won't accidentally interfere with each other. -[Cucumber] will reuse these [step] matchers: +[Cucumber] will reuse these [step] matchers: ![record](rec/quickstart_concurrent_sync.gif) > __NOTE__: Captured values are __bold__ to indicate which part of a [step] is actually captured. @@ -398,7 +398,7 @@ A contrived example, but it demonstrates that [step]s can be reused as long as t Let's switch our runtime to `tokio`: ```toml [dev-dependencies] -cucumber = "0.20" +cucumber = "0.22" tokio = { version = "1.10", features = ["macros", "rt-multi-thread", "time"] } [[test]] diff --git a/book/src/writing/hooks.md b/book/src/writing/hooks.md index 5e6f6944..a8ee1f38 100644 --- a/book/src/writing/hooks.md +++ b/book/src/writing/hooks.md @@ -35,6 +35,9 @@ World::cucumber() > __NOTE__: [`Before` hook] is enabled globally for all the executed [scenario]s. No exception is possible. +> __NOTE__: __Only one [`Before` hook] can be registered!__ +> If multiple `.before()` calls are made, only the last one will be run. + > __WARNING__: __Think twice before using [`Before` hook]!__ > Whatever happens in a [`Before` hook] is invisible to people reading `.feature`s. You should consider using a [`Background`] keyword as a more explicit alternative, especially if the setup should be readable by non-technical people. Only use a [`Before` hook] for low-level logic such as starting a browser or deleting data from a database. @@ -70,6 +73,9 @@ World::cucumber() > __NOTE__: [`After` hook] is enabled globally for all the executed [scenario]s. No exception is possible. +> __NOTE__: __Only one [`After` hook] can be registered!__ +> If multiple `.after()` calls are made, only the last one will be run. + > __TIP__: [`After` hook] receives an [`event::ScenarioFinished`] as one of its arguments, which indicates why the [scenario] has finished (passed, failed or skipped). This information, for example, may be used to decide whether some external resources (like files) should be cleaned up if the [scenario] passes, or leaved "as is" if it fails, so helping to "freeze" the failure conditions for better investigation. diff --git a/book/src/writing/retries.md b/book/src/writing/retries.md index 0e973fec..852a305d 100644 --- a/book/src/writing/retries.md +++ b/book/src/writing/retries.md @@ -1,7 +1,7 @@ Retrying failed scenarios ========================= -Often, it's nearly impossible to create fully-deterministic test case, especially when you are relying on environments like external services, browsers, file system, networking etc. That's why there is an ability to retry failed [scenario]s. +Often, it's nearly impossible to create fully-deterministic test case, especially when you are relying on environments like external services, browsers, file system, networking etc. That's why there is an ability to retry failed [scenario]s. > __WARNING__: Although this feature is supported, we highly recommend to use it as the _last resort only_. First, consider implementing in-[step] retries with your own needs (like [exponential backoff]). Other ways of dealing with flaky tests include, but not limited to: reducing number of concurrently executed scenarios (maybe even using `@serial` [tag]), mocking external environment, [controlling time in tests] or even [simulation testing]. It's always better to move towards tests determinism, rather than trying to tame their flakiness. @@ -20,7 +20,7 @@ Feature: Heads and tails Given a coin When I flip the coin Then I see tails - + # Attempts a single retry in 1 second. @retry.after(1s) Scenario: Heads @@ -50,7 +50,7 @@ Feature: Heads and tails # use std::time::Duration; # # use cucumber::{World, given, then, when}; -# use rand::Rng as _; +# use rand::RngExt as _; # use tokio::time::sleep; # # #[derive(Debug, Default, World)] @@ -67,7 +67,7 @@ async fn coin(_: &mut FlipWorld) { async fn flip(world: &mut FlipWorld) { sleep(Duration::from_secs(2)).await; - world.flipped = match rand::thread_rng().gen_range(0.0..1.0) { + world.flipped = match rand::rng().random_range(0.0..1.0) { p if p < 0.2 => "edge", p if p < 0.5 => "heads", _ => "tails", @@ -98,7 +98,7 @@ async fn never_lands(_: &mut FlipWorld) { ``` ![record](../rec/writing_retries.gif) -> __NOTE__: On failure, the whole [scenario] is re-executed with a new fresh [`World`] instance. +> __NOTE__: On failure, the whole [scenario] is re-executed with a new fresh [`World`] instance. @@ -112,7 +112,7 @@ The following [CLI option]s are related to the [scenario] retries: --retry-after Delay between each scenario retry attempt. - + Duration is represented in a human-readable format like `12min5s`. Supported suffixes: - `nsec`, `ns` — nanoseconds. diff --git a/book/src/writing/tags.md b/book/src/writing/tags.md index 662f9484..498879ff 100644 --- a/book/src/writing/tags.md +++ b/book/src/writing/tags.md @@ -31,7 +31,8 @@ Feature: Animal feature ``` To filter out running [scenario]s we may use: -- either `--tags` [CLI] option providing [tag expressions] (also consider [escaping]); +- either `--tags` [CLI] option providing [tag expressions] (also consider [escaping]). +- or `CUCUMBER_FILTER_TAGS` environment variable containing [tag expressions] (also consider [escaping]). - or [`filter_run()`]-like method. ![record](../rec/writing_tags_filtering.gif) @@ -65,13 +66,13 @@ Feature: Animal feature Then the is not hungry @home - Examples: + Examples: | animal | n | | cat | 2 | | dog | 3 | @dire - Examples: + Examples: | animal | n | | lion | 1 | | wolf | 1 | @@ -90,7 +91,7 @@ Feature: Animal feature ```gherkin Feature: Animal feature - + Scenario: If we feed a hungry cat it will no longer be hungry Given a hungry cat When I feed the cat @@ -120,7 +121,7 @@ Using [`Cucumber::fail_on_skipped()`] method fails the whole test suite if some ```gherkin Feature: Animal feature - + Scenario: If we feed a hungry cat it will no longer be hungry Given a hungry cat When I feed the cat @@ -139,7 +140,7 @@ Feature: Animal feature # # use cucumber::{World, given, then, when}; # use tokio::time::sleep; -# +# # #[derive(Debug, Default)] # struct Animal { # pub hungry: bool, @@ -194,7 +195,7 @@ async fn main() { ```gherkin Feature: Animal feature - + Scenario: If we feed a hungry cat it will no longer be hungry Given a hungry cat When I feed the cat diff --git a/codegen/CHANGELOG.md b/codegen/CHANGELOG.md index 788aae26..4b9c4d55 100644 --- a/codegen/CHANGELOG.md +++ b/codegen/CHANGELOG.md @@ -6,28 +6,47 @@ All user visible changes to `cucumber-codegen` crate will be documented in this -## [0.22.0] · 2024-??-?? (unreleased) -[0.22.0]: /../../tree/v0.22.0/codegen +## [0.22.1] · 2025-12-23 +[0.22.1]: https://github.com/cucumber-rs/cucumber/tree/v0.22.1/codegen -[Milestone](/../../milestone/28) +[Milestone](https://github.com/cucumber-rs/cucumber/milestone/31) + +### Version bump only + +See `cucumber` crate [changelog](https://github.com/cucumber-rs/cucumber/blob/v0.22.1/CHANGELOG.md). + + + + +## [0.22.0] · 2025-12-12 +[0.22.0]: https://github.com/cucumber-rs/cucumber/tree/v0.22.0/codegen + +[Milestone](https://github.com/cucumber-rs/cucumber/milestone/28) ### BC Breaks -- Bumped up [MSRV] to 1.87 to get rid of `once_cell` crate, for `#[expect]` attribute usage, and because of migration to 2024 edition. ([4010c1ad], [f1307038], [b46930c3], [9705253b], [todo]) +- Bumped up [MSRV] to 1.88 to get rid of `once_cell` crate, for `#[expect]` attribute usage, and because of migration to 2024 edition. ([4010c1ad], [f1307038], [b46930c3], [9705253b], [0c7dfc3c], [a4cbd3d2]) + +### Fixed + +- `clippy::trivial_regex` lint triggering on `#[given]`/`#[when]`/`#[then]` steps without regular expression. ([81acba84], [#384]) -[4010c1ad]: /../../commit/4010c1ad6a53d6b7f0b28cefea73c8c13e880e9f -[9705253b]: /../../commit/9705253bda5caadfe3eea91f50420222158dd944 -[b46930c3]: /../../commit/b46930c32ef5ae490df8063905144a45de27eda1 -[f1307038]: /../../commit/f1307038cb6b1e38c1cc259a0e09fb583033d0cf -[todo]: /../../commit/todo +[#384]: https://github.com/cucumber-rs/cucumber/pull/384 +[0c7dfc3c]: https://github.com/cucumber-rs/cucumber/commit/0c7dfc3c80f0f58ce9a52f252485d1d14e6eb0ed +[4010c1ad]: https://github.com/cucumber-rs/cucumber/commit/4010c1ad6a53d6b7f0b28cefea73c8c13e880e9f +[81acba84]: https://github.com/cucumber-rs/cucumber/commit/81acba84697a5b04c45e2c5d5446f1ffbe289632 +[9705253b]: https://github.com/cucumber-rs/cucumber/commit/9705253bda5caadfe3eea91f50420222158dd944 +[a4cbd3d2]: https://github.com/cucumber-rs/cucumber/commit/a4cbd3d282fe8e01f05609eabea6410c0e2b46a3 +[b46930c3]: https://github.com/cucumber-rs/cucumber/commit/b46930c32ef5ae490df8063905144a45de27eda1 +[f1307038]: https://github.com/cucumber-rs/cucumber/commit/f1307038cb6b1e38c1cc259a0e09fb583033d0cf ## [0.21.1] · 2024-06-16 -[0.21.1]: /../../tree/v0.21.1/codegen +[0.21.1]: https://github.com/cucumber-rs/cucumber/tree/v0.21.1/codegen -[Milestone](/../../milestone/29) +[Milestone](https://github.com/cucumber-rs/cucumber/milestone/29) ### Version bump only @@ -37,23 +56,23 @@ See `cucumber` crate [changelog](https://github.com/cucumber-rs/cucumber/blob/v0 ## [0.21.0] · 2024-04-22 -[0.21.0]: /../../tree/v0.21.0/codegen +[0.21.0]: https://github.com/cucumber-rs/cucumber/tree/v0.21.0/codegen -[Milestone](/../../milestone/26) +[Milestone](https://github.com/cucumber-rs/cucumber/milestone/26) ### BC Breaks - Bumped up [MSRV] to 1.75 for using `async fn` in traits. ([#324]) -[#324]: /../../pull/324 +[#324]: https://github.com/cucumber-rs/cucumber/pull/324 ## [0.20.2] · 2023-12-04 -[0.20.2]: /../../tree/v0.20.2/codegen +[0.20.2]: https://github.com/cucumber-rs/cucumber/tree/v0.20.2/codegen -[Milestone](/../../milestone/27) +[Milestone](https://github.com/cucumber-rs/cucumber/milestone/27) ### Version bump only @@ -63,9 +82,9 @@ See `cucumber` crate [changelog](https://github.com/cucumber-rs/cucumber/blob/v0 ## [0.20.1] · 2023-10-16 -[0.20.1]: /../../tree/v0.20.1/codegen +[0.20.1]: https://github.com/cucumber-rs/cucumber/tree/v0.20.1/codegen -[Milestone](/../../milestone/25) +[Milestone](https://github.com/cucumber-rs/cucumber/milestone/25) ### Version bump only @@ -75,9 +94,9 @@ See `cucumber` crate [changelog](https://github.com/cucumber-rs/cucumber/blob/v0 ## [0.20.0] · 2023-07-10 -[0.20.0]: /../../tree/v0.20.0/codegen +[0.20.0]: https://github.com/cucumber-rs/cucumber/tree/v0.20.0/codegen -[Milestone](/../../milestone/24) +[Milestone](https://github.com/cucumber-rs/cucumber/milestone/24) ### BC Breaks @@ -87,16 +106,16 @@ See `cucumber` crate [changelog](https://github.com/cucumber-rs/cucumber/blob/v0 - Switched to 2.0 version of [`syn`]. ([#266]) -[#266]: /../../pull/266 -[#288]: /../../pull/288 +[#266]: https://github.com/cucumber-rs/cucumber/pull/266 +[#288]: https://github.com/cucumber-rs/cucumber/pull/288 ## [0.19.1] · 2022-12-29 -[0.19.1]: /../../tree/v0.19.1/codegen +[0.19.1]: https://github.com/cucumber-rs/cucumber/tree/v0.19.1/codegen -[Milestone](/../../milestone/23) +[Milestone](https://github.com/cucumber-rs/cucumber/milestone/23) ### Version bump only @@ -106,9 +125,9 @@ See `cucumber` crate [changelog](https://github.com/cucumber-rs/cucumber/blob/v0 ## [0.19.0] · 2022-12-07 -[0.19.0]: /../../tree/v0.19.0/codegen +[0.19.0]: https://github.com/cucumber-rs/cucumber/tree/v0.19.0/codegen -[Milestone](/../../milestone/22) +[Milestone](https://github.com/cucumber-rs/cucumber/milestone/22) ### Version bump only @@ -118,9 +137,9 @@ See `cucumber` crate [changelog](https://github.com/cucumber-rs/cucumber/blob/v0 ## [0.18.0] · 2022-12-07 -[0.18.0]: /../../tree/v0.18.0/codegen +[0.18.0]: https://github.com/cucumber-rs/cucumber/tree/v0.18.0/codegen -[Milestone](/../../milestone/21) +[Milestone](https://github.com/cucumber-rs/cucumber/milestone/21) ### Version bump only @@ -130,9 +149,9 @@ See `cucumber` crate [changelog](https://github.com/cucumber-rs/cucumber/blob/v0 ## [0.17.0] · 2022-11-23 -[0.17.0]: /../../tree/v0.17.0/codegen +[0.17.0]: https://github.com/cucumber-rs/cucumber/tree/v0.17.0/codegen -[Milestone](/../../milestone/20) +[Milestone](https://github.com/cucumber-rs/cucumber/milestone/20) ### Version bump only @@ -142,23 +161,23 @@ See `cucumber` crate [changelog](https://github.com/cucumber-rs/cucumber/blob/v0 ## [0.16.0] · 2022-11-09 -[0.16.0]: /../../tree/v0.16.0/codegen +[0.16.0]: https://github.com/cucumber-rs/cucumber/tree/v0.16.0/codegen -[Milestone](/../../milestone/19) +[Milestone](https://github.com/cucumber-rs/cucumber/milestone/19) ### BC Breaks - Bumped up [MSRV] to 1.65 for using `let`-`else` statements. ([7f52d4a5]) -[7f52d4a5]: /../../commit/7f52d4a5faa3b69bec6c7fb765b50455cf7802aa +[7f52d4a5]: https://github.com/cucumber-rs/cucumber/commit/7f52d4a5faa3b69bec6c7fb765b50455cf7802aa ## [0.15.3] · 2022-11-01 -[0.15.3]: /../../tree/v0.15.3/codegen +[0.15.3]: https://github.com/cucumber-rs/cucumber/tree/v0.15.3/codegen -[Milestone](/../../milestone/18) +[Milestone](https://github.com/cucumber-rs/cucumber/milestone/18) ### Version bump only @@ -168,9 +187,9 @@ See `cucumber` crate [changelog](https://github.com/cucumber-rs/cucumber/blob/v0 ## [0.15.2] · 2022-10-25 -[0.15.2]: /../../tree/v0.15.2/codegen +[0.15.2]: https://github.com/cucumber-rs/cucumber/tree/v0.15.2/codegen -[Milestone](/../../milestone/17) +[Milestone](https://github.com/cucumber-rs/cucumber/milestone/17) ### Version bump only @@ -180,9 +199,9 @@ See `cucumber` crate [changelog](https://github.com/cucumber-rs/cucumber/blob/v0 ## [0.15.1] · 2022-10-12 -[0.15.1]: /../../tree/v0.15.1/codegen +[0.15.1]: https://github.com/cucumber-rs/cucumber/tree/v0.15.1/codegen -[Milestone](/../../milestone/16) +[Milestone](https://github.com/cucumber-rs/cucumber/milestone/16) ### Version bump only @@ -192,9 +211,9 @@ See `cucumber` crate [changelog](https://github.com/cucumber-rs/cucumber/blob/v0 ## [0.15.0] · 2022-10-05 -[0.15.0]: /../../tree/v0.15.0/codegen +[0.15.0]: https://github.com/cucumber-rs/cucumber/tree/v0.15.0/codegen -[Milestone](/../../milestone/15) +[Milestone](https://github.com/cucumber-rs/cucumber/milestone/15) ### Version bump only @@ -204,21 +223,21 @@ See `cucumber` crate [changelog](https://github.com/cucumber-rs/cucumber/blob/v0 ## [0.14.2] · 2022-09-19 -[0.14.2]: /../../tree/v0.14.2/codegen +[0.14.2]: https://github.com/cucumber-rs/cucumber/tree/v0.14.2/codegen ### Fixed - `#[derive(World)]` macro being unhygienic regarding custom `Result` types. ([186af8b1]) -[186af8b1]: /../../commit/186af8b1de37275b308897e2e30d6982830b0278 +[186af8b1]: https://github.com/cucumber-rs/cucumber/commit/186af8b1de37275b308897e2e30d6982830b0278 ## [0.14.1] · 2022-09-12 -[0.14.1]: /../../tree/v0.14.1/codegen +[0.14.1]: https://github.com/cucumber-rs/cucumber/tree/v0.14.1/codegen -[Milestone](/../../milestone/14) +[Milestone](https://github.com/cucumber-rs/cucumber/milestone/14) ### Version bump only @@ -228,28 +247,28 @@ See `cucumber` crate [changelog](https://github.com/cucumber-rs/cucumber/blob/v0 ## [0.14.0] · 2022-09-08 -[0.14.0]: /../../tree/v0.14.0/codegen +[0.14.0]: https://github.com/cucumber-rs/cucumber/tree/v0.14.0/codegen -[Milestone](/../../milestone/13) +[Milestone](https://github.com/cucumber-rs/cucumber/milestone/13) ### BC Breaks - Bumped up [MSRV] to 1.62 for more clever support of [Cargo feature]s and simplified codegen. ([fbd08ec2], [cf055ac0], [8ad5cc86]) - Replaced `#[derive(WorldInit)]` with `#[derive(World)]` to remove the need of manual `World` trait implementation. ([#219], [#217]) -[#217]: /../../issues/217 -[#219]: /../../pull/219 -[8ad5cc86]: /../../commit/8ad5cc866bb9d6b49470790e3b0dd40690f63a09 -[cf055ac0]: /../../commit/cf055ac06c7b72f572882ce15d6a60da92ad60a0 -[fbd08ec2]: /../../commit/fbd08ec24dbd036c89f5f0af4d936b616790a166 +[#217]: https://github.com/cucumber-rs/cucumber/issues/217 +[#219]: https://github.com/cucumber-rs/cucumber/pull/219 +[8ad5cc86]: https://github.com/cucumber-rs/cucumber/commit/8ad5cc866bb9d6b49470790e3b0dd40690f63a09 +[cf055ac0]: https://github.com/cucumber-rs/cucumber/commit/cf055ac06c7b72f572882ce15d6a60da92ad60a0 +[fbd08ec2]: https://github.com/cucumber-rs/cucumber/commit/fbd08ec24dbd036c89f5f0af4d936b616790a166 ## [0.13.0] · 2022-03-29 -[0.13.0]: /../../tree/v0.13.0/codegen +[0.13.0]: https://github.com/cucumber-rs/cucumber/tree/v0.13.0/codegen -[Milestone](/../../milestone/12) +[Milestone](https://github.com/cucumber-rs/cucumber/milestone/12) ### Version bump only @@ -259,9 +278,9 @@ See `cucumber` crate [changelog](https://github.com/cucumber-rs/cucumber/blob/v0 ## [0.12.2] · 2022-03-28 -[0.12.2]: /../../tree/v0.12.2/codegen +[0.12.2]: https://github.com/cucumber-rs/cucumber/tree/v0.12.2/codegen -[Milestone](/../../milestone/10) +[Milestone](https://github.com/cucumber-rs/cucumber/milestone/10) ### Version bump only @@ -271,9 +290,9 @@ See `cucumber` crate [changelog](https://github.com/cucumber-rs/cucumber/blob/v0 ## [0.12.1] · 2022-03-09 -[0.12.1]: /../../tree/v0.12.1/codegen +[0.12.1]: https://github.com/cucumber-rs/cucumber/tree/v0.12.1/codegen -[Milestone](/../../milestone/11) +[Milestone](https://github.com/cucumber-rs/cucumber/milestone/11) ### Security updated @@ -285,23 +304,23 @@ See `cucumber` crate [changelog](https://github.com/cucumber-rs/cucumber/blob/v0 ## [0.12.0] · 2022-02-10 -[0.12.0]: /../../tree/v0.12.0/codegen +[0.12.0]: https://github.com/cucumber-rs/cucumber/tree/v0.12.0/codegen -[Milestone](/../../milestone/9) +[Milestone](https://github.com/cucumber-rs/cucumber/milestone/9) ### Added - Support for multiple capturing groups in `Parameter` regex (previously was forbidden). ([#204]) -[#204]: /../../pull/204 +[#204]: https://github.com/cucumber-rs/cucumber/pull/204 ## [0.11.3] · 2022-01-31 -[0.11.3]: /../../tree/v0.11.3/codegen +[0.11.3]: https://github.com/cucumber-rs/cucumber/tree/v0.11.3/codegen -[Milestone](/../../milestone/8) +[Milestone](https://github.com/cucumber-rs/cucumber/milestone/8) ### Version bump only @@ -311,9 +330,9 @@ See `cucumber` crate [changelog](https://github.com/cucumber-rs/cucumber/blob/v0 ## [0.11.2] · 2022-01-19 -[0.11.2]: /../../tree/v0.11.2/codegen +[0.11.2]: https://github.com/cucumber-rs/cucumber/tree/v0.11.2/codegen -[Milestone](/../../milestone/7) +[Milestone](https://github.com/cucumber-rs/cucumber/milestone/7) ### Version bump only @@ -323,9 +342,9 @@ See `cucumber` crate [changelog](https://github.com/cucumber-rs/cucumber/blob/v0 ## [0.11.1] · 2022-01-07 -[0.11.1]: /../../tree/v0.11.1/codegen +[0.11.1]: https://github.com/cucumber-rs/cucumber/tree/v0.11.1/codegen -[Milestone](/../../milestone/6) +[Milestone](https://github.com/cucumber-rs/cucumber/milestone/6) ### Version bump only @@ -335,9 +354,9 @@ See `cucumber` crate [changelog](https://github.com/cucumber-rs/cucumber/blob/v0 ## [0.11.0] · 2022-01-03 -[0.11.0]: /../../tree/v0.11.0/codegen +[0.11.0]: https://github.com/cucumber-rs/cucumber/tree/v0.11.0/codegen -[Milestone](/../../milestone/3) +[Milestone](https://github.com/cucumber-rs/cucumber/milestone/3) ### BC Breaks @@ -349,32 +368,32 @@ See `cucumber` crate [changelog](https://github.com/cucumber-rs/cucumber/blob/v0 - `expr = ...` argument to `#[given(...)]`, `#[when(...)]` and `#[then(...)]` attributes allowing [Cucumber Expressions]. ([#157]) - `#[derive(Parameter)]` attribute macro for implementing custom parameters of [Cucumber Expressions]. ([#168]) -[#151]: /../../pull/151 -[#157]: /../../pull/157 -[#168]: /../../pull/168 -[cef3d480]: /../../commit/cef3d480579190425461ddb04a1248675248351e +[#151]: https://github.com/cucumber-rs/cucumber/pull/151 +[#157]: https://github.com/cucumber-rs/cucumber/pull/157 +[#168]: https://github.com/cucumber-rs/cucumber/pull/168 +[cef3d480]: https://github.com/cucumber-rs/cucumber/commit/cef3d480579190425461ddb04a1248675248351e ## [0.10.2] · 2021-11-03 -[0.10.2]: /../../tree/v0.10.2/codegen +[0.10.2]: https://github.com/cucumber-rs/cucumber/tree/v0.10.2/codegen -[Milestone](/../../milestone/5) +[Milestone](https://github.com/cucumber-rs/cucumber/milestone/5) ### Added - World's type name to the generated `WorldInit` machinery to omit conflicts for different types in the same module. ([#150]) -[#150]: /../../pull/150 +[#150]: https://github.com/cucumber-rs/cucumber/pull/150 ## [0.10.1] · 2021-10-29 -[0.10.1]: /../../tree/v0.10.1/codegen +[0.10.1]: https://github.com/cucumber-rs/cucumber/tree/v0.10.1/codegen -[Milestone](/../../milestone/4) +[Milestone](https://github.com/cucumber-rs/cucumber/milestone/4) ### Version bump only @@ -384,22 +403,22 @@ See `cucumber` crate [changelog](https://github.com/cucumber-rs/cucumber/blob/v0 ## [0.10.0] · 2021-10-26 -[0.10.0]: /../../tree/v0.10.0/codegen +[0.10.0]: https://github.com/cucumber-rs/cucumber/tree/v0.10.0/codegen -[Milestone](/../../milestone/2) +[Milestone](https://github.com/cucumber-rs/cucumber/milestone/2) ### BC Breaks - Renamed crate to `cucumber-codegen`. - Replaced `#[given(step)]`, `#[when(step)]` and `#[then(step)]` function argument attributes with a single `#[step]`. ([#128]) -[#128]: /../../pull/128 +[#128]: https://github.com/cucumber-rs/cucumber/pull/128 ## [0.1.0] · 2021-01-18 -[0.1.0]: /../../tree/v0.8.0/codegen +[0.1.0]: https://github.com/cucumber-rs/cucumber/tree/v0.8.0/codegen ### Added @@ -408,7 +427,7 @@ See `cucumber` crate [changelog](https://github.com/cucumber-rs/cucumber/blob/v0 - [`when`](https://docs.rs/cucumber_rust_codegen/0.1.0/cucumber_rust_codegen/attr.when.html); - [`then`](https://docs.rs/cucumber_rust_codegen/0.1.0/cucumber_rust_codegen/attr.then.html). -[#81]: /../../pull/81 +[#81]: https://github.com/cucumber-rs/cucumber/pull/81 diff --git a/codegen/Cargo.toml b/codegen/Cargo.toml index db3cb34f..25977eef 100644 --- a/codegen/Cargo.toml +++ b/codegen/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "cucumber-codegen" -version = "0.21.1" # should be the same as main crate version +version = "0.22.1" # should be the same as main crate version edition = "2024" -rust-version = "1.87" +rust-version = "1.88" description = "Code generation for `cucumber` crate." license = "MIT OR Apache-2.0" authors = [ @@ -21,14 +21,14 @@ exclude = ["/tests/"] proc-macro = true [dependencies] -cucumber-expressions = { version = "0.4", features = ["into-regex"] } +cucumber-expressions = { version = "0.5", features = ["into-regex"] } inflections = "1.1" itertools = "0.14" proc-macro2 = "1.0.28" quote = "1.0.9" regex = "1.5.5" syn = { version = "2.0", features = ["derive", "extra-traits", "full"] } -synthez = "0.3" +synthez = "0.4" [dev-dependencies] cucumber = { path = "..", features = ["libtest", "macros"] } diff --git a/codegen/README.md b/codegen/README.md index 8c5a255a..ded97a80 100644 --- a/codegen/README.md +++ b/codegen/README.md @@ -2,12 +2,12 @@ ======================== [![crates.io](https://img.shields.io/crates/v/cucumber-codegen.svg?maxAge=2592000 "crates.io")](https://crates.io/crates/cucumber-codegen) -[![Rust 1.87+](https://img.shields.io/badge/rustc-1.87+-lightgray.svg "Rust 1.87+")](https://blog.rust-lang.org/2025/05/15/Rust-1.87.0) +[![Rust 1.88+](https://img.shields.io/badge/rustc-1.88+-lightgray.svg "Rust 1.88+")](https://blog.rust-lang.org/2025/06/26/Rust-1.88.0) [![Unsafe Forbidden](https://img.shields.io/badge/unsafe-forbidden-success.svg "Unsafe forbidden")](https://github.com/rust-secure-code/safety-dance)\ [![CI](https://github.com/cucumber-rs/cucumber/actions/workflows/ci.yml/badge.svg?branch=main "CI")](https://github.com/cucumber-rs/cucumber/actions?query=workflow%3ACI+branch%3Amain) [![Rust docs](https://docs.rs/cucumber-codegen/badge.svg "Rust docs")](https://docs.rs/cucumber-codegen) -- [Changelog](https://github.com/cucumber-rs/cucumber/blob/main/codegen/CHANGELOG.md) +- [Changelog](https://github.com/cucumber-rs/cucumber/blob/v0.22.1/codegen/CHANGELOG.md) Code generation for [`cucumber`] tests auto-wiring. @@ -20,8 +20,8 @@ DO NOT use it directly, use [`cucumber`] crate instead. This project is licensed under either of -* Apache License, Version 2.0 ([LICENSE-APACHE](https://github.com/cucumber-rs/cucumber/blob/main/LICENSE-APACHE) or ) -* MIT license ([LICENSE-MIT](https://github.com/cucumber-rs/cucumber/blob/main/LICENSE-MIT) or ) +* Apache License, Version 2.0 ([LICENSE-APACHE](https://github.com/cucumber-rs/cucumber/blob/v0.22.1/LICENSE-APACHE) or ) +* MIT license ([LICENSE-MIT](https://github.com/cucumber-rs/cucumber/blob/v0.22.1/LICENSE-MIT) or ) at your option. diff --git a/codegen/src/attribute.rs b/codegen/src/attribute.rs index b81d1996..02b4cb2b 100644 --- a/codegen/src/attribute.rs +++ b/codegen/src/attribute.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2025 Brendan Molloy , +// Copyright (c) 2020-2026 Brendan Molloy , // Ilya Solovyiov , // Kai Ren // @@ -84,10 +84,10 @@ impl Step { }? .or_else(|| { func.sig.inputs.iter().find_map(|arg| { - if let Ok((ident, _)) = parse_fn_arg(arg) { - if ident == "step" { - return Some(ident.clone()); - } + if let Ok((ident, _)) = parse_fn_arg(arg) + && ident == "step" + { + return Some(ident.clone()); } None }) @@ -112,6 +112,9 @@ impl Step { self.fn_arguments_and_additional_parsing()?; let regex = self.gen_regex()?; + let allow_trivial_regex_attr = + matches!(self.attr_arg, AttributeArgument::Literal(_)) + .then(|| quote! { #[allow(clippy::trivial_regex)] }); let awaiting = func.sig.asyncness.map(|_| quote! { .await }); let unwrapping = (!self.returns_unit()) @@ -135,6 +138,7 @@ impl Step { column: ::std::column!(), }, regex: || { + #allow_trivial_regex_attr static LAZY: ::std::sync::LazyLock< ::cucumber::codegen::Regex > = ::std::sync::LazyLock::new(|| { #regex }); @@ -302,8 +306,7 @@ impl Step { let (ident, ty) = parse_fn_arg(arg)?; let is_ctx_arg = - self.arg_name_of_step_context.as_ref().map(|i| *i == *ident) - == Some(true); + self.arg_name_of_step_context.as_ref().is_some_and(|i| i == ident); let decl = if is_ctx_arg { quote! { @@ -794,10 +797,10 @@ fn remove_attr(attr_arg: &str, arg: &mut syn::FnArg) -> Option { let (mut other, mut removed): (Vec<_>, Vec<_>) = attrs.into_iter().partition_map(|attr| { - if let Some(ident) = attr.meta.path().get_ident() { - if ident == attr_arg { - return Either::Right(attr); - } + if let Some(ident) = attr.meta.path().get_ident() + && ident == attr_arg + { + return Either::Right(attr); } Either::Left(attr) }); diff --git a/codegen/src/lib.rs b/codegen/src/lib.rs index 053927fa..7b6eab3c 100644 --- a/codegen/src/lib.rs +++ b/codegen/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2025 Brendan Molloy , +// Copyright (c) 2020-2026 Brendan Molloy , // Ilya Solovyiov , // Kai Ren // @@ -37,6 +37,7 @@ clippy::default_union_representation, clippy::derive_partial_eq_without_eq, clippy::doc_include_without_cfg, + clippy::doc_paragraphs_missing_punctuation, clippy::empty_drop, clippy::empty_structs_with_brackets, clippy::equatable_if_let, @@ -109,7 +110,6 @@ clippy::string_lit_as_bytes, clippy::string_lit_chars_any, clippy::string_slice, - clippy::string_to_string, clippy::suboptimal_flops, clippy::suspicious_operation_groupings, clippy::suspicious_xor_used_as_pow, @@ -136,6 +136,7 @@ clippy::use_self, clippy::useless_let_if_seq, clippy::verbose_file_reads, + clippy::volatile_composites, clippy::while_float, clippy::wildcard_enum_match_arm, ambiguous_negative_literals, diff --git a/codegen/src/parameter.rs b/codegen/src/parameter.rs index a1677391..e1b564bb 100644 --- a/codegen/src/parameter.rs +++ b/codegen/src/parameter.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2025 Brendan Molloy , +// Copyright (c) 2020-2026 Brendan Molloy , // Ilya Solovyiov , // Kai Ren // diff --git a/codegen/src/world.rs b/codegen/src/world.rs index 15a75c09..2f614aeb 100644 --- a/codegen/src/world.rs +++ b/codegen/src/world.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2025 Brendan Molloy , +// Copyright (c) 2020-2026 Brendan Molloy , // Ilya Solovyiov , // Kai Ren // diff --git a/src/cli.rs b/src/cli.rs index a7c49db9..f016e6d7 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2025 Brendan Molloy , +// Copyright (c) 2018-2026 Brendan Molloy , // Ilya Solovyiov , // Kai Ren // @@ -111,6 +111,7 @@ where short = 't', value_name = "tagexpr", conflicts_with = "name", + env = "CUCUMBER_FILTER_TAGS", global = true )] pub tags_filter: Option, diff --git a/src/codegen.rs b/src/codegen.rs index b049c15f..71e6b3c7 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2025 Brendan Molloy , +// Copyright (c) 2018-2026 Brendan Molloy , // Ilya Solovyiov , // Kai Ren // diff --git a/src/cucumber.rs b/src/cucumber.rs index 462f43de..c5c6e1eb 100644 --- a/src/cucumber.rs +++ b/src/cucumber.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2025 Brendan Molloy , +// Copyright (c) 2018-2026 Brendan Molloy , // Ilya Solovyiov , // Kai Ren // @@ -1015,6 +1015,10 @@ where /// Sets a hook, executed on each [`Scenario`] before running all its /// [`Step`]s, including [`Background`] ones. /// + /// > **NOTE**: Only one [`before`] hook can be registered. If multiple + /// > calls are made, only the last one will be run. + /// + /// [`before`]: Self::before() /// [`Background`]: gherkin::Background /// [`Scenario`]: gherkin::Scenario /// [`Step`]: gherkin::Step @@ -1046,9 +1050,13 @@ where /// Sets a hook, executed on each [`Scenario`] after running all its /// [`Step`]s, even after [`Skipped`] of [`Failed`] [`Step`]s. /// + /// > **NOTE**: Only one [`after`] hook can be registered. If multiple + /// > calls are made, only the last one will be run. + /// /// Last `World` argument is supplied to the function, in case it was /// initialized before by running [`before`] hook or any [`Step`]. /// + /// [`after`]: Self::after() /// [`before`]: Self::before() /// [`Failed`]: event::Step::Failed /// [`Scenario`]: gherkin::Scenario diff --git a/src/event.rs b/src/event.rs index 39f3aed1..5c7e6b89 100644 --- a/src/event.rs +++ b/src/event.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2025 Brendan Molloy , +// Copyright (c) 2018-2026 Brendan Molloy , // Ilya Solovyiov , // Kai Ren // diff --git a/src/feature.rs b/src/feature.rs index 244447e4..1c9bd132 100644 --- a/src/feature.rs +++ b/src/feature.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2025 Brendan Molloy , +// Copyright (c) 2018-2026 Brendan Molloy , // Ilya Solovyiov , // Kai Ren // @@ -142,12 +142,18 @@ fn expand_scenario( ) -> Vec> { /// [`Regex`] matching placeholders [`Examples`] should expand into. /// + /// # Format + /// + /// - Spaces are allowed inside placeholder. + /// - Placeholder cannot start or end with a space. + /// /// [`Examples`]: gherkin::Examples // TODO: Switch back to `lazy-regex::regex!()` once it migrates to `std`: // https://github.com/Canop/lazy-regex/issues/10 #[expect(clippy::unwrap_used, reason = "regex is valid")] - static TEMPLATE_REGEX: LazyLock = - LazyLock::new(|| Regex::new(r"<([^>\s]+)>").unwrap()); + static TEMPLATE_REGEX: LazyLock = LazyLock::new(|| { + Regex::new(r"<([^>\s](?:[^>\s]?|[^>\t\n\r\v\f]*[^>\s]))>").unwrap() + }); if scenario.examples.is_empty() { return vec![Ok(scenario)]; diff --git a/src/lib.rs b/src/lib.rs index 2bf68c09..e9e681aa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2025 Brendan Molloy , +// Copyright (c) 2018-2026 Brendan Molloy , // Ilya Solovyiov , // Kai Ren // @@ -12,7 +12,7 @@ html_logo_url = "https://avatars.githubusercontent.com/u/91469139?s=128", html_favicon_url = "https://avatars.githubusercontent.com/u/91469139?s=256" )] -#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![cfg_attr(docsrs, feature(doc_cfg))] #![cfg_attr(any(doc, test), doc = include_str!("../README.md"))] #![cfg_attr(not(any(doc, test)), doc = env!("CARGO_PKG_NAME"))] #![deny(nonstandard_style, rustdoc::all, trivial_casts, trivial_numeric_casts)] @@ -38,6 +38,7 @@ clippy::default_union_representation, clippy::derive_partial_eq_without_eq, clippy::doc_include_without_cfg, + clippy::doc_paragraphs_missing_punctuation, clippy::empty_drop, clippy::empty_structs_with_brackets, clippy::equatable_if_let, @@ -110,7 +111,6 @@ clippy::string_lit_as_bytes, clippy::string_lit_chars_any, clippy::string_slice, - clippy::string_to_string, clippy::suboptimal_flops, clippy::suspicious_operation_groupings, clippy::suspicious_xor_used_as_pow, @@ -137,6 +137,7 @@ clippy::use_self, clippy::useless_let_if_seq, clippy::verbose_file_reads, + clippy::volatile_composites, clippy::while_float, clippy::wildcard_enum_match_arm, ambiguous_negative_literals, diff --git a/src/parser/basic.rs b/src/parser/basic.rs index 5eeae695..3c26d6f2 100644 --- a/src/parser/basic.rs +++ b/src/parser/basic.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2025 Brendan Molloy , +// Copyright (c) 2018-2026 Brendan Molloy , // Ilya Solovyiov , // Kai Ren // diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 58674b0e..5c3ebf6c 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2025 Brendan Molloy , +// Copyright (c) 2018-2026 Brendan Molloy , // Ilya Solovyiov , // Kai Ren // @@ -64,7 +64,7 @@ pub enum Error { #[display("Failed to parse feature: {_0}")] Parsing(Arc), - /// Failed to expand [`Examples`] + /// Failed to expand [`Examples`]. /// /// [`Examples`]: gherkin::Examples #[display("Failed to expand examples: {_0}")] diff --git a/src/runner/basic.rs b/src/runner/basic.rs index 64e090ef..9cadde2b 100644 --- a/src/runner/basic.rs +++ b/src/runner/basic.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2025 Brendan Molloy , +// Copyright (c) 2018-2026 Brendan Molloy , // Ilya Solovyiov , // Kai Ren // @@ -188,7 +188,7 @@ impl RetryOptions { apply_cli( parse_tags(&scenario.tags) - .or_else(|| rule.and_then(|r| parse_tags(&r.tags))) + .or_else(|| parse_tags(&rule?.tags)) .or_else(|| parse_tags(&feature.tags)), ) } @@ -576,6 +576,11 @@ impl Basic { /// Sets a hook, executed on each [`Scenario`] before running all its /// [`Step`]s, including [`Background`] ones. /// + /// > **NOTE**: Only one [`before`] hook can be registered. If + /// > multiple calls are made, only the last one will be + /// > run. + /// + /// [`before`]: Self::before() /// [`Background`]: gherkin::Background /// [`Scenario`]: gherkin::Scenario /// [`Step`]: gherkin::Step @@ -622,9 +627,14 @@ impl Basic { /// Sets hook, executed on each [`Scenario`] after running all its /// [`Step`]s, even after [`Skipped`] of [`Failed`] ones. /// + /// > **NOTE**: Only one [`after`] hook can be registered. If + /// > multiple calls are made, only the last one will be + /// > run. + /// /// Last `World` argument is supplied to the function, in case it was /// initialized before by running [`before`] hook or any [`Step`]. /// + /// [`after`]: Self::after() /// [`before`]: Self::before() /// [`Failed`]: event::Step::Failed /// [`Scenario`]: gherkin::Scenario @@ -976,10 +986,6 @@ async fn execute( coll.start_scenarios(&runnable); } async { - #[expect( // intentional - clippy::infinite_loop, - reason = "cannot annotate `async` block with `-> !" - )] loop { while let Some(logs) = logs_collector .as_mut() @@ -1021,23 +1027,21 @@ async fn execute( select_with_biased_first(forward_logs, run_scenarios.next()) .await .factor_first(); - if finished_scenario.is_some() { - if let ControlFlow::Continue(Some(sc)) = &mut started_scenarios - { - *sc += 1; - } + if finished_scenario.is_some() + && let ControlFlow::Continue(Some(sc)) = &mut started_scenarios + { + *sc += 1; } } while let Ok(Some((id, feat, rule, scenario_failed, retried))) = storage.finished_receiver.try_next() { - if let Some(rule) = rule { - if let Some(f) = + if let Some(rule) = rule + && let Some(f) = storage.rule_scenario_finished(feat.clone(), rule, retried) - { - executor.send_event(f); - } + { + executor.send_event(f); } if let Some(f) = storage.feature_scenario_finished(feat, retried) { executor.send_event(f); diff --git a/src/runner/mod.rs b/src/runner/mod.rs index 7b3763c7..dc917fb2 100644 --- a/src/runner/mod.rs +++ b/src/runner/mod.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2025 Brendan Molloy , +// Copyright (c) 2018-2026 Brendan Molloy , // Ilya Solovyiov , // Kai Ren // diff --git a/src/step.rs b/src/step.rs index 41c6cfbd..56325fc5 100644 --- a/src/step.rs +++ b/src/step.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2025 Brendan Molloy , +// Copyright (c) 2018-2026 Brendan Molloy , // Ilya Solovyiov , // Kai Ren // diff --git a/src/tag.rs b/src/tag.rs index abeed083..56fc7a99 100644 --- a/src/tag.rs +++ b/src/tag.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2025 Brendan Molloy , +// Copyright (c) 2018-2026 Brendan Molloy , // Ilya Solovyiov , // Kai Ren // diff --git a/src/tracing.rs b/src/tracing.rs index 647c8acd..700896be 100644 --- a/src/tracing.rs +++ b/src/tracing.rs @@ -303,9 +303,7 @@ impl Collector { } } -// TODO: Try remove on next Rust version update. -#[expect(clippy::allow_attributes, reason = "`#[expect]` doesn't work here")] -#[allow( // intentional +#[expect( // related to `tracing` capabilities only clippy::multiple_inherent_impl, reason = "related to `tracing` capabilities only" )] @@ -521,8 +519,7 @@ mod suffix { //! [`str`]ings appending [`tracing::Event`]s to separate them later. //! //! Every [`tracing::Event`] ends with: - //! - //! ([`BEFORE_SCENARIO_ID`][`ScenarioId`][`END`]|[`NO_SCENARIO_ID`][`END`]) + //! ([`BEFORE_SCENARIO_ID`][`ScenarioId`][`END`]|[`NO_SCENARIO_ID`][`END`]). //! //! [`ScenarioId`]: super::ScenarioId diff --git a/src/writer/basic.rs b/src/writer/basic.rs index 2c80772e..da8741cc 100644 --- a/src/writer/basic.rs +++ b/src/writer/basic.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2025 Brendan Molloy , +// Copyright (c) 2018-2026 Brendan Molloy , // Ilya Solovyiov , // Kai Ren // diff --git a/src/writer/discard.rs b/src/writer/discard.rs index f8f4513b..0f1a8148 100644 --- a/src/writer/discard.rs +++ b/src/writer/discard.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2025 Brendan Molloy , +// Copyright (c) 2018-2026 Brendan Molloy , // Ilya Solovyiov , // Kai Ren // diff --git a/src/writer/fail_on_skipped.rs b/src/writer/fail_on_skipped.rs index a992d5b7..30774725 100644 --- a/src/writer/fail_on_skipped.rs +++ b/src/writer/fail_on_skipped.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2025 Brendan Molloy , +// Copyright (c) 2018-2026 Brendan Molloy , // Ilya Solovyiov , // Kai Ren // diff --git a/src/writer/json.rs b/src/writer/json.rs index b13ecc7e..5cd30e1a 100644 --- a/src/writer/json.rs +++ b/src/writer/json.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2025 Brendan Molloy , +// Copyright (c) 2018-2026 Brendan Molloy , // Ilya Solovyiov , // Kai Ren // diff --git a/src/writer/junit.rs b/src/writer/junit.rs index 13aff4be..f6aa8d8f 100644 --- a/src/writer/junit.rs +++ b/src/writer/junit.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2025 Brendan Molloy , +// Copyright (c) 2018-2026 Brendan Molloy , // Ilya Solovyiov , // Kai Ren // diff --git a/src/writer/libtest.rs b/src/writer/libtest.rs index d02800fd..14c76dba 100644 --- a/src/writer/libtest.rs +++ b/src/writer/libtest.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2025 Brendan Molloy , +// Copyright (c) 2018-2026 Brendan Molloy , // Ilya Solovyiov , // Kai Ren // @@ -827,14 +827,14 @@ where enum LibTestJsonEvent { /// Event of test suite. Suite { - /// [`SuiteEvent`] + /// [`SuiteEvent`]. #[serde(flatten)] event: SuiteEvent, }, /// Event of the test case. Test { - /// [`TestEvent`] + /// [`TestEvent`]. #[serde(flatten)] event: TestEvent, }, diff --git a/src/writer/mod.rs b/src/writer/mod.rs index 611e79f0..ac7a4a6f 100644 --- a/src/writer/mod.rs +++ b/src/writer/mod.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2025 Brendan Molloy , +// Copyright (c) 2018-2026 Brendan Molloy , // Ilya Solovyiov , // Kai Ren // diff --git a/src/writer/normalize.rs b/src/writer/normalize.rs index 77712691..90970c7f 100644 --- a/src/writer/normalize.rs +++ b/src/writer/normalize.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2025 Brendan Molloy , +// Copyright (c) 2018-2026 Brendan Molloy , // Ilya Solovyiov , // Kai Ren // diff --git a/src/writer/or.rs b/src/writer/or.rs index fc5c7304..b6457d90 100644 --- a/src/writer/or.rs +++ b/src/writer/or.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2025 Brendan Molloy , +// Copyright (c) 2018-2026 Brendan Molloy , // Ilya Solovyiov , // Kai Ren // diff --git a/src/writer/out.rs b/src/writer/out.rs index 76d6e207..b8041cb1 100644 --- a/src/writer/out.rs +++ b/src/writer/out.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2025 Brendan Molloy , +// Copyright (c) 2018-2026 Brendan Molloy , // Ilya Solovyiov , // Kai Ren // diff --git a/src/writer/repeat.rs b/src/writer/repeat.rs index 5ca5a137..eae80947 100644 --- a/src/writer/repeat.rs +++ b/src/writer/repeat.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2025 Brendan Molloy , +// Copyright (c) 2018-2026 Brendan Molloy , // Ilya Solovyiov , // Kai Ren // diff --git a/src/writer/summarize.rs b/src/writer/summarize.rs index 27a5c18d..bbdc7313 100644 --- a/src/writer/summarize.rs +++ b/src/writer/summarize.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2025 Brendan Molloy , +// Copyright (c) 2018-2026 Brendan Molloy , // Ilya Solovyiov , // Kai Ren // @@ -539,9 +539,7 @@ pub trait Summarizable {} impl Summarizable for T {} -// TODO: Try remove on next Rust version update. -#[expect(clippy::allow_attributes, reason = "`#[expect]` doesn't work here")] -#[allow( // intentional +#[expect( // related to summarization only clippy::multiple_inherent_impl, reason = "related to summarization only" )] diff --git a/src/writer/tee.rs b/src/writer/tee.rs index 33ecb165..bd69e639 100644 --- a/src/writer/tee.rs +++ b/src/writer/tee.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2025 Brendan Molloy , +// Copyright (c) 2018-2026 Brendan Molloy , // Ilya Solovyiov , // Kai Ren // diff --git a/tests/cli.rs b/tests/cli.rs index 0bf10eb5..d4e7433c 100644 --- a/tests/cli.rs +++ b/tests/cli.rs @@ -1,8 +1,9 @@ -use std::panic::AssertUnwindSafe; +use std::{env, panic::AssertUnwindSafe}; use clap::Parser; use cucumber::{World as _, cli, given}; use futures::FutureExt as _; +use serial_test::{parallel, serial}; #[derive(cli::Args)] struct CustomCli { @@ -32,8 +33,9 @@ fn invalid_step(_world: &mut World) { // This test uses a subcommand with the global option `--tags` to filter on two // failing tests and verifies that the error output contains 2 failing steps. #[tokio::test] +#[parallel] async fn tags_option_filters_all_scenarios_with_subcommand() { - let cli = cli::Opts::<_, _, _, CustomCli>::try_parse_from(&[ + let cli = cli::Opts::<_, _, _, CustomCli>::try_parse_from([ "test", "smoke", r#"--report-name="smoke.report""#, @@ -54,8 +56,9 @@ async fn tags_option_filters_all_scenarios_with_subcommand() { // This test uses a subcommand with the global option `--tags` to filter on one // failing test and verifies that the error output contains 1 failing step. #[tokio::test] +#[parallel] async fn tags_option_filters_scenario1_with_subcommand() { - let cli = cli::Opts::<_, _, _, CustomCli>::try_parse_from(&[ + let cli = cli::Opts::<_, _, _, CustomCli>::try_parse_from([ "test", "smoke", r#"--report-name="smoke.report""#, @@ -76,8 +79,9 @@ async fn tags_option_filters_scenario1_with_subcommand() { // This test verifies that the global option `--tags` is still available without // subcommands and that the error output contains 1 failing step. #[tokio::test] +#[parallel] async fn tags_option_filters_scenario1_no_subcommand() { - let cli = cli::Opts::<_, _, _, CustomCli>::try_parse_from(&[ + let cli = cli::Opts::<_, _, _, CustomCli>::try_parse_from([ "test", "--tags=@scenario-1", ]) @@ -92,3 +96,29 @@ async fn tags_option_filters_scenario1_no_subcommand() { assert_eq!(err, "1 step failed"); } + +// This test verifies that the `CUCUMBER_FILTER_TAGS` env var filters apply and +// that the error output contains 1 failing step. +#[tokio::test] +#[serial] +async fn tags_option_filters_scenario1_via_env() { + unsafe { + env::set_var("CUCUMBER_FILTER_TAGS", "@scenario-1"); + } + + let cli = cli::Opts::<_, _, _, CustomCli>::try_parse_from(["test"]) + .expect("Invalid command line"); + + let res = + World::cucumber().with_cli(cli).run_and_exit("tests/features/cli"); + + let err = + AssertUnwindSafe(res).catch_unwind().await.expect_err("should err"); + let err = err.downcast_ref::().unwrap(); + + assert_eq!(err, "1 step failed"); + + unsafe { + env::remove_var("CUCUMBER_FILTER_TAGS"); + } +} diff --git a/tests/features/output/background_scenario_outline.feature b/tests/features/output/background_scenario_outline.feature index fbff210b..ebaf5c74 100644 --- a/tests/features/output/background_scenario_outline.feature +++ b/tests/features/output/background_scenario_outline.feature @@ -6,8 +6,8 @@ Feature: Outline Scenario Outline: foo Given foo is When foo is - Then foo is + Then foo is Examples: - | bar1 | bar2 | bar3 | - | 1 | 2 | 3 | + | bar1 | bar2 | bar 3 | + | 1 | 2 | 3 | diff --git a/tests/features/output/background_scenario_outline.feature.debug.out b/tests/features/output/background_scenario_outline.feature.debug.out index 14412f5f..b9fc6e2a 100644 --- a/tests/features/output/background_scenario_outline.feature.debug.out +++ b/tests/features/output/background_scenario_outline.feature.debug.out @@ -1,15 +1,15 @@ ParsingFinished { features: 1, rules: 0, scenarios: 1, steps: 3, parser_errors: 0 } Started -Feature(Feature { keyword: "Feature", name: "Outline", description: None, background: Some(Background { keyword: "Background", name: "", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }], position: LineCol { line: 3 } }), scenarios: [Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }], rules: [], tags: [], position: LineCol { line: 1 }, }, Started) -Feature(Feature { keyword: "Feature", name: "Outline", description: None, background: Some(Background { keyword: "Background", name: "", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }], position: LineCol { line: 3 } }), scenarios: [Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }], rules: [], tags: [], position: LineCol { line: 1 }, }, Scenario(Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }, RetryableScenario { event: Started, retries: None })) -Feature(Feature { keyword: "Feature", name: "Outline", description: None, background: Some(Background { keyword: "Background", name: "", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }], position: LineCol { line: 3 } }), scenarios: [Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }], rules: [], tags: [], position: LineCol { line: 1 }, }, Scenario(Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }, RetryableScenario { event: Background(Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }, Started), retries: None })) -Feature(Feature { keyword: "Feature", name: "Outline", description: None, background: Some(Background { keyword: "Background", name: "", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }], position: LineCol { line: 3 } }), scenarios: [Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }], rules: [], tags: [], position: LineCol { line: 1 }, }, Scenario(Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }, RetryableScenario { event: Background(Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }, Passed(CaptureLocations(Captures { pid: Some(PatternID(0)), spans: {0: 0..8, 1: 7..8} }), Some(Location { line: 9, column: 1 }))), retries: None })) -Feature(Feature { keyword: "Feature", name: "Outline", description: None, background: Some(Background { keyword: "Background", name: "", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }], position: LineCol { line: 3 } }), scenarios: [Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }], rules: [], tags: [], position: LineCol { line: 1 }, }, Scenario(Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }, RetryableScenario { event: Step(Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Started), retries: None })) -Feature(Feature { keyword: "Feature", name: "Outline", description: None, background: Some(Background { keyword: "Background", name: "", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }], position: LineCol { line: 3 } }), scenarios: [Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }], rules: [], tags: [], position: LineCol { line: 1 }, }, Scenario(Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }, RetryableScenario { event: Step(Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Passed(CaptureLocations(Captures { pid: Some(PatternID(0)), spans: {0: 0..8, 1: 7..8} }), Some(Location { line: 9, column: 1 }))), retries: None })) -Feature(Feature { keyword: "Feature", name: "Outline", description: None, background: Some(Background { keyword: "Background", name: "", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }], position: LineCol { line: 3 } }), scenarios: [Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }], rules: [], tags: [], position: LineCol { line: 1 }, }, Scenario(Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }, RetryableScenario { event: Step(Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Started), retries: None })) -Feature(Feature { keyword: "Feature", name: "Outline", description: None, background: Some(Background { keyword: "Background", name: "", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }], position: LineCol { line: 3 } }), scenarios: [Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }], rules: [], tags: [], position: LineCol { line: 1 }, }, Scenario(Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }, RetryableScenario { event: Step(Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Passed(CaptureLocations(Captures { pid: Some(PatternID(0)), spans: {0: 0..8, 1: 7..8} }), Some(Location { line: 10, column: 1 }))), retries: None })) -Feature(Feature { keyword: "Feature", name: "Outline", description: None, background: Some(Background { keyword: "Background", name: "", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }], position: LineCol { line: 3 } }), scenarios: [Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }], rules: [], tags: [], position: LineCol { line: 1 }, }, Scenario(Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }, RetryableScenario { event: Step(Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }, Started), retries: None })) -Feature(Feature { keyword: "Feature", name: "Outline", description: None, background: Some(Background { keyword: "Background", name: "", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }], position: LineCol { line: 3 } }), scenarios: [Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }], rules: [], tags: [], position: LineCol { line: 1 }, }, Scenario(Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }, RetryableScenario { event: Step(Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }, Passed(CaptureLocations(Captures { pid: Some(PatternID(0)), spans: {0: 0..8, 1: 7..8} }), Some(Location { line: 11, column: 1 }))), retries: None })) -Feature(Feature { keyword: "Feature", name: "Outline", description: None, background: Some(Background { keyword: "Background", name: "", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }], position: LineCol { line: 3 } }), scenarios: [Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }], rules: [], tags: [], position: LineCol { line: 1 }, }, Scenario(Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }, RetryableScenario { event: Finished, retries: None })) -Feature(Feature { keyword: "Feature", name: "Outline", description: None, background: Some(Background { keyword: "Background", name: "", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }], position: LineCol { line: 3 } }), scenarios: [Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }], rules: [], tags: [], position: LineCol { line: 1 }, }, Finished) -Finished \ No newline at end of file +Feature(Feature { keyword: "Feature", name: "Outline", description: None, background: Some(Background { keyword: "Background", name: "", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }], position: LineCol { line: 3 } }), scenarios: [Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar 3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }], rules: [], tags: [], position: LineCol { line: 1 }, }, Started) +Feature(Feature { keyword: "Feature", name: "Outline", description: None, background: Some(Background { keyword: "Background", name: "", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }], position: LineCol { line: 3 } }), scenarios: [Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar 3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }], rules: [], tags: [], position: LineCol { line: 1 }, }, Scenario(Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar 3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }, RetryableScenario { event: Started, retries: None })) +Feature(Feature { keyword: "Feature", name: "Outline", description: None, background: Some(Background { keyword: "Background", name: "", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }], position: LineCol { line: 3 } }), scenarios: [Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar 3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }], rules: [], tags: [], position: LineCol { line: 1 }, }, Scenario(Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar 3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }, RetryableScenario { event: Background(Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }, Started), retries: None })) +Feature(Feature { keyword: "Feature", name: "Outline", description: None, background: Some(Background { keyword: "Background", name: "", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }], position: LineCol { line: 3 } }), scenarios: [Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar 3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }], rules: [], tags: [], position: LineCol { line: 1 }, }, Scenario(Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar 3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }, RetryableScenario { event: Background(Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }, Passed(CaptureLocations(Captures { pid: Some(PatternID(0)), spans: {0: 0..8, 1: 7..8} }), Some(Location { line: 9, column: 1 }))), retries: None })) +Feature(Feature { keyword: "Feature", name: "Outline", description: None, background: Some(Background { keyword: "Background", name: "", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }], position: LineCol { line: 3 } }), scenarios: [Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar 3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }], rules: [], tags: [], position: LineCol { line: 1 }, }, Scenario(Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar 3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }, RetryableScenario { event: Step(Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Started), retries: None })) +Feature(Feature { keyword: "Feature", name: "Outline", description: None, background: Some(Background { keyword: "Background", name: "", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }], position: LineCol { line: 3 } }), scenarios: [Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar 3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }], rules: [], tags: [], position: LineCol { line: 1 }, }, Scenario(Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar 3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }, RetryableScenario { event: Step(Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Passed(CaptureLocations(Captures { pid: Some(PatternID(0)), spans: {0: 0..8, 1: 7..8} }), Some(Location { line: 9, column: 1 }))), retries: None })) +Feature(Feature { keyword: "Feature", name: "Outline", description: None, background: Some(Background { keyword: "Background", name: "", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }], position: LineCol { line: 3 } }), scenarios: [Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar 3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }], rules: [], tags: [], position: LineCol { line: 1 }, }, Scenario(Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar 3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }, RetryableScenario { event: Step(Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Started), retries: None })) +Feature(Feature { keyword: "Feature", name: "Outline", description: None, background: Some(Background { keyword: "Background", name: "", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }], position: LineCol { line: 3 } }), scenarios: [Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar 3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }], rules: [], tags: [], position: LineCol { line: 1 }, }, Scenario(Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar 3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }, RetryableScenario { event: Step(Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Passed(CaptureLocations(Captures { pid: Some(PatternID(0)), spans: {0: 0..8, 1: 7..8} }), Some(Location { line: 10, column: 1 }))), retries: None })) +Feature(Feature { keyword: "Feature", name: "Outline", description: None, background: Some(Background { keyword: "Background", name: "", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }], position: LineCol { line: 3 } }), scenarios: [Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar 3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }], rules: [], tags: [], position: LineCol { line: 1 }, }, Scenario(Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar 3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }, RetryableScenario { event: Step(Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }, Started), retries: None })) +Feature(Feature { keyword: "Feature", name: "Outline", description: None, background: Some(Background { keyword: "Background", name: "", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }], position: LineCol { line: 3 } }), scenarios: [Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar 3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }], rules: [], tags: [], position: LineCol { line: 1 }, }, Scenario(Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar 3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }, RetryableScenario { event: Step(Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }, Passed(CaptureLocations(Captures { pid: Some(PatternID(0)), spans: {0: 0..8, 1: 7..8} }), Some(Location { line: 11, column: 1 }))), retries: None })) +Feature(Feature { keyword: "Feature", name: "Outline", description: None, background: Some(Background { keyword: "Background", name: "", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }], position: LineCol { line: 3 } }), scenarios: [Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar 3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }], rules: [], tags: [], position: LineCol { line: 1 }, }, Scenario(Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar 3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }, RetryableScenario { event: Finished, retries: None })) +Feature(Feature { keyword: "Feature", name: "Outline", description: None, background: Some(Background { keyword: "Background", name: "", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }], position: LineCol { line: 3 } }), scenarios: [Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 7 } }, Step { keyword: "When ", ty: When, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 8 } }, Step { keyword: "Then ", ty: Then, value: "foo is 3", docstring: None, table: None, position: LineCol { line: 9 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar1", "bar2", "bar 3"], ["1", "2", "3"]], position: LineCol { line: 12 } }), tags: [], position: LineCol { line: 11 } }], tags: [], position: LineCol { line: 13 } }], rules: [], tags: [], position: LineCol { line: 1 }, }, Finished) +Finished diff --git a/tests/features/output/scenario_outline_with_spaces_in_headers.feature b/tests/features/output/scenario_outline_with_spaces_in_headers.feature new file mode 100644 index 00000000..40c096d9 --- /dev/null +++ b/tests/features/output/scenario_outline_with_spaces_in_headers.feature @@ -0,0 +1,10 @@ +Feature: Outline + + Scenario Outline: foo + Given foo is + When foo is + Then foo is + + Examples: + | bar 1 | bar two | bar three | + | 0 | 1 | 2 | diff --git a/tests/features/output/scenario_outline_with_spaces_in_headers.feature.basic.out b/tests/features/output/scenario_outline_with_spaces_in_headers.feature.basic.out new file mode 100644 index 00000000..1ff670a4 --- /dev/null +++ b/tests/features/output/scenario_outline_with_spaces_in_headers.feature.basic.out @@ -0,0 +1,5 @@ +Feature: Outline + Scenario Outline: foo + ✔ Given foo is 0 + ✔ When foo is 1 + ✔ Then foo is 2 diff --git a/tests/features/output/scenario_outline_with_spaces_in_headers.feature.colored.out b/tests/features/output/scenario_outline_with_spaces_in_headers.feature.colored.out new file mode 100644 index 00000000..34f5df45 --- /dev/null +++ b/tests/features/output/scenario_outline_with_spaces_in_headers.feature.colored.out @@ -0,0 +1,8 @@ +Feature: Outline + Scenario Outline: foo + Given foo is 0 +  ✔ Given foo is 0 + When foo is 1 +  ✔ When foo is 1 + Then foo is 2 +  ✔ Then foo is 2 diff --git a/tests/features/output/scenario_outline_with_spaces_in_headers.feature.debug.out b/tests/features/output/scenario_outline_with_spaces_in_headers.feature.debug.out new file mode 100644 index 00000000..2973be30 --- /dev/null +++ b/tests/features/output/scenario_outline_with_spaces_in_headers.feature.debug.out @@ -0,0 +1,13 @@ +ParsingFinished { features: 1, rules: 0, scenarios: 1, steps: 3, parser_errors: 0 } +Started +Feature(Feature { keyword: "Feature", name: "Outline", description: None, background: None, scenarios: [Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }, Step { keyword: "When ", ty: When, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 5 } }, Step { keyword: "Then ", ty: Then, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 6 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar 1", "bar two", "bar three"], ["0", "1", "2"]], position: LineCol { line: 9 } }), tags: [], position: LineCol { line: 8 } }], tags: [], position: LineCol { line: 10 } }], rules: [], tags: [], position: LineCol { line: 1 }, }, Started) +Feature(Feature { keyword: "Feature", name: "Outline", description: None, background: None, scenarios: [Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }, Step { keyword: "When ", ty: When, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 5 } }, Step { keyword: "Then ", ty: Then, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 6 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar 1", "bar two", "bar three"], ["0", "1", "2"]], position: LineCol { line: 9 } }), tags: [], position: LineCol { line: 8 } }], tags: [], position: LineCol { line: 10 } }], rules: [], tags: [], position: LineCol { line: 1 }, }, Scenario(Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }, Step { keyword: "When ", ty: When, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 5 } }, Step { keyword: "Then ", ty: Then, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 6 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar 1", "bar two", "bar three"], ["0", "1", "2"]], position: LineCol { line: 9 } }), tags: [], position: LineCol { line: 8 } }], tags: [], position: LineCol { line: 10 } }, RetryableScenario { event: Started, retries: None })) +Feature(Feature { keyword: "Feature", name: "Outline", description: None, background: None, scenarios: [Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }, Step { keyword: "When ", ty: When, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 5 } }, Step { keyword: "Then ", ty: Then, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 6 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar 1", "bar two", "bar three"], ["0", "1", "2"]], position: LineCol { line: 9 } }), tags: [], position: LineCol { line: 8 } }], tags: [], position: LineCol { line: 10 } }], rules: [], tags: [], position: LineCol { line: 1 }, }, Scenario(Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }, Step { keyword: "When ", ty: When, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 5 } }, Step { keyword: "Then ", ty: Then, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 6 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar 1", "bar two", "bar three"], ["0", "1", "2"]], position: LineCol { line: 9 } }), tags: [], position: LineCol { line: 8 } }], tags: [], position: LineCol { line: 10 } }, RetryableScenario { event: Step(Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }, Started), retries: None })) +Feature(Feature { keyword: "Feature", name: "Outline", description: None, background: None, scenarios: [Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }, Step { keyword: "When ", ty: When, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 5 } }, Step { keyword: "Then ", ty: Then, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 6 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar 1", "bar two", "bar three"], ["0", "1", "2"]], position: LineCol { line: 9 } }), tags: [], position: LineCol { line: 8 } }], tags: [], position: LineCol { line: 10 } }], rules: [], tags: [], position: LineCol { line: 1 }, }, Scenario(Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }, Step { keyword: "When ", ty: When, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 5 } }, Step { keyword: "Then ", ty: Then, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 6 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar 1", "bar two", "bar three"], ["0", "1", "2"]], position: LineCol { line: 9 } }), tags: [], position: LineCol { line: 8 } }], tags: [], position: LineCol { line: 10 } }, RetryableScenario { event: Step(Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }, Passed(CaptureLocations(Captures { pid: Some(PatternID(0)), spans: {0: 0..8, 1: 7..8} }), Some(Location { line: 9, column: 1 }))), retries: None })) +Feature(Feature { keyword: "Feature", name: "Outline", description: None, background: None, scenarios: [Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }, Step { keyword: "When ", ty: When, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 5 } }, Step { keyword: "Then ", ty: Then, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 6 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar 1", "bar two", "bar three"], ["0", "1", "2"]], position: LineCol { line: 9 } }), tags: [], position: LineCol { line: 8 } }], tags: [], position: LineCol { line: 10 } }], rules: [], tags: [], position: LineCol { line: 1 }, }, Scenario(Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }, Step { keyword: "When ", ty: When, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 5 } }, Step { keyword: "Then ", ty: Then, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 6 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar 1", "bar two", "bar three"], ["0", "1", "2"]], position: LineCol { line: 9 } }), tags: [], position: LineCol { line: 8 } }], tags: [], position: LineCol { line: 10 } }, RetryableScenario { event: Step(Step { keyword: "When ", ty: When, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 5 } }, Started), retries: None })) +Feature(Feature { keyword: "Feature", name: "Outline", description: None, background: None, scenarios: [Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }, Step { keyword: "When ", ty: When, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 5 } }, Step { keyword: "Then ", ty: Then, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 6 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar 1", "bar two", "bar three"], ["0", "1", "2"]], position: LineCol { line: 9 } }), tags: [], position: LineCol { line: 8 } }], tags: [], position: LineCol { line: 10 } }], rules: [], tags: [], position: LineCol { line: 1 }, }, Scenario(Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }, Step { keyword: "When ", ty: When, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 5 } }, Step { keyword: "Then ", ty: Then, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 6 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar 1", "bar two", "bar three"], ["0", "1", "2"]], position: LineCol { line: 9 } }), tags: [], position: LineCol { line: 8 } }], tags: [], position: LineCol { line: 10 } }, RetryableScenario { event: Step(Step { keyword: "When ", ty: When, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 5 } }, Passed(CaptureLocations(Captures { pid: Some(PatternID(0)), spans: {0: 0..8, 1: 7..8} }), Some(Location { line: 10, column: 1 }))), retries: None })) +Feature(Feature { keyword: "Feature", name: "Outline", description: None, background: None, scenarios: [Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }, Step { keyword: "When ", ty: When, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 5 } }, Step { keyword: "Then ", ty: Then, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 6 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar 1", "bar two", "bar three"], ["0", "1", "2"]], position: LineCol { line: 9 } }), tags: [], position: LineCol { line: 8 } }], tags: [], position: LineCol { line: 10 } }], rules: [], tags: [], position: LineCol { line: 1 }, }, Scenario(Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }, Step { keyword: "When ", ty: When, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 5 } }, Step { keyword: "Then ", ty: Then, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 6 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar 1", "bar two", "bar three"], ["0", "1", "2"]], position: LineCol { line: 9 } }), tags: [], position: LineCol { line: 8 } }], tags: [], position: LineCol { line: 10 } }, RetryableScenario { event: Step(Step { keyword: "Then ", ty: Then, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 6 } }, Started), retries: None })) +Feature(Feature { keyword: "Feature", name: "Outline", description: None, background: None, scenarios: [Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }, Step { keyword: "When ", ty: When, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 5 } }, Step { keyword: "Then ", ty: Then, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 6 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar 1", "bar two", "bar three"], ["0", "1", "2"]], position: LineCol { line: 9 } }), tags: [], position: LineCol { line: 8 } }], tags: [], position: LineCol { line: 10 } }], rules: [], tags: [], position: LineCol { line: 1 }, }, Scenario(Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }, Step { keyword: "When ", ty: When, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 5 } }, Step { keyword: "Then ", ty: Then, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 6 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar 1", "bar two", "bar three"], ["0", "1", "2"]], position: LineCol { line: 9 } }), tags: [], position: LineCol { line: 8 } }], tags: [], position: LineCol { line: 10 } }, RetryableScenario { event: Step(Step { keyword: "Then ", ty: Then, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 6 } }, Passed(CaptureLocations(Captures { pid: Some(PatternID(0)), spans: {0: 0..8, 1: 7..8} }), Some(Location { line: 11, column: 1 }))), retries: None })) +Feature(Feature { keyword: "Feature", name: "Outline", description: None, background: None, scenarios: [Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }, Step { keyword: "When ", ty: When, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 5 } }, Step { keyword: "Then ", ty: Then, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 6 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar 1", "bar two", "bar three"], ["0", "1", "2"]], position: LineCol { line: 9 } }), tags: [], position: LineCol { line: 8 } }], tags: [], position: LineCol { line: 10 } }], rules: [], tags: [], position: LineCol { line: 1 }, }, Scenario(Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }, Step { keyword: "When ", ty: When, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 5 } }, Step { keyword: "Then ", ty: Then, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 6 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar 1", "bar two", "bar three"], ["0", "1", "2"]], position: LineCol { line: 9 } }), tags: [], position: LineCol { line: 8 } }], tags: [], position: LineCol { line: 10 } }, RetryableScenario { event: Finished, retries: None })) +Feature(Feature { keyword: "Feature", name: "Outline", description: None, background: None, scenarios: [Scenario { keyword: "Scenario Outline", name: "foo", description: None, steps: [Step { keyword: "Given ", ty: Given, value: "foo is 0", docstring: None, table: None, position: LineCol { line: 4 } }, Step { keyword: "When ", ty: When, value: "foo is 1", docstring: None, table: None, position: LineCol { line: 5 } }, Step { keyword: "Then ", ty: Then, value: "foo is 2", docstring: None, table: None, position: LineCol { line: 6 } }], examples: [Examples { keyword: "Examples", name: None, description: None, table: Some(Table { rows: [["bar 1", "bar two", "bar three"], ["0", "1", "2"]], position: LineCol { line: 9 } }), tags: [], position: LineCol { line: 8 } }], tags: [], position: LineCol { line: 10 } }], rules: [], tags: [], position: LineCol { line: 1 }, }, Finished) +Finished