From 619ff4df92437b7422459c0a56308ea7788e090a Mon Sep 17 00:00:00 2001 From: "philips-software-forest-releaser[bot]" <80338643+philips-software-forest-releaser[bot]@users.noreply.github.com> Date: Fri, 21 Nov 2025 07:58:18 +0000 Subject: [PATCH 01/16] chore(main): release 3.1.1 (#257) Co-authored-by: philips-software-forest-releaser[bot] <80338643+philips-software-forest-releaser[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ CMakeLists.txt | 2 +- sonar-project.properties | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 81e1640f..96fd7be7 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "3.1.0" + ".": "3.1.1" } diff --git a/CHANGELOG.md b/CHANGELOG.md index c0efd33a..99a4d59d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## [3.1.1](https://github.com/philips-software/amp-cucumber-cpp-runner/compare/v3.1.0...v3.1.1) (2025-11-21) + + +### Bug Fixes + +* Resolve runtime static initialization order dependencies ([#254](https://github.com/philips-software/amp-cucumber-cpp-runner/issues/254)) ([#258](https://github.com/philips-software/amp-cucumber-cpp-runner/issues/258)) ([a45c85d](https://github.com/philips-software/amp-cucumber-cpp-runner/commit/a45c85d95cfe07d8c87b0ed5107c15982e86fe0d)) +* Revert IsEscapeCharacter signed char change ([#253](https://github.com/philips-software/amp-cucumber-cpp-runner/issues/253)) ([52d8a5d](https://github.com/philips-software/amp-cucumber-cpp-runner/commit/52d8a5d51d76535848499a98e4b75fbe4396e665)) + + +### Chores + +* Remove unused arguments in example app ([#255](https://github.com/philips-software/amp-cucumber-cpp-runner/issues/255)) ([410b33c](https://github.com/philips-software/amp-cucumber-cpp-runner/commit/410b33c71d98a2fb5f6efe0c2dcf65c76f5d7eb7)) + ## [3.1.0](https://github.com/philips-software/amp-cucumber-cpp-runner/compare/v3.0.0...v3.1.0) (2025-11-17) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9852a5f0..c30a33e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.24) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") -project(cucumber-cpp-runner LANGUAGES C CXX VERSION 3.1.0) # x-release-please-version +project(cucumber-cpp-runner LANGUAGES C CXX VERSION 3.1.1) # x-release-please-version include(ccr_test_helpers) diff --git a/sonar-project.properties b/sonar-project.properties index 91383944..b5f7fdd1 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -4,7 +4,7 @@ sonar.organization=philips-software sonar.projectName=amp-cucumber-cpp-runner # x-release-please-start-version -sonar.projectVersion=3.1.0 +sonar.projectVersion=3.1.1 # x-release-please-end sonar.links.homepage=https://github.com/philips-software/amp-cucumber-cpp-runner From 0abf7ab2a56e75191a05df144e105cfa330bb384 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Nov 2025 09:17:20 +0000 Subject: [PATCH 02/16] build(deps): bump philips-software/amp-devcontainer-cpp (#259) Bumps [philips-software/amp-devcontainer-cpp](https://github.com/philips-software/amp-devcontainer) from 6.0.1 to v6.6.0. - [Release notes](https://github.com/philips-software/amp-devcontainer/releases) - [Changelog](https://github.com/philips-software/amp-devcontainer/blob/main/CHANGELOG.md) - [Commits](https://github.com/philips-software/amp-devcontainer/compare/v6.0.1...v6.6.0) --- updated-dependencies: - dependency-name: philips-software/amp-devcontainer-cpp dependency-version: v6.6.0 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .devcontainer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 74399ea6..ad556862 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,3 +1,3 @@ -FROM ghcr.io/philips-software/amp-devcontainer-cpp:6.0.1@sha256:0b238dbdd0e39a9704fc5317269f654b8bfd23868bad9491e806ae417d645352 +FROM ghcr.io/philips-software/amp-devcontainer-cpp:v6.6.0@sha256:3f65569a719ca9b2d996222bcdce3dfe9797903ba4c3aafff364fa6fe9ca114d HEALTHCHECK NONE From 71e682f491060734317e1a839987eec02835d700 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Nov 2025 15:21:20 +0100 Subject: [PATCH 03/16] build(deps): bump actions/checkout from 5.0.1 to 6.0.0 (#261) Bumps [actions/checkout](https://github.com/actions/checkout) from 5.0.1 to 6.0.0. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/93cb6efe18208431cddfb8368fd83d5badbf9bfd...1af3b93b6815bc44a9784bd300feb67ff0d1eeb3) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 6.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 10 +++++----- .github/workflows/linting-formatting.yml | 2 +- .github/workflows/security.yml | 2 +- .github/workflows/static-analysis.yml | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 644bb6df..249f585e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,7 @@ jobs: runs-on: [ubuntu-latest] container: ghcr.io/philips-software/amp-devcontainer-cpp:5.6.2@sha256:a0804f7454d52564f07317f7e09a012261b6d9553dbe8854fcf265dce571cf86 # v5.6.2 steps: - - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-winsdk with: @@ -48,7 +48,7 @@ jobs: name: Linux Host Build runs-on: [ubuntu-24.04] steps: - - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - uses: hendrikmuhs/ccache-action@bfa03e1de4d7f7c3e80ad9109feedd05c4f5a716 # v1.2.19 with: key: ${{ github.job }} @@ -72,7 +72,7 @@ jobs: runs-on: [ubuntu-latest] container: ghcr.io/philips-software/amp-devcontainer-cpp:5.6.2@sha256:a0804f7454d52564f07317f7e09a012261b6d9553dbe8854fcf265dce571cf86 # v5.6.2 steps: - - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - uses: hendrikmuhs/ccache-action@bfa03e1de4d7f7c3e80ad9109feedd05c4f5a716 # v1.2.19 with: key: ${{ github.job }} @@ -100,7 +100,7 @@ jobs: pull-requests: write container: ghcr.io/philips-software/amp-devcontainer-cpp:5.6.2@sha256:a0804f7454d52564f07317f7e09a012261b6d9553dbe8854fcf265dce571cf86 # v5.6.2 steps: - - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - uses: hendrikmuhs/ccache-action@bfa03e1de4d7f7c3e80ad9109feedd05c4f5a716 # v1.2.19 with: key: ${{ github.job }} @@ -124,7 +124,7 @@ jobs: matrix: os: [macos-latest, windows-latest] steps: - - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false - uses: hendrikmuhs/ccache-action@bfa03e1de4d7f7c3e80ad9109feedd05c4f5a716 # v1.2.19 diff --git a/.github/workflows/linting-formatting.yml b/.github/workflows/linting-formatting.yml index d0979997..bfe0126d 100644 --- a/.github/workflows/linting-formatting.yml +++ b/.github/workflows/linting-formatting.yml @@ -22,7 +22,7 @@ jobs: pull-requests: write security-events: write steps: - - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: fetch-depth: 0 persist-credentials: false diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index ef16e3ca..c46765a5 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -21,7 +21,7 @@ jobs: actions: read contents: read steps: - - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false - name: Analysis diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 835a7928..e0535a37 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -22,7 +22,7 @@ jobs: env: SONAR_SERVER_URL: "https://sonarcloud.io" steps: - - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: fetch-depth: 0 # Disable shallow clone to enable blame information persist-credentials: false @@ -71,7 +71,7 @@ jobs: permissions: security-events: write steps: - - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false - uses: hendrikmuhs/ccache-action@bfa03e1de4d7f7c3e80ad9109feedd05c4f5a716 # v1.2.19 From 964806024796dedc666ed3dd78ac65183806f985 Mon Sep 17 00:00:00 2001 From: Alexander Romanenko Date: Fri, 3 Oct 2025 00:24:40 +0300 Subject: [PATCH 04/16] feat: ndjson reporting - Begin adding ndjson report writer and add compatibility validation tests. --- .../compatibility/ambiguous/ambiguous.feature | 6 ++ .../compatibility/ambiguous/ambiguous.ndjson | 13 +++ .../attachments/attachments.feature | 36 ++++++++ .../attachments/attachments.ndjson | 61 +++++++++++++ .../compatibility/attachments/cucumber.jpeg | Bin 0 -> 1444 bytes .../compatibility/attachments/cucumber.png | Bin 0 -> 1739 bytes .../compatibility/attachments/document.pdf | Bin 0 -> 10061 bytes .../backgrounds/backgrounds.feature | 17 ++++ .../backgrounds/backgrounds.ndjson | 36 ++++++++ .../compatibility/cdata/cdata.feature | 5 ++ .../compatibility/cdata/cdata.ndjson | 12 +++ .../data-tables/data-tables.feature | 13 +++ .../data-tables/data-tables.ndjson | 15 ++++ .../doc-strings/doc-strings.feature | 31 +++++++ .../doc-strings/doc-strings.ndjson | 24 ++++++ .../compatibility/empty/empty.feature | 7 ++ .../compatibility/empty/empty.ndjson | 9 ++ .../examples-tables-attachment/cucumber.jpeg | Bin 0 -> 1444 bytes .../examples-tables-attachment/cucumber.png | Bin 0 -> 1739 bytes .../examples-tables-attachment.feature | 10 +++ .../examples-tables-attachment.ndjson | 21 +++++ .../examples-tables-undefined.ndjson | 41 +++++++++ .../examples-undefined.feature | 17 ++++ .../examples-tables/examples-tables.feature | 37 ++++++++ .../examples-tables/examples-tables.ndjson | 80 ++++++++++++++++++ .../global-hooks-afterall-error.feature | 6 ++ .../global-hooks-afterall-error.ndjson | 27 ++++++ .../global-hooks-attachments.feature | 5 ++ .../global-hooks-attachments.ndjson | 20 +++++ .../global-hooks-beforeall-error.feature | 6 ++ .../global-hooks-beforeall-error.ndjson | 22 +++++ .../global-hooks/global-hooks.feature | 10 +++ .../global-hooks/global-hooks.ndjson | 31 +++++++ .../hooks-attachment/.gitattributes | 4 + .../hooks-attachment/cucumber.svg | 7 ++ .../hooks-attachment/hooks-attachment.feature | 7 ++ .../hooks-attachment/hooks-attachment.ndjson | 20 +++++ .../hooks-conditional.feature | 16 ++++ .../hooks-conditional.ndjson | 36 ++++++++ .../hooks-named/hooks-named.feature | 8 ++ .../hooks-named/hooks-named.ndjson | 18 ++++ .../hooks-undefined/hooks-undefined.feature | 5 ++ .../hooks-undefined/hooks-undefined.ndjson | 18 ++++ .../compatibility/hooks/hooks.feature | 8 ++ .../compatibility/hooks/hooks.ndjson | 29 +++++++ .../markdown/markdown.feature.md | 46 ++++++++++ .../compatibility/markdown/markdown.ndjson | 35 ++++++++ .../compatibility/minimal/minimal.feature | 10 +++ .../compatibility/minimal/minimal.ndjson | 12 +++ .../multiple-features-reversed-1.feature | 10 +++ .../multiple-features-reversed-2.feature | 10 +++ .../multiple-features-reversed-3.feature | 10 +++ .../multiple-features-reversed.arguments.txt | 1 + .../multiple-features-reversed.ndjson | 64 ++++++++++++++ .../multiple-features-1.feature | 10 +++ .../multiple-features-2.feature | 10 +++ .../multiple-features-3.feature | 10 +++ .../multiple-features.ndjson | 64 ++++++++++++++ .../parameter-types/parameter-types.feature | 11 +++ .../parameter-types/parameter-types.ndjson | 13 +++ .../compatibility/pending/pending.feature | 18 ++++ .../compatibility/pending/pending.ndjson | 30 +++++++ .../regular-expression.feature | 9 ++ .../regular-expression.ndjson | 16 ++++ .../retry-ambiguous.arguments.txt | 1 + .../retry-ambiguous/retry-ambiguous.feature | 3 + .../retry-ambiguous/retry-ambiguous.ndjson | 13 +++ .../retry-pending/retry-pending.arguments.txt | 1 + .../retry-pending/retry-pending.feature | 3 + .../retry-pending/retry-pending.ndjson | 12 +++ .../retry-undefined.arguments.txt | 1 + .../retry-undefined/retry-undefined.feature | 3 + .../retry-undefined/retry-undefined.ndjson | 12 +++ .../compatibility/retry/retry.arguments.txt | 1 + .../compatibility/retry/retry.feature | 18 ++++ .../compatibility/retry/retry.ndjson | 53 ++++++++++++ .../rules-backgrounds.feature | 23 +++++ .../rules-backgrounds.ndjson | 44 ++++++++++ .../compatibility/rules/rules.feature | 29 +++++++ .../compatibility/rules/rules.ndjson | 47 ++++++++++ .../compatibility/skipped/skipped.feature | 19 +++++ .../compatibility/skipped/skipped.ndjson | 33 ++++++++ .../stack-traces/stack-traces.feature | 10 +++ .../stack-traces/stack-traces.ndjson | 12 +++ .../compatibility/undefined/undefined.feature | 20 +++++ .../compatibility/undefined/undefined.ndjson | 39 +++++++++ .../unknown-parameter-type.feature | 7 ++ .../unknown-parameter-type.ndjson | 13 +++ .../unused-steps/unused-steps.feature | 6 ++ .../unused-steps/unused-steps.ndjson | 13 +++ cucumber_cpp/library/Application.cpp | 2 + .../library/cucumber_expression/Ast.cpp | 6 +- .../library/cucumber_expression/Ast.hpp | 6 +- cucumber_cpp/library/report/CMakeLists.txt | 2 + cucumber_cpp/library/report/NdjsonReport.cpp | 71 ++++++++++++++++ cucumber_cpp/library/report/NdjsonReport.hpp | 26 ++++++ 96 files changed, 1726 insertions(+), 6 deletions(-) create mode 100644 cucumber_cpp/acceptance_test/compatibility/ambiguous/ambiguous.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/ambiguous/ambiguous.ndjson create mode 100644 cucumber_cpp/acceptance_test/compatibility/attachments/attachments.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/attachments/attachments.ndjson create mode 100644 cucumber_cpp/acceptance_test/compatibility/attachments/cucumber.jpeg create mode 100644 cucumber_cpp/acceptance_test/compatibility/attachments/cucumber.png create mode 100644 cucumber_cpp/acceptance_test/compatibility/attachments/document.pdf create mode 100644 cucumber_cpp/acceptance_test/compatibility/backgrounds/backgrounds.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/backgrounds/backgrounds.ndjson create mode 100644 cucumber_cpp/acceptance_test/compatibility/cdata/cdata.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/cdata/cdata.ndjson create mode 100644 cucumber_cpp/acceptance_test/compatibility/data-tables/data-tables.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/data-tables/data-tables.ndjson create mode 100644 cucumber_cpp/acceptance_test/compatibility/doc-strings/doc-strings.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/doc-strings/doc-strings.ndjson create mode 100644 cucumber_cpp/acceptance_test/compatibility/empty/empty.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/empty/empty.ndjson create mode 100644 cucumber_cpp/acceptance_test/compatibility/examples-tables-attachment/cucumber.jpeg create mode 100644 cucumber_cpp/acceptance_test/compatibility/examples-tables-attachment/cucumber.png create mode 100644 cucumber_cpp/acceptance_test/compatibility/examples-tables-attachment/examples-tables-attachment.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/examples-tables-attachment/examples-tables-attachment.ndjson create mode 100644 cucumber_cpp/acceptance_test/compatibility/examples-tables-undefined/examples-tables-undefined.ndjson create mode 100644 cucumber_cpp/acceptance_test/compatibility/examples-tables-undefined/examples-undefined.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/examples-tables/examples-tables.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/examples-tables/examples-tables.ndjson create mode 100644 cucumber_cpp/acceptance_test/compatibility/global-hooks-afterall-error/global-hooks-afterall-error.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/global-hooks-afterall-error/global-hooks-afterall-error.ndjson create mode 100644 cucumber_cpp/acceptance_test/compatibility/global-hooks-attachments/global-hooks-attachments.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/global-hooks-attachments/global-hooks-attachments.ndjson create mode 100644 cucumber_cpp/acceptance_test/compatibility/global-hooks-beforeall-error/global-hooks-beforeall-error.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/global-hooks-beforeall-error/global-hooks-beforeall-error.ndjson create mode 100644 cucumber_cpp/acceptance_test/compatibility/global-hooks/global-hooks.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/global-hooks/global-hooks.ndjson create mode 100644 cucumber_cpp/acceptance_test/compatibility/hooks-attachment/.gitattributes create mode 100644 cucumber_cpp/acceptance_test/compatibility/hooks-attachment/cucumber.svg create mode 100644 cucumber_cpp/acceptance_test/compatibility/hooks-attachment/hooks-attachment.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/hooks-attachment/hooks-attachment.ndjson create mode 100644 cucumber_cpp/acceptance_test/compatibility/hooks-conditional/hooks-conditional.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/hooks-conditional/hooks-conditional.ndjson create mode 100644 cucumber_cpp/acceptance_test/compatibility/hooks-named/hooks-named.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/hooks-named/hooks-named.ndjson create mode 100644 cucumber_cpp/acceptance_test/compatibility/hooks-undefined/hooks-undefined.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/hooks-undefined/hooks-undefined.ndjson create mode 100644 cucumber_cpp/acceptance_test/compatibility/hooks/hooks.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/hooks/hooks.ndjson create mode 100644 cucumber_cpp/acceptance_test/compatibility/markdown/markdown.feature.md create mode 100644 cucumber_cpp/acceptance_test/compatibility/markdown/markdown.ndjson create mode 100644 cucumber_cpp/acceptance_test/compatibility/minimal/minimal.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/minimal/minimal.ndjson create mode 100644 cucumber_cpp/acceptance_test/compatibility/multiple-features-reversed/multiple-features-reversed-1.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/multiple-features-reversed/multiple-features-reversed-2.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/multiple-features-reversed/multiple-features-reversed-3.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/multiple-features-reversed/multiple-features-reversed.arguments.txt create mode 100644 cucumber_cpp/acceptance_test/compatibility/multiple-features-reversed/multiple-features-reversed.ndjson create mode 100644 cucumber_cpp/acceptance_test/compatibility/multiple-features/multiple-features-1.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/multiple-features/multiple-features-2.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/multiple-features/multiple-features-3.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/multiple-features/multiple-features.ndjson create mode 100644 cucumber_cpp/acceptance_test/compatibility/parameter-types/parameter-types.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/parameter-types/parameter-types.ndjson create mode 100644 cucumber_cpp/acceptance_test/compatibility/pending/pending.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/pending/pending.ndjson create mode 100644 cucumber_cpp/acceptance_test/compatibility/regular-expression/regular-expression.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/regular-expression/regular-expression.ndjson create mode 100644 cucumber_cpp/acceptance_test/compatibility/retry-ambiguous/retry-ambiguous.arguments.txt create mode 100644 cucumber_cpp/acceptance_test/compatibility/retry-ambiguous/retry-ambiguous.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/retry-ambiguous/retry-ambiguous.ndjson create mode 100644 cucumber_cpp/acceptance_test/compatibility/retry-pending/retry-pending.arguments.txt create mode 100644 cucumber_cpp/acceptance_test/compatibility/retry-pending/retry-pending.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/retry-pending/retry-pending.ndjson create mode 100644 cucumber_cpp/acceptance_test/compatibility/retry-undefined/retry-undefined.arguments.txt create mode 100644 cucumber_cpp/acceptance_test/compatibility/retry-undefined/retry-undefined.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/retry-undefined/retry-undefined.ndjson create mode 100644 cucumber_cpp/acceptance_test/compatibility/retry/retry.arguments.txt create mode 100644 cucumber_cpp/acceptance_test/compatibility/retry/retry.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/retry/retry.ndjson create mode 100644 cucumber_cpp/acceptance_test/compatibility/rules-backgrounds/rules-backgrounds.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/rules-backgrounds/rules-backgrounds.ndjson create mode 100644 cucumber_cpp/acceptance_test/compatibility/rules/rules.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/rules/rules.ndjson create mode 100644 cucumber_cpp/acceptance_test/compatibility/skipped/skipped.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/skipped/skipped.ndjson create mode 100644 cucumber_cpp/acceptance_test/compatibility/stack-traces/stack-traces.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/stack-traces/stack-traces.ndjson create mode 100644 cucumber_cpp/acceptance_test/compatibility/undefined/undefined.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/undefined/undefined.ndjson create mode 100644 cucumber_cpp/acceptance_test/compatibility/unknown-parameter-type/unknown-parameter-type.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/unknown-parameter-type/unknown-parameter-type.ndjson create mode 100644 cucumber_cpp/acceptance_test/compatibility/unused-steps/unused-steps.feature create mode 100644 cucumber_cpp/acceptance_test/compatibility/unused-steps/unused-steps.ndjson create mode 100644 cucumber_cpp/library/report/NdjsonReport.cpp create mode 100644 cucumber_cpp/library/report/NdjsonReport.hpp diff --git a/cucumber_cpp/acceptance_test/compatibility/ambiguous/ambiguous.feature b/cucumber_cpp/acceptance_test/compatibility/ambiguous/ambiguous.feature new file mode 100644 index 00000000..f021e17c --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/ambiguous/ambiguous.feature @@ -0,0 +1,6 @@ +Feature: Ambiguous steps + Multiple step definitions that match a pickle step result in an AMBIGUOUS status, since Cucumnber cannot determine + which one to execute. + + Scenario: Multiple step definitions for a step + Given a step with multiple definitions diff --git a/cucumber_cpp/acceptance_test/compatibility/ambiguous/ambiguous.ndjson b/cucumber_cpp/acceptance_test/compatibility/ambiguous/ambiguous.ndjson new file mode 100644 index 00000000..4e6b887b --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/ambiguous/ambiguous.ndjson @@ -0,0 +1,13 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"Feature: Ambiguous steps\n Multiple step definitions that match a pickle step result in an AMBIGUOUS status, since Cucumnber cannot determine\n which one to execute.\n\n Scenario: Multiple step definitions for a step\n Given a step with multiple definitions\n","uri":"samples/ambiguous/ambiguous.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Ambiguous steps","description":" Multiple step definitions that match a pickle step result in an AMBIGUOUS status, since Cucumnber cannot determine\n which one to execute.","children":[{"scenario":{"id":"1","tags":[],"location":{"line":5,"column":3},"keyword":"Scenario","name":"Multiple step definitions for a step","description":"","steps":[{"id":"0","location":{"line":6,"column":5},"keyword":"Given ","keywordType":"Context","text":"a step with multiple definitions"}],"examples":[]}}]},"comments":[],"uri":"samples/ambiguous/ambiguous.feature"}} +{"pickle":{"id":"3","uri":"samples/ambiguous/ambiguous.feature","astNodeIds":["1"],"tags":[],"name":"Multiple step definitions for a step","language":"en","steps":[{"id":"2","text":"a step with multiple definitions","type":"Context","astNodeIds":["0"]}]}} +{"stepDefinition":{"id":"4","pattern":{"type":"REGULAR_EXPRESSION","source":"^a (.*?) with (.*?)$"},"sourceReference":{"uri":"samples/ambiguous/ambiguous.ts","location":{"line":3}}}} +{"stepDefinition":{"id":"5","pattern":{"type":"REGULAR_EXPRESSION","source":"^a step with (.*)$"},"sourceReference":{"uri":"samples/ambiguous/ambiguous.ts","location":{"line":7}}}} +{"testRunStarted":{"id":"6","timestamp":{"seconds":0,"nanos":0}}} +{"testCase":{"id":"7","pickleId":"3","testSteps":[{"id":"8","pickleStepId":"2","stepDefinitionIds":["4","5"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":2,"value":"step","children":[]}},{"group":{"start":12,"value":"multiple definitions","children":[]}}]},{"stepMatchArguments":[{"group":{"start":12,"value":"multiple definitions","children":[]},"parameterTypeName":""}]}]}],"testRunStartedId":"6"}} +{"testCaseStarted":{"id":"9","testCaseId":"7","timestamp":{"seconds":0,"nanos":1000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"9","testStepId":"8","timestamp":{"seconds":0,"nanos":2000000}}} +{"testStepFinished":{"testCaseStartedId":"9","testStepId":"8","testStepResult":{"status":"AMBIGUOUS","duration":{"seconds":0,"nanos":0}},"timestamp":{"seconds":0,"nanos":3000000}}} +{"testCaseFinished":{"testCaseStartedId":"9","timestamp":{"seconds":0,"nanos":4000000},"willBeRetried":false}} +{"testRunFinished":{"testRunStartedId":"6","timestamp":{"seconds":0,"nanos":5000000},"success":false}} diff --git a/cucumber_cpp/acceptance_test/compatibility/attachments/attachments.feature b/cucumber_cpp/acceptance_test/compatibility/attachments/attachments.feature new file mode 100644 index 00000000..aa44b74d --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/attachments/attachments.feature @@ -0,0 +1,36 @@ +Feature: Attachments + It is sometimes useful to take a screenshot while a scenario runs or capture some logs. + + Cucumber lets you `attach` arbitrary files during execution, and you can + specify a content type for the contents. + + Formatters can then render these attachments in reports. + + Attachments must have a body and a content type. + + Scenario: Strings can be attached with a media type + Beware that some formatters such as @cucumber/react use the media type + to determine how to display an attachment. + + When the string "hello" is attached as "application/octet-stream" + + Scenario: Log text + When the string "hello" is logged + + Scenario: Log ANSI coloured text + When text with ANSI escapes is logged + + Scenario: Log JSON + When the following string is attached as "application/json": + ``` + {"message": "The big question", "foo": "bar"} + ``` + + Scenario: Byte arrays are base64-encoded regardless of media type + When an array with 10 bytes is attached as "text/plain" + + Scenario: Attaching PDFs with a different filename + When a PDF document is attached and renamed + + Scenario: Attaching URIs + When a link to "https://cucumber.io" is attached diff --git a/cucumber_cpp/acceptance_test/compatibility/attachments/attachments.ndjson b/cucumber_cpp/acceptance_test/compatibility/attachments/attachments.ndjson new file mode 100644 index 00000000..89496576 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/attachments/attachments.ndjson @@ -0,0 +1,61 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"Feature: Attachments\n It is sometimes useful to take a screenshot while a scenario runs or capture some logs.\n\n Cucumber lets you `attach` arbitrary files during execution, and you can\n specify a content type for the contents.\n\n Formatters can then render these attachments in reports.\n\n Attachments must have a body and a content type.\n\n Scenario: Strings can be attached with a media type\n Beware that some formatters such as @cucumber/react use the media type\n to determine how to display an attachment.\n\n When the string \"hello\" is attached as \"application/octet-stream\"\n\n Scenario: Log text\n When the string \"hello\" is logged\n\n Scenario: Log ANSI coloured text\n When text with ANSI escapes is logged\n\n Scenario: Log JSON\n When the following string is attached as \"application/json\":\n ```\n {\"message\": \"The big question\", \"foo\": \"bar\"}\n ```\n\n Scenario: Byte arrays are base64-encoded regardless of media type\n When an array with 10 bytes is attached as \"text/plain\"\n\n Scenario: Attaching PDFs with a different filename\n When a PDF document is attached and renamed\n\n Scenario: Attaching URIs\n When a link to \"https://cucumber.io\" is attached\n","uri":"samples/attachments/attachments.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Attachments","description":" It is sometimes useful to take a screenshot while a scenario runs or capture some logs.\n\n Cucumber lets you `attach` arbitrary files during execution, and you can\n specify a content type for the contents.\n\n Formatters can then render these attachments in reports.\n\n Attachments must have a body and a content type.","children":[{"scenario":{"id":"1","tags":[],"location":{"line":11,"column":3},"keyword":"Scenario","name":"Strings can be attached with a media type","description":" Beware that some formatters such as @cucumber/react use the media type\n to determine how to display an attachment.","steps":[{"id":"0","location":{"line":15,"column":5},"keyword":"When ","keywordType":"Action","text":"the string \"hello\" is attached as \"application/octet-stream\""}],"examples":[]}},{"scenario":{"id":"3","tags":[],"location":{"line":17,"column":3},"keyword":"Scenario","name":"Log text","description":"","steps":[{"id":"2","location":{"line":18,"column":5},"keyword":"When ","keywordType":"Action","text":"the string \"hello\" is logged"}],"examples":[]}},{"scenario":{"id":"5","tags":[],"location":{"line":20,"column":3},"keyword":"Scenario","name":"Log ANSI coloured text","description":"","steps":[{"id":"4","location":{"line":21,"column":5},"keyword":"When ","keywordType":"Action","text":"text with ANSI escapes is logged"}],"examples":[]}},{"scenario":{"id":"7","tags":[],"location":{"line":23,"column":3},"keyword":"Scenario","name":"Log JSON","description":"","steps":[{"id":"6","location":{"line":24,"column":6},"keyword":"When ","keywordType":"Action","text":"the following string is attached as \"application/json\":","docString":{"location":{"line":25,"column":8},"content":"{\"message\": \"The big question\", \"foo\": \"bar\"}","delimiter":"```"}}],"examples":[]}},{"scenario":{"id":"9","tags":[],"location":{"line":29,"column":3},"keyword":"Scenario","name":"Byte arrays are base64-encoded regardless of media type","description":"","steps":[{"id":"8","location":{"line":30,"column":5},"keyword":"When ","keywordType":"Action","text":"an array with 10 bytes is attached as \"text/plain\""}],"examples":[]}},{"scenario":{"id":"11","tags":[],"location":{"line":32,"column":3},"keyword":"Scenario","name":"Attaching PDFs with a different filename","description":"","steps":[{"id":"10","location":{"line":33,"column":5},"keyword":"When ","keywordType":"Action","text":"a PDF document is attached and renamed"}],"examples":[]}},{"scenario":{"id":"13","tags":[],"location":{"line":35,"column":3},"keyword":"Scenario","name":"Attaching URIs","description":"","steps":[{"id":"12","location":{"line":36,"column":5},"keyword":"When ","keywordType":"Action","text":"a link to \"https://cucumber.io\" is attached"}],"examples":[]}}]},"comments":[],"uri":"samples/attachments/attachments.feature"}} +{"pickle":{"id":"15","uri":"samples/attachments/attachments.feature","astNodeIds":["1"],"tags":[],"name":"Strings can be attached with a media type","language":"en","steps":[{"id":"14","text":"the string \"hello\" is attached as \"application/octet-stream\"","type":"Action","astNodeIds":["0"]}]}} +{"pickle":{"id":"17","uri":"samples/attachments/attachments.feature","astNodeIds":["3"],"tags":[],"name":"Log text","language":"en","steps":[{"id":"16","text":"the string \"hello\" is logged","type":"Action","astNodeIds":["2"]}]}} +{"pickle":{"id":"19","uri":"samples/attachments/attachments.feature","astNodeIds":["5"],"tags":[],"name":"Log ANSI coloured text","language":"en","steps":[{"id":"18","text":"text with ANSI escapes is logged","type":"Action","astNodeIds":["4"]}]}} +{"pickle":{"id":"21","uri":"samples/attachments/attachments.feature","astNodeIds":["7"],"tags":[],"name":"Log JSON","language":"en","steps":[{"id":"20","text":"the following string is attached as \"application/json\":","type":"Action","argument":{"docString":{"content":"{\"message\": \"The big question\", \"foo\": \"bar\"}"}},"astNodeIds":["6"]}]}} +{"pickle":{"id":"23","uri":"samples/attachments/attachments.feature","astNodeIds":["9"],"tags":[],"name":"Byte arrays are base64-encoded regardless of media type","language":"en","steps":[{"id":"22","text":"an array with 10 bytes is attached as \"text/plain\"","type":"Action","astNodeIds":["8"]}]}} +{"pickle":{"id":"25","uri":"samples/attachments/attachments.feature","astNodeIds":["11"],"tags":[],"name":"Attaching PDFs with a different filename","language":"en","steps":[{"id":"24","text":"a PDF document is attached and renamed","type":"Action","astNodeIds":["10"]}]}} +{"pickle":{"id":"27","uri":"samples/attachments/attachments.feature","astNodeIds":["13"],"tags":[],"name":"Attaching URIs","language":"en","steps":[{"id":"26","text":"a link to \"https://cucumber.io\" is attached","type":"Action","astNodeIds":["12"]}]}} +{"stepDefinition":{"id":"28","pattern":{"type":"CUCUMBER_EXPRESSION","source":"the string {string} is attached as {string}"},"sourceReference":{"uri":"samples/attachments/attachments.ts","location":{"line":4}}}} +{"stepDefinition":{"id":"29","pattern":{"type":"CUCUMBER_EXPRESSION","source":"the string {string} is logged"},"sourceReference":{"uri":"samples/attachments/attachments.ts","location":{"line":8}}}} +{"stepDefinition":{"id":"30","pattern":{"type":"CUCUMBER_EXPRESSION","source":"text with ANSI escapes is logged"},"sourceReference":{"uri":"samples/attachments/attachments.ts","location":{"line":12}}}} +{"stepDefinition":{"id":"31","pattern":{"type":"CUCUMBER_EXPRESSION","source":"the following string is attached as {string}:"},"sourceReference":{"uri":"samples/attachments/attachments.ts","location":{"line":18}}}} +{"stepDefinition":{"id":"32","pattern":{"type":"CUCUMBER_EXPRESSION","source":"an array with {int} bytes is attached as {string}"},"sourceReference":{"uri":"samples/attachments/attachments.ts","location":{"line":22}}}} +{"stepDefinition":{"id":"33","pattern":{"type":"CUCUMBER_EXPRESSION","source":"a PDF document is attached and renamed"},"sourceReference":{"uri":"samples/attachments/attachments.ts","location":{"line":31}}}} +{"stepDefinition":{"id":"34","pattern":{"type":"CUCUMBER_EXPRESSION","source":"a link to {string} is attached"},"sourceReference":{"uri":"samples/attachments/attachments.ts","location":{"line":38}}}} +{"testRunStarted":{"id":"35","timestamp":{"seconds":0,"nanos":0}}} +{"testCase":{"id":"36","pickleId":"15","testSteps":[{"id":"37","pickleStepId":"14","stepDefinitionIds":["28"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":11,"value":"\"hello\"","children":[{"start":12,"value":"hello","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"},{"group":{"start":34,"value":"\"application/octet-stream\"","children":[{"start":35,"value":"application/octet-stream","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]}],"testRunStartedId":"35"}} +{"testCase":{"id":"38","pickleId":"17","testSteps":[{"id":"39","pickleStepId":"16","stepDefinitionIds":["29"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":11,"value":"\"hello\"","children":[{"start":12,"value":"hello","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]}],"testRunStartedId":"35"}} +{"testCase":{"id":"40","pickleId":"19","testSteps":[{"id":"41","pickleStepId":"18","stepDefinitionIds":["30"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"35"}} +{"testCase":{"id":"42","pickleId":"21","testSteps":[{"id":"43","pickleStepId":"20","stepDefinitionIds":["31"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":36,"value":"\"application/json\"","children":[{"start":37,"value":"application/json","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]}],"testRunStartedId":"35"}} +{"testCase":{"id":"44","pickleId":"23","testSteps":[{"id":"45","pickleStepId":"22","stepDefinitionIds":["32"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":14,"value":"10","children":[]},"parameterTypeName":"int"},{"group":{"start":38,"value":"\"text/plain\"","children":[{"start":39,"value":"text/plain","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]}],"testRunStartedId":"35"}} +{"testCase":{"id":"46","pickleId":"25","testSteps":[{"id":"47","pickleStepId":"24","stepDefinitionIds":["33"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"35"}} +{"testCase":{"id":"48","pickleId":"27","testSteps":[{"id":"49","pickleStepId":"26","stepDefinitionIds":["34"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":10,"value":"\"https://cucumber.io\"","children":[{"start":11,"value":"https://cucumber.io","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]}],"testRunStartedId":"35"}} +{"testCaseStarted":{"id":"50","testCaseId":"36","timestamp":{"seconds":0,"nanos":1000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"50","testStepId":"37","timestamp":{"seconds":0,"nanos":2000000}}} +{"attachment":{"testCaseStartedId":"50","testStepId":"37","body":"hello","contentEncoding":"IDENTITY","mediaType":"application/octet-stream","timestamp":{"seconds":0,"nanos":3000000}}} +{"testStepFinished":{"testCaseStartedId":"50","testStepId":"37","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":4000000}}} +{"testCaseFinished":{"testCaseStartedId":"50","timestamp":{"seconds":0,"nanos":5000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"51","testCaseId":"38","timestamp":{"seconds":0,"nanos":6000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"51","testStepId":"39","timestamp":{"seconds":0,"nanos":7000000}}} +{"attachment":{"testCaseStartedId":"51","testStepId":"39","body":"hello","contentEncoding":"IDENTITY","mediaType":"text/x.cucumber.log+plain","timestamp":{"seconds":0,"nanos":8000000}}} +{"testStepFinished":{"testCaseStartedId":"51","testStepId":"39","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":9000000}}} +{"testCaseFinished":{"testCaseStartedId":"51","timestamp":{"seconds":0,"nanos":10000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"52","testCaseId":"40","timestamp":{"seconds":0,"nanos":11000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"52","testStepId":"41","timestamp":{"seconds":0,"nanos":12000000}}} +{"attachment":{"testCaseStartedId":"52","testStepId":"41","body":"This displays a \u001b[31mr\u001b[0m\u001b[91ma\u001b[0m\u001b[33mi\u001b[0m\u001b[32mn\u001b[0m\u001b[34mb\u001b[0m\u001b[95mo\u001b[0m\u001b[35mw\u001b[0m","contentEncoding":"IDENTITY","mediaType":"text/x.cucumber.log+plain","timestamp":{"seconds":0,"nanos":13000000}}} +{"testStepFinished":{"testCaseStartedId":"52","testStepId":"41","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":14000000}}} +{"testCaseFinished":{"testCaseStartedId":"52","timestamp":{"seconds":0,"nanos":15000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"53","testCaseId":"42","timestamp":{"seconds":0,"nanos":16000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"53","testStepId":"43","timestamp":{"seconds":0,"nanos":17000000}}} +{"attachment":{"testCaseStartedId":"53","testStepId":"43","body":"{\"message\": \"The big question\", \"foo\": \"bar\"}","contentEncoding":"IDENTITY","mediaType":"application/json","timestamp":{"seconds":0,"nanos":18000000}}} +{"testStepFinished":{"testCaseStartedId":"53","testStepId":"43","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":19000000}}} +{"testCaseFinished":{"testCaseStartedId":"53","timestamp":{"seconds":0,"nanos":20000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"54","testCaseId":"44","timestamp":{"seconds":0,"nanos":21000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"54","testStepId":"45","timestamp":{"seconds":0,"nanos":22000000}}} +{"attachment":{"testCaseStartedId":"54","testStepId":"45","body":"AAECAwQFBgcICQ==","contentEncoding":"BASE64","mediaType":"text/plain","timestamp":{"seconds":0,"nanos":23000000}}} +{"testStepFinished":{"testCaseStartedId":"54","testStepId":"45","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":24000000}}} +{"testCaseFinished":{"testCaseStartedId":"54","timestamp":{"seconds":0,"nanos":25000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"55","testCaseId":"46","timestamp":{"seconds":0,"nanos":26000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"55","testStepId":"47","timestamp":{"seconds":0,"nanos":27000000}}} +{"attachment":{"testCaseStartedId":"55","testStepId":"47","body":"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RmlsZTIgOCAwIFI+PgplbmRvYmoKMTAgMCBvYmoKPDwvVHlwZSAvRm9udAovRm9udERlc2NyaXB0b3IgOSAwIFIKL0Jhc2VGb250IC9BQUFBQUErQXJpYWxNVAovU3VidHlwZSAvQ0lERm9udFR5cGUyCi9DSURUb0dJRE1hcCAvSWRlbnRpdHkKL0NJRFN5c3RlbUluZm8gPDwvUmVnaXN0cnkgKEFkb2JlKQovT3JkZXJpbmcgKElkZW50aXR5KQovU3VwcGxlbWVudCAwPj4KL1cgWzAgWzc1MF0gNTUgWzYxMC44Mzk4NF0gNzIgWzU1Ni4xNTIzNF0gODcgWzI3Ny44MzIwM11dCi9EVyA1MDA+PgplbmRvYmoKMTEgMCBvYmoKPDwvRmlsdGVyIC9GbGF0ZURlY29kZQovTGVuZ3RoIDI1MD4+IHN0cmVhbQp4nF2Qy2rEIBSG9z7FWU4Xg0lmMtNFEMqUQha90LQPYPQkFRoVYxZ5+3pJU6ig8PP/n+dCb+1jq5UH+uaM6NDDoLR0OJvFCYQeR6VJWYFUwm8qvWLiltAAd+vscWr1YEjTAND34M7erXB4kKbHO0JfnUSn9AiHz1sXdLdY+40Tag8FYQwkDuGnZ25f+IRAE3ZsZfCVX4+B+Ut8rBahSrrM3QgjcbZcoON6RNIU4TBonsJhBLX851eZ6gfxxV1Mn64hXRT1mUV1vk/qUid2S5W/zF6ivmQos9fTls5+LBqXs08kFufCMGmDaYrYv9K4L9kaG6l4fwAdQH9hCmVuZHN0cmVhbQplbmRvYmoKNCAwIG9iago8PC9UeXBlIC9Gb250Ci9TdWJ0eXBlIC9UeXBlMAovQmFzZUZvbnQgL0FBQUFBQStBcmlhbE1UCi9FbmNvZGluZyAvSWRlbnRpdHktSAovRGVzY2VuZGFudEZvbnRzIFsxMCAwIFJdCi9Ub1VuaWNvZGUgMTEgMCBSPj4KZW5kb2JqCnhyZWYKMCAxMgowMDAwMDAwMDAwIDY1NTM1IGYgCjAwMDAwMDAwMTUgMDAwMDAgbiAKMDAwMDAwMDM4MiAwMDAwMCBuIAowMDAwMDAwMTA4IDAwMDAwIG4gCjAwMDAwMDk2MDYgMDAwMDAgbiAKMDAwMDAwMDE0NSAwMDAwMCBuIAowMDAwMDAwNTkwIDAwMDAwIG4gCjAwMDAwMDA2NDUgMDAwMDAgbiAKMDAwMDAwMDY5MiAwMDAwMCBuIAowMDAwMDA4Nzg3IDAwMDAwIG4gCjAwMDAwMDkwMjEgMDAwMDAgbiAKMDAwMDAwOTI4NSAwMDAwMCBuIAp0cmFpbGVyCjw8L1NpemUgMTIKL1Jvb3QgNyAwIFIKL0luZm8gMSAwIFI+PgpzdGFydHhyZWYKOTc0NQolJUVPRgo=","contentEncoding":"BASE64","mediaType":"application/pdf","fileName":"renamed.pdf","timestamp":{"seconds":0,"nanos":28000000}}} +{"testStepFinished":{"testCaseStartedId":"55","testStepId":"47","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":29000000}}} +{"testCaseFinished":{"testCaseStartedId":"55","timestamp":{"seconds":0,"nanos":30000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"56","testCaseId":"48","timestamp":{"seconds":0,"nanos":31000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"56","testStepId":"49","timestamp":{"seconds":0,"nanos":32000000}}} +{"attachment":{"testCaseStartedId":"56","testStepId":"49","body":"https://cucumber.io","contentEncoding":"IDENTITY","mediaType":"text/uri-list","timestamp":{"seconds":0,"nanos":33000000}}} +{"testStepFinished":{"testCaseStartedId":"56","testStepId":"49","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":34000000}}} +{"testCaseFinished":{"testCaseStartedId":"56","timestamp":{"seconds":0,"nanos":35000000},"willBeRetried":false}} +{"testRunFinished":{"testRunStartedId":"35","timestamp":{"seconds":0,"nanos":36000000},"success":true}} diff --git a/cucumber_cpp/acceptance_test/compatibility/attachments/cucumber.jpeg b/cucumber_cpp/acceptance_test/compatibility/attachments/cucumber.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..e833d6c77d33e620ae49d01c6341ad7e5543bbd1 GIT binary patch literal 1444 zcmex=ma3|jiIItm zOAI4iKMQ#V{6EAX$ibk;pvlar#K0uT$SlbC{|JK&&=V}oKwrQC2Ma43I|Cy#)Bjrx z93W3JFj%5R(9qV{Ntcq}Ky~tP0uLAPSj53Js=3YaT3(saOkCY9;`5A|n$EGYdN> z$V3JPCPrqUBN+tQg%k~il>!AEoq|My6AOzQCy9zF8yTB~CKo{+&uGtZX0w)!P@n75 z+pl=GZ!o)2TKe4kXH-t@v#4EXEL!JE?zOu6r)a^it+7!xlS1t8{b#8CcjV%O8K0Lw zw!5=@{{4E%lYXmb|9XFR)y|pcq!QHyPd&4_T>Dx#CekoQenQBu?LV{I?)a=Z|5`qv zFCb50m1$zkt9Lo_J0{jC=okGqK3#m~$Ha_v^0sbzj}ElmKM-8K@73}%+E1_Sj1$h= za&Sv<=wdZVW0znRzq!_L_bo^lOYMz6H&?{%)XoFh(vNfajh)BRw*tXt#N5h?h}`dZpTv+M2|iZeX+YndxfsS7m0HMKkjMk z3R-;5(6ii>*OK{q>6sTyS60rQly}eE#LW&5BG%-(C1!D;fUT^{(mfa_yh< z{#u>M^5=OJ`#1Z*!uSb$%D$efQTh0vq2T`C;?gU-q$)Q@ZJHi;`qC^B2V>vgrM{Op zz2Y^CHRFrdI~bc)vyq`s=08J-S2f$|3$=&W)J@FMUY+(-GI%Z`A@L?@)(B$FN=Q(t=#l1^;xf6 ztKqtSx0-4T?$s+Kr!hS|dgkT)$(;KdOXF_sl{kL&qTE`s1rg3$Iy;OF^4Vh9&`X%c- z?@Ir1`muNQ?HGfD#&eeSnRs0PY8_Wf0x zYr%isu|McfyL=m%q*VpMX&9LEAPE|n37MD~SOi&xgcSot42=?%9Sb43h7p*8_w1>- z6Mg&7uRHgQ{q+{+?($T>Bl_*Z+yh@{H3b$5c{NME=w}I8|8lFOYSF`(6w%|A@+BXl zmusIkS2)Mu_D0Bf{>CWJM_W~opFJsmFzB$zE1{4Rf8~=jG8xtK!v7@pU6p$h?!dst zAi;cKJ=ASXzzoOCisUvHRt7dfAw$K$LSa!QBS)~?m_cs48@=pNOiq~YFVP2{3ZGA2 z+`D6=>s#ATRX)mE@f(tl=gZwXkQQv**LRUIg?&x;o5PWIH+oN(d8?&{>zqn{JdOYJ zpDR~h9MUx8cipWf_R8znWtJ&uK2N+Xmx{{Kw?qP#Uw literal 0 HcmV?d00001 diff --git a/cucumber_cpp/acceptance_test/compatibility/attachments/cucumber.png b/cucumber_cpp/acceptance_test/compatibility/attachments/cucumber.png new file mode 100644 index 0000000000000000000000000000000000000000..2760899aa0ce16aeaaea93d3118a32e7ac5bec8d GIT binary patch literal 1739 zcmV;+1~mDJP)G+r@kQ0VOJz1t=x5=pe3owlM@Ei<#*ZtpGI zgKd}Iv=WU6L@O5L5Qs#)gFvk*7OQ`VCsjOx5<>9^RV-lQA0`qL#Hi6fjMC@#y`7oe zS+={g-EDP}m+f}vz4x2%_`Ec`caU@Gwv+u9&;ebh;EPxToe6TQSS7$RIEHqf|0i z0O+ z#n5`Lu?_+l5a?76FBT_ov)oVPu)W&2iyqQk6q$E2`kQlqo37e8-)c+O?QiP<=H+=W zgC{tLKe`UI8wSZ$`}IIZS7^VP!&SQ9uqqj{=4V~1HP0i=kNxUV+pBnmxV8-q#Bxu7a+-a2h-P!vK`Neu>T>`ydm{x2F*T=U zFja;RD&fUT?=ygOHKmEIjm9$XXg4i$m^A1Td}8TX_oouO^1 zftu}jxiw*Sqct@^-zMG^t)7q>c1_O=)^$NOakew|C1vwbb(rq-=>$Sb3W6-RZHa~m zCJ-n2XtkjN1C$hf07a9cuvH0K135T-J;#nfDUID~Sv*Yz!r1hE3|a|Q4_9AFEWLHK zWz~oq!$8|OVjZ(mf6Y*Z+@G&h%4HXA<`4i@t!XO}{GYwU7nxru-K+|Xtu%RHv$V5t zB%F}kxeBctB<7atq+W_2XaHsIuS|aaB@`qli21Zmg1ge~X)cg!Z$@+@T2Kf6wH3yz z&3Yvsd2vMF!t&A=G!b@&(o#XX>H~4DCJ(w*r-TNAhSk2Rta1dYR_3O9WK; zw#R~odmNn4Rrysbu1(x67Wr<38~#FiG1`n}wO&7`@#)Xk3f`-e^xfhbRWBNCp0aZ6 zG7j-w;#H4aR;4%|7`O;-+)Hl;uEM%I>mVnijiapH>2)nQ~8L|KJMiw<@G*t1yFW9;lFYc#uS`DwjogG)sqA zR1ZXz{)UVWQ#sGl0$Aj@M%qBOs8U>G?P+&{nu~!`wccEicA`NtKbHn#g?=au3r^~) z3?!GiqlV-fJj2A0p}mr}21v220F29iQ1fLV>-W%pUD-_S!;=aJIQ+*`W9=9^HPvL{ z0;-_op8_N*ciN&xk6wP@c=5J5d#{rWB-U?ag_zePQ!sYV&o8}(nae94B=$6zwdRg$ z{h^gdI-K$AkW4|MJIzg%@h!p>_RSE#rObbMsUUTO7bj4~!21~&^MANd_d&CC2wth| hfX@)Vpvv|h{{nxzjlgvW5(5AL002ovPDHLkV1gBrLk9o= literal 0 HcmV?d00001 diff --git a/cucumber_cpp/acceptance_test/compatibility/attachments/document.pdf b/cucumber_cpp/acceptance_test/compatibility/attachments/document.pdf new file mode 100644 index 0000000000000000000000000000000000000000..4647f3c9d70173713ad061f405a1aa9146615677 GIT binary patch literal 10061 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∨WEz|Va{bk-|&;_RAeM9+J zUnh0UX026ZO7^YamIZ5tFXz1xw3~EOReU=#MGVLU&?oU#=?!Q&VOGMa9g3{|}-(rTcEVg5D)DI{a z2GWDRGn4V{waEAz^x84pWqc%zrU@5vy=C+T^*opZy{sEeGZf(2bRQ7&>;3n3xehtByZm`RwV*79njVs~e!)Ed` z;YH~-tZ&NoXtbHSzJwFj7w*SIi)C%{Z8`Yu97yZ~Sa9T+txx2H)bjqO(lY!JZ9$Wd z?q>Zu#8Mn;b2b@_2~w}=Ym!RS<3n-cI9 zwjH50Myt%cFL0csJ&^^?GTKnrwi)*kO{uyhF(kR-koS?7m80R(c zIKR7oLwk9?hVqQyn)s}&`*Z`ke0eNnCvq*jB#li^lS_Wwa*V!tmKv21n> zIWRmXIB*O$9CN=2MaFzX^}(gDA^Pdq3=-`OpZdO+JS|#VtZN9tHt-cWHTu>u-?F#k zg|~2l_XW@B=IvR%<3*oH%%q4gQvvODblS~06nfp|{k(t{nm$Q>+P@j-Oauu{)-!d1p-7KZuoz;VzBBwu( zGi;S^D}Nr}uHT)sBb(kg=cqeOjYzwL|Arc%fB!xIC)99<9!MY@;SLsdNLzul+F$c0JmcRloYIBFCpvZ;0 zrxE)DdEkIRcsapfEub zk(E%lm6nxIgxR484--`O7Ra}MnAP4oqEeT&F}1xzI#dy67AUUdEr3}R#n~WGfR3^Q zioLP0F#|CFV;ah+=45AQg}6g_09<$M$Ll-jLzfTCr4Imu0lE+n7biats*w5sK5l?6 z7!2VAfw_55xBPr4WP^_nHHs>zKB^!RuK{4LyBPnd!@pod{~vUCCq~vXRzqlXO#k@lV>sE{OE+1y!pwuC+l-%Lw!84+cXP;}JYhW}G195Vmt850;vz9?0pz?(k=tBTq|bz2P^i#wnS0J__|f6=t71Hu#+ z)d1YMs6P1X06@TC9x%WZ@J|~E#Rc6R0Gof>c=%CR&wtoJT&RxucN-MKg~ECM-Npst z{qJ~SD5|^u!w>Sm_(7omwJtv&O0xek7s|zr%JkpkLAm+=WnH8L4AtZgckG**g&V3e ns1{VUwMD&4{_NjB+U+0Jazw%$kbl$)%Et@FWnhq0mcsoXXWVEI literal 0 HcmV?d00001 diff --git a/cucumber_cpp/acceptance_test/compatibility/backgrounds/backgrounds.feature b/cucumber_cpp/acceptance_test/compatibility/backgrounds/backgrounds.feature new file mode 100644 index 00000000..a99e739b --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/backgrounds/backgrounds.feature @@ -0,0 +1,17 @@ +Feature: Backgrounds + Though not recommended, Backgrounds can be used to share context steps between Scenarios. The Background steps + are prepended to the steps in each Scenario when they are compiled to Pickles. Only one Background at the Feature + level is supported. + + Background: + Given an order for "eggs" + And an order for "milk" + And an order for "bread" + + Scenario: one scenario + When an action + Then an outcome + + Scenario: another scenario + When an action + Then an outcome \ No newline at end of file diff --git a/cucumber_cpp/acceptance_test/compatibility/backgrounds/backgrounds.ndjson b/cucumber_cpp/acceptance_test/compatibility/backgrounds/backgrounds.ndjson new file mode 100644 index 00000000..311b3ae9 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/backgrounds/backgrounds.ndjson @@ -0,0 +1,36 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"Feature: Backgrounds\n Though not recommended, Backgrounds can be used to share context steps between Scenarios. The Background steps\n are prepended to the steps in each Scenario when they are compiled to Pickles. Only one Background at the Feature\n level is supported.\n\n Background:\n Given an order for \"eggs\"\n And an order for \"milk\"\n And an order for \"bread\"\n\n Scenario: one scenario\n When an action\n Then an outcome\n\n Scenario: another scenario\n When an action\n Then an outcome","uri":"samples/backgrounds/backgrounds.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Backgrounds","description":" Though not recommended, Backgrounds can be used to share context steps between Scenarios. The Background steps\n are prepended to the steps in each Scenario when they are compiled to Pickles. Only one Background at the Feature\n level is supported.","children":[{"background":{"id":"3","location":{"line":6,"column":3},"keyword":"Background","name":"","description":"","steps":[{"id":"0","location":{"line":7,"column":5},"keyword":"Given ","keywordType":"Context","text":"an order for \"eggs\""},{"id":"1","location":{"line":8,"column":5},"keyword":"And ","keywordType":"Conjunction","text":"an order for \"milk\""},{"id":"2","location":{"line":9,"column":5},"keyword":"And ","keywordType":"Conjunction","text":"an order for \"bread\""}]}},{"scenario":{"id":"6","tags":[],"location":{"line":11,"column":3},"keyword":"Scenario","name":"one scenario","description":"","steps":[{"id":"4","location":{"line":12,"column":5},"keyword":"When ","keywordType":"Action","text":"an action"},{"id":"5","location":{"line":13,"column":5},"keyword":"Then ","keywordType":"Outcome","text":"an outcome"}],"examples":[]}},{"scenario":{"id":"9","tags":[],"location":{"line":15,"column":3},"keyword":"Scenario","name":"another scenario","description":"","steps":[{"id":"7","location":{"line":16,"column":5},"keyword":"When ","keywordType":"Action","text":"an action"},{"id":"8","location":{"line":17,"column":5},"keyword":"Then ","keywordType":"Outcome","text":"an outcome"}],"examples":[]}}]},"comments":[],"uri":"samples/backgrounds/backgrounds.feature"}} +{"pickle":{"id":"15","uri":"samples/backgrounds/backgrounds.feature","astNodeIds":["6"],"tags":[],"name":"one scenario","language":"en","steps":[{"id":"10","text":"an order for \"eggs\"","type":"Context","astNodeIds":["0"]},{"id":"11","text":"an order for \"milk\"","type":"Context","astNodeIds":["1"]},{"id":"12","text":"an order for \"bread\"","type":"Context","astNodeIds":["2"]},{"id":"13","text":"an action","type":"Action","astNodeIds":["4"]},{"id":"14","text":"an outcome","type":"Outcome","astNodeIds":["5"]}]}} +{"pickle":{"id":"21","uri":"samples/backgrounds/backgrounds.feature","astNodeIds":["9"],"tags":[],"name":"another scenario","language":"en","steps":[{"id":"16","text":"an order for \"eggs\"","type":"Context","astNodeIds":["0"]},{"id":"17","text":"an order for \"milk\"","type":"Context","astNodeIds":["1"]},{"id":"18","text":"an order for \"bread\"","type":"Context","astNodeIds":["2"]},{"id":"19","text":"an action","type":"Action","astNodeIds":["7"]},{"id":"20","text":"an outcome","type":"Outcome","astNodeIds":["8"]}]}} +{"stepDefinition":{"id":"22","pattern":{"type":"CUCUMBER_EXPRESSION","source":"an order for {string}"},"sourceReference":{"uri":"samples/backgrounds/backgrounds.ts","location":{"line":3}}}} +{"stepDefinition":{"id":"23","pattern":{"type":"CUCUMBER_EXPRESSION","source":"an action"},"sourceReference":{"uri":"samples/backgrounds/backgrounds.ts","location":{"line":7}}}} +{"stepDefinition":{"id":"24","pattern":{"type":"CUCUMBER_EXPRESSION","source":"an outcome"},"sourceReference":{"uri":"samples/backgrounds/backgrounds.ts","location":{"line":11}}}} +{"testRunStarted":{"id":"25","timestamp":{"seconds":0,"nanos":0}}} +{"testCase":{"id":"26","pickleId":"15","testSteps":[{"id":"27","pickleStepId":"10","stepDefinitionIds":["22"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"eggs\"","children":[{"start":14,"value":"eggs","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]},{"id":"28","pickleStepId":"11","stepDefinitionIds":["22"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"milk\"","children":[{"start":14,"value":"milk","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]},{"id":"29","pickleStepId":"12","stepDefinitionIds":["22"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"bread\"","children":[{"start":14,"value":"bread","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]},{"id":"30","pickleStepId":"13","stepDefinitionIds":["23"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]},{"id":"31","pickleStepId":"14","stepDefinitionIds":["24"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"25"}} +{"testCase":{"id":"32","pickleId":"21","testSteps":[{"id":"33","pickleStepId":"16","stepDefinitionIds":["22"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"eggs\"","children":[{"start":14,"value":"eggs","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]},{"id":"34","pickleStepId":"17","stepDefinitionIds":["22"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"milk\"","children":[{"start":14,"value":"milk","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]},{"id":"35","pickleStepId":"18","stepDefinitionIds":["22"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"bread\"","children":[{"start":14,"value":"bread","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]},{"id":"36","pickleStepId":"19","stepDefinitionIds":["23"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]},{"id":"37","pickleStepId":"20","stepDefinitionIds":["24"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"25"}} +{"testCaseStarted":{"id":"38","testCaseId":"26","timestamp":{"seconds":0,"nanos":1000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"38","testStepId":"27","timestamp":{"seconds":0,"nanos":2000000}}} +{"testStepFinished":{"testCaseStartedId":"38","testStepId":"27","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":3000000}}} +{"testStepStarted":{"testCaseStartedId":"38","testStepId":"28","timestamp":{"seconds":0,"nanos":4000000}}} +{"testStepFinished":{"testCaseStartedId":"38","testStepId":"28","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":5000000}}} +{"testStepStarted":{"testCaseStartedId":"38","testStepId":"29","timestamp":{"seconds":0,"nanos":6000000}}} +{"testStepFinished":{"testCaseStartedId":"38","testStepId":"29","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":7000000}}} +{"testStepStarted":{"testCaseStartedId":"38","testStepId":"30","timestamp":{"seconds":0,"nanos":8000000}}} +{"testStepFinished":{"testCaseStartedId":"38","testStepId":"30","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":9000000}}} +{"testStepStarted":{"testCaseStartedId":"38","testStepId":"31","timestamp":{"seconds":0,"nanos":10000000}}} +{"testStepFinished":{"testCaseStartedId":"38","testStepId":"31","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":11000000}}} +{"testCaseFinished":{"testCaseStartedId":"38","timestamp":{"seconds":0,"nanos":12000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"39","testCaseId":"32","timestamp":{"seconds":0,"nanos":13000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"39","testStepId":"33","timestamp":{"seconds":0,"nanos":14000000}}} +{"testStepFinished":{"testCaseStartedId":"39","testStepId":"33","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":15000000}}} +{"testStepStarted":{"testCaseStartedId":"39","testStepId":"34","timestamp":{"seconds":0,"nanos":16000000}}} +{"testStepFinished":{"testCaseStartedId":"39","testStepId":"34","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":17000000}}} +{"testStepStarted":{"testCaseStartedId":"39","testStepId":"35","timestamp":{"seconds":0,"nanos":18000000}}} +{"testStepFinished":{"testCaseStartedId":"39","testStepId":"35","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":19000000}}} +{"testStepStarted":{"testCaseStartedId":"39","testStepId":"36","timestamp":{"seconds":0,"nanos":20000000}}} +{"testStepFinished":{"testCaseStartedId":"39","testStepId":"36","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":21000000}}} +{"testStepStarted":{"testCaseStartedId":"39","testStepId":"37","timestamp":{"seconds":0,"nanos":22000000}}} +{"testStepFinished":{"testCaseStartedId":"39","testStepId":"37","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":23000000}}} +{"testCaseFinished":{"testCaseStartedId":"39","timestamp":{"seconds":0,"nanos":24000000},"willBeRetried":false}} +{"testRunFinished":{"testRunStartedId":"25","timestamp":{"seconds":0,"nanos":25000000},"success":true}} diff --git a/cucumber_cpp/acceptance_test/compatibility/cdata/cdata.feature b/cucumber_cpp/acceptance_test/compatibility/cdata/cdata.feature new file mode 100644 index 00000000..ca75bff7 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/cdata/cdata.feature @@ -0,0 +1,5 @@ +Feature: cdata + Cucumber xml formatters should be able to handle xml cdata elements. + + Scenario: cdata + Given I have 42 in my belly diff --git a/cucumber_cpp/acceptance_test/compatibility/cdata/cdata.ndjson b/cucumber_cpp/acceptance_test/compatibility/cdata/cdata.ndjson new file mode 100644 index 00000000..5c2d6d2d --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/cdata/cdata.ndjson @@ -0,0 +1,12 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"Feature: cdata\n Cucumber xml formatters should be able to handle xml cdata elements.\n\n Scenario: cdata\n Given I have 42 in my belly\n","uri":"samples/cdata/cdata.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"cdata","description":" Cucumber xml formatters should be able to handle xml cdata elements.","children":[{"scenario":{"id":"1","tags":[],"location":{"line":4,"column":3},"keyword":"Scenario","name":"cdata","description":"","steps":[{"id":"0","location":{"line":5,"column":5},"keyword":"Given ","keywordType":"Context","text":"I have 42 in my belly"}],"examples":[]}}]},"comments":[],"uri":"samples/cdata/cdata.feature"}} +{"pickle":{"id":"3","uri":"samples/cdata/cdata.feature","astNodeIds":["1"],"tags":[],"name":"cdata","language":"en","steps":[{"id":"2","text":"I have 42 in my belly","type":"Context","astNodeIds":["0"]}]}} +{"stepDefinition":{"id":"4","pattern":{"type":"CUCUMBER_EXPRESSION","source":"I have {int} in my belly"},"sourceReference":{"uri":"samples/cdata/cdata.ts","location":{"line":3}}}} +{"testRunStarted":{"id":"5","timestamp":{"seconds":0,"nanos":0}}} +{"testCase":{"id":"6","pickleId":"3","testSteps":[{"id":"7","pickleStepId":"2","stepDefinitionIds":["4"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":7,"value":"42","children":[]},"parameterTypeName":"int"}]}]}],"testRunStartedId":"5"}} +{"testCaseStarted":{"id":"8","testCaseId":"6","timestamp":{"seconds":0,"nanos":1000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"8","testStepId":"7","timestamp":{"seconds":0,"nanos":2000000}}} +{"testStepFinished":{"testCaseStartedId":"8","testStepId":"7","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":3000000}}} +{"testCaseFinished":{"testCaseStartedId":"8","timestamp":{"seconds":0,"nanos":4000000},"willBeRetried":false}} +{"testRunFinished":{"testRunStartedId":"5","timestamp":{"seconds":0,"nanos":5000000},"success":true}} diff --git a/cucumber_cpp/acceptance_test/compatibility/data-tables/data-tables.feature b/cucumber_cpp/acceptance_test/compatibility/data-tables/data-tables.feature new file mode 100644 index 00000000..2822419e --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/data-tables/data-tables.feature @@ -0,0 +1,13 @@ +Feature: Data Tables + Data Tables can be placed underneath a step and will be passed as the last + argument to the step definition. + + They can be used to represent richer data structures, and can be transformed to other data-types. + + Scenario: transposed table + When the following table is transposed: + | a | b | + | 1 | 2 | + Then it should be: + | a | 1 | + | b | 2 | diff --git a/cucumber_cpp/acceptance_test/compatibility/data-tables/data-tables.ndjson b/cucumber_cpp/acceptance_test/compatibility/data-tables/data-tables.ndjson new file mode 100644 index 00000000..1b43475d --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/data-tables/data-tables.ndjson @@ -0,0 +1,15 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"Feature: Data Tables\n Data Tables can be placed underneath a step and will be passed as the last\n argument to the step definition.\n\n They can be used to represent richer data structures, and can be transformed to other data-types.\n\n Scenario: transposed table\n When the following table is transposed:\n | a | b |\n | 1 | 2 |\n Then it should be:\n | a | 1 |\n | b | 2 |\n","uri":"samples/data-tables/data-tables.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Data Tables","description":" Data Tables can be placed underneath a step and will be passed as the last\n argument to the step definition.\n\n They can be used to represent richer data structures, and can be transformed to other data-types.","children":[{"scenario":{"id":"6","tags":[],"location":{"line":7,"column":3},"keyword":"Scenario","name":"transposed table","description":"","steps":[{"id":"2","location":{"line":8,"column":5},"keyword":"When ","keywordType":"Action","text":"the following table is transposed:","dataTable":{"location":{"line":9,"column":7},"rows":[{"id":"0","location":{"line":9,"column":7},"cells":[{"location":{"line":9,"column":9},"value":"a"},{"location":{"line":9,"column":13},"value":"b"}]},{"id":"1","location":{"line":10,"column":7},"cells":[{"location":{"line":10,"column":9},"value":"1"},{"location":{"line":10,"column":13},"value":"2"}]}]}},{"id":"5","location":{"line":11,"column":5},"keyword":"Then ","keywordType":"Outcome","text":"it should be:","dataTable":{"location":{"line":12,"column":7},"rows":[{"id":"3","location":{"line":12,"column":7},"cells":[{"location":{"line":12,"column":9},"value":"a"},{"location":{"line":12,"column":13},"value":"1"}]},{"id":"4","location":{"line":13,"column":7},"cells":[{"location":{"line":13,"column":9},"value":"b"},{"location":{"line":13,"column":13},"value":"2"}]}]}}],"examples":[]}}]},"comments":[],"uri":"samples/data-tables/data-tables.feature"}} +{"pickle":{"id":"9","uri":"samples/data-tables/data-tables.feature","astNodeIds":["6"],"tags":[],"name":"transposed table","language":"en","steps":[{"id":"7","text":"the following table is transposed:","type":"Action","argument":{"dataTable":{"rows":[{"cells":[{"value":"a"},{"value":"b"}]},{"cells":[{"value":"1"},{"value":"2"}]}]}},"astNodeIds":["2"]},{"id":"8","text":"it should be:","type":"Outcome","argument":{"dataTable":{"rows":[{"cells":[{"value":"a"},{"value":"1"}]},{"cells":[{"value":"b"},{"value":"2"}]}]}},"astNodeIds":["5"]}]}} +{"stepDefinition":{"id":"10","pattern":{"type":"CUCUMBER_EXPRESSION","source":"the following table is transposed:"},"sourceReference":{"uri":"samples/data-tables/data-tables.ts","location":{"line":4}}}} +{"stepDefinition":{"id":"11","pattern":{"type":"CUCUMBER_EXPRESSION","source":"it should be:"},"sourceReference":{"uri":"samples/data-tables/data-tables.ts","location":{"line":8}}}} +{"testRunStarted":{"id":"12","timestamp":{"seconds":0,"nanos":0}}} +{"testCase":{"id":"13","pickleId":"9","testSteps":[{"id":"14","pickleStepId":"7","stepDefinitionIds":["10"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]},{"id":"15","pickleStepId":"8","stepDefinitionIds":["11"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"12"}} +{"testCaseStarted":{"id":"16","testCaseId":"13","timestamp":{"seconds":0,"nanos":1000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"16","testStepId":"14","timestamp":{"seconds":0,"nanos":2000000}}} +{"testStepFinished":{"testCaseStartedId":"16","testStepId":"14","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":3000000}}} +{"testStepStarted":{"testCaseStartedId":"16","testStepId":"15","timestamp":{"seconds":0,"nanos":4000000}}} +{"testStepFinished":{"testCaseStartedId":"16","testStepId":"15","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":5000000}}} +{"testCaseFinished":{"testCaseStartedId":"16","timestamp":{"seconds":0,"nanos":6000000},"willBeRetried":false}} +{"testRunFinished":{"testRunStartedId":"12","timestamp":{"seconds":0,"nanos":7000000},"success":true}} diff --git a/cucumber_cpp/acceptance_test/compatibility/doc-strings/doc-strings.feature b/cucumber_cpp/acceptance_test/compatibility/doc-strings/doc-strings.feature new file mode 100644 index 00000000..c3917189 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/doc-strings/doc-strings.feature @@ -0,0 +1,31 @@ +Feature: Doc strings + Doc strings are a way to supply long, sometimes multi-line, text to a step. They are passed as the last argument + to the step definition. + + Scenario: a doc string with standard delimiter + Three double quotes above and below are the standard delimiter for doc strings. + + Given a doc string: + """ + Here is some content + And some more on another line + """ + + Scenario: a doc string with backticks delimiter + Backticks can also be used, like Markdown, but are less widely supported by editors. + + Given a doc string: + ``` + Here is some content + And some more on another line + ``` + + Scenario: a doc string with media type + The media type can be optionally specified too, following the opening delimiter. + + Given a doc string: + """application/json + { + "foo": "bar" + } + """ \ No newline at end of file diff --git a/cucumber_cpp/acceptance_test/compatibility/doc-strings/doc-strings.ndjson b/cucumber_cpp/acceptance_test/compatibility/doc-strings/doc-strings.ndjson new file mode 100644 index 00000000..f529b322 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/doc-strings/doc-strings.ndjson @@ -0,0 +1,24 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"Feature: Doc strings\n Doc strings are a way to supply long, sometimes multi-line, text to a step. They are passed as the last argument\n to the step definition.\n\n Scenario: a doc string with standard delimiter\n Three double quotes above and below are the standard delimiter for doc strings.\n\n Given a doc string:\n \"\"\"\n Here is some content\n And some more on another line\n \"\"\"\n\n Scenario: a doc string with backticks delimiter\n Backticks can also be used, like Markdown, but are less widely supported by editors.\n\n Given a doc string:\n ```\n Here is some content\n And some more on another line\n ```\n\n Scenario: a doc string with media type\n The media type can be optionally specified too, following the opening delimiter.\n\n Given a doc string:\n \"\"\"application/json\n {\n \"foo\": \"bar\"\n }\n \"\"\"","uri":"samples/doc-strings/doc-strings.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Doc strings","description":" Doc strings are a way to supply long, sometimes multi-line, text to a step. They are passed as the last argument\n to the step definition.","children":[{"scenario":{"id":"1","tags":[],"location":{"line":5,"column":3},"keyword":"Scenario","name":"a doc string with standard delimiter","description":" Three double quotes above and below are the standard delimiter for doc strings.","steps":[{"id":"0","location":{"line":8,"column":5},"keyword":"Given ","keywordType":"Context","text":"a doc string:","docString":{"location":{"line":9,"column":5},"content":"Here is some content\nAnd some more on another line","delimiter":"\"\"\""}}],"examples":[]}},{"scenario":{"id":"3","tags":[],"location":{"line":14,"column":3},"keyword":"Scenario","name":"a doc string with backticks delimiter","description":" Backticks can also be used, like Markdown, but are less widely supported by editors.","steps":[{"id":"2","location":{"line":17,"column":5},"keyword":"Given ","keywordType":"Context","text":"a doc string:","docString":{"location":{"line":18,"column":5},"content":"Here is some content\nAnd some more on another line","delimiter":"```"}}],"examples":[]}},{"scenario":{"id":"5","tags":[],"location":{"line":23,"column":3},"keyword":"Scenario","name":"a doc string with media type","description":" The media type can be optionally specified too, following the opening delimiter.","steps":[{"id":"4","location":{"line":26,"column":5},"keyword":"Given ","keywordType":"Context","text":"a doc string:","docString":{"location":{"line":27,"column":5},"content":"{\n \"foo\": \"bar\"\n}","delimiter":"\"\"\"","mediaType":"application/json"}}],"examples":[]}}]},"comments":[],"uri":"samples/doc-strings/doc-strings.feature"}} +{"pickle":{"id":"7","uri":"samples/doc-strings/doc-strings.feature","astNodeIds":["1"],"tags":[],"name":"a doc string with standard delimiter","language":"en","steps":[{"id":"6","text":"a doc string:","type":"Context","argument":{"docString":{"content":"Here is some content\nAnd some more on another line"}},"astNodeIds":["0"]}]}} +{"pickle":{"id":"9","uri":"samples/doc-strings/doc-strings.feature","astNodeIds":["3"],"tags":[],"name":"a doc string with backticks delimiter","language":"en","steps":[{"id":"8","text":"a doc string:","type":"Context","argument":{"docString":{"content":"Here is some content\nAnd some more on another line"}},"astNodeIds":["2"]}]}} +{"pickle":{"id":"11","uri":"samples/doc-strings/doc-strings.feature","astNodeIds":["5"],"tags":[],"name":"a doc string with media type","language":"en","steps":[{"id":"10","text":"a doc string:","type":"Context","argument":{"docString":{"content":"{\n \"foo\": \"bar\"\n}","mediaType":"application/json"}},"astNodeIds":["4"]}]}} +{"stepDefinition":{"id":"12","pattern":{"type":"CUCUMBER_EXPRESSION","source":"a doc string:"},"sourceReference":{"uri":"samples/doc-strings/doc-strings.ts","location":{"line":3}}}} +{"testRunStarted":{"id":"13","timestamp":{"seconds":0,"nanos":0}}} +{"testCase":{"id":"14","pickleId":"7","testSteps":[{"id":"15","pickleStepId":"6","stepDefinitionIds":["12"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"13"}} +{"testCase":{"id":"16","pickleId":"9","testSteps":[{"id":"17","pickleStepId":"8","stepDefinitionIds":["12"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"13"}} +{"testCase":{"id":"18","pickleId":"11","testSteps":[{"id":"19","pickleStepId":"10","stepDefinitionIds":["12"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"13"}} +{"testCaseStarted":{"id":"20","testCaseId":"14","timestamp":{"seconds":0,"nanos":1000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"20","testStepId":"15","timestamp":{"seconds":0,"nanos":2000000}}} +{"testStepFinished":{"testCaseStartedId":"20","testStepId":"15","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":3000000}}} +{"testCaseFinished":{"testCaseStartedId":"20","timestamp":{"seconds":0,"nanos":4000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"21","testCaseId":"16","timestamp":{"seconds":0,"nanos":5000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"21","testStepId":"17","timestamp":{"seconds":0,"nanos":6000000}}} +{"testStepFinished":{"testCaseStartedId":"21","testStepId":"17","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":7000000}}} +{"testCaseFinished":{"testCaseStartedId":"21","timestamp":{"seconds":0,"nanos":8000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"22","testCaseId":"18","timestamp":{"seconds":0,"nanos":9000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"22","testStepId":"19","timestamp":{"seconds":0,"nanos":10000000}}} +{"testStepFinished":{"testCaseStartedId":"22","testStepId":"19","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":11000000}}} +{"testCaseFinished":{"testCaseStartedId":"22","timestamp":{"seconds":0,"nanos":12000000},"willBeRetried":false}} +{"testRunFinished":{"testRunStartedId":"13","timestamp":{"seconds":0,"nanos":13000000},"success":true}} diff --git a/cucumber_cpp/acceptance_test/compatibility/empty/empty.feature b/cucumber_cpp/acceptance_test/compatibility/empty/empty.feature new file mode 100644 index 00000000..e9767eff --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/empty/empty.feature @@ -0,0 +1,7 @@ +Feature: Empty Scenarios + Sometimes we want to quickly jot down a new scenario without specifying any actual steps + for what should be executed. + + In this instance we want to stipulate what should / shouldn't run and what the output is. + + Scenario: Blank Scenario diff --git a/cucumber_cpp/acceptance_test/compatibility/empty/empty.ndjson b/cucumber_cpp/acceptance_test/compatibility/empty/empty.ndjson new file mode 100644 index 00000000..7aefb40f --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/empty/empty.ndjson @@ -0,0 +1,9 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"Feature: Empty Scenarios\n Sometimes we want to quickly jot down a new scenario without specifying any actual steps\n for what should be executed.\n\n In this instance we want to stipulate what should / shouldn't run and what the output is.\n\n Scenario: Blank Scenario\n","uri":"samples/empty/empty.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Empty Scenarios","description":" Sometimes we want to quickly jot down a new scenario without specifying any actual steps\n for what should be executed.\n\n In this instance we want to stipulate what should / shouldn't run and what the output is.","children":[{"scenario":{"id":"0","tags":[],"location":{"line":7,"column":3},"keyword":"Scenario","name":"Blank Scenario","description":"","steps":[],"examples":[]}}]},"comments":[],"uri":"samples/empty/empty.feature"}} +{"pickle":{"id":"1","uri":"samples/empty/empty.feature","astNodeIds":["0"],"tags":[],"name":"Blank Scenario","language":"en","steps":[]}} +{"testRunStarted":{"id":"2","timestamp":{"seconds":0,"nanos":0}}} +{"testCase":{"id":"3","pickleId":"1","testSteps":[],"testRunStartedId":"2"}} +{"testCaseStarted":{"id":"4","testCaseId":"3","timestamp":{"seconds":0,"nanos":1000000},"attempt":0}} +{"testCaseFinished":{"testCaseStartedId":"4","timestamp":{"seconds":0,"nanos":2000000},"willBeRetried":false}} +{"testRunFinished":{"testRunStartedId":"2","timestamp":{"seconds":0,"nanos":3000000},"success":true}} diff --git a/cucumber_cpp/acceptance_test/compatibility/examples-tables-attachment/cucumber.jpeg b/cucumber_cpp/acceptance_test/compatibility/examples-tables-attachment/cucumber.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..e833d6c77d33e620ae49d01c6341ad7e5543bbd1 GIT binary patch literal 1444 zcmex=ma3|jiIItm zOAI4iKMQ#V{6EAX$ibk;pvlar#K0uT$SlbC{|JK&&=V}oKwrQC2Ma43I|Cy#)Bjrx z93W3JFj%5R(9qV{Ntcq}Ky~tP0uLAPSj53Js=3YaT3(saOkCY9;`5A|n$EGYdN> z$V3JPCPrqUBN+tQg%k~il>!AEoq|My6AOzQCy9zF8yTB~CKo{+&uGtZX0w)!P@n75 z+pl=GZ!o)2TKe4kXH-t@v#4EXEL!JE?zOu6r)a^it+7!xlS1t8{b#8CcjV%O8K0Lw zw!5=@{{4E%lYXmb|9XFR)y|pcq!QHyPd&4_T>Dx#CekoQenQBu?LV{I?)a=Z|5`qv zFCb50m1$zkt9Lo_J0{jC=okGqK3#m~$Ha_v^0sbzj}ElmKM-8K@73}%+E1_Sj1$h= za&Sv<=wdZVW0znRzq!_L_bo^lOYMz6H&?{%)XoFh(vNfajh)BRw*tXt#N5h?h}`dZpTv+M2|iZeX+YndxfsS7m0HMKkjMk z3R-;5(6ii>*OK{q>6sTyS60rQly}eE#LW&5BG%-(C1!D;fUT^{(mfa_yh< z{#u>M^5=OJ`#1Z*!uSb$%D$efQTh0vq2T`C;?gU-q$)Q@ZJHi;`qC^B2V>vgrM{Op zz2Y^CHRFrdI~bc)vyq`s=08J-S2f$|3$=&W)J@FMUY+(-GI%Z`A@L?@)(B$FN=Q(t=#l1^;xf6 ztKqtSx0-4T?$s+Kr!hS|dgkT)$(;KdOXF_sl{kL&qTE`s1rg3$Iy;OF^4Vh9&`X%c- z?@Ir1`muNQ?HGfD#&eeSnRs0PY8_Wf0x zYr%isu|McfyL=m%q*VpMX&9LEAPE|n37MD~SOi&xgcSot42=?%9Sb43h7p*8_w1>- z6Mg&7uRHgQ{q+{+?($T>Bl_*Z+yh@{H3b$5c{NME=w}I8|8lFOYSF`(6w%|A@+BXl zmusIkS2)Mu_D0Bf{>CWJM_W~opFJsmFzB$zE1{4Rf8~=jG8xtK!v7@pU6p$h?!dst zAi;cKJ=ASXzzoOCisUvHRt7dfAw$K$LSa!QBS)~?m_cs48@=pNOiq~YFVP2{3ZGA2 z+`D6=>s#ATRX)mE@f(tl=gZwXkQQv**LRUIg?&x;o5PWIH+oN(d8?&{>zqn{JdOYJ zpDR~h9MUx8cipWf_R8znWtJ&uK2N+Xmx{{Kw?qP#Uw literal 0 HcmV?d00001 diff --git a/cucumber_cpp/acceptance_test/compatibility/examples-tables-attachment/cucumber.png b/cucumber_cpp/acceptance_test/compatibility/examples-tables-attachment/cucumber.png new file mode 100644 index 0000000000000000000000000000000000000000..2760899aa0ce16aeaaea93d3118a32e7ac5bec8d GIT binary patch literal 1739 zcmV;+1~mDJP)G+r@kQ0VOJz1t=x5=pe3owlM@Ei<#*ZtpGI zgKd}Iv=WU6L@O5L5Qs#)gFvk*7OQ`VCsjOx5<>9^RV-lQA0`qL#Hi6fjMC@#y`7oe zS+={g-EDP}m+f}vz4x2%_`Ec`caU@Gwv+u9&;ebh;EPxToe6TQSS7$RIEHqf|0i z0O+ z#n5`Lu?_+l5a?76FBT_ov)oVPu)W&2iyqQk6q$E2`kQlqo37e8-)c+O?QiP<=H+=W zgC{tLKe`UI8wSZ$`}IIZS7^VP!&SQ9uqqj{=4V~1HP0i=kNxUV+pBnmxV8-q#Bxu7a+-a2h-P!vK`Neu>T>`ydm{x2F*T=U zFja;RD&fUT?=ygOHKmEIjm9$XXg4i$m^A1Td}8TX_oouO^1 zftu}jxiw*Sqct@^-zMG^t)7q>c1_O=)^$NOakew|C1vwbb(rq-=>$Sb3W6-RZHa~m zCJ-n2XtkjN1C$hf07a9cuvH0K135T-J;#nfDUID~Sv*Yz!r1hE3|a|Q4_9AFEWLHK zWz~oq!$8|OVjZ(mf6Y*Z+@G&h%4HXA<`4i@t!XO}{GYwU7nxru-K+|Xtu%RHv$V5t zB%F}kxeBctB<7atq+W_2XaHsIuS|aaB@`qli21Zmg1ge~X)cg!Z$@+@T2Kf6wH3yz z&3Yvsd2vMF!t&A=G!b@&(o#XX>H~4DCJ(w*r-TNAhSk2Rta1dYR_3O9WK; zw#R~odmNn4Rrysbu1(x67Wr<38~#FiG1`n}wO&7`@#)Xk3f`-e^xfhbRWBNCp0aZ6 zG7j-w;#H4aR;4%|7`O;-+)Hl;uEM%I>mVnijiapH>2)nQ~8L|KJMiw<@G*t1yFW9;lFYc#uS`DwjogG)sqA zR1ZXz{)UVWQ#sGl0$Aj@M%qBOs8U>G?P+&{nu~!`wccEicA`NtKbHn#g?=au3r^~) z3?!GiqlV-fJj2A0p}mr}21v220F29iQ1fLV>-W%pUD-_S!;=aJIQ+*`W9=9^HPvL{ z0;-_op8_N*ciN&xk6wP@c=5J5d#{rWB-U?ag_zePQ!sYV&o8}(nae94B=$6zwdRg$ z{h^gdI-K$AkW4|MJIzg%@h!p>_RSE#rObbMsUUTO7bj4~!21~&^MANd_d&CC2wth| hfX@)Vpvv|h{{nxzjlgvW5(5AL002ovPDHLkV1gBrLk9o= literal 0 HcmV?d00001 diff --git a/cucumber_cpp/acceptance_test/compatibility/examples-tables-attachment/examples-tables-attachment.feature b/cucumber_cpp/acceptance_test/compatibility/examples-tables-attachment/examples-tables-attachment.feature new file mode 100644 index 00000000..b8e6466a --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/examples-tables-attachment/examples-tables-attachment.feature @@ -0,0 +1,10 @@ +Feature: Examples Tables - With attachments + It is sometimes useful to take a screenshot while a scenario runs or capture some logs. + + Scenario Outline: Attaching images in an examples table + When a image is attached + + Examples: + | type | + | JPEG | + | PNG | diff --git a/cucumber_cpp/acceptance_test/compatibility/examples-tables-attachment/examples-tables-attachment.ndjson b/cucumber_cpp/acceptance_test/compatibility/examples-tables-attachment/examples-tables-attachment.ndjson new file mode 100644 index 00000000..ad291271 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/examples-tables-attachment/examples-tables-attachment.ndjson @@ -0,0 +1,21 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"Feature: Examples Tables - With attachments\n It is sometimes useful to take a screenshot while a scenario runs or capture some logs.\n\n Scenario Outline: Attaching images in an examples table\n When a image is attached\n\n Examples:\n | type |\n | JPEG |\n | PNG |\n","uri":"samples/examples-tables-attachment/examples-tables-attachment.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Examples Tables - With attachments","description":" It is sometimes useful to take a screenshot while a scenario runs or capture some logs.","children":[{"scenario":{"id":"5","tags":[],"location":{"line":4,"column":3},"keyword":"Scenario Outline","name":"Attaching images in an examples table","description":"","steps":[{"id":"0","location":{"line":5,"column":5},"keyword":"When ","keywordType":"Action","text":"a image is attached"}],"examples":[{"id":"4","tags":[],"location":{"line":7,"column":5},"keyword":"Examples","name":"","description":"","tableHeader":{"id":"1","location":{"line":8,"column":7},"cells":[{"location":{"line":8,"column":9},"value":"type"}]},"tableBody":[{"id":"2","location":{"line":9,"column":7},"cells":[{"location":{"line":9,"column":9},"value":"JPEG"}]},{"id":"3","location":{"line":10,"column":7},"cells":[{"location":{"line":10,"column":9},"value":"PNG"}]}]}]}}]},"comments":[],"uri":"samples/examples-tables-attachment/examples-tables-attachment.feature"}} +{"pickle":{"id":"7","uri":"samples/examples-tables-attachment/examples-tables-attachment.feature","astNodeIds":["5","2"],"name":"Attaching images in an examples table","language":"en","steps":[{"id":"6","text":"a JPEG image is attached","type":"Action","astNodeIds":["0","2"]}],"tags":[]}} +{"pickle":{"id":"9","uri":"samples/examples-tables-attachment/examples-tables-attachment.feature","astNodeIds":["5","3"],"name":"Attaching images in an examples table","language":"en","steps":[{"id":"8","text":"a PNG image is attached","type":"Action","astNodeIds":["0","3"]}],"tags":[]}} +{"stepDefinition":{"id":"10","pattern":{"type":"CUCUMBER_EXPRESSION","source":"a JPEG image is attached"},"sourceReference":{"uri":"samples/examples-tables-attachment/examples-tables-attachment.ts","location":{"line":4}}}} +{"stepDefinition":{"id":"11","pattern":{"type":"CUCUMBER_EXPRESSION","source":"a PNG image is attached"},"sourceReference":{"uri":"samples/examples-tables-attachment/examples-tables-attachment.ts","location":{"line":8}}}} +{"testRunStarted":{"id":"12","timestamp":{"seconds":0,"nanos":0}}} +{"testCase":{"id":"13","pickleId":"7","testSteps":[{"id":"14","pickleStepId":"6","stepDefinitionIds":["10"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"12"}} +{"testCase":{"id":"15","pickleId":"9","testSteps":[{"id":"16","pickleStepId":"8","stepDefinitionIds":["11"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"12"}} +{"testCaseStarted":{"id":"17","testCaseId":"13","timestamp":{"seconds":0,"nanos":1000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"17","testStepId":"14","timestamp":{"seconds":0,"nanos":2000000}}} +{"attachment":{"testCaseStartedId":"17","testStepId":"14","body":"/9j/4AAQSkZJRgABAQAAAQABAAD//gAfQ29tcHJlc3NlZCBieSBqcGVnLXJlY29tcHJlc3P/2wCEAAQEBAQEBAQEBAQGBgUGBggHBwcHCAwJCQkJCQwTDA4MDA4MExEUEA8QFBEeFxUVFx4iHRsdIiolJSo0MjRERFwBBAQEBAQEBAQEBAYGBQYGCAcHBwcIDAkJCQkJDBMMDgwMDgwTERQQDxAUER4XFRUXHiIdGx0iKiUlKjQyNEREXP/CABEIAC4AKQMBIgACEQEDEQH/xAAcAAABBAMBAAAAAAAAAAAAAAAIBAUGBwABAwL/2gAIAQEAAAAAOESYe+lPPw0bK2mvU5gRhNkM/tNMGeuJM5msiEjujvC+s0ApSWvn/8QAFgEBAQEAAAAAAAAAAAAAAAAABQME/9oACAECEAAAADs6pclK4E//xAAWAQEBAQAAAAAAAAAAAAAAAAAHBgT/2gAIAQMQAAAAMJZbKcF1XHit/8QANhAAAQQBAgQDBAcJAAAAAAAAAgEDBAUGABEHEiExEyJREEFCUhRTYXFzgZIVFiMyMzRVY3L/2gAIAQEAAT8AzLMqPBKOReXb6gy3sDbYdXXnS/labH3mWrrMOIWdGb063fxyoPq1XVp8klQ/3v8Aff7E0eCY86fjPtynn99/GclOq5v6782quZnOGmEnEcrmPNN96y1cWTFcH5BUurf5a4bcTKzP6x9QjlBuIKo1YVzq7mwfuJF+IC9y+zPLc8z4kWiuHz1GLuLAht/AU3u+6qfMK+XUuV4TbrTBtFNVoyYZM0RTJE6dO+2+oGcWZY1fzp0URsq5wGuXkUU3dLlHmH1FdYvMs59HCmW7SBKdQiVEHl3Hfyqqe7dNFbOYRlNDnkQlBth9uHaoPZ2C+SCSl9oL1HX0qN9c3+pNY6pkeSG9/XO/sie9fEV5d9Z5FxdbKNKsbeREsUbHZGAVxeQV6Lt8K6gtMPQYzhD43istETjzaC45sm6EaeulzOgC1Kmdkm1KF3wvO2Qjz+m+syECxe7Q+30ZV/NF3TX7dyv5nv06zGpPDOJd/WvAoV+QvHb1znwk8f8AcN/9c3XUuhp5s1qyl17L0poUQDNN+3VN07LqDTZdNg5fLsFdanyxAI4c/wBUSnsGy9B9w6x+kWwrq2blFW2VtHVUF11P4qiC+RT27r9+r6E9kUyiwmDusq8nNMny924zZc7rv3Cia/dSg/xTH6dcQMDpc/oSqbLmZeaNHoUxro9GfHs4C6uoGZYC4cXM6Z+TCb6BdV7avRjH1dEerRagWEO0iNToDyOx3N+Q0RU32XZehbLq4u4VMyByFI33VQI8ZpOZ5416IICnVdcHuHNjUOSs3y5lByGwaRpiL3Svid0b/EL4vavbXDDBM5ymjjRKi3qK2vZ5lOSYOvykRw1Lyhsgawbg9jGGSUtzJ63v1TzWU/zuB+CPZtPb/8QAJREAAgEDBAEEAwAAAAAAAAAAAQIDAAQRBRITIVEUMTJhI0Fx/9oACAECAQE/ALy8eNxb2/z63N4zTy6hbbpJJ9wV9uCdwPWaglFxEkqDGeiPBFSv6bUZJXLhXGQVx3kfdPBbpyvLNyDOAEbsEjOfsVpJ4rUlx83JH8FSwxTqElTI/R9iKGkBJm5X/GGO1R7kV0AABgAYA8Cv/8QAJREAAgIBBAEDBQAAAAAAAAAAAQIDBAUABhESMSFRcRMVIjJB/9oACAEDAQE/AN1bpuJcbFYt+hXgSSDzydG9uLFF7T3yekwjKl+wY8dvHtrAZlMzjo7RAWQHrIvsw1k+2I3LdksmZVcsymPjlg/z/NTU6MIsy2bf1x26hYnHKsy9ufXyB41sWnN9rmlPKrJNyvwBxrL4LH5mMLbj/Nf1dfRhqjsKaa27WZgtRZD1APLsuq1aGpBHXgQLGihVA1//2Q==","contentEncoding":"BASE64","mediaType":"image/jpeg","timestamp":{"seconds":0,"nanos":3000000}}} +{"testStepFinished":{"testCaseStartedId":"17","testStepId":"14","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":4000000}}} +{"testCaseFinished":{"testCaseStartedId":"17","timestamp":{"seconds":0,"nanos":5000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"18","testCaseId":"15","timestamp":{"seconds":0,"nanos":6000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"18","testStepId":"16","timestamp":{"seconds":0,"nanos":7000000}}} +{"attachment":{"testCaseStartedId":"18","testStepId":"16","body":"iVBORw0KGgoAAAANSUhEUgAAACkAAAAuCAYAAAC1ZTBOAAAABmJLR0QA/wD/AP+gvaeTAAAGgElEQVRYw81ZeWwUVRgfNF4xalDo7Oy92yYmEkm0nZ22olYtM7Pbbu8t24Ntl960Eo0HRCsW5BCIRLyDQK0pFqt/iCdVPIISQvEIVSxg4h8mEhPEqNE/jNLn972dmd1Ztruz3W11kpftdue995vv+H2/7w3DzPBatChwKcvLd7GCvJn1SG+YPNIp+PwFxm8wzrO89CPrEY/A36/keKRuc4F8PTNX18IC700AaAg2/x0GSXN8B8AfNuf7F8wKuBxBXgybHIzdlKvxE2v/MmLf00Kc77QT16ddxH2sh346320nzn1hYtvcSMyhKsIukWPB/sny4iZ2sXhlVsBZiwJXmHh5Gyz8N25gKvES29ogcX3USXJP9RkfE73EMRgiXF1FLNjTbKEoZATwuqJyC+uRj1FwhTKxPrKM5H7Zkx64+HGyjzj2honJV64ChYcX7565e3npDAVY6Seu9zoyAxc33F+tJNZ766JW5eX+9JKjSMpjBfEnnGxpq6ELZhNg7LBta9SAmjzyA4YAssViDkz4ngLsqSW5J3pnDaAGdEeTCvSfHGGpmBokL+3HCebmSpL7zewDVId1Tb0K9NxC3meaHqBHbqNmLy2jVDJXAOkAj3HBCsXt0lBCgAtuqbiKFaSzeJMD+M1Q8E8CrewKEfvzy0nu1xda3THcQiz3B4hjqMXQeq6xDgIYEOhUDi8WJ3Cz3E/jsL3auIse0lwUmXcy+ptzf5uu2jjfakvX7W/rAObleS+DJziHP7oOtBsGyVX79UBGV2i/mcNVut+wKhmy5mddqjXPI8tEOdEjVtFkgfKVVrCvrtcBQdeq1YUtjKnZ8DdubnRdS1cNnQfCZEtMwkij9GlfWJ4eIUNymcSyaC2vr4hY41CnDjyW0XTWdQy3qnNPqBjnwZezaGL3eHfScmZ/uplYVtUS26YG4j4Sudf9cSfh/OU6kFg6FZcRy31g3cn0q5GpKCJIuGKfI1JdMO2r/MmfbqRVL7tA1WiWh8y2P9VM7M9GPWF7vIE4Xw3PmJLMzZGYhixvYkyCWEefuK826SQM/EQa0fFiaHbIXYl3KJUDAFLqxS/W9cGUZIuJobpRq7e3ezNXRomMsl0tlfIwZvajNGmeaDJMuLYNDcRyT4Bymn13iGZz1kEqnoPqcwAzeyMFCTE1p2UwVYYPKuHFS+8zgHQ1pYmtjcYy72g3LXOYNOgSfGL38eRSzvVhJ00q9Jb9mWbi/iS1qne8pOXAQQY7ORqT0KsknQg0YtvYQNhiWZ888D0ZdbkhXjFudXOA3DExkslApDvqbl56naFtqYGa7Xi5NWF2ozU1QN8m3hStnpAZdk3PDNZ1QTVxtjP2JWXzUXWY7vTpBEJKCoIst22JhggmECf5aLWhAgOUFH0ARZOisFUJWgM5OH09x45AKY3dalk8TQXC2PR9DFoJVQ9XX0ksvXW0ZdWIG8NA2zhiHbNSf81Qhdyfr1TKZRdt5hAAVq1pKxH8n73DF5lfKN2sCoytNHlgs7SzcCSckNy5Cq0bJOaW6qReih9oAGXur0x+/iUUJCeI+bROgrvS7WkukGtvRnQjWlAH/rUVxqvNeiUeeXFE38Ly0hc0EXaG0lJBuuoDca0mD7pVp4QGgobVvqqscgSpVq/MBaky0t/4DJc5umC0ySe2J6MFwX24i5hujVJPrPhIGj5DWoKe0Vwdc6FkG6ec+WDAsDUxGdBKtM+JSwRU+bbHgoZ7HJzPVflVK65N3C0W+W6EG/5CejHajGW1Xj+n8enP1wreq5P03eIaVS8abZ6ycuwyDvFd4lWPXFalOB4YuAhu3EtvBq7CujvrICej5A1ePMoEAhcbO8UVpA/Uoz7n6Oy6HoldcfMfJsF7g+FDK2dJyeUAdJ9WAqGZck9k/+AK67cqpGmrMINrHqiQdXiQRK0ql0V4NEuHWFQPRJX+howOUznP0gJY5LhG2kC2qFJcY+1pd4Kai4FTtd5ckHaiQTI/lwZihX4oDAtO6qoMJJe5o4bkGjzDxJChvZK2BkixrACMy35Q82Ug6/fQfl3ZTO3DkwoHOPzHU2PtGDo11WThAqqg5J8CJCp32qJGj15+4Hjxtjl7r5MMJNZvZIWY1yNTMHbPzy+9hpnLKx4k9jSYteaOav2hlUc6nPHrkExBojvNTZXxLcIU9s0Qv6XMf3mpIHWDFydQxcD7GRfzf7hQ90GzdAheqeyAzxC+oMr2Hv8Cf7uNwHUHEgMAAAAASUVORK5CYII=","contentEncoding":"BASE64","mediaType":"image/png","timestamp":{"seconds":0,"nanos":8000000}}} +{"testStepFinished":{"testCaseStartedId":"18","testStepId":"16","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":9000000}}} +{"testCaseFinished":{"testCaseStartedId":"18","timestamp":{"seconds":0,"nanos":10000000},"willBeRetried":false}} +{"testRunFinished":{"testRunStartedId":"12","timestamp":{"seconds":0,"nanos":11000000},"success":true}} diff --git a/cucumber_cpp/acceptance_test/compatibility/examples-tables-undefined/examples-tables-undefined.ndjson b/cucumber_cpp/acceptance_test/compatibility/examples-tables-undefined/examples-tables-undefined.ndjson new file mode 100644 index 00000000..df0e7b29 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/examples-tables-undefined/examples-tables-undefined.ndjson @@ -0,0 +1,41 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"Feature: Examples Tables - With Undefined Steps\n The replacement pattern used in scenario outlines does not influence how steps\n are matched. The replacement pattern is replaced, and step definitions are\n matched against that text. Because of that the following results in one\n undefined step for each example and a suggested snippet to implement it. \n\n Scenario Outline: Eating cucumbers\n Given there are cucumbers\n When I eat cucumbers\n Then I should have cucumbers\n\n @undefined\n Examples: These are undefined because the value is not an {int}\n | start | eat | left |\n | pear | 1 | 12 |\n | 12 | banana | 12 |\n | 0 | 1 | apple |\n","uri":"samples/examples-tables-undefined/examples-undefined.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Examples Tables - With Undefined Steps","description":" The replacement pattern used in scenario outlines does not influence how steps\n are matched. The replacement pattern is replaced, and step definitions are\n matched against that text. Because of that the following results in one\n undefined step for each example and a suggested snippet to implement it. ","children":[{"scenario":{"id":"9","tags":[],"location":{"line":7,"column":3},"keyword":"Scenario Outline","name":"Eating cucumbers","description":"","steps":[{"id":"0","location":{"line":8,"column":5},"keyword":"Given ","keywordType":"Context","text":"there are cucumbers"},{"id":"1","location":{"line":9,"column":5},"keyword":"When ","keywordType":"Action","text":"I eat cucumbers"},{"id":"2","location":{"line":10,"column":5},"keyword":"Then ","keywordType":"Outcome","text":"I should have cucumbers"}],"examples":[{"id":"8","tags":[{"location":{"line":12,"column":5},"name":"@undefined","id":"7"}],"location":{"line":13,"column":5},"keyword":"Examples","name":"These are undefined because the value is not an {int}","description":"","tableHeader":{"id":"3","location":{"line":14,"column":7},"cells":[{"location":{"line":14,"column":9},"value":"start"},{"location":{"line":14,"column":17},"value":"eat"},{"location":{"line":14,"column":26},"value":"left"}]},"tableBody":[{"id":"4","location":{"line":15,"column":7},"cells":[{"location":{"line":15,"column":9},"value":"pear"},{"location":{"line":15,"column":17},"value":"1"},{"location":{"line":15,"column":26},"value":"12"}]},{"id":"5","location":{"line":16,"column":7},"cells":[{"location":{"line":16,"column":9},"value":"12"},{"location":{"line":16,"column":17},"value":"banana"},{"location":{"line":16,"column":26},"value":"12"}]},{"id":"6","location":{"line":17,"column":7},"cells":[{"location":{"line":17,"column":9},"value":"0"},{"location":{"line":17,"column":17},"value":"1"},{"location":{"line":17,"column":26},"value":"apple"}]}]}]}}]},"comments":[],"uri":"samples/examples-tables-undefined/examples-undefined.feature"}} +{"pickle":{"id":"13","uri":"samples/examples-tables-undefined/examples-undefined.feature","astNodeIds":["9","4"],"name":"Eating cucumbers","language":"en","steps":[{"id":"10","text":"there are pear cucumbers","type":"Context","astNodeIds":["0","4"]},{"id":"11","text":"I eat 1 cucumbers","type":"Action","astNodeIds":["1","4"]},{"id":"12","text":"I should have 12 cucumbers","type":"Outcome","astNodeIds":["2","4"]}],"tags":[{"name":"@undefined","astNodeId":"7"}]}} +{"pickle":{"id":"17","uri":"samples/examples-tables-undefined/examples-undefined.feature","astNodeIds":["9","5"],"name":"Eating cucumbers","language":"en","steps":[{"id":"14","text":"there are 12 cucumbers","type":"Context","astNodeIds":["0","5"]},{"id":"15","text":"I eat banana cucumbers","type":"Action","astNodeIds":["1","5"]},{"id":"16","text":"I should have 12 cucumbers","type":"Outcome","astNodeIds":["2","5"]}],"tags":[{"name":"@undefined","astNodeId":"7"}]}} +{"pickle":{"id":"21","uri":"samples/examples-tables-undefined/examples-undefined.feature","astNodeIds":["9","6"],"name":"Eating cucumbers","language":"en","steps":[{"id":"18","text":"there are 0 cucumbers","type":"Context","astNodeIds":["0","6"]},{"id":"19","text":"I eat 1 cucumbers","type":"Action","astNodeIds":["1","6"]},{"id":"20","text":"I should have apple cucumbers","type":"Outcome","astNodeIds":["2","6"]}],"tags":[{"name":"@undefined","astNodeId":"7"}]}} +{"stepDefinition":{"id":"22","pattern":{"type":"CUCUMBER_EXPRESSION","source":"there are {int} cucumbers"},"sourceReference":{"uri":"samples/examples-tables-undefined/examples-tables-undefined.ts","location":{"line":4}}}} +{"stepDefinition":{"id":"23","pattern":{"type":"CUCUMBER_EXPRESSION","source":"I eat {int} cucumbers"},"sourceReference":{"uri":"samples/examples-tables-undefined/examples-tables-undefined.ts","location":{"line":8}}}} +{"stepDefinition":{"id":"24","pattern":{"type":"CUCUMBER_EXPRESSION","source":"I should have {int} cucumbers"},"sourceReference":{"uri":"samples/examples-tables-undefined/examples-tables-undefined.ts","location":{"line":12}}}} +{"testRunStarted":{"id":"25","timestamp":{"seconds":0,"nanos":0}}} +{"testCase":{"id":"26","pickleId":"13","testSteps":[{"id":"27","pickleStepId":"10","stepDefinitionIds":[],"stepMatchArgumentsLists":[]},{"id":"28","pickleStepId":"11","stepDefinitionIds":["23"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":6,"value":"1","children":[]},"parameterTypeName":"int"}]}]},{"id":"29","pickleStepId":"12","stepDefinitionIds":["24"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":14,"value":"12","children":[]},"parameterTypeName":"int"}]}]}],"testRunStartedId":"25"}} +{"testCase":{"id":"30","pickleId":"17","testSteps":[{"id":"31","pickleStepId":"14","stepDefinitionIds":["22"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":10,"value":"12","children":[]},"parameterTypeName":"int"}]}]},{"id":"32","pickleStepId":"15","stepDefinitionIds":[],"stepMatchArgumentsLists":[]},{"id":"33","pickleStepId":"16","stepDefinitionIds":["24"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":14,"value":"12","children":[]},"parameterTypeName":"int"}]}]}],"testRunStartedId":"25"}} +{"testCase":{"id":"34","pickleId":"21","testSteps":[{"id":"35","pickleStepId":"18","stepDefinitionIds":["22"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":10,"value":"0","children":[]},"parameterTypeName":"int"}]}]},{"id":"36","pickleStepId":"19","stepDefinitionIds":["23"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":6,"value":"1","children":[]},"parameterTypeName":"int"}]}]},{"id":"37","pickleStepId":"20","stepDefinitionIds":[],"stepMatchArgumentsLists":[]}],"testRunStartedId":"25"}} +{"testCaseStarted":{"id":"38","testCaseId":"26","timestamp":{"seconds":0,"nanos":1000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"38","testStepId":"27","timestamp":{"seconds":0,"nanos":2000000}}} +{"suggestion":{"id":"39","pickleStepId":"10","snippets":[{"language":"typescript","code":"Given(\"there are pear cucumbers\", () => {\n return \"pending\"\n})"}]}} +{"testStepFinished":{"testCaseStartedId":"38","testStepId":"27","testStepResult":{"status":"UNDEFINED","duration":{"seconds":0,"nanos":0}},"timestamp":{"seconds":0,"nanos":3000000}}} +{"testStepStarted":{"testCaseStartedId":"38","testStepId":"28","timestamp":{"seconds":0,"nanos":4000000}}} +{"testStepFinished":{"testCaseStartedId":"38","testStepId":"28","testStepResult":{"status":"SKIPPED","duration":{"seconds":0,"nanos":0}},"timestamp":{"seconds":0,"nanos":5000000}}} +{"testStepStarted":{"testCaseStartedId":"38","testStepId":"29","timestamp":{"seconds":0,"nanos":6000000}}} +{"testStepFinished":{"testCaseStartedId":"38","testStepId":"29","testStepResult":{"status":"SKIPPED","duration":{"seconds":0,"nanos":0}},"timestamp":{"seconds":0,"nanos":7000000}}} +{"testCaseFinished":{"testCaseStartedId":"38","timestamp":{"seconds":0,"nanos":8000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"40","testCaseId":"30","timestamp":{"seconds":0,"nanos":9000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"40","testStepId":"31","timestamp":{"seconds":0,"nanos":10000000}}} +{"testStepFinished":{"testCaseStartedId":"40","testStepId":"31","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":11000000}}} +{"testStepStarted":{"testCaseStartedId":"40","testStepId":"32","timestamp":{"seconds":0,"nanos":12000000}}} +{"suggestion":{"id":"41","pickleStepId":"15","snippets":[{"language":"typescript","code":"When(\"I eat banana cucumbers\", () => {\n return \"pending\"\n})"}]}} +{"testStepFinished":{"testCaseStartedId":"40","testStepId":"32","testStepResult":{"status":"UNDEFINED","duration":{"seconds":0,"nanos":0}},"timestamp":{"seconds":0,"nanos":13000000}}} +{"testStepStarted":{"testCaseStartedId":"40","testStepId":"33","timestamp":{"seconds":0,"nanos":14000000}}} +{"testStepFinished":{"testCaseStartedId":"40","testStepId":"33","testStepResult":{"status":"SKIPPED","duration":{"seconds":0,"nanos":0}},"timestamp":{"seconds":0,"nanos":15000000}}} +{"testCaseFinished":{"testCaseStartedId":"40","timestamp":{"seconds":0,"nanos":16000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"42","testCaseId":"34","timestamp":{"seconds":0,"nanos":17000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"42","testStepId":"35","timestamp":{"seconds":0,"nanos":18000000}}} +{"testStepFinished":{"testCaseStartedId":"42","testStepId":"35","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":19000000}}} +{"testStepStarted":{"testCaseStartedId":"42","testStepId":"36","timestamp":{"seconds":0,"nanos":20000000}}} +{"testStepFinished":{"testCaseStartedId":"42","testStepId":"36","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":21000000}}} +{"testStepStarted":{"testCaseStartedId":"42","testStepId":"37","timestamp":{"seconds":0,"nanos":22000000}}} +{"suggestion":{"id":"43","pickleStepId":"20","snippets":[{"language":"typescript","code":"Then(\"I should have apple cucumbers\", () => {\n return \"pending\"\n})"}]}} +{"testStepFinished":{"testCaseStartedId":"42","testStepId":"37","testStepResult":{"status":"UNDEFINED","duration":{"seconds":0,"nanos":0}},"timestamp":{"seconds":0,"nanos":23000000}}} +{"testCaseFinished":{"testCaseStartedId":"42","timestamp":{"seconds":0,"nanos":24000000},"willBeRetried":false}} +{"testRunFinished":{"testRunStartedId":"25","timestamp":{"seconds":0,"nanos":25000000},"success":false}} diff --git a/cucumber_cpp/acceptance_test/compatibility/examples-tables-undefined/examples-undefined.feature b/cucumber_cpp/acceptance_test/compatibility/examples-tables-undefined/examples-undefined.feature new file mode 100644 index 00000000..0e35aaf1 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/examples-tables-undefined/examples-undefined.feature @@ -0,0 +1,17 @@ +Feature: Examples Tables - With Undefined Steps + The replacement pattern used in scenario outlines does not influence how steps + are matched. The replacement pattern is replaced, and step definitions are + matched against that text. Because of that the following results in one + undefined step for each example and a suggested snippet to implement it. + + Scenario Outline: Eating cucumbers + Given there are cucumbers + When I eat cucumbers + Then I should have cucumbers + + @undefined + Examples: These are undefined because the value is not an {int} + | start | eat | left | + | pear | 1 | 12 | + | 12 | banana | 12 | + | 0 | 1 | apple | diff --git a/cucumber_cpp/acceptance_test/compatibility/examples-tables/examples-tables.feature b/cucumber_cpp/acceptance_test/compatibility/examples-tables/examples-tables.feature new file mode 100644 index 00000000..523309dc --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/examples-tables/examples-tables.feature @@ -0,0 +1,37 @@ +Feature: Examples Tables + Sometimes it can be desirable to run the same scenario multiple times with + different data each time - this can be done by placing an Examples table + underneath a Scenario, and use in the Scenario which match the + table headers. + + The Scenario Outline name can also be parameterized. The name of the resulting + pickle will have the replaced with the value from the examples + table. + + Scenario Outline: Eating cucumbers + Given there are cucumbers + When I eat cucumbers + Then I should have cucumbers + + @passing + Examples: These are passing + | start | eat | left | + | 12 | 5 | 7 | + | 20 | 5 | 15 | + + @failing + Examples: These are failing + | start | eat | left | + | 12 | 20 | 0 | + | 0 | 1 | 0 | + + Scenario Outline: Eating cucumbers with friends + Given there are friends + And there are cucumbers + Then each person can eat cucumbers + + Examples: + | friends | start | share | + | 11 | 12 | 1 | + | 1 | 4 | 2 | + | 0 | 4 | 4 | diff --git a/cucumber_cpp/acceptance_test/compatibility/examples-tables/examples-tables.ndjson b/cucumber_cpp/acceptance_test/compatibility/examples-tables/examples-tables.ndjson new file mode 100644 index 00000000..3207ee09 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/examples-tables/examples-tables.ndjson @@ -0,0 +1,80 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"Feature: Examples Tables\n Sometimes it can be desirable to run the same scenario multiple times with\n different data each time - this can be done by placing an Examples table\n underneath a Scenario, and use in the Scenario which match the\n table headers.\n\n The Scenario Outline name can also be parameterized. The name of the resulting\n pickle will have the replaced with the value from the examples\n table.\n\n Scenario Outline: Eating cucumbers\n Given there are cucumbers\n When I eat cucumbers\n Then I should have cucumbers\n\n @passing\n Examples: These are passing\n | start | eat | left |\n | 12 | 5 | 7 |\n | 20 | 5 | 15 |\n\n @failing\n Examples: These are failing\n | start | eat | left |\n | 12 | 20 | 0 |\n | 0 | 1 | 0 |\n\n Scenario Outline: Eating cucumbers with friends\n Given there are friends\n And there are cucumbers\n Then each person can eat cucumbers\n\n Examples:\n | friends | start | share |\n | 11 | 12 | 1 |\n | 1 | 4 | 2 |\n | 0 | 4 | 4 |\n","uri":"samples/examples-tables/examples-tables.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Examples Tables","description":" Sometimes it can be desirable to run the same scenario multiple times with\n different data each time - this can be done by placing an Examples table\n underneath a Scenario, and use in the Scenario which match the\n table headers.\n\n The Scenario Outline name can also be parameterized. The name of the resulting\n pickle will have the replaced with the value from the examples\n table.","children":[{"scenario":{"id":"13","tags":[],"location":{"line":11,"column":3},"keyword":"Scenario Outline","name":"Eating cucumbers","description":"","steps":[{"id":"0","location":{"line":12,"column":5},"keyword":"Given ","keywordType":"Context","text":"there are cucumbers"},{"id":"1","location":{"line":13,"column":5},"keyword":"When ","keywordType":"Action","text":"I eat cucumbers"},{"id":"2","location":{"line":14,"column":5},"keyword":"Then ","keywordType":"Outcome","text":"I should have cucumbers"}],"examples":[{"id":"7","tags":[{"location":{"line":16,"column":5},"name":"@passing","id":"6"}],"location":{"line":17,"column":5},"keyword":"Examples","name":"These are passing","description":"","tableHeader":{"id":"3","location":{"line":18,"column":7},"cells":[{"location":{"line":18,"column":9},"value":"start"},{"location":{"line":18,"column":17},"value":"eat"},{"location":{"line":18,"column":23},"value":"left"}]},"tableBody":[{"id":"4","location":{"line":19,"column":7},"cells":[{"location":{"line":19,"column":12},"value":"12"},{"location":{"line":19,"column":19},"value":"5"},{"location":{"line":19,"column":26},"value":"7"}]},{"id":"5","location":{"line":20,"column":7},"cells":[{"location":{"line":20,"column":12},"value":"20"},{"location":{"line":20,"column":19},"value":"5"},{"location":{"line":20,"column":25},"value":"15"}]}]},{"id":"12","tags":[{"location":{"line":22,"column":5},"name":"@failing","id":"11"}],"location":{"line":23,"column":5},"keyword":"Examples","name":"These are failing","description":"","tableHeader":{"id":"8","location":{"line":24,"column":7},"cells":[{"location":{"line":24,"column":9},"value":"start"},{"location":{"line":24,"column":17},"value":"eat"},{"location":{"line":24,"column":23},"value":"left"}]},"tableBody":[{"id":"9","location":{"line":25,"column":7},"cells":[{"location":{"line":25,"column":12},"value":"12"},{"location":{"line":25,"column":18},"value":"20"},{"location":{"line":25,"column":26},"value":"0"}]},{"id":"10","location":{"line":26,"column":7},"cells":[{"location":{"line":26,"column":13},"value":"0"},{"location":{"line":26,"column":19},"value":"1"},{"location":{"line":26,"column":26},"value":"0"}]}]}]}},{"scenario":{"id":"22","tags":[],"location":{"line":28,"column":3},"keyword":"Scenario Outline","name":"Eating cucumbers with friends","description":"","steps":[{"id":"14","location":{"line":29,"column":5},"keyword":"Given ","keywordType":"Context","text":"there are friends"},{"id":"15","location":{"line":30,"column":5},"keyword":"And ","keywordType":"Conjunction","text":"there are cucumbers"},{"id":"16","location":{"line":31,"column":5},"keyword":"Then ","keywordType":"Outcome","text":"each person can eat cucumbers"}],"examples":[{"id":"21","tags":[],"location":{"line":33,"column":5},"keyword":"Examples","name":"","description":"","tableHeader":{"id":"17","location":{"line":34,"column":7},"cells":[{"location":{"line":34,"column":9},"value":"friends"},{"location":{"line":34,"column":19},"value":"start"},{"location":{"line":34,"column":27},"value":"share"}]},"tableBody":[{"id":"18","location":{"line":35,"column":7},"cells":[{"location":{"line":35,"column":14},"value":"11"},{"location":{"line":35,"column":22},"value":"12"},{"location":{"line":35,"column":31},"value":"1"}]},{"id":"19","location":{"line":36,"column":7},"cells":[{"location":{"line":36,"column":15},"value":"1"},{"location":{"line":36,"column":23},"value":"4"},{"location":{"line":36,"column":31},"value":"2"}]},{"id":"20","location":{"line":37,"column":7},"cells":[{"location":{"line":37,"column":15},"value":"0"},{"location":{"line":37,"column":23},"value":"4"},{"location":{"line":37,"column":31},"value":"4"}]}]}]}}]},"comments":[],"uri":"samples/examples-tables/examples-tables.feature"}} +{"pickle":{"id":"26","uri":"samples/examples-tables/examples-tables.feature","astNodeIds":["13","4"],"name":"Eating cucumbers","language":"en","steps":[{"id":"23","text":"there are 12 cucumbers","type":"Context","astNodeIds":["0","4"]},{"id":"24","text":"I eat 5 cucumbers","type":"Action","astNodeIds":["1","4"]},{"id":"25","text":"I should have 7 cucumbers","type":"Outcome","astNodeIds":["2","4"]}],"tags":[{"name":"@passing","astNodeId":"6"}]}} +{"pickle":{"id":"30","uri":"samples/examples-tables/examples-tables.feature","astNodeIds":["13","5"],"name":"Eating cucumbers","language":"en","steps":[{"id":"27","text":"there are 20 cucumbers","type":"Context","astNodeIds":["0","5"]},{"id":"28","text":"I eat 5 cucumbers","type":"Action","astNodeIds":["1","5"]},{"id":"29","text":"I should have 15 cucumbers","type":"Outcome","astNodeIds":["2","5"]}],"tags":[{"name":"@passing","astNodeId":"6"}]}} +{"pickle":{"id":"34","uri":"samples/examples-tables/examples-tables.feature","astNodeIds":["13","9"],"name":"Eating cucumbers","language":"en","steps":[{"id":"31","text":"there are 12 cucumbers","type":"Context","astNodeIds":["0","9"]},{"id":"32","text":"I eat 20 cucumbers","type":"Action","astNodeIds":["1","9"]},{"id":"33","text":"I should have 0 cucumbers","type":"Outcome","astNodeIds":["2","9"]}],"tags":[{"name":"@failing","astNodeId":"11"}]}} +{"pickle":{"id":"38","uri":"samples/examples-tables/examples-tables.feature","astNodeIds":["13","10"],"name":"Eating cucumbers","language":"en","steps":[{"id":"35","text":"there are 0 cucumbers","type":"Context","astNodeIds":["0","10"]},{"id":"36","text":"I eat 1 cucumbers","type":"Action","astNodeIds":["1","10"]},{"id":"37","text":"I should have 0 cucumbers","type":"Outcome","astNodeIds":["2","10"]}],"tags":[{"name":"@failing","astNodeId":"11"}]}} +{"pickle":{"id":"42","uri":"samples/examples-tables/examples-tables.feature","astNodeIds":["22","18"],"name":"Eating cucumbers with 11 friends","language":"en","steps":[{"id":"39","text":"there are 11 friends","type":"Context","astNodeIds":["14","18"]},{"id":"40","text":"there are 12 cucumbers","type":"Context","astNodeIds":["15","18"]},{"id":"41","text":"each person can eat 1 cucumbers","type":"Outcome","astNodeIds":["16","18"]}],"tags":[]}} +{"pickle":{"id":"46","uri":"samples/examples-tables/examples-tables.feature","astNodeIds":["22","19"],"name":"Eating cucumbers with 1 friends","language":"en","steps":[{"id":"43","text":"there are 1 friends","type":"Context","astNodeIds":["14","19"]},{"id":"44","text":"there are 4 cucumbers","type":"Context","astNodeIds":["15","19"]},{"id":"45","text":"each person can eat 2 cucumbers","type":"Outcome","astNodeIds":["16","19"]}],"tags":[]}} +{"pickle":{"id":"50","uri":"samples/examples-tables/examples-tables.feature","astNodeIds":["22","20"],"name":"Eating cucumbers with 0 friends","language":"en","steps":[{"id":"47","text":"there are 0 friends","type":"Context","astNodeIds":["14","20"]},{"id":"48","text":"there are 4 cucumbers","type":"Context","astNodeIds":["15","20"]},{"id":"49","text":"each person can eat 4 cucumbers","type":"Outcome","astNodeIds":["16","20"]}],"tags":[]}} +{"stepDefinition":{"id":"51","pattern":{"type":"CUCUMBER_EXPRESSION","source":"there are {int} cucumbers"},"sourceReference":{"uri":"samples/examples-tables/examples-tables.ts","location":{"line":4}}}} +{"stepDefinition":{"id":"52","pattern":{"type":"CUCUMBER_EXPRESSION","source":"there are {int} friends"},"sourceReference":{"uri":"samples/examples-tables/examples-tables.ts","location":{"line":8}}}} +{"stepDefinition":{"id":"53","pattern":{"type":"CUCUMBER_EXPRESSION","source":"I eat {int} cucumbers"},"sourceReference":{"uri":"samples/examples-tables/examples-tables.ts","location":{"line":12}}}} +{"stepDefinition":{"id":"54","pattern":{"type":"CUCUMBER_EXPRESSION","source":"I should have {int} cucumbers"},"sourceReference":{"uri":"samples/examples-tables/examples-tables.ts","location":{"line":16}}}} +{"stepDefinition":{"id":"55","pattern":{"type":"CUCUMBER_EXPRESSION","source":"each person can eat {int} cucumbers"},"sourceReference":{"uri":"samples/examples-tables/examples-tables.ts","location":{"line":20}}}} +{"testRunStarted":{"id":"56","timestamp":{"seconds":0,"nanos":0}}} +{"testCase":{"id":"57","pickleId":"26","testSteps":[{"id":"58","pickleStepId":"23","stepDefinitionIds":["51"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":10,"value":"12","children":[]},"parameterTypeName":"int"}]}]},{"id":"59","pickleStepId":"24","stepDefinitionIds":["53"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":6,"value":"5","children":[]},"parameterTypeName":"int"}]}]},{"id":"60","pickleStepId":"25","stepDefinitionIds":["54"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":14,"value":"7","children":[]},"parameterTypeName":"int"}]}]}],"testRunStartedId":"56"}} +{"testCase":{"id":"61","pickleId":"30","testSteps":[{"id":"62","pickleStepId":"27","stepDefinitionIds":["51"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":10,"value":"20","children":[]},"parameterTypeName":"int"}]}]},{"id":"63","pickleStepId":"28","stepDefinitionIds":["53"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":6,"value":"5","children":[]},"parameterTypeName":"int"}]}]},{"id":"64","pickleStepId":"29","stepDefinitionIds":["54"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":14,"value":"15","children":[]},"parameterTypeName":"int"}]}]}],"testRunStartedId":"56"}} +{"testCase":{"id":"65","pickleId":"34","testSteps":[{"id":"66","pickleStepId":"31","stepDefinitionIds":["51"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":10,"value":"12","children":[]},"parameterTypeName":"int"}]}]},{"id":"67","pickleStepId":"32","stepDefinitionIds":["53"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":6,"value":"20","children":[]},"parameterTypeName":"int"}]}]},{"id":"68","pickleStepId":"33","stepDefinitionIds":["54"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":14,"value":"0","children":[]},"parameterTypeName":"int"}]}]}],"testRunStartedId":"56"}} +{"testCase":{"id":"69","pickleId":"38","testSteps":[{"id":"70","pickleStepId":"35","stepDefinitionIds":["51"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":10,"value":"0","children":[]},"parameterTypeName":"int"}]}]},{"id":"71","pickleStepId":"36","stepDefinitionIds":["53"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":6,"value":"1","children":[]},"parameterTypeName":"int"}]}]},{"id":"72","pickleStepId":"37","stepDefinitionIds":["54"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":14,"value":"0","children":[]},"parameterTypeName":"int"}]}]}],"testRunStartedId":"56"}} +{"testCase":{"id":"73","pickleId":"42","testSteps":[{"id":"74","pickleStepId":"39","stepDefinitionIds":["52"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":10,"value":"11","children":[]},"parameterTypeName":"int"}]}]},{"id":"75","pickleStepId":"40","stepDefinitionIds":["51"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":10,"value":"12","children":[]},"parameterTypeName":"int"}]}]},{"id":"76","pickleStepId":"41","stepDefinitionIds":["55"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":20,"value":"1","children":[]},"parameterTypeName":"int"}]}]}],"testRunStartedId":"56"}} +{"testCase":{"id":"77","pickleId":"46","testSteps":[{"id":"78","pickleStepId":"43","stepDefinitionIds":["52"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":10,"value":"1","children":[]},"parameterTypeName":"int"}]}]},{"id":"79","pickleStepId":"44","stepDefinitionIds":["51"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":10,"value":"4","children":[]},"parameterTypeName":"int"}]}]},{"id":"80","pickleStepId":"45","stepDefinitionIds":["55"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":20,"value":"2","children":[]},"parameterTypeName":"int"}]}]}],"testRunStartedId":"56"}} +{"testCase":{"id":"81","pickleId":"50","testSteps":[{"id":"82","pickleStepId":"47","stepDefinitionIds":["52"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":10,"value":"0","children":[]},"parameterTypeName":"int"}]}]},{"id":"83","pickleStepId":"48","stepDefinitionIds":["51"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":10,"value":"4","children":[]},"parameterTypeName":"int"}]}]},{"id":"84","pickleStepId":"49","stepDefinitionIds":["55"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":20,"value":"4","children":[]},"parameterTypeName":"int"}]}]}],"testRunStartedId":"56"}} +{"testCaseStarted":{"id":"85","testCaseId":"57","timestamp":{"seconds":0,"nanos":1000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"85","testStepId":"58","timestamp":{"seconds":0,"nanos":2000000}}} +{"testStepFinished":{"testCaseStartedId":"85","testStepId":"58","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":3000000}}} +{"testStepStarted":{"testCaseStartedId":"85","testStepId":"59","timestamp":{"seconds":0,"nanos":4000000}}} +{"testStepFinished":{"testCaseStartedId":"85","testStepId":"59","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":5000000}}} +{"testStepStarted":{"testCaseStartedId":"85","testStepId":"60","timestamp":{"seconds":0,"nanos":6000000}}} +{"testStepFinished":{"testCaseStartedId":"85","testStepId":"60","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":7000000}}} +{"testCaseFinished":{"testCaseStartedId":"85","timestamp":{"seconds":0,"nanos":8000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"86","testCaseId":"61","timestamp":{"seconds":0,"nanos":9000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"86","testStepId":"62","timestamp":{"seconds":0,"nanos":10000000}}} +{"testStepFinished":{"testCaseStartedId":"86","testStepId":"62","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":11000000}}} +{"testStepStarted":{"testCaseStartedId":"86","testStepId":"63","timestamp":{"seconds":0,"nanos":12000000}}} +{"testStepFinished":{"testCaseStartedId":"86","testStepId":"63","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":13000000}}} +{"testStepStarted":{"testCaseStartedId":"86","testStepId":"64","timestamp":{"seconds":0,"nanos":14000000}}} +{"testStepFinished":{"testCaseStartedId":"86","testStepId":"64","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":15000000}}} +{"testCaseFinished":{"testCaseStartedId":"86","timestamp":{"seconds":0,"nanos":16000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"87","testCaseId":"65","timestamp":{"seconds":0,"nanos":17000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"87","testStepId":"66","timestamp":{"seconds":0,"nanos":18000000}}} +{"testStepFinished":{"testCaseStartedId":"87","testStepId":"66","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":19000000}}} +{"testStepStarted":{"testCaseStartedId":"87","testStepId":"67","timestamp":{"seconds":0,"nanos":20000000}}} +{"testStepFinished":{"testCaseStartedId":"87","testStepId":"67","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":21000000}}} +{"testStepStarted":{"testCaseStartedId":"87","testStepId":"68","timestamp":{"seconds":0,"nanos":22000000}}} +{"testStepFinished":{"testCaseStartedId":"87","testStepId":"68","testStepResult":{"message":"Expected values to be strictly equal:\n\n-8 !== 0\n","exception":{"type":"AssertionError","message":"Expected values to be strictly equal:\n\n-8 !== 0\n","stackTrace":"AssertionError: Expected values to be strictly equal:\n\n-8 !== 0\n\nsamples/examples-tables/examples-tables.feature:14"},"status":"FAILED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":23000000}}} +{"testCaseFinished":{"testCaseStartedId":"87","timestamp":{"seconds":0,"nanos":24000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"88","testCaseId":"69","timestamp":{"seconds":0,"nanos":25000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"88","testStepId":"70","timestamp":{"seconds":0,"nanos":26000000}}} +{"testStepFinished":{"testCaseStartedId":"88","testStepId":"70","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":27000000}}} +{"testStepStarted":{"testCaseStartedId":"88","testStepId":"71","timestamp":{"seconds":0,"nanos":28000000}}} +{"testStepFinished":{"testCaseStartedId":"88","testStepId":"71","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":29000000}}} +{"testStepStarted":{"testCaseStartedId":"88","testStepId":"72","timestamp":{"seconds":0,"nanos":30000000}}} +{"testStepFinished":{"testCaseStartedId":"88","testStepId":"72","testStepResult":{"message":"Expected values to be strictly equal:\n\n-1 !== 0\n","exception":{"type":"AssertionError","message":"Expected values to be strictly equal:\n\n-1 !== 0\n","stackTrace":"AssertionError: Expected values to be strictly equal:\n\n-1 !== 0\n\nsamples/examples-tables/examples-tables.feature:14"},"status":"FAILED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":31000000}}} +{"testCaseFinished":{"testCaseStartedId":"88","timestamp":{"seconds":0,"nanos":32000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"89","testCaseId":"73","timestamp":{"seconds":0,"nanos":33000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"89","testStepId":"74","timestamp":{"seconds":0,"nanos":34000000}}} +{"testStepFinished":{"testCaseStartedId":"89","testStepId":"74","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":35000000}}} +{"testStepStarted":{"testCaseStartedId":"89","testStepId":"75","timestamp":{"seconds":0,"nanos":36000000}}} +{"testStepFinished":{"testCaseStartedId":"89","testStepId":"75","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":37000000}}} +{"testStepStarted":{"testCaseStartedId":"89","testStepId":"76","timestamp":{"seconds":0,"nanos":38000000}}} +{"testStepFinished":{"testCaseStartedId":"89","testStepId":"76","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":39000000}}} +{"testCaseFinished":{"testCaseStartedId":"89","timestamp":{"seconds":0,"nanos":40000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"90","testCaseId":"77","timestamp":{"seconds":0,"nanos":41000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"90","testStepId":"78","timestamp":{"seconds":0,"nanos":42000000}}} +{"testStepFinished":{"testCaseStartedId":"90","testStepId":"78","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":43000000}}} +{"testStepStarted":{"testCaseStartedId":"90","testStepId":"79","timestamp":{"seconds":0,"nanos":44000000}}} +{"testStepFinished":{"testCaseStartedId":"90","testStepId":"79","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":45000000}}} +{"testStepStarted":{"testCaseStartedId":"90","testStepId":"80","timestamp":{"seconds":0,"nanos":46000000}}} +{"testStepFinished":{"testCaseStartedId":"90","testStepId":"80","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":47000000}}} +{"testCaseFinished":{"testCaseStartedId":"90","timestamp":{"seconds":0,"nanos":48000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"91","testCaseId":"81","timestamp":{"seconds":0,"nanos":49000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"91","testStepId":"82","timestamp":{"seconds":0,"nanos":50000000}}} +{"testStepFinished":{"testCaseStartedId":"91","testStepId":"82","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":51000000}}} +{"testStepStarted":{"testCaseStartedId":"91","testStepId":"83","timestamp":{"seconds":0,"nanos":52000000}}} +{"testStepFinished":{"testCaseStartedId":"91","testStepId":"83","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":53000000}}} +{"testStepStarted":{"testCaseStartedId":"91","testStepId":"84","timestamp":{"seconds":0,"nanos":54000000}}} +{"testStepFinished":{"testCaseStartedId":"91","testStepId":"84","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":55000000}}} +{"testCaseFinished":{"testCaseStartedId":"91","timestamp":{"seconds":0,"nanos":56000000},"willBeRetried":false}} +{"testRunFinished":{"testRunStartedId":"56","timestamp":{"seconds":0,"nanos":57000000},"success":false}} diff --git a/cucumber_cpp/acceptance_test/compatibility/global-hooks-afterall-error/global-hooks-afterall-error.feature b/cucumber_cpp/acceptance_test/compatibility/global-hooks-afterall-error/global-hooks-afterall-error.feature new file mode 100644 index 00000000..0ef1bfed --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/global-hooks-afterall-error/global-hooks-afterall-error.feature @@ -0,0 +1,6 @@ +Feature: Global hooks - AfterAll error + Errors in AfterAll hooks cause the whole test run to fail. The remaining AfterAll hooks will still run, in an + effort to clean up resources as well as possible. + + Scenario: A passing scenario + When a step passes diff --git a/cucumber_cpp/acceptance_test/compatibility/global-hooks-afterall-error/global-hooks-afterall-error.ndjson b/cucumber_cpp/acceptance_test/compatibility/global-hooks-afterall-error/global-hooks-afterall-error.ndjson new file mode 100644 index 00000000..f3fc04d2 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/global-hooks-afterall-error/global-hooks-afterall-error.ndjson @@ -0,0 +1,27 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"Feature: Global hooks - AfterAll error\n Errors in AfterAll hooks cause the whole test run to fail. The remaining AfterAll hooks will still run, in an\n effort to clean up resources as well as possible.\n\n Scenario: A passing scenario\n When a step passes\n","uri":"samples/global-hooks-afterall-error/global-hooks-afterall-error.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Global hooks - AfterAll error","description":" Errors in AfterAll hooks cause the whole test run to fail. The remaining AfterAll hooks will still run, in an\n effort to clean up resources as well as possible.","children":[{"scenario":{"id":"1","tags":[],"location":{"line":5,"column":3},"keyword":"Scenario","name":"A passing scenario","description":"","steps":[{"id":"0","location":{"line":6,"column":5},"keyword":"When ","keywordType":"Action","text":"a step passes"}],"examples":[]}}]},"comments":[],"uri":"samples/global-hooks-afterall-error/global-hooks-afterall-error.feature"}} +{"pickle":{"id":"3","uri":"samples/global-hooks-afterall-error/global-hooks-afterall-error.feature","astNodeIds":["1"],"tags":[],"name":"A passing scenario","language":"en","steps":[{"id":"2","text":"a step passes","type":"Action","astNodeIds":["0"]}]}} +{"stepDefinition":{"id":"6","pattern":{"type":"CUCUMBER_EXPRESSION","source":"a step passes"},"sourceReference":{"uri":"samples/global-hooks-afterall-error/global-hooks-afterall-error.ts","location":{"line":11}}}} +{"hook":{"id":"4","type":"BEFORE_TEST_RUN","sourceReference":{"uri":"samples/global-hooks-afterall-error/global-hooks-afterall-error.ts","location":{"line":3}}}} +{"hook":{"id":"5","type":"BEFORE_TEST_RUN","sourceReference":{"uri":"samples/global-hooks-afterall-error/global-hooks-afterall-error.ts","location":{"line":7}}}} +{"hook":{"id":"7","type":"AFTER_TEST_RUN","sourceReference":{"uri":"samples/global-hooks-afterall-error/global-hooks-afterall-error.ts","location":{"line":15}}}} +{"hook":{"id":"8","type":"AFTER_TEST_RUN","sourceReference":{"uri":"samples/global-hooks-afterall-error/global-hooks-afterall-error.ts","location":{"line":19}}}} +{"hook":{"id":"9","type":"AFTER_TEST_RUN","sourceReference":{"uri":"samples/global-hooks-afterall-error/global-hooks-afterall-error.ts","location":{"line":23}}}} +{"testRunStarted":{"id":"10","timestamp":{"seconds":0,"nanos":0}}} +{"testRunHookStarted":{"testRunStartedId":"10","id":"11","hookId":"4","timestamp":{"seconds":0,"nanos":1000000}}} +{"testRunHookFinished":{"testRunHookStartedId":"11","timestamp":{"seconds":0,"nanos":2000000},"result":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}}}} +{"testRunHookStarted":{"testRunStartedId":"10","id":"12","hookId":"5","timestamp":{"seconds":0,"nanos":3000000}}} +{"testRunHookFinished":{"testRunHookStartedId":"12","timestamp":{"seconds":0,"nanos":4000000},"result":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}}}} +{"testCase":{"id":"13","pickleId":"3","testSteps":[{"id":"14","pickleStepId":"2","stepDefinitionIds":["6"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"10"}} +{"testCaseStarted":{"id":"15","testCaseId":"13","timestamp":{"seconds":0,"nanos":5000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"15","testStepId":"14","timestamp":{"seconds":0,"nanos":6000000}}} +{"testStepFinished":{"testCaseStartedId":"15","testStepId":"14","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":7000000}}} +{"testCaseFinished":{"testCaseStartedId":"15","timestamp":{"seconds":0,"nanos":8000000},"willBeRetried":false}} +{"testRunHookStarted":{"testRunStartedId":"10","id":"16","hookId":"9","timestamp":{"seconds":0,"nanos":9000000}}} +{"testRunHookFinished":{"testRunHookStartedId":"16","timestamp":{"seconds":0,"nanos":10000000},"result":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}}}} +{"testRunHookStarted":{"testRunStartedId":"10","id":"17","hookId":"8","timestamp":{"seconds":0,"nanos":11000000}}} +{"testRunHookFinished":{"testRunHookStartedId":"17","timestamp":{"seconds":0,"nanos":12000000},"result":{"message":"AfterAll hook went wrong","exception":{"type":"Error","message":"AfterAll hook went wrong","stackTrace":"Error: AfterAll hook went wrong\nsamples/global-hooks-afterall-error/global-hooks-afterall-error.ts:19"},"status":"FAILED","duration":{"seconds":0,"nanos":1000000}}}} +{"testRunHookStarted":{"testRunStartedId":"10","id":"18","hookId":"7","timestamp":{"seconds":0,"nanos":13000000}}} +{"testRunHookFinished":{"testRunHookStartedId":"18","timestamp":{"seconds":0,"nanos":14000000},"result":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}}}} +{"testRunFinished":{"testRunStartedId":"10","timestamp":{"seconds":0,"nanos":15000000},"success":false}} diff --git a/cucumber_cpp/acceptance_test/compatibility/global-hooks-attachments/global-hooks-attachments.feature b/cucumber_cpp/acceptance_test/compatibility/global-hooks-attachments/global-hooks-attachments.feature new file mode 100644 index 00000000..d96ccf2b --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/global-hooks-attachments/global-hooks-attachments.feature @@ -0,0 +1,5 @@ +Feature: Global hooks with attachments + Attachments can be captured in BeforeAll and AfterAll hooks. + + Scenario: A scenario + When a step passes diff --git a/cucumber_cpp/acceptance_test/compatibility/global-hooks-attachments/global-hooks-attachments.ndjson b/cucumber_cpp/acceptance_test/compatibility/global-hooks-attachments/global-hooks-attachments.ndjson new file mode 100644 index 00000000..dfc8e177 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/global-hooks-attachments/global-hooks-attachments.ndjson @@ -0,0 +1,20 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"Feature: Global hooks with attachments\n Attachments can be captured in BeforeAll and AfterAll hooks.\n\n Scenario: A scenario\n When a step passes\n","uri":"samples/global-hooks-attachments/global-hooks-attachments.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Global hooks with attachments","description":" Attachments can be captured in BeforeAll and AfterAll hooks.","children":[{"scenario":{"id":"1","tags":[],"location":{"line":4,"column":3},"keyword":"Scenario","name":"A scenario","description":"","steps":[{"id":"0","location":{"line":5,"column":5},"keyword":"When ","keywordType":"Action","text":"a step passes"}],"examples":[]}}]},"comments":[],"uri":"samples/global-hooks-attachments/global-hooks-attachments.feature"}} +{"pickle":{"id":"3","uri":"samples/global-hooks-attachments/global-hooks-attachments.feature","astNodeIds":["1"],"tags":[],"name":"A scenario","language":"en","steps":[{"id":"2","text":"a step passes","type":"Action","astNodeIds":["0"]}]}} +{"stepDefinition":{"id":"5","pattern":{"type":"CUCUMBER_EXPRESSION","source":"a step passes"},"sourceReference":{"uri":"samples/global-hooks-attachments/global-hooks-attachments.ts","location":{"line":7}}}} +{"hook":{"id":"4","type":"BEFORE_TEST_RUN","sourceReference":{"uri":"samples/global-hooks-attachments/global-hooks-attachments.ts","location":{"line":3}}}} +{"hook":{"id":"6","type":"AFTER_TEST_RUN","sourceReference":{"uri":"samples/global-hooks-attachments/global-hooks-attachments.ts","location":{"line":11}}}} +{"testRunStarted":{"id":"7","timestamp":{"seconds":0,"nanos":0}}} +{"testRunHookStarted":{"testRunStartedId":"7","id":"8","hookId":"4","timestamp":{"seconds":0,"nanos":1000000}}} +{"attachment":{"testRunHookStartedId":"8","body":"Attachment from BeforeAll hook","contentEncoding":"IDENTITY","mediaType":"text/plain","timestamp":{"seconds":0,"nanos":2000000}}} +{"testRunHookFinished":{"testRunHookStartedId":"8","timestamp":{"seconds":0,"nanos":3000000},"result":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}}}} +{"testCase":{"id":"9","pickleId":"3","testSteps":[{"id":"10","pickleStepId":"2","stepDefinitionIds":["5"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"7"}} +{"testCaseStarted":{"id":"11","testCaseId":"9","timestamp":{"seconds":0,"nanos":4000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"11","testStepId":"10","timestamp":{"seconds":0,"nanos":5000000}}} +{"testStepFinished":{"testCaseStartedId":"11","testStepId":"10","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":6000000}}} +{"testCaseFinished":{"testCaseStartedId":"11","timestamp":{"seconds":0,"nanos":7000000},"willBeRetried":false}} +{"testRunHookStarted":{"testRunStartedId":"7","id":"12","hookId":"6","timestamp":{"seconds":0,"nanos":8000000}}} +{"attachment":{"testRunHookStartedId":"12","body":"Attachment from AfterAll hook","contentEncoding":"IDENTITY","mediaType":"text/plain","timestamp":{"seconds":0,"nanos":9000000}}} +{"testRunHookFinished":{"testRunHookStartedId":"12","timestamp":{"seconds":0,"nanos":10000000},"result":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}}}} +{"testRunFinished":{"testRunStartedId":"7","timestamp":{"seconds":0,"nanos":11000000},"success":true}} diff --git a/cucumber_cpp/acceptance_test/compatibility/global-hooks-beforeall-error/global-hooks-beforeall-error.feature b/cucumber_cpp/acceptance_test/compatibility/global-hooks-beforeall-error/global-hooks-beforeall-error.feature new file mode 100644 index 00000000..2b42678e --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/global-hooks-beforeall-error/global-hooks-beforeall-error.feature @@ -0,0 +1,6 @@ +Feature: Global hooks - BeforeAll error + Errors in BeforeAll hooks cause the whole test run to fail. Test cases will not be executed. The remaining BeforeAll + hooks will still run, along with all AfterAll hooks, in an effort to clean up resources as well as possible. + + Scenario: A passing scenario + When a step passes diff --git a/cucumber_cpp/acceptance_test/compatibility/global-hooks-beforeall-error/global-hooks-beforeall-error.ndjson b/cucumber_cpp/acceptance_test/compatibility/global-hooks-beforeall-error/global-hooks-beforeall-error.ndjson new file mode 100644 index 00000000..0785d794 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/global-hooks-beforeall-error/global-hooks-beforeall-error.ndjson @@ -0,0 +1,22 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"Feature: Global hooks - BeforeAll error\n Errors in BeforeAll hooks cause the whole test run to fail. Test cases will not be executed. The remaining BeforeAll\n hooks will still run, along with all AfterAll hooks, in an effort to clean up resources as well as possible.\n\n Scenario: A passing scenario\n When a step passes\n","uri":"samples/global-hooks-beforeall-error/global-hooks-beforeall-error.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Global hooks - BeforeAll error","description":" Errors in BeforeAll hooks cause the whole test run to fail. Test cases will not be executed. The remaining BeforeAll\n hooks will still run, along with all AfterAll hooks, in an effort to clean up resources as well as possible.","children":[{"scenario":{"id":"1","tags":[],"location":{"line":5,"column":3},"keyword":"Scenario","name":"A passing scenario","description":"","steps":[{"id":"0","location":{"line":6,"column":5},"keyword":"When ","keywordType":"Action","text":"a step passes"}],"examples":[]}}]},"comments":[],"uri":"samples/global-hooks-beforeall-error/global-hooks-beforeall-error.feature"}} +{"pickle":{"id":"3","uri":"samples/global-hooks-beforeall-error/global-hooks-beforeall-error.feature","astNodeIds":["1"],"tags":[],"name":"A passing scenario","language":"en","steps":[{"id":"2","text":"a step passes","type":"Action","astNodeIds":["0"]}]}} +{"stepDefinition":{"id":"7","pattern":{"type":"CUCUMBER_EXPRESSION","source":"a step passes"},"sourceReference":{"uri":"samples/global-hooks-beforeall-error/global-hooks-beforeall-error.ts","location":{"line":15}}}} +{"hook":{"id":"4","type":"BEFORE_TEST_RUN","sourceReference":{"uri":"samples/global-hooks-beforeall-error/global-hooks-beforeall-error.ts","location":{"line":3}}}} +{"hook":{"id":"5","type":"BEFORE_TEST_RUN","sourceReference":{"uri":"samples/global-hooks-beforeall-error/global-hooks-beforeall-error.ts","location":{"line":7}}}} +{"hook":{"id":"6","type":"BEFORE_TEST_RUN","sourceReference":{"uri":"samples/global-hooks-beforeall-error/global-hooks-beforeall-error.ts","location":{"line":11}}}} +{"hook":{"id":"8","type":"AFTER_TEST_RUN","sourceReference":{"uri":"samples/global-hooks-beforeall-error/global-hooks-beforeall-error.ts","location":{"line":19}}}} +{"hook":{"id":"9","type":"AFTER_TEST_RUN","sourceReference":{"uri":"samples/global-hooks-beforeall-error/global-hooks-beforeall-error.ts","location":{"line":23}}}} +{"testRunStarted":{"id":"10","timestamp":{"seconds":0,"nanos":0}}} +{"testRunHookStarted":{"testRunStartedId":"10","id":"11","hookId":"4","timestamp":{"seconds":0,"nanos":1000000}}} +{"testRunHookFinished":{"testRunHookStartedId":"11","timestamp":{"seconds":0,"nanos":2000000},"result":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}}}} +{"testRunHookStarted":{"testRunStartedId":"10","id":"12","hookId":"5","timestamp":{"seconds":0,"nanos":3000000}}} +{"testRunHookFinished":{"testRunHookStartedId":"12","timestamp":{"seconds":0,"nanos":4000000},"result":{"message":"BeforeAll hook went wrong","exception":{"type":"Error","message":"BeforeAll hook went wrong","stackTrace":"Error: BeforeAll hook went wrong\nsamples/global-hooks-beforeall-error/global-hooks-beforeall-error.ts:7"},"status":"FAILED","duration":{"seconds":0,"nanos":1000000}}}} +{"testRunHookStarted":{"testRunStartedId":"10","id":"13","hookId":"6","timestamp":{"seconds":0,"nanos":5000000}}} +{"testRunHookFinished":{"testRunHookStartedId":"13","timestamp":{"seconds":0,"nanos":6000000},"result":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}}}} +{"testRunHookStarted":{"testRunStartedId":"10","id":"14","hookId":"9","timestamp":{"seconds":0,"nanos":7000000}}} +{"testRunHookFinished":{"testRunHookStartedId":"14","timestamp":{"seconds":0,"nanos":8000000},"result":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}}}} +{"testRunHookStarted":{"testRunStartedId":"10","id":"15","hookId":"8","timestamp":{"seconds":0,"nanos":9000000}}} +{"testRunHookFinished":{"testRunHookStartedId":"15","timestamp":{"seconds":0,"nanos":10000000},"result":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}}}} +{"testRunFinished":{"testRunStartedId":"10","timestamp":{"seconds":0,"nanos":11000000},"success":false}} diff --git a/cucumber_cpp/acceptance_test/compatibility/global-hooks/global-hooks.feature b/cucumber_cpp/acceptance_test/compatibility/global-hooks/global-hooks.feature new file mode 100644 index 00000000..715a76f3 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/global-hooks/global-hooks.feature @@ -0,0 +1,10 @@ +Feature: Global hooks + Hooks can be at the test run level, so they run once before or after all test cases. + + AfterAll hooks are executed in reverse order of definition. + + Scenario: A passing scenario + When a step passes + + Scenario: A failing scenario + When a step fails diff --git a/cucumber_cpp/acceptance_test/compatibility/global-hooks/global-hooks.ndjson b/cucumber_cpp/acceptance_test/compatibility/global-hooks/global-hooks.ndjson new file mode 100644 index 00000000..1af9114e --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/global-hooks/global-hooks.ndjson @@ -0,0 +1,31 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"Feature: Global hooks\n Hooks can be at the test run level, so they run once before or after all test cases.\n\n AfterAll hooks are executed in reverse order of definition.\n\n Scenario: A passing scenario\n When a step passes\n\n Scenario: A failing scenario\n When a step fails\n","uri":"samples/global-hooks/global-hooks.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Global hooks","description":" Hooks can be at the test run level, so they run once before or after all test cases.\n\n AfterAll hooks are executed in reverse order of definition.","children":[{"scenario":{"id":"1","tags":[],"location":{"line":6,"column":3},"keyword":"Scenario","name":"A passing scenario","description":"","steps":[{"id":"0","location":{"line":7,"column":5},"keyword":"When ","keywordType":"Action","text":"a step passes"}],"examples":[]}},{"scenario":{"id":"3","tags":[],"location":{"line":9,"column":3},"keyword":"Scenario","name":"A failing scenario","description":"","steps":[{"id":"2","location":{"line":10,"column":5},"keyword":"When ","keywordType":"Action","text":"a step fails"}],"examples":[]}}]},"comments":[],"uri":"samples/global-hooks/global-hooks.feature"}} +{"pickle":{"id":"5","uri":"samples/global-hooks/global-hooks.feature","astNodeIds":["1"],"tags":[],"name":"A passing scenario","language":"en","steps":[{"id":"4","text":"a step passes","type":"Action","astNodeIds":["0"]}]}} +{"pickle":{"id":"7","uri":"samples/global-hooks/global-hooks.feature","astNodeIds":["3"],"tags":[],"name":"A failing scenario","language":"en","steps":[{"id":"6","text":"a step fails","type":"Action","astNodeIds":["2"]}]}} +{"stepDefinition":{"id":"10","pattern":{"type":"CUCUMBER_EXPRESSION","source":"a step passes"},"sourceReference":{"uri":"samples/global-hooks/global-hooks.ts","location":{"line":11}}}} +{"stepDefinition":{"id":"11","pattern":{"type":"CUCUMBER_EXPRESSION","source":"a step fails"},"sourceReference":{"uri":"samples/global-hooks/global-hooks.ts","location":{"line":15}}}} +{"hook":{"id":"8","type":"BEFORE_TEST_RUN","sourceReference":{"uri":"samples/global-hooks/global-hooks.ts","location":{"line":3}}}} +{"hook":{"id":"9","type":"BEFORE_TEST_RUN","sourceReference":{"uri":"samples/global-hooks/global-hooks.ts","location":{"line":7}}}} +{"hook":{"id":"12","type":"AFTER_TEST_RUN","sourceReference":{"uri":"samples/global-hooks/global-hooks.ts","location":{"line":19}}}} +{"hook":{"id":"13","type":"AFTER_TEST_RUN","sourceReference":{"uri":"samples/global-hooks/global-hooks.ts","location":{"line":23}}}} +{"testRunStarted":{"id":"14","timestamp":{"seconds":0,"nanos":0}}} +{"testRunHookStarted":{"testRunStartedId":"14","id":"15","hookId":"8","timestamp":{"seconds":0,"nanos":1000000}}} +{"testRunHookFinished":{"testRunHookStartedId":"15","timestamp":{"seconds":0,"nanos":2000000},"result":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}}}} +{"testRunHookStarted":{"testRunStartedId":"14","id":"16","hookId":"9","timestamp":{"seconds":0,"nanos":3000000}}} +{"testRunHookFinished":{"testRunHookStartedId":"16","timestamp":{"seconds":0,"nanos":4000000},"result":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}}}} +{"testCase":{"id":"17","pickleId":"5","testSteps":[{"id":"18","pickleStepId":"4","stepDefinitionIds":["10"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"14"}} +{"testCase":{"id":"19","pickleId":"7","testSteps":[{"id":"20","pickleStepId":"6","stepDefinitionIds":["11"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"14"}} +{"testCaseStarted":{"id":"21","testCaseId":"17","timestamp":{"seconds":0,"nanos":5000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"21","testStepId":"18","timestamp":{"seconds":0,"nanos":6000000}}} +{"testStepFinished":{"testCaseStartedId":"21","testStepId":"18","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":7000000}}} +{"testCaseFinished":{"testCaseStartedId":"21","timestamp":{"seconds":0,"nanos":8000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"22","testCaseId":"19","timestamp":{"seconds":0,"nanos":9000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"22","testStepId":"20","timestamp":{"seconds":0,"nanos":10000000}}} +{"testStepFinished":{"testCaseStartedId":"22","testStepId":"20","testStepResult":{"message":"Exception in step","exception":{"type":"Error","message":"Exception in step","stackTrace":"Error: Exception in step\nsamples/global-hooks/global-hooks.feature:10"},"status":"FAILED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":11000000}}} +{"testCaseFinished":{"testCaseStartedId":"22","timestamp":{"seconds":0,"nanos":12000000},"willBeRetried":false}} +{"testRunHookStarted":{"testRunStartedId":"14","id":"23","hookId":"13","timestamp":{"seconds":0,"nanos":13000000}}} +{"testRunHookFinished":{"testRunHookStartedId":"23","timestamp":{"seconds":0,"nanos":14000000},"result":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}}}} +{"testRunHookStarted":{"testRunStartedId":"14","id":"24","hookId":"12","timestamp":{"seconds":0,"nanos":15000000}}} +{"testRunHookFinished":{"testRunHookStartedId":"24","timestamp":{"seconds":0,"nanos":16000000},"result":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}}}} +{"testRunFinished":{"testRunStartedId":"14","timestamp":{"seconds":0,"nanos":17000000},"success":false}} diff --git a/cucumber_cpp/acceptance_test/compatibility/hooks-attachment/.gitattributes b/cucumber_cpp/acceptance_test/compatibility/hooks-attachment/.gitattributes new file mode 100644 index 00000000..6ea7b312 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/hooks-attachment/.gitattributes @@ -0,0 +1,4 @@ +# SVG files are plain text. So git will change line endings on windows. +# Because we expect the image to have been encoded in base64 with lf rather than +# crlf this is not desirable. +cucumber.svg eol=lf diff --git a/cucumber_cpp/acceptance_test/compatibility/hooks-attachment/cucumber.svg b/cucumber_cpp/acceptance_test/compatibility/hooks-attachment/cucumber.svg new file mode 100644 index 00000000..e76ff7fa --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/hooks-attachment/cucumber.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/cucumber_cpp/acceptance_test/compatibility/hooks-attachment/hooks-attachment.feature b/cucumber_cpp/acceptance_test/compatibility/hooks-attachment/hooks-attachment.feature new file mode 100644 index 00000000..721e3470 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/hooks-attachment/hooks-attachment.feature @@ -0,0 +1,7 @@ +Feature: Hooks - Attachments + Hooks are special steps that run before or after each scenario's steps. + + Like regular steps, it is possible to attach a file to the output. + + Scenario: With an valid attachment in the hook and a passed step + When a step passes diff --git a/cucumber_cpp/acceptance_test/compatibility/hooks-attachment/hooks-attachment.ndjson b/cucumber_cpp/acceptance_test/compatibility/hooks-attachment/hooks-attachment.ndjson new file mode 100644 index 00000000..2d7c0871 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/hooks-attachment/hooks-attachment.ndjson @@ -0,0 +1,20 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"Feature: Hooks - Attachments\n Hooks are special steps that run before or after each scenario's steps.\n\n Like regular steps, it is possible to attach a file to the output.\n\n Scenario: With an valid attachment in the hook and a passed step\n When a step passes\n","uri":"samples/hooks-attachment/hooks-attachment.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Hooks - Attachments","description":" Hooks are special steps that run before or after each scenario's steps.\n\n Like regular steps, it is possible to attach a file to the output.","children":[{"scenario":{"id":"1","tags":[],"location":{"line":6,"column":3},"keyword":"Scenario","name":"With an valid attachment in the hook and a passed step","description":"","steps":[{"id":"0","location":{"line":7,"column":5},"keyword":"When ","keywordType":"Action","text":"a step passes"}],"examples":[]}}]},"comments":[],"uri":"samples/hooks-attachment/hooks-attachment.feature"}} +{"pickle":{"id":"3","uri":"samples/hooks-attachment/hooks-attachment.feature","astNodeIds":["1"],"tags":[],"name":"With an valid attachment in the hook and a passed step","language":"en","steps":[{"id":"2","text":"a step passes","type":"Action","astNodeIds":["0"]}]}} +{"stepDefinition":{"id":"5","pattern":{"type":"CUCUMBER_EXPRESSION","source":"a step passes"},"sourceReference":{"uri":"samples/hooks-attachment/hooks-attachment.ts","location":{"line":9}}}} +{"hook":{"id":"4","type":"BEFORE_TEST_CASE","sourceReference":{"uri":"samples/hooks-attachment/hooks-attachment.ts","location":{"line":4}}}} +{"hook":{"id":"6","type":"AFTER_TEST_CASE","sourceReference":{"uri":"samples/hooks-attachment/hooks-attachment.ts","location":{"line":13}}}} +{"testRunStarted":{"id":"7","timestamp":{"seconds":0,"nanos":0}}} +{"testCase":{"id":"8","pickleId":"3","testSteps":[{"id":"9","hookId":"4"},{"id":"10","pickleStepId":"2","stepDefinitionIds":["5"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]},{"id":"11","hookId":"6"}],"testRunStartedId":"7"}} +{"testCaseStarted":{"id":"12","testCaseId":"8","timestamp":{"seconds":0,"nanos":1000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"12","testStepId":"9","timestamp":{"seconds":0,"nanos":2000000}}} +{"attachment":{"testCaseStartedId":"12","testStepId":"9","body":"PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGNsYXNzPSJtbC0zIG1sLW1kLTAiIHZpZXdCb3g9IjAgMCA0MC41OSA0Ni4zMSIgd2lkdGg9IjQwLjU5IiBoZWlnaHQ9IjQ2LjMxIj4KICAgIDxnPgogICAgICAgIDxwYXRoIGZpbGw9IiMyM2Q5NmMiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZD0iTTMwLjI4MyAzLjY0NXEtLjUyOC0uMzE3LTEuMDgtLjU5M2ExNi4xNjQgMTYuMTY0IDAgMDAtMS4xNTQtLjUxOGMtLjEyNC0uMDUyLS4yNDctLjEtLjM3Mi0uMTQ5LS4zNDMtLjEyNy0uNjg5LS4yNjgtMS4wNDItLjM3MWExOS40MjcgMTkuNDI3IDAgMTAtOS43OTIgMzcuNTF2NS41NmMxMS42NzYtMS43NTMgMjIuMDE2LTEwLjk3OSAyMi43ODctMjMuMDkzLjQ1OS03LjI4OS0zLjE5My0xNC43My05LjM0Ny0xOC4zNDZ6Ii8+CiAgICAgICAgPHBhdGggZmlsbD0iIzE3MzY0NyIgZD0iTTE1Ljc4NyA0Ni4zMDd2LTUuOTM1QTIwLjQ3MiAyMC40NzIgMCAxMTI2Ljk1OSAxLjAxNWMuMjc0LjA4LjU1Ny4xODcuODMyLjI5MWwuMjQ4LjA5M2MuMTY1LjA2NC4yOTEuMTEzLjQxNy4xNjcuMzQ4LjEzNy43MzkuMzEzIDEuMjA4LjU0M3EuNTg5LjI5NSAxLjE1My42MzNjNi4zOTMgMy43NTYgMTAuMzU0IDExLjUxOCA5Ljg1NyAxOS4zMTYtLjc2MyAxMi0xMC43MjIgMjIuMTIyLTIzLjY3OSAyNC4wNjd6bTQuOC00NC4yMTRoLS4wMjZhMTguMzY2IDE4LjM2NiAwIDAwLTMuNTI0IDM2LjQwOGwuODUuMTY1djUuMThjMTEuMzkyLTIuMjI0IDIwLjAwOS0xMS4yNzIgMjAuNjg2LTIxLjkyMi40NDgtNy4wMzMtMy4xLTE0LjAxOC04LjgzLTE3LjM4M2wtLjAwOC0uMDA1QTE0LjY5MSAxNC42OTEgMCAwMDI3LjY1NCAzLjVhNS43NCA1Ljc0IDAgMDAtLjM0NC0uMTM4bC0uMjctLjFhOS40OSA5LjQ5IDAgMDAtLjcwOC0uMjQ5IDE4LjQyNSAxOC40MjUgMCAwMC01Ljc0My0uOTJ6Ii8+CiAgICAgICAgPHBhdGggZmlsbD0iIzE3MzY0NyIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMTYuNjY2IDEwLjU4YTEuOCAxLjggMCAwMTEuNTgzLjYwOCA0LjE4NCA0LjE4NCAwIDAxLjcyOCAxLjEwN2MuNjQ1IDEuNDIyIDEuMDI3IDMuNDYxLjIzIDQuNjA1YTYuMzM0IDYuMzM0IDAgMDEtMy45ODEtMy4wODcgMy4yMzYgMy4yMzYgMCAwMS0uMzQ3LTEuMzM5IDEuOTU3IDEuOTU3IDAgMDExLjc4Ny0xLjg5NHptLTUuNjgzIDguMDI1YTcuNzQyIDcuNzQyIDAgMDAxLjIxOC43MzcgNS43ODkgNS43ODkgMCAwMDQuODgzLS4xMzggNi4xMTYgNi4xMTYgMCAwMC0zLjM0NS0zLjQ1IDMuNjY0IDMuNjY0IDAgMDAtMS40NDItLjMyMSAxLjg4NCAxLjg4NCAwIDAwLS4zMTkgMCAxLjc2NiAxLjc2NiAwIDAwLS45OTUgMy4xNzJ6bTYuMSAzLjQzM2MtLjc3Ny0uNTE4LTIuMzc5LS4zMDktMy4zMTItLjI5MmE0LjQxNiA0LjQxNiAwIDAwLTEuNjY2LjM1MiAzLjUgMy41IDAgMDAtMS4yMTguNzM4IDEuODE3IDEuODE3IDAgMDAxLjQwOSAzLjE3MSAzLjMgMy4zIDAgMDAxLjQ0Mi0uMzIxYzEuNDM2LS42MiAzLjE0MS0yLjMyIDMuMzQ2LTMuNjQ4em0yLjYxIDJhNi41NTYgNi41NTYgMCAwMC0zLjcyNCAzLjUwNiAzLjA5MSAzLjA5MSAwIDAwLS4zMjEgMS4zMTQgMS45MDcgMS45MDcgMCAwMDMuMyAxLjM0NiA3LjQyMiA3LjQyMiAwIDAwLjctMS4yMThjLjYyMS0xLjMzMy44NjYtMy43Mi4wNDYtNC45NDh6bTIuNTU3LTcuMTY3YTUuOTQxIDUuOTQxIDAgMDAzLjctMy4xNjcgMy4yNDMgMy4yNDMgMCAwMC4zMTktMS4zNDYgMS45MTUgMS45MTUgMCAwMC0xLjc5NC0xLjk1NCAxLjgzMiAxLjgzMiAwIDAwLTEuNi42NDEgNy4zODIgNy4zODIgMCAwMC0uNzA1IDEuMjE4Yy0uNjIgMS40MzQtLjg0MiAzLjQ4LjA4MSA0LjYwM3ptNC4yMDggMTIuMTE1YTMuMjQ0IDMuMjQ0IDAgMDAtLjMyMS0xLjM0NSA1Ljg2OSA1Ljg2OSAwIDAwLTMuNTU0LTMuMjY5IDUuMzg2IDUuMzg2IDAgMDAtLjIyNiA0LjcxMSA0LjE0NyA0LjE0NyAwIDAwLjcgMS4xMjFjMS4xMzMgMS4yMyAzLjUwNS4zMiAzLjQwMi0xLjIxOHptNC4yLTYuMjhhNy40NjYgNy40NjYgMCAwMC0xLjIxNy0uNyA0LjQyNSA0LjQyNSAwIDAwLTEuNjY2LS4zNTIgNi40IDYuNCAwIDAwLTMuMTg4LjU1NSA1Ljk1OSA1Ljk1OSAwIDAwMy4zMTYgMy4zODYgMy42NzIgMy42NzIgMCAwMDEuNDQyLjMyIDEuOCAxLjggMCAwMDEuMzEtMy4yMDl6Ii8+CiAgICA8L2c+Cjwvc3ZnPg==","contentEncoding":"BASE64","mediaType":"image/svg+xml","timestamp":{"seconds":0,"nanos":3000000}}} +{"testStepFinished":{"testCaseStartedId":"12","testStepId":"9","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":4000000}}} +{"testStepStarted":{"testCaseStartedId":"12","testStepId":"10","timestamp":{"seconds":0,"nanos":5000000}}} +{"testStepFinished":{"testCaseStartedId":"12","testStepId":"10","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":6000000}}} +{"testStepStarted":{"testCaseStartedId":"12","testStepId":"11","timestamp":{"seconds":0,"nanos":7000000}}} +{"attachment":{"testCaseStartedId":"12","testStepId":"11","body":"PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGNsYXNzPSJtbC0zIG1sLW1kLTAiIHZpZXdCb3g9IjAgMCA0MC41OSA0Ni4zMSIgd2lkdGg9IjQwLjU5IiBoZWlnaHQ9IjQ2LjMxIj4KICAgIDxnPgogICAgICAgIDxwYXRoIGZpbGw9IiMyM2Q5NmMiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZD0iTTMwLjI4MyAzLjY0NXEtLjUyOC0uMzE3LTEuMDgtLjU5M2ExNi4xNjQgMTYuMTY0IDAgMDAtMS4xNTQtLjUxOGMtLjEyNC0uMDUyLS4yNDctLjEtLjM3Mi0uMTQ5LS4zNDMtLjEyNy0uNjg5LS4yNjgtMS4wNDItLjM3MWExOS40MjcgMTkuNDI3IDAgMTAtOS43OTIgMzcuNTF2NS41NmMxMS42NzYtMS43NTMgMjIuMDE2LTEwLjk3OSAyMi43ODctMjMuMDkzLjQ1OS03LjI4OS0zLjE5My0xNC43My05LjM0Ny0xOC4zNDZ6Ii8+CiAgICAgICAgPHBhdGggZmlsbD0iIzE3MzY0NyIgZD0iTTE1Ljc4NyA0Ni4zMDd2LTUuOTM1QTIwLjQ3MiAyMC40NzIgMCAxMTI2Ljk1OSAxLjAxNWMuMjc0LjA4LjU1Ny4xODcuODMyLjI5MWwuMjQ4LjA5M2MuMTY1LjA2NC4yOTEuMTEzLjQxNy4xNjcuMzQ4LjEzNy43MzkuMzEzIDEuMjA4LjU0M3EuNTg5LjI5NSAxLjE1My42MzNjNi4zOTMgMy43NTYgMTAuMzU0IDExLjUxOCA5Ljg1NyAxOS4zMTYtLjc2MyAxMi0xMC43MjIgMjIuMTIyLTIzLjY3OSAyNC4wNjd6bTQuOC00NC4yMTRoLS4wMjZhMTguMzY2IDE4LjM2NiAwIDAwLTMuNTI0IDM2LjQwOGwuODUuMTY1djUuMThjMTEuMzkyLTIuMjI0IDIwLjAwOS0xMS4yNzIgMjAuNjg2LTIxLjkyMi40NDgtNy4wMzMtMy4xLTE0LjAxOC04LjgzLTE3LjM4M2wtLjAwOC0uMDA1QTE0LjY5MSAxNC42OTEgMCAwMDI3LjY1NCAzLjVhNS43NCA1Ljc0IDAgMDAtLjM0NC0uMTM4bC0uMjctLjFhOS40OSA5LjQ5IDAgMDAtLjcwOC0uMjQ5IDE4LjQyNSAxOC40MjUgMCAwMC01Ljc0My0uOTJ6Ii8+CiAgICAgICAgPHBhdGggZmlsbD0iIzE3MzY0NyIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMTYuNjY2IDEwLjU4YTEuOCAxLjggMCAwMTEuNTgzLjYwOCA0LjE4NCA0LjE4NCAwIDAxLjcyOCAxLjEwN2MuNjQ1IDEuNDIyIDEuMDI3IDMuNDYxLjIzIDQuNjA1YTYuMzM0IDYuMzM0IDAgMDEtMy45ODEtMy4wODcgMy4yMzYgMy4yMzYgMCAwMS0uMzQ3LTEuMzM5IDEuOTU3IDEuOTU3IDAgMDExLjc4Ny0xLjg5NHptLTUuNjgzIDguMDI1YTcuNzQyIDcuNzQyIDAgMDAxLjIxOC43MzcgNS43ODkgNS43ODkgMCAwMDQuODgzLS4xMzggNi4xMTYgNi4xMTYgMCAwMC0zLjM0NS0zLjQ1IDMuNjY0IDMuNjY0IDAgMDAtMS40NDItLjMyMSAxLjg4NCAxLjg4NCAwIDAwLS4zMTkgMCAxLjc2NiAxLjc2NiAwIDAwLS45OTUgMy4xNzJ6bTYuMSAzLjQzM2MtLjc3Ny0uNTE4LTIuMzc5LS4zMDktMy4zMTItLjI5MmE0LjQxNiA0LjQxNiAwIDAwLTEuNjY2LjM1MiAzLjUgMy41IDAgMDAtMS4yMTguNzM4IDEuODE3IDEuODE3IDAgMDAxLjQwOSAzLjE3MSAzLjMgMy4zIDAgMDAxLjQ0Mi0uMzIxYzEuNDM2LS42MiAzLjE0MS0yLjMyIDMuMzQ2LTMuNjQ4em0yLjYxIDJhNi41NTYgNi41NTYgMCAwMC0zLjcyNCAzLjUwNiAzLjA5MSAzLjA5MSAwIDAwLS4zMjEgMS4zMTQgMS45MDcgMS45MDcgMCAwMDMuMyAxLjM0NiA3LjQyMiA3LjQyMiAwIDAwLjctMS4yMThjLjYyMS0xLjMzMy44NjYtMy43Mi4wNDYtNC45NDh6bTIuNTU3LTcuMTY3YTUuOTQxIDUuOTQxIDAgMDAzLjctMy4xNjcgMy4yNDMgMy4yNDMgMCAwMC4zMTktMS4zNDYgMS45MTUgMS45MTUgMCAwMC0xLjc5NC0xLjk1NCAxLjgzMiAxLjgzMiAwIDAwLTEuNi42NDEgNy4zODIgNy4zODIgMCAwMC0uNzA1IDEuMjE4Yy0uNjIgMS40MzQtLjg0MiAzLjQ4LjA4MSA0LjYwM3ptNC4yMDggMTIuMTE1YTMuMjQ0IDMuMjQ0IDAgMDAtLjMyMS0xLjM0NSA1Ljg2OSA1Ljg2OSAwIDAwLTMuNTU0LTMuMjY5IDUuMzg2IDUuMzg2IDAgMDAtLjIyNiA0LjcxMSA0LjE0NyA0LjE0NyAwIDAwLjcgMS4xMjFjMS4xMzMgMS4yMyAzLjUwNS4zMiAzLjQwMi0xLjIxOHptNC4yLTYuMjhhNy40NjYgNy40NjYgMCAwMC0xLjIxNy0uNyA0LjQyNSA0LjQyNSAwIDAwLTEuNjY2LS4zNTIgNi40IDYuNCAwIDAwLTMuMTg4LjU1NSA1Ljk1OSA1Ljk1OSAwIDAwMy4zMTYgMy4zODYgMy42NzIgMy42NzIgMCAwMDEuNDQyLjMyIDEuOCAxLjggMCAwMDEuMzEtMy4yMDl6Ii8+CiAgICA8L2c+Cjwvc3ZnPg==","contentEncoding":"BASE64","mediaType":"image/svg+xml","timestamp":{"seconds":0,"nanos":8000000}}} +{"testStepFinished":{"testCaseStartedId":"12","testStepId":"11","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":9000000}}} +{"testCaseFinished":{"testCaseStartedId":"12","timestamp":{"seconds":0,"nanos":10000000},"willBeRetried":false}} +{"testRunFinished":{"testRunStartedId":"7","timestamp":{"seconds":0,"nanos":11000000},"success":true}} diff --git a/cucumber_cpp/acceptance_test/compatibility/hooks-conditional/hooks-conditional.feature b/cucumber_cpp/acceptance_test/compatibility/hooks-conditional/hooks-conditional.feature new file mode 100644 index 00000000..86aa9fb3 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/hooks-conditional/hooks-conditional.feature @@ -0,0 +1,16 @@ +Feature: Hooks - Conditional execution + Hooks are special steps that run before or after each scenario's steps. + + They can also conditionally target specific scenarios, using tag expressions. + + @fail-before + Scenario: A failure in the before hook and a skipped step + When a step passes + + @fail-after + Scenario: A failure in the after hook and a passed step + When a step passes + + @passing-hook + Scenario: With an tag, a passed step and hook + When a step passes diff --git a/cucumber_cpp/acceptance_test/compatibility/hooks-conditional/hooks-conditional.ndjson b/cucumber_cpp/acceptance_test/compatibility/hooks-conditional/hooks-conditional.ndjson new file mode 100644 index 00000000..54723f54 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/hooks-conditional/hooks-conditional.ndjson @@ -0,0 +1,36 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"Feature: Hooks - Conditional execution\n Hooks are special steps that run before or after each scenario's steps.\n\n They can also conditionally target specific scenarios, using tag expressions.\n\n @fail-before\n Scenario: A failure in the before hook and a skipped step\n When a step passes\n\n @fail-after\n Scenario: A failure in the after hook and a passed step\n When a step passes\n\n @passing-hook\n Scenario: With an tag, a passed step and hook\n When a step passes\n","uri":"samples/hooks-conditional/hooks-conditional.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Hooks - Conditional execution","description":" Hooks are special steps that run before or after each scenario's steps.\n\n They can also conditionally target specific scenarios, using tag expressions.","children":[{"scenario":{"id":"2","tags":[{"location":{"line":6,"column":3},"name":"@fail-before","id":"1"}],"location":{"line":7,"column":3},"keyword":"Scenario","name":"A failure in the before hook and a skipped step","description":"","steps":[{"id":"0","location":{"line":8,"column":5},"keyword":"When ","keywordType":"Action","text":"a step passes"}],"examples":[]}},{"scenario":{"id":"5","tags":[{"location":{"line":10,"column":3},"name":"@fail-after","id":"4"}],"location":{"line":11,"column":3},"keyword":"Scenario","name":"A failure in the after hook and a passed step","description":"","steps":[{"id":"3","location":{"line":12,"column":5},"keyword":"When ","keywordType":"Action","text":"a step passes"}],"examples":[]}},{"scenario":{"id":"8","tags":[{"location":{"line":14,"column":3},"name":"@passing-hook","id":"7"}],"location":{"line":15,"column":3},"keyword":"Scenario","name":"With an tag, a passed step and hook","description":"","steps":[{"id":"6","location":{"line":16,"column":5},"keyword":"When ","keywordType":"Action","text":"a step passes"}],"examples":[]}}]},"comments":[],"uri":"samples/hooks-conditional/hooks-conditional.feature"}} +{"pickle":{"id":"10","uri":"samples/hooks-conditional/hooks-conditional.feature","astNodeIds":["2"],"tags":[{"name":"@fail-before","astNodeId":"1"}],"name":"A failure in the before hook and a skipped step","language":"en","steps":[{"id":"9","text":"a step passes","type":"Action","astNodeIds":["0"]}]}} +{"pickle":{"id":"12","uri":"samples/hooks-conditional/hooks-conditional.feature","astNodeIds":["5"],"tags":[{"name":"@fail-after","astNodeId":"4"}],"name":"A failure in the after hook and a passed step","language":"en","steps":[{"id":"11","text":"a step passes","type":"Action","astNodeIds":["3"]}]}} +{"pickle":{"id":"14","uri":"samples/hooks-conditional/hooks-conditional.feature","astNodeIds":["8"],"tags":[{"name":"@passing-hook","astNodeId":"7"}],"name":"With an tag, a passed step and hook","language":"en","steps":[{"id":"13","text":"a step passes","type":"Action","astNodeIds":["6"]}]}} +{"stepDefinition":{"id":"17","pattern":{"type":"CUCUMBER_EXPRESSION","source":"a step passes"},"sourceReference":{"uri":"samples/hooks-conditional/hooks-conditional.ts","location":{"line":11}}}} +{"hook":{"id":"15","type":"BEFORE_TEST_CASE","tagExpression":"@passing-hook","sourceReference":{"uri":"samples/hooks-conditional/hooks-conditional.ts","location":{"line":3}}}} +{"hook":{"id":"16","type":"BEFORE_TEST_CASE","tagExpression":"@fail-before","sourceReference":{"uri":"samples/hooks-conditional/hooks-conditional.ts","location":{"line":7}}}} +{"hook":{"id":"18","type":"AFTER_TEST_CASE","tagExpression":"@fail-after","sourceReference":{"uri":"samples/hooks-conditional/hooks-conditional.ts","location":{"line":15}}}} +{"hook":{"id":"19","type":"AFTER_TEST_CASE","tagExpression":"@passing-hook","sourceReference":{"uri":"samples/hooks-conditional/hooks-conditional.ts","location":{"line":19}}}} +{"testRunStarted":{"id":"20","timestamp":{"seconds":0,"nanos":0}}} +{"testCase":{"id":"21","pickleId":"10","testSteps":[{"id":"22","hookId":"16"},{"id":"23","pickleStepId":"9","stepDefinitionIds":["17"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"20"}} +{"testCase":{"id":"24","pickleId":"12","testSteps":[{"id":"25","pickleStepId":"11","stepDefinitionIds":["17"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]},{"id":"26","hookId":"18"}],"testRunStartedId":"20"}} +{"testCase":{"id":"27","pickleId":"14","testSteps":[{"id":"28","hookId":"15"},{"id":"29","pickleStepId":"13","stepDefinitionIds":["17"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]},{"id":"30","hookId":"19"}],"testRunStartedId":"20"}} +{"testCaseStarted":{"id":"31","testCaseId":"21","timestamp":{"seconds":0,"nanos":1000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"31","testStepId":"22","timestamp":{"seconds":0,"nanos":2000000}}} +{"testStepFinished":{"testCaseStartedId":"31","testStepId":"22","testStepResult":{"message":"Exception in conditional hook","exception":{"type":"Error","message":"Exception in conditional hook","stackTrace":"Error: Exception in conditional hook\nsamples/hooks-conditional/hooks-conditional.feature:7"},"status":"FAILED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":3000000}}} +{"testStepStarted":{"testCaseStartedId":"31","testStepId":"23","timestamp":{"seconds":0,"nanos":4000000}}} +{"testStepFinished":{"testCaseStartedId":"31","testStepId":"23","testStepResult":{"status":"SKIPPED","duration":{"seconds":0,"nanos":0}},"timestamp":{"seconds":0,"nanos":5000000}}} +{"testCaseFinished":{"testCaseStartedId":"31","timestamp":{"seconds":0,"nanos":6000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"32","testCaseId":"24","timestamp":{"seconds":0,"nanos":7000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"32","testStepId":"25","timestamp":{"seconds":0,"nanos":8000000}}} +{"testStepFinished":{"testCaseStartedId":"32","testStepId":"25","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":9000000}}} +{"testStepStarted":{"testCaseStartedId":"32","testStepId":"26","timestamp":{"seconds":0,"nanos":10000000}}} +{"testStepFinished":{"testCaseStartedId":"32","testStepId":"26","testStepResult":{"message":"Exception in conditional hook","exception":{"type":"Error","message":"Exception in conditional hook","stackTrace":"Error: Exception in conditional hook\nsamples/hooks-conditional/hooks-conditional.feature:11"},"status":"FAILED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":11000000}}} +{"testCaseFinished":{"testCaseStartedId":"32","timestamp":{"seconds":0,"nanos":12000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"33","testCaseId":"27","timestamp":{"seconds":0,"nanos":13000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"33","testStepId":"28","timestamp":{"seconds":0,"nanos":14000000}}} +{"testStepFinished":{"testCaseStartedId":"33","testStepId":"28","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":15000000}}} +{"testStepStarted":{"testCaseStartedId":"33","testStepId":"29","timestamp":{"seconds":0,"nanos":16000000}}} +{"testStepFinished":{"testCaseStartedId":"33","testStepId":"29","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":17000000}}} +{"testStepStarted":{"testCaseStartedId":"33","testStepId":"30","timestamp":{"seconds":0,"nanos":18000000}}} +{"testStepFinished":{"testCaseStartedId":"33","testStepId":"30","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":19000000}}} +{"testCaseFinished":{"testCaseStartedId":"33","timestamp":{"seconds":0,"nanos":20000000},"willBeRetried":false}} +{"testRunFinished":{"testRunStartedId":"20","timestamp":{"seconds":0,"nanos":21000000},"success":false}} diff --git a/cucumber_cpp/acceptance_test/compatibility/hooks-named/hooks-named.feature b/cucumber_cpp/acceptance_test/compatibility/hooks-named/hooks-named.feature new file mode 100644 index 00000000..41007112 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/hooks-named/hooks-named.feature @@ -0,0 +1,8 @@ +Feature: Hooks - Named + Hooks are special steps that run before or after each scenario's steps. + + Hooks can be given a name. Which is nice for reporting. Otherwise they work + exactly the same as regular hooks. + + Scenario: With a named before and after hook + When a step passes diff --git a/cucumber_cpp/acceptance_test/compatibility/hooks-named/hooks-named.ndjson b/cucumber_cpp/acceptance_test/compatibility/hooks-named/hooks-named.ndjson new file mode 100644 index 00000000..84fff790 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/hooks-named/hooks-named.ndjson @@ -0,0 +1,18 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"Feature: Hooks - Named\n Hooks are special steps that run before or after each scenario's steps.\n\n Hooks can be given a name. Which is nice for reporting. Otherwise they work\n exactly the same as regular hooks.\n\n Scenario: With a named before and after hook\n When a step passes\n","uri":"samples/hooks-named/hooks-named.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Hooks - Named","description":" Hooks are special steps that run before or after each scenario's steps.\n\n Hooks can be given a name. Which is nice for reporting. Otherwise they work\n exactly the same as regular hooks.","children":[{"scenario":{"id":"1","tags":[],"location":{"line":7,"column":3},"keyword":"Scenario","name":"With a named before and after hook","description":"","steps":[{"id":"0","location":{"line":8,"column":5},"keyword":"When ","keywordType":"Action","text":"a step passes"}],"examples":[]}}]},"comments":[],"uri":"samples/hooks-named/hooks-named.feature"}} +{"pickle":{"id":"3","uri":"samples/hooks-named/hooks-named.feature","astNodeIds":["1"],"tags":[],"name":"With a named before and after hook","language":"en","steps":[{"id":"2","text":"a step passes","type":"Action","astNodeIds":["0"]}]}} +{"stepDefinition":{"id":"5","pattern":{"type":"CUCUMBER_EXPRESSION","source":"a step passes"},"sourceReference":{"uri":"samples/hooks-named/hooks-named.ts","location":{"line":7}}}} +{"hook":{"id":"4","type":"BEFORE_TEST_CASE","name":"A named before hook","sourceReference":{"uri":"samples/hooks-named/hooks-named.ts","location":{"line":3}}}} +{"hook":{"id":"6","type":"AFTER_TEST_CASE","name":"A named after hook","sourceReference":{"uri":"samples/hooks-named/hooks-named.ts","location":{"line":11}}}} +{"testRunStarted":{"id":"7","timestamp":{"seconds":0,"nanos":0}}} +{"testCase":{"id":"8","pickleId":"3","testSteps":[{"id":"9","hookId":"4"},{"id":"10","pickleStepId":"2","stepDefinitionIds":["5"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]},{"id":"11","hookId":"6"}],"testRunStartedId":"7"}} +{"testCaseStarted":{"id":"12","testCaseId":"8","timestamp":{"seconds":0,"nanos":1000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"12","testStepId":"9","timestamp":{"seconds":0,"nanos":2000000}}} +{"testStepFinished":{"testCaseStartedId":"12","testStepId":"9","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":3000000}}} +{"testStepStarted":{"testCaseStartedId":"12","testStepId":"10","timestamp":{"seconds":0,"nanos":4000000}}} +{"testStepFinished":{"testCaseStartedId":"12","testStepId":"10","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":5000000}}} +{"testStepStarted":{"testCaseStartedId":"12","testStepId":"11","timestamp":{"seconds":0,"nanos":6000000}}} +{"testStepFinished":{"testCaseStartedId":"12","testStepId":"11","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":7000000}}} +{"testCaseFinished":{"testCaseStartedId":"12","timestamp":{"seconds":0,"nanos":8000000},"willBeRetried":false}} +{"testRunFinished":{"testRunStartedId":"7","timestamp":{"seconds":0,"nanos":9000000},"success":true}} diff --git a/cucumber_cpp/acceptance_test/compatibility/hooks-undefined/hooks-undefined.feature b/cucumber_cpp/acceptance_test/compatibility/hooks-undefined/hooks-undefined.feature new file mode 100644 index 00000000..a13e450b --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/hooks-undefined/hooks-undefined.feature @@ -0,0 +1,5 @@ +Feature: Hooks - With Undefined Steps + Hooks also run before and after undefined steps + + Scenario: No tags and a undefined step + When a step does not exist diff --git a/cucumber_cpp/acceptance_test/compatibility/hooks-undefined/hooks-undefined.ndjson b/cucumber_cpp/acceptance_test/compatibility/hooks-undefined/hooks-undefined.ndjson new file mode 100644 index 00000000..4d90c89f --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/hooks-undefined/hooks-undefined.ndjson @@ -0,0 +1,18 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"Feature: Hooks - With Undefined Steps\n Hooks also run before and after undefined steps\n\n Scenario: No tags and a undefined step\n When a step does not exist\n","uri":"samples/hooks-undefined/hooks-undefined.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Hooks - With Undefined Steps","description":" Hooks also run before and after undefined steps","children":[{"scenario":{"id":"1","tags":[],"location":{"line":4,"column":3},"keyword":"Scenario","name":"No tags and a undefined step","description":"","steps":[{"id":"0","location":{"line":5,"column":5},"keyword":"When ","keywordType":"Action","text":"a step does not exist"}],"examples":[]}}]},"comments":[],"uri":"samples/hooks-undefined/hooks-undefined.feature"}} +{"pickle":{"id":"3","uri":"samples/hooks-undefined/hooks-undefined.feature","astNodeIds":["1"],"tags":[],"name":"No tags and a undefined step","language":"en","steps":[{"id":"2","text":"a step does not exist","type":"Action","astNodeIds":["0"]}]}} +{"hook":{"id":"4","type":"BEFORE_TEST_CASE","sourceReference":{"uri":"samples/hooks-undefined/hooks-undefined.ts","location":{"line":3}}}} +{"hook":{"id":"5","type":"AFTER_TEST_CASE","sourceReference":{"uri":"samples/hooks-undefined/hooks-undefined.ts","location":{"line":7}}}} +{"testRunStarted":{"id":"6","timestamp":{"seconds":0,"nanos":0}}} +{"testCase":{"id":"7","pickleId":"3","testSteps":[{"id":"8","hookId":"4"},{"id":"9","pickleStepId":"2","stepDefinitionIds":[],"stepMatchArgumentsLists":[]},{"id":"10","hookId":"5"}],"testRunStartedId":"6"}} +{"testCaseStarted":{"id":"11","testCaseId":"7","timestamp":{"seconds":0,"nanos":1000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"11","testStepId":"8","timestamp":{"seconds":0,"nanos":2000000}}} +{"testStepFinished":{"testCaseStartedId":"11","testStepId":"8","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":3000000}}} +{"testStepStarted":{"testCaseStartedId":"11","testStepId":"9","timestamp":{"seconds":0,"nanos":4000000}}} +{"suggestion":{"id":"12","pickleStepId":"2","snippets":[{"language":"typescript","code":"When(\"a step does not exist\", () => {\n return \"pending\"\n})"}]}} +{"testStepFinished":{"testCaseStartedId":"11","testStepId":"9","testStepResult":{"status":"UNDEFINED","duration":{"seconds":0,"nanos":0}},"timestamp":{"seconds":0,"nanos":5000000}}} +{"testStepStarted":{"testCaseStartedId":"11","testStepId":"10","timestamp":{"seconds":0,"nanos":6000000}}} +{"testStepFinished":{"testCaseStartedId":"11","testStepId":"10","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":7000000}}} +{"testCaseFinished":{"testCaseStartedId":"11","timestamp":{"seconds":0,"nanos":8000000},"willBeRetried":false}} +{"testRunFinished":{"testRunStartedId":"6","timestamp":{"seconds":0,"nanos":9000000},"success":false}} diff --git a/cucumber_cpp/acceptance_test/compatibility/hooks/hooks.feature b/cucumber_cpp/acceptance_test/compatibility/hooks/hooks.feature new file mode 100644 index 00000000..5a29a802 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/hooks/hooks.feature @@ -0,0 +1,8 @@ +Feature: Hooks + Hooks are special steps that run before or after each scenario's steps. + + Scenario: No tags and a passed step + When a step passes + + Scenario: No tags and a failed step + When a step fails diff --git a/cucumber_cpp/acceptance_test/compatibility/hooks/hooks.ndjson b/cucumber_cpp/acceptance_test/compatibility/hooks/hooks.ndjson new file mode 100644 index 00000000..c99fa75c --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/hooks/hooks.ndjson @@ -0,0 +1,29 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"Feature: Hooks\n Hooks are special steps that run before or after each scenario's steps.\n\n Scenario: No tags and a passed step\n When a step passes\n\n Scenario: No tags and a failed step\n When a step fails\n","uri":"samples/hooks/hooks.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Hooks","description":" Hooks are special steps that run before or after each scenario's steps.","children":[{"scenario":{"id":"1","tags":[],"location":{"line":4,"column":3},"keyword":"Scenario","name":"No tags and a passed step","description":"","steps":[{"id":"0","location":{"line":5,"column":5},"keyword":"When ","keywordType":"Action","text":"a step passes"}],"examples":[]}},{"scenario":{"id":"3","tags":[],"location":{"line":7,"column":3},"keyword":"Scenario","name":"No tags and a failed step","description":"","steps":[{"id":"2","location":{"line":8,"column":5},"keyword":"When ","keywordType":"Action","text":"a step fails"}],"examples":[]}}]},"comments":[],"uri":"samples/hooks/hooks.feature"}} +{"pickle":{"id":"5","uri":"samples/hooks/hooks.feature","astNodeIds":["1"],"tags":[],"name":"No tags and a passed step","language":"en","steps":[{"id":"4","text":"a step passes","type":"Action","astNodeIds":["0"]}]}} +{"pickle":{"id":"7","uri":"samples/hooks/hooks.feature","astNodeIds":["3"],"tags":[],"name":"No tags and a failed step","language":"en","steps":[{"id":"6","text":"a step fails","type":"Action","astNodeIds":["2"]}]}} +{"stepDefinition":{"id":"9","pattern":{"type":"CUCUMBER_EXPRESSION","source":"a step passes"},"sourceReference":{"uri":"samples/hooks/hooks.ts","location":{"line":7}}}} +{"stepDefinition":{"id":"10","pattern":{"type":"CUCUMBER_EXPRESSION","source":"a step fails"},"sourceReference":{"uri":"samples/hooks/hooks.ts","location":{"line":11}}}} +{"hook":{"id":"8","type":"BEFORE_TEST_CASE","sourceReference":{"uri":"samples/hooks/hooks.ts","location":{"line":3}}}} +{"hook":{"id":"11","type":"AFTER_TEST_CASE","sourceReference":{"uri":"samples/hooks/hooks.ts","location":{"line":15}}}} +{"testRunStarted":{"id":"12","timestamp":{"seconds":0,"nanos":0}}} +{"testCase":{"id":"13","pickleId":"5","testSteps":[{"id":"14","hookId":"8"},{"id":"15","pickleStepId":"4","stepDefinitionIds":["9"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]},{"id":"16","hookId":"11"}],"testRunStartedId":"12"}} +{"testCase":{"id":"17","pickleId":"7","testSteps":[{"id":"18","hookId":"8"},{"id":"19","pickleStepId":"6","stepDefinitionIds":["10"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]},{"id":"20","hookId":"11"}],"testRunStartedId":"12"}} +{"testCaseStarted":{"id":"21","testCaseId":"13","timestamp":{"seconds":0,"nanos":1000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"21","testStepId":"14","timestamp":{"seconds":0,"nanos":2000000}}} +{"testStepFinished":{"testCaseStartedId":"21","testStepId":"14","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":3000000}}} +{"testStepStarted":{"testCaseStartedId":"21","testStepId":"15","timestamp":{"seconds":0,"nanos":4000000}}} +{"testStepFinished":{"testCaseStartedId":"21","testStepId":"15","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":5000000}}} +{"testStepStarted":{"testCaseStartedId":"21","testStepId":"16","timestamp":{"seconds":0,"nanos":6000000}}} +{"testStepFinished":{"testCaseStartedId":"21","testStepId":"16","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":7000000}}} +{"testCaseFinished":{"testCaseStartedId":"21","timestamp":{"seconds":0,"nanos":8000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"22","testCaseId":"17","timestamp":{"seconds":0,"nanos":9000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"22","testStepId":"18","timestamp":{"seconds":0,"nanos":10000000}}} +{"testStepFinished":{"testCaseStartedId":"22","testStepId":"18","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":11000000}}} +{"testStepStarted":{"testCaseStartedId":"22","testStepId":"19","timestamp":{"seconds":0,"nanos":12000000}}} +{"testStepFinished":{"testCaseStartedId":"22","testStepId":"19","testStepResult":{"message":"Exception in step","exception":{"type":"Error","message":"Exception in step","stackTrace":"Error: Exception in step\nsamples/hooks/hooks.feature:8"},"status":"FAILED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":13000000}}} +{"testStepStarted":{"testCaseStartedId":"22","testStepId":"20","timestamp":{"seconds":0,"nanos":14000000}}} +{"testStepFinished":{"testCaseStartedId":"22","testStepId":"20","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":15000000}}} +{"testCaseFinished":{"testCaseStartedId":"22","timestamp":{"seconds":0,"nanos":16000000},"willBeRetried":false}} +{"testRunFinished":{"testRunStartedId":"12","timestamp":{"seconds":0,"nanos":17000000},"success":false}} diff --git a/cucumber_cpp/acceptance_test/compatibility/markdown/markdown.feature.md b/cucumber_cpp/acceptance_test/compatibility/markdown/markdown.feature.md new file mode 100644 index 00000000..e0cdec5b --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/markdown/markdown.feature.md @@ -0,0 +1,46 @@ +# Feature: Cheese + +This table is not picked up by Gherkin (not indented 2+ spaces) + +| foo | bar | +| --- | --- | +| boz | boo | + + +## Rule: Nom nom nom + +I love cheese, especially fromage macaroni cheese. Rubber cheese ricotta caerphilly blue castello who moved my cheese queso bavarian bergkase melted cheese. + +### Scenario Outline: Ylajali! + +* Given some TypeScript code: + ```typescript + type Cheese = 'reblochon' | 'roquefort' | 'rocamadour' + ``` +* And some classic Gherkin: + ```gherkin + Given there are 24 apples in Mary's basket + ``` +* When we use a data table and attach something and then + | name | age | + | ---- | --: | + | Bill | 3 | + | Jane | 6 | + | Isla | 5 | +* Then this might or might not run + +#### Examples: because we need more tables + +This table is indented 2 spaces, so Gherkin will pick it up + + | what | + | ---- | + | fail | + | pass | + +And oh by the way, this table is also ignored by Gherkin because it doesn't have 2+ space indent: + +| cheese | +| -------- | +| gouda | +| gamalost | diff --git a/cucumber_cpp/acceptance_test/compatibility/markdown/markdown.ndjson b/cucumber_cpp/acceptance_test/compatibility/markdown/markdown.ndjson new file mode 100644 index 00000000..78a92b18 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/markdown/markdown.ndjson @@ -0,0 +1,35 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"# Feature: Cheese\n\nThis table is not picked up by Gherkin (not indented 2+ spaces)\n\n| foo | bar |\n| --- | --- |\n| boz | boo |\n\n\n## Rule: Nom nom nom\n\nI love cheese, especially fromage macaroni cheese. Rubber cheese ricotta caerphilly blue castello who moved my cheese queso bavarian bergkase melted cheese.\n\n### Scenario Outline: Ylajali!\n\n* Given some TypeScript code:\n ```typescript\n type Cheese = 'reblochon' | 'roquefort' | 'rocamadour'\n ```\n* And some classic Gherkin:\n ```gherkin\n Given there are 24 apples in Mary's basket\n ```\n* When we use a data table and attach something and then \n | name | age |\n | ---- | --: |\n | Bill | 3 |\n | Jane | 6 |\n | Isla | 5 |\n* Then this might or might not run\n\n#### Examples: because we need more tables\n\nThis table is indented 2 spaces, so Gherkin will pick it up\n\n | what |\n | ---- |\n | fail |\n | pass |\n\nAnd oh by the way, this table is also ignored by Gherkin because it doesn't have 2+ space indent:\n\n| cheese |\n| -------- |\n| gouda |\n| gamalost |\n","uri":"samples/markdown/markdown.feature.md","mediaType":"text/x.cucumber.gherkin+markdown"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":3},"language":"en","keyword":"Feature","name":"Cheese","description":"| boz | boo |","children":[{"rule":{"id":"13","location":{"line":10,"column":4},"keyword":"Rule","name":"Nom nom nom","description":"","children":[{"scenario":{"id":"12","tags":[],"location":{"line":14,"column":5},"keyword":"Scenario Outline","name":"Ylajali!","description":"","steps":[{"id":"0","location":{"line":16,"column":3},"keyword":"Given ","keywordType":"Context","text":"some TypeScript code:","docString":{"location":{"line":17,"column":3},"content":"type Cheese = 'reblochon' | 'roquefort' | 'rocamadour'","delimiter":"```","mediaType":"typescript"}},{"id":"1","location":{"line":20,"column":3},"keyword":"And ","keywordType":"Conjunction","text":"some classic Gherkin:","docString":{"location":{"line":21,"column":3},"content":"Given there are 24 apples in Mary's basket","delimiter":"```","mediaType":"gherkin"}},{"id":"6","location":{"line":24,"column":3},"keyword":"When ","keywordType":"Action","text":"we use a data table and attach something and then ","dataTable":{"location":{"line":25,"column":3},"rows":[{"id":"2","location":{"line":25,"column":3},"cells":[{"location":{"line":25,"column":5},"value":"name"},{"location":{"line":25,"column":12},"value":"age"}]},{"id":"3","location":{"line":27,"column":3},"cells":[{"location":{"line":27,"column":5},"value":"Bill"},{"location":{"line":27,"column":14},"value":"3"}]},{"id":"4","location":{"line":28,"column":3},"cells":[{"location":{"line":28,"column":5},"value":"Jane"},{"location":{"line":28,"column":14},"value":"6"}]},{"id":"5","location":{"line":29,"column":3},"cells":[{"location":{"line":29,"column":5},"value":"Isla"},{"location":{"line":29,"column":14},"value":"5"}]}]}},{"id":"7","location":{"line":30,"column":3},"keyword":"Then ","keywordType":"Outcome","text":"this might or might not run"}],"examples":[{"id":"11","tags":[],"location":{"line":32,"column":6},"keyword":"Examples","name":"because we need more tables","description":"","tableHeader":{"id":"8","location":{"line":36,"column":3},"cells":[{"location":{"line":36,"column":5},"value":"what"}]},"tableBody":[{"id":"9","location":{"line":38,"column":3},"cells":[{"location":{"line":38,"column":5},"value":"fail"}]},{"id":"10","location":{"line":39,"column":3},"cells":[{"location":{"line":39,"column":5},"value":"pass"}]}]}]}}],"tags":[]}}]},"comments":[],"uri":"samples/markdown/markdown.feature.md"}} +{"pickle":{"id":"18","uri":"samples/markdown/markdown.feature.md","astNodeIds":["12","9"],"name":"Ylajali!","language":"en","steps":[{"id":"14","text":"some TypeScript code:","type":"Context","argument":{"docString":{"content":"type Cheese = 'reblochon' | 'roquefort' | 'rocamadour'","mediaType":"typescript"}},"astNodeIds":["0","9"]},{"id":"15","text":"some classic Gherkin:","type":"Context","argument":{"docString":{"content":"Given there are 24 apples in Mary's basket","mediaType":"gherkin"}},"astNodeIds":["1","9"]},{"id":"16","text":"we use a data table and attach something and then fail","type":"Action","argument":{"dataTable":{"rows":[{"cells":[{"value":"name"},{"value":"age"}]},{"cells":[{"value":"Bill"},{"value":"3"}]},{"cells":[{"value":"Jane"},{"value":"6"}]},{"cells":[{"value":"Isla"},{"value":"5"}]}]}},"astNodeIds":["6","9"]},{"id":"17","text":"this might or might not run","type":"Outcome","astNodeIds":["7","9"]}],"tags":[]}} +{"pickle":{"id":"23","uri":"samples/markdown/markdown.feature.md","astNodeIds":["12","10"],"name":"Ylajali!","language":"en","steps":[{"id":"19","text":"some TypeScript code:","type":"Context","argument":{"docString":{"content":"type Cheese = 'reblochon' | 'roquefort' | 'rocamadour'","mediaType":"typescript"}},"astNodeIds":["0","10"]},{"id":"20","text":"some classic Gherkin:","type":"Context","argument":{"docString":{"content":"Given there are 24 apples in Mary's basket","mediaType":"gherkin"}},"astNodeIds":["1","10"]},{"id":"21","text":"we use a data table and attach something and then pass","type":"Action","argument":{"dataTable":{"rows":[{"cells":[{"value":"name"},{"value":"age"}]},{"cells":[{"value":"Bill"},{"value":"3"}]},{"cells":[{"value":"Jane"},{"value":"6"}]},{"cells":[{"value":"Isla"},{"value":"5"}]}]}},"astNodeIds":["6","10"]},{"id":"22","text":"this might or might not run","type":"Outcome","astNodeIds":["7","10"]}],"tags":[]}} +{"stepDefinition":{"id":"24","pattern":{"type":"CUCUMBER_EXPRESSION","source":"some TypeScript code:"},"sourceReference":{"uri":"samples/markdown/markdown.ts","location":{"line":4}}}} +{"stepDefinition":{"id":"25","pattern":{"type":"CUCUMBER_EXPRESSION","source":"some classic Gherkin:"},"sourceReference":{"uri":"samples/markdown/markdown.ts","location":{"line":8}}}} +{"stepDefinition":{"id":"26","pattern":{"type":"CUCUMBER_EXPRESSION","source":"we use a data table and attach something and then {word}"},"sourceReference":{"uri":"samples/markdown/markdown.ts","location":{"line":12}}}} +{"stepDefinition":{"id":"27","pattern":{"type":"CUCUMBER_EXPRESSION","source":"this might or might not run"},"sourceReference":{"uri":"samples/markdown/markdown.ts","location":{"line":23}}}} +{"testRunStarted":{"id":"28","timestamp":{"seconds":0,"nanos":0}}} +{"testCase":{"id":"29","pickleId":"18","testSteps":[{"id":"30","pickleStepId":"14","stepDefinitionIds":["24"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]},{"id":"31","pickleStepId":"15","stepDefinitionIds":["25"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]},{"id":"32","pickleStepId":"16","stepDefinitionIds":["26"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":50,"value":"fail","children":[]},"parameterTypeName":"word"}]}]},{"id":"33","pickleStepId":"17","stepDefinitionIds":["27"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"28"}} +{"testCase":{"id":"34","pickleId":"23","testSteps":[{"id":"35","pickleStepId":"19","stepDefinitionIds":["24"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]},{"id":"36","pickleStepId":"20","stepDefinitionIds":["25"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]},{"id":"37","pickleStepId":"21","stepDefinitionIds":["26"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":50,"value":"pass","children":[]},"parameterTypeName":"word"}]}]},{"id":"38","pickleStepId":"22","stepDefinitionIds":["27"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"28"}} +{"testCaseStarted":{"id":"39","testCaseId":"29","timestamp":{"seconds":0,"nanos":1000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"39","testStepId":"30","timestamp":{"seconds":0,"nanos":2000000}}} +{"testStepFinished":{"testCaseStartedId":"39","testStepId":"30","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":3000000}}} +{"testStepStarted":{"testCaseStartedId":"39","testStepId":"31","timestamp":{"seconds":0,"nanos":4000000}}} +{"testStepFinished":{"testCaseStartedId":"39","testStepId":"31","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":5000000}}} +{"testStepStarted":{"testCaseStartedId":"39","testStepId":"32","timestamp":{"seconds":0,"nanos":6000000}}} +{"attachment":{"testCaseStartedId":"39","testStepId":"32","body":"We are logging some plain text (fail)","contentEncoding":"IDENTITY","mediaType":"text/x.cucumber.log+plain","timestamp":{"seconds":0,"nanos":7000000}}} +{"testStepFinished":{"testCaseStartedId":"39","testStepId":"32","testStepResult":{"message":"You asked me to fail","exception":{"type":"Error","message":"You asked me to fail","stackTrace":"Error: You asked me to fail\nsamples/markdown/markdown.feature.md:24"},"status":"FAILED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":8000000}}} +{"testStepStarted":{"testCaseStartedId":"39","testStepId":"33","timestamp":{"seconds":0,"nanos":9000000}}} +{"testStepFinished":{"testCaseStartedId":"39","testStepId":"33","testStepResult":{"status":"SKIPPED","duration":{"seconds":0,"nanos":0}},"timestamp":{"seconds":0,"nanos":10000000}}} +{"testCaseFinished":{"testCaseStartedId":"39","timestamp":{"seconds":0,"nanos":11000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"40","testCaseId":"34","timestamp":{"seconds":0,"nanos":12000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"40","testStepId":"35","timestamp":{"seconds":0,"nanos":13000000}}} +{"testStepFinished":{"testCaseStartedId":"40","testStepId":"35","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":14000000}}} +{"testStepStarted":{"testCaseStartedId":"40","testStepId":"36","timestamp":{"seconds":0,"nanos":15000000}}} +{"testStepFinished":{"testCaseStartedId":"40","testStepId":"36","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":16000000}}} +{"testStepStarted":{"testCaseStartedId":"40","testStepId":"37","timestamp":{"seconds":0,"nanos":17000000}}} +{"attachment":{"testCaseStartedId":"40","testStepId":"37","body":"We are logging some plain text (pass)","contentEncoding":"IDENTITY","mediaType":"text/x.cucumber.log+plain","timestamp":{"seconds":0,"nanos":18000000}}} +{"testStepFinished":{"testCaseStartedId":"40","testStepId":"37","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":19000000}}} +{"testStepStarted":{"testCaseStartedId":"40","testStepId":"38","timestamp":{"seconds":0,"nanos":20000000}}} +{"testStepFinished":{"testCaseStartedId":"40","testStepId":"38","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":21000000}}} +{"testCaseFinished":{"testCaseStartedId":"40","timestamp":{"seconds":0,"nanos":22000000},"willBeRetried":false}} +{"testRunFinished":{"testRunStartedId":"28","timestamp":{"seconds":0,"nanos":23000000},"success":false}} diff --git a/cucumber_cpp/acceptance_test/compatibility/minimal/minimal.feature b/cucumber_cpp/acceptance_test/compatibility/minimal/minimal.feature new file mode 100644 index 00000000..158fde29 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/minimal/minimal.feature @@ -0,0 +1,10 @@ +Feature: minimal + + Cucumber doesn't execute this markdown, but @cucumber/react renders it. + + * This is + * a bullet + * list + + Scenario: cukes + Given I have 42 cukes in my belly diff --git a/cucumber_cpp/acceptance_test/compatibility/minimal/minimal.ndjson b/cucumber_cpp/acceptance_test/compatibility/minimal/minimal.ndjson new file mode 100644 index 00000000..dc5f1704 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/minimal/minimal.ndjson @@ -0,0 +1,12 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"Feature: minimal\n \n Cucumber doesn't execute this markdown, but @cucumber/react renders it.\n \n * This is\n * a bullet\n * list\n \n Scenario: cukes\n Given I have 42 cukes in my belly\n","uri":"samples/minimal/minimal.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"minimal","description":" Cucumber doesn't execute this markdown, but @cucumber/react renders it.\n \n * This is\n * a bullet\n * list","children":[{"scenario":{"id":"1","tags":[],"location":{"line":9,"column":3},"keyword":"Scenario","name":"cukes","description":"","steps":[{"id":"0","location":{"line":10,"column":5},"keyword":"Given ","keywordType":"Context","text":"I have 42 cukes in my belly"}],"examples":[]}}]},"comments":[],"uri":"samples/minimal/minimal.feature"}} +{"pickle":{"id":"3","uri":"samples/minimal/minimal.feature","astNodeIds":["1"],"tags":[],"name":"cukes","language":"en","steps":[{"id":"2","text":"I have 42 cukes in my belly","type":"Context","astNodeIds":["0"]}]}} +{"stepDefinition":{"id":"4","pattern":{"type":"CUCUMBER_EXPRESSION","source":"I have {int} cukes in my belly"},"sourceReference":{"uri":"samples/minimal/minimal.ts","location":{"line":3}}}} +{"testRunStarted":{"id":"5","timestamp":{"seconds":0,"nanos":0}}} +{"testCase":{"id":"6","pickleId":"3","testSteps":[{"id":"7","pickleStepId":"2","stepDefinitionIds":["4"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":7,"value":"42","children":[]},"parameterTypeName":"int"}]}]}],"testRunStartedId":"5"}} +{"testCaseStarted":{"id":"8","testCaseId":"6","timestamp":{"seconds":0,"nanos":1000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"8","testStepId":"7","timestamp":{"seconds":0,"nanos":2000000}}} +{"testStepFinished":{"testCaseStartedId":"8","testStepId":"7","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":3000000}}} +{"testCaseFinished":{"testCaseStartedId":"8","timestamp":{"seconds":0,"nanos":4000000},"willBeRetried":false}} +{"testRunFinished":{"testRunStartedId":"5","timestamp":{"seconds":0,"nanos":5000000},"success":true}} diff --git a/cucumber_cpp/acceptance_test/compatibility/multiple-features-reversed/multiple-features-reversed-1.feature b/cucumber_cpp/acceptance_test/compatibility/multiple-features-reversed/multiple-features-reversed-1.feature new file mode 100644 index 00000000..faf03eee --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/multiple-features-reversed/multiple-features-reversed-1.feature @@ -0,0 +1,10 @@ +Feature: First feature + + Scenario: First scenario + Given an order for "eggs" + + Scenario: Second scenario + Given an order for "milk" + + Scenario: Third scenario + Given an order for "bread" \ No newline at end of file diff --git a/cucumber_cpp/acceptance_test/compatibility/multiple-features-reversed/multiple-features-reversed-2.feature b/cucumber_cpp/acceptance_test/compatibility/multiple-features-reversed/multiple-features-reversed-2.feature new file mode 100644 index 00000000..0b0f7569 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/multiple-features-reversed/multiple-features-reversed-2.feature @@ -0,0 +1,10 @@ +Feature: Second feature + + Scenario: First scenario + Given an order for "batteries" + + Scenario: Second scenario + Given an order for "light bulbs" + + Scenario: Third scenario + Given an order for "fuses" \ No newline at end of file diff --git a/cucumber_cpp/acceptance_test/compatibility/multiple-features-reversed/multiple-features-reversed-3.feature b/cucumber_cpp/acceptance_test/compatibility/multiple-features-reversed/multiple-features-reversed-3.feature new file mode 100644 index 00000000..4c306c6c --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/multiple-features-reversed/multiple-features-reversed-3.feature @@ -0,0 +1,10 @@ +Feature: Third feature + + Scenario: First scenario + Given an order for "pencils" + + Scenario: Second scenario + Given an order for "rulers" + + Scenario: Third scenario + Given an order for "paperclips" \ No newline at end of file diff --git a/cucumber_cpp/acceptance_test/compatibility/multiple-features-reversed/multiple-features-reversed.arguments.txt b/cucumber_cpp/acceptance_test/compatibility/multiple-features-reversed/multiple-features-reversed.arguments.txt new file mode 100644 index 00000000..97072c0c --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/multiple-features-reversed/multiple-features-reversed.arguments.txt @@ -0,0 +1 @@ +--order reverse diff --git a/cucumber_cpp/acceptance_test/compatibility/multiple-features-reversed/multiple-features-reversed.ndjson b/cucumber_cpp/acceptance_test/compatibility/multiple-features-reversed/multiple-features-reversed.ndjson new file mode 100644 index 00000000..6abdaead --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/multiple-features-reversed/multiple-features-reversed.ndjson @@ -0,0 +1,64 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"Feature: First feature\n\n Scenario: First scenario\n Given an order for \"eggs\"\n\n Scenario: Second scenario\n Given an order for \"milk\"\n\n Scenario: Third scenario\n Given an order for \"bread\"","uri":"samples/multiple-features-reversed/multiple-features-reversed-1.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"First feature","description":"","children":[{"scenario":{"id":"1","tags":[],"location":{"line":3,"column":3},"keyword":"Scenario","name":"First scenario","description":"","steps":[{"id":"0","location":{"line":4,"column":5},"keyword":"Given ","keywordType":"Context","text":"an order for \"eggs\""}],"examples":[]}},{"scenario":{"id":"3","tags":[],"location":{"line":6,"column":3},"keyword":"Scenario","name":"Second scenario","description":"","steps":[{"id":"2","location":{"line":7,"column":5},"keyword":"Given ","keywordType":"Context","text":"an order for \"milk\""}],"examples":[]}},{"scenario":{"id":"5","tags":[],"location":{"line":9,"column":3},"keyword":"Scenario","name":"Third scenario","description":"","steps":[{"id":"4","location":{"line":10,"column":5},"keyword":"Given ","keywordType":"Context","text":"an order for \"bread\""}],"examples":[]}}]},"comments":[],"uri":"samples/multiple-features-reversed/multiple-features-reversed-1.feature"}} +{"pickle":{"id":"7","uri":"samples/multiple-features-reversed/multiple-features-reversed-1.feature","astNodeIds":["1"],"tags":[],"name":"First scenario","language":"en","steps":[{"id":"6","text":"an order for \"eggs\"","type":"Context","astNodeIds":["0"]}]}} +{"pickle":{"id":"9","uri":"samples/multiple-features-reversed/multiple-features-reversed-1.feature","astNodeIds":["3"],"tags":[],"name":"Second scenario","language":"en","steps":[{"id":"8","text":"an order for \"milk\"","type":"Context","astNodeIds":["2"]}]}} +{"pickle":{"id":"11","uri":"samples/multiple-features-reversed/multiple-features-reversed-1.feature","astNodeIds":["5"],"tags":[],"name":"Third scenario","language":"en","steps":[{"id":"10","text":"an order for \"bread\"","type":"Context","astNodeIds":["4"]}]}} +{"source":{"data":"Feature: Second feature\n\n Scenario: First scenario\n Given an order for \"batteries\"\n\n Scenario: Second scenario\n Given an order for \"light bulbs\"\n\n Scenario: Third scenario\n Given an order for \"fuses\"","uri":"samples/multiple-features-reversed/multiple-features-reversed-2.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Second feature","description":"","children":[{"scenario":{"id":"13","tags":[],"location":{"line":3,"column":3},"keyword":"Scenario","name":"First scenario","description":"","steps":[{"id":"12","location":{"line":4,"column":5},"keyword":"Given ","keywordType":"Context","text":"an order for \"batteries\""}],"examples":[]}},{"scenario":{"id":"15","tags":[],"location":{"line":6,"column":3},"keyword":"Scenario","name":"Second scenario","description":"","steps":[{"id":"14","location":{"line":7,"column":5},"keyword":"Given ","keywordType":"Context","text":"an order for \"light bulbs\""}],"examples":[]}},{"scenario":{"id":"17","tags":[],"location":{"line":9,"column":3},"keyword":"Scenario","name":"Third scenario","description":"","steps":[{"id":"16","location":{"line":10,"column":5},"keyword":"Given ","keywordType":"Context","text":"an order for \"fuses\""}],"examples":[]}}]},"comments":[],"uri":"samples/multiple-features-reversed/multiple-features-reversed-2.feature"}} +{"pickle":{"id":"19","uri":"samples/multiple-features-reversed/multiple-features-reversed-2.feature","astNodeIds":["13"],"tags":[],"name":"First scenario","language":"en","steps":[{"id":"18","text":"an order for \"batteries\"","type":"Context","astNodeIds":["12"]}]}} +{"pickle":{"id":"21","uri":"samples/multiple-features-reversed/multiple-features-reversed-2.feature","astNodeIds":["15"],"tags":[],"name":"Second scenario","language":"en","steps":[{"id":"20","text":"an order for \"light bulbs\"","type":"Context","astNodeIds":["14"]}]}} +{"pickle":{"id":"23","uri":"samples/multiple-features-reversed/multiple-features-reversed-2.feature","astNodeIds":["17"],"tags":[],"name":"Third scenario","language":"en","steps":[{"id":"22","text":"an order for \"fuses\"","type":"Context","astNodeIds":["16"]}]}} +{"source":{"data":"Feature: Third feature\n\n Scenario: First scenario\n Given an order for \"pencils\"\n\n Scenario: Second scenario\n Given an order for \"rulers\"\n\n Scenario: Third scenario\n Given an order for \"paperclips\"","uri":"samples/multiple-features-reversed/multiple-features-reversed-3.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Third feature","description":"","children":[{"scenario":{"id":"25","tags":[],"location":{"line":3,"column":3},"keyword":"Scenario","name":"First scenario","description":"","steps":[{"id":"24","location":{"line":4,"column":5},"keyword":"Given ","keywordType":"Context","text":"an order for \"pencils\""}],"examples":[]}},{"scenario":{"id":"27","tags":[],"location":{"line":6,"column":3},"keyword":"Scenario","name":"Second scenario","description":"","steps":[{"id":"26","location":{"line":7,"column":5},"keyword":"Given ","keywordType":"Context","text":"an order for \"rulers\""}],"examples":[]}},{"scenario":{"id":"29","tags":[],"location":{"line":9,"column":3},"keyword":"Scenario","name":"Third scenario","description":"","steps":[{"id":"28","location":{"line":10,"column":5},"keyword":"Given ","keywordType":"Context","text":"an order for \"paperclips\""}],"examples":[]}}]},"comments":[],"uri":"samples/multiple-features-reversed/multiple-features-reversed-3.feature"}} +{"pickle":{"id":"31","uri":"samples/multiple-features-reversed/multiple-features-reversed-3.feature","astNodeIds":["25"],"tags":[],"name":"First scenario","language":"en","steps":[{"id":"30","text":"an order for \"pencils\"","type":"Context","astNodeIds":["24"]}]}} +{"pickle":{"id":"33","uri":"samples/multiple-features-reversed/multiple-features-reversed-3.feature","astNodeIds":["27"],"tags":[],"name":"Second scenario","language":"en","steps":[{"id":"32","text":"an order for \"rulers\"","type":"Context","astNodeIds":["26"]}]}} +{"pickle":{"id":"35","uri":"samples/multiple-features-reversed/multiple-features-reversed-3.feature","astNodeIds":["29"],"tags":[],"name":"Third scenario","language":"en","steps":[{"id":"34","text":"an order for \"paperclips\"","type":"Context","astNodeIds":["28"]}]}} +{"stepDefinition":{"id":"36","pattern":{"type":"CUCUMBER_EXPRESSION","source":"an order for {string}"},"sourceReference":{"uri":"samples/multiple-features-reversed/multiple-features-reversed.ts","location":{"line":3}}}} +{"testRunStarted":{"id":"37","timestamp":{"seconds":0,"nanos":0}}} +{"testCase":{"id":"38","pickleId":"35","testSteps":[{"id":"39","pickleStepId":"34","stepDefinitionIds":["36"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"paperclips\"","children":[{"start":14,"value":"paperclips","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]}],"testRunStartedId":"37"}} +{"testCase":{"id":"40","pickleId":"33","testSteps":[{"id":"41","pickleStepId":"32","stepDefinitionIds":["36"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"rulers\"","children":[{"start":14,"value":"rulers","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]}],"testRunStartedId":"37"}} +{"testCase":{"id":"42","pickleId":"31","testSteps":[{"id":"43","pickleStepId":"30","stepDefinitionIds":["36"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"pencils\"","children":[{"start":14,"value":"pencils","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]}],"testRunStartedId":"37"}} +{"testCase":{"id":"44","pickleId":"23","testSteps":[{"id":"45","pickleStepId":"22","stepDefinitionIds":["36"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"fuses\"","children":[{"start":14,"value":"fuses","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]}],"testRunStartedId":"37"}} +{"testCase":{"id":"46","pickleId":"21","testSteps":[{"id":"47","pickleStepId":"20","stepDefinitionIds":["36"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"light bulbs\"","children":[{"start":14,"value":"light bulbs","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]}],"testRunStartedId":"37"}} +{"testCase":{"id":"48","pickleId":"19","testSteps":[{"id":"49","pickleStepId":"18","stepDefinitionIds":["36"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"batteries\"","children":[{"start":14,"value":"batteries","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]}],"testRunStartedId":"37"}} +{"testCase":{"id":"50","pickleId":"11","testSteps":[{"id":"51","pickleStepId":"10","stepDefinitionIds":["36"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"bread\"","children":[{"start":14,"value":"bread","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]}],"testRunStartedId":"37"}} +{"testCase":{"id":"52","pickleId":"9","testSteps":[{"id":"53","pickleStepId":"8","stepDefinitionIds":["36"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"milk\"","children":[{"start":14,"value":"milk","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]}],"testRunStartedId":"37"}} +{"testCase":{"id":"54","pickleId":"7","testSteps":[{"id":"55","pickleStepId":"6","stepDefinitionIds":["36"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"eggs\"","children":[{"start":14,"value":"eggs","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]}],"testRunStartedId":"37"}} +{"testCaseStarted":{"id":"56","testCaseId":"38","timestamp":{"seconds":0,"nanos":1000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"56","testStepId":"39","timestamp":{"seconds":0,"nanos":2000000}}} +{"testStepFinished":{"testCaseStartedId":"56","testStepId":"39","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":3000000}}} +{"testCaseFinished":{"testCaseStartedId":"56","timestamp":{"seconds":0,"nanos":4000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"57","testCaseId":"40","timestamp":{"seconds":0,"nanos":5000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"57","testStepId":"41","timestamp":{"seconds":0,"nanos":6000000}}} +{"testStepFinished":{"testCaseStartedId":"57","testStepId":"41","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":7000000}}} +{"testCaseFinished":{"testCaseStartedId":"57","timestamp":{"seconds":0,"nanos":8000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"58","testCaseId":"42","timestamp":{"seconds":0,"nanos":9000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"58","testStepId":"43","timestamp":{"seconds":0,"nanos":10000000}}} +{"testStepFinished":{"testCaseStartedId":"58","testStepId":"43","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":11000000}}} +{"testCaseFinished":{"testCaseStartedId":"58","timestamp":{"seconds":0,"nanos":12000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"59","testCaseId":"44","timestamp":{"seconds":0,"nanos":13000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"59","testStepId":"45","timestamp":{"seconds":0,"nanos":14000000}}} +{"testStepFinished":{"testCaseStartedId":"59","testStepId":"45","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":15000000}}} +{"testCaseFinished":{"testCaseStartedId":"59","timestamp":{"seconds":0,"nanos":16000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"60","testCaseId":"46","timestamp":{"seconds":0,"nanos":17000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"60","testStepId":"47","timestamp":{"seconds":0,"nanos":18000000}}} +{"testStepFinished":{"testCaseStartedId":"60","testStepId":"47","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":19000000}}} +{"testCaseFinished":{"testCaseStartedId":"60","timestamp":{"seconds":0,"nanos":20000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"61","testCaseId":"48","timestamp":{"seconds":0,"nanos":21000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"61","testStepId":"49","timestamp":{"seconds":0,"nanos":22000000}}} +{"testStepFinished":{"testCaseStartedId":"61","testStepId":"49","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":23000000}}} +{"testCaseFinished":{"testCaseStartedId":"61","timestamp":{"seconds":0,"nanos":24000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"62","testCaseId":"50","timestamp":{"seconds":0,"nanos":25000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"62","testStepId":"51","timestamp":{"seconds":0,"nanos":26000000}}} +{"testStepFinished":{"testCaseStartedId":"62","testStepId":"51","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":27000000}}} +{"testCaseFinished":{"testCaseStartedId":"62","timestamp":{"seconds":0,"nanos":28000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"63","testCaseId":"52","timestamp":{"seconds":0,"nanos":29000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"63","testStepId":"53","timestamp":{"seconds":0,"nanos":30000000}}} +{"testStepFinished":{"testCaseStartedId":"63","testStepId":"53","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":31000000}}} +{"testCaseFinished":{"testCaseStartedId":"63","timestamp":{"seconds":0,"nanos":32000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"64","testCaseId":"54","timestamp":{"seconds":0,"nanos":33000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"64","testStepId":"55","timestamp":{"seconds":0,"nanos":34000000}}} +{"testStepFinished":{"testCaseStartedId":"64","testStepId":"55","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":35000000}}} +{"testCaseFinished":{"testCaseStartedId":"64","timestamp":{"seconds":0,"nanos":36000000},"willBeRetried":false}} +{"testRunFinished":{"testRunStartedId":"37","timestamp":{"seconds":0,"nanos":37000000},"success":true}} diff --git a/cucumber_cpp/acceptance_test/compatibility/multiple-features/multiple-features-1.feature b/cucumber_cpp/acceptance_test/compatibility/multiple-features/multiple-features-1.feature new file mode 100644 index 00000000..faf03eee --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/multiple-features/multiple-features-1.feature @@ -0,0 +1,10 @@ +Feature: First feature + + Scenario: First scenario + Given an order for "eggs" + + Scenario: Second scenario + Given an order for "milk" + + Scenario: Third scenario + Given an order for "bread" \ No newline at end of file diff --git a/cucumber_cpp/acceptance_test/compatibility/multiple-features/multiple-features-2.feature b/cucumber_cpp/acceptance_test/compatibility/multiple-features/multiple-features-2.feature new file mode 100644 index 00000000..0b0f7569 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/multiple-features/multiple-features-2.feature @@ -0,0 +1,10 @@ +Feature: Second feature + + Scenario: First scenario + Given an order for "batteries" + + Scenario: Second scenario + Given an order for "light bulbs" + + Scenario: Third scenario + Given an order for "fuses" \ No newline at end of file diff --git a/cucumber_cpp/acceptance_test/compatibility/multiple-features/multiple-features-3.feature b/cucumber_cpp/acceptance_test/compatibility/multiple-features/multiple-features-3.feature new file mode 100644 index 00000000..4c306c6c --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/multiple-features/multiple-features-3.feature @@ -0,0 +1,10 @@ +Feature: Third feature + + Scenario: First scenario + Given an order for "pencils" + + Scenario: Second scenario + Given an order for "rulers" + + Scenario: Third scenario + Given an order for "paperclips" \ No newline at end of file diff --git a/cucumber_cpp/acceptance_test/compatibility/multiple-features/multiple-features.ndjson b/cucumber_cpp/acceptance_test/compatibility/multiple-features/multiple-features.ndjson new file mode 100644 index 00000000..065a17cd --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/multiple-features/multiple-features.ndjson @@ -0,0 +1,64 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"Feature: First feature\n\n Scenario: First scenario\n Given an order for \"eggs\"\n\n Scenario: Second scenario\n Given an order for \"milk\"\n\n Scenario: Third scenario\n Given an order for \"bread\"","uri":"samples/multiple-features/multiple-features-1.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"First feature","description":"","children":[{"scenario":{"id":"1","tags":[],"location":{"line":3,"column":3},"keyword":"Scenario","name":"First scenario","description":"","steps":[{"id":"0","location":{"line":4,"column":5},"keyword":"Given ","keywordType":"Context","text":"an order for \"eggs\""}],"examples":[]}},{"scenario":{"id":"3","tags":[],"location":{"line":6,"column":3},"keyword":"Scenario","name":"Second scenario","description":"","steps":[{"id":"2","location":{"line":7,"column":5},"keyword":"Given ","keywordType":"Context","text":"an order for \"milk\""}],"examples":[]}},{"scenario":{"id":"5","tags":[],"location":{"line":9,"column":3},"keyword":"Scenario","name":"Third scenario","description":"","steps":[{"id":"4","location":{"line":10,"column":5},"keyword":"Given ","keywordType":"Context","text":"an order for \"bread\""}],"examples":[]}}]},"comments":[],"uri":"samples/multiple-features/multiple-features-1.feature"}} +{"pickle":{"id":"7","uri":"samples/multiple-features/multiple-features-1.feature","astNodeIds":["1"],"tags":[],"name":"First scenario","language":"en","steps":[{"id":"6","text":"an order for \"eggs\"","type":"Context","astNodeIds":["0"]}]}} +{"pickle":{"id":"9","uri":"samples/multiple-features/multiple-features-1.feature","astNodeIds":["3"],"tags":[],"name":"Second scenario","language":"en","steps":[{"id":"8","text":"an order for \"milk\"","type":"Context","astNodeIds":["2"]}]}} +{"pickle":{"id":"11","uri":"samples/multiple-features/multiple-features-1.feature","astNodeIds":["5"],"tags":[],"name":"Third scenario","language":"en","steps":[{"id":"10","text":"an order for \"bread\"","type":"Context","astNodeIds":["4"]}]}} +{"source":{"data":"Feature: Second feature\n\n Scenario: First scenario\n Given an order for \"batteries\"\n\n Scenario: Second scenario\n Given an order for \"light bulbs\"\n\n Scenario: Third scenario\n Given an order for \"fuses\"","uri":"samples/multiple-features/multiple-features-2.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Second feature","description":"","children":[{"scenario":{"id":"13","tags":[],"location":{"line":3,"column":3},"keyword":"Scenario","name":"First scenario","description":"","steps":[{"id":"12","location":{"line":4,"column":5},"keyword":"Given ","keywordType":"Context","text":"an order for \"batteries\""}],"examples":[]}},{"scenario":{"id":"15","tags":[],"location":{"line":6,"column":3},"keyword":"Scenario","name":"Second scenario","description":"","steps":[{"id":"14","location":{"line":7,"column":5},"keyword":"Given ","keywordType":"Context","text":"an order for \"light bulbs\""}],"examples":[]}},{"scenario":{"id":"17","tags":[],"location":{"line":9,"column":3},"keyword":"Scenario","name":"Third scenario","description":"","steps":[{"id":"16","location":{"line":10,"column":5},"keyword":"Given ","keywordType":"Context","text":"an order for \"fuses\""}],"examples":[]}}]},"comments":[],"uri":"samples/multiple-features/multiple-features-2.feature"}} +{"pickle":{"id":"19","uri":"samples/multiple-features/multiple-features-2.feature","astNodeIds":["13"],"tags":[],"name":"First scenario","language":"en","steps":[{"id":"18","text":"an order for \"batteries\"","type":"Context","astNodeIds":["12"]}]}} +{"pickle":{"id":"21","uri":"samples/multiple-features/multiple-features-2.feature","astNodeIds":["15"],"tags":[],"name":"Second scenario","language":"en","steps":[{"id":"20","text":"an order for \"light bulbs\"","type":"Context","astNodeIds":["14"]}]}} +{"pickle":{"id":"23","uri":"samples/multiple-features/multiple-features-2.feature","astNodeIds":["17"],"tags":[],"name":"Third scenario","language":"en","steps":[{"id":"22","text":"an order for \"fuses\"","type":"Context","astNodeIds":["16"]}]}} +{"source":{"data":"Feature: Third feature\n\n Scenario: First scenario\n Given an order for \"pencils\"\n\n Scenario: Second scenario\n Given an order for \"rulers\"\n\n Scenario: Third scenario\n Given an order for \"paperclips\"","uri":"samples/multiple-features/multiple-features-3.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Third feature","description":"","children":[{"scenario":{"id":"25","tags":[],"location":{"line":3,"column":3},"keyword":"Scenario","name":"First scenario","description":"","steps":[{"id":"24","location":{"line":4,"column":5},"keyword":"Given ","keywordType":"Context","text":"an order for \"pencils\""}],"examples":[]}},{"scenario":{"id":"27","tags":[],"location":{"line":6,"column":3},"keyword":"Scenario","name":"Second scenario","description":"","steps":[{"id":"26","location":{"line":7,"column":5},"keyword":"Given ","keywordType":"Context","text":"an order for \"rulers\""}],"examples":[]}},{"scenario":{"id":"29","tags":[],"location":{"line":9,"column":3},"keyword":"Scenario","name":"Third scenario","description":"","steps":[{"id":"28","location":{"line":10,"column":5},"keyword":"Given ","keywordType":"Context","text":"an order for \"paperclips\""}],"examples":[]}}]},"comments":[],"uri":"samples/multiple-features/multiple-features-3.feature"}} +{"pickle":{"id":"31","uri":"samples/multiple-features/multiple-features-3.feature","astNodeIds":["25"],"tags":[],"name":"First scenario","language":"en","steps":[{"id":"30","text":"an order for \"pencils\"","type":"Context","astNodeIds":["24"]}]}} +{"pickle":{"id":"33","uri":"samples/multiple-features/multiple-features-3.feature","astNodeIds":["27"],"tags":[],"name":"Second scenario","language":"en","steps":[{"id":"32","text":"an order for \"rulers\"","type":"Context","astNodeIds":["26"]}]}} +{"pickle":{"id":"35","uri":"samples/multiple-features/multiple-features-3.feature","astNodeIds":["29"],"tags":[],"name":"Third scenario","language":"en","steps":[{"id":"34","text":"an order for \"paperclips\"","type":"Context","astNodeIds":["28"]}]}} +{"stepDefinition":{"id":"36","pattern":{"type":"CUCUMBER_EXPRESSION","source":"an order for {string}"},"sourceReference":{"uri":"samples/multiple-features/multiple-features.ts","location":{"line":3}}}} +{"testRunStarted":{"id":"37","timestamp":{"seconds":0,"nanos":0}}} +{"testCase":{"id":"38","pickleId":"7","testSteps":[{"id":"39","pickleStepId":"6","stepDefinitionIds":["36"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"eggs\"","children":[{"start":14,"value":"eggs","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]}],"testRunStartedId":"37"}} +{"testCase":{"id":"40","pickleId":"9","testSteps":[{"id":"41","pickleStepId":"8","stepDefinitionIds":["36"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"milk\"","children":[{"start":14,"value":"milk","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]}],"testRunStartedId":"37"}} +{"testCase":{"id":"42","pickleId":"11","testSteps":[{"id":"43","pickleStepId":"10","stepDefinitionIds":["36"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"bread\"","children":[{"start":14,"value":"bread","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]}],"testRunStartedId":"37"}} +{"testCase":{"id":"44","pickleId":"19","testSteps":[{"id":"45","pickleStepId":"18","stepDefinitionIds":["36"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"batteries\"","children":[{"start":14,"value":"batteries","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]}],"testRunStartedId":"37"}} +{"testCase":{"id":"46","pickleId":"21","testSteps":[{"id":"47","pickleStepId":"20","stepDefinitionIds":["36"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"light bulbs\"","children":[{"start":14,"value":"light bulbs","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]}],"testRunStartedId":"37"}} +{"testCase":{"id":"48","pickleId":"23","testSteps":[{"id":"49","pickleStepId":"22","stepDefinitionIds":["36"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"fuses\"","children":[{"start":14,"value":"fuses","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]}],"testRunStartedId":"37"}} +{"testCase":{"id":"50","pickleId":"31","testSteps":[{"id":"51","pickleStepId":"30","stepDefinitionIds":["36"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"pencils\"","children":[{"start":14,"value":"pencils","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]}],"testRunStartedId":"37"}} +{"testCase":{"id":"52","pickleId":"33","testSteps":[{"id":"53","pickleStepId":"32","stepDefinitionIds":["36"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"rulers\"","children":[{"start":14,"value":"rulers","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]}],"testRunStartedId":"37"}} +{"testCase":{"id":"54","pickleId":"35","testSteps":[{"id":"55","pickleStepId":"34","stepDefinitionIds":["36"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"paperclips\"","children":[{"start":14,"value":"paperclips","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]}],"testRunStartedId":"37"}} +{"testCaseStarted":{"id":"56","testCaseId":"38","timestamp":{"seconds":0,"nanos":1000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"56","testStepId":"39","timestamp":{"seconds":0,"nanos":2000000}}} +{"testStepFinished":{"testCaseStartedId":"56","testStepId":"39","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":3000000}}} +{"testCaseFinished":{"testCaseStartedId":"56","timestamp":{"seconds":0,"nanos":4000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"57","testCaseId":"40","timestamp":{"seconds":0,"nanos":5000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"57","testStepId":"41","timestamp":{"seconds":0,"nanos":6000000}}} +{"testStepFinished":{"testCaseStartedId":"57","testStepId":"41","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":7000000}}} +{"testCaseFinished":{"testCaseStartedId":"57","timestamp":{"seconds":0,"nanos":8000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"58","testCaseId":"42","timestamp":{"seconds":0,"nanos":9000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"58","testStepId":"43","timestamp":{"seconds":0,"nanos":10000000}}} +{"testStepFinished":{"testCaseStartedId":"58","testStepId":"43","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":11000000}}} +{"testCaseFinished":{"testCaseStartedId":"58","timestamp":{"seconds":0,"nanos":12000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"59","testCaseId":"44","timestamp":{"seconds":0,"nanos":13000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"59","testStepId":"45","timestamp":{"seconds":0,"nanos":14000000}}} +{"testStepFinished":{"testCaseStartedId":"59","testStepId":"45","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":15000000}}} +{"testCaseFinished":{"testCaseStartedId":"59","timestamp":{"seconds":0,"nanos":16000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"60","testCaseId":"46","timestamp":{"seconds":0,"nanos":17000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"60","testStepId":"47","timestamp":{"seconds":0,"nanos":18000000}}} +{"testStepFinished":{"testCaseStartedId":"60","testStepId":"47","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":19000000}}} +{"testCaseFinished":{"testCaseStartedId":"60","timestamp":{"seconds":0,"nanos":20000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"61","testCaseId":"48","timestamp":{"seconds":0,"nanos":21000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"61","testStepId":"49","timestamp":{"seconds":0,"nanos":22000000}}} +{"testStepFinished":{"testCaseStartedId":"61","testStepId":"49","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":23000000}}} +{"testCaseFinished":{"testCaseStartedId":"61","timestamp":{"seconds":0,"nanos":24000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"62","testCaseId":"50","timestamp":{"seconds":0,"nanos":25000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"62","testStepId":"51","timestamp":{"seconds":0,"nanos":26000000}}} +{"testStepFinished":{"testCaseStartedId":"62","testStepId":"51","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":27000000}}} +{"testCaseFinished":{"testCaseStartedId":"62","timestamp":{"seconds":0,"nanos":28000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"63","testCaseId":"52","timestamp":{"seconds":0,"nanos":29000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"63","testStepId":"53","timestamp":{"seconds":0,"nanos":30000000}}} +{"testStepFinished":{"testCaseStartedId":"63","testStepId":"53","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":31000000}}} +{"testCaseFinished":{"testCaseStartedId":"63","timestamp":{"seconds":0,"nanos":32000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"64","testCaseId":"54","timestamp":{"seconds":0,"nanos":33000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"64","testStepId":"55","timestamp":{"seconds":0,"nanos":34000000}}} +{"testStepFinished":{"testCaseStartedId":"64","testStepId":"55","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":35000000}}} +{"testCaseFinished":{"testCaseStartedId":"64","timestamp":{"seconds":0,"nanos":36000000},"willBeRetried":false}} +{"testRunFinished":{"testRunStartedId":"37","timestamp":{"seconds":0,"nanos":37000000},"success":true}} diff --git a/cucumber_cpp/acceptance_test/compatibility/parameter-types/parameter-types.feature b/cucumber_cpp/acceptance_test/compatibility/parameter-types/parameter-types.feature new file mode 100644 index 00000000..67e09946 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/parameter-types/parameter-types.feature @@ -0,0 +1,11 @@ +Feature: Parameter Types + Cucumber lets you define your own parameter types, which can be used + in Cucumber Expressions. + + This lets you define a precise domain-specific vocabulary which can be used to + generate a glossary with examples taken from your scenarios. + + Parameter types also enable you to transform strings and tables into different types. + + Scenario: Flight transformer + Given LHR-CDG has been delayed diff --git a/cucumber_cpp/acceptance_test/compatibility/parameter-types/parameter-types.ndjson b/cucumber_cpp/acceptance_test/compatibility/parameter-types/parameter-types.ndjson new file mode 100644 index 00000000..0a7b63cc --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/parameter-types/parameter-types.ndjson @@ -0,0 +1,13 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"Feature: Parameter Types\n Cucumber lets you define your own parameter types, which can be used\n in Cucumber Expressions.\n\n This lets you define a precise domain-specific vocabulary which can be used to\n generate a glossary with examples taken from your scenarios.\n\n Parameter types also enable you to transform strings and tables into different types.\n\n Scenario: Flight transformer\n Given LHR-CDG has been delayed\n","uri":"samples/parameter-types/parameter-types.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Parameter Types","description":" Cucumber lets you define your own parameter types, which can be used\n in Cucumber Expressions.\n\n This lets you define a precise domain-specific vocabulary which can be used to\n generate a glossary with examples taken from your scenarios.\n\n Parameter types also enable you to transform strings and tables into different types.","children":[{"scenario":{"id":"1","tags":[],"location":{"line":10,"column":3},"keyword":"Scenario","name":"Flight transformer","description":"","steps":[{"id":"0","location":{"line":11,"column":5},"keyword":"Given ","keywordType":"Context","text":"LHR-CDG has been delayed"}],"examples":[]}}]},"comments":[],"uri":"samples/parameter-types/parameter-types.feature"}} +{"pickle":{"id":"3","uri":"samples/parameter-types/parameter-types.feature","astNodeIds":["1"],"tags":[],"name":"Flight transformer","language":"en","steps":[{"id":"2","text":"LHR-CDG has been delayed","type":"Context","astNodeIds":["0"]}]}} +{"parameterType":{"id":"4","name":"flight","regularExpressions":["([A-Z]{3})-([A-Z]{3})"],"preferForRegularExpressionMatch":false,"useForSnippets":true,"sourceReference":{"uri":"samples/parameter-types/parameter-types.ts","location":{"line":8}}}} +{"stepDefinition":{"id":"5","pattern":{"type":"CUCUMBER_EXPRESSION","source":"{flight} has been delayed"},"sourceReference":{"uri":"samples/parameter-types/parameter-types.ts","location":{"line":16}}}} +{"testRunStarted":{"id":"6","timestamp":{"seconds":0,"nanos":0}}} +{"testCase":{"id":"7","pickleId":"3","testSteps":[{"id":"8","pickleStepId":"2","stepDefinitionIds":["5"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":0,"value":"LHR-CDG","children":[{"start":0,"value":"LHR","children":[]},{"start":4,"value":"CDG","children":[]}]},"parameterTypeName":"flight"}]}]}],"testRunStartedId":"6"}} +{"testCaseStarted":{"id":"9","testCaseId":"7","timestamp":{"seconds":0,"nanos":1000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"9","testStepId":"8","timestamp":{"seconds":0,"nanos":2000000}}} +{"testStepFinished":{"testCaseStartedId":"9","testStepId":"8","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":3000000}}} +{"testCaseFinished":{"testCaseStartedId":"9","timestamp":{"seconds":0,"nanos":4000000},"willBeRetried":false}} +{"testRunFinished":{"testRunStartedId":"6","timestamp":{"seconds":0,"nanos":5000000},"success":true}} diff --git a/cucumber_cpp/acceptance_test/compatibility/pending/pending.feature b/cucumber_cpp/acceptance_test/compatibility/pending/pending.feature new file mode 100644 index 00000000..767ece53 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/pending/pending.feature @@ -0,0 +1,18 @@ +Feature: Pending steps + During development, step definitions can signal at runtime that they are + not yet implemented (or "pending") by returning or throwing a particular + value. + + This causes subsequent steps in the scenario to be skipped, and the overall + result to be treated as a failure. + + Scenario: Unimplemented step signals pending status + Given an unimplemented pending step + + Scenario: Steps before unimplemented steps are executed + Given an implemented non-pending step + And an unimplemented pending step + + Scenario: Steps after unimplemented steps are skipped + Given an unimplemented pending step + And an implemented step that is skipped diff --git a/cucumber_cpp/acceptance_test/compatibility/pending/pending.ndjson b/cucumber_cpp/acceptance_test/compatibility/pending/pending.ndjson new file mode 100644 index 00000000..259b5e1d --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/pending/pending.ndjson @@ -0,0 +1,30 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"Feature: Pending steps\n During development, step definitions can signal at runtime that they are\n not yet implemented (or \"pending\") by returning or throwing a particular\n value.\n\n This causes subsequent steps in the scenario to be skipped, and the overall\n result to be treated as a failure.\n\n Scenario: Unimplemented step signals pending status\n Given an unimplemented pending step\n\n Scenario: Steps before unimplemented steps are executed\n Given an implemented non-pending step\n And an unimplemented pending step\n\n Scenario: Steps after unimplemented steps are skipped\n Given an unimplemented pending step\n And an implemented step that is skipped\n","uri":"samples/pending/pending.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Pending steps","description":" During development, step definitions can signal at runtime that they are\n not yet implemented (or \"pending\") by returning or throwing a particular\n value.\n\n This causes subsequent steps in the scenario to be skipped, and the overall\n result to be treated as a failure.","children":[{"scenario":{"id":"1","tags":[],"location":{"line":9,"column":3},"keyword":"Scenario","name":"Unimplemented step signals pending status","description":"","steps":[{"id":"0","location":{"line":10,"column":5},"keyword":"Given ","keywordType":"Context","text":"an unimplemented pending step"}],"examples":[]}},{"scenario":{"id":"4","tags":[],"location":{"line":12,"column":3},"keyword":"Scenario","name":"Steps before unimplemented steps are executed","description":"","steps":[{"id":"2","location":{"line":13,"column":5},"keyword":"Given ","keywordType":"Context","text":"an implemented non-pending step"},{"id":"3","location":{"line":14,"column":5},"keyword":"And ","keywordType":"Conjunction","text":"an unimplemented pending step"}],"examples":[]}},{"scenario":{"id":"7","tags":[],"location":{"line":16,"column":3},"keyword":"Scenario","name":"Steps after unimplemented steps are skipped","description":"","steps":[{"id":"5","location":{"line":17,"column":5},"keyword":"Given ","keywordType":"Context","text":"an unimplemented pending step"},{"id":"6","location":{"line":18,"column":5},"keyword":"And ","keywordType":"Conjunction","text":"an implemented step that is skipped"}],"examples":[]}}]},"comments":[],"uri":"samples/pending/pending.feature"}} +{"pickle":{"id":"9","uri":"samples/pending/pending.feature","astNodeIds":["1"],"tags":[],"name":"Unimplemented step signals pending status","language":"en","steps":[{"id":"8","text":"an unimplemented pending step","type":"Context","astNodeIds":["0"]}]}} +{"pickle":{"id":"12","uri":"samples/pending/pending.feature","astNodeIds":["4"],"tags":[],"name":"Steps before unimplemented steps are executed","language":"en","steps":[{"id":"10","text":"an implemented non-pending step","type":"Context","astNodeIds":["2"]},{"id":"11","text":"an unimplemented pending step","type":"Context","astNodeIds":["3"]}]}} +{"pickle":{"id":"15","uri":"samples/pending/pending.feature","astNodeIds":["7"],"tags":[],"name":"Steps after unimplemented steps are skipped","language":"en","steps":[{"id":"13","text":"an unimplemented pending step","type":"Context","astNodeIds":["5"]},{"id":"14","text":"an implemented step that is skipped","type":"Context","astNodeIds":["6"]}]}} +{"stepDefinition":{"id":"16","pattern":{"type":"CUCUMBER_EXPRESSION","source":"an implemented non-pending step"},"sourceReference":{"uri":"samples/pending/pending.ts","location":{"line":3}}}} +{"stepDefinition":{"id":"17","pattern":{"type":"CUCUMBER_EXPRESSION","source":"an implemented step that is skipped"},"sourceReference":{"uri":"samples/pending/pending.ts","location":{"line":7}}}} +{"stepDefinition":{"id":"18","pattern":{"type":"CUCUMBER_EXPRESSION","source":"an unimplemented pending step"},"sourceReference":{"uri":"samples/pending/pending.ts","location":{"line":11}}}} +{"testRunStarted":{"id":"19","timestamp":{"seconds":0,"nanos":0}}} +{"testCase":{"id":"20","pickleId":"9","testSteps":[{"id":"21","pickleStepId":"8","stepDefinitionIds":["18"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"19"}} +{"testCase":{"id":"22","pickleId":"12","testSteps":[{"id":"23","pickleStepId":"10","stepDefinitionIds":["16"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]},{"id":"24","pickleStepId":"11","stepDefinitionIds":["18"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"19"}} +{"testCase":{"id":"25","pickleId":"15","testSteps":[{"id":"26","pickleStepId":"13","stepDefinitionIds":["18"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]},{"id":"27","pickleStepId":"14","stepDefinitionIds":["17"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"19"}} +{"testCaseStarted":{"id":"28","testCaseId":"20","timestamp":{"seconds":0,"nanos":1000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"28","testStepId":"21","timestamp":{"seconds":0,"nanos":2000000}}} +{"testStepFinished":{"testCaseStartedId":"28","testStepId":"21","testStepResult":{"status":"PENDING","message":"TODO","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":3000000}}} +{"testCaseFinished":{"testCaseStartedId":"28","timestamp":{"seconds":0,"nanos":4000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"29","testCaseId":"22","timestamp":{"seconds":0,"nanos":5000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"29","testStepId":"23","timestamp":{"seconds":0,"nanos":6000000}}} +{"testStepFinished":{"testCaseStartedId":"29","testStepId":"23","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":7000000}}} +{"testStepStarted":{"testCaseStartedId":"29","testStepId":"24","timestamp":{"seconds":0,"nanos":8000000}}} +{"testStepFinished":{"testCaseStartedId":"29","testStepId":"24","testStepResult":{"status":"PENDING","message":"TODO","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":9000000}}} +{"testCaseFinished":{"testCaseStartedId":"29","timestamp":{"seconds":0,"nanos":10000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"30","testCaseId":"25","timestamp":{"seconds":0,"nanos":11000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"30","testStepId":"26","timestamp":{"seconds":0,"nanos":12000000}}} +{"testStepFinished":{"testCaseStartedId":"30","testStepId":"26","testStepResult":{"status":"PENDING","message":"TODO","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":13000000}}} +{"testStepStarted":{"testCaseStartedId":"30","testStepId":"27","timestamp":{"seconds":0,"nanos":14000000}}} +{"testStepFinished":{"testCaseStartedId":"30","testStepId":"27","testStepResult":{"status":"SKIPPED","duration":{"seconds":0,"nanos":0}},"timestamp":{"seconds":0,"nanos":15000000}}} +{"testCaseFinished":{"testCaseStartedId":"30","timestamp":{"seconds":0,"nanos":16000000},"willBeRetried":false}} +{"testRunFinished":{"testRunStartedId":"19","timestamp":{"seconds":0,"nanos":17000000},"success":false}} diff --git a/cucumber_cpp/acceptance_test/compatibility/regular-expression/regular-expression.feature b/cucumber_cpp/acceptance_test/compatibility/regular-expression/regular-expression.feature new file mode 100644 index 00000000..fcf7ae59 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/regular-expression/regular-expression.feature @@ -0,0 +1,9 @@ +Feature: regular expression + + Cucumber supports both Cucumber and regular expressions in step + definitions. This shows a sample that uses a regular expression. + + Scenario: regular expression + Given a cucumber + Given a cucumber and a zucchini + Given a cucumber and a zucchini and a gourd diff --git a/cucumber_cpp/acceptance_test/compatibility/regular-expression/regular-expression.ndjson b/cucumber_cpp/acceptance_test/compatibility/regular-expression/regular-expression.ndjson new file mode 100644 index 00000000..de094052 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/regular-expression/regular-expression.ndjson @@ -0,0 +1,16 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"Feature: regular expression\n \n Cucumber supports both Cucumber and regular expressions in step\n definitions. This shows a sample that uses a regular expression.\n \n Scenario: regular expression\n Given a cucumber\n Given a cucumber and a zucchini\n Given a cucumber and a zucchini and a gourd\n","uri":"samples/regular-expression/regular-expression.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"regular expression","description":" Cucumber supports both Cucumber and regular expressions in step\n definitions. This shows a sample that uses a regular expression.","children":[{"scenario":{"id":"3","tags":[],"location":{"line":6,"column":3},"keyword":"Scenario","name":"regular expression","description":"","steps":[{"id":"0","location":{"line":7,"column":5},"keyword":"Given ","keywordType":"Context","text":"a cucumber"},{"id":"1","location":{"line":8,"column":5},"keyword":"Given ","keywordType":"Context","text":"a cucumber and a zucchini"},{"id":"2","location":{"line":9,"column":5},"keyword":"Given ","keywordType":"Context","text":"a cucumber and a zucchini and a gourd"}],"examples":[]}}]},"comments":[],"uri":"samples/regular-expression/regular-expression.feature"}} +{"pickle":{"id":"7","uri":"samples/regular-expression/regular-expression.feature","astNodeIds":["3"],"tags":[],"name":"regular expression","language":"en","steps":[{"id":"4","text":"a cucumber","type":"Context","astNodeIds":["0"]},{"id":"5","text":"a cucumber and a zucchini","type":"Context","astNodeIds":["1"]},{"id":"6","text":"a cucumber and a zucchini and a gourd","type":"Context","astNodeIds":["2"]}]}} +{"stepDefinition":{"id":"8","pattern":{"type":"REGULAR_EXPRESSION","source":"^a (.*?)(?: and a (.*?))?(?: and a (.*?))?$"},"sourceReference":{"uri":"samples/regular-expression/regular-expression.ts","location":{"line":3}}}} +{"testRunStarted":{"id":"9","timestamp":{"seconds":0,"nanos":0}}} +{"testCase":{"id":"10","pickleId":"7","testSteps":[{"id":"11","pickleStepId":"4","stepDefinitionIds":["8"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":2,"value":"cucumber","children":[]}},{"group":{"children":[]}},{"group":{"children":[]}}]}]},{"id":"12","pickleStepId":"5","stepDefinitionIds":["8"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":2,"value":"cucumber","children":[]}},{"group":{"start":17,"value":"zucchini","children":[]}},{"group":{"children":[]}}]}]},{"id":"13","pickleStepId":"6","stepDefinitionIds":["8"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":2,"value":"cucumber","children":[]}},{"group":{"start":17,"value":"zucchini","children":[]}},{"group":{"start":32,"value":"gourd","children":[]}}]}]}],"testRunStartedId":"9"}} +{"testCaseStarted":{"id":"14","testCaseId":"10","timestamp":{"seconds":0,"nanos":1000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"14","testStepId":"11","timestamp":{"seconds":0,"nanos":2000000}}} +{"testStepFinished":{"testCaseStartedId":"14","testStepId":"11","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":3000000}}} +{"testStepStarted":{"testCaseStartedId":"14","testStepId":"12","timestamp":{"seconds":0,"nanos":4000000}}} +{"testStepFinished":{"testCaseStartedId":"14","testStepId":"12","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":5000000}}} +{"testStepStarted":{"testCaseStartedId":"14","testStepId":"13","timestamp":{"seconds":0,"nanos":6000000}}} +{"testStepFinished":{"testCaseStartedId":"14","testStepId":"13","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":7000000}}} +{"testCaseFinished":{"testCaseStartedId":"14","timestamp":{"seconds":0,"nanos":8000000},"willBeRetried":false}} +{"testRunFinished":{"testRunStartedId":"9","timestamp":{"seconds":0,"nanos":9000000},"success":true}} diff --git a/cucumber_cpp/acceptance_test/compatibility/retry-ambiguous/retry-ambiguous.arguments.txt b/cucumber_cpp/acceptance_test/compatibility/retry-ambiguous/retry-ambiguous.arguments.txt new file mode 100644 index 00000000..cf83a555 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/retry-ambiguous/retry-ambiguous.arguments.txt @@ -0,0 +1 @@ +--retry 2 diff --git a/cucumber_cpp/acceptance_test/compatibility/retry-ambiguous/retry-ambiguous.feature b/cucumber_cpp/acceptance_test/compatibility/retry-ambiguous/retry-ambiguous.feature new file mode 100644 index 00000000..2769d2f4 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/retry-ambiguous/retry-ambiguous.feature @@ -0,0 +1,3 @@ +Feature: Retry - With Ambiguous Steps + Scenario: Test cases won't retry when the status is AMBIGUOUS + Given an ambiguous step diff --git a/cucumber_cpp/acceptance_test/compatibility/retry-ambiguous/retry-ambiguous.ndjson b/cucumber_cpp/acceptance_test/compatibility/retry-ambiguous/retry-ambiguous.ndjson new file mode 100644 index 00000000..5d3e0d19 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/retry-ambiguous/retry-ambiguous.ndjson @@ -0,0 +1,13 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"Feature: Retry - With Ambiguous Steps\n Scenario: Test cases won't retry when the status is AMBIGUOUS\n Given an ambiguous step\n","uri":"samples/retry-ambiguous/retry-ambiguous.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Retry - With Ambiguous Steps","description":"","children":[{"scenario":{"id":"1","tags":[],"location":{"line":2,"column":3},"keyword":"Scenario","name":"Test cases won't retry when the status is AMBIGUOUS","description":"","steps":[{"id":"0","location":{"line":3,"column":5},"keyword":"Given ","keywordType":"Context","text":"an ambiguous step"}],"examples":[]}}]},"comments":[],"uri":"samples/retry-ambiguous/retry-ambiguous.feature"}} +{"pickle":{"id":"3","uri":"samples/retry-ambiguous/retry-ambiguous.feature","astNodeIds":["1"],"tags":[],"name":"Test cases won't retry when the status is AMBIGUOUS","language":"en","steps":[{"id":"2","text":"an ambiguous step","type":"Context","astNodeIds":["0"]}]}} +{"stepDefinition":{"id":"4","pattern":{"type":"CUCUMBER_EXPRESSION","source":"an ambiguous step"},"sourceReference":{"uri":"samples/retry-ambiguous/retry-ambiguous.ts","location":{"line":3}}}} +{"stepDefinition":{"id":"5","pattern":{"type":"CUCUMBER_EXPRESSION","source":"an ambiguous step"},"sourceReference":{"uri":"samples/retry-ambiguous/retry-ambiguous.ts","location":{"line":7}}}} +{"testRunStarted":{"id":"6","timestamp":{"seconds":0,"nanos":0}}} +{"testCase":{"id":"7","pickleId":"3","testSteps":[{"id":"8","pickleStepId":"2","stepDefinitionIds":["4","5"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]},{"stepMatchArguments":[]}]}],"testRunStartedId":"6"}} +{"testCaseStarted":{"id":"9","testCaseId":"7","timestamp":{"seconds":0,"nanos":1000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"9","testStepId":"8","timestamp":{"seconds":0,"nanos":2000000}}} +{"testStepFinished":{"testCaseStartedId":"9","testStepId":"8","testStepResult":{"status":"AMBIGUOUS","duration":{"seconds":0,"nanos":0}},"timestamp":{"seconds":0,"nanos":3000000}}} +{"testCaseFinished":{"testCaseStartedId":"9","timestamp":{"seconds":0,"nanos":4000000},"willBeRetried":false}} +{"testRunFinished":{"testRunStartedId":"6","timestamp":{"seconds":0,"nanos":5000000},"success":false}} diff --git a/cucumber_cpp/acceptance_test/compatibility/retry-pending/retry-pending.arguments.txt b/cucumber_cpp/acceptance_test/compatibility/retry-pending/retry-pending.arguments.txt new file mode 100644 index 00000000..cf83a555 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/retry-pending/retry-pending.arguments.txt @@ -0,0 +1 @@ +--retry 2 diff --git a/cucumber_cpp/acceptance_test/compatibility/retry-pending/retry-pending.feature b/cucumber_cpp/acceptance_test/compatibility/retry-pending/retry-pending.feature new file mode 100644 index 00000000..bacc607e --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/retry-pending/retry-pending.feature @@ -0,0 +1,3 @@ +Feature: Retry - With Pending Steps + Scenario: Test cases won't retry when the status is PENDING + Given a pending step diff --git a/cucumber_cpp/acceptance_test/compatibility/retry-pending/retry-pending.ndjson b/cucumber_cpp/acceptance_test/compatibility/retry-pending/retry-pending.ndjson new file mode 100644 index 00000000..21f00d78 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/retry-pending/retry-pending.ndjson @@ -0,0 +1,12 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"Feature: Retry - With Pending Steps\n Scenario: Test cases won't retry when the status is PENDING\n Given a pending step\n","uri":"samples/retry-pending/retry-pending.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Retry - With Pending Steps","description":"","children":[{"scenario":{"id":"1","tags":[],"location":{"line":2,"column":3},"keyword":"Scenario","name":"Test cases won't retry when the status is PENDING","description":"","steps":[{"id":"0","location":{"line":3,"column":5},"keyword":"Given ","keywordType":"Context","text":"a pending step"}],"examples":[]}}]},"comments":[],"uri":"samples/retry-pending/retry-pending.feature"}} +{"pickle":{"id":"3","uri":"samples/retry-pending/retry-pending.feature","astNodeIds":["1"],"tags":[],"name":"Test cases won't retry when the status is PENDING","language":"en","steps":[{"id":"2","text":"a pending step","type":"Context","astNodeIds":["0"]}]}} +{"stepDefinition":{"id":"4","pattern":{"type":"CUCUMBER_EXPRESSION","source":"a pending step"},"sourceReference":{"uri":"samples/retry-pending/retry-pending.ts","location":{"line":3}}}} +{"testRunStarted":{"id":"5","timestamp":{"seconds":0,"nanos":0}}} +{"testCase":{"id":"6","pickleId":"3","testSteps":[{"id":"7","pickleStepId":"2","stepDefinitionIds":["4"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"5"}} +{"testCaseStarted":{"id":"8","testCaseId":"6","timestamp":{"seconds":0,"nanos":1000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"8","testStepId":"7","timestamp":{"seconds":0,"nanos":2000000}}} +{"testStepFinished":{"testCaseStartedId":"8","testStepId":"7","testStepResult":{"status":"PENDING","message":"TODO","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":3000000}}} +{"testCaseFinished":{"testCaseStartedId":"8","timestamp":{"seconds":0,"nanos":4000000},"willBeRetried":false}} +{"testRunFinished":{"testRunStartedId":"5","timestamp":{"seconds":0,"nanos":5000000},"success":false}} diff --git a/cucumber_cpp/acceptance_test/compatibility/retry-undefined/retry-undefined.arguments.txt b/cucumber_cpp/acceptance_test/compatibility/retry-undefined/retry-undefined.arguments.txt new file mode 100644 index 00000000..cf83a555 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/retry-undefined/retry-undefined.arguments.txt @@ -0,0 +1 @@ +--retry 2 diff --git a/cucumber_cpp/acceptance_test/compatibility/retry-undefined/retry-undefined.feature b/cucumber_cpp/acceptance_test/compatibility/retry-undefined/retry-undefined.feature new file mode 100644 index 00000000..10f7eab6 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/retry-undefined/retry-undefined.feature @@ -0,0 +1,3 @@ +Feature: Retry - With Undefined Steps + Scenario: Test cases won't retry when the status is UNDEFINED + Given a non-existent step diff --git a/cucumber_cpp/acceptance_test/compatibility/retry-undefined/retry-undefined.ndjson b/cucumber_cpp/acceptance_test/compatibility/retry-undefined/retry-undefined.ndjson new file mode 100644 index 00000000..1c0e31d4 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/retry-undefined/retry-undefined.ndjson @@ -0,0 +1,12 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"Feature: Retry - With Undefined Steps\n Scenario: Test cases won't retry when the status is UNDEFINED\n Given a non-existent step\n","uri":"samples/retry-undefined/retry-undefined.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Retry - With Undefined Steps","description":"","children":[{"scenario":{"id":"1","tags":[],"location":{"line":2,"column":3},"keyword":"Scenario","name":"Test cases won't retry when the status is UNDEFINED","description":"","steps":[{"id":"0","location":{"line":3,"column":5},"keyword":"Given ","keywordType":"Context","text":"a non-existent step"}],"examples":[]}}]},"comments":[],"uri":"samples/retry-undefined/retry-undefined.feature"}} +{"pickle":{"id":"3","uri":"samples/retry-undefined/retry-undefined.feature","astNodeIds":["1"],"tags":[],"name":"Test cases won't retry when the status is UNDEFINED","language":"en","steps":[{"id":"2","text":"a non-existent step","type":"Context","astNodeIds":["0"]}]}} +{"testRunStarted":{"id":"4","timestamp":{"seconds":0,"nanos":0}}} +{"testCase":{"id":"5","pickleId":"3","testSteps":[{"id":"6","pickleStepId":"2","stepDefinitionIds":[],"stepMatchArgumentsLists":[]}],"testRunStartedId":"4"}} +{"testCaseStarted":{"id":"7","testCaseId":"5","timestamp":{"seconds":0,"nanos":1000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"7","testStepId":"6","timestamp":{"seconds":0,"nanos":2000000}}} +{"suggestion":{"id":"8","pickleStepId":"2","snippets":[{"language":"typescript","code":"Given(\"a non-existent step\", () => {\n return \"pending\"\n})"}]}} +{"testStepFinished":{"testCaseStartedId":"7","testStepId":"6","testStepResult":{"status":"UNDEFINED","duration":{"seconds":0,"nanos":0}},"timestamp":{"seconds":0,"nanos":3000000}}} +{"testCaseFinished":{"testCaseStartedId":"7","timestamp":{"seconds":0,"nanos":4000000},"willBeRetried":false}} +{"testRunFinished":{"testRunStartedId":"4","timestamp":{"seconds":0,"nanos":5000000},"success":false}} diff --git a/cucumber_cpp/acceptance_test/compatibility/retry/retry.arguments.txt b/cucumber_cpp/acceptance_test/compatibility/retry/retry.arguments.txt new file mode 100644 index 00000000..cf83a555 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/retry/retry.arguments.txt @@ -0,0 +1 @@ +--retry 2 diff --git a/cucumber_cpp/acceptance_test/compatibility/retry/retry.feature b/cucumber_cpp/acceptance_test/compatibility/retry/retry.feature new file mode 100644 index 00000000..e48671dd --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/retry/retry.feature @@ -0,0 +1,18 @@ +Feature: Retry + Some Cucumber implementations support a Retry mechanism, where test cases that fail + can be retried up to a limited number of attempts in the same test run. + + Non-passing statuses other than FAILED won't trigger a retry, as they are not + going to pass however many times we attempt them. + + Scenario: Test cases that pass aren't retried + Given a step that always passes + + Scenario: Test cases that fail are retried if within the --retry limit + Given a step that passes the second time + + Scenario: Test cases that fail will continue to retry up to the --retry limit + Given a step that passes the third time + + Scenario: Test cases won't retry after failing more than the --retry limit + Given a step that always fails diff --git a/cucumber_cpp/acceptance_test/compatibility/retry/retry.ndjson b/cucumber_cpp/acceptance_test/compatibility/retry/retry.ndjson new file mode 100644 index 00000000..1bbc345e --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/retry/retry.ndjson @@ -0,0 +1,53 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"Feature: Retry\n Some Cucumber implementations support a Retry mechanism, where test cases that fail\n can be retried up to a limited number of attempts in the same test run.\n\n Non-passing statuses other than FAILED won't trigger a retry, as they are not\n going to pass however many times we attempt them.\n\n Scenario: Test cases that pass aren't retried\n Given a step that always passes\n\n Scenario: Test cases that fail are retried if within the --retry limit\n Given a step that passes the second time\n\n Scenario: Test cases that fail will continue to retry up to the --retry limit\n Given a step that passes the third time\n\n Scenario: Test cases won't retry after failing more than the --retry limit\n Given a step that always fails\n","uri":"samples/retry/retry.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Retry","description":" Some Cucumber implementations support a Retry mechanism, where test cases that fail\n can be retried up to a limited number of attempts in the same test run.\n\n Non-passing statuses other than FAILED won't trigger a retry, as they are not\n going to pass however many times we attempt them.","children":[{"scenario":{"id":"1","tags":[],"location":{"line":8,"column":3},"keyword":"Scenario","name":"Test cases that pass aren't retried","description":"","steps":[{"id":"0","location":{"line":9,"column":5},"keyword":"Given ","keywordType":"Context","text":"a step that always passes"}],"examples":[]}},{"scenario":{"id":"3","tags":[],"location":{"line":11,"column":3},"keyword":"Scenario","name":"Test cases that fail are retried if within the --retry limit","description":"","steps":[{"id":"2","location":{"line":12,"column":5},"keyword":"Given ","keywordType":"Context","text":"a step that passes the second time"}],"examples":[]}},{"scenario":{"id":"5","tags":[],"location":{"line":14,"column":3},"keyword":"Scenario","name":"Test cases that fail will continue to retry up to the --retry limit","description":"","steps":[{"id":"4","location":{"line":15,"column":5},"keyword":"Given ","keywordType":"Context","text":"a step that passes the third time"}],"examples":[]}},{"scenario":{"id":"7","tags":[],"location":{"line":17,"column":3},"keyword":"Scenario","name":"Test cases won't retry after failing more than the --retry limit","description":"","steps":[{"id":"6","location":{"line":18,"column":5},"keyword":"Given ","keywordType":"Context","text":"a step that always fails"}],"examples":[]}}]},"comments":[],"uri":"samples/retry/retry.feature"}} +{"pickle":{"id":"9","uri":"samples/retry/retry.feature","astNodeIds":["1"],"tags":[],"name":"Test cases that pass aren't retried","language":"en","steps":[{"id":"8","text":"a step that always passes","type":"Context","astNodeIds":["0"]}]}} +{"pickle":{"id":"11","uri":"samples/retry/retry.feature","astNodeIds":["3"],"tags":[],"name":"Test cases that fail are retried if within the --retry limit","language":"en","steps":[{"id":"10","text":"a step that passes the second time","type":"Context","astNodeIds":["2"]}]}} +{"pickle":{"id":"13","uri":"samples/retry/retry.feature","astNodeIds":["5"],"tags":[],"name":"Test cases that fail will continue to retry up to the --retry limit","language":"en","steps":[{"id":"12","text":"a step that passes the third time","type":"Context","astNodeIds":["4"]}]}} +{"pickle":{"id":"15","uri":"samples/retry/retry.feature","astNodeIds":["7"],"tags":[],"name":"Test cases won't retry after failing more than the --retry limit","language":"en","steps":[{"id":"14","text":"a step that always fails","type":"Context","astNodeIds":["6"]}]}} +{"stepDefinition":{"id":"16","pattern":{"type":"CUCUMBER_EXPRESSION","source":"a step that always passes"},"sourceReference":{"uri":"samples/retry/retry.ts","location":{"line":3}}}} +{"stepDefinition":{"id":"17","pattern":{"type":"CUCUMBER_EXPRESSION","source":"a step that passes the second time"},"sourceReference":{"uri":"samples/retry/retry.ts","location":{"line":8}}}} +{"stepDefinition":{"id":"18","pattern":{"type":"CUCUMBER_EXPRESSION","source":"a step that passes the third time"},"sourceReference":{"uri":"samples/retry/retry.ts","location":{"line":16}}}} +{"stepDefinition":{"id":"19","pattern":{"type":"CUCUMBER_EXPRESSION","source":"a step that always fails"},"sourceReference":{"uri":"samples/retry/retry.ts","location":{"line":23}}}} +{"testRunStarted":{"id":"20","timestamp":{"seconds":0,"nanos":0}}} +{"testCase":{"id":"21","pickleId":"9","testSteps":[{"id":"22","pickleStepId":"8","stepDefinitionIds":["16"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"20"}} +{"testCase":{"id":"23","pickleId":"11","testSteps":[{"id":"24","pickleStepId":"10","stepDefinitionIds":["17"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"20"}} +{"testCase":{"id":"25","pickleId":"13","testSteps":[{"id":"26","pickleStepId":"12","stepDefinitionIds":["18"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"20"}} +{"testCase":{"id":"27","pickleId":"15","testSteps":[{"id":"28","pickleStepId":"14","stepDefinitionIds":["19"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"20"}} +{"testCaseStarted":{"id":"29","testCaseId":"21","timestamp":{"seconds":0,"nanos":1000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"29","testStepId":"22","timestamp":{"seconds":0,"nanos":2000000}}} +{"testStepFinished":{"testCaseStartedId":"29","testStepId":"22","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":3000000}}} +{"testCaseFinished":{"testCaseStartedId":"29","timestamp":{"seconds":0,"nanos":4000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"30","testCaseId":"23","timestamp":{"seconds":0,"nanos":5000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"30","testStepId":"24","timestamp":{"seconds":0,"nanos":6000000}}} +{"testStepFinished":{"testCaseStartedId":"30","testStepId":"24","testStepResult":{"message":"Exception in step","exception":{"type":"Error","message":"Exception in step","stackTrace":"Error: Exception in step\nsamples/retry/retry.feature:12"},"status":"FAILED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":7000000}}} +{"testCaseFinished":{"testCaseStartedId":"30","timestamp":{"seconds":0,"nanos":8000000},"willBeRetried":true}} +{"testCaseStarted":{"id":"31","testCaseId":"23","timestamp":{"seconds":0,"nanos":9000000},"attempt":1}} +{"testStepStarted":{"testCaseStartedId":"31","testStepId":"24","timestamp":{"seconds":0,"nanos":10000000}}} +{"testStepFinished":{"testCaseStartedId":"31","testStepId":"24","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":11000000}}} +{"testCaseFinished":{"testCaseStartedId":"31","timestamp":{"seconds":0,"nanos":12000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"32","testCaseId":"25","timestamp":{"seconds":0,"nanos":13000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"32","testStepId":"26","timestamp":{"seconds":0,"nanos":14000000}}} +{"testStepFinished":{"testCaseStartedId":"32","testStepId":"26","testStepResult":{"message":"Exception in step","exception":{"type":"Error","message":"Exception in step","stackTrace":"Error: Exception in step\nsamples/retry/retry.feature:15"},"status":"FAILED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":15000000}}} +{"testCaseFinished":{"testCaseStartedId":"32","timestamp":{"seconds":0,"nanos":16000000},"willBeRetried":true}} +{"testCaseStarted":{"id":"33","testCaseId":"25","timestamp":{"seconds":0,"nanos":17000000},"attempt":1}} +{"testStepStarted":{"testCaseStartedId":"33","testStepId":"26","timestamp":{"seconds":0,"nanos":18000000}}} +{"testStepFinished":{"testCaseStartedId":"33","testStepId":"26","testStepResult":{"message":"Exception in step","exception":{"type":"Error","message":"Exception in step","stackTrace":"Error: Exception in step\nsamples/retry/retry.feature:15"},"status":"FAILED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":19000000}}} +{"testCaseFinished":{"testCaseStartedId":"33","timestamp":{"seconds":0,"nanos":20000000},"willBeRetried":true}} +{"testCaseStarted":{"id":"34","testCaseId":"25","timestamp":{"seconds":0,"nanos":21000000},"attempt":2}} +{"testStepStarted":{"testCaseStartedId":"34","testStepId":"26","timestamp":{"seconds":0,"nanos":22000000}}} +{"testStepFinished":{"testCaseStartedId":"34","testStepId":"26","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":23000000}}} +{"testCaseFinished":{"testCaseStartedId":"34","timestamp":{"seconds":0,"nanos":24000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"35","testCaseId":"27","timestamp":{"seconds":0,"nanos":25000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"35","testStepId":"28","timestamp":{"seconds":0,"nanos":26000000}}} +{"testStepFinished":{"testCaseStartedId":"35","testStepId":"28","testStepResult":{"message":"Exception in step","exception":{"type":"Error","message":"Exception in step","stackTrace":"Error: Exception in step\nsamples/retry/retry.feature:18"},"status":"FAILED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":27000000}}} +{"testCaseFinished":{"testCaseStartedId":"35","timestamp":{"seconds":0,"nanos":28000000},"willBeRetried":true}} +{"testCaseStarted":{"id":"36","testCaseId":"27","timestamp":{"seconds":0,"nanos":29000000},"attempt":1}} +{"testStepStarted":{"testCaseStartedId":"36","testStepId":"28","timestamp":{"seconds":0,"nanos":30000000}}} +{"testStepFinished":{"testCaseStartedId":"36","testStepId":"28","testStepResult":{"message":"Exception in step","exception":{"type":"Error","message":"Exception in step","stackTrace":"Error: Exception in step\nsamples/retry/retry.feature:18"},"status":"FAILED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":31000000}}} +{"testCaseFinished":{"testCaseStartedId":"36","timestamp":{"seconds":0,"nanos":32000000},"willBeRetried":true}} +{"testCaseStarted":{"id":"37","testCaseId":"27","timestamp":{"seconds":0,"nanos":33000000},"attempt":2}} +{"testStepStarted":{"testCaseStartedId":"37","testStepId":"28","timestamp":{"seconds":0,"nanos":34000000}}} +{"testStepFinished":{"testCaseStartedId":"37","testStepId":"28","testStepResult":{"message":"Exception in step","exception":{"type":"Error","message":"Exception in step","stackTrace":"Error: Exception in step\nsamples/retry/retry.feature:18"},"status":"FAILED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":35000000}}} +{"testCaseFinished":{"testCaseStartedId":"37","timestamp":{"seconds":0,"nanos":36000000},"willBeRetried":false}} +{"testRunFinished":{"testRunStartedId":"20","timestamp":{"seconds":0,"nanos":37000000},"success":false}} diff --git a/cucumber_cpp/acceptance_test/compatibility/rules-backgrounds/rules-backgrounds.feature b/cucumber_cpp/acceptance_test/compatibility/rules-backgrounds/rules-backgrounds.feature new file mode 100644 index 00000000..d4f79667 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/rules-backgrounds/rules-backgrounds.feature @@ -0,0 +1,23 @@ +Feature: Rules with Backgrounds + Like Features, Rules can also have Backgrounds, whose steps are prepended to those of each child Scenario. Only + one Background at the Rule level is supported. + + It's even possible to have a Background at both Feature and Rule level, in which case they are concatenated. + + Background: + Given an order for "eggs" + And an order for "milk" + And an order for "bread" + + Rule: + Background: + Given an order for "batteries" + And an order for "light bulbs" + + Example: one scenario + When an action + Then an outcome + + Example: another scenario + When an action + Then an outcome \ No newline at end of file diff --git a/cucumber_cpp/acceptance_test/compatibility/rules-backgrounds/rules-backgrounds.ndjson b/cucumber_cpp/acceptance_test/compatibility/rules-backgrounds/rules-backgrounds.ndjson new file mode 100644 index 00000000..96eaa696 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/rules-backgrounds/rules-backgrounds.ndjson @@ -0,0 +1,44 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"Feature: Rules with Backgrounds\n Like Features, Rules can also have Backgrounds, whose steps are prepended to those of each child Scenario. Only\n one Background at the Rule level is supported.\n\n It's even possible to have a Background at both Feature and Rule level, in which case they are concatenated.\n\n Background:\n Given an order for \"eggs\"\n And an order for \"milk\"\n And an order for \"bread\"\n\n Rule:\n Background:\n Given an order for \"batteries\"\n And an order for \"light bulbs\"\n\n Example: one scenario\n When an action\n Then an outcome\n\n Example: another scenario\n When an action\n Then an outcome","uri":"samples/rules-backgrounds/rules-backgrounds.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Rules with Backgrounds","description":" Like Features, Rules can also have Backgrounds, whose steps are prepended to those of each child Scenario. Only\n one Background at the Rule level is supported.\n\n It's even possible to have a Background at both Feature and Rule level, in which case they are concatenated.","children":[{"background":{"id":"3","location":{"line":7,"column":3},"keyword":"Background","name":"","description":"","steps":[{"id":"0","location":{"line":8,"column":5},"keyword":"Given ","keywordType":"Context","text":"an order for \"eggs\""},{"id":"1","location":{"line":9,"column":5},"keyword":"And ","keywordType":"Conjunction","text":"an order for \"milk\""},{"id":"2","location":{"line":10,"column":5},"keyword":"And ","keywordType":"Conjunction","text":"an order for \"bread\""}]}},{"rule":{"id":"13","location":{"line":12,"column":3},"keyword":"Rule","name":"","description":"","children":[{"background":{"id":"6","location":{"line":13,"column":5},"keyword":"Background","name":"","description":"","steps":[{"id":"4","location":{"line":14,"column":7},"keyword":"Given ","keywordType":"Context","text":"an order for \"batteries\""},{"id":"5","location":{"line":15,"column":7},"keyword":"And ","keywordType":"Conjunction","text":"an order for \"light bulbs\""}]}},{"scenario":{"id":"9","tags":[],"location":{"line":17,"column":5},"keyword":"Example","name":"one scenario","description":"","steps":[{"id":"7","location":{"line":18,"column":7},"keyword":"When ","keywordType":"Action","text":"an action"},{"id":"8","location":{"line":19,"column":7},"keyword":"Then ","keywordType":"Outcome","text":"an outcome"}],"examples":[]}},{"scenario":{"id":"12","tags":[],"location":{"line":21,"column":5},"keyword":"Example","name":"another scenario","description":"","steps":[{"id":"10","location":{"line":22,"column":7},"keyword":"When ","keywordType":"Action","text":"an action"},{"id":"11","location":{"line":23,"column":7},"keyword":"Then ","keywordType":"Outcome","text":"an outcome"}],"examples":[]}}],"tags":[]}}]},"comments":[],"uri":"samples/rules-backgrounds/rules-backgrounds.feature"}} +{"pickle":{"id":"21","uri":"samples/rules-backgrounds/rules-backgrounds.feature","astNodeIds":["9"],"tags":[],"name":"one scenario","language":"en","steps":[{"id":"14","text":"an order for \"eggs\"","type":"Context","astNodeIds":["0"]},{"id":"15","text":"an order for \"milk\"","type":"Context","astNodeIds":["1"]},{"id":"16","text":"an order for \"bread\"","type":"Context","astNodeIds":["2"]},{"id":"17","text":"an order for \"batteries\"","type":"Context","astNodeIds":["4"]},{"id":"18","text":"an order for \"light bulbs\"","type":"Context","astNodeIds":["5"]},{"id":"19","text":"an action","type":"Action","astNodeIds":["7"]},{"id":"20","text":"an outcome","type":"Outcome","astNodeIds":["8"]}]}} +{"pickle":{"id":"29","uri":"samples/rules-backgrounds/rules-backgrounds.feature","astNodeIds":["12"],"tags":[],"name":"another scenario","language":"en","steps":[{"id":"22","text":"an order for \"eggs\"","type":"Context","astNodeIds":["0"]},{"id":"23","text":"an order for \"milk\"","type":"Context","astNodeIds":["1"]},{"id":"24","text":"an order for \"bread\"","type":"Context","astNodeIds":["2"]},{"id":"25","text":"an order for \"batteries\"","type":"Context","astNodeIds":["4"]},{"id":"26","text":"an order for \"light bulbs\"","type":"Context","astNodeIds":["5"]},{"id":"27","text":"an action","type":"Action","astNodeIds":["10"]},{"id":"28","text":"an outcome","type":"Outcome","astNodeIds":["11"]}]}} +{"stepDefinition":{"id":"30","pattern":{"type":"CUCUMBER_EXPRESSION","source":"an order for {string}"},"sourceReference":{"uri":"samples/rules-backgrounds/rules-backgrounds.ts","location":{"line":3}}}} +{"stepDefinition":{"id":"31","pattern":{"type":"CUCUMBER_EXPRESSION","source":"an action"},"sourceReference":{"uri":"samples/rules-backgrounds/rules-backgrounds.ts","location":{"line":7}}}} +{"stepDefinition":{"id":"32","pattern":{"type":"CUCUMBER_EXPRESSION","source":"an outcome"},"sourceReference":{"uri":"samples/rules-backgrounds/rules-backgrounds.ts","location":{"line":11}}}} +{"testRunStarted":{"id":"33","timestamp":{"seconds":0,"nanos":0}}} +{"testCase":{"id":"34","pickleId":"21","testSteps":[{"id":"35","pickleStepId":"14","stepDefinitionIds":["30"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"eggs\"","children":[{"start":14,"value":"eggs","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]},{"id":"36","pickleStepId":"15","stepDefinitionIds":["30"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"milk\"","children":[{"start":14,"value":"milk","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]},{"id":"37","pickleStepId":"16","stepDefinitionIds":["30"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"bread\"","children":[{"start":14,"value":"bread","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]},{"id":"38","pickleStepId":"17","stepDefinitionIds":["30"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"batteries\"","children":[{"start":14,"value":"batteries","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]},{"id":"39","pickleStepId":"18","stepDefinitionIds":["30"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"light bulbs\"","children":[{"start":14,"value":"light bulbs","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]},{"id":"40","pickleStepId":"19","stepDefinitionIds":["31"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]},{"id":"41","pickleStepId":"20","stepDefinitionIds":["32"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"33"}} +{"testCase":{"id":"42","pickleId":"29","testSteps":[{"id":"43","pickleStepId":"22","stepDefinitionIds":["30"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"eggs\"","children":[{"start":14,"value":"eggs","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]},{"id":"44","pickleStepId":"23","stepDefinitionIds":["30"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"milk\"","children":[{"start":14,"value":"milk","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]},{"id":"45","pickleStepId":"24","stepDefinitionIds":["30"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"bread\"","children":[{"start":14,"value":"bread","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]},{"id":"46","pickleStepId":"25","stepDefinitionIds":["30"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"batteries\"","children":[{"start":14,"value":"batteries","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]},{"id":"47","pickleStepId":"26","stepDefinitionIds":["30"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":13,"value":"\"light bulbs\"","children":[{"start":14,"value":"light bulbs","children":[{"children":[]}]},{"children":[{"children":[]}]}]},"parameterTypeName":"string"}]}]},{"id":"48","pickleStepId":"27","stepDefinitionIds":["31"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]},{"id":"49","pickleStepId":"28","stepDefinitionIds":["32"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"33"}} +{"testCaseStarted":{"id":"50","testCaseId":"34","timestamp":{"seconds":0,"nanos":1000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"50","testStepId":"35","timestamp":{"seconds":0,"nanos":2000000}}} +{"testStepFinished":{"testCaseStartedId":"50","testStepId":"35","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":3000000}}} +{"testStepStarted":{"testCaseStartedId":"50","testStepId":"36","timestamp":{"seconds":0,"nanos":4000000}}} +{"testStepFinished":{"testCaseStartedId":"50","testStepId":"36","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":5000000}}} +{"testStepStarted":{"testCaseStartedId":"50","testStepId":"37","timestamp":{"seconds":0,"nanos":6000000}}} +{"testStepFinished":{"testCaseStartedId":"50","testStepId":"37","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":7000000}}} +{"testStepStarted":{"testCaseStartedId":"50","testStepId":"38","timestamp":{"seconds":0,"nanos":8000000}}} +{"testStepFinished":{"testCaseStartedId":"50","testStepId":"38","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":9000000}}} +{"testStepStarted":{"testCaseStartedId":"50","testStepId":"39","timestamp":{"seconds":0,"nanos":10000000}}} +{"testStepFinished":{"testCaseStartedId":"50","testStepId":"39","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":11000000}}} +{"testStepStarted":{"testCaseStartedId":"50","testStepId":"40","timestamp":{"seconds":0,"nanos":12000000}}} +{"testStepFinished":{"testCaseStartedId":"50","testStepId":"40","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":13000000}}} +{"testStepStarted":{"testCaseStartedId":"50","testStepId":"41","timestamp":{"seconds":0,"nanos":14000000}}} +{"testStepFinished":{"testCaseStartedId":"50","testStepId":"41","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":15000000}}} +{"testCaseFinished":{"testCaseStartedId":"50","timestamp":{"seconds":0,"nanos":16000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"51","testCaseId":"42","timestamp":{"seconds":0,"nanos":17000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"51","testStepId":"43","timestamp":{"seconds":0,"nanos":18000000}}} +{"testStepFinished":{"testCaseStartedId":"51","testStepId":"43","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":19000000}}} +{"testStepStarted":{"testCaseStartedId":"51","testStepId":"44","timestamp":{"seconds":0,"nanos":20000000}}} +{"testStepFinished":{"testCaseStartedId":"51","testStepId":"44","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":21000000}}} +{"testStepStarted":{"testCaseStartedId":"51","testStepId":"45","timestamp":{"seconds":0,"nanos":22000000}}} +{"testStepFinished":{"testCaseStartedId":"51","testStepId":"45","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":23000000}}} +{"testStepStarted":{"testCaseStartedId":"51","testStepId":"46","timestamp":{"seconds":0,"nanos":24000000}}} +{"testStepFinished":{"testCaseStartedId":"51","testStepId":"46","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":25000000}}} +{"testStepStarted":{"testCaseStartedId":"51","testStepId":"47","timestamp":{"seconds":0,"nanos":26000000}}} +{"testStepFinished":{"testCaseStartedId":"51","testStepId":"47","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":27000000}}} +{"testStepStarted":{"testCaseStartedId":"51","testStepId":"48","timestamp":{"seconds":0,"nanos":28000000}}} +{"testStepFinished":{"testCaseStartedId":"51","testStepId":"48","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":29000000}}} +{"testStepStarted":{"testCaseStartedId":"51","testStepId":"49","timestamp":{"seconds":0,"nanos":30000000}}} +{"testStepFinished":{"testCaseStartedId":"51","testStepId":"49","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":31000000}}} +{"testCaseFinished":{"testCaseStartedId":"51","timestamp":{"seconds":0,"nanos":32000000},"willBeRetried":false}} +{"testRunFinished":{"testRunStartedId":"33","timestamp":{"seconds":0,"nanos":33000000},"success":true}} diff --git a/cucumber_cpp/acceptance_test/compatibility/rules/rules.feature b/cucumber_cpp/acceptance_test/compatibility/rules/rules.feature new file mode 100644 index 00000000..5d576ac7 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/rules/rules.feature @@ -0,0 +1,29 @@ +Feature: Usage of a `Rule` + You can place scenarios inside rules. This makes it possible to structure Gherkin documents + in the same way as [example maps](https://cucumber.io/blog/bdd/example-mapping-introduction/). + + You can also use the Examples synonym for Scenario to make them even similar. + + Rule: A sale cannot happen if the customer does not have enough money + # Unhappy path + Example: Not enough money + Given the customer has 100 cents + And there are chocolate bars in stock + When the customer tries to buy a 125 cent chocolate bar + Then the sale should not happen + + # Happy path + Example: Enough money + Given the customer has 100 cents + And there are chocolate bars in stock + When the customer tries to buy a 75 cent chocolate bar + Then the sale should happen + + @some-tag + Rule: a sale cannot happen if there is no stock + # Unhappy path + Example: No chocolates left + Given the customer has 100 cents + And there are no chocolate bars in stock + When the customer tries to buy a 1 cent chocolate bar + Then the sale should not happen diff --git a/cucumber_cpp/acceptance_test/compatibility/rules/rules.ndjson b/cucumber_cpp/acceptance_test/compatibility/rules/rules.ndjson new file mode 100644 index 00000000..6431aba2 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/rules/rules.ndjson @@ -0,0 +1,47 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"Feature: Usage of a `Rule`\n You can place scenarios inside rules. This makes it possible to structure Gherkin documents\n in the same way as [example maps](https://cucumber.io/blog/bdd/example-mapping-introduction/).\n\n You can also use the Examples synonym for Scenario to make them even similar.\n\n Rule: A sale cannot happen if the customer does not have enough money\n # Unhappy path\n Example: Not enough money\n Given the customer has 100 cents\n And there are chocolate bars in stock\n When the customer tries to buy a 125 cent chocolate bar\n Then the sale should not happen\n\n # Happy path\n Example: Enough money\n Given the customer has 100 cents\n And there are chocolate bars in stock\n When the customer tries to buy a 75 cent chocolate bar\n Then the sale should happen\n\n @some-tag\n Rule: a sale cannot happen if there is no stock\n # Unhappy path\n Example: No chocolates left\n Given the customer has 100 cents\n And there are no chocolate bars in stock\n When the customer tries to buy a 1 cent chocolate bar\n Then the sale should not happen\n","uri":"samples/rules/rules.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Usage of a `Rule`","description":" You can place scenarios inside rules. This makes it possible to structure Gherkin documents\n in the same way as [example maps](https://cucumber.io/blog/bdd/example-mapping-introduction/).\n\n You can also use the Examples synonym for Scenario to make them even similar.","children":[{"rule":{"id":"10","location":{"line":7,"column":3},"keyword":"Rule","name":"A sale cannot happen if the customer does not have enough money","description":"","children":[{"scenario":{"id":"4","tags":[],"location":{"line":9,"column":5},"keyword":"Example","name":"Not enough money","description":"","steps":[{"id":"0","location":{"line":10,"column":7},"keyword":"Given ","keywordType":"Context","text":"the customer has 100 cents"},{"id":"1","location":{"line":11,"column":7},"keyword":"And ","keywordType":"Conjunction","text":"there are chocolate bars in stock"},{"id":"2","location":{"line":12,"column":7},"keyword":"When ","keywordType":"Action","text":"the customer tries to buy a 125 cent chocolate bar"},{"id":"3","location":{"line":13,"column":7},"keyword":"Then ","keywordType":"Outcome","text":"the sale should not happen"}],"examples":[]}},{"scenario":{"id":"9","tags":[],"location":{"line":16,"column":5},"keyword":"Example","name":"Enough money","description":"","steps":[{"id":"5","location":{"line":17,"column":7},"keyword":"Given ","keywordType":"Context","text":"the customer has 100 cents"},{"id":"6","location":{"line":18,"column":7},"keyword":"And ","keywordType":"Conjunction","text":"there are chocolate bars in stock"},{"id":"7","location":{"line":19,"column":7},"keyword":"When ","keywordType":"Action","text":"the customer tries to buy a 75 cent chocolate bar"},{"id":"8","location":{"line":20,"column":7},"keyword":"Then ","keywordType":"Outcome","text":"the sale should happen"}],"examples":[]}}],"tags":[]}},{"rule":{"id":"17","location":{"line":23,"column":3},"keyword":"Rule","name":"a sale cannot happen if there is no stock","description":"","children":[{"scenario":{"id":"15","tags":[],"location":{"line":25,"column":5},"keyword":"Example","name":"No chocolates left","description":"","steps":[{"id":"11","location":{"line":26,"column":7},"keyword":"Given ","keywordType":"Context","text":"the customer has 100 cents"},{"id":"12","location":{"line":27,"column":7},"keyword":"And ","keywordType":"Conjunction","text":"there are no chocolate bars in stock"},{"id":"13","location":{"line":28,"column":7},"keyword":"When ","keywordType":"Action","text":"the customer tries to buy a 1 cent chocolate bar"},{"id":"14","location":{"line":29,"column":7},"keyword":"Then ","keywordType":"Outcome","text":"the sale should not happen"}],"examples":[]}}],"tags":[{"location":{"line":22,"column":3},"name":"@some-tag","id":"16"}]}}]},"comments":[{"location":{"line":8,"column":1},"text":" # Unhappy path"},{"location":{"line":15,"column":1},"text":" # Happy path"},{"location":{"line":24,"column":1},"text":" # Unhappy path"}],"uri":"samples/rules/rules.feature"}} +{"pickle":{"id":"22","uri":"samples/rules/rules.feature","astNodeIds":["4"],"tags":[],"name":"Not enough money","language":"en","steps":[{"id":"18","text":"the customer has 100 cents","type":"Context","astNodeIds":["0"]},{"id":"19","text":"there are chocolate bars in stock","type":"Context","astNodeIds":["1"]},{"id":"20","text":"the customer tries to buy a 125 cent chocolate bar","type":"Action","astNodeIds":["2"]},{"id":"21","text":"the sale should not happen","type":"Outcome","astNodeIds":["3"]}]}} +{"pickle":{"id":"27","uri":"samples/rules/rules.feature","astNodeIds":["9"],"tags":[],"name":"Enough money","language":"en","steps":[{"id":"23","text":"the customer has 100 cents","type":"Context","astNodeIds":["5"]},{"id":"24","text":"there are chocolate bars in stock","type":"Context","astNodeIds":["6"]},{"id":"25","text":"the customer tries to buy a 75 cent chocolate bar","type":"Action","astNodeIds":["7"]},{"id":"26","text":"the sale should happen","type":"Outcome","astNodeIds":["8"]}]}} +{"pickle":{"id":"32","uri":"samples/rules/rules.feature","astNodeIds":["15"],"tags":[{"name":"@some-tag","astNodeId":"16"}],"name":"No chocolates left","language":"en","steps":[{"id":"28","text":"the customer has 100 cents","type":"Context","astNodeIds":["11"]},{"id":"29","text":"there are no chocolate bars in stock","type":"Context","astNodeIds":["12"]},{"id":"30","text":"the customer tries to buy a 1 cent chocolate bar","type":"Action","astNodeIds":["13"]},{"id":"31","text":"the sale should not happen","type":"Outcome","astNodeIds":["14"]}]}} +{"stepDefinition":{"id":"33","pattern":{"type":"CUCUMBER_EXPRESSION","source":"the customer has {int} cents"},"sourceReference":{"uri":"samples/rules/rules.ts","location":{"line":4}}}} +{"stepDefinition":{"id":"34","pattern":{"type":"CUCUMBER_EXPRESSION","source":"there are chocolate bars in stock"},"sourceReference":{"uri":"samples/rules/rules.ts","location":{"line":8}}}} +{"stepDefinition":{"id":"35","pattern":{"type":"CUCUMBER_EXPRESSION","source":"there are no chocolate bars in stock"},"sourceReference":{"uri":"samples/rules/rules.ts","location":{"line":12}}}} +{"stepDefinition":{"id":"36","pattern":{"type":"CUCUMBER_EXPRESSION","source":"the customer tries to buy a {int} cent chocolate bar"},"sourceReference":{"uri":"samples/rules/rules.ts","location":{"line":16}}}} +{"stepDefinition":{"id":"37","pattern":{"type":"CUCUMBER_EXPRESSION","source":"the sale should not happen"},"sourceReference":{"uri":"samples/rules/rules.ts","location":{"line":22}}}} +{"stepDefinition":{"id":"38","pattern":{"type":"CUCUMBER_EXPRESSION","source":"the sale should happen"},"sourceReference":{"uri":"samples/rules/rules.ts","location":{"line":26}}}} +{"testRunStarted":{"id":"39","timestamp":{"seconds":0,"nanos":0}}} +{"testCase":{"id":"40","pickleId":"22","testSteps":[{"id":"41","pickleStepId":"18","stepDefinitionIds":["33"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":17,"value":"100","children":[]},"parameterTypeName":"int"}]}]},{"id":"42","pickleStepId":"19","stepDefinitionIds":["34"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]},{"id":"43","pickleStepId":"20","stepDefinitionIds":["36"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":28,"value":"125","children":[]},"parameterTypeName":"int"}]}]},{"id":"44","pickleStepId":"21","stepDefinitionIds":["37"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"39"}} +{"testCase":{"id":"45","pickleId":"27","testSteps":[{"id":"46","pickleStepId":"23","stepDefinitionIds":["33"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":17,"value":"100","children":[]},"parameterTypeName":"int"}]}]},{"id":"47","pickleStepId":"24","stepDefinitionIds":["34"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]},{"id":"48","pickleStepId":"25","stepDefinitionIds":["36"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":28,"value":"75","children":[]},"parameterTypeName":"int"}]}]},{"id":"49","pickleStepId":"26","stepDefinitionIds":["38"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"39"}} +{"testCase":{"id":"50","pickleId":"32","testSteps":[{"id":"51","pickleStepId":"28","stepDefinitionIds":["33"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":17,"value":"100","children":[]},"parameterTypeName":"int"}]}]},{"id":"52","pickleStepId":"29","stepDefinitionIds":["35"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]},{"id":"53","pickleStepId":"30","stepDefinitionIds":["36"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":28,"value":"1","children":[]},"parameterTypeName":"int"}]}]},{"id":"54","pickleStepId":"31","stepDefinitionIds":["37"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"39"}} +{"testCaseStarted":{"id":"55","testCaseId":"40","timestamp":{"seconds":0,"nanos":1000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"55","testStepId":"41","timestamp":{"seconds":0,"nanos":2000000}}} +{"testStepFinished":{"testCaseStartedId":"55","testStepId":"41","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":3000000}}} +{"testStepStarted":{"testCaseStartedId":"55","testStepId":"42","timestamp":{"seconds":0,"nanos":4000000}}} +{"testStepFinished":{"testCaseStartedId":"55","testStepId":"42","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":5000000}}} +{"testStepStarted":{"testCaseStartedId":"55","testStepId":"43","timestamp":{"seconds":0,"nanos":6000000}}} +{"testStepFinished":{"testCaseStartedId":"55","testStepId":"43","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":7000000}}} +{"testStepStarted":{"testCaseStartedId":"55","testStepId":"44","timestamp":{"seconds":0,"nanos":8000000}}} +{"testStepFinished":{"testCaseStartedId":"55","testStepId":"44","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":9000000}}} +{"testCaseFinished":{"testCaseStartedId":"55","timestamp":{"seconds":0,"nanos":10000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"56","testCaseId":"45","timestamp":{"seconds":0,"nanos":11000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"56","testStepId":"46","timestamp":{"seconds":0,"nanos":12000000}}} +{"testStepFinished":{"testCaseStartedId":"56","testStepId":"46","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":13000000}}} +{"testStepStarted":{"testCaseStartedId":"56","testStepId":"47","timestamp":{"seconds":0,"nanos":14000000}}} +{"testStepFinished":{"testCaseStartedId":"56","testStepId":"47","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":15000000}}} +{"testStepStarted":{"testCaseStartedId":"56","testStepId":"48","timestamp":{"seconds":0,"nanos":16000000}}} +{"testStepFinished":{"testCaseStartedId":"56","testStepId":"48","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":17000000}}} +{"testStepStarted":{"testCaseStartedId":"56","testStepId":"49","timestamp":{"seconds":0,"nanos":18000000}}} +{"testStepFinished":{"testCaseStartedId":"56","testStepId":"49","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":19000000}}} +{"testCaseFinished":{"testCaseStartedId":"56","timestamp":{"seconds":0,"nanos":20000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"57","testCaseId":"50","timestamp":{"seconds":0,"nanos":21000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"57","testStepId":"51","timestamp":{"seconds":0,"nanos":22000000}}} +{"testStepFinished":{"testCaseStartedId":"57","testStepId":"51","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":23000000}}} +{"testStepStarted":{"testCaseStartedId":"57","testStepId":"52","timestamp":{"seconds":0,"nanos":24000000}}} +{"testStepFinished":{"testCaseStartedId":"57","testStepId":"52","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":25000000}}} +{"testStepStarted":{"testCaseStartedId":"57","testStepId":"53","timestamp":{"seconds":0,"nanos":26000000}}} +{"testStepFinished":{"testCaseStartedId":"57","testStepId":"53","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":27000000}}} +{"testStepStarted":{"testCaseStartedId":"57","testStepId":"54","timestamp":{"seconds":0,"nanos":28000000}}} +{"testStepFinished":{"testCaseStartedId":"57","testStepId":"54","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":29000000}}} +{"testCaseFinished":{"testCaseStartedId":"57","timestamp":{"seconds":0,"nanos":30000000},"willBeRetried":false}} +{"testRunFinished":{"testRunStartedId":"39","timestamp":{"seconds":0,"nanos":31000000},"success":true}} diff --git a/cucumber_cpp/acceptance_test/compatibility/skipped/skipped.feature b/cucumber_cpp/acceptance_test/compatibility/skipped/skipped.feature new file mode 100644 index 00000000..c8efe7af --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/skipped/skipped.feature @@ -0,0 +1,19 @@ +Feature: Skipping scenarios + + Hooks and step definitions are able to signal at runtime that the scenario should + be skipped by raising a particular kind of exception status (For example PENDING or SKIPPED). + + This can be useful in certain situations e.g. the current environment doesn't have + the right conditions for running a particular scenario. + + @skip + Scenario: Skipping from a Before hook + Given a step that is skipped + + Scenario: Skipping from a step doesn't affect the previous steps + Given a step that does not skip + And I skip a step + + Scenario: Skipping from a step causes the rest of the scenario to be skipped + Given I skip a step + And a step that is skipped diff --git a/cucumber_cpp/acceptance_test/compatibility/skipped/skipped.ndjson b/cucumber_cpp/acceptance_test/compatibility/skipped/skipped.ndjson new file mode 100644 index 00000000..a6832c22 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/skipped/skipped.ndjson @@ -0,0 +1,33 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"Feature: Skipping scenarios\n\n Hooks and step definitions are able to signal at runtime that the scenario should\n be skipped by raising a particular kind of exception status (For example PENDING or SKIPPED).\n\n This can be useful in certain situations e.g. the current environment doesn't have\n the right conditions for running a particular scenario.\n\n @skip\n Scenario: Skipping from a Before hook\n Given a step that is skipped\n\n Scenario: Skipping from a step doesn't affect the previous steps\n Given a step that does not skip\n And I skip a step\n\n Scenario: Skipping from a step causes the rest of the scenario to be skipped\n Given I skip a step\n And a step that is skipped\n","uri":"samples/skipped/skipped.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Skipping scenarios","description":" Hooks and step definitions are able to signal at runtime that the scenario should\n be skipped by raising a particular kind of exception status (For example PENDING or SKIPPED).\n\n This can be useful in certain situations e.g. the current environment doesn't have\n the right conditions for running a particular scenario.","children":[{"scenario":{"id":"2","tags":[{"location":{"line":9,"column":3},"name":"@skip","id":"1"}],"location":{"line":10,"column":3},"keyword":"Scenario","name":"Skipping from a Before hook","description":"","steps":[{"id":"0","location":{"line":11,"column":5},"keyword":"Given ","keywordType":"Context","text":"a step that is skipped"}],"examples":[]}},{"scenario":{"id":"5","tags":[],"location":{"line":13,"column":3},"keyword":"Scenario","name":"Skipping from a step doesn't affect the previous steps","description":"","steps":[{"id":"3","location":{"line":14,"column":5},"keyword":"Given ","keywordType":"Context","text":"a step that does not skip"},{"id":"4","location":{"line":15,"column":5},"keyword":"And ","keywordType":"Conjunction","text":"I skip a step"}],"examples":[]}},{"scenario":{"id":"8","tags":[],"location":{"line":17,"column":3},"keyword":"Scenario","name":"Skipping from a step causes the rest of the scenario to be skipped","description":"","steps":[{"id":"6","location":{"line":18,"column":5},"keyword":"Given ","keywordType":"Context","text":"I skip a step"},{"id":"7","location":{"line":19,"column":5},"keyword":"And ","keywordType":"Conjunction","text":"a step that is skipped"}],"examples":[]}}]},"comments":[],"uri":"samples/skipped/skipped.feature"}} +{"pickle":{"id":"10","uri":"samples/skipped/skipped.feature","astNodeIds":["2"],"tags":[{"name":"@skip","astNodeId":"1"}],"name":"Skipping from a Before hook","language":"en","steps":[{"id":"9","text":"a step that is skipped","type":"Context","astNodeIds":["0"]}]}} +{"pickle":{"id":"13","uri":"samples/skipped/skipped.feature","astNodeIds":["5"],"tags":[],"name":"Skipping from a step doesn't affect the previous steps","language":"en","steps":[{"id":"11","text":"a step that does not skip","type":"Context","astNodeIds":["3"]},{"id":"12","text":"I skip a step","type":"Context","astNodeIds":["4"]}]}} +{"pickle":{"id":"16","uri":"samples/skipped/skipped.feature","astNodeIds":["8"],"tags":[],"name":"Skipping from a step causes the rest of the scenario to be skipped","language":"en","steps":[{"id":"14","text":"I skip a step","type":"Context","astNodeIds":["6"]},{"id":"15","text":"a step that is skipped","type":"Context","astNodeIds":["7"]}]}} +{"stepDefinition":{"id":"18","pattern":{"type":"CUCUMBER_EXPRESSION","source":"a step that does not skip"},"sourceReference":{"uri":"samples/skipped/skipped.ts","location":{"line":7}}}} +{"stepDefinition":{"id":"19","pattern":{"type":"CUCUMBER_EXPRESSION","source":"a step that is skipped"},"sourceReference":{"uri":"samples/skipped/skipped.ts","location":{"line":11}}}} +{"stepDefinition":{"id":"20","pattern":{"type":"CUCUMBER_EXPRESSION","source":"I skip a step"},"sourceReference":{"uri":"samples/skipped/skipped.ts","location":{"line":15}}}} +{"hook":{"id":"17","type":"BEFORE_TEST_CASE","tagExpression":"@skip","sourceReference":{"uri":"samples/skipped/skipped.ts","location":{"line":3}}}} +{"testRunStarted":{"id":"21","timestamp":{"seconds":0,"nanos":0}}} +{"testCase":{"id":"22","pickleId":"10","testSteps":[{"id":"23","hookId":"17"},{"id":"24","pickleStepId":"9","stepDefinitionIds":["19"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"21"}} +{"testCase":{"id":"25","pickleId":"13","testSteps":[{"id":"26","pickleStepId":"11","stepDefinitionIds":["18"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]},{"id":"27","pickleStepId":"12","stepDefinitionIds":["20"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"21"}} +{"testCase":{"id":"28","pickleId":"16","testSteps":[{"id":"29","pickleStepId":"14","stepDefinitionIds":["20"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]},{"id":"30","pickleStepId":"15","stepDefinitionIds":["19"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"21"}} +{"testCaseStarted":{"id":"31","testCaseId":"22","timestamp":{"seconds":0,"nanos":1000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"31","testStepId":"23","timestamp":{"seconds":0,"nanos":2000000}}} +{"testStepFinished":{"testCaseStartedId":"31","testStepId":"23","testStepResult":{"status":"SKIPPED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":3000000}}} +{"testStepStarted":{"testCaseStartedId":"31","testStepId":"24","timestamp":{"seconds":0,"nanos":4000000}}} +{"testStepFinished":{"testCaseStartedId":"31","testStepId":"24","testStepResult":{"status":"SKIPPED","duration":{"seconds":0,"nanos":0}},"timestamp":{"seconds":0,"nanos":5000000}}} +{"testCaseFinished":{"testCaseStartedId":"31","timestamp":{"seconds":0,"nanos":6000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"32","testCaseId":"25","timestamp":{"seconds":0,"nanos":7000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"32","testStepId":"26","timestamp":{"seconds":0,"nanos":8000000}}} +{"testStepFinished":{"testCaseStartedId":"32","testStepId":"26","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":9000000}}} +{"testStepStarted":{"testCaseStartedId":"32","testStepId":"27","timestamp":{"seconds":0,"nanos":10000000}}} +{"testStepFinished":{"testCaseStartedId":"32","testStepId":"27","testStepResult":{"status":"SKIPPED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":11000000}}} +{"testCaseFinished":{"testCaseStartedId":"32","timestamp":{"seconds":0,"nanos":12000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"33","testCaseId":"28","timestamp":{"seconds":0,"nanos":13000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"33","testStepId":"29","timestamp":{"seconds":0,"nanos":14000000}}} +{"testStepFinished":{"testCaseStartedId":"33","testStepId":"29","testStepResult":{"status":"SKIPPED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":15000000}}} +{"testStepStarted":{"testCaseStartedId":"33","testStepId":"30","timestamp":{"seconds":0,"nanos":16000000}}} +{"testStepFinished":{"testCaseStartedId":"33","testStepId":"30","testStepResult":{"status":"SKIPPED","duration":{"seconds":0,"nanos":0}},"timestamp":{"seconds":0,"nanos":17000000}}} +{"testCaseFinished":{"testCaseStartedId":"33","timestamp":{"seconds":0,"nanos":18000000},"willBeRetried":false}} +{"testRunFinished":{"testRunStartedId":"21","timestamp":{"seconds":0,"nanos":19000000},"success":true}} diff --git a/cucumber_cpp/acceptance_test/compatibility/stack-traces/stack-traces.feature b/cucumber_cpp/acceptance_test/compatibility/stack-traces/stack-traces.feature new file mode 100644 index 00000000..2f6ff485 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/stack-traces/stack-traces.feature @@ -0,0 +1,10 @@ +Feature: Stack traces + Stack traces can help you diagnose the source of a bug. + + Cucumber provides helpful stack traces that includes the stack frames from the + Gherkin document and remove uninteresting frames by default. + + The first line of the stack trace will contain a reference to the feature file. + + Scenario: A failing step + When a step throws an exception diff --git a/cucumber_cpp/acceptance_test/compatibility/stack-traces/stack-traces.ndjson b/cucumber_cpp/acceptance_test/compatibility/stack-traces/stack-traces.ndjson new file mode 100644 index 00000000..c646feea --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/stack-traces/stack-traces.ndjson @@ -0,0 +1,12 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"Feature: Stack traces\n Stack traces can help you diagnose the source of a bug.\n\n Cucumber provides helpful stack traces that includes the stack frames from the\n Gherkin document and remove uninteresting frames by default.\n\n The first line of the stack trace will contain a reference to the feature file.\n\n Scenario: A failing step\n When a step throws an exception\n","uri":"samples/stack-traces/stack-traces.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Stack traces","description":" Stack traces can help you diagnose the source of a bug.\n\n Cucumber provides helpful stack traces that includes the stack frames from the\n Gherkin document and remove uninteresting frames by default.\n\n The first line of the stack trace will contain a reference to the feature file.","children":[{"scenario":{"id":"1","tags":[],"location":{"line":9,"column":3},"keyword":"Scenario","name":"A failing step","description":"","steps":[{"id":"0","location":{"line":10,"column":5},"keyword":"When ","keywordType":"Action","text":"a step throws an exception"}],"examples":[]}}]},"comments":[],"uri":"samples/stack-traces/stack-traces.feature"}} +{"pickle":{"id":"3","uri":"samples/stack-traces/stack-traces.feature","astNodeIds":["1"],"tags":[],"name":"A failing step","language":"en","steps":[{"id":"2","text":"a step throws an exception","type":"Action","astNodeIds":["0"]}]}} +{"stepDefinition":{"id":"4","pattern":{"type":"CUCUMBER_EXPRESSION","source":"a step throws an exception"},"sourceReference":{"uri":"samples/stack-traces/stack-traces.ts","location":{"line":3}}}} +{"testRunStarted":{"id":"5","timestamp":{"seconds":0,"nanos":0}}} +{"testCase":{"id":"6","pickleId":"3","testSteps":[{"id":"7","pickleStepId":"2","stepDefinitionIds":["4"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"5"}} +{"testCaseStarted":{"id":"8","testCaseId":"6","timestamp":{"seconds":0,"nanos":1000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"8","testStepId":"7","timestamp":{"seconds":0,"nanos":2000000}}} +{"testStepFinished":{"testCaseStartedId":"8","testStepId":"7","testStepResult":{"message":"BOOM","exception":{"type":"Error","message":"BOOM","stackTrace":"Error: BOOM\nsamples/stack-traces/stack-traces.feature:10"},"status":"FAILED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":3000000}}} +{"testCaseFinished":{"testCaseStartedId":"8","timestamp":{"seconds":0,"nanos":4000000},"willBeRetried":false}} +{"testRunFinished":{"testRunStartedId":"5","timestamp":{"seconds":0,"nanos":5000000},"success":false}} diff --git a/cucumber_cpp/acceptance_test/compatibility/undefined/undefined.feature b/cucumber_cpp/acceptance_test/compatibility/undefined/undefined.feature new file mode 100644 index 00000000..c1e19e9a --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/undefined/undefined.feature @@ -0,0 +1,20 @@ +Feature: Undefined steps + + At runtime, Cucumber may encounter a step in a scenario that it cannot match to a step definition. + + In these cases, the scenario is not able to run and so the step status will be UNDEFINED, with + subsequent steps being SKIPPED and the overall result will be FAILURE. + + Scenario: An undefined step causes a failure + Given a step that is yet to be defined + + Scenario: Steps before undefined steps are executed + Given an implemented step + And a step that is yet to be defined + + Scenario: Steps after undefined steps are skipped + Given a step that is yet to be defined + And a step that will be skipped + + Scenario: Snippets reflect parameter types + Given a list of 8 things diff --git a/cucumber_cpp/acceptance_test/compatibility/undefined/undefined.ndjson b/cucumber_cpp/acceptance_test/compatibility/undefined/undefined.ndjson new file mode 100644 index 00000000..59e8c46e --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/undefined/undefined.ndjson @@ -0,0 +1,39 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"Feature: Undefined steps\n\n At runtime, Cucumber may encounter a step in a scenario that it cannot match to a step definition.\n\n In these cases, the scenario is not able to run and so the step status will be UNDEFINED, with\n subsequent steps being SKIPPED and the overall result will be FAILURE.\n\n Scenario: An undefined step causes a failure\n Given a step that is yet to be defined\n\n Scenario: Steps before undefined steps are executed\n Given an implemented step\n And a step that is yet to be defined\n\n Scenario: Steps after undefined steps are skipped\n Given a step that is yet to be defined\n And a step that will be skipped\n\n Scenario: Snippets reflect parameter types\n Given a list of 8 things\n","uri":"samples/undefined/undefined.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Undefined steps","description":" At runtime, Cucumber may encounter a step in a scenario that it cannot match to a step definition.\n\n In these cases, the scenario is not able to run and so the step status will be UNDEFINED, with\n subsequent steps being SKIPPED and the overall result will be FAILURE.","children":[{"scenario":{"id":"1","tags":[],"location":{"line":8,"column":3},"keyword":"Scenario","name":"An undefined step causes a failure","description":"","steps":[{"id":"0","location":{"line":9,"column":5},"keyword":"Given ","keywordType":"Context","text":"a step that is yet to be defined"}],"examples":[]}},{"scenario":{"id":"4","tags":[],"location":{"line":11,"column":3},"keyword":"Scenario","name":"Steps before undefined steps are executed","description":"","steps":[{"id":"2","location":{"line":12,"column":5},"keyword":"Given ","keywordType":"Context","text":"an implemented step"},{"id":"3","location":{"line":13,"column":5},"keyword":"And ","keywordType":"Conjunction","text":"a step that is yet to be defined"}],"examples":[]}},{"scenario":{"id":"7","tags":[],"location":{"line":15,"column":3},"keyword":"Scenario","name":"Steps after undefined steps are skipped","description":"","steps":[{"id":"5","location":{"line":16,"column":5},"keyword":"Given ","keywordType":"Context","text":"a step that is yet to be defined"},{"id":"6","location":{"line":17,"column":5},"keyword":"And ","keywordType":"Conjunction","text":"a step that will be skipped"}],"examples":[]}},{"scenario":{"id":"9","tags":[],"location":{"line":19,"column":3},"keyword":"Scenario","name":"Snippets reflect parameter types","description":"","steps":[{"id":"8","location":{"line":20,"column":5},"keyword":"Given ","keywordType":"Context","text":"a list of 8 things"}],"examples":[]}}]},"comments":[],"uri":"samples/undefined/undefined.feature"}} +{"pickle":{"id":"11","uri":"samples/undefined/undefined.feature","astNodeIds":["1"],"tags":[],"name":"An undefined step causes a failure","language":"en","steps":[{"id":"10","text":"a step that is yet to be defined","type":"Context","astNodeIds":["0"]}]}} +{"pickle":{"id":"14","uri":"samples/undefined/undefined.feature","astNodeIds":["4"],"tags":[],"name":"Steps before undefined steps are executed","language":"en","steps":[{"id":"12","text":"an implemented step","type":"Context","astNodeIds":["2"]},{"id":"13","text":"a step that is yet to be defined","type":"Context","astNodeIds":["3"]}]}} +{"pickle":{"id":"17","uri":"samples/undefined/undefined.feature","astNodeIds":["7"],"tags":[],"name":"Steps after undefined steps are skipped","language":"en","steps":[{"id":"15","text":"a step that is yet to be defined","type":"Context","astNodeIds":["5"]},{"id":"16","text":"a step that will be skipped","type":"Context","astNodeIds":["6"]}]}} +{"pickle":{"id":"19","uri":"samples/undefined/undefined.feature","astNodeIds":["9"],"tags":[],"name":"Snippets reflect parameter types","language":"en","steps":[{"id":"18","text":"a list of 8 things","type":"Context","astNodeIds":["8"]}]}} +{"stepDefinition":{"id":"20","pattern":{"type":"CUCUMBER_EXPRESSION","source":"an implemented step"},"sourceReference":{"uri":"samples/undefined/undefined.ts","location":{"line":3}}}} +{"stepDefinition":{"id":"21","pattern":{"type":"CUCUMBER_EXPRESSION","source":"a step that will be skipped"},"sourceReference":{"uri":"samples/undefined/undefined.ts","location":{"line":7}}}} +{"testRunStarted":{"id":"22","timestamp":{"seconds":0,"nanos":0}}} +{"testCase":{"id":"23","pickleId":"11","testSteps":[{"id":"24","pickleStepId":"10","stepDefinitionIds":[],"stepMatchArgumentsLists":[]}],"testRunStartedId":"22"}} +{"testCase":{"id":"25","pickleId":"14","testSteps":[{"id":"26","pickleStepId":"12","stepDefinitionIds":["20"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]},{"id":"27","pickleStepId":"13","stepDefinitionIds":[],"stepMatchArgumentsLists":[]}],"testRunStartedId":"22"}} +{"testCase":{"id":"28","pickleId":"17","testSteps":[{"id":"29","pickleStepId":"15","stepDefinitionIds":[],"stepMatchArgumentsLists":[]},{"id":"30","pickleStepId":"16","stepDefinitionIds":["21"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"22"}} +{"testCase":{"id":"31","pickleId":"19","testSteps":[{"id":"32","pickleStepId":"18","stepDefinitionIds":[],"stepMatchArgumentsLists":[]}],"testRunStartedId":"22"}} +{"testCaseStarted":{"id":"33","testCaseId":"23","timestamp":{"seconds":0,"nanos":1000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"33","testStepId":"24","timestamp":{"seconds":0,"nanos":2000000}}} +{"suggestion":{"id":"34","pickleStepId":"10","snippets":[{"language":"typescript","code":"Given(\"a step that is yet to be defined\", () => {\n return \"pending\"\n})"}]}} +{"testStepFinished":{"testCaseStartedId":"33","testStepId":"24","testStepResult":{"status":"UNDEFINED","duration":{"seconds":0,"nanos":0}},"timestamp":{"seconds":0,"nanos":3000000}}} +{"testCaseFinished":{"testCaseStartedId":"33","timestamp":{"seconds":0,"nanos":4000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"35","testCaseId":"25","timestamp":{"seconds":0,"nanos":5000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"35","testStepId":"26","timestamp":{"seconds":0,"nanos":6000000}}} +{"testStepFinished":{"testCaseStartedId":"35","testStepId":"26","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":7000000}}} +{"testStepStarted":{"testCaseStartedId":"35","testStepId":"27","timestamp":{"seconds":0,"nanos":8000000}}} +{"suggestion":{"id":"36","pickleStepId":"13","snippets":[{"language":"typescript","code":"Given(\"a step that is yet to be defined\", () => {\n return \"pending\"\n})"}]}} +{"testStepFinished":{"testCaseStartedId":"35","testStepId":"27","testStepResult":{"status":"UNDEFINED","duration":{"seconds":0,"nanos":0}},"timestamp":{"seconds":0,"nanos":9000000}}} +{"testCaseFinished":{"testCaseStartedId":"35","timestamp":{"seconds":0,"nanos":10000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"37","testCaseId":"28","timestamp":{"seconds":0,"nanos":11000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"37","testStepId":"29","timestamp":{"seconds":0,"nanos":12000000}}} +{"suggestion":{"id":"38","pickleStepId":"15","snippets":[{"language":"typescript","code":"Given(\"a step that is yet to be defined\", () => {\n return \"pending\"\n})"}]}} +{"testStepFinished":{"testCaseStartedId":"37","testStepId":"29","testStepResult":{"status":"UNDEFINED","duration":{"seconds":0,"nanos":0}},"timestamp":{"seconds":0,"nanos":13000000}}} +{"testStepStarted":{"testCaseStartedId":"37","testStepId":"30","timestamp":{"seconds":0,"nanos":14000000}}} +{"testStepFinished":{"testCaseStartedId":"37","testStepId":"30","testStepResult":{"status":"SKIPPED","duration":{"seconds":0,"nanos":0}},"timestamp":{"seconds":0,"nanos":15000000}}} +{"testCaseFinished":{"testCaseStartedId":"37","timestamp":{"seconds":0,"nanos":16000000},"willBeRetried":false}} +{"testCaseStarted":{"id":"39","testCaseId":"31","timestamp":{"seconds":0,"nanos":17000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"39","testStepId":"32","timestamp":{"seconds":0,"nanos":18000000}}} +{"suggestion":{"id":"40","pickleStepId":"18","snippets":[{"language":"typescript","code":"Given(\"a list of {int} things\", (int: number) => {\n return \"pending\"\n})"},{"language":"typescript","code":"Given(\"a list of {float} things\", (float: number) => {\n return \"pending\"\n})"}]}} +{"testStepFinished":{"testCaseStartedId":"39","testStepId":"32","testStepResult":{"status":"UNDEFINED","duration":{"seconds":0,"nanos":0}},"timestamp":{"seconds":0,"nanos":19000000}}} +{"testCaseFinished":{"testCaseStartedId":"39","timestamp":{"seconds":0,"nanos":20000000},"willBeRetried":false}} +{"testRunFinished":{"testRunStartedId":"22","timestamp":{"seconds":0,"nanos":21000000},"success":false}} diff --git a/cucumber_cpp/acceptance_test/compatibility/unknown-parameter-type/unknown-parameter-type.feature b/cucumber_cpp/acceptance_test/compatibility/unknown-parameter-type/unknown-parameter-type.feature new file mode 100644 index 00000000..1d68f1e6 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/unknown-parameter-type/unknown-parameter-type.feature @@ -0,0 +1,7 @@ +Feature: Parameter Types + Cucumber will generate an error message if a step definition registers + an unknown parameter type, but the suite will run. Additionally, because + the step is effectively undefined, a suggestion will also be created. + + Scenario: undefined parameter type + Given CDG is closed because of a strike diff --git a/cucumber_cpp/acceptance_test/compatibility/unknown-parameter-type/unknown-parameter-type.ndjson b/cucumber_cpp/acceptance_test/compatibility/unknown-parameter-type/unknown-parameter-type.ndjson new file mode 100644 index 00000000..0bd30026 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/unknown-parameter-type/unknown-parameter-type.ndjson @@ -0,0 +1,13 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"Feature: Parameter Types\n Cucumber will generate an error message if a step definition registers\n an unknown parameter type, but the suite will run. Additionally, because\n the step is effectively undefined, a suggestion will also be created.\n\n Scenario: undefined parameter type\n Given CDG is closed because of a strike\n","uri":"samples/unknown-parameter-type/unknown-parameter-type.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Parameter Types","description":" Cucumber will generate an error message if a step definition registers\n an unknown parameter type, but the suite will run. Additionally, because\n the step is effectively undefined, a suggestion will also be created.","children":[{"scenario":{"id":"1","tags":[],"location":{"line":6,"column":3},"keyword":"Scenario","name":"undefined parameter type","description":"","steps":[{"id":"0","location":{"line":7,"column":5},"keyword":"Given ","keywordType":"Context","text":"CDG is closed because of a strike"}],"examples":[]}}]},"comments":[],"uri":"samples/unknown-parameter-type/unknown-parameter-type.feature"}} +{"pickle":{"id":"3","uri":"samples/unknown-parameter-type/unknown-parameter-type.feature","astNodeIds":["1"],"tags":[],"name":"undefined parameter type","language":"en","steps":[{"id":"2","text":"CDG is closed because of a strike","type":"Context","astNodeIds":["0"]}]}} +{"undefinedParameterType":{"name":"airport","expression":"{airport} is closed because of a strike"}} +{"testRunStarted":{"id":"5","timestamp":{"seconds":0,"nanos":0}}} +{"testCase":{"id":"6","pickleId":"3","testSteps":[{"id":"7","pickleStepId":"2","stepDefinitionIds":[],"stepMatchArgumentsLists":[]}],"testRunStartedId":"5"}} +{"testCaseStarted":{"id":"8","testCaseId":"6","timestamp":{"seconds":0,"nanos":1000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"8","testStepId":"7","timestamp":{"seconds":0,"nanos":2000000}}} +{"suggestion":{"id":"9","pickleStepId":"2","snippets":[{"language":"typescript","code":"Given(\"CDG is closed because of a strike\", () => {\n return \"pending\"\n})"}]}} +{"testStepFinished":{"testCaseStartedId":"8","testStepId":"7","testStepResult":{"status":"UNDEFINED","duration":{"seconds":0,"nanos":0}},"timestamp":{"seconds":0,"nanos":3000000}}} +{"testCaseFinished":{"testCaseStartedId":"8","timestamp":{"seconds":0,"nanos":4000000},"willBeRetried":false}} +{"testRunFinished":{"testRunStartedId":"5","timestamp":{"seconds":0,"nanos":5000000},"success":false}} diff --git a/cucumber_cpp/acceptance_test/compatibility/unused-steps/unused-steps.feature b/cucumber_cpp/acceptance_test/compatibility/unused-steps/unused-steps.feature new file mode 100644 index 00000000..19c48a29 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/unused-steps/unused-steps.feature @@ -0,0 +1,6 @@ +Feature: Unused steps + Depending on the run, some step definitions may not be used. This is valid, and the step definitions are still + includes in the stream of messages, which allows formatters to report on step usage if desired. + + Scenario: a scenario + Given a step that is used diff --git a/cucumber_cpp/acceptance_test/compatibility/unused-steps/unused-steps.ndjson b/cucumber_cpp/acceptance_test/compatibility/unused-steps/unused-steps.ndjson new file mode 100644 index 00000000..39182bd5 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility/unused-steps/unused-steps.ndjson @@ -0,0 +1,13 @@ +{"meta":{"protocolVersion":"29.0.1","implementation":{"name":"fake-cucumber","version":"123.45.6"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"24.5.0"},"runtime":{"name":"Node.js","version":"24.4.1"},"ci":{"name":"GitHub Actions","url":"https://github.com/cucumber-ltd/shouty.rb/actions/runs/154666429","buildNumber":"154666429","git":{"revision":"99684bcacf01d95875834d87903dcb072306c9ad","remote":"https://github.com/cucumber-ltd/shouty.rb.git","branch":"main"}}}} +{"source":{"data":"Feature: Unused steps\n Depending on the run, some step definitions may not be used. This is valid, and the step definitions are still\n includes in the stream of messages, which allows formatters to report on step usage if desired.\n\n Scenario: a scenario\n Given a step that is used\n","uri":"samples/unused-steps/unused-steps.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[],"location":{"line":1,"column":1},"language":"en","keyword":"Feature","name":"Unused steps","description":" Depending on the run, some step definitions may not be used. This is valid, and the step definitions are still\n includes in the stream of messages, which allows formatters to report on step usage if desired.","children":[{"scenario":{"id":"1","tags":[],"location":{"line":5,"column":3},"keyword":"Scenario","name":"a scenario","description":"","steps":[{"id":"0","location":{"line":6,"column":5},"keyword":"Given ","keywordType":"Context","text":"a step that is used"}],"examples":[]}}]},"comments":[],"uri":"samples/unused-steps/unused-steps.feature"}} +{"pickle":{"id":"3","uri":"samples/unused-steps/unused-steps.feature","astNodeIds":["1"],"tags":[],"name":"a scenario","language":"en","steps":[{"id":"2","text":"a step that is used","type":"Context","astNodeIds":["0"]}]}} +{"stepDefinition":{"id":"4","pattern":{"type":"CUCUMBER_EXPRESSION","source":"a step that is used"},"sourceReference":{"uri":"samples/unused-steps/unused-steps.ts","location":{"line":3}}}} +{"stepDefinition":{"id":"5","pattern":{"type":"CUCUMBER_EXPRESSION","source":"a step that is not used"},"sourceReference":{"uri":"samples/unused-steps/unused-steps.ts","location":{"line":7}}}} +{"testRunStarted":{"id":"6","timestamp":{"seconds":0,"nanos":0}}} +{"testCase":{"id":"7","pickleId":"3","testSteps":[{"id":"8","pickleStepId":"2","stepDefinitionIds":["4"],"stepMatchArgumentsLists":[{"stepMatchArguments":[]}]}],"testRunStartedId":"6"}} +{"testCaseStarted":{"id":"9","testCaseId":"7","timestamp":{"seconds":0,"nanos":1000000},"attempt":0}} +{"testStepStarted":{"testCaseStartedId":"9","testStepId":"8","timestamp":{"seconds":0,"nanos":2000000}}} +{"testStepFinished":{"testCaseStartedId":"9","testStepId":"8","testStepResult":{"status":"PASSED","duration":{"seconds":0,"nanos":1000000}},"timestamp":{"seconds":0,"nanos":3000000}}} +{"testCaseFinished":{"testCaseStartedId":"9","timestamp":{"seconds":0,"nanos":4000000},"willBeRetried":false}} +{"testRunFinished":{"testRunStartedId":"6","timestamp":{"seconds":0,"nanos":5000000},"success":true}} diff --git a/cucumber_cpp/library/Application.cpp b/cucumber_cpp/library/Application.cpp index 934700eb..a76c8339 100644 --- a/cucumber_cpp/library/Application.cpp +++ b/cucumber_cpp/library/Application.cpp @@ -13,6 +13,7 @@ #include "cucumber_cpp/library/engine/TestExecution.hpp" #include "cucumber_cpp/library/engine/TestRunner.hpp" #include "cucumber_cpp/library/report/JunitReport.hpp" +#include "cucumber_cpp/library/report/NdjsonReport.hpp" #include "cucumber_cpp/library/report/Report.hpp" #include "cucumber_cpp/library/report/StdOutReport.hpp" #include @@ -121,6 +122,7 @@ namespace cucumber_cpp::library reporters.Add("console", std::make_unique()); reporters.Add("junit-xml", std::make_unique(options.outputfolder, options.reportfile)); + reporters.Add("ndjson", std::make_unique(options.outputfolder, options.reportfile)); ProgramContext().InsertRef(options); } diff --git a/cucumber_cpp/library/cucumber_expression/Ast.cpp b/cucumber_cpp/library/cucumber_expression/Ast.cpp index 79542357..14bf4645 100644 --- a/cucumber_cpp/library/cucumber_expression/Ast.cpp +++ b/cucumber_cpp/library/cucumber_expression/Ast.cpp @@ -115,12 +115,12 @@ namespace cucumber_cpp::library::cucumber_expression return end; } - bool Token::IsEscapeCharacter(char ch) + bool Token::IsEscapeCharacter(unsigned char ch) { return ch == '\\'; } - TokenType Token::TypeOf(char ch) + TokenType Token::TypeOf(unsigned char ch) { if (std::isspace(static_cast(ch)) != 0) return TokenType::whiteSpace; @@ -131,7 +131,7 @@ namespace cucumber_cpp::library::cucumber_expression return TokenType::text; } - bool Token::CanEscape(char ch) + bool Token::CanEscape(unsigned char ch) { if (std::isspace(static_cast(ch)) != 0) return true; diff --git a/cucumber_cpp/library/cucumber_expression/Ast.hpp b/cucumber_cpp/library/cucumber_expression/Ast.hpp index caa64fd6..4017e674 100644 --- a/cucumber_cpp/library/cucumber_expression/Ast.hpp +++ b/cucumber_cpp/library/cucumber_expression/Ast.hpp @@ -69,9 +69,9 @@ namespace cucumber_cpp::library::cucumber_expression std::size_t Start() const; std::size_t End() const; - static bool IsEscapeCharacter(char ch); - static TokenType TypeOf(char ch); - static bool CanEscape(char ch); + static bool IsEscapeCharacter(unsigned char ch); + static TokenType TypeOf(unsigned char ch); + static bool CanEscape(unsigned char ch); static std::string NameOf(TokenType type); static std::string SymbolOf(TokenType type); static std::string PurposeOf(TokenType type); diff --git a/cucumber_cpp/library/report/CMakeLists.txt b/cucumber_cpp/library/report/CMakeLists.txt index bba15987..e9beb1d2 100644 --- a/cucumber_cpp/library/report/CMakeLists.txt +++ b/cucumber_cpp/library/report/CMakeLists.txt @@ -3,6 +3,8 @@ add_library(cucumber_cpp.library.report STATIC ${CCR_EXCLUDE_FROM_ALL}) target_sources(cucumber_cpp.library.report PRIVATE JunitReport.cpp JunitReport.hpp + NdjsonReport.cpp + NdjsonReport.hpp Report.cpp Report.hpp StdOutReport.cpp diff --git a/cucumber_cpp/library/report/NdjsonReport.cpp b/cucumber_cpp/library/report/NdjsonReport.cpp new file mode 100644 index 00000000..4e979d99 --- /dev/null +++ b/cucumber_cpp/library/report/NdjsonReport.cpp @@ -0,0 +1,71 @@ +#include "NdjsonReport.hpp" + +namespace cucumber_cpp::library::report +{ + namespace + { + + } + + NdjsonReport::NdjsonReport(const std::string& outputfolder, const std::string& reportfile) + { + + } + + NdjsonReport::~NdjsonReport() + = default; + + void NdjsonReport::FeatureStart(const engine::FeatureInfo& featureInfo) + { + + } + + void NdjsonReport::FeatureEnd(engine::Result result, const engine::FeatureInfo& featureInfo, TraceTime::Duration duration) + { + } + + void NdjsonReport::RuleStart(const engine::RuleInfo& ruleInfo) + { + } + + void NdjsonReport::RuleEnd(engine::Result result, const engine::RuleInfo& ruleInfo, TraceTime::Duration duration) + { + } + + void NdjsonReport::ScenarioStart(const engine::ScenarioInfo& scenarioInfo) + { + } + + void NdjsonReport::ScenarioEnd(engine::Result result, const engine::ScenarioInfo& scenarioInfo, TraceTime::Duration duration) + { + } + + void NdjsonReport::StepSkipped(const engine::StepInfo& stepInfo) + { + } + + void NdjsonReport::StepStart(const engine::StepInfo& stepInfo) + { + } + + void NdjsonReport::StepEnd(engine::Result result, const engine::StepInfo& stepInfo, TraceTime::Duration duration) + { + } + + void NdjsonReport::Failure(const std::string& error, std::optional path, std::optional line, std::optional column) + { + } + + void NdjsonReport::Error(const std::string& error, std::optional path, std::optional line, std::optional column) + { + } + + void NdjsonReport::Trace(const std::string& trace) + { + } + + void NdjsonReport::Summary(TraceTime::Duration duration) + { + } + +} diff --git a/cucumber_cpp/library/report/NdjsonReport.hpp b/cucumber_cpp/library/report/NdjsonReport.hpp new file mode 100644 index 00000000..6cbc1972 --- /dev/null +++ b/cucumber_cpp/library/report/NdjsonReport.hpp @@ -0,0 +1,26 @@ +#pragma once +#include "Report.hpp" + +namespace cucumber_cpp::library::report +{ + struct NdjsonReport : ReportHandlerV2 + { + NdjsonReport(const std::string& outputfolder, const std::string& reportfile); + ~NdjsonReport() override; + + void FeatureStart(const engine::FeatureInfo& featureInfo) override; + void FeatureEnd(engine::Result result, const engine::FeatureInfo& featureInfo, TraceTime::Duration duration) override; + void RuleStart(const engine::RuleInfo& ruleInfo) override; + void RuleEnd(engine::Result result, const engine::RuleInfo& ruleInfo, TraceTime::Duration duration) override; + void ScenarioStart(const engine::ScenarioInfo& scenarioInfo) override; + void ScenarioEnd(engine::Result result, const engine::ScenarioInfo& scenarioInfo, TraceTime::Duration duration) override; + void StepSkipped(const engine::StepInfo& stepInfo) override; + void StepStart(const engine::StepInfo& stepInfo) override; + void StepEnd(engine::Result result, const engine::StepInfo& stepInfo, TraceTime::Duration duration) override; + void Failure(const std::string& error, std::optional path, std::optional line, std::optional column) override; + void Error(const std::string& error, std::optional path, std::optional line, std::optional column) override; + void Trace(const std::string& trace) override; + void Summary(TraceTime::Duration duration) override; + }; + +} From 46710e4b8f6f57354af00f5ce5c3f62dea9a14bf Mon Sep 17 00:00:00 2001 From: Alexander Romanenko Date: Fri, 24 Oct 2025 23:46:37 +0300 Subject: [PATCH 05/16] feat: ndjson reporting - Begin adding ndjson report writer and add compatibility validation tests. --- cucumber_cpp/library/report/JunitReport.cpp | 9 ------ cucumber_cpp/library/report/NdjsonReport.cpp | 34 ++++++++++++++++++-- cucumber_cpp/library/report/NdjsonReport.hpp | 9 +++++- 3 files changed, 39 insertions(+), 13 deletions(-) diff --git a/cucumber_cpp/library/report/JunitReport.cpp b/cucumber_cpp/library/report/JunitReport.cpp index 3b321169..b6c219dc 100644 --- a/cucumber_cpp/library/report/JunitReport.cpp +++ b/cucumber_cpp/library/report/JunitReport.cpp @@ -24,15 +24,6 @@ namespace cucumber_cpp::library::report { constexpr double precision = 0.0000001; - const std::map successLut{ - { engine::Result::passed, "done" }, - { engine::Result::skipped, "skipped" }, - { engine::Result::failed, "failed" }, - { engine::Result::pending, "pending" }, - { engine::Result::ambiguous, "ambiguous" }, - { engine::Result::undefined, "undefined" }, - }; - std::string RoundTo(double value, double roundToPrecision) { const auto d = std::round(value / roundToPrecision) * roundToPrecision; diff --git a/cucumber_cpp/library/report/NdjsonReport.cpp b/cucumber_cpp/library/report/NdjsonReport.cpp index 4e979d99..6c46f940 100644 --- a/cucumber_cpp/library/report/NdjsonReport.cpp +++ b/cucumber_cpp/library/report/NdjsonReport.cpp @@ -1,4 +1,5 @@ #include "NdjsonReport.hpp" +#include namespace cucumber_cpp::library::report { @@ -7,13 +8,40 @@ namespace cucumber_cpp::library::report } - NdjsonReport::NdjsonReport(const std::string& outputfolder, const std::string& reportfile) + NdjsonReport::NdjsonReport(const std::string& outputFolder, const std::string& reportFile) + : outputFolder(outputFolder) + , reportFile(reportFile) { - } NdjsonReport::~NdjsonReport() - = default; + { + try + { + if (!std::filesystem::exists(outputFolder)) + { + std::filesystem::create_directories(outputFolder); + + const std::filesystem::path outputFile = std::filesystem::path{ outputFolder }.append(reportFile + ".ndjson"); + std::ofstream out(outputFile); + for (nlohmann::json& jsonEvent : docs) + { + out << jsonEvent; + } + + out.close(); + } + } + catch (const std::filesystem::filesystem_error& ex) + { + std::cout << "\nwhat(): " << ex.what() << '\n' + << "path1(): " << ex.path1() << '\n' + << "path2(): " << ex.path2() << '\n' + << "code().value(): " << ex.code().value() << '\n' + << "code().message(): " << ex.code().message() << '\n' + << "code().category(): " << ex.code().category().name() << '\n'; + } + } void NdjsonReport::FeatureStart(const engine::FeatureInfo& featureInfo) { diff --git a/cucumber_cpp/library/report/NdjsonReport.hpp b/cucumber_cpp/library/report/NdjsonReport.hpp index 6cbc1972..0c2a1f84 100644 --- a/cucumber_cpp/library/report/NdjsonReport.hpp +++ b/cucumber_cpp/library/report/NdjsonReport.hpp @@ -1,11 +1,12 @@ #pragma once #include "Report.hpp" +#include namespace cucumber_cpp::library::report { struct NdjsonReport : ReportHandlerV2 { - NdjsonReport(const std::string& outputfolder, const std::string& reportfile); + NdjsonReport(const std::string& outputFolder, const std::string& reportFile); ~NdjsonReport() override; void FeatureStart(const engine::FeatureInfo& featureInfo) override; @@ -21,6 +22,12 @@ namespace cucumber_cpp::library::report void Error(const std::string& error, std::optional path, std::optional line, std::optional column) override; void Trace(const std::string& trace) override; void Summary(TraceTime::Duration duration) override; + + private: + const std::string& outputFolder; + const std::string& reportFile; + + std::vector docs; }; } From 0ede5f917d0cebb9c88e8e5c4d604e676af7c1ba Mon Sep 17 00:00:00 2001 From: Aleksander Romanenko Date: Wed, 29 Oct 2025 22:37:36 +0300 Subject: [PATCH 06/16] feat: ndjson reporting - Add SourceInfo class to be able to handle source ndjson. Since it contains path information, move path output to it. --- cucumber_cpp/library/Application.cpp | 2 +- cucumber_cpp/library/engine/CMakeLists.txt | 2 ++ .../library/engine/FeatureFactory.cpp | 14 +++++++---- cucumber_cpp/library/engine/FeatureInfo.cpp | 13 +++++++--- cucumber_cpp/library/engine/FeatureInfo.hpp | 7 ++++-- cucumber_cpp/library/engine/SourceInfo.cpp | 22 +++++++++++++++++ cucumber_cpp/library/engine/SourceInfo.hpp | 24 +++++++++++++++++++ cucumber_cpp/library/report/NdjsonReport.cpp | 7 +++++- 8 files changed, 80 insertions(+), 11 deletions(-) create mode 100644 cucumber_cpp/library/engine/SourceInfo.cpp create mode 100644 cucumber_cpp/library/engine/SourceInfo.hpp diff --git a/cucumber_cpp/library/Application.cpp b/cucumber_cpp/library/Application.cpp index a76c8339..7857e248 100644 --- a/cucumber_cpp/library/Application.cpp +++ b/cucumber_cpp/library/Application.cpp @@ -100,7 +100,7 @@ namespace cucumber_cpp::library , removeDefaultGoogleTestListener{ removeDefaultGoogleTestListener } { - gherkin.include_source(false); + gherkin.include_source(true); gherkin.include_ast(true); gherkin.include_pickles(true); diff --git a/cucumber_cpp/library/engine/CMakeLists.txt b/cucumber_cpp/library/engine/CMakeLists.txt index 06594974..bd38b65e 100644 --- a/cucumber_cpp/library/engine/CMakeLists.txt +++ b/cucumber_cpp/library/engine/CMakeLists.txt @@ -13,6 +13,8 @@ target_sources(cucumber_cpp.library.engine PRIVATE RuleInfo.hpp ScenarioInfo.cpp ScenarioInfo.hpp + SourceInfo.cpp + SourceInfo.hpp Step.cpp Step.hpp StepInfo.cpp diff --git a/cucumber_cpp/library/engine/FeatureFactory.cpp b/cucumber_cpp/library/engine/FeatureFactory.cpp index b254e627..f1ce8516 100644 --- a/cucumber_cpp/library/engine/FeatureFactory.cpp +++ b/cucumber_cpp/library/engine/FeatureFactory.cpp @@ -1,4 +1,5 @@ #include "cucumber_cpp/library/engine/FeatureFactory.hpp" +#include "SourceInfo.hpp" #include "cucumber/gherkin/app.hpp" #include "cucumber/gherkin/file.hpp" #include "cucumber/gherkin/parse_error.hpp" @@ -283,13 +284,13 @@ namespace cucumber_cpp::library::engine std::visit(visitor, flatAst.at(pickle.ast_node_ids.front())); } - std::unique_ptr FeatureFactory(std::filesystem::path path, const cucumber::gherkin::app::parser_result& ast) + std::unique_ptr FeatureFactory(std::unique_ptr sourceInfo, const cucumber::gherkin::app::parser_result& ast) { return std::make_unique( TagsFactory(ast.feature->tags), ast.feature->name, ast.feature->description, - std::move(path), + std::move(sourceInfo), ast.feature->location.line, ast.feature->location.column.value_or(0)); } @@ -319,12 +320,17 @@ namespace cucumber_cpp::library::engine std::unique_ptr FeatureTreeFactory::Create(const std::filesystem::path& path, std::string_view tagExpression) const { std::unique_ptr featureInfo; + std::unique_ptr sourceInfo; std::optional flatAst; cucumber::gherkin::app::callbacks callbacks{ - .ast = [&path, &flatAst, &featureInfo](const cucumber::gherkin::app::parser_result& ast) + .source = [&sourceInfo, &path](const cucumber::messages::source& source) { - featureInfo = FeatureFactory(path, ast); + sourceInfo = std::make_unique(std::move(path), source); + }, + .ast = [&sourceInfo, &flatAst, &featureInfo](const cucumber::gherkin::app::parser_result& ast) + { + featureInfo = FeatureFactory(std::move(sourceInfo), ast); flatAst = FlattenAst(*ast.feature); }, .pickle = [this, &featureInfo, &flatAst, &tagExpression](const cucumber::messages::pickle& pickle) diff --git a/cucumber_cpp/library/engine/FeatureInfo.cpp b/cucumber_cpp/library/engine/FeatureInfo.cpp index 016f964c..6d271675 100644 --- a/cucumber_cpp/library/engine/FeatureInfo.cpp +++ b/cucumber_cpp/library/engine/FeatureInfo.cpp @@ -1,4 +1,5 @@ #include "cucumber_cpp/library/engine/FeatureInfo.hpp" +#include "SourceInfo.hpp" #include "cucumber_cpp/library/engine/RuleInfo.hpp" #include "cucumber_cpp/library/engine/ScenarioInfo.hpp" #include @@ -12,16 +13,22 @@ namespace cucumber_cpp::library::engine { - FeatureInfo::FeatureInfo(std::set> tags, std::string title, std::string description, std::filesystem::path path, std::size_t line, std::size_t column) + FeatureInfo::FeatureInfo(std::set> tags, std::string title, std::string description, std::unique_ptr sourceInfo, std::size_t line, std::size_t column) : tags{ std::move(tags) } , title{ std::move(title) } , description{ std::move(description) } - , path{ std::move(path) } + , sourceInfo{ std::move(sourceInfo) } , line{ line } , column{ column } { } + SourceInfo* FeatureInfo::SourceInfo() const + { + return sourceInfo.get(); + } + + const std::set>& FeatureInfo::Tags() const { return tags; @@ -39,7 +46,7 @@ namespace cucumber_cpp::library::engine const std::filesystem::path& FeatureInfo::Path() const { - return path; + return sourceInfo->Path(); } std::size_t FeatureInfo::Line() const diff --git a/cucumber_cpp/library/engine/FeatureInfo.hpp b/cucumber_cpp/library/engine/FeatureInfo.hpp index 1cf18401..b5662fb9 100644 --- a/cucumber_cpp/library/engine/FeatureInfo.hpp +++ b/cucumber_cpp/library/engine/FeatureInfo.hpp @@ -3,6 +3,7 @@ #include "cucumber_cpp/library/engine/RuleInfo.hpp" #include "cucumber_cpp/library/engine/ScenarioInfo.hpp" +#include "SourceInfo.hpp" #include #include #include @@ -15,7 +16,9 @@ namespace cucumber_cpp::library::engine { struct FeatureInfo { - FeatureInfo(std::set> tags, std::string title, std::string description, std::filesystem::path path, std::size_t line, std::size_t column); + FeatureInfo(std::set> tags, std::string title, std::string description, std::unique_ptr, std::size_t line, std::size_t column); + + [[nodiscard]] SourceInfo* SourceInfo() const; [[nodiscard]] const std::set>& Tags() const; [[nodiscard]] const std::string& Title() const; @@ -37,7 +40,7 @@ namespace cucumber_cpp::library::engine std::string title; std::string description; - std::filesystem::path path; + std::unique_ptr sourceInfo; std::size_t line; std::size_t column; diff --git a/cucumber_cpp/library/engine/SourceInfo.cpp b/cucumber_cpp/library/engine/SourceInfo.cpp new file mode 100644 index 00000000..755804fe --- /dev/null +++ b/cucumber_cpp/library/engine/SourceInfo.cpp @@ -0,0 +1,22 @@ +#include "SourceInfo.hpp" + +namespace cucumber_cpp::library::engine +{ + + SourceInfo::SourceInfo(std::filesystem::path path, const cucumber::messages::source& source) + : path(std::move(path)) + , source(std::move(source)) + { + + } + + const std::filesystem::path& SourceInfo::Path() const + { + return path; + } + + std::string SourceInfo::ToJson() const + { + return source.to_json(); + } +} diff --git a/cucumber_cpp/library/engine/SourceInfo.hpp b/cucumber_cpp/library/engine/SourceInfo.hpp new file mode 100644 index 00000000..8220ddab --- /dev/null +++ b/cucumber_cpp/library/engine/SourceInfo.hpp @@ -0,0 +1,24 @@ +#ifndef CUCUMBER_CPP_RUNNER_SOURCEINFO_H +#define CUCUMBER_CPP_RUNNER_SOURCEINFO_H +#include "cucumber/messages/source.hpp" + +#include + +namespace cucumber_cpp::library::engine +{ + struct SourceInfo + { + SourceInfo(std::filesystem::path path, const cucumber::messages::source& source); + + const std::filesystem::path& Path() const; + + std::string ToJson() const; + + private: + const cucumber::messages::source source; + std::filesystem::path path; + }; + +} + +#endif diff --git a/cucumber_cpp/library/report/NdjsonReport.cpp b/cucumber_cpp/library/report/NdjsonReport.cpp index 6c46f940..9f4b270c 100644 --- a/cucumber_cpp/library/report/NdjsonReport.cpp +++ b/cucumber_cpp/library/report/NdjsonReport.cpp @@ -1,4 +1,5 @@ #include "NdjsonReport.hpp" +#include #include namespace cucumber_cpp::library::report @@ -45,7 +46,11 @@ namespace cucumber_cpp::library::report void NdjsonReport::FeatureStart(const engine::FeatureInfo& featureInfo) { - + engine::SourceInfo* sourceInfo = featureInfo.SourceInfo(); + const std::filesystem::path& path = sourceInfo->Path(); + std::string stringPath = path.string(); + std::string sourceJson = featureInfo.SourceInfo()->ToJson(); + // gherkinDocument from featureInfo } void NdjsonReport::FeatureEnd(engine::Result result, const engine::FeatureInfo& featureInfo, TraceTime::Duration duration) From 60fb20dfb64defcc6950287e786fb400e2251e36 Mon Sep 17 00:00:00 2001 From: Aleksander Romanenko Date: Mon, 3 Nov 2025 11:27:35 +0300 Subject: [PATCH 07/16] feat: ndjson reporting - fix creation of reporters so they are not instantiated during CLI parsing stage. This causes their destructor to always run at the end, which writes report to the file system whether that reporter was requested or not. Use factory method instead. --- cucumber_cpp/library/Application.cpp | 11 +++-------- cucumber_cpp/library/Application.hpp | 2 -- cucumber_cpp/library/report/Report.cpp | 6 +++--- cucumber_cpp/library/report/Report.hpp | 4 ++-- 4 files changed, 8 insertions(+), 15 deletions(-) diff --git a/cucumber_cpp/library/Application.cpp b/cucumber_cpp/library/Application.cpp index 7857e248..a418cdfa 100644 --- a/cucumber_cpp/library/Application.cpp +++ b/cucumber_cpp/library/Application.cpp @@ -120,9 +120,9 @@ namespace cucumber_cpp::library runCommand->add_flag("--dry", options.dryrun, "Generate report without running tests"); runCommand->add_flag("--unused", options.printStepsNotUsed, "Show step definitions that were not used"); - reporters.Add("console", std::make_unique()); - reporters.Add("junit-xml", std::make_unique(options.outputfolder, options.reportfile)); - reporters.Add("ndjson", std::make_unique(options.outputfolder, options.reportfile)); + reporters.Add("console", [] { return std::make_unique();}); + reporters.Add("junit-xml", [this] { return std::make_unique(options.outputfolder, options.reportfile); }); + reporters.Add("ndjson", [this] { return std::make_unique(options.outputfolder, options.reportfile); }); ProgramContext().InsertRef(options); } @@ -189,11 +189,6 @@ namespace cucumber_cpp::library return parameterRegistry; } - void Application::AddReportHandler(const std::string& name, std::unique_ptr&& reporter) - { - reporters.Add(name, std::move(reporter)); - } - void Application::RunFeatures() { for (const auto& selectedReporter : options.reporters) diff --git a/cucumber_cpp/library/Application.hpp b/cucumber_cpp/library/Application.hpp index 989baea1..61162eb6 100644 --- a/cucumber_cpp/library/Application.hpp +++ b/cucumber_cpp/library/Application.hpp @@ -52,8 +52,6 @@ namespace cucumber_cpp::library Context& ProgramContext(); cucumber_expression::ParameterRegistration& ParameterRegistration(); - void AddReportHandler(const std::string& name, std::unique_ptr&& reporter); - private: void DryRunFeatures(); void RunFeatures(); diff --git a/cucumber_cpp/library/report/Report.cpp b/cucumber_cpp/library/report/Report.cpp index 3ca74a18..d212fad5 100644 --- a/cucumber_cpp/library/report/Report.cpp +++ b/cucumber_cpp/library/report/Report.cpp @@ -26,15 +26,15 @@ namespace cucumber_cpp::library::report } } - void Reporters::Add(const std::string& name, std::unique_ptr reporter) + void Reporters::Add(const std::string& name, std::function()> reporterFactory) { - availableReporters[name] = std::move(reporter); + availableReporters[name] = std::move(reporterFactory); } void Reporters::Use(const std::string& name) { if (availableReporters[name]) - Add(std::move(availableReporters[name])); + Add(std::move(availableReporters[name]())); } void Reporters::Add(std::unique_ptr report) diff --git a/cucumber_cpp/library/report/Report.hpp b/cucumber_cpp/library/report/Report.hpp index a70b6f15..84134606 100644 --- a/cucumber_cpp/library/report/Report.hpp +++ b/cucumber_cpp/library/report/Report.hpp @@ -56,7 +56,7 @@ namespace cucumber_cpp::library::report struct Reporters { - void Add(const std::string& name, std::unique_ptr reporter); + void Add(const std::string& name, std::function()> reporterFactory); void Use(const std::string& name); [[nodiscard]] std::vector AvailableReporters() const; @@ -66,7 +66,7 @@ namespace cucumber_cpp::library::report std::vector>& Storage(); private: - std::map, std::less<>> availableReporters; + std::map()>, std::less<>> availableReporters; std::vector> reporters; }; From 1c01aeba9b3e2080b10779cdc329d936b54693a1 Mon Sep 17 00:00:00 2001 From: Aleksander Romanenko Date: Tue, 4 Nov 2025 00:10:18 +0300 Subject: [PATCH 08/16] feat: ndjson reporting - keep cucumber::messages::feature in the FeatureInfo because it has needed to_json call. Other properties can then be accessed through it without data duplication in memory. --- .../library/engine/FeatureFactory.cpp | 27 +++++--------- cucumber_cpp/library/engine/FeatureInfo.cpp | 28 ++++++++------- cucumber_cpp/library/engine/FeatureInfo.hpp | 16 ++++----- cucumber_cpp/library/engine/SourceInfo.cpp | 6 ++-- cucumber_cpp/library/engine/SourceInfo.hpp | 7 ++-- cucumber_cpp/library/report/NdjsonReport.cpp | 36 +++++++++++-------- cucumber_cpp/library/report/NdjsonReport.hpp | 6 ++-- 7 files changed, 64 insertions(+), 62 deletions(-) diff --git a/cucumber_cpp/library/engine/FeatureFactory.cpp b/cucumber_cpp/library/engine/FeatureFactory.cpp index f1ce8516..1f48fb1c 100644 --- a/cucumber_cpp/library/engine/FeatureFactory.cpp +++ b/cucumber_cpp/library/engine/FeatureFactory.cpp @@ -148,12 +148,6 @@ namespace cucumber_cpp::library::engine return optionalPickleStepArgument.value().doc_string.value().content; } - std::set> TagsFactory(const std::vector& tags) - { - const auto range = tags | std::views::transform(&cucumber::messages::tag::name); - return { range.begin(), range.end() }; - } - std::set> TagsFactory(const std::vector& tags) { const auto range = tags | std::views::transform(&cucumber::messages::pickle_tag::name); @@ -287,12 +281,9 @@ namespace cucumber_cpp::library::engine std::unique_ptr FeatureFactory(std::unique_ptr sourceInfo, const cucumber::gherkin::app::parser_result& ast) { return std::make_unique( - TagsFactory(ast.feature->tags), - ast.feature->name, - ast.feature->description, - std::move(sourceInfo), - ast.feature->location.line, - ast.feature->location.column.value_or(0)); + ast.feature.value(), + std::move(sourceInfo) + ); } } @@ -323,21 +314,21 @@ namespace cucumber_cpp::library::engine std::unique_ptr sourceInfo; std::optional flatAst; - cucumber::gherkin::app::callbacks callbacks{ - .source = [&sourceInfo, &path](const cucumber::messages::source& source) + const cucumber::gherkin::app::callbacks callbacks{ + .source = [&sourceInfo, &path](const cucumber::messages::source& source) -> void { - sourceInfo = std::make_unique(std::move(path), source); + sourceInfo = std::make_unique(path, source); }, - .ast = [&sourceInfo, &flatAst, &featureInfo](const cucumber::gherkin::app::parser_result& ast) + .ast = [&sourceInfo, &flatAst, &featureInfo](const cucumber::gherkin::app::parser_result& ast) -> void { featureInfo = FeatureFactory(std::move(sourceInfo), ast); flatAst = FlattenAst(*ast.feature); }, - .pickle = [this, &featureInfo, &flatAst, &tagExpression](const cucumber::messages::pickle& pickle) + .pickle = [this, &featureInfo, &flatAst, &tagExpression](const cucumber::messages::pickle& pickle) -> void { ConstructScenario(*this, *featureInfo, *flatAst, pickle, tagExpression); }, - .error = [](const cucumber::gherkin::parse_error& /* _ */) + .error = [](const cucumber::gherkin::parse_error& /* _ */) -> void { /* not handled yet */ } diff --git a/cucumber_cpp/library/engine/FeatureInfo.cpp b/cucumber_cpp/library/engine/FeatureInfo.cpp index 6d271675..2961f9ec 100644 --- a/cucumber_cpp/library/engine/FeatureInfo.cpp +++ b/cucumber_cpp/library/engine/FeatureInfo.cpp @@ -13,13 +13,9 @@ namespace cucumber_cpp::library::engine { - FeatureInfo::FeatureInfo(std::set> tags, std::string title, std::string description, std::unique_ptr sourceInfo, std::size_t line, std::size_t column) - : tags{ std::move(tags) } - , title{ std::move(title) } - , description{ std::move(description) } + FeatureInfo::FeatureInfo(cucumber::messages::feature feature, std::unique_ptr sourceInfo) + : feature{ std::move(feature) } , sourceInfo{ std::move(sourceInfo) } - , line{ line } - , column{ column } { } @@ -28,20 +24,20 @@ namespace cucumber_cpp::library::engine return sourceInfo.get(); } - - const std::set>& FeatureInfo::Tags() const + std::set> FeatureInfo::Tags() const { - return tags; + const auto range = feature.tags | std::views::transform(&cucumber::messages::tag::name); + return { range.begin(), range.end() }; } const std::string& FeatureInfo::Title() const { - return title; + return feature.name; } const std::string& FeatureInfo::Description() const { - return description; + return feature.description; } const std::filesystem::path& FeatureInfo::Path() const @@ -51,12 +47,12 @@ namespace cucumber_cpp::library::engine std::size_t FeatureInfo::Line() const { - return line; + return feature.location.line; } std::size_t FeatureInfo::Column() const { - return column; + return feature.location.column.value_or(0); } std::vector>& FeatureInfo::Rules() @@ -79,4 +75,10 @@ namespace cucumber_cpp::library::engine return scenarios; } + std::string FeatureInfo::ToJson() const + { + return feature.to_json(); + } + + } diff --git a/cucumber_cpp/library/engine/FeatureInfo.hpp b/cucumber_cpp/library/engine/FeatureInfo.hpp index b5662fb9..1b02812c 100644 --- a/cucumber_cpp/library/engine/FeatureInfo.hpp +++ b/cucumber_cpp/library/engine/FeatureInfo.hpp @@ -1,9 +1,10 @@ #ifndef ENGINE_FEATUREINFO_HPP #define ENGINE_FEATUREINFO_HPP +#include "SourceInfo.hpp" #include "cucumber_cpp/library/engine/RuleInfo.hpp" #include "cucumber_cpp/library/engine/ScenarioInfo.hpp" -#include "SourceInfo.hpp" +#include "cucumber/messages/feature.hpp" #include #include #include @@ -16,11 +17,11 @@ namespace cucumber_cpp::library::engine { struct FeatureInfo { - FeatureInfo(std::set> tags, std::string title, std::string description, std::unique_ptr, std::size_t line, std::size_t column); + FeatureInfo(cucumber::messages::feature, std::unique_ptr); [[nodiscard]] SourceInfo* SourceInfo() const; - [[nodiscard]] const std::set>& Tags() const; + [[nodiscard]] std::set> Tags() const; [[nodiscard]] const std::string& Title() const; [[nodiscard]] const std::string& Description() const; @@ -35,16 +36,13 @@ namespace cucumber_cpp::library::engine [[nodiscard]] std::vector>& Scenarios(); [[nodiscard]] const std::vector>& Scenarios() const; + [[nodiscard]] std::string ToJson() const; + private: - std::set> tags; - std::string title; - std::string description; + cucumber::messages::feature feature; std::unique_ptr sourceInfo; - std::size_t line; - std::size_t column; - std::vector> rules; std::vector> scenarios; }; diff --git a/cucumber_cpp/library/engine/SourceInfo.cpp b/cucumber_cpp/library/engine/SourceInfo.cpp index 755804fe..358d2cd3 100644 --- a/cucumber_cpp/library/engine/SourceInfo.cpp +++ b/cucumber_cpp/library/engine/SourceInfo.cpp @@ -3,9 +3,9 @@ namespace cucumber_cpp::library::engine { - SourceInfo::SourceInfo(std::filesystem::path path, const cucumber::messages::source& source) - : path(std::move(path)) - , source(std::move(source)) + SourceInfo::SourceInfo(std::filesystem::path path, cucumber::messages::source source) + : source(std::move(source)) + , path(std::move(path)) { } diff --git a/cucumber_cpp/library/engine/SourceInfo.hpp b/cucumber_cpp/library/engine/SourceInfo.hpp index 8220ddab..74870afd 100644 --- a/cucumber_cpp/library/engine/SourceInfo.hpp +++ b/cucumber_cpp/library/engine/SourceInfo.hpp @@ -1,5 +1,6 @@ #ifndef CUCUMBER_CPP_RUNNER_SOURCEINFO_H #define CUCUMBER_CPP_RUNNER_SOURCEINFO_H + #include "cucumber/messages/source.hpp" #include @@ -8,11 +9,11 @@ namespace cucumber_cpp::library::engine { struct SourceInfo { - SourceInfo(std::filesystem::path path, const cucumber::messages::source& source); + SourceInfo(std::filesystem::path path, cucumber::messages::source source); - const std::filesystem::path& Path() const; + [[nodiscard]] const std::filesystem::path& Path() const; - std::string ToJson() const; + [[nodiscard]] std::string ToJson() const; private: const cucumber::messages::source source; diff --git a/cucumber_cpp/library/report/NdjsonReport.cpp b/cucumber_cpp/library/report/NdjsonReport.cpp index 9f4b270c..a213da8e 100644 --- a/cucumber_cpp/library/report/NdjsonReport.cpp +++ b/cucumber_cpp/library/report/NdjsonReport.cpp @@ -16,22 +16,27 @@ namespace cucumber_cpp::library::report } NdjsonReport::~NdjsonReport() + { + outStream.close(); + } + + + /* + * Unlike XML reporter, where a single document is built up over time and then has to be flushed out in the end all at once, + * NDJSON is a series of individual json objects appended one after another as the test run progresses. + * Therefore, need to prepare a stream on first call to the reporter + */ + void NdjsonReport::InitReportDirectory() { try { if (!std::filesystem::exists(outputFolder)) { std::filesystem::create_directories(outputFolder); - - const std::filesystem::path outputFile = std::filesystem::path{ outputFolder }.append(reportFile + ".ndjson"); - std::ofstream out(outputFile); - for (nlohmann::json& jsonEvent : docs) - { - out << jsonEvent; - } - - out.close(); } + + const std::filesystem::path outputFile = std::filesystem::path{ outputFolder }.append(reportFile + ".ndjson"); + outStream.open(outputFile, std::ios::trunc); } catch (const std::filesystem::filesystem_error& ex) { @@ -44,17 +49,20 @@ namespace cucumber_cpp::library::report } } + void NdjsonReport::FeatureStart(const engine::FeatureInfo& featureInfo) { - engine::SourceInfo* sourceInfo = featureInfo.SourceInfo(); - const std::filesystem::path& path = sourceInfo->Path(); - std::string stringPath = path.string(); - std::string sourceJson = featureInfo.SourceInfo()->ToJson(); - // gherkinDocument from featureInfo + InitReportDirectory(); + // TODO find a place to record first meta line. + outStream << "{\"source\":" << featureInfo.SourceInfo()->ToJson() << "}\n"; + outStream << "{\"gherkinDocument\":" << featureInfo.ToJson() << "}\n"; + // TODO find where pickle definition is coming from + // TODO testRunStarted } void NdjsonReport::FeatureEnd(engine::Result result, const engine::FeatureInfo& featureInfo, TraceTime::Duration duration) { + // TODO testRunFinished } void NdjsonReport::RuleStart(const engine::RuleInfo& ruleInfo) diff --git a/cucumber_cpp/library/report/NdjsonReport.hpp b/cucumber_cpp/library/report/NdjsonReport.hpp index 0c2a1f84..ffe76ac9 100644 --- a/cucumber_cpp/library/report/NdjsonReport.hpp +++ b/cucumber_cpp/library/report/NdjsonReport.hpp @@ -1,6 +1,6 @@ #pragma once #include "Report.hpp" -#include +#include namespace cucumber_cpp::library::report { @@ -27,7 +27,9 @@ namespace cucumber_cpp::library::report const std::string& outputFolder; const std::string& reportFile; - std::vector docs; + std::ofstream outStream; + void InitReportDirectory(); + }; } From 7aecc0cc800a72b313badd70b317e4295f670b05 Mon Sep 17 00:00:00 2001 From: Aleksander Romanenko Date: Tue, 4 Nov 2025 09:59:54 +0300 Subject: [PATCH 09/16] feat: ndjson reporting - add Ndjson report comparer as a separate executable that can be run from bats for assertions. --- cucumber_cpp/acceptance_test/CMakeLists.txt | 12 ++++++++++++ .../acceptance_test/MainNdjsonAssertion.cpp | 16 ++++++++++++++++ cucumber_cpp/acceptance_test/util/CMakeLists.txt | 12 ++++++++++++ .../acceptance_test/util/NdjsonComparer.cpp | 1 + .../acceptance_test/util/NdjsonComparer.h | 10 ++++++++++ cucumber_cpp/library/Application.cpp | 5 +++++ 6 files changed, 56 insertions(+) create mode 100644 cucumber_cpp/acceptance_test/MainNdjsonAssertion.cpp create mode 100644 cucumber_cpp/acceptance_test/util/CMakeLists.txt create mode 100644 cucumber_cpp/acceptance_test/util/NdjsonComparer.cpp create mode 100644 cucumber_cpp/acceptance_test/util/NdjsonComparer.h diff --git a/cucumber_cpp/acceptance_test/CMakeLists.txt b/cucumber_cpp/acceptance_test/CMakeLists.txt index eda7ed36..983e3814 100644 --- a/cucumber_cpp/acceptance_test/CMakeLists.txt +++ b/cucumber_cpp/acceptance_test/CMakeLists.txt @@ -21,5 +21,17 @@ target_link_libraries(cucumber_cpp.acceptance_test.custom PRIVATE cucumber_cpp.acceptance_test.steps ) +add_executable(cucumber_cpp.acceptance_test.ndjson_assertion ${CCR_EXCLUDE_FROMALL}) + +target_sources(cucumber_cpp.acceptance_test.ndjson_assertion PRIVATE + MainNdjsonAssertion.cpp +) + +target_link_libraries(cucumber_cpp.acceptance_test.ndjson_assertion PRIVATE + cucumber_cpp.acceptance_test.util + CLI11 +) + add_subdirectory(hooks) add_subdirectory(steps) +add_subdirectory(util) diff --git a/cucumber_cpp/acceptance_test/MainNdjsonAssertion.cpp b/cucumber_cpp/acceptance_test/MainNdjsonAssertion.cpp new file mode 100644 index 00000000..d31adfe1 --- /dev/null +++ b/cucumber_cpp/acceptance_test/MainNdjsonAssertion.cpp @@ -0,0 +1,16 @@ +#include +#include +#include +#include + +int main(const int argc, char**argv) +{ + CLI::App app("Cucumber Ndjson reporter acceptance test assertion"); + + std::string pathExpected; + std::string pathActual; + app.add_option("-e,--expected", pathExpected, "Path to expected ndjson report to compare against")->required(); + app.add_option("-a,--actual", pathActual, "Path to ndjson report to be validated")->required(); + + CLI11_PARSE(app, argc, argv); +} diff --git a/cucumber_cpp/acceptance_test/util/CMakeLists.txt b/cucumber_cpp/acceptance_test/util/CMakeLists.txt new file mode 100644 index 00000000..545f4660 --- /dev/null +++ b/cucumber_cpp/acceptance_test/util/CMakeLists.txt @@ -0,0 +1,12 @@ +set(CMAKE_COMPILE_WARNING_AS_ERROR On) + +add_library(cucumber_cpp.acceptance_test.util OBJECT ${CCR_EXCLUDE_FROM_ALL}) + +target_sources(cucumber_cpp.acceptance_test.util PRIVATE + NdjsonComparer.cpp + NdjsonComparer.h +) + +target_link_libraries(cucumber_cpp.acceptance_test.util PUBLIC + nlohmann_json +) diff --git a/cucumber_cpp/acceptance_test/util/NdjsonComparer.cpp b/cucumber_cpp/acceptance_test/util/NdjsonComparer.cpp new file mode 100644 index 00000000..e68b0ca3 --- /dev/null +++ b/cucumber_cpp/acceptance_test/util/NdjsonComparer.cpp @@ -0,0 +1 @@ +#include "NdjsonComparer.h" diff --git a/cucumber_cpp/acceptance_test/util/NdjsonComparer.h b/cucumber_cpp/acceptance_test/util/NdjsonComparer.h new file mode 100644 index 00000000..ee09e498 --- /dev/null +++ b/cucumber_cpp/acceptance_test/util/NdjsonComparer.h @@ -0,0 +1,10 @@ +#ifndef CUCUMBER_CPP_RUNNER_NDJSONCOMPARER_H +#define CUCUMBER_CPP_RUNNER_NDJSONCOMPARER_H + +#include + +class NdjsonComparer +{ +}; + +#endif // CUCUMBER_CPP_RUNNER_NDJSONCOMPARER_H diff --git a/cucumber_cpp/library/Application.cpp b/cucumber_cpp/library/Application.cpp index a418cdfa..a9013504 100644 --- a/cucumber_cpp/library/Application.cpp +++ b/cucumber_cpp/library/Application.cpp @@ -120,6 +120,11 @@ namespace cucumber_cpp::library runCommand->add_flag("--dry", options.dryrun, "Generate report without running tests"); runCommand->add_flag("--unused", options.printStepsNotUsed, "Show step definitions that were not used"); + // Some IDEs have hardcoded parameters in test runner. Can either allow and ignore all additional unknown parameters, or individually allow them as they get discovered + // runCommand->allow_extras(); // This will break one of the tests + runCommand->add_option("--gtest_color"); + runCommand->add_option("--gtest_filter"); + reporters.Add("console", [] { return std::make_unique();}); reporters.Add("junit-xml", [this] { return std::make_unique(options.outputfolder, options.reportfile); }); reporters.Add("ndjson", [this] { return std::make_unique(options.outputfolder, options.reportfile); }); From 4d09e9ef8b70d0cbf2d5ccfbe72a2e122ac03ce9 Mon Sep 17 00:00:00 2001 From: Aleksander Romanenko Date: Tue, 4 Nov 2025 10:49:47 +0300 Subject: [PATCH 10/16] feat: ndjson reporting - mark where ndjson comparer will be called from. --- cucumber_cpp/acceptance_test/compatibility.bats | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100755 cucumber_cpp/acceptance_test/compatibility.bats diff --git a/cucumber_cpp/acceptance_test/compatibility.bats b/cucumber_cpp/acceptance_test/compatibility.bats new file mode 100755 index 00000000..e2cb9ef7 --- /dev/null +++ b/cucumber_cpp/acceptance_test/compatibility.bats @@ -0,0 +1,6 @@ +#!/usr/bin/env bats + +@test "Minimal" { + run .build/Host/cucumber_cpp/acceptance_test/Debug/cucumber_cpp.acceptance_test run --feature cucumber_cpp/acceptance_test/compatibility/minimal/ --report ndjson + # TODO link run NdjsonComparer with paths to expected file in the repository and actual file from the result +} From 6428fefafe2fd6a73b2a959a7b0027ef725b2cff Mon Sep 17 00:00:00 2001 From: Aleksander Romanenko Date: Sat, 8 Nov 2025 01:03:06 +0300 Subject: [PATCH 11/16] feat: ndjson reporting - start implementing expected vs actual comparer for testing. --- .../acceptance_test/MainNdjsonAssertion.cpp | 7 +++ .../acceptance_test/util/NdjsonComparer.cpp | 53 +++++++++++++++++++ .../acceptance_test/util/NdjsonComparer.h | 3 ++ 3 files changed, 63 insertions(+) diff --git a/cucumber_cpp/acceptance_test/MainNdjsonAssertion.cpp b/cucumber_cpp/acceptance_test/MainNdjsonAssertion.cpp index d31adfe1..81cd4f0a 100644 --- a/cucumber_cpp/acceptance_test/MainNdjsonAssertion.cpp +++ b/cucumber_cpp/acceptance_test/MainNdjsonAssertion.cpp @@ -1,3 +1,4 @@ +#include "util/NdjsonComparer.h" #include #include #include @@ -13,4 +14,10 @@ int main(const int argc, char**argv) app.add_option("-a,--actual", pathActual, "Path to ndjson report to be validated")->required(); CLI11_PARSE(app, argc, argv); + + NdjsonComparer comparer; + const bool areEquivalent = comparer.AreEquivalent(pathExpected, pathActual); + + std::cout << (areEquivalent ? "true" : "false"); + } diff --git a/cucumber_cpp/acceptance_test/util/NdjsonComparer.cpp b/cucumber_cpp/acceptance_test/util/NdjsonComparer.cpp index e68b0ca3..a325d2d6 100644 --- a/cucumber_cpp/acceptance_test/util/NdjsonComparer.cpp +++ b/cucumber_cpp/acceptance_test/util/NdjsonComparer.cpp @@ -1 +1,54 @@ #include "NdjsonComparer.h" +#include + +using json = nlohmann::json; + +bool NdjsonComparer::AreEquivalent(const std::string& pathExpected, const std::string& pathActual) +{ + std::ifstream expected(pathExpected); + std::string jsonLine; + std::vector expectedJsonObjects; + while (std::getline(expected, jsonLine)) + { + expectedJsonObjects.push_back(json::parse(jsonLine)); + } + + std::ifstream actual(pathActual); + std::vector actualJsonObjects; + while (std::getline(actual, jsonLine)) + { + actualJsonObjects.push_back(json::parse(jsonLine)); + } + + if (expectedJsonObjects.size() != actualJsonObjects.size()) + { + return false; + } + + for (size_t i = 0; i < expectedJsonObjects.size(); i++) + { + json expectedJson = expectedJsonObjects[i]; + json actualJson = actualJsonObjects[i]; + + if (expectedJson.size() != actualJson.size()) + { + return false; + } + + const json::iterator expectedIterator = expectedJson.begin(); + const json::iterator actualIterator = actualJson.begin(); + + while (expectedIterator != expectedJson.end()) + { + // TODO this will most definitely fail without predictable sorting + if (expectedIterator.key() != actualIterator.key() || + expectedIterator.value() != actualIterator.value()) + { + // TODO dynamic values such as timestamps and paths will need special handling + return false; + } + } + } + + return true; +} \ No newline at end of file diff --git a/cucumber_cpp/acceptance_test/util/NdjsonComparer.h b/cucumber_cpp/acceptance_test/util/NdjsonComparer.h index ee09e498..4dab5b17 100644 --- a/cucumber_cpp/acceptance_test/util/NdjsonComparer.h +++ b/cucumber_cpp/acceptance_test/util/NdjsonComparer.h @@ -5,6 +5,9 @@ class NdjsonComparer { +public: + [[nodiscard]] + static bool AreEquivalent(const std::string& pathExpected, const std::string& pathActual); }; #endif // CUCUMBER_CPP_RUNNER_NDJSONCOMPARER_H From bb371f077ca1bf763252eb63bfcb06b86ced4805 Mon Sep 17 00:00:00 2001 From: Aleksander Romanenko Date: Wed, 12 Nov 2025 21:07:55 +0300 Subject: [PATCH 12/16] feat: ndjson reporting - get pickle json from scenario info --- .../acceptance_test/MainNdjsonAssertion.cpp | 3 +-- .../library/engine/FeatureFactory.cpp | 4 ++-- cucumber_cpp/library/engine/ScenarioInfo.cpp | 20 ++++++++++++------- cucumber_cpp/library/engine/ScenarioInfo.hpp | 9 ++++++--- cucumber_cpp/library/report/NdjsonReport.cpp | 3 ++- 5 files changed, 24 insertions(+), 15 deletions(-) diff --git a/cucumber_cpp/acceptance_test/MainNdjsonAssertion.cpp b/cucumber_cpp/acceptance_test/MainNdjsonAssertion.cpp index 81cd4f0a..f47ead6a 100644 --- a/cucumber_cpp/acceptance_test/MainNdjsonAssertion.cpp +++ b/cucumber_cpp/acceptance_test/MainNdjsonAssertion.cpp @@ -15,8 +15,7 @@ int main(const int argc, char**argv) CLI11_PARSE(app, argc, argv); - NdjsonComparer comparer; - const bool areEquivalent = comparer.AreEquivalent(pathExpected, pathActual); + const bool areEquivalent = NdjsonComparer::AreEquivalent(pathExpected, pathActual); std::cout << (areEquivalent ? "true" : "false"); diff --git a/cucumber_cpp/library/engine/FeatureFactory.cpp b/cucumber_cpp/library/engine/FeatureFactory.cpp index 1f48fb1c..60630e9f 100644 --- a/cucumber_cpp/library/engine/FeatureFactory.cpp +++ b/cucumber_cpp/library/engine/FeatureFactory.cpp @@ -187,9 +187,9 @@ namespace cucumber_cpp::library::engine return; featureInfo.Scenarios().push_back(std::make_unique( + pickle, featureInfo, std::move(tags), - pickle.name, scenario.description, scenario.location.line, scenario.location.column.value_or(0))); @@ -200,9 +200,9 @@ namespace cucumber_cpp::library::engine void ConstructScenario(const FeatureTreeFactory& featureTreeFactory, RuleInfo& ruleInfo, const FlatAst& flatAst, const cucumber::messages::scenario& scenario, const cucumber::messages::pickle& pickle, std::set> tags) { ruleInfo.Scenarios().push_back(std::make_unique( + pickle, ruleInfo, std::move(tags), - pickle.name, scenario.description, scenario.location.line, scenario.location.column.value_or(0))); diff --git a/cucumber_cpp/library/engine/ScenarioInfo.cpp b/cucumber_cpp/library/engine/ScenarioInfo.cpp index 655a93b4..adee9b70 100644 --- a/cucumber_cpp/library/engine/ScenarioInfo.cpp +++ b/cucumber_cpp/library/engine/ScenarioInfo.cpp @@ -16,19 +16,19 @@ namespace cucumber_cpp::library::engine { - ScenarioInfo::ScenarioInfo(const struct RuleInfo& ruleInfo, std::set> tags, std::string title, std::string description, std::size_t line, std::size_t column) - : parentInfo{ &ruleInfo } + ScenarioInfo::ScenarioInfo(cucumber::messages::pickle pickle, const struct RuleInfo& ruleInfo, std::set> tags, std::string description, std::size_t line, std::size_t column) + : pickle(std::move(pickle)) + , parentInfo{ &ruleInfo } , tags{ std::move(tags) } - , title{ std::move(title) } , description{ std::move(description) } , line{ line } , column{ column } {} - ScenarioInfo::ScenarioInfo(const struct FeatureInfo& featureInfo, std::set> tags, std::string title, std::string description, std::size_t line, std::size_t column) - : parentInfo{ &featureInfo } + ScenarioInfo::ScenarioInfo(cucumber::messages::pickle pickle, const struct FeatureInfo& featureInfo, std::set> tags, std::string description, std::size_t line, std::size_t column) + : pickle(std::move(pickle)) + , parentInfo{ &featureInfo } , tags{ std::move(tags) } - , title{ std::move(title) } , description{ std::move(description) } , line{ line } , column{ column } @@ -61,7 +61,7 @@ namespace cucumber_cpp::library::engine const std::string& ScenarioInfo::Title() const { - return title; + return pickle.name; } const std::string& ScenarioInfo::Description() const @@ -93,4 +93,10 @@ namespace cucumber_cpp::library::engine { return children; } + + std::string ScenarioInfo::ToJson() const + { + return pickle.to_json(); + } + } diff --git a/cucumber_cpp/library/engine/ScenarioInfo.hpp b/cucumber_cpp/library/engine/ScenarioInfo.hpp index c502da49..993f7a37 100644 --- a/cucumber_cpp/library/engine/ScenarioInfo.hpp +++ b/cucumber_cpp/library/engine/ScenarioInfo.hpp @@ -4,6 +4,7 @@ #include "cucumber_cpp/library/engine/RuleInfo.hpp" #include "cucumber_cpp/library/engine/StepInfo.hpp" #include +#include #include #include #include @@ -19,8 +20,8 @@ namespace cucumber_cpp::library::engine struct ScenarioInfo { - ScenarioInfo(const RuleInfo& ruleInfo, std::set> tags, std::string title, std::string description, std::size_t line, std::size_t column); - ScenarioInfo(const FeatureInfo& featureInfo, std::set> tags, std::string title, std::string description, std::size_t line, std::size_t column); + ScenarioInfo(cucumber::messages::pickle pickle, const RuleInfo& ruleInfo, std::set> tags, std::string description, std::size_t line, std::size_t column); + ScenarioInfo(cucumber::messages::pickle pickle, const FeatureInfo& featureInfo, std::set> tags, std::string description, std::size_t line, std::size_t column); [[nodiscard]] const struct FeatureInfo& FeatureInfo() const; [[nodiscard]] std::optional> RuleInfo() const; @@ -37,11 +38,13 @@ namespace cucumber_cpp::library::engine [[nodiscard]] std::vector>& Children(); [[nodiscard]] const std::vector>& Children() const; + [[nodiscard]] std::string ToJson() const; + private: + const cucumber::messages::pickle pickle; std::variant parentInfo; std::set> tags; - std::string title; std::string description; std::size_t line; diff --git a/cucumber_cpp/library/report/NdjsonReport.cpp b/cucumber_cpp/library/report/NdjsonReport.cpp index a213da8e..55b67827 100644 --- a/cucumber_cpp/library/report/NdjsonReport.cpp +++ b/cucumber_cpp/library/report/NdjsonReport.cpp @@ -56,7 +56,6 @@ namespace cucumber_cpp::library::report // TODO find a place to record first meta line. outStream << "{\"source\":" << featureInfo.SourceInfo()->ToJson() << "}\n"; outStream << "{\"gherkinDocument\":" << featureInfo.ToJson() << "}\n"; - // TODO find where pickle definition is coming from // TODO testRunStarted } @@ -75,6 +74,8 @@ namespace cucumber_cpp::library::report void NdjsonReport::ScenarioStart(const engine::ScenarioInfo& scenarioInfo) { + // each scenario is a pickle + outStream << "{\"pickle\":" << scenarioInfo.ToJson() << "}\n"; } void NdjsonReport::ScenarioEnd(engine::Result result, const engine::ScenarioInfo& scenarioInfo, TraceTime::Duration duration) From d5b84d2c7148e10c4eef9dfdfa7f71078aa1e977 Mon Sep 17 00:00:00 2001 From: Alexander Romanenko Date: Mon, 24 Nov 2025 00:47:49 +0300 Subject: [PATCH 13/16] feat: ndjson reporting - fix test compilation --- cucumber_cpp/library/engine/test/TestContextManager.cpp | 4 ++-- cucumber_cpp/library/engine/test/TestTestRunner.cpp | 2 +- .../library/engine/test_helper/ContextManagerInstance.hpp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cucumber_cpp/library/engine/test/TestContextManager.cpp b/cucumber_cpp/library/engine/test/TestContextManager.cpp index b048917a..e369b537 100644 --- a/cucumber_cpp/library/engine/test/TestContextManager.cpp +++ b/cucumber_cpp/library/engine/test/TestContextManager.cpp @@ -17,9 +17,9 @@ namespace cucumber_cpp::library::engine std::shared_ptr contextStorageFactory = std::make_shared(); cucumber_cpp::library::engine::ContextManager contextManager{ contextStorageFactory }; - cucumber_cpp::library::engine::FeatureInfo feature{ {}, {}, {}, {}, {}, {} }; + cucumber_cpp::library::engine::FeatureInfo feature{ {}, {} }; cucumber_cpp::library::engine::RuleInfo rule{ feature, {}, {}, {}, {}, {} }; - cucumber_cpp::library::engine::ScenarioInfo scenario{ rule, {}, {}, {}, {}, {} }; + cucumber_cpp::library::engine::ScenarioInfo scenario{ {}, rule, {}, {}, {}, {}}; cucumber_cpp::library::engine::StepInfo step{ scenario, {}, {}, {}, {}, {}, {} }; }; diff --git a/cucumber_cpp/library/engine/test/TestTestRunner.cpp b/cucumber_cpp/library/engine/test/TestTestRunner.cpp index e733f269..8a9556b2 100644 --- a/cucumber_cpp/library/engine/test/TestTestRunner.cpp +++ b/cucumber_cpp/library/engine/test/TestTestRunner.cpp @@ -27,7 +27,7 @@ namespace cucumber_cpp::library::engine { TestExecutionMockInstance() { - reporters.Add("console", std::make_unique()); + reporters.Add("console", [] { return std::make_unique();}); reporters.Use("console"); } diff --git a/cucumber_cpp/library/engine/test_helper/ContextManagerInstance.hpp b/cucumber_cpp/library/engine/test_helper/ContextManagerInstance.hpp index fecbcc0a..c2e82ded 100644 --- a/cucumber_cpp/library/engine/test_helper/ContextManagerInstance.hpp +++ b/cucumber_cpp/library/engine/test_helper/ContextManagerInstance.hpp @@ -25,9 +25,9 @@ namespace cucumber_cpp::library::engine::test_helper { ContextManagerInstance(std::set> tags = {}) : cucumber_cpp::library::engine::ContextManager{ contextStorageFactory } - , feature{ tags, {}, {}, {}, {}, {} } + , feature{{}, {}} , rule{ feature, {}, {}, {}, {}, {} } - , scenario{ rule, tags, {}, {}, {}, {} } + , scenario{ {}, rule, tags, {}, {}, {} } , step{ scenario, {}, {}, {}, {}, {}, {} } { } From 890d940a030bdc2030559a0b3fa042c88e969c6a Mon Sep 17 00:00:00 2001 From: Alexander Romanenko Date: Mon, 24 Nov 2025 00:49:30 +0300 Subject: [PATCH 14/16] feat: ndjson reporting - meta record requires knowing what version of messages protocol is targeted --- CMakeLists.txt | 3 ++- cucumber_cpp/library/report/CMakeLists.txt | 7 +++++++ cucumber_cpp/library/report/Environment.h.in | 6 ++++++ cucumber_cpp/library/report/NdjsonReport.cpp | 11 ++++++++++- cucumber_cpp/library/report/NdjsonReport.hpp | 1 + external/cucumber/messages/CMakeLists.txt | 2 +- 6 files changed, 27 insertions(+), 3 deletions(-) create mode 100644 cucumber_cpp/library/report/Environment.h.in diff --git a/CMakeLists.txt b/CMakeLists.txt index c30a33e2..b48b22d7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,8 @@ cmake_minimum_required(VERSION 3.24) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") -project(cucumber-cpp-runner LANGUAGES C CXX VERSION 3.1.1) # x-release-please-version +project(cucumber-cpp-runner LANGUAGES C CXX VERSION 3.1.0) # x-release-please-version +set(MESSAGES_PROTOCOL_VERSION "26.0.1") include(ccr_test_helpers) diff --git a/cucumber_cpp/library/report/CMakeLists.txt b/cucumber_cpp/library/report/CMakeLists.txt index e9beb1d2..ab6f0558 100644 --- a/cucumber_cpp/library/report/CMakeLists.txt +++ b/cucumber_cpp/library/report/CMakeLists.txt @@ -1,5 +1,10 @@ add_library(cucumber_cpp.library.report STATIC ${CCR_EXCLUDE_FROM_ALL}) +configure_file( + Environment.h.in + "${CMAKE_CURRENT_BINARY_DIR}/g/Environment.h" +) + target_sources(cucumber_cpp.library.report PRIVATE JunitReport.cpp JunitReport.hpp @@ -11,6 +16,8 @@ target_sources(cucumber_cpp.library.report PRIVATE StdOutReport.hpp ) +target_include_directories(cucumber_cpp.library.report PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/g") + target_include_directories(cucumber_cpp.library.report PUBLIC ../../.. ) diff --git a/cucumber_cpp/library/report/Environment.h.in b/cucumber_cpp/library/report/Environment.h.in new file mode 100644 index 00000000..23fe5483 --- /dev/null +++ b/cucumber_cpp/library/report/Environment.h.in @@ -0,0 +1,6 @@ +#ifndef ENVIRONMENT_H_IN +#define ENVIRONMENT_H_IN + +#define MESSAGES_PROTOCOL_VERSION "@MESSAGES_PROTOCOL_VERSION@" + +#endif diff --git a/cucumber_cpp/library/report/NdjsonReport.cpp b/cucumber_cpp/library/report/NdjsonReport.cpp index 55b67827..ee1139c2 100644 --- a/cucumber_cpp/library/report/NdjsonReport.cpp +++ b/cucumber_cpp/library/report/NdjsonReport.cpp @@ -1,4 +1,6 @@ #include "NdjsonReport.hpp" +#include "Environment.h" +#include #include #include @@ -49,11 +51,18 @@ namespace cucumber_cpp::library::report } } + void NdjsonReport::CreateMeta() + { + // Makeup own metadata since https://github.com/cucumber/ci-environment does not have c++ version (yet) + cucumber::messages::meta meta (MESSAGES_PROTOCOL_VERSION); + } + void NdjsonReport::FeatureStart(const engine::FeatureInfo& featureInfo) { InitReportDirectory(); - // TODO find a place to record first meta line. + CreateMeta(); + outStream << "{\"source\":" << featureInfo.SourceInfo()->ToJson() << "}\n"; outStream << "{\"gherkinDocument\":" << featureInfo.ToJson() << "}\n"; // TODO testRunStarted diff --git a/cucumber_cpp/library/report/NdjsonReport.hpp b/cucumber_cpp/library/report/NdjsonReport.hpp index ffe76ac9..0cd468e8 100644 --- a/cucumber_cpp/library/report/NdjsonReport.hpp +++ b/cucumber_cpp/library/report/NdjsonReport.hpp @@ -29,6 +29,7 @@ namespace cucumber_cpp::library::report std::ofstream outStream; void InitReportDirectory(); + static void CreateMeta() ; }; diff --git a/external/cucumber/messages/CMakeLists.txt b/external/cucumber/messages/CMakeLists.txt index 4b609947..c5f206d0 100644 --- a/external/cucumber/messages/CMakeLists.txt +++ b/external/cucumber/messages/CMakeLists.txt @@ -1,6 +1,6 @@ FetchContent_Declare(cucumber_messages GIT_REPOSITORY https://github.com/cucumber/messages.git - GIT_TAG "v26.0.1" + GIT_TAG "v${MESSAGES_PROTOCOL_VERSION}" OVERRIDE_FIND_PACKAGE ) From fc7bc5ca48ebdcdf92e8f6dd2a966471a4aa1c1f Mon Sep 17 00:00:00 2001 From: Alexander Romanenko Date: Sun, 30 Nov 2025 11:12:20 +0300 Subject: [PATCH 15/16] feat: ndjson reporting - gherkin document is not just feature but other properties too. Need to expose original feature pickle since it does not independently generate json but is part of a bigger object. --- cucumber_cpp/library/engine/FeatureInfo.cpp | 4 ++-- cucumber_cpp/library/engine/FeatureInfo.hpp | 2 +- cucumber_cpp/library/report/NdjsonReport.cpp | 15 +++++++++++---- cucumber_cpp/library/report/NdjsonReport.hpp | 2 +- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/cucumber_cpp/library/engine/FeatureInfo.cpp b/cucumber_cpp/library/engine/FeatureInfo.cpp index 2961f9ec..bbd0aa94 100644 --- a/cucumber_cpp/library/engine/FeatureInfo.cpp +++ b/cucumber_cpp/library/engine/FeatureInfo.cpp @@ -75,9 +75,9 @@ namespace cucumber_cpp::library::engine return scenarios; } - std::string FeatureInfo::ToJson() const + const cucumber::messages::feature& FeatureInfo::Pickle() const { - return feature.to_json(); + return feature; } diff --git a/cucumber_cpp/library/engine/FeatureInfo.hpp b/cucumber_cpp/library/engine/FeatureInfo.hpp index 1b02812c..28af6cae 100644 --- a/cucumber_cpp/library/engine/FeatureInfo.hpp +++ b/cucumber_cpp/library/engine/FeatureInfo.hpp @@ -36,7 +36,7 @@ namespace cucumber_cpp::library::engine [[nodiscard]] std::vector>& Scenarios(); [[nodiscard]] const std::vector>& Scenarios() const; - [[nodiscard]] std::string ToJson() const; + [[nodiscard]] const cucumber::messages::feature& Pickle() const; private: diff --git a/cucumber_cpp/library/report/NdjsonReport.cpp b/cucumber_cpp/library/report/NdjsonReport.cpp index ee1139c2..6f9eae07 100644 --- a/cucumber_cpp/library/report/NdjsonReport.cpp +++ b/cucumber_cpp/library/report/NdjsonReport.cpp @@ -1,5 +1,6 @@ #include "NdjsonReport.hpp" #include "Environment.h" +#include #include #include #include @@ -22,7 +23,6 @@ namespace cucumber_cpp::library::report outStream.close(); } - /* * Unlike XML reporter, where a single document is built up over time and then has to be flushed out in the end all at once, * NDJSON is a series of individual json objects appended one after another as the test run progresses. @@ -51,20 +51,27 @@ namespace cucumber_cpp::library::report } } - void NdjsonReport::CreateMeta() + void NdjsonReport::RecordMeta() { // Makeup own metadata since https://github.com/cucumber/ci-environment does not have c++ version (yet) cucumber::messages::meta meta (MESSAGES_PROTOCOL_VERSION); + meta.ci = cucumber::messages::ci("name", "url", "build_number"); + meta.ci->git = cucumber::messages::git("remote", "revision", "branch", "tag"); + outStream << "{\"meta\":" << meta.to_json() << "}\n"; } void NdjsonReport::FeatureStart(const engine::FeatureInfo& featureInfo) { InitReportDirectory(); - CreateMeta(); + RecordMeta(); outStream << "{\"source\":" << featureInfo.SourceInfo()->ToJson() << "}\n"; - outStream << "{\"gherkinDocument\":" << featureInfo.ToJson() << "}\n"; + + cucumber::messages::gherkin_document gherkinDocument; + gherkinDocument.feature = featureInfo.Pickle(); + + outStream << "{\"gherkinDocument\":" << gherkinDocument.to_json() << "}\n"; // TODO testRunStarted } diff --git a/cucumber_cpp/library/report/NdjsonReport.hpp b/cucumber_cpp/library/report/NdjsonReport.hpp index 0cd468e8..9406da66 100644 --- a/cucumber_cpp/library/report/NdjsonReport.hpp +++ b/cucumber_cpp/library/report/NdjsonReport.hpp @@ -29,7 +29,7 @@ namespace cucumber_cpp::library::report std::ofstream outStream; void InitReportDirectory(); - static void CreateMeta() ; + void RecordMeta() ; }; From 5e0a4c4dbc36af531c2edc133285c55495aab851 Mon Sep 17 00:00:00 2001 From: Aleksander Romanenko Date: Mon, 1 Dec 2025 21:42:31 +0300 Subject: [PATCH 16/16] feat: ndjson reporting - verify that all event objects are present (not values, yet) --- .../acceptance_test/util/NdjsonComparer.cpp | 57 ++++++++++++------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/cucumber_cpp/acceptance_test/util/NdjsonComparer.cpp b/cucumber_cpp/acceptance_test/util/NdjsonComparer.cpp index a325d2d6..952bdc28 100644 --- a/cucumber_cpp/acceptance_test/util/NdjsonComparer.cpp +++ b/cucumber_cpp/acceptance_test/util/NdjsonComparer.cpp @@ -1,5 +1,7 @@ #include "NdjsonComparer.h" +#include #include +#include using json = nlohmann::json; @@ -15,40 +17,55 @@ bool NdjsonComparer::AreEquivalent(const std::string& pathExpected, const std::s std::ifstream actual(pathActual); std::vector actualJsonObjects; + int lineNumber = 1; + bool hasEmptyLine = false; while (std::getline(actual, jsonLine)) { - actualJsonObjects.push_back(json::parse(jsonLine)); - } + if (hasEmptyLine) + { + std::cerr << std::format("\nFailure: output contains unexpected empty line number {}.", lineNumber); + return false; + } + if (jsonLine.empty()) + { + hasEmptyLine = true; + continue; + } - if (expectedJsonObjects.size() != actualJsonObjects.size()) - { - return false; + try + { + actualJsonObjects.push_back(json::parse(jsonLine)); + } catch (json::exception& e) + { + std::cerr << std::format("\nFailure: line {} contains invalid json. {}", lineNumber, e.what()); + } + lineNumber++; } - for (size_t i = 0; i < expectedJsonObjects.size(); i++) + for (int i = 0; i < expectedJsonObjects.size(); i++) { - json expectedJson = expectedJsonObjects[i]; - json actualJson = actualJsonObjects[i]; - - if (expectedJson.size() != actualJson.size()) + if (i > actualJsonObjects.size() - 1) { + std::cerr << std::format("\nFailure: Unexpectedly reached the end of generated output. Expected {} but received {} objects.", expectedJsonObjects.size(), actualJsonObjects.size()); return false; } - - const json::iterator expectedIterator = expectedJson.begin(); - const json::iterator actualIterator = actualJson.begin(); - - while (expectedIterator != expectedJson.end()) + // Missing of the keys at the first level implies that the entire event is missing + json::iterator topLevelKeyIterator = expectedJsonObjects[i].begin(); + while (topLevelKeyIterator != expectedJsonObjects[i].end()) { - // TODO this will most definitely fail without predictable sorting - if (expectedIterator.key() != actualIterator.key() || - expectedIterator.value() != actualIterator.value()) + const json& actualJson = actualJsonObjects[i]; + const std::string& expectedKey = topLevelKeyIterator.key(); + if (actualJson.contains(expectedKey)) { - // TODO dynamic values such as timestamps and paths will need special handling + // TODO Perform event data assertions. Dynamic values, such as timestamps and paths, will need special handling + ++topLevelKeyIterator; + } else { + std::cerr << std::format("\nFailure: Event \"{}\" is missing on line {}. Found \"{}\" instead.", expectedKey, i, actualJson.begin().key()); + return false; } } } return true; -} \ No newline at end of file +}