Full Code of cucumber/cucumber-cpp for AI

main fedcaeab5382 cached
129 files
244.6 KB
64.6k tokens
540 symbols
1 requests
Download .txt
Showing preview only (276K chars total). Download the full file or copy to clipboard to get everything.
Repository: cucumber/cucumber-cpp
Branch: main
Commit: fedcaeab5382
Files: 129
Total size: 244.6 KB

Directory structure:
gitextract_c6fituri/

├── .clang-format
├── .github/
│   ├── ISSUE_TEMPLATE.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   └── workflows/
│       ├── format.yml
│       ├── linux-build.yml
│       ├── qt5.yml
│       ├── run-all.yml
│       ├── windows-build.yml
│       └── zizmor-analysis.yaml
├── .gitignore
├── CHANGELOG.md
├── CMakeLists.txt
├── CONTRIBUTING.md
├── Gemfile
├── LICENSE
├── README.md
├── cmake/
│   └── modules/
│       ├── FindAsio.cmake
│       ├── FindTCLAP.cmake
│       ├── FindValgrind.cmake
│       └── GitVersion.cmake
├── examples/
│   ├── CMakeLists.txt
│   ├── Calc/
│   │   ├── CMakeLists.txt
│   │   ├── README.txt
│   │   ├── features/
│   │   │   ├── addition.feature
│   │   │   ├── division.feature
│   │   │   └── step_definitions/
│   │   │       ├── BoostCalculatorSteps.cpp
│   │   │       ├── CalculatorSteps.cpp
│   │   │       ├── FuncArgsCalculatorSteps.cpp
│   │   │       ├── GTestCalculatorSteps.cpp
│   │   │       ├── QtTestCalculatorSteps.cpp
│   │   │       └── cucumber.wire
│   │   └── src/
│   │       ├── Calculator.cpp
│   │       └── Calculator.hpp
│   ├── CalcQt/
│   │   ├── CMakeLists.txt
│   │   ├── README.txt
│   │   ├── features/
│   │   │   ├── addition.feature
│   │   │   ├── behavior.feature
│   │   │   ├── initialization.feature
│   │   │   ├── step_definitions/
│   │   │   │   ├── BoostCalculatorQtSteps.cpp
│   │   │   │   ├── CalculatorQtSteps.cpp
│   │   │   │   ├── GTestCalculatorQtSteps.cpp
│   │   │   │   ├── QtTestCalculatorQtSteps.cpp
│   │   │   │   └── cucumber.wire
│   │   │   └── subtraction.feature
│   │   └── src/
│   │       ├── CalcQt.cpp
│   │       ├── Calculator.cpp
│   │       ├── Calculator.hpp
│   │       ├── CalculatorWidget.cpp
│   │       └── CalculatorWidget.hpp
│   └── FeatureShowcase/
│       ├── CMakeLists.txt
│       ├── README.txt
│       └── features/
│           ├── step_definitions/
│           │   ├── TableSteps.cpp
│           │   ├── TagSteps.cpp
│           │   └── cucumber.wire
│           ├── table.feature
│           └── tag.feature
├── include/
│   └── cucumber-cpp/
│       ├── autodetect.hpp
│       ├── defs.hpp
│       ├── generic.hpp
│       └── internal/
│           ├── ContextManager.hpp
│           ├── CukeCommands.hpp
│           ├── CukeEngine.hpp
│           ├── CukeEngineImpl.hpp
│           ├── Macros.hpp
│           ├── RegistrationMacros.hpp
│           ├── Scenario.hpp
│           ├── Table.hpp
│           ├── connectors/
│           │   └── wire/
│           │       ├── ProtocolHandler.hpp
│           │       ├── WireProtocol.hpp
│           │       ├── WireProtocolCommands.hpp
│           │       └── WireServer.hpp
│           ├── defs.hpp
│           ├── drivers/
│           │   ├── BoostDriver.hpp
│           │   ├── DriverSelector.hpp
│           │   ├── GTestDriver.hpp
│           │   ├── GenericDriver.hpp
│           │   └── QtTestDriver.hpp
│           ├── hook/
│           │   ├── HookMacros.hpp
│           │   ├── HookRegistrar.hpp
│           │   └── Tag.hpp
│           ├── step/
│           │   ├── StepMacros.hpp
│           │   └── StepManager.hpp
│           └── utils/
│               ├── IndexSequence.hpp
│               └── Regex.hpp
├── run-linux.sh
├── run-windows.ps1
├── src/
│   ├── CMakeLists.txt
│   ├── ContextManager.cpp
│   ├── CukeCommands.cpp
│   ├── CukeEngine.cpp
│   ├── CukeEngineImpl.cpp
│   ├── HookRegistrar.cpp
│   ├── Regex.cpp
│   ├── Scenario.cpp
│   ├── StepManager.cpp
│   ├── Table.cpp
│   ├── Tag.cpp
│   ├── connectors/
│   │   └── wire/
│   │       ├── WireProtocol.cpp
│   │       ├── WireProtocolCommands.cpp
│   │       └── WireServer.cpp
│   ├── drivers/
│   │   ├── BoostDriver.cpp
│   │   ├── GTestDriver.cpp
│   │   ├── GenericDriver.cpp
│   │   └── QtTestDriver.cpp
│   └── main.cpp
└── tests/
    ├── CMakeLists.txt
    ├── integration/
    │   ├── ContextHandlingTest.cpp
    │   ├── HookRegistrationTest.cpp
    │   ├── StepRegistrationTest.cpp
    │   ├── TaggedHookRegistrationTest.cpp
    │   ├── WireProtocolTest.cpp
    │   ├── WireServerTest.cpp
    │   └── drivers/
    │       ├── BoostDriverTest.cpp
    │       ├── GTestDriverTest.cpp
    │       ├── GenericDriverTest.cpp
    │       └── QtTestDriverTest.cpp
    ├── unit/
    │   ├── BasicStepTest.cpp
    │   ├── ContextManagerTest.cpp
    │   ├── CukeCommandsTest.cpp
    │   ├── RegexTest.cpp
    │   ├── StepCallChainTest.cpp
    │   ├── StepManagerTest.cpp
    │   ├── TableTest.cpp
    │   └── TagTest.cpp
    └── utils/
        ├── ContextManagerTestDouble.hpp
        ├── CukeCommandsFixture.hpp
        ├── DriverTestRunner.hpp
        ├── HookRegistrationFixture.hpp
        └── StepManagerTestDouble.hpp

================================================
FILE CONTENTS
================================================

================================================
FILE: .clang-format
================================================
---
Language: Cpp
AccessModifierOffset: -4
AlignAfterOpenBracket: BlockIndent
AlignEscapedNewlinesLeft: true
AllowShortEnumsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AlwaysBreakTemplateDeclarations: true
BinPackArguments: false
BinPackParameters: false
BreakBeforeBinaryOperators: All
BreakBeforeBraces: Attach
BreakConstructorInitializers: AfterColon
ColumnLimit: 100
FixNamespaceComments: true
IncludeCategories: 
  # The autodetect header should always be included last
  - Regex:           '^<cucumber-cpp/autodetect\.hpp>$'
    Priority:        3
  - Regex:           '^["<]cucumber-cpp/'
    Priority:        1
  - Regex:           '.*'
    Priority:        2
IndentPPDirectives: BeforeHash
IndentWidth: 4
NamespaceIndentation: None
PackConstructorInitializers: Never
PenaltyBreakString: 1000
PenaltyExcessCharacter: 10000
PenaltyReturnTypeOnItsOwnLine: 1000
PointerAlignment: Left
ShortNamespaceLines: 200
SortIncludes: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
Standard: Cpp11
...



================================================
FILE: .github/ISSUE_TEMPLATE.md
================================================
<!-- These sections are meant as guidance for you, to help you give the kind of information we'll need to help with your issue. If a section  doesn't seem to fit, just skip it.

This is not a support or discussion forum. If you have a question, please ask it on [The Cukes Google Group](http://groups.google.com/group/cukes) or on [Gitter](https://gitter.im/cucumber/).

In general: Please provide as much information as you can to help us solving your problem -->

## Summary

<!--- Provide a general summary description of the issue -->

## Expected Behavior

<!--- If you're describing a bug, tell us what should happen -->
<!--- If you're suggesting a change/improvement, tell us how it should work -->
<!--- Feel free to use Given / When / Then if that helps, but please add some plain-language context too -->

## Current Behavior

<!--- If describing a bug, tell us what happens instead of the expected behavior -->
<!--- If suggesting a change/improvement, explain the difference from current behavior -->

<!--- If you have got some output place it in the code block below. Otherwise remove it. -->
~~~
~~~

## Possible Solution

<!--- Not obligatory, but suggest a fix/reason for the bug, -->
<!--- or ideas how to implement the addition or change -->

## Steps to Reproduce (for bugs)

<!--- Provide a link to a live example, or an unambiguous set of steps to -->
<!--- reproduce this bug. Include code to reproduce, if relevant -->
1.
2.
3.
4.

## Context & Motivation

<!--- How has this issue affected you? What are you trying to accomplish? -->
<!--- Providing context helps us come up with a solution that is most useful in the real world -->

## Your Environment

<!--- If you're reporting a bug, include as many relevant details about the environment you experienced the bug in -->
* Version used:
* Operating System and version:
* Link to your project:


================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
<!-- These sections are meant as guidance for you. If something doesn't fit, you can just skip it. -->

## Summary

<!--- Provide a general summary description of your changes -->

## Details

<!--- Describe your changes in detail -->

## Motivation and Context

<!--- Why is this change required? What problem does it solve? -->
<!--- If it fixes an open issue, please link to the issue here. -->

## How Has This Been Tested?

<!--- Please add tests for changes to the code, otherwise we probably won't merge it -->

<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, tests ran to see how -->
<!--- your change affects other areas of the code, etc. -->

## Types of changes

<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
- [ ] Bug fix (non-breaking change which fixes an issue).
- [ ] New feature (non-breaking change which adds functionality).
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected).

## Checklist:

<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
- [ ] It is my own work, its copyright is implicitly assigned to the project and no substantial part of it has been copied from other sources (including [Stack Overflow](https://stackoverflow.com/)). In rare occasions this is acceptable, like in CMake modules where the original copyright information should be kept.
- [ ] I'm using the same code standards as the existing code (indentation, spacing, variable naming, ...).
- [ ] I've added tests for my code.
- [ ] I have verified whether my change requires changes to the documentation
- [ ] My change either requires no documentation change or I've updated the documentation accordingly.
- [ ] My branch has been rebased to main, keeping only relevant commits.


================================================
FILE: .github/workflows/format.yml
================================================
name: check format

permissions: {}

on:
  pull_request:
    branches: [ main ]
  workflow_dispatch:
  push:
    branches:
      - main

concurrency:
  group: ${{ github.workflow }}-${{ github.head_ref || github.ref || github.run_id }}
  cancel-in-progress: true

jobs:
  build:
    runs-on: ubuntu-22.04

    steps:
    - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      with:
        persist-credentials: false

    - name: setup environment
      run: |
        sudo apt-get install --no-install-recommends \
        clang-format-15

    - name: check code format
      run: |
        clang-format-15 --style=file --Werror --dry-run --verbose `find . -type d \( -name '3rdparty' \) -prune -o -regex '.*\.\(cpp\|hpp\)' -print`


================================================
FILE: .github/workflows/linux-build.yml
================================================
name: Linux build

permissions: {}

on:
  pull_request:
    branches: [ main ]
  workflow_dispatch:
  push:
    branches:
      - main

concurrency:
  group: ${{ github.workflow }}-${{ github.head_ref || github.ref || github.run_id }}
  cancel-in-progress: true


jobs:
  build:
    strategy:
      matrix:
        cpp-compiler:
          - g++
          - clang++-15
        cpp-standard:
          - 17
          - 20

    runs-on: ubuntu-22.04

    steps:
    - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      with:
        persist-credentials: false

    - name: setup environment
      run: |
        sudo apt-get install --no-install-recommends \
          clang-15 \
          cmake \
          g++ \
          git \
          libasio-dev \
          libboost-test-dev \
          libgl1-mesa-dev \
          libtclap-dev \
          ninja-build \
          nlohmann-json3-dev \
          qt6-base-dev

    - name: install gtest
      run: |
        git clone https://github.com/google/googletest.git
        cd googletest
        mkdir build
        cd build
        cmake \
          ..
        cmake --build . --parallel
        sudo cmake --install .

    - name: build
      run: |
        cmake -E make_directory build
        cmake -E chdir build cmake \
          -DCMAKE_CXX_COMPILER=${{ matrix.cpp-compiler }} \
          -DCMAKE_CXX_STANDARD=${{ matrix.cpp-standard }} \
          -G Ninja \
          -DCUKE_STRICT=on \
          -DCUKE_ENABLE_BOOST_TEST=on \
          -DCUKE_ENABLE_GTEST=on \
          -DCUKE_ENABLE_QT_6=on \
          -DCUKE_ENABLE_EXAMPLES=on \
          -DCUKE_TESTS_UNIT=on \
          ..
        cmake --build build --parallel --verbose

    - name: unit tests
      run: |
        cmake --build build --target test


================================================
FILE: .github/workflows/qt5.yml
================================================
name: build and test with Qt5

permissions: {}

on:
  pull_request:
    branches: [ main ]
  workflow_dispatch:
  push:
    branches:
      - main

concurrency:
  group: ${{ github.workflow }}-${{ github.head_ref || github.ref || github.run_id }}
  cancel-in-progress: true

jobs:
  build:
    runs-on: ubuntu-22.04

    steps:
    - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      with:
        persist-credentials: false

    - name: setup environment
      run: |
        sudo apt-get install --no-install-recommends \
          cmake \
          g++ \
          git \
          libasio-dev \
          libboost-test-dev \
          libtclap-dev \
          ninja-build \
          nlohmann-json3-dev \
          qtbase5-dev \
          ruby \
          ruby-dev

    - name: install ruby tools
      run: |
        sudo gem install bundler
        sudo bundle install

    - name: install gtest
      run: |
        git clone https://github.com/google/googletest.git
        cd googletest
        mkdir build
        cd build
        cmake ../
        cmake --build . --parallel
        sudo cmake --install .

    - name: build
      run: |
        cmake -E make_directory build
        cmake -E chdir build cmake \
          -G Ninja \
          -DCUKE_STRICT=on \
          -DCUKE_ENABLE_BOOST_TEST=on \
          -DCUKE_ENABLE_GTEST=on \
          -DCUKE_ENABLE_QT_5=on \
          -DCUKE_ENABLE_EXAMPLES=on \
          -DCUKE_TESTS_UNIT=on \
          ..
        cmake --build build --parallel --verbose

    - name: unit tests
      run: |
        cmake --build build --target test

    - name: QtCalc examples
      run: |
        for TEST in \
          build/examples/CalcQt/GTestCalculatorQtSteps \
          build/examples/CalcQt/QtTestCalculatorQtSteps \
          build/examples/CalcQt/BoostCalculatorQtSteps \
        ; do
          "${TEST}" 2> /dev/null &
          sleep 1
          (cd examples/CalcQt; cucumber)
          wait %
        done


================================================
FILE: .github/workflows/run-all.yml
================================================
name: run all

permissions: {}

on:
  pull_request:
    branches: [ main ]
  workflow_dispatch:
  push:
    branches:
      - main

concurrency:
  group: ${{ github.workflow }}-${{ github.head_ref || github.ref || github.run_id }}
  cancel-in-progress: true

jobs:
  build-linux:
    runs-on: ubuntu-22.04

    steps:
    - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      with:
        persist-credentials: false

    - name: update package index
      run: sudo apt-get -y update

    - name: setup environment
      run: |
        sudo apt-get install --no-install-recommends \
          cmake \
          g++ \
          gcovr \
          git \
          libasio-dev \
          libboost-test-dev \
          libgl1-mesa-dev \
          libtclap-dev \
          ninja-build \
          nlohmann-json3-dev \
          qt6-base-dev \
          ruby \
          ruby-dev

    - name: install ruby tools
      run: |
        sudo gem install bundler
        sudo bundle install

    - name: install gtest
      run: |
        git clone https://github.com/google/googletest.git
        cd googletest
        mkdir build
        cd build
        cmake ../
        cmake --build . --parallel
        sudo cmake --install .

    - name: build and run
      run: |
        ./run-linux.sh

    - name: code coverage summary report
      uses: irongut/CodeCoverageSummary@51cc3a756ddcd398d447c044c02cb6aa83fdae95 #v1.3.0
      with:
        filename: coverage/cobertura.xml
        indicators: false
        hide_complexity: true
        format: markdown
        output: file

    - name: publish code coverage summary
      run: |
        echo '# Code Coverage Report' >> $GITHUB_STEP_SUMMARY
        cat code-coverage-results.md >> $GITHUB_STEP_SUMMARY


================================================
FILE: .github/workflows/windows-build.yml
================================================
name: Windows build

permissions: {}

on:
  pull_request:
    branches: [ main ]
  workflow_dispatch:
  push:
    branches:
      - main

concurrency:
  group: ${{ github.workflow }}-${{ github.head_ref || github.ref || github.run_id }}
  cancel-in-progress: true

jobs:
  build:
    strategy:
      matrix:
        cpp-standard:
          - 17
          - 20
    # You can find specific tool versions for Windows builds in the Runner specification:
    # https://github.com/actions/runner-images/blob/main/images/windows/Windows2022-Readme.md
    # In particular, this build uses:
    # cmake: 3.27.9
    # VSCode: 2022 Enterprise Edition (corresponding C++ version: https://blog.knatten.org/2022/08/26/microsoft-c-versions-explained/)
    # Ruby: 3.0.6p216
    # boost: 1.82.0
    runs-on: windows-2022
    env:
      BOOST_VERSION: 1.82.0
      NLOHMANN_CLONE_DIR: nlohmann
      NLOHMANN_TAG: v3.11.3
      ASIO_CLONE_DIR: asio
      ASIO_TAG: asio-1-29-0
      TCLAP_CLONE_DIR: tclap
      TCLAP_TAG: v1.2.5

    steps:
    - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      with:
        persist-credentials: false

    - name: install ruby tools
      run: |
        gem install bundler
        bundle install

    # - name: Install Google Test
    #   uses: MarkusJx/googletest-installer@v1.1

    - name: Restore cached boost dependencies
      id: cache-boost-deps
      uses: actions/cache@6f8efc29b200d32929f49075959781ed54ec270c #v3.5.0
      with:
        path: |
          boost_1_82_0
        key: ${{ runner.os }}-boost-1820

    - name: install boost
      if: steps.cache-boost-deps.outputs.cache-hit != 'true'
      run: |
        $boost_version_str = ${Env:BOOST_VERSION}.Replace(".","_")
        $boost_url = "https://archives.boost.io/release/${Env:BOOST_VERSION}/source/boost_${boost_version_str}.zip"
        $ProgressPreference = 'SilentlyContinue'
        Write-Host "Downloading Boost from $boost_url"
        Invoke-WebRequest -Uri $boost_url -OutFile boost_${boost_version_str}.zip
        7z x boost_${boost_version_str}.zip
        Write-Host "Unzipped directory content:"
        Get-ChildItem -Directory
        cd boost_${boost_version_str}
        cmd /C bootstrap
        ./b2.exe --build-type=complete toolset=msvc --with-regex --with-program_options --with-system --with-test

    - name: Get and build nlohmann-json
      run: |
        Start-Process "git" -ArgumentList "clone https://github.com/nlohmann/json.git $Env:NLOHMANN_CLONE_DIR --depth 1 --branch $Env:NLOHMANN_TAG" -PassThru -NoNewWindow -Wait
        cd $Env:NLOHMANN_CLONE_DIR
        cmake -B build -S .
        cd ..

    - name: Get ASIO
      run: Start-Process "git" -ArgumentList "clone https://github.com/chriskohlhoff/asio.git $Env:ASIO_CLONE_DIR --depth 1 --branch $Env:ASIO_TAG" -PassThru -NoNewWindow -Wait

    - name: Get TCLAP
      run: Start-Process "git" -ArgumentList "clone https://github.com/mirror/tclap.git $Env:TCLAP_CLONE_DIR --depth 1 --branch $Env:TCLAP_TAG" -PassThru -NoNewWindow -Wait

    - name: build and run
      run: |
        $current_script_dir = Get-Location | Select-Object -Expand "Path"
        $Env:nlohmann_json_DIR = "${current_script_dir}/$Env:NLOHMANN_CLONE_DIR/build"
        $Env:Asio_ROOT = "${current_script_dir}/$Env:ASIO_CLONE_DIR/asio"
        $Env:TCLAP_ROOT = "${current_script_dir}/$Env:TCLAP_CLONE_DIR"
        $Env:cpp_standard = ${{ matrix.cpp-standard }}
        ./run-windows.ps1


================================================
FILE: .github/workflows/zizmor-analysis.yaml
================================================
name: GitHub Actions Security Analysis

on:
  push:
    branches:
      - main
      - 'releases/**'
    paths:
      - '.github/**'
  pull_request:
    paths:
      - '.github/**'

permissions: {}

jobs:
  zizmor:
    name: Run Zizmor
    runs-on: ubuntu-latest
    permissions:
      security-events: write
    steps:
      - name: Checkout repository
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false

      - name: Run Zizmor
        uses: zizmorcore/zizmor-action@71321a20a9ded102f6e9ce5718a2fcec2c4f70d8 # v0.5.2


================================================
FILE: .gitignore
================================================
# Bundler
/Gemfile.lock

# rvm
/.ruby-version
/.ruby-gemset

# Build artifacts
/build/
/coverage/
/.local/

# vim swap files
*.swp

# CLion
/.idea
/cmake-build-*/

# Qt Creator
/CMakeLists.txt.user

# build folder
build


================================================
FILE: CHANGELOG.md
================================================
Please see [CONTRIBUTING.md](https://github.com/cucumber/cucumber/blob/main/CONTRIBUTING.md) on how to contribute to Cucumber.

## [0.8.0](https://github.com/cucumber/cucumber-cpp/compare/v0.7.0...v0.8.0) (07 January 2026)

### Added

* Qt6 support ([#283](https://github.com/cucumber/cucumber-cpp/pull/283) Urs Fässler)
* Windows CI support ([#288](https://github.com/cucumber/cucumber-cpp/pull/288) Christoph Wellm)
* Test compilation with different compilers and language standards on Linux ([#282](https://github.com/cucumber/cucumber-cpp/pull/282) Urs Fässler)
* Test to fail the build for deprecated asio features ([72e5fa9](https://github.com/cucumber/cucumber-cpp/commit/72e5fa9ff643d90a513bff57f7322606ecaf4270) Shirzart Enwer)

### Changed

* Only enable minimal set of CMake options by default ([#281](https://github.com/cucumber/cucumber-cpp/pull/281) Urs Fässler)
* Use CMake option for strict checks ([#310](https://github.com/cucumber/cucumber-cpp/pull/310) Joerg Kreuzberger)
* Only treat compilation warnings as error in CI ([#301](https://github.com/cucumber/cucumber-cpp/pull/301) Joerg Kreuzberger)
* Remove support for Qt4 ([#283](https://github.com/cucumber/cucumber-cpp/pull/283) Urs Fässler)
* CalcQt example improvements ([#283](https://github.com/cucumber/cucumber-cpp/pull/283) Urs Fässler)
* Update README with explanation how it works ([#291](https://github.com/cucumber/cucumber-cpp/pull/291) erichstuder)
* Adjust links and information regarding where to get help ([#306](https://github.com/cucumber/cucumber-cpp/pull/306) Joerg Kreuzberger)
* Use https for all links in README ([0911bd2](https://github.com/cucumber/cucumber-cpp/commit/0911bd265bf0b484d5661f4163074714868cc77b) Joerg Kreuzberger)

### Fixed

* Support asio 1.33 ([#308](https://github.com/cucumber/cucumber-cpp/pull/308) Shirzart Enwer)
* Boost download source fixed ([#309](https://github.com/cucumber/cucumber-cpp/pull/309) Shirzart Enwer)
* Windows QtTestDriver ([#305](https://github.com/cucumber/cucumber-cpp/pull/305) Joerg Kreuzberger)
* Flaky QtTestDriver test ([#296](https://github.com/cucumber/cucumber-cpp/pull/296) Joerg Kreuzberger)
* Links to website and discussion group in README ([#299](https://github.com/cucumber/cucumber-cpp/pull/299) Joerg Kreuzberger)
* Compile error with C++20 ([ea089a6](https://github.com/cucumber/cucumber-cpp/commit/ea089a6369641445dc52099298779cef6affdb8f) Urs Fässler)

## [0.7.0](https://github.com/cucumber/cucumber-cpp/compare/v0.6...v0.7.0) (30 December 2023)

### Added

* add version info to cucumber-cpp-main ([8a0d16b8](https://github.com/cucumber/cucumber-cpp/pull/275/commits/8a0d16b8f59dd1c9d75045aa016d9ce235257311) Urs Fässler)
* Remove dependency to Boost ([#275](https://github.com/cucumber/cucumber-cpp/pull/275) Urs Fässler)
* List headers in cmake ([#274](https://github.com/cucumber/cucumber-cpp/pull/274) Urs Fässler)
* Check code format on PR and main branch ([#268](https://github.com/cucumber/cucumber-cpp/pull/268) Urs Fässler)

### Changed

* use semantic versioning ([#280](https://github.com/cucumber/cucumber-cpp/pull/280) Urs Fässler)
* No googletest auto-download ([#279](https://github.com/cucumber/cucumber-cpp/pull/279) Urs Fässler)
* Remove dependency to Boost ([#275](https://github.com/cucumber/cucumber-cpp/pull/275) Urs Fässler)
  * use asio without boost  ([d131ae39](https://github.com/cucumber/cucumber-cpp/pull/275/commits/d131ae3951b9aeb03dd787bf6fee4a06a81c1f04))
  * use TCLAP to parse program options ([b688cf41](https://github.com/cucumber/cucumber-cpp/pull/275/commits/b688cf41647803daa8a7656595b0d1bcbabf2310))
* use nlohmann/json library ([#273](https://github.com/cucumber/cucumber-cpp/pull/273) Urs Fässler)
* remove boost::multi_array ([#269](https://github.com/cucumber/cucumber-cpp/pull/269) Urs Fässler)
* Modernize overloading ([#267](https://github.com/cucumber/cucumber-cpp/pull/267) Urs Fässler)
* refactoring: use stl regex instead of boost::regex ([#266](https://github.com/cucumber/cucumber-cpp/pull/266) Urs Fässler)

### Fixed

* mention CI scripts for details about dependency installation ([#278](https://github.com/cucumber/cucumber-cpp/pull/278) Urs Fässler)
* remove broken E2E tests ([#272](https://github.com/cucumber/cucumber-cpp/pull/272) Urs Fässler)
* remove broken AppVeyor build ([#271](https://github.com/cucumber/cucumber-cpp/pull/271) Urs Fässler)

## [0.6](https://github.com/cucumber/cucumber-cpp/compare/v0.5...v0.6) (17 December 2023)

### Added

### Changed

* Using C++ standard library where possible instead of boost ([#264](https://github.com/cucumber/cucumber-cpp/pull/264) Urs Fässler)

### Fixed

* Statically linking `boost_system` ([#197](https://github.com/cucumber/cucumber-cpp/pull/197) Matthieu Longo)
* Unable to `add_subdirectory(cucumber-cpp)` ([#211](https://github.com/cucumber/cucumber-cpp/pull/211) Sergey Bon)
* Warning C4265 on Visual Studio ([#195](https://github.com/cucumber/cucumber-cpp/pull/195) Matthieu Longo)
* Fix handling of optional regex captures ([#221](https://github.com/cucumber/cucumber-cpp/pull/221) Alain Martin)
* Fix compilation with Boost 1.70.0 ([#225](https://github.com/cucumber/cucumber-cpp/pull/225) Krystian Młynarczyk)
* Support step definitions with multi-byte characters ([#224](https://github.com/cucumber/cucumber-cpp/pull/224) Spencer Rudnick)
* Supress warning about deprecated QSignalMapper ([#228](https://github.com/cucumber/cucumber-cpp/pull/228) Lukas Woodtli)
* Remove CACHE FORCE arguments from CMAKE_CXX_FLAG on colored terminal output ([#232](https://github.com/cucumber/cucumber-cpp/pull/232)  Alex Cani)
* Enable compiling with clang's -Wsuggest-override ([#244](https://github.com/cucumber/cucumber-cpp/pull/244) Tobias Hahn)
* Add posibility to build with sanitizers enabled ([#247](https://github.com/cucumber/cucumber-cpp/pull/247) Lukas Woodtli)
* Add support for latest GoogleTest and Boost ([#249](https://github.com/cucumber/cucumber-cpp/pull/249) Canmor Lam)
* add file extensions to adhere to policy CMP0115 ([#250](https://github.com/cucumber/cucumber-cpp/pull/250) Urs Fässler)
* Support latest Qt and test on Ubuntu 22.04 ([#253](https://github.com/cucumber/cucumber-cpp/pull/253) Urs Fässler)
* Update table.feature ([#258](https://github.com/cucumber/cucumber-cpp/pull/258) mbed101)

## [0.5](https://github.com/cucumber/cucumber-cpp/compare/v0.4...v0.5) (2 July 2018)

### Added

* QtTest based test driver for cucumber-cpp ([#165](https://github.com/cucumber/cucumber-cpp/pull/165) Kamil Strzempowicz)
* Listen on localhost by default to avoid firewall warnings ([#158](https://github.com/cucumber/cucumber-cpp/pull/158) Nik Reiman)
* Better integrate Qt into buildsystem, it can now be disabled, and test it in CI ([#160](https://github.com/cucumber/cucumber-cpp/pull/160) Kamil Strzempowicz & Giel van Schijndel)
* Support taking regex captures as arguments to the step definition's function ([#159](https://github.com/cucumber/cucumber-cpp/pull/159) Giel van Schijndel)
* Support building as shared library on Windows and hide internal symbols on all platforms ([#147](https://github.com/cucumber/cucumber-cpp/pull/147) [Nik Reiman](https://github.com/nre-ableton))
* Support installing library targets along with headers ([#182](https://github.com/cucumber/cucumber-cpp/pull/182) [Matthieu](https://github.com/matlo607))

### Changed

* Renamed HISTORY.md to CHANGELOG.md and updated to bring inline with [cucumber/cucumber #251](https://github.com/cucumber/cucumber/issues/251) ([#166](https://github.com/cucumber/cucumber-cpp/pull/166) [jaysonesmith](https://github.com/jaysonesmith))

### Fixed

* Fix compiler warning ([#192](https://github.com/cucumber/cucumber-cpp/issues/192) [Giel van Schijndel](https://github.com/muggenhor)), ([#184](https://github.com/cucumber/cucumber-cpp/pull/184) [Kamil Strzempowicz](https://github.com/konserw))
* Add missing virtual destructor in base class SocketServer used by TCPSocketServer and UnixSocketServer ([#183](https://github.com/cucumber/cucumber-cpp/pull/183) Matthieu Longo)
* Fix breaking changes in API of boost-1.66.0 ([#180](https://github.com/cucumber/cucumber-cpp/pull/180)  Matthieu Longo)
* Fix conflicting "using std" declaration with "using boost::thread" ([#181](https://github.com/cucumber/cucumber-cpp/pull/181)  Matthieu Longo)
* Fix building with boost > 1.64 by adding 2 new methods to BoostLogInterceptor ([#175](https://github.com/cucumber/cucumber-cpp/pull/175) Kamil Strzempowicz)
* Fixing Visual Studio 2013 error: no appropriate default constructor available ([#188](https://github.com/cucumber/cucumber-cpp/pull/188) Antoine Allard)
* Fix issue #81 by intercepting messages from BOOST_*_MESSAGE macros ([#164](https://github.com/cucumber/cucumber-cpp/pull/164) Kamil Strzempowicz)
* Allow running all GTest cases without filter separation ([#144](https://github.com/cucumber/cucumber-cpp/pull/144) Giel van Schijndel)
* Fix QNX build by depending on standard C++ instead of specific implementation ([#156](https://github.com/cucumber/cucumber-cpp/issues/156) Giel van Schijndel)
* Ensure CMake 3.1+ is available, 2.8.12 wasn't enough for quite a while ([#152](https://github.com/cucumber/cucumber-cpp/pull/152) Giel van Schijndel)
* Fix crash during termination of the CalcQt example's step definitions ([#62](https://github.com/cucumber/cucumber-cpp/issues/62) Giel van Schijndel)

## [0.4](https://github.com/cucumber/cucumber-cpp/compare/v0.3.1...v0.4) (31 March 2017)

### New Features

* Support for MinGW build ([#130](https://github.com/cucumber/cucumber-cpp/pull/130) Michel Estermann)
* Add support for Unix sockets ([#126](https://github.com/cucumber/cucumber-cpp/pull/126) Giel van Schijndel)
* Add support for using ephemeral ports ([#131](https://github.com/cucumber/cucumber-cpp/pull/131) Giel van Schijndel)
* Removed CppSpec support ([#118](https://github.com/cucumber/cucumber-cpp/pull/118) Paolo Ambrosio)
* Support for GoogleTest 1.8 ([#120](https://github.com/cucumber/cucumber-cpp/pull/120) Kamil Strzempowicz)
* Disable Nagle on TCP socket ([#125](https://github.com/cucumber/cucumber-cpp/pull/125) Giel van Schijndel)

### Bugfixes

* Fixed suggested step definition when step sentence contains double quote ([#116](https://github.com/cucumber/cucumber-cpp/issues/116) Kamil Strzempowicz, [fbc49a3](https://github.com/cucumber/cucumber-cpp/commit/fbc49a34e12a0b9b2a6e121d97ba1ad8f46dce8f) Paolo Ambrosio)
* Fixed `defs.hpp` deprecation warning on MSVC ([#124](https://github.com/cucumber/cucumber-cpp/pull/124) Antoine Allard)
* Fixed parallel build ([#135](https://github.com/cucumber/cucumber-cpp/pull/135) Giel van Schijndel)
* Fixed memory leaks and better memory management ([#134](https://github.com/cucumber/cucumber-cpp/pull/134) Giel van Schijndel)
* Fixed clang warning about bad `typeid` usage ([#138](https://github.com/cucumber/cucumber-cpp/pull/138) Kamil Strzempowicz)

## [0.3.1](https://github.com/cucumber/cucumber-cpp/compare/v0.3...v0.3.1) (11 April 2016)

### New Features

* Support for Boost 1.60 ([#101](https://github.com/cucumber/cucumber-cpp/pull/101) Kai Unger)
* Support for CMake inclusion in other projects ([#76](https://github.com/cucumber/cucumber-cpp/pull/76) Eric Brayet)
* Added Qt5 support in CalcQt example ([#98](https://github.com/cucumber/cucumber-cpp/pull/98) Kamil Strzempowicz)
* Improved Generic Driver to write steps without testing framework ([#99](https://github.com/cucumber/cucumber-cpp/pull/99) Kamil Strzempowicz)

### Bugfixes

None

## [0.3](https://github.com/cucumber/cucumber-cpp/compare/v0.2...v0.3) (22 December 2013)

### New Features

* Added BEFORE_ALL and AFTER_ALL macros ([#65](https://github.com/cucumber/cucumber-cpp/pull/65) Larry Price)
* Added CalcQt example ([#58](https://github.com/cucumber/cucumber-cpp/pull/58) Gianni Ambrosio)
* Replaced USING_CONTEXT with ScenarioScope<T> ([27256e9](https://github.com/cucumber/cucumber-cpp/commit/27256e932c75e9d4d57d4839042317e6a04cfe46) Paolo Ambrosio)
* Changed include name from core.hpp to defs.hpp ([5bbac06](https://github.com/cucumber/cucumber-cpp/commit/5bbac062e19dcf9de2761f4ded115aa7212c14d7) Paolo Ambrosio)
* Project rename from CukeBins to Cucumber-Cpp ([efecfd0](https://github.com/cucumber/cucumber-cpp/commit/efecfd0813efa1b6d406c2fd0cd03d8a84bed3ff) Paolo Ambrosio)

### Bugfixes

* Fixed socket server bug in VS2012 forcing Boost 1.51 ([#57](https://github.com/cucumber/cucumber-cpp/pull/57) Jared Szechy, [e41a9b7](https://github.com/cucumber/cucumber-cpp/commit/e681c5028a756d8f711574a86e84ca8b98333d5c) Paolo Ambrosio)
* Fixed crashes on some architectures ([#52](https://github.com/cucumber/cucumber-cpp/pull/52) Sabst)
* Fixed AFTER hook ordering issue ([#43](https://github.com/cucumber/cucumber-cpp/pull/43) Greg Williams)
* Added default empty constructor to work with less permissive gcc 4.6 settings ([#38](https://github.com/cucumber/cucumber-cpp/pull/38) Hugo Ferreira)


## [0.2](https://github.com/cucumber/cucumber-cpp/compare/v0.1...v0.2) (25 June 2011)

TODO


## [0.1](https://github.com/cucumber/cucumber-cpp/commits/v0.1) (03 May 2010)

* Initial implementation



================================================
FILE: CMakeLists.txt
================================================
cmake_minimum_required(VERSION 3.16)

cmake_policy(SET CMP0063 NEW)

# CMP0077: option() honors normal variables
# https://cmake.org/cmake/help/latest/policy/CMP0077.html
cmake_policy(SET CMP0077 NEW)

# CMP0074: find_package() makes use of <PackageName>_ROOT variables
# https://cmake.org/cmake/help/latest/policy/CMP0074.html
cmake_policy(SET CMP0074 NEW)

project(Cucumber-Cpp)

option(CUKE_ENABLE_BOOST_TEST   "Enable Boost.Test framework" OFF)
option(CUKE_ENABLE_GTEST        "Enable Google Test framework" OFF)
option(CUKE_ENABLE_QT_5         "Enable Qt5 framework" OFF)
option(CUKE_ENABLE_QT_6         "Enable Qt6 framework" OFF)

option(CUKE_ENABLE_EXAMPLES     "Build examples" OFF)
option(CUKE_TESTS_UNIT          "Enable unit tests" OFF)

option(BUILD_SHARED_LIBS        "Generate shared libraries" OFF)
option(CUKE_CODE_COVERAGE       "Enable instrumentation for code coverage" OFF)
set(CUKE_ENABLE_SANITIZER       "OFF" CACHE STRING "Sanitizer to use for checking")
set_property(CACHE CUKE_ENABLE_SANITIZER PROPERTY STRINGS OFF "address" "thread" "undefined")
option(CUKE_TESTS_VALGRIND      "Enable tests within Valgrind" OFF)
option(CUKE_STRICT              "Additional and more strict checks" OFF)

if(NOT DEFINED CMAKE_CXX_STANDARD)
    set(CMAKE_CXX_STANDARD 17)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    set(CMAKE_CXX_EXTENSIONS OFF)
elseif(CMAKE_CXX_STANDARD LESS 17)
    message(FATAL_ERROR "C++17 (above) is required")
endif()

if(CUKE_CODE_COVERAGE)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage")
endif()

if(CUKE_STRICT)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DASIO_NO_DEPRECATED")
endif()

set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/modules)

#
# Option deprecation: if deprecated option is defined
# then print a warning and use its value instead
#

function(option_depr_message old prefer)
    message (DEPRECATION "${old} is deprecated in favor of ${prefer}")
endfunction()

function(option_depr old prefer)
    if(DEFINED ${old})
        option_depr_message(${old} ${prefer})
        set (${prefer} ${${old}} CACHE BOOL "Set from deprecated ${old}" FORCE)
    endif()
endfunction()

function(option_depr_invert old prefer)
    if(DEFINED ${old})
        option_depr_message(${old} ${prefer})
        set (${prefer} $<NOT:${${old}}> CACHE BOOL "Set from deprecated ${old}" FORCE)
    endif()
endfunction()


option_depr_invert (CUKE_DISABLE_BOOST_TEST   CUKE_ENABLE_BOOST_TEST)
option_depr_invert (CUKE_DISABLE_GTEST        CUKE_ENABLE_GTEST)
option_depr_invert (CUKE_DISABLE_QT_5         CUKE_ENABLE_QT_5)
option_depr_invert (CUKE_DISABLE_QT_6         CUKE_ENABLE_QT_6)
option_depr_invert (CUKE_DISABLE_UNIT_TESTS   CUKE_TESTS_UNIT)
option_depr        (VALGRIND_TESTS            CUKE_TESTS_VALGRIND)

#
# Check that at least one test framework is enabled
#

set(CUKE_TEST_FRAMEWORKS
    CUKE_ENABLE_BOOST_TEST
    CUKE_ENABLE_GTEST
    CUKE_ENABLE_QT_5
    CUKE_ENABLE_QT_6
)

set(TEST_FRAMEWORK_FOUND FALSE)
foreach(test_framework ${CUKE_TEST_FRAMEWORKS})
    if(${test_framework})
        set(TEST_FRAMEWORK_FOUND TRUE)
    endif()
endforeach()

if(NOT TEST_FRAMEWORK_FOUND)
    message(WARNING "No test framework enabled. At least one should be enabled. Options are: ${CUKE_TEST_FRAMEWORKS}.")
endif()

#
# Generic Compiler Flags
#

if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_INIT} -Wall -Wextra -Wsuggest-override ${CMAKE_CXX_FLAGS}")
    # TODO: A better fix should handle ld's --as-needed flag
    if(UNIX AND NOT APPLE)
        set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Xlinker '--no-as-needed'")
    endif()
elseif(MSVC)
    set(CMAKE_CXX_FLAGS "-DNOMINMAX ${CMAKE_CXX_FLAGS}") # exclude M$ min/max macros
    set(CMAKE_CXX_FLAGS "/wd4996 ${CMAKE_CXX_FLAGS}") # don't warn about use of plain C functions without (non-portable) "_s" suffix
    #set(CMAKE_CXX_FLAGS_DEBUG "/analyze ${CMAKE_CXX_FLAGS_DEBUG}")
endif()

#
# Colored Terminal Output
#

if(UNIX AND (
       (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
    OR (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9))
    AND CMAKE_GENERATOR STREQUAL "Ninja")
  # These compilers generate coloured output, but by default only when their output channel is a
  # terminal (TTY/PTY). Ninja however captures all output in a pipe (per-subprocess), disabling
  # coloured compiler diagnostics. We forcefully enable it because Ninja, since 1.0.0
  # (ninja-build/ninja#198) takes care to strip VT100 CSI control sequences from the output if Ninja
  # itself is writing to a pipe instead of a terminal. As a result this should give us the best of
  # both worlds: coloured output when we're running in a terminal, plain output for editors, IDEs,
  # etc.
  set(CMAKE_CXX_FLAGS "-fdiagnostics-color=always ${CMAKE_CXX_FLAGS}")
endif()

#
# Boost
#

set(Boost_USE_STATIC_RUNTIME OFF)
if(CUKE_ENABLE_BOOST_TEST)
    # "An external test runner utility is required to link with dynamic library" (Boost User's Guide)
    set(CMAKE_CXX_FLAGS "-DBOOST_TEST_DYN_LINK ${CMAKE_CXX_FLAGS}")
    find_package(Boost 1.70 COMPONENTS unit_test_framework REQUIRED)
endif()

#
# GTest
#

if(CUKE_ENABLE_GTEST)
    find_package(GTest 1.11.0 REQUIRED)
endif()

#
# Qt
#

if(CUKE_ENABLE_QT_5 AND CUKE_ENABLE_QT_6)
    message(FATAL_ERROR "Qt version 5 and 6 enabled, please select at most one")
endif()


if(CUKE_ENABLE_QT_5)
    find_package(Qt5 REQUIRED COMPONENTS
        Core
        Gui
        Widgets
        Test
    )

    message(STATUS "Found Qt version: ${Qt5Core_VERSION_STRING}")
    if(Qt5Core_VERSION_STRING VERSION_LESS 5.15.0)
        add_library(Qt::Core    INTERFACE IMPORTED)
        add_library(Qt::Gui     INTERFACE IMPORTED)
        add_library(Qt::Widgets INTERFACE IMPORTED)
        add_library(Qt::Test    INTERFACE IMPORTED)
        set_target_properties(Qt::Core    PROPERTIES INTERFACE_LINK_LIBRARIES Qt5::Core   )
        set_target_properties(Qt::Gui     PROPERTIES INTERFACE_LINK_LIBRARIES Qt5::Gui    )
        set_target_properties(Qt::Widgets PROPERTIES INTERFACE_LINK_LIBRARIES Qt5::Widgets)
        set_target_properties(Qt::Test    PROPERTIES INTERFACE_LINK_LIBRARIES Qt5::Test   )
    endif()
endif()

if(CUKE_ENABLE_QT_6)
    find_package(Qt6 REQUIRED COMPONENTS
        Core
        Gui
        Widgets
        Test
    )

    message(STATUS "Found Qt version: ${Qt6Core_VERSION}")
endif()


#
# Sanitizers
#

if(CUKE_ENABLE_SANITIZER AND NOT ${CUKE_ENABLE_SANITIZER} EQUAL "OFF")
    message("Disabling valgrind when a sanitizer is enabled")
    set(CUKE_TESTS_VALGRIND OFF)

    if (WIN32)
        message(WARNING "The use of the sanatizers on Windows is not tested")
    endif()

    add_compile_options("-fsanitize=${CUKE_ENABLE_SANITIZER}")
    add_link_options("-fsanitize=${CUKE_ENABLE_SANITIZER}")
endif()



#
# Valgrind
#

if(CUKE_TESTS_VALGRIND)
    find_package(Valgrind REQUIRED)
    set(VALGRIND_ARGS --error-exitcode=2 --leak-check=full --undef-value-errors=no)
    if(NOT VALGRIND_VERSION_STRING VERSION_LESS 3.9)
        # Valgrind 3.9 no longer shows all leaks unless asked to
        list(APPEND VALGRIND_ARGS --show-leak-kinds=all)
    endif()
    function(add_test name)
        if(NOT name STREQUAL "NAME")
            _add_test(${VALGRIND_EXECUTABLE} ${VALGRIND_ARGS} ${ARGV})
            return()
        endif()

        set(TEST_ARGS ${ARGV})
        list(FIND TEST_ARGS COMMAND COMMAND_IDX)
        if(COMMAND_IDX EQUAL -1)
            message(AUTHOR_WARNING "Weird command-line given to add_test(), not injecting valgrind")
            _add_test(${ARGV})
            return()
        endif()

        # We want to operate on the COMMAND, not the 'COMMAND' keyword preceding it
        math(EXPR COMMAND_IDX "${COMMAND_IDX} + 1")

        # Keep add_test() behaviour of replacing COMMANDs, when executable targets, with their output files
        list(GET TEST_ARGS ${COMMAND_IDX} COMMAND)
        if(TARGET ${COMMAND})
            get_target_property(COMMAND_TYPE ${COMMAND} TYPE)
            if(COMMAND_TYPE STREQUAL "EXECUTABLE")
                # Inserting first, removing the original only after that, because inserting to the end of the list doesn't work
                math(EXPR ORIG_COMMAND_IDX "${COMMAND_IDX} + 1")
                list(INSERT TEST_ARGS ${COMMAND_IDX} "$<TARGET_FILE:${COMMAND}>")
                list(REMOVE_AT TEST_ARGS ${ORIG_COMMAND_IDX})
            endif()
        endif()

        # Insert the valgrind command line, before the command to execute
        list(INSERT TEST_ARGS ${COMMAND_IDX} ${VALGRIND_EXECUTABLE} ${VALGRIND_ARGS})

        _add_test(${TEST_ARGS})
    endfunction()
endif()

#
# Cucumber-Cpp
#

set(CUKE_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include)
add_subdirectory(src)

#
# Tests
#

if(CUKE_TESTS_UNIT)
    enable_testing()
    add_subdirectory(tests)
else()
    message(STATUS "Skipping unit tests")
endif()

#
# Examples
#

if(CUKE_ENABLE_EXAMPLES)
    add_subdirectory(examples)
endif()


================================================
FILE: CONTRIBUTING.md
================================================
## About to create a new Github Issue?

We appreciate that. But before you do, please learn our basic rules:

* Do you have a feature request? Then don't expect it to be implemented unless you or someone else sends a [pull request](https://help.github.com/articles/using-pull-requests).
* Reporting a bug? We need to know what compiler, operating system and architecture (32 or 64 bit) you are using, including versions of all libraries. Bugs with [pull requests](https://help.github.com/articles/using-pull-requests) get fixed quicker. Some bugs may never be fixed.
* You have to tell us how to reproduce a bug. Bonus point for a [pull request](https://help.github.com/articles/using-pull-requests) with a failing test that reproduces the bug.
* Want to paste some code or output? Put \`\`\` on a line above and below your code/output. See [GFM](https://help.github.com/articles/github-flavored-markdown)'s *Fenced Code Blocks* for details.
* We love [pull requests](https://help.github.com/articles/using-pull-requests), but if you don't have a test to go with it we probably won't merge it.

## Contributing

Before you can contribute, you have to be able to build the source and run tests.

### The Github Process

The process for using git/github is similar to the [Github-Flow](http://scottchacon.com/2011/08/31/github-flow.html)

* **Anything** in the main branch is good enough to release
* Working on nontrivial features
    + Create a descriptively named branch off of main
    + Commit to that branch locally and regularly
    + Push your work to the same named branch on the server
    + Regularly rebase this branch from main to keep it up to date
* Open a pull request
    + When you need feedback or help
    + You think the branch is ready for merging (you can use the [hub](https://github.com/defunkt/hub#git-pull-request) command-line tool)
* For any nontrivial change, even if you have the rights to merge the pull request yourself, wait before someone else has reviewed and agreed on the change

Here is an [Example](https://github.com/cucumber/bool/pull/12) of this process in action

#### Tips for good commits

1. Read up on [Github Flavored Markdown](https://help.github.com/articles/github-flavored-markdown)
    + Especially links and syntax highlighting. GFM can be used in tickets as well as commit messages (e.g. put "#4" somewhere in a commit message to link ticket 4 to that commit
2. Close tickets with commits if you can
    + Add "Closes #5, #9" somewhere in the commit message to both link and close. See [Issues 2.0 the Next Generation](https://github.com/blog/831-issues-2-0-the-next-generation) for details.
    + Use [this script](https://gist.github.com/aslakhellesoy/4754009) to compile and view GFM locally
3. Subscribe to ticket feeds so you stay in the loop and get a chance to provide feedback on tickets
4. The code standard is the existing code
    + Use the same indentation, spacing, line ending, ASCII for source code, UTF-8 everywhere else
5. Use git diff (or git diff --cached if you have staged) before every commit
    + This helps you avoid committing changes you didn't mean to

## Maintainers' guide

### Merge a PR

- Verify that:
  - All checks have passed
  - At least one maintainer has approved any non-trivial change, and a
    discussion has occurred for any breaking change
  - The branch does not need rebasing or squashing of commits
- To merge:
  - Follow the command line instructions on GitHub
  - If it is either a new feature or a bugfix, specify the `--no-commit`
    flag when merging and add a line to `CHANGELOG.md` following the
    current convention. Add this file to the changes to be committed and
    commit the merge.
  - Commit message should follow the current convention:
    `Merge #42 'Description of the change usually from the PR description'`

### Do a release

- Release commit (e.g. [fdf8a5c](https://github.com/cucumber/cucumber-cpp/commit/fdf8a5c4ef4c51dfa7ea82077f706414a4c6322d)):
  - Change `CHANGELOG.md` renaming the "In Git" section with the release number and date
  - Commit with message `Update changelog for the X.Y.Z release`
  - Create an annotated tag for this commit named `vX.Y.Z`
- New development branch commit (e.g. [da60995](https://github.com/cucumber/cucumber-cpp/commit/da609956fcd42046e5182c6226acd7e53dd7754e)):
  - Add new "In Git" section to `CHANGELOG.md`
  - Commit with message `Preparing history file for next development release`
- Push commits and tags to main


================================================
FILE: Gemfile
================================================
source 'https://rubygems.org'

group :test do
  gem 'cucumber', "=7.1.0"
  gem 'cucumber-wire', "=6.2.1"
end



================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2010 Paolo Ambrosio

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# Cucumber-CPP

## Overview

Cucumber-Cpp allows Cucumber to support step definitions written in C++.

* [Cucumber-Cpp Website](https://github.com/cucumber/cucumber-cpp)
* [Cucumber-Cpp Documentation](https://github.com/cucumber/cucumber-cpp/wiki/)
* [Cucumber Website](https://cucumber.io/)
* [Get in touch](https://cucumber.io/docs/community/get-in-touch/)

If you need to ask a question, post on the [Cucumber discussion group](https://github.com/orgs/cucumber/discussions).

If you want to contribute code to the project, guidelines are in [CONTRIBUTING.md](CONTRIBUTING.md).

## Dependencies

It relies on a few executables:

* [cmake](https://cmake.org/download/) 3.16 or later.
  Required to setup environment and build software

It relies on a few libraries:

* [Asio](https://think-async.com/Asio/) 1.18.1 or later.
* [Boost.Test](https://www.boost.org/) 1.70. Optional for the Boost Test driver.
* [GTest](https://github.com/google/googletest) 1.11.0 or later. Optional for the GTest driver.
* [GMock](https://github.com/google/googletest) 1.11.0 or later. Optional for the internal test suite.
* [nlohmann-json](https://github.com/nlohmann/json) 3.10.5 or later.
* [Qt6 or Qt5](https://qt-project.org/). Optional for the CalcQt example and QtTest driver.
* [TCLAP](https://tclap.sourceforge.net/) 1.2.5 or later.

It might work with earlier versions of the libraries, but it was not tested with them.
See the [CI scripts](.github/workflows/run-all.yml) for details about dependency installation.

Cucumber-Cpp uses the wire protocol at the moment, so you will need
Cucumber-Ruby installed and available on the path. It is also needed
to run the functional test suite.

Please mind that Cucumber-Cpp is not compatible with Cucumber-Ruby 3.x
due to a [bug in its wire protocol](https://github.com/cucumber/cucumber-ruby/issues/1183)
implementation.

To install the Ruby prerequisites:

```
gem install bundler // For windows: gem install bundle
bundle install
```

### Windows vs. Linux

To get an inspiration on how to set up the dependencies on your specific system (Windows or Linux), you may want to have a look at the
workflow files [for Windows](.github/workflows/windows-build.yml) and [for Linux](.github/workflows/linux-build.yml).


## Build

Building Cucumber-Cpp with tests and samples:

```
# Create build directory
cmake -E make_directory build

# Generate Makefiles
cmake -E chdir build cmake \
    -DCUKE_ENABLE_BOOST_TEST=on \
    -DCUKE_ENABLE_GTEST=on \
    -DCUKE_ENABLE_QT_6=on \
    -DCUKE_TESTS_UNIT=on \
    -DCUKE_ENABLE_EXAMPLES=on \
    ..

# Build cucumber-cpp
cmake --build build

# Run unit tests
cmake --build build --target test

# Run install
cmake --install build
```

Running the Calc example on Unix:

```
build/examples/Calc/BoostCalculatorSteps >/dev/null &
(cd examples/Calc; cucumber)
```

Running the Calc example on Windows (NMake):

```
start build\examples\Calc\BoostCalculatorSteps.exe
cucumber examples\Calc
```

## The way it works
(This is a great explanation by [paoloambrosio](https://github.com/paoloambrosio) copied from [stackoverflow](https://stackoverflow.com/questions/50760865/cucumber-cpp-required-software-for-running-example))

The way Cucumber-CPP currently works is by having Cucumber-Ruby connecting to a TCP port where the C++ implementation is listening. When the wire protocol is defined in the cucumber.wire file, with host and port where your C++ wire protocol server is listening, Cucumber-Ruby will try and run them with Cucumber-CPP.

C++ is a compiled language, so step definitions must be compiled first. The examples provided use CMake, as described in the README. Cucumber-CPP needs to be linked to the step definitions and to everything that they use (usually the application under test), creating an executable file that will listen to the wire protocol port (defaults to localhost:3902) for Cucumber-Ruby to connect to (and exiting when it disconnects).

```
                    +------------------------------------------+
                    |                                          |
+----------+        | +----------+  +----------+  +----------+ |
|          |        | |          |  |          |  |          | |
| Cucumber |        | | Cucumber |  | C++ Step |  | Your     | |
| Ruby     |--------->| CPP Wire |--| Defs     |--| CPP App  | |
|          |        | | Server   |  |          |  |          | |
|          |        | |          |  |          |  |          | |
+----------+        | +----------+  +----------+  +----------+ |
                    |                                          |
                    +------------------------------------------+
```

## Getting started

Here is a basic example on how to get started with *cucumber-cpp*. First you need to create the basic feature structure:

```
cucumber --init
```

Then create a *cucumber.wire* file in the *features/step_definitions* folder with the following content:

```
host: localhost
port: 3902
```

Create your first feature (an example is available [here](examples/Calc/features/addition.feature)).

Then create your step definition runner (an example is available [here](examples/Calc/features/step_definitions/BoostCalculatorSteps.cpp)). In order to compile the step definition runner, make sure to add [cucumber include directory](include/cucumber-cpp) to the include path and link with *libcucumber-cpp.a* and additional testing libraries (boost unit test).

Run the step definition runner in the background and then cucumber, like in the Calc example in the previous section. The step definition runner should exit after the feature is run and cucumber exits.


================================================
FILE: cmake/modules/FindAsio.cmake
================================================
find_path(ASIO_INCLUDE_DIR asio.hpp)

if (ASIO_INCLUDE_DIR)
    set(ASIO_FOUND TRUE)
else ()
    set(ASIO_FOUND FALSE)
endif ()

include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Asio REQUIRED_VARS ASIO_INCLUDE_DIR)


================================================
FILE: cmake/modules/FindTCLAP.cmake
================================================
find_path(TCLAP_INCLUDE_DIR tclap/CmdLine.h)

if (TCLAP_INCLUDE_DIR)
    set(TCLAP_FOUND TRUE)
else ()
    set(TCLAP_FOUND FALSE)
endif ()

include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(TCLAP REQUIRED_VARS TCLAP_INCLUDE_DIR)


================================================
FILE: cmake/modules/FindValgrind.cmake
================================================
#.rst:
# FindValgrind
# -------
#
# The module defines the following variables:
#
# ``VALGRIND_EXECUTABLE``
#   Path to Valgrind command-line client.
# ``Valgrind_FOUND``
#   True if the Valgrind command-line client was found.
# ``VALGRIND_VERSION_STRING``
#   The version of Valgrind found.
#
# Example usage:
#
# .. code-block:: cmake
#
#    find_package(Valgrind)
#    if(Valgrind_FOUND)
#      message("Valgrind found: ${VALGRIND_EXECUTABLE}")
#    endif()

#=============================================================================
# Copyright (c) 2017 Giel van Schijndel
#
# CMake - Cross Platform Makefile Generator
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
#   notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright
#   notice, this list of conditions and the following disclaimer in the
#   documentation and/or other materials provided with the distribution.
#
# * Neither the names of Kitware, Inc., the Insight Software Consortium,
#   nor the names of their contributors may be used to endorse or promote
#   products derived from this software without specific prior written
#   permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# ------------------------------------------------------------------------------
#
# The above copyright and license notice applies to distributions of
# CMake in source and binary form.  Some source files contain additional
# notices of original copyright by their contributors; see each source
# for details.  Third-party software packages supplied with CMake under
# compatible licenses provide their own copyright notices documented in
# corresponding subdirectories.
#
# ------------------------------------------------------------------------------
#
# CMake was initially developed by Kitware with the following sponsorship:
#
#  * National Library of Medicine at the National Institutes of Health
#    as part of the Insight Segmentation and Registration Toolkit (ITK).
#
#  * US National Labs (Los Alamos, Livermore, Sandia) ASC Parallel
#    Visualization Initiative.
#
#  * National Alliance for Medical Image Computing (NAMIC) is funded by the
#    National Institutes of Health through the NIH Roadmap for Medical Research,
#    Grant U54 EB005149.
#
#  * Kitware, Inc.
#=============================================================================

find_program(VALGRIND_EXECUTABLE
  NAMES valgrind
  DOC "Valgrind command line executable"
)
mark_as_advanced(VALGRIND_EXECUTABLE)

if(VALGRIND_EXECUTABLE)
    execute_process(COMMAND ${VALGRIND_EXECUTABLE} --version
                    OUTPUT_VARIABLE VALGRIND_VERSION_STRING
                    ERROR_QUIET
                    OUTPUT_STRIP_TRAILING_WHITESPACE)
    if (VALGRIND_VERSION_STRING MATCHES "^valgrind-[0-9]")
        string(REPLACE "valgrind-" "" VALGRIND_VERSION_STRING "${VALGRIND_VERSION_STRING}")
    endif()
endif()

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Valgrind
                                  REQUIRED_VARS VALGRIND_EXECUTABLE
                                  VERSION_VAR VALGRIND_VERSION_STRING)


================================================
FILE: cmake/modules/GitVersion.cmake
================================================
function(git_get_version VERSION_VARIABLE)
    find_program(GIT_EXECUTABLE git)

    if(NOT GIT_EXECUTABLE)
        message(FATAL_ERROR "Git not found. Please install Git and make sure it is in your system's PATH.")
    endif()

    execute_process(
        COMMAND ${GIT_EXECUTABLE} describe --always --dirty
        OUTPUT_VARIABLE VERSION_STRING
        OUTPUT_STRIP_TRAILING_WHITESPACE
        WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
        ERROR_VARIABLE GIT_DESCRIBE_ERROR
        RESULT_VARIABLE GIT_DESCRIBE_RESULT
    )

    if(NOT GIT_DESCRIBE_RESULT EQUAL 0)
        message(FATAL_ERROR "Error running 'git describe': ${GIT_DESCRIBE_ERROR}")
    endif()

    string(LENGTH "${VERSION_STRING}" VERSION_STRING_LENGTH)
    string(SUBSTRING "${VERSION_STRING}" 0 1 FIRST_CHARACTER)

    if("${FIRST_CHARACTER}" STREQUAL "v")
        string(SUBSTRING "${VERSION_STRING}" 1 ${VERSION_STRING_LENGTH} VERSION_STRING)
    endif()

    set(${VERSION_VARIABLE} ${VERSION_STRING} PARENT_SCOPE)
endfunction()


================================================
FILE: examples/CMakeLists.txt
================================================
add_subdirectory(Calc)
add_subdirectory(CalcQt)
add_subdirectory(FeatureShowcase)


================================================
FILE: examples/Calc/CMakeLists.txt
================================================
project(Calc)

add_library(Calc STATIC src/Calculator.cpp)
target_include_directories(Calc INTERFACE src)

if(TARGET GTest::gtest)
    add_executable(GTestCalculatorSteps features/step_definitions/GTestCalculatorSteps.cpp)
    target_link_libraries(GTestCalculatorSteps PRIVATE Calc cucumber-cpp GTest::gtest)

    add_executable(FuncArgsCalculatorSteps features/step_definitions/FuncArgsCalculatorSteps.cpp)
    target_link_libraries(FuncArgsCalculatorSteps PRIVATE Calc cucumber-cpp GTest::gtest)
endif()

if(TARGET Boost::unit_test_framework)
    add_executable(BoostCalculatorSteps features/step_definitions/BoostCalculatorSteps.cpp)
    target_link_libraries(BoostCalculatorSteps PRIVATE Calc cucumber-cpp Boost::unit_test_framework)
endif()

if(TARGET Qt::Test)
    add_executable(QtTestCalculatorSteps features/step_definitions/QtTestCalculatorSteps.cpp)
    target_link_libraries(QtTestCalculatorSteps Calc Qt::Test cucumber-cpp)
endif()


================================================
FILE: examples/Calc/README.txt
================================================
This was inspired by Cuke4Nuke Calc sample



================================================
FILE: examples/Calc/features/addition.feature
================================================
# language: en
Feature: Addition
  In order to avoid silly mistakes
  As a math idiot 
  I want to be told the sum of two numbers

  Scenario Outline: Add two numbers
    Given I have entered <input_1> into the calculator
    And I have entered <input_2> into the calculator
    When I press <button>
    Then the result should be <output> on the screen

  Examples:
    | input_1 | input_2 | button | output |
    | 20      | 30      | add    | 50     |
    | 2       | 5       | add    | 7      |
    | 0       | 40      | add    | 40     |


================================================
FILE: examples/Calc/features/division.feature
================================================
# language: en
Feature: Division
  In order to avoid silly mistakes
  Cashiers must be able to calculate a fraction

  Scenario: Regular numbers
    Given I have entered 3 into the calculator
    And I have entered 2 into the calculator
    When I press divide
    Then the result should be 1.5 on the screen


================================================
FILE: examples/Calc/features/step_definitions/BoostCalculatorSteps.cpp
================================================
#include <boost/test/unit_test.hpp>
// Pretend to be GTest
#define EXPECT_EQ BOOST_CHECK_EQUAL
#include "CalculatorSteps.cpp"


================================================
FILE: examples/Calc/features/step_definitions/CalculatorSteps.cpp
================================================
#include <cucumber-cpp/autodetect.hpp>

#include <Calculator.hpp>

using cucumber::ScenarioScope;

struct CalcCtx {
    Calculator calc;
    double result;
};

GIVEN("^I have entered (\\d+) into the calculator$") {
    REGEX_PARAM(double, n);
    ScenarioScope<CalcCtx> context;

    context->calc.push(n);
}

WHEN("^I press add") {
    ScenarioScope<CalcCtx> context;

    context->result = context->calc.add();
}

WHEN("^I press divide") {
    ScenarioScope<CalcCtx> context;

    context->result = context->calc.divide();
}

THEN("^the result should be (.*) on the screen$") {
    REGEX_PARAM(double, expected);
    ScenarioScope<CalcCtx> context;

    EXPECT_EQ(expected, context->result);
}


================================================
FILE: examples/Calc/features/step_definitions/FuncArgsCalculatorSteps.cpp
================================================
#include <gtest/gtest.h>
#include <cucumber-cpp/autodetect.hpp>

#include <Calculator.hpp>

using cucumber::ScenarioScope;

struct CalcCtx {
    Calculator calc;
    double result;
};

GIVEN("^I have entered (\\d+) into the calculator$", (const double n)) {
    ScenarioScope<CalcCtx> context;

    context->calc.push(n);
}

WHEN("^I press add") {
    ScenarioScope<CalcCtx> context;

    context->result = context->calc.add();
}

WHEN("^I press divide") {
    ScenarioScope<CalcCtx> context;

    context->result = context->calc.divide();
}

THEN("^the result should be (.*) on the screen$", (const double expected)) {
    ScenarioScope<CalcCtx> context;

    EXPECT_EQ(expected, context->result);
}


================================================
FILE: examples/Calc/features/step_definitions/GTestCalculatorSteps.cpp
================================================
#include <gtest/gtest.h>
#include "CalculatorSteps.cpp"


================================================
FILE: examples/Calc/features/step_definitions/QtTestCalculatorSteps.cpp
================================================
#include <QTest>
// Pretend to be GTest
#define EXPECT_EQ QCOMPARE
#include "CalculatorSteps.cpp"


================================================
FILE: examples/Calc/features/step_definitions/cucumber.wire
================================================
host: localhost
port: 3902


================================================
FILE: examples/Calc/src/Calculator.cpp
================================================
#include <limits>
#include "Calculator.hpp"

void Calculator::push(double n) {
    values.push_back(n);
}

double Calculator::add() {
    double result = 0;
    for (std::list<double>::const_iterator i = values.begin(); i != values.end(); ++i) {
        result += *i;
    }
    return result;
}

double Calculator::divide() {
    double result = std::numeric_limits<double>::quiet_NaN();
    for (std::list<double>::const_iterator i = values.begin(); i != values.end(); ++i) {
        if (i == values.begin()) {
            result = *i;
        } else {
            result /= *i;
        }
    }
    return result;
}


================================================
FILE: examples/Calc/src/Calculator.hpp
================================================
#pragma once

#include <list>

class Calculator {
private:
    std::list<double> values;

public:
    void push(double);
    double add();
    double divide();
};


================================================
FILE: examples/CalcQt/CMakeLists.txt
================================================
project(CalcQt)

if(TARGET Qt::Core AND TARGET Qt::Gui AND TARGET Qt::Widgets AND TARGET Qt::Test)
    set(CMAKE_AUTOMOC ON)

    add_library(libcalcqt STATIC src/Calculator.cpp src/Calculator.hpp)
    target_include_directories(libcalcqt INTERFACE src)
    target_link_libraries(libcalcqt
        PUBLIC
            Qt::Core
    )

    add_executable(calcqt
        src/CalcQt.cpp
        src/CalculatorWidget.cpp
        src/CalculatorWidget.hpp
    )
    target_link_libraries(calcqt
        PRIVATE
            libcalcqt
            Qt::Core
            Qt::Gui
            Qt::Widgets
    )

    add_executable(QtTestCalculatorQtSteps features/step_definitions/QtTestCalculatorQtSteps.cpp)
    target_link_libraries(QtTestCalculatorQtSteps PRIVATE libcalcqt Qt::Test cucumber-cpp)

    if(TARGET Boost::unit_test_framework)
        add_executable(BoostCalculatorQtSteps features/step_definitions/BoostCalculatorQtSteps.cpp)
        target_link_libraries(BoostCalculatorQtSteps PRIVATE libcalcqt Boost::unit_test_framework cucumber-cpp)
    endif()

    if(TARGET GTest::gtest)
        add_executable(GTestCalculatorQtSteps features/step_definitions/GTestCalculatorQtSteps.cpp)
        target_link_libraries(GTestCalculatorQtSteps PRIVATE libcalcqt GTest::gtest cucumber-cpp)
    endif()

endif()


================================================
FILE: examples/CalcQt/README.txt
================================================
This sample shows how to test a QT GUI. The environment variable
CALCQT_STEP_DELAY allows to introduce delays in the step execution for
demo purposes (i.e. CALCQT_STEP_DELAY=100 ./BoostCalculatorQtSteps)



================================================
FILE: examples/CalcQt/features/addition.feature
================================================
# language: en
Feature: Addition
  In order to avoid silly mistakes
  As a math idiot 
  I want to be told the sum of two numbers

  Scenario Outline: Add two numbers
    Given I just turned on the calculator
    When I press <button1>
    And I press add
    And I press <button2>
    And I press calculate
    Then the display should show <result>

  Examples:
    | button1 | button2 | result |
    | 2       | 3       | 5      |
    | 7       | 5       | 12     |
    | 9       | 1       | 10     |


================================================
FILE: examples/CalcQt/features/behavior.feature
================================================
# language: en
Feature: GUI behavior
  tests for buttons

  Scenario Outline: Digit buttons
    Given I just turned on the calculator
    When I press <button>
    Then the display should show <output>

  Examples:
    | button | output |
    | 0      | 0      |
    | 1      | 1      |
    | 2      | 2      |
    | 3      | 3      |
    | 4      | 4      |
    | 5      | 5      |
    | 6      | 6      |
    | 7      | 7      |
    | 8      | 8      |
    | 9      | 9      |

  Scenario: Clear button
    Given I just turned on the calculator
    When I press 2
    And I press clear
    Then the display should be empty

  Scenario: Addition button
    Given I just turned on the calculator
    When I press add
    Then the display should show +

  Scenario: Subtraction button
    Given I just turned on the calculator
    When I press subtract
    Then the display should show -

  Scenario Outline: Digit sequence
    Given I just turned on the calculator
    When I press <button1>
    And I press <button2>
    Then the display should show <output>

  Examples:
    | button1 | button2 | output |
    | 2       | 2       | 22     |
    | 7       | 4       | 74     |
    | 3       | 8       | 38     |

  Scenario Outline: Addition operation
    Given I just turned on the calculator
    When I press <button1>
	 And I press add
    And I press <button2>
    Then the display should show <output>

  Examples:
    | button1 | button2 | output |
    | 2       | 2       | 2+2    |
    | 7       | 4       | 7+4    |
    | 3       | 8       | 3+8    |


  Scenario Outline: Subtraction operation
    Given I just turned on the calculator
    When I press <button1>
	 And I press subtract
    And I press <button2>
    Then the display should show <output>

  Examples:
    | button1 | button2 | output |
    | 2       | 2       | 2-2    |
    | 7       | 4       | 7-4    |
    | 3       | 8       | 3-8    |



================================================
FILE: examples/CalcQt/features/initialization.feature
================================================
# language: en
Feature: GUI initalization
  test the initial status of the calculator

  Scenario: Initialization
    Given I just turned on the calculator
    Then the display should be empty



================================================
FILE: examples/CalcQt/features/step_definitions/BoostCalculatorQtSteps.cpp
================================================
#include <boost/test/unit_test.hpp>
// Pretend to be GTest
#define EXPECT_EQ BOOST_CHECK_EQUAL
#define ASSERT_TRUE BOOST_REQUIRE
#include "CalculatorQtSteps.cpp"


================================================
FILE: examples/CalcQt/features/step_definitions/CalculatorQtSteps.cpp
================================================
#include <cucumber-cpp/autodetect.hpp>

#include "Calculator.hpp"

class CalculatorCtx {
public:
    CalculatorCtx() {
        QObject::connect(&calculator, &Calculator::updateDisplay, [this](QString value) {
            display = value;
        });
    }

    Calculator calculator{};
    QString display{};
};

std::istream& operator>>(std::istream& in, QString& val) {
    std::string s;
    in >> s;
    val = s.c_str();
    return in;
}
std::ostream& operator<<(std::ostream& out, const QString& val) {
    out << val.toLatin1().data();
    return out;
}

GIVEN("^I just turned on the calculator$") {
    cucumber::ScenarioScope<CalculatorCtx> ctx;
}

WHEN("^I press (\\d+)$") {
    REGEX_PARAM(unsigned int, n);
    cucumber::ScenarioScope<CalculatorCtx> ctx;
    ctx->calculator.number(n);
}

WHEN("^I press add") {
    cucumber::ScenarioScope<CalculatorCtx> ctx;
    ctx->calculator.add();
}

WHEN("^I press calculate") {
    cucumber::ScenarioScope<CalculatorCtx> ctx;
    ctx->calculator.calculate();
}

WHEN("^I press clear") {
    cucumber::ScenarioScope<CalculatorCtx> ctx;
    ctx->calculator.clear();
}

WHEN("^I press subtract") {
    cucumber::ScenarioScope<CalculatorCtx> ctx;
    ctx->calculator.subtract();
}

THEN("^the display should be empty$") {
    cucumber::ScenarioScope<CalculatorCtx> ctx;
    EXPECT_EQ(QString{}, ctx->display);
}

THEN("^the display should show (.*)$") {
    REGEX_PARAM(QString, expected);
    cucumber::ScenarioScope<CalculatorCtx> ctx;
    EXPECT_EQ(expected, ctx->display);
}


================================================
FILE: examples/CalcQt/features/step_definitions/GTestCalculatorQtSteps.cpp
================================================
#include <gtest/gtest.h>
#include "CalculatorQtSteps.cpp"


================================================
FILE: examples/CalcQt/features/step_definitions/QtTestCalculatorQtSteps.cpp
================================================
#include <QTest>
// Pretend to be GTest
#define EXPECT_EQ QCOMPARE
#define ASSERT_TRUE QVERIFY
#include "CalculatorQtSteps.cpp"


================================================
FILE: examples/CalcQt/features/step_definitions/cucumber.wire
================================================
host: localhost
port: 3902


================================================
FILE: examples/CalcQt/features/subtraction.feature
================================================
# language: en
Feature: Subtraction
  In order to avoid silly mistakes
  As a math idiot 
  I want to be told the difference of two numbers

  Scenario Outline: Subtract two numbers
    Given I just turned on the calculator
    When I press <button1>
    And I press subtract
    And I press <button2>
    And I press calculate
    Then the display should show <result>

  Examples:
    | button1 | button2 | result |
    | 2       | 3       | -1     |
    | 7       | 5       | 2      |
    | 9       | 1       | 8      |


================================================
FILE: examples/CalcQt/src/CalcQt.cpp
================================================
#include <QApplication>

#include "Calculator.hpp"
#include "CalculatorWidget.hpp"

int main(int argc, char* argv[]) {
    QApplication app(argc, argv);
    app.setApplicationName("Qt Calculator");
    Calculator calculator{};
    CalculatorWidget widget{&calculator};
    widget.show();
    return app.exec();
}


================================================
FILE: examples/CalcQt/src/Calculator.cpp
================================================
#include "Calculator.hpp"

#include <QRegularExpression>

QString Calculator::calculate(const QString& expression) const {
    int result = 0;
    char operation = '+';
    const QRegularExpression regexp("(\\d+)");
    QRegularExpressionMatchIterator matches = regexp.globalMatch(expression);

    while (matches.hasNext()) {
        const auto match = matches.next();
        const int value = match.captured(1).toInt();

        switch (operation) {
        case '+':
            result += value;
            break;
        case '-':
            result -= value;
            break;
        }

        const int pos = match.capturedEnd();
        if (pos < expression.length()) {
            operation = expression.at(pos).toLatin1();
        }
    }

    return QString::number(result);
}

void Calculator::number(quint8 number) {
    expression += QString::number(number);
    emit updateDisplay(expression);
}

void Calculator::add() {
    expression += "+";
    emit updateDisplay(expression);
}

void Calculator::subtract() {
    expression += "-";
    emit updateDisplay(expression);
}

void Calculator::calculate() {
    expression = calculate(expression);
    emit updateDisplay(expression);
}

void Calculator::clear() {
    expression.clear();
    emit updateDisplay(expression);
}


================================================
FILE: examples/CalcQt/src/Calculator.hpp
================================================
#pragma once

#include <QObject>

class Calculator : public QObject {
    Q_OBJECT

public:
    using QObject::QObject;

public slots:
    void number(quint8);
    void add();
    void subtract();
    void calculate();
    void clear();

signals:
    void updateDisplay(QString);

private:
    QString expression{};
    QString calculate(const QString& expression) const;
};


================================================
FILE: examples/CalcQt/src/CalculatorWidget.cpp
================================================
#include "CalculatorWidget.hpp"

#include "Calculator.hpp"
#include <QGridLayout>
#include <QKeyEvent>
#include <QLabel>
#include <QPushButton>

CalculatorWidget::CalculatorWidget(Calculator* calculator, QWidget* parent) :
    QWidget(parent) {
    QGridLayout* layout = new QGridLayout(this);
    layout->setSizeConstraint(QLayout::SetFixedSize);
    setLayout(layout);

    QSizePolicy policy = sizePolicy();

    displayLabel = new QLabel(this);
    layout->addWidget(displayLabel, 0, 0, 1, 3);
    displayLabel->setAutoFillBackground(true);
    displayLabel->setBackgroundRole(QPalette::Base);
    displayLabel->setAlignment(Qt::AlignRight);
    policy = displayLabel->sizePolicy();
    policy.setVerticalPolicy(QSizePolicy::Fixed);
    displayLabel->setSizePolicy(policy);
    QObject::connect(calculator, &Calculator::updateDisplay, displayLabel, &QLabel::setText);

    QPushButton* button = new QPushButton(QString::number(0), this);
    QObject::connect(button, &QPushButton::clicked, calculator, [calculator] {
        calculator->number(0);
    });
    layout->addWidget(button, 4, 1);
    digitButtons.push_back(button);
    for (unsigned int i = 1; i < 10; ++i) {
        QPushButton* button = new QPushButton(QString::number(i), this);
        QObject::connect(button, &QPushButton::clicked, calculator, [i, calculator] {
            calculator->number(i);
        });
        layout->addWidget(button, 1 + (9 - i) / 3, (i - 1) % 3);
        digitButtons.push_back(button);
    }

    clearButton = new QPushButton("C", this);
    layout->addWidget(clearButton, 1, 4);
    QObject::connect(clearButton, &QPushButton::clicked, calculator, [calculator] {
        calculator->clear();
    });

    additionButton = new QPushButton("+", this);
    layout->addWidget(additionButton, 2, 4);
    QObject::connect(additionButton, &QPushButton::clicked, calculator, [calculator] {
        calculator->add();
    });

    subtractionButton = new QPushButton("-", this);
    layout->addWidget(subtractionButton, 3, 4);
    QObject::connect(subtractionButton, &QPushButton::clicked, calculator, [calculator] {
        calculator->subtract();
    });

    calculateButton = new QPushButton("=", this);
    layout->addWidget(calculateButton, 4, 4);
    QObject::connect(calculateButton, &QPushButton::clicked, calculator, [calculator] {
        calculator->calculate();
    });
}

void CalculatorWidget::keyPressEvent(QKeyEvent* event) {
    keyclickedButton = nullptr;
    int key = event->key();
    if (key >= Qt::Key_0 && key <= Qt::Key_9) {
        keyclickedButton = digitButtons[key - Qt::Key_0];
    } else {
        switch (key) {
        case Qt::Key_Plus:
            keyclickedButton = additionButton;
            break;
        case Qt::Key_Minus:
            keyclickedButton = subtractionButton;
            break;
        case Qt::Key_Return:
        case Qt::Key_Enter:
        case Qt::Key_Equal:
            keyclickedButton = calculateButton;
            break;
        case Qt::Key_Escape:
            keyclickedButton = clearButton;
            break;
        }
    }
    if (keyclickedButton) {
        keyclickedButton->click();
        keyclickedButton->setDown(true);
    }
}

void CalculatorWidget::keyReleaseEvent(QKeyEvent* event) {
    Q_UNUSED(event)
    if (keyclickedButton) {
        keyclickedButton->setDown(false);
        keyclickedButton = nullptr;
    }
}

void CalculatorWidget::updateDisplay(QString text) {
    displayLabel->setText(text);
}


================================================
FILE: examples/CalcQt/src/CalculatorWidget.hpp
================================================
#pragma once

class QLabel;
class QPushButton;
class Calculator;

#include <QString>
#include <QWidget>

class CalculatorWidget : public QWidget {
    Q_OBJECT

public:
    CalculatorWidget(Calculator* calculator, QWidget* parent = 0);

protected:
    void keyPressEvent(QKeyEvent* event) override;
    void keyReleaseEvent(QKeyEvent* event) override;

private:
    QLabel* displayLabel;
    QVector<QPushButton*> digitButtons;
    QPushButton* additionButton;
    QPushButton* calculateButton;
    QPushButton* clearButton;
    QPushButton* subtractionButton;

    QPushButton* keyclickedButton{};

private Q_SLOTS:
    void updateDisplay(QString);
};


================================================
FILE: examples/FeatureShowcase/CMakeLists.txt
================================================
project(FeatureShowcase)

if(TARGET GTest::gtest)
    function(add_cucumber_executable)
        add_executable(FeatureShowcaseSteps ${ARGV})
        target_link_libraries(FeatureShowcaseSteps PRIVATE cucumber-cpp GTest::gtest)
        foreach(_arg ${ARGN})
            get_filename_component(OBJECT_PREFIX ${_arg} NAME_WE)
            set_source_files_properties(${_arg} PROPERTIES COMPILE_FLAGS "-DCUKE_OBJECT_PREFIX=${OBJECT_PREFIX}")
        endforeach(_arg)
    endfunction()

    add_cucumber_executable(
        features/step_definitions/TagSteps.cpp
        features/step_definitions/TableSteps.cpp
    )
endif()



================================================
FILE: examples/FeatureShowcase/README.txt
================================================
This sample shows a few advanced features: tags and table arguments.



================================================
FILE: examples/FeatureShowcase/features/step_definitions/TableSteps.cpp
================================================
#include <gtest/gtest.h>
#include <cucumber-cpp/autodetect.hpp>

#include <string>
#include <map>

using cucumber::ScenarioScope;

class ActiveActors {
public:
    typedef std::string actor_name_type;
    typedef unsigned short actor_year_type;

private:
    typedef std::map<actor_name_type, actor_year_type> actors_type;

    actors_type actors;

public:
    void addActor(const actor_name_type name, const actor_year_type year) {
        actors[name] = year;
    }

    void retireActor(const actor_name_type name) {
        actors.erase(actors.find(name));
    }

    actor_name_type getOldestActor() {
        actors_type::iterator it = actors.begin();
        actor_name_type name = it->first;
        actor_year_type year = it->second;
        while (++it != actors.end()) {
            actor_year_type currentYear = it->second;
            if (year > currentYear) {
                name = it->first;
            }
        }
        return name;
    }
};

GIVEN("^the following actors are still active") {
    TABLE_PARAM(actorsParam);
    ScenarioScope<ActiveActors> context;

    const table_hashes_type& actors = actorsParam.hashes();
    for (table_hashes_type::const_iterator ait = actors.begin(); ait != actors.end(); ++ait) {
        std::string name(ait->at("name"));
        std::string yearString(ait->at("born"));
        const ActiveActors::actor_year_type year
            = ::cucumber::internal::fromString<ActiveActors::actor_year_type>(yearString);
        context->addActor(name, year);
    }
}

WHEN("^(.+) retires") {
    REGEX_PARAM(std::string, retiringActor);
    ScenarioScope<ActiveActors> context;

    context->retireActor(retiringActor);
}

THEN("^the oldest actor should be (.+)$") {
    REGEX_PARAM(std::string, oldestActor);
    ScenarioScope<ActiveActors> context;

    ASSERT_EQ(oldestActor, context->getOldestActor());
}


================================================
FILE: examples/FeatureShowcase/features/step_definitions/TagSteps.cpp
================================================
#include <gtest/gtest.h>
#include <cucumber-cpp/autodetect.hpp>

#include <iostream>

using std::cout;
using std::endl;
using std::string;

BEFORE_ALL() {
    cout << "-------------------- (Before all scenarios)" << endl;
}

AFTER_ALL() {
    cout << "-------------------- (After all scenarios)" << endl;
}

BEFORE() {
    cout << "-------------------- (Before any scenario)" << endl;
}

BEFORE("@foo,@bar", "@baz") {
    cout << "Before scenario (\"@foo,@baz\",\"@bar\")" << endl;
}

AROUND_STEP("@baz") {
    cout << "Around step (\"@baz\") ...before" << endl;
    step->call();
    cout << "Around step (\"@baz\") ..after" << endl;
}

AFTER_STEP("@bar") {
    cout << "After step (\"@bar\")" << endl;
}

AFTER("@foo") {
    cout << "After scenario (\"@foo\")" << endl;
}

AFTER("@gherkin") {
    cout << "After scenario (\"@gherkin\")" << endl;
}

/*
 * CUKE_STEP_ is used just because the feature does not convey any
 * business value. It should NEVER be used in real step definitions!
 */

CUKE_STEP_("^I'm running a step from a scenario not tagged$") {
    cout << "Running step from scenario without tags" << endl;
    EXPECT_TRUE(true); // To fix a problem at link time
}

CUKE_STEP_("^I'm running a step from a scenario tagged with (.*)$") {
    REGEX_PARAM(string, tags);
    cout << "Running step from scenario with tags: " << tags << endl;
    EXPECT_TRUE(true); // To fix a problem at link time
}


================================================
FILE: examples/FeatureShowcase/features/step_definitions/cucumber.wire
================================================
host: localhost
port: 3902


================================================
FILE: examples/FeatureShowcase/features/table.feature
================================================
# language: en
Feature: Table
  In order to explain how to use tables
  I have to make this silly example

  Scenario: No tag
    Given the following actors are still active:
      | name           | born |
      | Al Pacino      | 1940 |
      | Robert De Niro | 1943 |
      | George Clooney | 1961 |
      | Morgan Freeman | 1937 |
    When Morgan Freeman retires
    Then the oldest actor should be Al Pacino


================================================
FILE: examples/FeatureShowcase/features/tag.feature
================================================
# language: en
Feature: Tags
  In order to explain how to use tags
  I have to make this silly example

  Scenario: No tag
    Given I'm running a step from a scenario not tagged
    When I'm running a step from a scenario not tagged
    Then I'm running a step from a scenario not tagged

  @foo
  Scenario: Foo
    Given I'm running a step from a scenario tagged with @foo
    When I'm running a step from a scenario tagged with @foo
    Then I'm running a step from a scenario tagged with @foo

  @bar
  Scenario: Bar
    Given I'm running a step from a scenario tagged with @bar
    When I'm running a step from a scenario tagged with @bar
    Then I'm running a step from a scenario tagged with @bar

  @baz
  Scenario: Baz
    Given I'm running a step from a scenario tagged with @baz
    When I'm running a step from a scenario tagged with @baz
    Then I'm running a step from a scenario tagged with @baz

  @bar @foo
  Scenario: Bar and Foo
    Given I'm running a step from a scenario tagged with @bar,@foo
    When I'm running a step from a scenario tagged with @bar,@foo
    Then I'm running a step from a scenario tagged with @bar,@foo

  @pickle
  Scenario: Pickle
    Given I'm running a step from a scenario tagged with @pickle
    When I'm running a step from a scenario tagged with @pickle
    Then I'm running a step from a scenario tagged with @pickle


================================================
FILE: include/cucumber-cpp/autodetect.hpp
================================================
#include "internal/defs.hpp"
#ifndef STEP_INHERITANCE
    #error No test framework found: please include a testing framework before autodetect.hpp or include generic.hpp
#endif


================================================
FILE: include/cucumber-cpp/defs.hpp
================================================
#ifdef __GNUC__
    #warning "Use of defs.hpp is deprecated, please use either autodetect.hpp or generic.hpp"
#else
    #pragma message(                                                                     \
        "Use of defs.hpp is deprecated, please use either autodetect.hpp or generic.hpp" \
    )
#endif
#include "internal/defs.hpp"
#ifndef STEP_INHERITANCE
    #include "internal/drivers/GenericDriver.hpp"
#endif


================================================
FILE: include/cucumber-cpp/generic.hpp
================================================
#include "internal/defs.hpp"
#ifdef STEP_INHERITANCE
    #error Test framework found: please include autodetect.hpp or remove the test framework includes
#else
    #include "internal/drivers/GenericDriver.hpp"
#endif


================================================
FILE: include/cucumber-cpp/internal/ContextManager.hpp
================================================
#ifndef CUKE_CONTEXTMANAGER_HPP_
#define CUKE_CONTEXTMANAGER_HPP_

#include <cucumber-cpp/internal/CukeExport.hpp>

#include <vector>

#include <memory>

namespace cucumber {

namespace internal {

typedef std::vector<std::shared_ptr<void>> contexts_type;

class CUCUMBER_CPP_EXPORT ContextManager {
public:
    void purgeContexts();
    template<class T>
    std::weak_ptr<T> addContext();

protected:
    static contexts_type contexts;
};

template<class T>
std::weak_ptr<T> ContextManager::addContext() {
    std::shared_ptr<T> shared(std::make_shared<T>());
    contexts.push_back(shared);
    return std::weak_ptr<T>(shared);
}

}

template<class T>
class ScenarioScope {
public:
    ScenarioScope();

    T& operator*();
    T* operator->();
    T* get();

private:
    internal::ContextManager contextManager;
    std::shared_ptr<T> context;
    static std::weak_ptr<T> contextReference;
};

template<class T>
std::weak_ptr<T> ScenarioScope<T>::contextReference;

template<class T>
ScenarioScope<T>::ScenarioScope() {
    if (contextReference.expired()) {
        contextReference = contextManager.addContext<T>();
    }
    context = contextReference.lock();
}

template<class T>
T& ScenarioScope<T>::operator*() {
    return *(context.get());
}

template<class T>
T* ScenarioScope<T>::operator->() {
    return (context.get());
}

template<class T>
T* ScenarioScope<T>::get() {
    return context.get();
}

}

#endif /* CUKE_CONTEXTMANAGER_HPP_ */


================================================
FILE: include/cucumber-cpp/internal/CukeCommands.hpp
================================================
#ifndef CUKE_CUKECOMMANDS_HPP_
#define CUKE_CUKECOMMANDS_HPP_

#include "ContextManager.hpp"
#include <cucumber-cpp/internal/CukeExport.hpp>
#include "Scenario.hpp"
#include "Table.hpp"
#include "step/StepManager.hpp"

#include <map>
#include <string>
#include <sstream>

#include <memory>

namespace cucumber {
namespace internal {

/**
 * Legacy class to be removed when feature #31 is complete, substituted by CukeEngineImpl.
 */
class CUCUMBER_CPP_EXPORT CukeCommands {
public:
    CukeCommands();
    virtual ~CukeCommands();

    void beginScenario(const TagExpression::tag_list& tags = TagExpression::tag_list());
    void endScenario();
    const std::string snippetText(const std::string stepKeyword, const std::string stepName) const;
    MatchResult stepMatches(const std::string description) const;
    InvokeResult invoke(step_id_type id, const InvokeArgs* pArgs);

protected:
    const std::string escapeRegex(const std::string regex) const;
    const std::string escapeCString(const std::string str) const;

private:
    ContextManager contextManager;
    bool hasStarted;

private:
    static std::shared_ptr<Scenario> currentScenario;
};

}
}

#endif /* CUKE_CUKECOMMANDS_HPP_ */


================================================
FILE: include/cucumber-cpp/internal/CukeEngine.hpp
================================================
#ifndef CUKE_CUKEENGINE_HPP_
#define CUKE_CUKEENGINE_HPP_

#include <cstddef>
#include <string>
#include <vector>

#include <cucumber-cpp/internal/CukeExport.hpp>

namespace cucumber {
namespace internal {

class CUCUMBER_CPP_EXPORT StepMatchArg {
public:
    std::string value;
    std::ptrdiff_t position;
};

class CUCUMBER_CPP_EXPORT StepMatch {
public:
    std::string id;
    std::vector<StepMatchArg> args;
    std::string source;
    std::string regexp;
};

class CUCUMBER_CPP_EXPORT InvokeException {
private:
    const std::string message;

public:
    InvokeException(const std::string& message);
    InvokeException(const InvokeException& rhs);

    const std::string getMessage() const;

    virtual ~InvokeException() = default;
};

class CUCUMBER_CPP_EXPORT InvokeFailureException : public InvokeException {
private:
    const std::string exceptionType;

public:
    InvokeFailureException(const std::string& message, const std::string& exceptionType);
    InvokeFailureException(const InvokeFailureException& rhs);

    const std::string getExceptionType() const;
};

class CUCUMBER_CPP_EXPORT PendingStepException : public InvokeException {
public:
    PendingStepException(const std::string& message);
    PendingStepException(const PendingStepException& rhs);
};

/**
 * The entry point to Cucumber.
 *
 * It uses standard types (as much as possible) to be easier to call.
 * Returns standard types if possible.
 */
class CukeEngine {
private:
    typedef std::vector<std::string> string_array;
    typedef std::vector<std::vector<std::string>> string_2d_array;

public:
    typedef string_array tags_type;
    typedef string_array invoke_args_type;
    typedef string_2d_array invoke_table_type;

    /**
     * Finds steps whose regexp match some text.
     */
    virtual std::vector<StepMatch> stepMatches(const std::string& name) const = 0;

    /**
     * Starts a scenario.
     */
    virtual void beginScenario(const tags_type& tags) = 0;

    /**
     * Invokes a step passing arguments to it.
     *
     * @throws InvokeException if the test fails or it is pending
     */
    virtual void invokeStep(
        const std::string& id, const invoke_args_type& args, const invoke_table_type& tableArg
    ) = 0;

    /**
     * Ends a scenario.
     */
    virtual void endScenario(const tags_type& tags) = 0;

    /**
     * Returns the step definition for a pending step.
     */
    virtual std::string snippetText(
        const std::string& keyword, const std::string& name, const std::string& multilineArgClass
    ) const
        = 0;

    CUCUMBER_CPP_EXPORT CukeEngine();
    CUCUMBER_CPP_EXPORT virtual ~CukeEngine() = default;
};

}
}

#endif /* CUKE_CUKEENGINE_HPP_ */


================================================
FILE: include/cucumber-cpp/internal/CukeEngineImpl.hpp
================================================
#ifndef CUKE_CUKEENGINE_IMPL_HPP_
#define CUKE_CUKEENGINE_IMPL_HPP_

#include "CukeEngine.hpp"
#include <cucumber-cpp/internal/CukeExport.hpp>
#include "CukeCommands.hpp"

namespace cucumber {
namespace internal {

/**
 * Default Engine Implementation
 *
 * Currently it is a wrapper around CukeCommands. It will have its own
 * implementation when feature #31 is complete.
 */
class CUCUMBER_CPP_EXPORT CukeEngineImpl : public CukeEngine {
private:
    CukeCommands cukeCommands;

public:
    std::vector<StepMatch> stepMatches(const std::string& name) const override;
    void beginScenario(const tags_type& tags) override;
    void invokeStep(
        const std::string& id, const invoke_args_type& args, const invoke_table_type& tableArg
    ) override;
    void endScenario(const tags_type& tags) override;
    std::string snippetText(
        const std::string& keyword, const std::string& name, const std::string& multilineArgClass
    ) const override;
};

}
}

#endif /* CUKE_CUKEENGINE_IMPL_HPP_ */


================================================
FILE: include/cucumber-cpp/internal/Macros.hpp
================================================
#ifndef CUKE_MACROS_HPP_
#define CUKE_MACROS_HPP_

#include "RegistrationMacros.hpp"
#include "step/StepMacros.hpp"
#include "hook/HookMacros.hpp"

#endif /* CUKE_MACROS_HPP_ */


================================================
FILE: include/cucumber-cpp/internal/RegistrationMacros.hpp
================================================
#ifndef CUKE_REGISTRATIONMACROS_HPP_
#define CUKE_REGISTRATIONMACROS_HPP_

// ************************************************************************** //
// **************            OBJECT NAMING MACROS              ************** //
// ************************************************************************** //

// from https://www.boost.org/doc/libs/1_84_0/boost/config/helper_macros.hpp
#define CUKE_JOIN(X, Y) CUKE_DO_JOIN(X, Y)
#define CUKE_DO_JOIN(X, Y) CUKE_DO_JOIN2(X, Y)
#define CUKE_DO_JOIN2(X, Y) X##Y

#ifndef CUKE_OBJECT_PREFIX
    #define CUKE_OBJECT_PREFIX CukeObject
#endif

#ifdef __COUNTER__
    #define CUKE_GEN_OBJECT_NAME_ CUKE_JOIN(CUKE_OBJECT_PREFIX, __COUNTER__)
#else
    // Use a counter to be incremented every time cucumber-cpp is included
    // in case this does not suffice (possible with multiple files only)
    #define CUKE_GEN_OBJECT_NAME_ CUKE_JOIN(CUKE_OBJECT_PREFIX, __LINE__)
#endif

// ************************************************************************** //
// **************                 CUKE OBJECTS                 ************** //
// ************************************************************************** //

#define CUKE_OBJECT_(class_name, parent_class, registration_fn, args)                     \
    class class_name : public parent_class {                                              \
    public:                                                                               \
        void body() override { return invokeWithArgs(*this, &class_name::bodyWithArgs); } \
        void bodyWithArgs args;                                                           \
                                                                                          \
    private:                                                                              \
        static const int cukeRegId;                                                       \
    };                                                                                    \
    const int class_name ::cukeRegId = registration_fn;                                   \
    void class_name ::bodyWithArgs args /**/

#endif /* CUKE_REGISTRATIONMACROS_HPP_ */


================================================
FILE: include/cucumber-cpp/internal/Scenario.hpp
================================================
#ifndef CUKE_SCENARIO_HPP_
#define CUKE_SCENARIO_HPP_

#include "hook/Tag.hpp"

namespace cucumber {
namespace internal {

class Scenario {
public:
    Scenario(const TagExpression::tag_list& tags = TagExpression::tag_list());

    const TagExpression::tag_list& getTags();

private:
    const TagExpression::tag_list tags;
};

}
}

#endif /* CUKE_SCENARIO_HPP_ */


================================================
FILE: include/cucumber-cpp/internal/Table.hpp
================================================
#ifndef CUKE_TABLE_HPP_
#define CUKE_TABLE_HPP_

#include <cucumber-cpp/internal/CukeExport.hpp>

#include <vector>
#include <map>
#include <string>
#include <stdexcept>

namespace cucumber {
namespace internal {

class CUCUMBER_CPP_EXPORT Table {
private:
    typedef std::vector<std::string> basic_type;

public:
    typedef std::map<std::string, std::string> hash_row_type;
    typedef basic_type columns_type;
    typedef basic_type row_type;
    typedef std::vector<hash_row_type> hashes_type;

    /**
     * @brief addColumn
     * @param column
     *
     * @throws std::runtime_error
     */
    void addColumn(const std::string column);

    /**
     * @brief addRow
     * @param row
     *
     * @throws std::range_error
     * @throws std::runtime_error
     */
    void addRow(const row_type& row);
    const hashes_type& hashes() const;

private:
    hash_row_type buildHashRow(const row_type& row);

    columns_type columns;
    hashes_type rows;
};

}
}

#endif /* CUKE_TABLE_HPP_ */


================================================
FILE: include/cucumber-cpp/internal/connectors/wire/ProtocolHandler.hpp
================================================
#ifndef CUKE_PROTOCOLHANDLER_HPP_
#define CUKE_PROTOCOLHANDLER_HPP_

#include <string>

namespace cucumber {
namespace internal {

/**
 * Protocol that reads one command for each input line.
 */
class ProtocolHandler {
public:
    virtual std::string handle(const std::string& request) const = 0;
    virtual ~ProtocolHandler() = default;
};

}
}

#endif /* CUKE_PROTOCOLHANDLER_HPP_ */


================================================
FILE: include/cucumber-cpp/internal/connectors/wire/WireProtocol.hpp
================================================
#ifndef CUKE_WIREPROTOCOL_HPP_
#define CUKE_WIREPROTOCOL_HPP_

#include <cucumber-cpp/internal/CukeExport.hpp>
#include "ProtocolHandler.hpp"
#include "../../CukeEngine.hpp"

#include <memory>

namespace cucumber {
namespace internal {

/*
 * Response messages
 */

class WireResponseVisitor;

class CUCUMBER_CPP_EXPORT WireResponse {
public:
    WireResponse(){};

    virtual void accept(WireResponseVisitor& visitor) const = 0;

    virtual ~WireResponse() = default;
};

class CUCUMBER_CPP_EXPORT SuccessResponse : public WireResponse {
public:
    void accept(WireResponseVisitor& visitor) const override;
};

class CUCUMBER_CPP_EXPORT FailureResponse : public WireResponse {
private:
    const std::string message, exceptionType;

public:
    FailureResponse(const std::string& message = "", const std::string& exceptionType = "");

    const std::string getMessage() const;
    const std::string getExceptionType() const;

    void accept(WireResponseVisitor& visitor) const override;
};

class CUCUMBER_CPP_EXPORT PendingResponse : public WireResponse {
private:
    const std::string message;

public:
    PendingResponse(const std::string& message);

    const std::string getMessage() const;

    void accept(WireResponseVisitor& visitor) const override;
};

class CUCUMBER_CPP_EXPORT StepMatchesResponse : public WireResponse {
private:
    const std::vector<StepMatch> matchingSteps;

public:
    StepMatchesResponse(const std::vector<StepMatch>& matchingSteps);
    const std::vector<StepMatch>& getMatchingSteps() const;

    void accept(WireResponseVisitor& visitor) const override;
};

class CUCUMBER_CPP_EXPORT SnippetTextResponse : public WireResponse {
private:
    const std::string stepSnippet;

public:
    SnippetTextResponse(const std::string& stepSnippet);

    const std::string getStepSnippet() const;

    void accept(WireResponseVisitor& visitor) const override;
};

class CUCUMBER_CPP_EXPORT WireResponseVisitor {
public:
    virtual void visit(const SuccessResponse& response) = 0;
    virtual void visit(const FailureResponse& response) = 0;
    virtual void visit(const PendingResponse& response) = 0;
    virtual void visit(const StepMatchesResponse& response) = 0;
    virtual void visit(const SnippetTextResponse& response) = 0;

    virtual ~WireResponseVisitor() = default;
};

/**
 * Wire protocol request command.
 */
class CUCUMBER_CPP_EXPORT WireCommand {
public:
    /**
     * Runs the command on the provided engine
     *
     * @param The engine
     *
     * @return The command response (ownership passed to the caller)
     */
    virtual std::shared_ptr<WireResponse> run(CukeEngine& engine) const = 0;

    virtual ~WireCommand() = default;
};

class CUCUMBER_CPP_EXPORT WireMessageCodecException : public std::exception {
private:
    const char* description;

public:
    WireMessageCodecException(const char* description) :
        description(description) {
    }

    const char* what() const throw() override {
        return description;
    }
};

/**
 * Transforms wire messages into commands and responses to messages.
 */
class CUCUMBER_CPP_EXPORT WireMessageCodec {
public:
    /**
     * Decodes a wire message into a command.
     *
     * @param One single message to decode
     *
     * @return The decoded command (ownership passed to the caller)
     *
     * @throws WireMessageCodecException
     */
    virtual std::shared_ptr<WireCommand> decode(const std::string& request) const = 0;

    /**
     * Encodes a response to wire format.
     *
     * @param Response to encode
     *
     * @return The encoded string
     */
    virtual const std::string encode(const WireResponse& response) const = 0;

    virtual ~WireMessageCodec() = default;
};

/**
 * WireMessageCodec implementation with Json.
 */
class CUCUMBER_CPP_EXPORT JsonWireMessageCodec : public WireMessageCodec {
public:
    JsonWireMessageCodec() = default;
    std::shared_ptr<WireCommand> decode(const std::string& request) const override;
    const std::string encode(const WireResponse& response) const override;
};

/**
 * Wire protocol handler, delegating JSON encoding and decoding to a
 * codec object and running commands on a provided engine instance.
 */
class CUCUMBER_CPP_EXPORT WireProtocolHandler : public ProtocolHandler {
private:
    const WireMessageCodec& codec;
    CukeEngine& engine;

public:
    WireProtocolHandler(const WireMessageCodec& codec, CukeEngine& engine);

    std::string handle(const std::string& request) const override;
};

}
}

#endif /* CUKE_WIREPROTOCOL_HPP_ */


================================================
FILE: include/cucumber-cpp/internal/connectors/wire/WireProtocolCommands.hpp
================================================
#ifndef CUKE_WIREPROTOCOL_COMMANDS_HPP_
#define CUKE_WIREPROTOCOL_COMMANDS_HPP_

#include "WireProtocol.hpp"
#include <memory>

namespace cucumber {
namespace internal {

class ScenarioCommand : public WireCommand {
protected:
    const CukeEngine::tags_type tags;

    ScenarioCommand(const CukeEngine::tags_type& tags);
};

class BeginScenarioCommand : public ScenarioCommand {
public:
    BeginScenarioCommand(const CukeEngine::tags_type& tags);

    std::shared_ptr<WireResponse> run(CukeEngine& engine) const override;
};

class EndScenarioCommand : public ScenarioCommand {
public:
    EndScenarioCommand(const CukeEngine::tags_type& tags);

    std::shared_ptr<WireResponse> run(CukeEngine& engine) const override;
};

class StepMatchesCommand : public WireCommand {
private:
    const std::string stepName;

public:
    StepMatchesCommand(const std::string& stepName);

    std::shared_ptr<WireResponse> run(CukeEngine& engine) const override;
};

class InvokeCommand : public WireCommand {
private:
    const std::string stepId;
    const CukeEngine::invoke_args_type args;
    const CukeEngine::invoke_table_type tableArg;

public:
    InvokeCommand(
        const std::string& stepId,
        const CukeEngine::invoke_args_type& args,
        const CukeEngine::invoke_table_type& tableArg
    );

    std::shared_ptr<WireResponse> run(CukeEngine& engine) const override;
};

class SnippetTextCommand : public WireCommand {
private:
    std::string keyword, name, multilineArgClass;

public:
    SnippetTextCommand(
        const std::string& keyword, const std::string& name, const std::string& multilineArgClass
    );

    std::shared_ptr<WireResponse> run(CukeEngine& engine) const override;
};

class FailingCommand : public WireCommand {
public:
    std::shared_ptr<WireResponse> run(CukeEngine& engine) const override;
};

}
}

#endif /* CUKE_WIREPROTOCOL_COMMANDS_HPP_ */


================================================
FILE: include/cucumber-cpp/internal/connectors/wire/WireServer.hpp
================================================
#ifndef CUKE_WIRESERVER_HPP_
#define CUKE_WIRESERVER_HPP_

#include <cucumber-cpp/internal/CukeExport.hpp>
#include "ProtocolHandler.hpp"

#include <string>

#include <asio.hpp>

namespace cucumber {
namespace internal {

/**
 * Socket server that calls a protocol handler line by line
 */
class CUCUMBER_CPP_EXPORT SocketServer {
public:
    /**
     * Constructor for DI
     */
    SocketServer(const ProtocolHandler* protocolHandler);
    virtual ~SocketServer() = default;

    /**
     * Accept one connection
     */
    virtual void acceptOnce() = 0;

protected:
    const ProtocolHandler* protocolHandler;
    asio::io_context ios;

    template<typename Protocol>
    void doListen(
        asio::basic_socket_acceptor<Protocol>& acceptor, const typename Protocol::endpoint& endpoint
    );
    template<typename Protocol>
    void doAcceptOnce(asio::basic_socket_acceptor<Protocol>& acceptor);
    void processStream(std::iostream& stream);
};

/**
 * Socket server that calls a protocol handler line by line
 */
class CUCUMBER_CPP_EXPORT TCPSocketServer : public SocketServer {
public:
    /**
     * Type definition for TCP port
     */
    typedef unsigned short port_type;

    /**
     * Constructor for DI
     */
    TCPSocketServer(const ProtocolHandler* protocolHandler);

    /**
     * Bind and listen to a TCP port
     */
    void listen(const port_type port);

    /**
     * Bind and listen to a TCP port on the given endpoint
     */
    void listen(const asio::ip::tcp::endpoint endpoint);

    /**
     * Endpoint (IP address and port number) that this server is currently
     * listening on.
     *
     * @throw std::system_error when not listening on any socket or
     *        the endpoint cannot be determined.
     */
    asio::ip::tcp::endpoint listenEndpoint() const;

    void acceptOnce() override;

private:
    asio::ip::tcp::acceptor acceptor;
};

#if defined(ASIO_HAS_LOCAL_SOCKETS)
/**
 * Socket server that calls a protocol handler line by line
 */
class CUCUMBER_CPP_EXPORT UnixSocketServer : public SocketServer {
public:
    /**
     * Constructor for DI
     */
    UnixSocketServer(const ProtocolHandler* protocolHandler);

    /**
     * Bind and listen on a local stream socket
     */
    void listen(const std::string& unixPath);

    /**
     * Port number that this server is currently listening on.
     *
     * @throw std::system_error when not listening on any socket or
     *        the endpoint cannot be determined.
     */
    asio::local::stream_protocol::endpoint listenEndpoint() const;

    void acceptOnce() override;

    ~UnixSocketServer() override;

private:
    asio::local::stream_protocol::acceptor acceptor;
};
#endif

}
}

#endif /* CUKE_WIRESERVER_HPP_ */


================================================
FILE: include/cucumber-cpp/internal/defs.hpp
================================================
#include "step/StepManager.hpp"
#include "hook/HookRegistrar.hpp"
#include "ContextManager.hpp"
#include "Macros.hpp"
#include "drivers/DriverSelector.hpp"


================================================
FILE: include/cucumber-cpp/internal/drivers/BoostDriver.hpp
================================================
#ifndef CUKE_BOOSTDRIVER_HPP_
#define CUKE_BOOSTDRIVER_HPP_

#include "../step/StepManager.hpp"
#include <cucumber-cpp/internal/CukeExport.hpp>

namespace cucumber {
namespace internal {

class CukeBoostLogInterceptor;

class CUCUMBER_CPP_EXPORT BoostStep : public BasicStep {
protected:
    const InvokeResult invokeStepBody() override;

private:
    static void initBoostTest();
    void runWithMasterSuite();
};

#define STEP_INHERITANCE(step_name) ::cucumber::internal::BoostStep

}
}

#endif /* CUKE_BOOSTDRIVER_HPP_ */


================================================
FILE: include/cucumber-cpp/internal/drivers/DriverSelector.hpp
================================================
#if defined(GTEST_INCLUDE_GTEST_GTEST_H_) || defined(GOOGLETEST_INCLUDE_GTEST_GTEST_H_)
    #include "GTestDriver.hpp"
#elif defined(BOOST_TEST_CASE)
    #include "BoostDriver.hpp"
#elif defined(QTEST_H)
    #include "QtTestDriver.hpp"
#endif


================================================
FILE: include/cucumber-cpp/internal/drivers/GTestDriver.hpp
================================================
#ifndef CUKE_GTESTDRIVER_HPP_
#define CUKE_GTESTDRIVER_HPP_

#include <cucumber-cpp/internal/CukeExport.hpp>
#include "../step/StepManager.hpp"

#include <iostream>

namespace cucumber {
namespace internal {

class CUCUMBER_CPP_EXPORT GTestStep : public BasicStep {
protected:
    const InvokeResult invokeStepBody() override;

private:
    void initGTest();
    void initFlags();

protected:
    static bool initialized;
};

#define STEP_INHERITANCE(step_name) ::cucumber::internal::GTestStep

}
}

#endif /* CUKE_GTESTDRIVER_HPP_ */


================================================
FILE: include/cucumber-cpp/internal/drivers/GenericDriver.hpp
================================================
#ifndef CUKE_GENERICDRIVER_HPP_
#define CUKE_GENERICDRIVER_HPP_

#include "../step/StepManager.hpp"
#include <cucumber-cpp/internal/CukeExport.hpp>

namespace cucumber {
namespace internal {

class CUCUMBER_CPP_EXPORT GenericStep : public BasicStep {
protected:
    const InvokeResult invokeStepBody() override;
};

#define STEP_INHERITANCE(step_name) virtual ::cucumber::internal::GenericStep

}
}

#endif /* CUKE_GENERICDRIVER_HPP_ */


================================================
FILE: include/cucumber-cpp/internal/drivers/QtTestDriver.hpp
================================================
#ifndef CUKE_QTTESTDRIVER_HPP_
#define CUKE_QTTESTDRIVER_HPP_

#include "../step/StepManager.hpp"
#include <cucumber-cpp/internal/CukeExport.hpp>
#include <QObject>

namespace cucumber {
namespace internal {

class CUCUMBER_CPP_EXPORT QtTestStep : public BasicStep {
    friend class QtTestObject;

public:
    QtTestStep() :
        BasicStep() {
    }

protected:
    const InvokeResult invokeStepBody() override;
};

#define STEP_INHERITANCE(step_name) ::cucumber::internal::QtTestStep

class QtTestObject : public QObject {
    Q_OBJECT
public:
    QtTestObject(QtTestStep* qtTestStep) :
        step(qtTestStep) {
    }

protected:
    QtTestStep* step;

private slots:
    void test() const {
        step->body();
    }
};

}
}

#endif /* CUKE_QTTESTDRIVER_HPP_ */


================================================
FILE: include/cucumber-cpp/internal/hook/HookMacros.hpp
================================================
#ifndef CUKE_HOOKMACROS_HPP_
#define CUKE_HOOKMACROS_HPP_

#include "../RegistrationMacros.hpp"

// ************************************************************************** //
// **************                 BEFORE HOOK                  ************** //
// ************************************************************************** //

#define BEFORE(...)                                           \
    BEFORE_WITH_NAME_(CUKE_GEN_OBJECT_NAME_, "" #__VA_ARGS__) \
    /**/

#define BEFORE_WITH_NAME_(step_name, tag_expression)          \
    CUKE_OBJECT_(                                             \
        step_name,                                            \
        ::cucumber::internal::BeforeHook,                     \
        BEFORE_HOOK_REGISTRATION_(step_name, tag_expression), \
        ()                                                    \
    )                                                         \
    /**/

#define BEFORE_HOOK_REGISTRATION_(step_name, tag_expression) \
    ::cucumber::internal::registerBeforeHook<step_name>(tag_expression) /**/

// ************************************************************************** //
// **************              AROUND_STEP HOOK                ************** //
// ************************************************************************** //

#define AROUND_STEP(...)                                           \
    AROUND_STEP_WITH_NAME_(CUKE_GEN_OBJECT_NAME_, "" #__VA_ARGS__) \
    /**/

#define AROUND_STEP_WITH_NAME_(step_name, tag_expression)          \
    CUKE_OBJECT_(                                                  \
        step_name,                                                 \
        ::cucumber::internal::AroundStepHook,                      \
        AROUND_STEP_HOOK_REGISTRATION_(step_name, tag_expression), \
        ()                                                         \
    )                                                              \
    /**/

#define AROUND_STEP_HOOK_REGISTRATION_(step_name, tag_expression) \
    ::cucumber::internal::registerAroundStepHook<step_name>(tag_expression) /**/

// ************************************************************************** //
// **************               AFTER_STEP HOOK                ************** //
// ************************************************************************** //

#define AFTER_STEP(...)                                           \
    AFTER_STEP_WITH_NAME_(CUKE_GEN_OBJECT_NAME_, "" #__VA_ARGS__) \
    /**/

#define AFTER_STEP_WITH_NAME_(step_name, tag_expression)          \
    CUKE_OBJECT_(                                                 \
        step_name,                                                \
        ::cucumber::internal::AfterStepHook,                      \
        AFTER_STEP_HOOK_REGISTRATION_(step_name, tag_expression), \
        ()                                                        \
    )                                                             \
    /**/

#define AFTER_STEP_HOOK_REGISTRATION_(step_name, tag_expression) \
    ::cucumber::internal::registerAfterStepHook<step_name>(tag_expression) /**/

// ************************************************************************** //
// **************                  AFTER HOOK                  ************** //
// ************************************************************************** //

#define AFTER(...)                                           \
    AFTER_WITH_NAME_(CUKE_GEN_OBJECT_NAME_, "" #__VA_ARGS__) \
    /**/

#define AFTER_WITH_NAME_(step_name, tag_expression)          \
    CUKE_OBJECT_(                                            \
        step_name,                                           \
        ::cucumber::internal::AfterHook,                     \
        AFTER_HOOK_REGISTRATION_(step_name, tag_expression), \
        ()                                                   \
    )                                                        \
    /**/

#define AFTER_HOOK_REGISTRATION_(step_name, tag_expression) \
    ::cucumber::internal::registerAfterHook<step_name>(tag_expression) /**/

// ************************************************************************** //
// **************                BEFORE_ALL HOOK               ************** //
// ************************************************************************** //

#define BEFORE_ALL()                             \
    BEFORE_ALL_WITH_NAME_(CUKE_GEN_OBJECT_NAME_) \
    /**/

#define BEFORE_ALL_WITH_NAME_(step_name)          \
    CUKE_OBJECT_(                                 \
        step_name,                                \
        ::cucumber::internal::BeforeAllHook,      \
        BEFORE_ALL_HOOK_REGISTRATION_(step_name), \
        ()                                        \
    )                                             \
    /**/

#define BEFORE_ALL_HOOK_REGISTRATION_(step_name) \
    ::cucumber::internal::registerBeforeAllHook<step_name>() /**/

// ************************************************************************** //
// **************                 AFTER_ALL HOOK               ************** //
// ************************************************************************** //

#define AFTER_ALL()                             \
    AFTER_ALL_WITH_NAME_(CUKE_GEN_OBJECT_NAME_) \
    /**/

#define AFTER_ALL_WITH_NAME_(step_name)                                                            \
    CUKE_OBJECT_(                                                                                  \
        step_name, ::cucumber::internal::AfterAllHook, AFTER_ALL_HOOK_REGISTRATION_(step_name), () \
    )                                                                                              \
    /**/

#define AFTER_ALL_HOOK_REGISTRATION_(step_name) \
    ::cucumber::internal::registerAfterAllHook<step_name>() /**/

#endif /* CUKE_HOOKMACROS_HPP_ */


================================================
FILE: include/cucumber-cpp/internal/hook/HookRegistrar.hpp
================================================
#ifndef CUKE_HOOKREGISTRAR_HPP_
#define CUKE_HOOKREGISTRAR_HPP_

#include <cucumber-cpp/internal/CukeExport.hpp>
#include "Tag.hpp"
#include "../Scenario.hpp"
#include "../step/StepManager.hpp"

#include <memory>
#include <list>

namespace cucumber {
namespace internal {

class CUCUMBER_CPP_EXPORT CallableStep {
public:
    virtual void call() = 0;
};

class CUCUMBER_CPP_EXPORT Hook {
public:
    virtual ~Hook() = default;

    void setTags(const std::string& csvTagNotation);
    virtual void invokeHook(Scenario* scenario, CallableStep* step);
    virtual void skipHook();
    virtual void body() = 0;

protected:
    bool tagsMatch(Scenario* scenario);

    template<typename Derived, typename R>
    static R invokeWithArgs(Derived& that, R (Derived::*f)()) {
        return (that.*f)();
    }

private:
    AndTagExpression tagExpression;
};

class CUCUMBER_CPP_EXPORT BeforeHook : public Hook {};

class CUCUMBER_CPP_EXPORT AroundStepHook : public Hook {
public:
    void invokeHook(Scenario* scenario, CallableStep* step) override;
    void skipHook() override;

protected:
    CallableStep* step;
};

class CUCUMBER_CPP_EXPORT AfterStepHook : public Hook {};

class CUCUMBER_CPP_EXPORT AfterHook : public Hook {};

class CUCUMBER_CPP_EXPORT UnconditionalHook : public Hook {
public:
    void invokeHook(Scenario* scenario, CallableStep* step) override;
};

class CUCUMBER_CPP_EXPORT BeforeAllHook : public UnconditionalHook {};

class CUCUMBER_CPP_EXPORT AfterAllHook : public UnconditionalHook {};

class CUCUMBER_CPP_EXPORT HookRegistrar {
public:
    typedef std::list<std::shared_ptr<Hook>> hook_list_type;
    typedef std::list<std::shared_ptr<AroundStepHook>> aroundhook_list_type;

    static void addBeforeHook(std::shared_ptr<BeforeHook> afterHook);
    static void execBeforeHooks(Scenario* scenario);

    static void addAroundStepHook(std::shared_ptr<AroundStepHook> aroundStepHook);
    static InvokeResult execStepChain(
        Scenario* scenario, const StepInfo* stepInfo, const InvokeArgs* pArgs
    );

    static void addAfterStepHook(std::shared_ptr<AfterStepHook> afterStepHook);
    static void execAfterStepHooks(Scenario* scenario);

    static void addAfterHook(std::shared_ptr<AfterHook> afterHook);
    static void execAfterHooks(Scenario* scenario);

    static void addBeforeAllHook(std::shared_ptr<BeforeAllHook> beforeAllHook);
    static void execBeforeAllHooks();

    static void addAfterAllHook(std::shared_ptr<AfterAllHook> afterAllHook);
    static void execAfterAllHooks();

private:
    static void execHooks(HookRegistrar::hook_list_type& hookList, Scenario* scenario);

protected:
    static hook_list_type& beforeAllHooks();
    static hook_list_type& beforeHooks();
    static aroundhook_list_type& aroundStepHooks();
    static hook_list_type& afterStepHooks();
    static hook_list_type& afterHooks();
    static hook_list_type& afterAllHooks();

private:
    // We're a singleton so don't allow instances
    HookRegistrar() = delete;
};

class CUCUMBER_CPP_EXPORT StepCallChain {
public:
    StepCallChain(
        Scenario* scenario,
        const StepInfo* stepInfo,
        const InvokeArgs* pStepArgs,
        HookRegistrar::aroundhook_list_type& aroundHooks
    );
    InvokeResult exec();
    void execNext();

private:
    void execStep();

    Scenario* scenario;
    const StepInfo* stepInfo;
    const InvokeArgs* pStepArgs;

    HookRegistrar::aroundhook_list_type::iterator nextHook;
    HookRegistrar::aroundhook_list_type::iterator hookEnd;
    InvokeResult result;
};

class CUCUMBER_CPP_EXPORT CallableStepChain : public CallableStep {
public:
    CallableStepChain(StepCallChain* scc);
    void call() override;

private:
    StepCallChain* scc;
};

template<class T>
static int registerBeforeHook(const std::string& csvTagNotation) {
    std::shared_ptr<T> hook(std::make_shared<T>());
    hook->setTags(csvTagNotation);
    HookRegistrar::addBeforeHook(hook);
    return 0; // We are not interested in the ID at this time
}

template<class T>
static int registerAroundStepHook(const std::string& csvTagNotation) {
    std::shared_ptr<T> hook(std::make_shared<T>());
    hook->setTags(csvTagNotation);
    HookRegistrar::addAroundStepHook(hook);
    return 0;
}

template<class T>
static int registerAfterStepHook(const std::string& csvTagNotation) {
    std::shared_ptr<T> hook(std::make_shared<T>());
    hook->setTags(csvTagNotation);
    HookRegistrar::addAfterStepHook(hook);
    return 0;
}

template<class T>
static int registerAfterHook(const std::string& csvTagNotation) {
    std::shared_ptr<T> hook(std::make_shared<T>());
    hook->setTags(csvTagNotation);
    HookRegistrar::addAfterHook(hook);
    return 0;
}

template<class T>
static int registerBeforeAllHook() {
    HookRegistrar::addBeforeAllHook(std::make_shared<T>());
    return 0;
}

template<class T>
static int registerAfterAllHook() {
    HookRegistrar::addAfterAllHook(std::make_shared<T>());
    return 0;
}

}
}

#endif /* CUKE_HOOKREGISTRAR_HPP_ */


================================================
FILE: include/cucumber-cpp/internal/hook/Tag.hpp
================================================
#ifndef CUKE_TAG_HPP_
#define CUKE_TAG_HPP_

#include <string>
#include <vector>

#include <cucumber-cpp/internal/CukeExport.hpp>
#include "../utils/Regex.hpp"

namespace cucumber {
namespace internal {

class CUCUMBER_CPP_EXPORT TagExpression {
public:
    typedef std::vector<std::string> tag_list;

    virtual ~TagExpression() = default;
    virtual bool matches(const tag_list& tags) const = 0;
};

class CUCUMBER_CPP_EXPORT OrTagExpression : public TagExpression {
public:
    OrTagExpression(const std::string& csvTagNotation);
    bool matches(const tag_list& tags) const override;

private:
    bool orTagMatchesTagList(const std::string& currentOrTag, const tag_list& tags) const;

    tag_list orTags;

    static Regex& csvTagNotationRegex();
};

class CUCUMBER_CPP_EXPORT AndTagExpression : public TagExpression {
public:
    AndTagExpression() = default;
    AndTagExpression(const std::string& csvTagNotation);
    bool matches(const tag_list& tags) const override;

private:
    typedef std::vector<OrTagExpression> or_expressions_type;
    or_expressions_type orExpressions;

    static Regex& csvTagNotationRegex();
};

}
}

#endif /* CUKE_TAG_HPP_ */


================================================
FILE: include/cucumber-cpp/internal/step/StepMacros.hpp
================================================
#ifndef CUKE_STEPMACROS_HPP_
#define CUKE_STEPMACROS_HPP_

#include "../RegistrationMacros.hpp"

// ************************************************************************** //
// **************                     STEP                     ************** //
// ************************************************************************** //

#define CUKE_STEP_GET_MATCHER_(step_matcher, ...) step_matcher
#define CUKE_STEP_GET_ARGS_(step_matcher, args, ...) args

#define CUKE_STEP_(...)                          \
    CUKE_STEP_WITH_NAME_(                        \
        CUKE_GEN_OBJECT_NAME_,                   \
        CUKE_STEP_GET_MATCHER_(__VA_ARGS__, ()), \
        CUKE_STEP_GET_ARGS_(__VA_ARGS__, (), ()) \
    )                                            \
    /**/

#define CUKE_STEP_WITH_NAME_(step_name, step_matcher, args) \
    CUKE_OBJECT_(                                           \
        step_name,                                          \
        STEP_INHERITANCE(step_name),                        \
        CUKE_STEP_REGISTRATION_(step_name, step_matcher),   \
        args                                                \
    )                                                       \
    /**/

#define CUKE_STEP_REGISTRATION_(step_name, step_matcher) \
    ::cucumber::internal::registerStep<step_name>(step_matcher, __FILE__, __LINE__) /**/

// ************************************************************************** //
// **************               GIVEN/WHEN/THEN                ************** //
// ************************************************************************** //

#define GIVEN CUKE_STEP_
#define WHEN CUKE_STEP_
#define THEN CUKE_STEP_

// ************************************************************************** //
// **************                 REGEX_PARAM                  ************** //
// ************************************************************************** //

#define REGEX_PARAM(type, name) const type name(getInvokeArg<type>())
#define TABLE_PARAM(name) const ::cucumber::internal::Table& name = getArgs()->getTableArg()

#endif /* CUKE_STEPMACROS_HPP_ */


================================================
FILE: include/cucumber-cpp/internal/step/StepManager.hpp
================================================
#ifndef CUKE_STEPMANAGER_HPP_
#define CUKE_STEPMANAGER_HPP_

#include <map>
#include <sstream>
#include <stdexcept>
#include <string>
#include <vector>
#include <memory>
#include <type_traits>

#include <cucumber-cpp/internal/CukeExport.hpp>
#include "../Table.hpp"
#include "../utils/IndexSequence.hpp"
#include "../utils/Regex.hpp"

namespace cucumber {
namespace internal {

typedef unsigned int step_id_type;

class StepInfo;

class CUCUMBER_CPP_EXPORT SingleStepMatch {
public:
    typedef RegexMatch::submatches_type submatches_type;

    operator const void*() const;

    std::shared_ptr<const StepInfo> stepInfo;
    submatches_type submatches;
};

class CUCUMBER_CPP_EXPORT MatchResult {
public:
    typedef std::vector<SingleStepMatch> match_results_type;

    const match_results_type& getResultSet();
    void addMatch(SingleStepMatch match);

    explicit operator bool() const;

private:
    match_results_type resultSet;
};

class CUCUMBER_CPP_EXPORT InvokeArgs {
    typedef std::vector<std::string> args_type;

public:
    typedef args_type::size_type size_type;

    InvokeArgs() = default;

    void addArg(const std::string arg);
    Table& getVariableTableArg();

    template<class T>
    T getInvokeArg(size_type i) const;
    const Table& getTableArg() const;

private:
    Table tableArg;
    args_type args;
};

enum InvokeResultType {
    SUCCESS,
    FAILURE,
    PENDING
};

class CUCUMBER_CPP_EXPORT InvokeResult {
private:
    InvokeResultType type;
    std::string description;

    InvokeResult(const InvokeResultType type, const char* description);

public:
    InvokeResult();
    InvokeResult(const InvokeResult& ir);
    InvokeResult& operator=(const InvokeResult& rhs);

    static InvokeResult success();
    static InvokeResult failure(const char* description);
    static InvokeResult failure(const std::string& description);
    static InvokeResult pending(const char* description);

    bool isSuccess() const;
    bool isPending() const;
    InvokeResultType getType() const;
    const std::string& getDescription() const;
};

class CUCUMBER_CPP_EXPORT StepInfo : public std::enable_shared_from_this<StepInfo> {
public:
    StepInfo(const std::string& stepMatcher, const std::string source);

    virtual ~StepInfo() = default;

    SingleStepMatch matches(const std::string& stepDescription) const;
    virtual InvokeResult invokeStep(const InvokeArgs* pArgs) const = 0;

    step_id_type id;
    Regex regex;
    const std::string source;

private:
    // Shut up MSVC warning C4512: assignment operator could not be generated
    StepInfo& operator=(const StepInfo& other);
};

class CUCUMBER_CPP_EXPORT BasicStep {
public:
    virtual ~BasicStep() = default;

    InvokeResult invoke(const InvokeArgs* pArgs);

protected:
    typedef const Table table_type;
    typedef const Table::hashes_type table_hashes_type;

    virtual const InvokeResult invokeStepBody() = 0;
    virtual void body() = 0;

    void pending(const char* description);
    void pending();

    template<class T>
    const T getInvokeArg();
    const InvokeArgs* getArgs();

    template<typename Derived, typename R, typename... Args, std::size_t... N>
    static R invokeWithIndexedArgs(Derived& that, R (Derived::*f)(Args...), index_sequence<N...>) {
        return (that.*f)(that.pArgs->template getInvokeArg<typename std::decay<Args>::type>(N)...);
    }

    template<typename Derived, typename R, typename... Args>
    static R invokeWithArgs(Derived& that, R (Derived::*f)(Args...)) {
        that.currentArgIndex = sizeof...(Args);
        return invokeWithIndexedArgs(that, f, index_sequence_for<Args...>{});
    }

private:
    // FIXME: awful hack because of Boost::Test
    InvokeResult currentResult;

    const InvokeArgs* pArgs;
    InvokeArgs::size_type currentArgIndex;
};

template<class T>
class StepInvoker : public StepInfo {
public:
    StepInvoker(const std::string& stepMatcher, const std::string source);

    InvokeResult invokeStep(const InvokeArgs* args) const override;
};

class CUCUMBER_CPP_EXPORT StepManager {
protected:
    typedef std::map<step_id_type, std::shared_ptr<const StepInfo>> steps_type;

public:
    static step_id_type addStep(std::shared_ptr<StepInfo> stepInfo);
    static MatchResult stepMatches(const std::string& stepDescription);
    static const StepInfo* getStep(step_id_type id);

protected:
    static steps_type& steps();

private:
    // We're a singleton so don't allow instances
    StepManager() = delete;
};

static inline std::string toSourceString(const char* filePath, const int line) {
    using namespace std;
    stringstream s;
    string file(filePath);
    string::size_type pos = file.find_last_of("/\\");
    if (pos == string::npos) {
        s << file;
    } else {
        s << file.substr(++pos);
    }
    s << ":" << line;
    return s.str();
}

template<class T>
static int registerStep(const std::string& stepMatcher, const char* file, const int line) {
    return StepManager::addStep(
        std::make_shared<StepInvoker<T>>(stepMatcher, toSourceString(file, line))
    );
}

template<typename T>
T fromString(const std::string& s) {
    std::istringstream stream(s);
    T t;
    stream >> t;
    if (stream.fail()) {
        throw std::invalid_argument("Cannot convert parameter");
    }
    return t;
}

template<>
inline std::string fromString(const std::string& s) {
    return s;
}

template<typename T>
std::string toString(T arg) {
    std::stringstream s;
    s << arg;
    return s.str();
}

template<typename T>
T InvokeArgs::getInvokeArg(size_type i) const {
    if (i >= args.size()) {
        throw std::invalid_argument("Parameter not found");
    }
    return fromString<T>(args.at(i));
}

template<typename T>
const T BasicStep::getInvokeArg() {
    return pArgs->getInvokeArg<T>(currentArgIndex++);
}

template<class T>
StepInvoker<T>::StepInvoker(const std::string& stepMatcher, const std::string source) :
    StepInfo(stepMatcher, source) {
}

template<class T>
InvokeResult StepInvoker<T>::invokeStep(const InvokeArgs* pArgs) const {
    T t;
    return t.invoke(pArgs);
}

}
}

#endif /* CUKE_STEPMANAGER_HPP_ */


================================================
FILE: include/cucumber-cpp/internal/utils/IndexSequence.hpp
================================================
#ifndef CUKE_INDEXSEQ_HPP_
#define CUKE_INDEXSEQ_HPP_

#include <utility>

namespace cucumber {
namespace internal {

using ::std::index_sequence;
using ::std::index_sequence_for;

}
}

#endif /* CUKE_INDEXSEQ_HPP_ */


================================================
FILE: include/cucumber-cpp/internal/utils/Regex.hpp
================================================
#ifndef CUKE_REGEX_HPP_
#define CUKE_REGEX_HPP_

#include <cstddef>
#include <vector>

#include <regex>

namespace cucumber {
namespace internal {

struct RegexSubmatch {
    std::string value;
    std::ptrdiff_t position;
};

class RegexMatch {
public:
    typedef std::vector<RegexSubmatch> submatches_type;

    virtual ~RegexMatch() = default;

    bool matches();
    const submatches_type& getSubmatches();

protected:
    bool regexMatched;
    submatches_type submatches;
};

class FindRegexMatch : public RegexMatch {
public:
    FindRegexMatch(const std::regex& regexImpl, const std::string& expression);
};

class FindAllRegexMatch : public RegexMatch {
public:
    FindAllRegexMatch(const std::regex& regexImpl, const std::string& expression);
};

class Regex {
private:
    std::regex regexImpl;
    const std::string regexString;

public:
    Regex(std::string expr);

    std::shared_ptr<RegexMatch> find(const std::string& expression) const;
    std::shared_ptr<RegexMatch> findAll(const std::string& expression) const;

    std::string str() const;
};

}
}

#endif /* CUKE_REGEX_HPP_ */


================================================
FILE: run-linux.sh
================================================
#!/bin/sh
set -e #break script on non-zero exitcode from any command
set -x #display command being executed

CTEST_OUTPUT_ON_FAILURE=ON
export CTEST_OUTPUT_ON_FAILURE

cmake -E make_directory build
cmake -E chdir build cmake \
    -G Ninja \
    -DCUKE_STRICT=on \
    -DCUKE_ENABLE_BOOST_TEST=on \
    -DCUKE_ENABLE_GTEST=on \
    -DCUKE_ENABLE_QT_6=on \
    -DCUKE_ENABLE_EXAMPLES=on \
    -DCUKE_TESTS_UNIT=on \
    -DCUKE_CODE_COVERAGE=on \
    ..
cmake --build build --parallel --verbose

#
# Run tests
#

cmake --build build --target test

#
# Execute Calc examples
#

for TEST in \
    build/examples/Calc/GTestCalculatorSteps \
    build/examples/Calc/QtTestCalculatorSteps \
    build/examples/Calc/BoostCalculatorSteps \
    build/examples/Calc/FuncArgsCalculatorSteps \
; do
    "${TEST}" > /dev/null &
    sleep 1
    (cd examples/Calc; cucumber)
    wait %
done

#
# Execute QtCalc examples
#

for TEST in \
    build/examples/CalcQt/GTestCalculatorQtSteps \
    build/examples/CalcQt/QtTestCalculatorQtSteps \
    build/examples/CalcQt/BoostCalculatorQtSteps \
; do
    "${TEST}" 2> /dev/null &
    sleep 1
    (cd examples/CalcQt; cucumber)
    wait %
done

#
# Execute feature showcase on Unix socket
#

SOCK=`pwd`/cucumber.wire.sock
TEST=build/examples/FeatureShowcase/FeatureShowcaseSteps
echo "unix: ${SOCK}" > examples/FeatureShowcase/features/step_definitions/cucumber.wire
"${TEST}" --unix "${SOCK}" > /dev/null &
(cd examples/FeatureShowcase; cucumber)
wait %

mkdir -p coverage
gcovr build/ --html-details --output coverage/index.html --xml coverage/cobertura.xml

sudo cmake --install build


================================================
FILE: run-windows.ps1
================================================
# --- Function definitions ---
function Invoke-CMake {
    param (
        $Arguments
    )
    $process = Start-Process "cmake" -ArgumentList "$Arguments" -NoNewWindow -Wait -PassThru
    If ($process.ExitCode -ne 0) {
        Write-Host "Abort script execution due to CMake error."
        Exit(42)
    }
}

function Get-VariableOrEnv {
    param (
        [string]$Name
    )

    $envValue = [Environment]::GetEnvironmentVariable($Name)
    if ($envValue -ne $null) {
        return $envValue
    }

    if (Get-Variable -Name $Name -ErrorAction SilentlyContinue) {
        return (Get-Variable -Name $Name).Value
    }

    return $null
}

# --- Variable definitions ---
$cpp_standard = Get-VariableOrEnv -Name "cpp_standard"

$nlohmann_json_DIR = Get-VariableOrEnv -Name "nlohmann_json_DIR"
$Asio_ROOT = Get-VariableOrEnv -Name "Asio_ROOT"
$TCLAP_ROOT = Get-VariableOrEnv -Name "TCLAP_ROOT"
$Env:BOOST_ROOT = "boost_${Env:BOOST_VERSION}".Replace(".","_")

$Env:CTEST_OUTPUT_ON_FAILURE="ON"


# --- Script ---

Invoke-CMake "-E","make_directory","build"

$cmake_params = "-E chdir build cmake",
    "-DBUILD_SHARED_LIBS=`"${BUILD_SHARED_LIBS}`"",
    "-DCMAKE_INSTALL_PREFIX=${HOME}/.local"

$cmake_params += "-DCMAKE_CXX_STANDARD=${cpp_standard}"

$cmake_params += "-DCUKE_ENABLE_BOOST_TEST=OFF"
$cmake_params += "-DCUKE_ENABLE_GTEST=OFF"
$cmake_params += "-DCUKE_ENABLE_QT_6=OFF"
$cmake_params += "-DCUKE_ENABLE_EXAMPLES=OFF"
$cmake_params += "-DCUKE_TESTS_UNIT=OFF"
$cmake_params += "-DCUKE_CODE_COVERAGE=OFF"

$cmake_params += "-Dnlohmann_json_DIR=${nlohmann_json_DIR}"
$cmake_params += "-DAsio_ROOT=${Asio_ROOT}"
$cmake_params += "-DTCLAP_ROOT=${TCLAP_ROOT}"

$cmake_params += ".."


Invoke-CMake "$cmake_params"
Invoke-CMake "--build","build" #,"--parallel"


================================================
FILE: src/CMakeLists.txt
================================================
include(GenerateExportHeader)

find_package(nlohmann_json 3.10.5 REQUIRED)
find_package(Asio REQUIRED)
find_package(TCLAP REQUIRED)
include(../cmake/modules/GitVersion.cmake)

set(CUKE_SOURCES
    drivers/GenericDriver.cpp
    ContextManager.cpp
    CukeCommands.cpp
    CukeEngine.cpp
    CukeEngineImpl.cpp
    StepManager.cpp
    HookRegistrar.cpp
    Regex.cpp
    Scenario.cpp
    Table.cpp
    Tag.cpp
    connectors/wire/WireServer.cpp
    connectors/wire/WireProtocol.cpp
    connectors/wire/WireProtocolCommands.cpp
    )

if(TARGET GTest::gtest)
    list(APPEND CUKE_EXTRA_PRIVATE_LIBRARIES GTest::gtest)
    list(APPEND CUKE_SOURCES drivers/GTestDriver.cpp)
endif()

if(TARGET Boost::unit_test_framework)
    list(APPEND CUKE_EXTRA_PRIVATE_LIBRARIES Boost::unit_test_framework)
    list(APPEND CUKE_SOURCES drivers/BoostDriver.cpp)
    list(APPEND CUKE_DEP_LIBRARIES ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
endif()

if(TARGET Qt::Test)
    qt_wrap_cpp(MOC_FILE ../include/cucumber-cpp/internal/drivers/QtTestDriver.hpp)
    list(APPEND CUKE_SOURCES ${MOC_FILE})
    list(APPEND CUKE_SOURCES drivers/QtTestDriver.cpp)
    list(APPEND CUKE_EXTRA_PRIVATE_LIBRARIES Qt::Test)
endif()

message(STATUS "Adding header files to project")
set(CUKE_HEADERS
    ../include/cucumber-cpp/autodetect.hpp
    ../include/cucumber-cpp/defs.hpp
    ../include/cucumber-cpp/generic.hpp
    ../include/cucumber-cpp/internal/ContextManager.hpp
    ../include/cucumber-cpp/internal/CukeCommands.hpp
    ../include/cucumber-cpp/internal/CukeEngine.hpp
    ../include/cucumber-cpp/internal/CukeEngineImpl.hpp
    ../include/cucumber-cpp/internal/Macros.hpp
    ../include/cucumber-cpp/internal/RegistrationMacros.hpp
    ../include/cucumber-cpp/internal/Scenario.hpp
    ../include/cucumber-cpp/internal/Table.hpp
    ../include/cucumber-cpp/internal/connectors/wire/ProtocolHandler.hpp
    ../include/cucumber-cpp/internal/connectors/wire/WireProtocol.hpp
    ../include/cucumber-cpp/internal/connectors/wire/WireProtocolCommands.hpp
    ../include/cucumber-cpp/internal/connectors/wire/WireServer.hpp
    ../include/cucumber-cpp/internal/defs.hpp
    ../include/cucumber-cpp/internal/drivers/BoostDriver.hpp
    ../include/cucumber-cpp/internal/drivers/DriverSelector.hpp
    ../include/cucumber-cpp/internal/drivers/GTestDriver.hpp
    ../include/cucumber-cpp/internal/drivers/GenericDriver.hpp
    ../include/cucumber-cpp/internal/drivers/QtTestDriver.hpp
    ../include/cucumber-cpp/internal/hook/HookMacros.hpp
    ../include/cucumber-cpp/internal/hook/HookRegistrar.hpp
    ../include/cucumber-cpp/internal/hook/Tag.hpp
    ../include/cucumber-cpp/internal/step/StepMacros.hpp
    ../include/cucumber-cpp/internal/step/StepManager.hpp
    ../include/cucumber-cpp/internal/utils/IndexSequence.hpp
    ../include/cucumber-cpp/internal/utils/Regex.hpp
)
if(MSVC_IDE)
    source_group("Header Files" FILES ${CUKE_HEADERS})
endif()
list(APPEND CUKE_SOURCES ${CUKE_HEADERS})

# Library for unit tests relying on internals
add_library(cucumber-cpp-internal STATIC ${CUKE_SOURCES})

add_library(cucumber-cpp-nomain ${CUKE_SOURCES})
add_library(cucumber-cpp ${CUKE_SOURCES} main.cpp)

set_target_properties(
    cucumber-cpp-internal
    cucumber-cpp
    cucumber-cpp-nomain
    PROPERTIES
        DEFINE_SYMBOL cucumber_cpp_EXPORTS
        CXX_VISIBILITY_PRESET hidden
        VISIBILITY_INLINES_HIDDEN ON
)

generate_export_header(cucumber-cpp
    EXPORT_FILE_NAME "cucumber-cpp/internal/CukeExport.hpp"
)

foreach(TARGET
        cucumber-cpp-internal
        cucumber-cpp-nomain
        cucumber-cpp
)
    target_include_directories(${TARGET}
        PUBLIC
            $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
            $<BUILD_INTERFACE:${CUKE_INCLUDE_DIR}>
            $<BUILD_INTERFACE:${ASIO_INCLUDE_DIR}>
            $<BUILD_INTERFACE:${TCLAP_INCLUDE_DIR}>
            $<INSTALL_INTERFACE:$<INSTALL_PREFIX>/include>
    )
    target_link_libraries(${TARGET}
        PRIVATE
            ${CUKE_EXTRA_PRIVATE_LIBRARIES}
            nlohmann_json::nlohmann_json
    )
    # Don't export or import symbols for statically linked libraries
    get_property(type TARGET ${TARGET} PROPERTY TYPE)
    if(NOT "${type}" MATCHES "^(SHARED|MODULE)_LIBRARY$")
        target_compile_definitions(${TARGET} PUBLIC CUCUMBER_CPP_STATIC_DEFINE)
    endif()
    if(MINGW)
        target_link_libraries(${TARGET}
            PRIVATE
                ws2_32
        )
    endif(MINGW)
endforeach()

git_get_version(CUKE_VERSION)
message(STATUS "Version: ${CUKE_VERSION}")
target_compile_definitions(cucumber-cpp PRIVATE
    CUKE_VERSION="${CUKE_VERSION}"
)

include(GNUInstallDirs)
install(DIRECTORY ${CUKE_INCLUDE_DIR}/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(
    FILES
        "${CMAKE_CURRENT_BINARY_DIR}/cucumber-cpp/internal/CukeExport.hpp"
    DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/cucumber-cpp/internal"
)
install(
    TARGETS
        cucumber-cpp-nomain
        cucumber-cpp
    EXPORT   CucumberCpp
    ARCHIVE  DESTINATION ${CMAKE_INSTALL_LIBDIR}
    LIBRARY  DESTINATION ${CMAKE_INSTALL_LIBDIR}
    RUNTIME  DESTINATION ${CMAKE_INSTALL_BINDIR}
)
install(
    EXPORT      CucumberCpp
    NAMESPACE   CucumberCpp::
    DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake
    FILE        CucumberCppConfig.cmake
)


================================================
FILE: src/ContextManager.cpp
================================================
#include "cucumber-cpp/internal/ContextManager.hpp"

namespace cucumber {
namespace internal {

contexts_type ContextManager::contexts;

void ContextManager::purgeContexts() {
    contexts.clear();
}

}
}


================================================
FILE: src/CukeCommands.cpp
================================================
#include "cucumber-cpp/internal/CukeCommands.hpp"
#include "cucumber-cpp/internal/hook/HookRegistrar.hpp"

#include <sstream>

namespace cucumber {
namespace internal {

std::shared_ptr<Scenario> CukeCommands::currentScenario;

CukeCommands::CukeCommands() :
    hasStarted(false) {
}

CukeCommands::~CukeCommands() {
    if (hasStarted) {
        HookRegistrar::execAfterAllHooks();
    }
}

void CukeCommands::beginScenario(const TagExpression::tag_list& tags) {
    if (!hasStarted) {
        hasStarted = true;
        HookRegistrar::execBeforeAllHooks();
    }

    currentScenario = std::make_shared<Scenario>(tags);
    HookRegistrar::execBeforeHooks(currentScenario.get());
}

void CukeCommands::endScenario() {
    HookRegistrar::execAfterHooks(currentScenario.get());
    contextManager.purgeContexts();
    currentScenario.reset();
}

const std::string CukeCommands::snippetText(
    const std::string stepKeyword, const std::string stepName
) const {
    std::stringstream text;
    std::string stepKeywordUpperCase;
    std::transform(
        stepKeyword.begin(), stepKeyword.end(), std::back_inserter(stepKeywordUpperCase), ::toupper
    );
    text << stepKeywordUpperCase << "(\"" << escapeCString("^" + escapeRegex(stepName) + "$")
         << "\") {\n"
         << "    pending();\n"
         << "}\n";
    return text.str();
}

const std::string CukeCommands::escapeRegex(const std::string reg) const {
    return regex_replace(
        reg,
        std::regex("[\\|\\(\\)\\[\\]\\{\\}\\^\\$\\*\\+\\?\\.\\\\]"),
        "\\\\&",
        std::regex_constants::match_default | std::regex_constants::format_sed
    );
}

const std::string CukeCommands::escapeCString(const std::string str) const {
    return regex_replace(
        str,
        std::regex("[\"\\\\]"),
        "\\\\&",
        std::regex_constants::match_default | std::regex_constants::format_sed
    );
}

MatchResult CukeCommands::stepMatches(const std::string description) const {
    return StepManager::stepMatches(description);
}

InvokeResult CukeCommands::invoke(step_id_type id, const InvokeArgs* pArgs) {
    const StepInfo* const stepInfo = StepManager::getStep(id);
    InvokeResult result = HookRegistrar::execStepChain(currentScenario.get(), stepInfo, pArgs);
    HookRegistrar::execAfterStepHooks(currentScenario.get());
    return result;
}

}
}


================================================
FILE: src/CukeEngine.cpp
================================================
#include "cucumber-cpp/internal/CukeEngine.hpp"

namespace cucumber {
namespace internal {

InvokeException::InvokeException(const std::string& message) :
    message(message) {
}

InvokeException::InvokeException(const InvokeException& rhs) :
    message(rhs.message) {
}

const std::string InvokeException::getMessage() const {
    return message;
}

InvokeFailureException::InvokeFailureException(
    const std::string& message, const std::string& exceptionType
) :
    InvokeException(message),
    exceptionType(exceptionType) {
}

InvokeFailureException::InvokeFailureException(const InvokeFailureException& rhs) :
    InvokeException(rhs),
    exceptionType(rhs.exceptionType) {
}

const std::string InvokeFailureException::getExceptionType() const {
    return exceptionType;
}

PendingStepException::PendingStepException(const std::string& message) :
    InvokeException(message) {
}

PendingStepException::PendingStepException(const PendingStepException& rhs) :
    InvokeException(rhs) {
}

CukeEngine::CukeEngine() {
}

}
}


================================================
FILE: src/CukeEngineImpl.cpp
================================================
#include "cucumber-cpp/internal/CukeEngineImpl.hpp"

namespace cucumber {
namespace internal {

namespace {

std::string convertId(step_id_type id) {
    std::stringstream ss;
    ss << id;
    return ss.str();
}

step_id_type convertId(const std::string& stringid) {
    std::stringstream ss(stringid);
    step_id_type id;
    ss >> id;
    return id;
}
}

std::vector<StepMatch> CukeEngineImpl::stepMatches(const std::string& name) const {
    std::vector<StepMatch> engineResult;
    MatchResult commandResult = cukeCommands.stepMatches(name);
    for (const SingleStepMatch& commandMatch : commandResult.getResultSet()) {
        StepMatch engineMatch;
        engineMatch.id = convertId(commandMatch.stepInfo->id);
        engineMatch.source = commandMatch.stepInfo->source;
        engineMatch.regexp = commandMatch.stepInfo->regex.str();
        for (const RegexSubmatch& commandMatchArg : commandMatch.submatches) {
            StepMatchArg engineMatchArg;
            engineMatchArg.value = commandMatchArg.value;
            engineMatchArg.position = commandMatchArg.position;
            engineMatch.args.push_back(engineMatchArg);
        }
        engineResult.push_back(engineMatch);
    }
    return engineResult;
}

void CukeEngineImpl::beginScenario(const tags_type& tags) {
    cukeCommands.beginScenario(tags);
}

void CukeEngineImpl::invokeStep(
    const std::string& id, const invoke_args_type& args, const invoke_table_type& tableArg
) {
    InvokeArgs commandArgs;
    try {
        for (const std::string& a : args) {
            commandArgs.addArg(a);
        }

        if (!tableArg.empty() && !tableArg.front().empty()) {
            Table& commandTableArg = commandArgs.getVariableTableArg();
            for (const auto& arg : tableArg[0]) {
                commandTableArg.addColumn(arg);
            }

            for (std::size_t i = 1; i < tableArg.size(); ++i) {
                Table::row_type row;
                for (const auto& arg : tableArg[i]) {
                    row.push_back(arg);
                }
                commandTableArg.addRow(row);
            }
        }
    } catch (...) {
        throw InvokeException("Unable to decode arguments");
    }

    InvokeResult commandResult;
    try {
        commandResult = cukeCommands.invoke(convertId(id), &commandArgs);
    } catch (...) {
        throw InvokeException("Uncatched exception");
    }
    switch (commandResult.getType()) {
    case SUCCESS:
        return;
    case FAILURE:
        throw InvokeFailureException(commandResult.getDescription(), "");
    case PENDING:
        throw PendingStepException(commandResult.getDescription());
    }
}

void CukeEngineImpl::endScenario(const tags_type& /*tags*/) {
    cukeCommands.endScenario();
}

std::string CukeEngineImpl::snippetText(
    const std::string& keyword, const std::string& name, const std::string& /*multilineArgClass*/
) const {
    return cukeCommands.snippetText(keyword, name);
}

}
}


================================================
FILE: src/HookRegistrar.cpp
================================================
#include <cucumber-cpp/internal/hook/HookRegistrar.hpp>
#include <cucumber-cpp/internal/CukeCommands.hpp>

namespace cucumber {
namespace internal {

void Hook::invokeHook(Scenario* scenario, CallableStep*) {
    if (tagsMatch(scenario)) {
        body();
    } else {
        skipHook();
    }
}

void Hook::skipHook() {
}

void Hook::setTags(const std::string& csvTagNotation) {
    tagExpression = AndTagExpression(csvTagNotation);
}

bool Hook::tagsMatch(Scenario* scenario) {
    return !scenario || tagExpression.matches(scenario->getTags());
}

void AroundStepHook::invokeHook(Scenario* scenario, CallableStep* step) {
    this->step = step;
    Hook::invokeHook(scenario, NULL);
}

void AroundStepHook::skipHook() {
    step->call();
}

void UnconditionalHook::invokeHook(Scenario*, CallableStep*) {
    body();
}

void HookRegistrar::addBeforeHook(std::shared_ptr<BeforeHook> beforeHook) {
    beforeHooks().push_back(beforeHook);
}

HookRegistrar::hook_list_type& HookRegistrar::beforeHooks() {
    static hook_list_type beforeHooks;
    return beforeHooks;
}

void HookRegistrar::execBeforeHooks(Scenario* scenario) {
    execHooks(beforeHooks(), scenario);
}

void HookRegistrar::addAroundStepHook(std::shared_ptr<AroundStepHook> aroundStepHook) {
    aroundStepHooks().push_front(aroundStepHook);
}

HookRegistrar::aroundhook_list_type& HookRegistrar::aroundStepHooks() {
    static aroundhook_list_type aroundStepHooks;
    return aroundStepHooks;
}

InvokeResult HookRegistrar::execStepChain(
    Scenario* scenario, const StepInfo* const stepInfo, const InvokeArgs* pArgs
) {
    StepCallChain scc(scenario, stepInfo, pArgs, aroundStepHooks());
    return scc.exec();
}

void HookRegistrar::addAfterStepHook(std::shared_ptr<AfterStepHook> afterStepHook) {
    afterStepHooks().push_front(afterStepHook);
}

HookRegistrar::hook_list_type& HookRegistrar::afterStepHooks() {
    static hook_list_type afterStepHooks;
    return afterStepHooks;
}

void HookRegistrar::execAfterStepHooks(Scenario* scenario) {
    execHooks(afterStepHooks(), scenario);
}

void HookRegistrar::addAfterHook(std::shared_ptr<AfterHook> afterHook) {
    afterHooks().push_front(afterHook);
}

HookRegistrar::hook_list_type& HookRegistrar::afterHooks() {
    static hook_list_type afterHooks;
    return afterHooks;
}

void HookRegistrar::execAfterHooks(Scenario* scenario) {
    execHooks(afterHooks(), scenario);
}

void HookRegistrar::execHooks(HookRegistrar::hook_list_type& hookList, Scenario* scenario) {
    for (HookRegistrar::hook_list_type::iterator hook = hookList.begin(); hook != hookList.end();
         ++hook) {
        (*hook)->invokeHook(scenario, NULL);
    }
}

HookRegistrar::hook_list_type& HookRegistrar::beforeAllHooks() {
    static hook_list_type beforeAllHooks;
    return beforeAllHooks;
}

void HookRegistrar::addBeforeAllHook(std::shared_ptr<BeforeAllHook> beforeAllHook) {
    beforeAllHooks().push_back(beforeAllHook);
}

void HookRegistrar::execBeforeAllHooks() {
    execHooks(beforeAllHooks(), NULL);
}

HookRegistrar::hook_list_type& HookRegistrar::afterAllHooks() {
    static hook_list_type afterAllHooks;
    return afterAllHooks;
}

void HookRegistrar::addAfterAllHook(std::shared_ptr<AfterAllHook> afterAllHook) {
    afterAllHooks().push_back(afterAllHook);
}

void HookRegistrar::execAfterAllHooks() {
    execHooks(afterAllHooks(), NULL);
}

StepCallChain::StepCallChain(
    Scenario* scenario,
    const StepInfo* const stepInfo,
    const InvokeArgs* pStepArgs,
    HookRegistrar::aroundhook_list_type& aroundHooks
) :
    scenario(scenario),
    stepInfo(stepInfo),
    pStepArgs(pStepArgs) {
    nextHook = aroundHooks.begin();
    hookEnd = aroundHooks.end();
}

InvokeResult StepCallChain::exec() {
    execNext();
    return result;
}

void StepCallChain::execNext() {
    if (nextHook == hookEnd) {
        execStep();
    } else {
        HookRegistrar::aroundhook_list_type::iterator currentHook = nextHook++;
        CallableStepChain callableStepChain(this);
        (*currentHook)->invokeHook(scenario, &callableStepChain);
    }
}

void StepCallChain::execStep() {
    if (stepInfo) {
        result = stepInfo->invokeStep(pStepArgs);
    }
}

CallableStepChain::CallableStepChain(StepCallChain* scc) :
    scc(scc) {
}

void CallableStepChain::call() {
    scc->execNext();
}

}
}


================================================
FILE: src/Regex.cpp
================================================
#include <cucumber-cpp/internal/utils/Regex.hpp>

#include <algorithm>

namespace cucumber {
namespace internal {

Regex::Regex(std::string regularExpression) :
    regexImpl(regularExpression),
    regexString(regularExpression) {
}

bool RegexMatch::matches() {
    return regexMatched;
}

const RegexMatch::submatches_type& RegexMatch::getSubmatches() {
    return submatches;
}

std::string Regex::str() const {
    return regexString;
}

std::shared_ptr<RegexMatch> Regex::find(const std::string& expression) const {
    return std::make_shared<FindRegexMatch>(regexImpl, expression);
}

namespace {
bool isUtf8CodeUnitStartOfCodepoint(unsigned int i) {
    return (i & 0xc0) != 0x80;
}

std::ptrdiff_t utf8CodepointOffset(
    const std::string& expression, const std::string::const_iterator& it
) {
    return count_if(expression.begin(), it, &isUtf8CodeUnitStartOfCodepoint);
}
} // namespace

FindRegexMatch::FindRegexMatch(const std::regex& regexImpl, const std::string& expression) {
    std::smatch matchResults;
    regexMatched = std::regex_search(expression, matchResults, regexImpl);
    if (regexMatched) {
        std::smatch::const_iterator i = matchResults.begin();
        if (i != matchResults.end())
            // Skip capture group 0 which is the whole match, not a user marked sub-expression
            ++i;
        for (; i != matchResults.end(); ++i) {
            if (i->matched) {
                RegexSubmatch s = {*i, utf8CodepointOffset(expression, i->first)};
                submatches.push_back(s);
            } else {
                submatches.push_back(RegexSubmatch());
            }
        }
    }
}

std::shared_ptr<RegexMatch> Regex::findAll(const std::string& expression) const {
    return std::make_shared<FindAllRegexMatch>(regexImpl, expression);
}

FindAllRegexMatch::FindAllRegexMatch(const std::regex& regexImpl, const std::string& expression) {
    std::sregex_token_iterator i(
        expression.begin(), expression.end(), regexImpl, 1, std::regex_constants::match_continuous
    );
    const std::sregex_token_iterator end;
    for (; i != end; ++i) {
        RegexSubmatch s = {*i, -1};
        submatches.push_back(s);
    }
    regexMatched = !submatches.empty();
}

}
}


================================================
FILE: src/Scenario.cpp
================================================
#include <cucumber-cpp/internal/Scenario.hpp>

namespace cucumber {
namespace internal {

Scenario::Scenario(const TagExpression::tag_list& tags) :
    tags(tags) {
}

const TagExpression::tag_list& Scenario::getTags() {
    return tags;
}

}
}


================================================
FILE: src/StepManager.cpp
================================================
#include "cucumber-cpp/internal/step/StepManager.hpp"

namespace cucumber {
namespace internal {

StepInfo::StepInfo(const std::string& stepMatcher, const std::string source) :
    regex(stepMatcher),
    source(source) {
    static step_id_type currentId = 0;
    id = ++currentId;
}

SingleStepMatch StepInfo::matches(const std::string& stepDescription) const {
    SingleStepMatch stepMatch;
    std::shared_ptr<RegexMatch> regexMatch(regex.find(stepDescription));
    if (regexMatch->matches()) {
        stepMatch.stepInfo = shared_from_this();
        stepMatch.submatches = regexMatch->getSubmatches();
    }
    return stepMatch;
}

SingleStepMatch::operator const void*() const {
    return stepInfo.get();
}

MatchResult::operator bool() const {
    return !resultSet.empty();
}

const MatchResult::match_results_type& MatchResult::getResultSet() {
    return resultSet;
}

void MatchResult::addMatch(SingleStepMatch match) {
    resultSet.push_back(match);
}

void InvokeArgs::addArg(const std::string arg) {
    args.push_back(arg);
}

const Table& InvokeArgs::getTableArg() const {
    return tableArg;
}

Table& InvokeArgs::getVariableTableArg() {
    return tableArg;
}

InvokeResult::InvokeResult(const InvokeResultType type, const char* description) :
    type(type) {
    if (description) {
        this->description = description;
    };
}

InvokeResult::InvokeResult() :
    type(FAILURE) {
}

InvokeResult::InvokeResult(const InvokeResult& ir) :
    type(ir.type),
    description(ir.description) {
}

InvokeResult& InvokeResult::operator=(const InvokeResult& rhs) {
    this->type = rhs.type;
    this->description = rhs.description;
    return *this;
}

InvokeResult InvokeResult::success() {
    return InvokeResult(SUCCESS, 0);
}

InvokeResult InvokeResult::failure(const char* description) {
    return InvokeResult(FAILURE, description);
}

InvokeResult InvokeResult::failure(const std::string& description) {
    return InvokeResult(FAILURE, description.c_str());
}

InvokeResult InvokeResult::pending(const char* description) {
    return InvokeResult(PENDING, description);
}

bool InvokeResult::isSuccess() const {
    return (type == SUCCESS);
}

bool InvokeResult::isPending() const {
    return (type == PENDING);
}

InvokeResultType InvokeResult::getType() const {
    return type;
}

const std::string& InvokeResult::getDescription() const {
    return description;
}

step_id_type StepManager::addStep(std::shared_ptr<StepInfo> stepInfo) {
    return steps().insert(std::make_pair(stepInfo->id, stepInfo)).first->first;
}

MatchResult StepManager::stepMatches(const std::string& stepDescription) {
    MatchResult matchResult;
    for (steps_type::iterator iter = steps().begin(); iter != steps().end(); ++iter) {
        const std::shared_ptr<const StepInfo>& stepInfo = iter->second;
        SingleStepMatch currentMatch = stepInfo->matches(stepDescription);
        if (currentMatch) {
            matchResult.addMatch(currentMatch);
        }
    }
    return matchResult;
}

const StepInfo* StepManager::getStep(step_id_type id) {
    const steps_type::const_iterator step = steps().find(id);
    if (step == steps().end()) {
        return NULL;
    }
    return step->second.get();
}

/**
 * Needed to fix the "static initialization order fiasco"
 * http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.12
 */
StepManager::steps_type& StepManager::steps() {
    static steps_type steps;
    return steps;
}

InvokeResult BasicStep::invoke(const InvokeArgs* pArgs) {
    this->pArgs = pArgs;
    currentArgIndex = 0;
    currentResult = InvokeResult::success();
    try {
        InvokeResult returnedResult = invokeStepBody();
        if (currentResult.isPending()) {
            return currentResult;
        } else {
            return returnedResult;
        }
    } catch (const std::exception& ex) {
        return InvokeResult::failure(ex.what());
    } catch (const std::string& ex) {
        return InvokeResult::failure(ex);
    } catch (const char* ex) {
        return InvokeResult::failure(ex);
    } catch (...) {
        // Cucumber needs a description here
        return InvokeResult::failure("Unknown exception");
    }
}

void BasicStep::pending() {
    pending(0);
}

void BasicStep::pending(const char* description) {
    currentResult = InvokeResult::pending(description);
}

const InvokeArgs* BasicStep::getArgs() {
    return pArgs;
}

}
}


================================================
FILE: src/Table.cpp
================================================
#include <cucumber-cpp/internal/Table.hpp>

namespace cucumber {
namespace internal {

void Table::addColumn(const std::string column) {
    if (rows.empty()) {
        columns.push_back(column);
    } else {
        throw std::runtime_error("Cannot alter columns after rows have been added");
    }
}

void Table::addRow(const row_type& row) {
    const basic_type::size_type colSize = columns.size();
    if (colSize == 0) {
        throw std::runtime_error("No column defined yet");
    } else if (colSize != row.size()) {
        throw std::range_error("Row size does not match the table column size");
    } else {
        rows.push_back(buildHashRow(row));
    }
}

Table::hash_row_type Table::buildHashRow(const row_type& row) {
    hash_row_type hashRow;
    for (columns_type::size_type i = 0; i < columns.size(); ++i) {
        hashRow[columns[i]] = row[i];
    }
    return hashRow;
}

const Table::hashes_type& Table::hashes() const {
    return rows;
}

}
}


================================================
FILE: src/Tag.cpp
================================================
#include <cucumber-cpp/internal/hook/Tag.hpp>
#include <memory>

namespace cucumber {
namespace internal {

Regex& AndTagExpression::csvTagNotationRegex() {
    static Regex r("\\s*\"([^\"]+)\"\\s*(?:,|$)");
    return r;
}

AndTagExpression::AndTagExpression(const std::string& csvTagNotation) {
    const std::shared_ptr<RegexMatch> match(csvTagNotationRegex().findAll(csvTagNotation));
    const RegexMatch::submatches_type submatches = match->getSubmatches();
    orExpressions.reserve(submatches.size());
    for (RegexMatch::submatches_type::const_iterator i = submatches.begin(); i != submatches.end();
         ++i) {
        const std::string orCsvTagNotation = i->value;
        orExpressions.push_back(OrTagExpression(orCsvTagNotation));
    }
}

bool AndTagExpression::matches(const tag_list& tags) const {
    bool match = true;
    for (or_expressions_type::const_iterator i = orExpressions.begin();
         i != orExpressions.end() && match;
         ++i) {
        match &= i->matches(tags);
    }
    return match;
}

Regex& OrTagExpression::csvTagNotationRegex() {
    static Regex r("\\s*@(\\w+)\\s*(?:,|$)");
    return r;
}

OrTagExpression::OrTagExpression(const std::string& csvTagNotation) {
    const std::shared_ptr<RegexMatch> match(csvTagNotationRegex().findAll(csvTagNotation));
    const RegexMatch::submatches_type submatches = match->getSubmatches();
    orTags.reserve(submatches.size());
    for (RegexMatch::submatches_type::const_iterator i = submatches.begin(); i != submatches.end();
         ++i) {
        orTags.push_back(i->value);
    }
}

bool OrTagExpression::matches(const tag_list& tags) const {
    for (tag_list::const_iterator i = orTags.begin(); i != orTags.end(); ++i) {
        if (orTagMatchesTagList(*i, tags))
            return true;
    }
    return false;
}

bool OrTagExpression::orTagMatchesTagList(const std::string& currentOrTag, const tag_list& tags)
    const {
    for (tag_list::const_iterator i = tags.begin(); i != tags.end(); ++i) {
        if (*i == currentOrTag)
            return true;
    }
    return false;
}

}
}


================================================
FILE: src/connectors/wire/WireProtocol.cpp
================================================
#include <cucumber-cpp/internal/connectors/wire/WireProtocol.hpp>
#include <cucumber-cpp/internal/connectors/wire/WireProtocolCommands.hpp>

#include <nlohmann/json.hpp>

#include <iostream>
#include <string>
#include <sstream>

using json = nlohmann::json;

namespace cucumber {
namespace internal {

/*
 * Responses
 */

void SuccessResponse::accept(WireResponseVisitor& visitor) const {
    visitor.visit(*this);
}

FailureResponse::FailureResponse(const std::string& message, const std::string& exceptionType) :
    message(message),
    exceptionType(exceptionType) {
}

const std::string FailureResponse::getMessage() const {
    return message;
}

const std::string FailureResponse::getExceptionType() const {
    return exceptionType;
}

void FailureResponse::accept(WireResponseVisitor& visitor) const {
    visitor.visit(*this);
}

PendingResponse::PendingResponse(const std::string& message) :
    message(message) {
}

const std::string PendingResponse::getMessage() const {
    return message;
}

void PendingResponse::accept(WireResponseVisitor& visitor) const {
    visitor.visit(*this);
}

StepMatchesResponse::StepMatchesResponse(const std::vector<StepMatch>& matchingSteps) :
    matchingSteps(matchingSteps) {
}

const std::vector<StepMatch>& StepMatchesResponse::getMatchingSteps() const {
    return matchingSteps;
}

void StepMatchesResponse::accept(WireResponseVisitor& visitor) const {
    visitor.visit(*this);
}

SnippetTextResponse::SnippetTextResponse(const std::string& stepSnippet) :
    stepSnippet(stepSnippet) {
}

const std::string SnippetTextResponse::getStepSnippet() const {
    return stepSnippet;
}

void SnippetTextResponse::accept(WireResponseVisitor& visitor) const {
    visitor.visit(*this);
}

/*
 * Command decoders
 */

namespace {
typedef std::shared_ptr<WireCommand> (*CommandDecoder)(const json& jsonArgs);

CukeEngine::tags_type getScenarioTags(const json& jsonArgs) {
    CukeEngine::tags_type tags;
    if (!jsonArgs.is_null()) {
        const auto& jsonTags = jsonArgs.at("tags");
        for (const auto& tag : jsonTags) {
            tags.push_back(tag.get<std::string>());
        }
    }
    return tags;
}

std::shared_ptr<WireCommand> BeginScenarioDecoder(const json& jsonArgs) {
    return std::make_shared<BeginScenarioCommand>(getScenarioTags(jsonArgs));
}

std::shared_ptr<WireCommand> EndScenarioDecoder(const json& jsonArgs) {
    return std::make_shared<EndScenarioCommand>(getScenarioTags(jsonArgs));
}

std::shared_ptr<WireCommand> StepMatchesDecoder(const json& jsonArgs) {
    const std::string& nameToMatch = jsonArgs.at("name_to_match");
    return std::make_shared<StepMatchesCommand>(nameToMatch);
}

void fillTableArg(const json& jsonTableArg, CukeEngine::invoke_table_type& tableArg) {
    const std::size_t rows = jsonTableArg.size();
    if (rows > 0) {
        const std::size_t columns = jsonTableArg[0].get<std::vector<std::string>>().size();
        tableArg.resize(rows);
        for (std::size_t i = 0; i < rows; ++i) {
            const auto& jsonRow(jsonTableArg[i].get<std::vector<std::string>>());
            if (jsonRow.size() == columns) {
                for (std::size_t j = 0; j < columns; ++j) {
                    tableArg[i].push_back(jsonRow[j]);
                }
            } else {
                // TODO: Invalid row
            }
        }
    } else {
        // TODO: Invalid table (no column specified)
    }
}

void fillInvokeArgs(
    const json& invokeParams,
    CukeEngine::invoke_args_type& args,
    CukeEngine::invoke_table_type& tableArg
) {
    const auto& jsonArgs = invokeParams.at("args");
    for (const auto& arg : jsonArgs) {
        if (arg.is_string()) {
            args.push_back(arg.get<std::string>());
        } else if (arg.is_array()) {
            fillTableArg(arg, tableArg);
        }
    }
}

std::shared_ptr<WireCommand> InvokeDecoder(const json& jsonArgs) {
    const auto& invokeParams = jsonArgs.get<json::object_t>();

    CukeEngine::invoke_args_type args;
    CukeEngine::invoke_table_type tableArg;
    const std::string& id = invokeParams.at("id");
    fillInvokeArgs(invokeParams, args, tableArg);
    return std::make_shared<InvokeCommand>(id, args, tableArg);
}

std::shared_ptr<WireCommand> SnippetTextDecoder(const json& jsonArgs) {
    const auto& snippetTextArgs = jsonArgs.get<json::object_t>();
    const std::string& stepKeyword = snippetTextArgs.at("step_keyword");
    const std::string& stepName = snippetTextArgs.at("step_name");
    const std::string& multilineArgClass = snippetTextArgs.at("multiline_arg_class");
    return std::make_shared<SnippetTextCommand>(stepKeyword, stepName, multilineArgClass);
}
}

static const std::map<std::string, CommandDecoder> commandDecodersMap = {
    {"begin_scenario", BeginScenarioDecoder},
    {"end_scenario", EndScenarioDecoder},
    {"step_matches", StepMatchesDecoder},
    {"invoke", InvokeDecoder},
    {"snippet_text", SnippetTextDecoder},
};

std::shared_ptr<WireCommand> JsonWireMessageCodec::decode(const std::string& request) const {
    try {
        json jsonRequest = json::parse(request);
        const auto& jsonCommand = jsonRequest.at(0);

        const auto& commandDecoder = commandDecodersMap.find(jsonCommand.get<std::string>());
        if (commandDecoder != commandDecodersMap.end() && commandDecoder->second) {
            json jsonArgs;
            if (jsonRequest.size() > 1) {
                jsonArgs = jsonRequest.at(1);
            }
            return commandDecoder->second(jsonArgs);
        }
    } catch (...) {
        // LOG Error decoding wire protocol command
    }
    return std::make_shared<FailingCommand>();
}

namespace {

class WireResponseEncoder : public WireResponseVisitor {
private:
    json jsonOutput = json::array();

    void success(const json* detail = nullptr) {
        output("success", detail);
    }

    void fail(const json* detail = nullptr) {
        output("fail", detail);
    }

    void output(const std::string& responseType, const json* detail = nullptr) {
        jsonOutput.push_back(responseType);
        if (detail == nullptr || detail->is_null()) {
            return;
        }
        jsonOutput.push_back(*detail);
    }

public:
    std::string encode(const WireResponse& response) {
        jsonOutput.clear();
        response.accept(*this);
        return jsonOutput.dump();
    }

    void visit(const SuccessResponse& /*response*/) override {
        success();
    }

    void visit(const FailureResponse& response) override {
        json detailObject;
        if (!response.getMessage().empty()) {
            detailObject["message"] = response.getMessage();
        }
        if (!response.getExceptionType().empty()) {
            detailObject["exception"] = response.getExceptionType();
        }
        if (detailObject.empty()) {
            fail();
        } else {
            const json detail(detailObject);
            fail(&detail);
        }
    }

    void visit(const PendingResponse& response) override {
        json jsonReponse(response.getMessage());
        output("pending", &jsonReponse);
    }

    void visit(const StepMatchesResponse& response) override {
        json jsonMatches = json::array();
        for (const StepMatch& m : response.getMatchingSteps()) {
            json jsonM;
            jsonM["id"] = m.id;
            json jsonArgs = json::array();
            for (const StepMatchArg& ma : m.args) {
                json jsonMa;
                jsonMa["val"] = ma.value;
                jsonMa["pos"] = static_cast<int64_t>(ma.position);
                jsonArgs.push_back(jsonMa);
            }
            jsonM["args"] = jsonArgs;
            if (!m.source.empty()) {
                jsonM["source"] = m.source;
            }
            if (!m.regexp.empty()) {
                jsonM["regexp"] = m.regexp;
            }
            jsonMatches.push_back(jsonM);
        }
        json jsonReponse(jsonMatches);
        output("success", &jsonReponse);
    }

    void visit(const SnippetTextResponse& response) override {
        json jsonReponse(response.getStepSnippet());
        success(&jsonReponse);
    }
};

}

const std::string JsonWireMessageCodec::encode(const WireResponse& response) const {
    try {
        WireResponseEncoder encoder;
        return encoder.encode(response);
    } catch (...) {
        throw WireMessageCodecException("Error decoding wire protocol response");
    }
}

WireProtocolHandler::WireProtocolHandler(const WireMessageCodec& codec, CukeEngine& engine) :
    codec(codec),
    engine(engine) {
}

std::string WireProtocolHandler::handle(const std::string& request) const {
    std::string response;
    // LOG request
    try {
        std::shared_ptr<const WireCommand> command = codec.decode(request);
        std::shared_ptr<const WireResponse> wireResponse = command->run(engine);
        response = codec.encode(*wireResponse);
    } catch (...) {
        response = "[\"fail\"]";
    }
    // LOG response
    return response;
}

} // namespace internal
} // namespace cucumber


================================================
FILE: src/connectors/wire/WireProtocolCommands.cpp
================================================
#include <cucumber-cpp/internal/connectors/wire/WireProtocolCommands.hpp>

namespace cucumber {
namespace internal {

ScenarioCommand::ScenarioCommand(const CukeEngine::tags_type& tags) :
    tags(tags) {
}

BeginScenarioCommand::BeginScenarioCommand(const CukeEngine::tags_type& tags) :
    ScenarioCommand(tags) {
}

std::shared_ptr<WireResponse> BeginScenarioCommand::run(CukeEngine& engine) const {
    engine.beginScenario(tags);
    return std::make_shared<SuccessResponse>();
}

EndScenarioCommand::EndScenarioCommand(const CukeEngine::tags_type& tags) :
    ScenarioCommand(tags) {
}

std::shared_ptr<WireResponse> EndScenarioCommand::run(CukeEngine& engine) const {
    engine.endScenario(tags);
    return std::make_shared<SuccessResponse>();
}

StepMatchesCommand::StepMatchesCommand(const std::string& stepName) :
    stepName(stepName) {
}

std::shared_ptr<WireResponse> StepMatchesCommand::run(CukeEngine& engine) const {
    std::vector<StepMatch> matchingSteps = engine.stepMatches(stepName);
    return std::make_shared<StepMatchesResponse>(matchingSteps);
}

InvokeCommand::InvokeCommand(
    const std::string& stepId,
    const CukeEngine::invoke_args_type& args,
    const CukeEngine::invoke_table_type& tableArg
) :
    stepId(stepId),
    args(args),
    tableArg(tableArg) {
}

std::shared_ptr<WireResponse> InvokeCommand::run(CukeEngine& engine) const {
    try {
        engine.invokeStep(stepId, args, tableArg);
        return std::make_shared<SuccessResponse>();
    } catch (const InvokeFailureException& e) {
        return std::make_shared<FailureResponse>(e.getMessage(), e.getExceptionType());
    } catch (const PendingStepException& e) {
        return std::make_shared<PendingResponse>(e.getMessage());
    } catch (...) {
        return std::make_shared<FailureResponse>();
    }
}

SnippetTextCommand::SnippetTextCommand(
    const std::string& keyword, const std::string& name, const std::string& multilineArgClass
) :
    keyword(keyword),
    name(name),
    multilineArgClass(multilineArgClass) {
}

std::shared_ptr<WireResponse> SnippetTextCommand::run(CukeEngine& engine) const {
    return std::make_shared<SnippetTextResponse>(
        engine.snippetText(keyword, name, multilineArgClass)
    );
}

std::shared_ptr<WireResponse> FailingCommand::run(CukeEngine& /*engine*/) const {
    return std::make_shared<FailureResponse>();
}

}
}


================================================
FILE: src/connectors/wire/WireServer.cpp
================================================
#include <cucumber-cpp/internal/connectors/wire/WireServer.hpp>
#include <filesystem>

namespace cucumber {
namespace internal {

SocketServer::SocketServer(const ProtocolHandler* protocolHandler) :
    protocolHandler(protocolHandler),
    ios() {
}

template<typename Protocol>
void SocketServer::doListen(
    asio::basic_socket_acceptor<Protocol>& acceptor, const typename Protocol::endpoint& endpoint
) {
    if (acceptor.is_open())
        throw std::system_error(asio::error::already_open);
    acceptor.open(endpoint.protocol());
    acceptor.set_option(typename Protocol::acceptor::reuse_address(true));
    acceptor.bind(endpoint);
    acceptor.listen(1);
}

template<typename Protocol>
void SocketServer::doAcceptOnce(asio::basic_socket_acceptor<Protocol>& acceptor) {
    typename Protocol::socket socket(ios);
    acceptor.accept(socket);
    typename Protocol::iostream stream(std::move(socket));
    processStream(stream);
}

void SocketServer::processStream(std::iostream& stream) {
    std::string request;
    while (getline(stream, request)) {
        stream << protocolHandler->handle(request) << std::endl << std::flush;
    }
}

TCPSocketServer::TCPSocketServer(const ProtocolHandler* protocolHandler) :
    SocketServer(protocolHandler),
    acceptor(ios) {
}

void TCPSocketServer::listen(const port_type port) {
    listen(asio::ip::tcp::endpoint(asio::ip::tcp::v4(), port));
}

void TCPSocketServer::listen(const asio::ip::tcp::endpoint endpoint) {
    doListen(acceptor, endpoint);
    acceptor.set_option(asio::ip::tcp::no_delay(true));
}

asio::ip::tcp::endpoint TCPSocketServer::listenEndpoint() const {
    return acceptor.local_endpoint();
}

void TCPSocketServer::acceptOnce() {
    doAcceptOnce(acceptor);
}

#if defined(ASIO_HAS_LOCAL_SOCKETS)
UnixSocketServer::UnixSocketServer(const ProtocolHandler* protocolHandler) :
    SocketServer(protocolHandler),
    acceptor(ios) {
}

void UnixSocketServer::listen(const std::string& unixPath) {
    if (std::filesystem::status(unixPath).type() == std::filesystem::file_type::socket)
        std::filesystem::remove(unixPath);

    doListen(acceptor, asio::local::stream_protocol::endpoint(unixPath));
}

asio::local::stream_protocol::endpoint UnixSocketServer::listenEndpoint() const {
    return acceptor.local_endpoint();
}

void UnixSocketServer::acceptOnce() {
    doAcceptOnce(acceptor);
}

UnixSocketServer::~UnixSocketServer() {
    if (!acceptor.is_open())
        return;
    std::string path = acceptor.local_endpoint().path();
    // NOTE: this will fail if this path got deleted manually or represents an abstract-namespace
    // socket
    std::filesystem::remove(path);
}
#endif

}
}


================================================
FILE: src/drivers/BoostDriver.cpp
================================================
#include <cucumber-cpp/internal/drivers/BoostDriver.hpp>

#include <sstream>

#include <boost/function.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/test/unit_test_log_formatter.hpp>
#include <mutex>
#include <boost/version.hpp>

using namespace ::boost::unit_test;
using ::boost::execution_exception;

namespace cucumber {
namespace internal {

namespace {

test_case* testCase = 0;
boost::function<void()> currentTestBody;

void exec_test_body() {
    if (currentTestBody) {
        currentTestBody();
    }
}

bool boost_test_init() {
    testCase = BOOST_TEST_CASE(&exec_test_body);
    framework::master_test_suite().add(testCase);

    return true;
}

// Freed by Boost's unit test framework on exit
static CukeBoostLogInterceptor* logInterceptor = 0;

}

class CukeBoostLogInterceptor : public ::boost::unit_test::unit_test_log_formatter {
public:
    const InvokeResult getResult() const;
    void reset();

    // Formatter
    void log_start(std::ostream&, counter_t /*test_cases_amount*/) override{};
    void log_finish(std::ostream&) override{};
    void log_build_info(std::ostream&, bool /*log_build_info*/) override{};

    void test_unit_start(std::ostream&, test_unit const& /*tu*/) override{};
    void test_unit_finish(std::ostream&, test_unit const& /*tu*/, unsigned long /*elapsed*/)
        override{};
    void test_unit_skipped(std::ostream&, test_unit const& /*tu*/) override{};

    void log_exception_start(std::ostream&, log_checkpoint_data const&, execution_exception const&)
        override{};
    void log_exception_finish(std::ostream&) override{};

    void log_entry_start(std::ostream&, log_entry_data const&, log_entry_types /*let*/) override{};
    void log_entry_value(std::ostream&, const_string value) override;
    void log_entry_value(std::ostream&, lazy_ostream const& value) override;
    void log_entry_finish(std::ostream&) override{};

    void entry_context_start(std::ostream&, log_level /*l*/) override {
    }
    void log_entry_context(std::ostream&, log_level /*l*/, const_string /*value*/) override {
    }
    void entry_context_finish(std::ostream&, log_level /*l*/) override {
    }

private:
    std::stringstream description;
};

void CukeBoostLogInterceptor::reset() {
    description.str("");
}

/*
 * Threshold level set to log_all_errors, so we should be fine logging everything
 */
void CukeBoostLogInterceptor::log_entry_value(std::ostream&, const_string value) {
    description << value;
}

void CukeBoostLogInterceptor::log_entry_value(std::ostream&, lazy_ostream const& value) {
    description << value;
}

const InvokeResult CukeBoostLogInterceptor::getResult() const {
    std::string d = description.str();
    if (d.empty()) {
        return InvokeResult::success();
    } else {
        return InvokeResult::failure(description.str());
    }
}

const InvokeResult BoostStep::invokeStepBody() {
    static std::once_flag initialized;
    std::call_once(initialized, BoostStep::initBoostTest);

    logInterceptor->reset();
    runWithMasterSuite();
    return logInterceptor->getResult();
}

void BoostStep::initBoostTest() {
    int argc = 1;
    char dummyArg[] = "dummy";
    char* argv[] = {dummyArg};
    framework::init(&boost_test_init, argc, argv);
    framework::finalize_setup_phase();

    logInterceptor = new CukeBoostLogInterceptor;
    ::boost::unit_test::unit_test_log.set_formatter(logInterceptor);
    ::boost::unit_test::unit_test_log.set_threshold_level(log_all_errors);
}

void BoostStep::runWithMasterSuite() {
    currentTestBody = std::bind(&BoostStep::body, this);

    ::boost::unit_test::framework::run(testCase, false);

    currentTestBody.clear();
}

}
}


================================================
FILE: src/drivers/GTestDriver.cpp
================================================
#include <cucumber-cpp/internal/drivers/GTestDriver.hpp>

#include <gtest/gtest.h>

namespace cucumber {
namespace internal {

bool GTestStep::initialized(false);

const InvokeResult GTestStep::invokeStepBody() {
    if (!initialized) {
        initGTest();
        initFlags();
    }
    try {
        body();
        return InvokeResult::success();
    } catch (const ::std::runtime_error& e) {
        // ::testing::GoogleTestFailureException inherits from ::std::runtime_error
        return InvokeResult::failure(e.what());
    }
}

void GTestStep::initGTest() {
    int fake_argc = 1;
    char* fake_argv[1];
    fake_argv[0] = (char*)"cucumber-cpp";
    ::testing::InitGoogleTest(&fake_argc, fake_argv);
    initialized = true;
}

void GTestStep::initFlags() {
    ::testing::GTEST_FLAG(throw_on_failure) = true;  // let cucumber-cpp drive
    ::testing::GTEST_FLAG(break_on_failure) = false; // turn off debugger breakpoints
    ::testing::GTEST_FLAG(catch_exceptions) = true;
}

}
}


================================================
FILE: src/drivers/GenericDriver.cpp
================================================
#include "cucumber-cpp/internal/drivers/GenericDriver.hpp"

namespace cucumber {
namespace internal {

const InvokeResult GenericStep::invokeStepBody() {
    // No try/catch block to throw the original exceptions to the testing framework
    body();
    return InvokeResult::success();
}

}
}


================================================
FILE: src/drivers/QtTestDriver.cpp
================================================
#include "cucumber-cpp/internal/drivers/QtTestDriver.hpp"

#include <QTest>
#include <QTemporaryFile>
#include <QTextStream>

namespace cucumber {
namespace internal {

/**
 * Wraps the QTemporaryFile for Windows.
 *
 * On Windows. the file can not be written as long as QTemporaryFile keeps it open.
 */
class TemporaryFileWrapper {
public:
    ~TemporaryFileWrapper() {
        QFile::remove(filename);
    }

    bool exists() const {
        return !filename.isEmpty();
    }

    QString name() const {
        return filename;
    }

    QString read() const {
        QFile file{filename};
        if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
            return QString();
        QTextStream in(&file);
        return in.readAll();
    }

private:
    const QString filename{getTmpFileName()};

    static QString getTmpFileName() {
        QTemporaryFile tempFile{};
        if (!tempFile.open()) {
            return {};
        }
        return tempFile.fileName() + ".txt";
    }
};

const InvokeResult QtTestStep::invokeStepBody() {
    const TemporaryFileWrapper file{};
    if (!file.exists()) {
        return InvokeResult::failure("Unable to open temporary file needed for this test");
    }

    QtTestObject testObject{this};
    const QStringList args{"test", "-o", file.name() + ",tap"};
    const int returnValue = QTest::qExec(&testObject, args);

    if (returnValue == 0) {
        return InvokeResult::success();
    } else {
        return InvokeResult::failure(file.read().toLocal8Bit());
    }
}

}
}


================================================
FILE: src/main.cpp
================================================
#include <cucumber-cpp/internal/CukeEngineImpl.hpp>
#include <cucumber-cpp/internal/CukeExport.hpp>
#include <cucumber-cpp/internal/connectors/wire/WireServer.hpp>
#include <cucumber-cpp/internal/connectors/wire/WireProtocol.hpp>
#include <iostream>
#include <memory>
#include <tclap/CmdLine.h>

namespace {

void acceptWireProtocol(
    const std::string& host, int port, const std::string& unixPath, bool verbose
) {
    using namespace ::cucumber::internal;
    CukeEngineImpl cukeEngine;
    JsonWireMessageCodec wireCodec;
    WireProtocolHandler protocolHandler(wireCodec, cukeEngine);
    std::unique_ptr<SocketServer> server;
#if defined(ASIO_HAS_LOCAL_SOCKETS)
    if (!unixPath.empty()) {
        UnixSocketServer* const unixServer = new UnixSocketServer(&protocolHandler);
        server.reset(unixServer);
        unixServer->listen(unixPath);
        if (verbose)
            std::clog << "Listening on socket " << unixServer->listenEndpoint() << std::endl;
    } else
#else
    // Prevent warning about unused parameter
    static_cast<void>(unixPath);
#endif
    {
        TCPSocketServer* const tcpServer = new TCPSocketServer(&protocolHandler);
        server.reset(tcpServer);
        tcpServer->listen(asio::ip::tcp::endpoint(asio::ip::make_address(host), port));
        if (verbose)
            std::clog << "Listening on " << tcpServer->listenEndpoint() << std::endl;
    }
    server->acceptOnce();
}

}

int CUCUMBER_CPP_EXPORT main(int argc, char** argv) {
    TCLAP::CmdLine cmd("C++ Cucumber wireserver", ' ', CUKE_VERSION);

    TCLAP::SwitchArg verboseArg("v", "verbose", "Verbose output", cmd, false);
    TCLAP::ValueArg<std::string> listenArg(
        "l", "listen", "Listening address of wireserver", false, "127.0.0.1", "string"
    );
    cmd.add(listenArg);
    TCLAP::ValueArg<int> portArg(
        "p",
        "port",
        "Listening port of wireserver, use '0' (zero) to select an ephemeral port",
        false,
        3902,
        "int"
    );
    cmd.add(portArg);

#if defined(ASIO_HAS_LOCAL_SOCKETS)
    TCLAP::ValueArg<std::string> unixArg(
        "u",
        "unix",
        "Listening unix socket of wireserver (disables listening on port)",
        false,
        "",
        "string"
    );
    cmd.add(unixArg);
#endif

    cmd.parse(argc, argv);

    std::string unixPath;
    std::string listenHost = listenArg.getValue();
    int port = portArg.getValue();
#if defined(ASIO_HAS_LOCAL_SOCKETS)
    unixPath = unixArg.getValue();
#endif

    bool verbose = verboseArg.getValue();

    try {
        acceptWireProtocol(listenHost, port, unixPath, verbose);
    } catch (std::exception& e) {
        std::cerr << e.what() << std::endl;
        exit(1);
    }
    return 0;
}


================================================
FILE: tests/CMakeLists.txt
================================================
find_package(GTest REQUIRED)

add_library(utils INTERFACE
    utils/HookRegistrationFixture.hpp
    utils/ContextManagerTestDouble.hpp
    utils/DriverTestRunner.hpp
    utils/CukeCommandsFixture.hpp
    utils/StepManagerTestDouble.hpp
)
target_include_directories(utils INTERFACE
    .
)

function(cuke_add_driver_test TEST_FILE)
    get_filename_component(TEST_NAME ${TEST_FILE} NAME)
    message(STATUS "Adding " ${TEST_NAME})
    add_executable(${TEST_NAME} ${TEST_FILE}.cpp)
    target_link_libraries(${TEST_NAME} PRIVATE cucumber-cpp-internal utils ${ARGN})
    add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME})
endfunction()

if(TARGET GTest::gmock_main)
    function(cuke_add_test TEST_FILE)
        get_filename_component(TEST_NAME ${TEST_FILE} NAME)
        message(STATUS "Adding " ${TEST_NAME})
        add_executable(${TEST_NAME} ${TEST_FILE}.cpp)
        target_link_libraries(${TEST_NAME} PRIVATE cucumber-cpp-internal utils ${ARGN} GTest::gmock_main)
        gtest_add_tests(${TEST_NAME} "" ${TEST_FILE}.cpp)
        # Run all tests in executable at once too. This ensures that the used fixtures get tested
        # properly too. Additionally gather the output in jUnit compatible output for CI.
        add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME} "--gtest_output=xml:TEST-${TEST_NAME}.xml")
    endfunction()

    # TODO Compile tests with the least possible code, not with the entire library
    cuke_add_test(integration/ContextHandlingTest)
    cuke_add_test(integration/HookRegistrationTest)
    cuke_add_test(integration/StepRegistrationTest)
    cuke_add_test(integration/TaggedHookRegistrationTest)
    if(NOT WIN32)
        cuke_add_test(integration/WireServerTest)
    endif()
    cuke_add_test(integration/WireProtocolTest)
    cuke_add_test(unit/BasicStepTest)
    cuke_add_test(unit/ContextManagerTest)
    cuke_add_test(unit/CukeCommandsTest)
    cuke_add_test(unit/RegexTest)
    cuke_add_test(unit/StepCallChainTest)
    cuke_add_test(unit/StepManagerTest)
    cuke_add_test(unit/TableTest)
    cuke_add_test(unit/TagTest)
endif()

if(TARGET GTest::gtest_main)
    cuke_add_driver_test(integration/drivers/GTestDriverTest GTest::gtest_main)
endif()

if(TARGET Boost::unit_test_framework)
    cuke_add_driver_test(integration/drivers/BoostDriverTest Boost::unit_test_framework)
endif()

if((TARGET Qt::Test)
    # FIXME: not including this in the test suite due to memory leak #190
    AND (NOT VALGRIND_TESTS)
    )
    cuke_add_driver_test(integration/drivers/QtTestDriverTest Qt::Test)
endif()

cuke_add_driver_test(integration/drivers/GenericDriverTest)


================================================
FILE: tests/integration/ContextHandlingTest.cpp
================================================
#include <gtest/gtest.h>

#include "utils/ContextManagerTestDouble.hpp"

using namespace std;
using namespace cucumber::internal;

class ContextHandlingTest : public ::testing::Test {
public:
    ContextHandlingTest() :
        contextManager() {
    }

protected:
    ContextManagerTestDouble contextManager;

private:
    void TearDown() override {
        contextManager.purgeContexts();
    }
};

struct Context1 {
    int i;
};
struct Context2 {};

TEST_F(ContextHandlingTest, contextsAreCreatedWhenNeeded) {
    ASSERT_EQ(0, contextManager.countContexts());
    ::cucumber::ScenarioScope<Context1> context1;
    ASSERT_EQ(1, contextManager.countContexts());
    ::cucumber::ScenarioScope<Context2> context2;
    ASSERT_EQ(2, contextManager.countContexts());
}

TEST_F(ContextHandlingTest, sameContextTypesShareTheSamePointer) {
    ::cucumber::ScenarioScope<Context1> context1_a;
    ::cucumber::ScenarioScope<Context1> context1_b;
    context1_a->i = 42;
    ASSERT_EQ(context1_a->i, context1_b->i);
}

TEST_F(ContextHandlingTest, theSameContextIsNotCreatedTwice) {
    ASSERT_EQ(0, contextManager.countContexts());
    ::cucumber::ScenarioScope<Context1> context1_a;
    ASSERT_EQ(1, contextManager.countContexts());
    ::cucumber::ScenarioScope<Context1> context1_b;
    ASSERT_EQ(1, contextManager.countContexts());
}

TEST_F(ContextHandlingTest, contextsArePurgedExplicitlyOnly) {
    ASSERT_EQ(0, contextManager.countContexts());
    ::cucumber::ScenarioScope<Context1> context1_a;
    ASSERT_EQ(1, contextManager.countContexts());
    ::cucumber::ScenarioScope<Context2>* context1_b = new ::cucumber::ScenarioScope<Context2>();
    ASSERT_EQ(2, contextManager.countContexts());
    delete context1_b;
    ASSERT_EQ(2, contextManager.countContexts());
    contextManager.purgeContexts();
    ASSERT_EQ(0, contextManager.countContexts());
}


================================================
FILE: tests/integration/HookRegistrationTest.cpp
================================================
#include <gtest/gtest.h>

#include "utils/HookRegistrationFixture.hpp"

#include <cucumber-cpp/internal/hook/HookMacros.hpp>

#define BEFORE_ALL_MARKER_1 "A"
#define BEFORE_ALL_MARKER_2 "B"
#define BEFORE_ALL_MARKER_3 "C"
BEFORE_ALL() {
    beforeAllHookCallMarker << BEFORE_ALL_MARKER_1;
}
BEFORE_ALL() {
    beforeAllHookCallMarker << BEFORE_ALL_MARKER_2;
}
BEFORE_ALL() {
    beforeAllHookCallMarker << BEFORE_ALL_MARKER_3;
}

#define BEFORE_MARKER_1 "D"
#define BEFORE_MARKER_2 "E"
#define BEFORE_MARKER_3 "F"
BEFORE() {
    beforeHookCallMarker << BEFORE_MARKER_1;
}
BEFORE() {
    beforeHookCallMarker << BEFORE_MARKER_2;
}
BEFORE() {
    beforeHookCallMarker << BEFORE_MARKER_3;
}

#define AROUND_STEP_MARKER_BEFORE_1 "G"
#define AROUND_STEP_MARKER_BEFORE_2 "H"
#define AROUND_STEP_MARKER_BEFORE_3 "I"
#define AROUND_STEP_MARKER_AFTER_3 "g"
#define AROUND_STEP_MARKER_AFTER_2 "h"
#define AROUND_STEP_MARKER_AFTER_1 "i"
AROUND_STEP() {
    beforeAroundStepHookCallMarker << AROUND_STEP_MARKER_BEFORE_1;
    globalStepHookCallMarker << AROUND_STEP_MARKER_BEFORE_1;
    step->call();
    globalStepHookCallMarker << AROUND_STEP_MARKER_AFTER_1;
    afterAroundStepHookCallMarker << AROUND_STEP_MARKER_AFTER_1;
}
AROUND_STEP() {
    beforeAroundStepHookCallMarker << AROUND_STEP_MARKER_BEFORE_2;
    globalStepHookCallMarker << AROUND_STEP_MARKER_BEFORE_2;
    step->call();
    globalStepHookCallMarker << AROUND_STEP_MARKER_AFTER_2;
    afterAroundStepHookCallMarker << AROUND_STEP_MARKER_AFTER_2;
}
AROUND_STEP() {
    beforeAroundStepHookCallMarker << AROUND_STEP_MARKER_BEFORE_3;
    globalStepHookCallMarker << AROUND_STEP_MARKER_BEFORE_3;
    step->call();
    globalStepHookCallMarker << AROUND_STEP_MARKER_AFTER_3;
    afterAroundStepHookCallMarker << AROUND_STEP_MARKER_AFTER_3;
}

#define AFTER_STEP_MARKER_1 "J"
#define AFTER_STEP_MARKER_2 "K"
#define AFTER_STEP_MARKER_3 "L"
AFTER_STEP() {
    afterStepHookCallMarker << AFTER_STEP_MARKER_1;
    globalStepHookCallMarker << AFTER_STEP_MARKER_1;
}
AFTER_STEP() {
    afterStepHookCallMarker << AFTER_STEP_MARKER_2;
    globalStepHookCallMarker << AFTER_STEP_MARKER_2;
}
AFTER_STEP() {
    afterStepHookCallMarker << AFTER_STEP_MARKER_3;
    globalStepHookCallMarker << AFTER_STEP_MARKER_3;
}

#define AFTER_MARKER_1 "M"
#define AFTER_MARKER_2 "N"
#define AFTER_MARKER_3 "O"
AFTER() {
    afterHookCallMarker << AFTER_MARKER_1;
}
AFTER() {
    afterHookCallMarker << AFTER_MARKER_2;
}
AFTER() {
    afterHookCallMarker << AFTER_MARKER_3;
}

#define AFTER_ALL_MARKER_1 "P"
#define AFTER_ALL_MARKER_2 "Q"
#define AFTER_ALL_MARKER_3 "R"
AFTER_ALL() {
    afterAllHookCallMarker << AFTER_ALL_MARKER_1;
}
AFTER_ALL() {
    afterAllHookCallMarker << AFTER_ALL_MARKER_2;
}
AFTER_ALL() {
    afterAllHookCallMarker << AFTER_ALL_MARKER_3;
}

#define CONTEXT_MARKER "X"
BEFORE() {
    cucumber::ScenarioScope<std::string> context;
    *context = CONTEXT_MARKER;
}
AFTER() {
    cucumber::ScenarioScope<std::string> context;
    contextContents = *context;
}

const std::string correctBeforeOrder(BEFORE_MARKER_1 BEFORE_MARKER_2 BEFORE_MARKER_3);
const std::string correctBeforeAroundStepOrder(
    AROUND_STEP_MARKER_BEFORE_1 AROUND_STEP_MARKER_BEFORE_2 AROUND_STEP_MARKER_BEFORE_3
);
const std::string correctAfterAroundStepOrder(AROUND_STEP_MARKER_AFTER_3 AROUND_STEP_MARKER_AFTER_2
                                                  AROUND_STEP_MARKER_AFTER_1);
const std::string correctAfterStepOrder(AFTER_STEP_MARKER_1 AFTER_STEP_MARKER_2 AFTER_STEP_MARKER_3
);
const std::string correctAfterOrder(AFTER_MARKER_1 AFTER_MARKER_2 AFTER_MARKER_3);
const std::string correctBeforeAllOrder(BEFORE_ALL_MARKER_1 BEFORE_ALL_MARKER_2 BEFORE_ALL_MARKER_3
);
const std::string correctAfterAllOrder(AFTER_ALL_MARKER_1 AFTER_ALL_MARKER_2 AFTER_ALL_MARKER_3);

TEST_F(HookRegistrationTest, hooksAreRegisteredByTheMacros) {
    beginScenario();
    EXPECT_EQ(correctBeforeOrder, sort(beforeHookOrder()));
    EXPECT_EQ(correctBeforeAroundStepOrder, sort(aroundStepHookOrder()));
    EXPECT_EQ(correctAfterStepOrder, sort(afterStepHookOrder()));
    EXPECT_EQ(correctAfterOrder, sort(afterHookOrder()));
    endScenario();
}

TEST_F(HookRegistrationTest, beforeHooksAreInvokedInAnyOrder) {
    EXPECT_EQ("", beforeHookCallMarker.str());
    beginScenario();
    EXPECT_EQ(correctBeforeOrder, sort(beforeHookCallMarker.str()));
    invokeStep();
    endScenario();
    EXPECT_EQ(correctBeforeOrder, sort(beforeHookCallMarker.str()));
}

TEST_F(HookRegistrationTest, aroundStepHooksAreInvokedInAnyOrderButNested) {
    beginScenario();
    EXPECT_EQ("", beforeAroundStepHookCallMarker.str());
    invokeStep();
    EXPECT_EQ(correctBeforeAroundStepOrder, sort(beforeAroundStepHookCallMarker.str()));
    EXPECT_EQ(correctAfterAroundStepOrder, sort(afterAroun
Download .txt
gitextract_c6fituri/

├── .clang-format
├── .github/
│   ├── ISSUE_TEMPLATE.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   └── workflows/
│       ├── format.yml
│       ├── linux-build.yml
│       ├── qt5.yml
│       ├── run-all.yml
│       ├── windows-build.yml
│       └── zizmor-analysis.yaml
├── .gitignore
├── CHANGELOG.md
├── CMakeLists.txt
├── CONTRIBUTING.md
├── Gemfile
├── LICENSE
├── README.md
├── cmake/
│   └── modules/
│       ├── FindAsio.cmake
│       ├── FindTCLAP.cmake
│       ├── FindValgrind.cmake
│       └── GitVersion.cmake
├── examples/
│   ├── CMakeLists.txt
│   ├── Calc/
│   │   ├── CMakeLists.txt
│   │   ├── README.txt
│   │   ├── features/
│   │   │   ├── addition.feature
│   │   │   ├── division.feature
│   │   │   └── step_definitions/
│   │   │       ├── BoostCalculatorSteps.cpp
│   │   │       ├── CalculatorSteps.cpp
│   │   │       ├── FuncArgsCalculatorSteps.cpp
│   │   │       ├── GTestCalculatorSteps.cpp
│   │   │       ├── QtTestCalculatorSteps.cpp
│   │   │       └── cucumber.wire
│   │   └── src/
│   │       ├── Calculator.cpp
│   │       └── Calculator.hpp
│   ├── CalcQt/
│   │   ├── CMakeLists.txt
│   │   ├── README.txt
│   │   ├── features/
│   │   │   ├── addition.feature
│   │   │   ├── behavior.feature
│   │   │   ├── initialization.feature
│   │   │   ├── step_definitions/
│   │   │   │   ├── BoostCalculatorQtSteps.cpp
│   │   │   │   ├── CalculatorQtSteps.cpp
│   │   │   │   ├── GTestCalculatorQtSteps.cpp
│   │   │   │   ├── QtTestCalculatorQtSteps.cpp
│   │   │   │   └── cucumber.wire
│   │   │   └── subtraction.feature
│   │   └── src/
│   │       ├── CalcQt.cpp
│   │       ├── Calculator.cpp
│   │       ├── Calculator.hpp
│   │       ├── CalculatorWidget.cpp
│   │       └── CalculatorWidget.hpp
│   └── FeatureShowcase/
│       ├── CMakeLists.txt
│       ├── README.txt
│       └── features/
│           ├── step_definitions/
│           │   ├── TableSteps.cpp
│           │   ├── TagSteps.cpp
│           │   └── cucumber.wire
│           ├── table.feature
│           └── tag.feature
├── include/
│   └── cucumber-cpp/
│       ├── autodetect.hpp
│       ├── defs.hpp
│       ├── generic.hpp
│       └── internal/
│           ├── ContextManager.hpp
│           ├── CukeCommands.hpp
│           ├── CukeEngine.hpp
│           ├── CukeEngineImpl.hpp
│           ├── Macros.hpp
│           ├── RegistrationMacros.hpp
│           ├── Scenario.hpp
│           ├── Table.hpp
│           ├── connectors/
│           │   └── wire/
│           │       ├── ProtocolHandler.hpp
│           │       ├── WireProtocol.hpp
│           │       ├── WireProtocolCommands.hpp
│           │       └── WireServer.hpp
│           ├── defs.hpp
│           ├── drivers/
│           │   ├── BoostDriver.hpp
│           │   ├── DriverSelector.hpp
│           │   ├── GTestDriver.hpp
│           │   ├── GenericDriver.hpp
│           │   └── QtTestDriver.hpp
│           ├── hook/
│           │   ├── HookMacros.hpp
│           │   ├── HookRegistrar.hpp
│           │   └── Tag.hpp
│           ├── step/
│           │   ├── StepMacros.hpp
│           │   └── StepManager.hpp
│           └── utils/
│               ├── IndexSequence.hpp
│               └── Regex.hpp
├── run-linux.sh
├── run-windows.ps1
├── src/
│   ├── CMakeLists.txt
│   ├── ContextManager.cpp
│   ├── CukeCommands.cpp
│   ├── CukeEngine.cpp
│   ├── CukeEngineImpl.cpp
│   ├── HookRegistrar.cpp
│   ├── Regex.cpp
│   ├── Scenario.cpp
│   ├── StepManager.cpp
│   ├── Table.cpp
│   ├── Tag.cpp
│   ├── connectors/
│   │   └── wire/
│   │       ├── WireProtocol.cpp
│   │       ├── WireProtocolCommands.cpp
│   │       └── WireServer.cpp
│   ├── drivers/
│   │   ├── BoostDriver.cpp
│   │   ├── GTestDriver.cpp
│   │   ├── GenericDriver.cpp
│   │   └── QtTestDriver.cpp
│   └── main.cpp
└── tests/
    ├── CMakeLists.txt
    ├── integration/
    │   ├── ContextHandlingTest.cpp
    │   ├── HookRegistrationTest.cpp
    │   ├── StepRegistrationTest.cpp
    │   ├── TaggedHookRegistrationTest.cpp
    │   ├── WireProtocolTest.cpp
    │   ├── WireServerTest.cpp
    │   └── drivers/
    │       ├── BoostDriverTest.cpp
    │       ├── GTestDriverTest.cpp
    │       ├── GenericDriverTest.cpp
    │       └── QtTestDriverTest.cpp
    ├── unit/
    │   ├── BasicStepTest.cpp
    │   ├── ContextManagerTest.cpp
    │   ├── CukeCommandsTest.cpp
    │   ├── RegexTest.cpp
    │   ├── StepCallChainTest.cpp
    │   ├── StepManagerTest.cpp
    │   ├── TableTest.cpp
    │   └── TagTest.cpp
    └── utils/
        ├── ContextManagerTestDouble.hpp
        ├── CukeCommandsFixture.hpp
        ├── DriverTestRunner.hpp
        ├── HookRegistrationFixture.hpp
        └── StepManagerTestDouble.hpp
Download .txt
SYMBOL INDEX (540 symbols across 70 files)

FILE: examples/Calc/features/step_definitions/CalculatorSteps.cpp
  type CalcCtx (line 7) | struct CalcCtx {

FILE: examples/Calc/features/step_definitions/FuncArgsCalculatorSteps.cpp
  type CalcCtx (line 8) | struct CalcCtx {

FILE: examples/Calc/src/Calculator.hpp
  class Calculator (line 5) | class Calculator {

FILE: examples/CalcQt/features/step_definitions/CalculatorQtSteps.cpp
  class CalculatorCtx (line 5) | class CalculatorCtx {
    method CalculatorCtx (line 7) | CalculatorCtx() {

FILE: examples/CalcQt/src/CalcQt.cpp
  function main (line 6) | int main(int argc, char* argv[]) {

FILE: examples/CalcQt/src/Calculator.cpp
  function QString (line 5) | QString Calculator::calculate(const QString& expression) const {

FILE: examples/CalcQt/src/Calculator.hpp
  class Calculator (line 5) | class Calculator : public QObject {

FILE: examples/CalcQt/src/CalculatorWidget.hpp
  class QLabel (line 3) | class QLabel
  class QPushButton (line 4) | class QPushButton
  class Calculator (line 5) | class Calculator
  class CalculatorWidget (line 10) | class CalculatorWidget : public QWidget {

FILE: examples/FeatureShowcase/features/step_definitions/TableSteps.cpp
  class ActiveActors (line 9) | class ActiveActors {
    method addActor (line 20) | void addActor(const actor_name_type name, const actor_year_type year) {
    method retireActor (line 24) | void retireActor(const actor_name_type name) {
    method actor_name_type (line 28) | actor_name_type getOldestActor() {

FILE: examples/FeatureShowcase/features/step_definitions/TagSteps.cpp
  function BEFORE_ALL (line 10) | BEFORE_ALL() {
  function AFTER_ALL (line 14) | AFTER_ALL() {
  function BEFORE (line 18) | BEFORE() {

FILE: include/cucumber-cpp/internal/ContextManager.hpp
  type cucumber (line 10) | namespace cucumber {
    type internal (line 12) | namespace internal {
      function ContextManager (line 16) | class CUCUMBER_CPP_EXPORT ContextManager {
    class ScenarioScope (line 36) | class ScenarioScope {
    function T (line 62) | T& ScenarioScope<T>::operator*() {
    function T (line 67) | T* ScenarioScope<T>::operator->() {
    function T (line 72) | T* ScenarioScope<T>::get() {

FILE: include/cucumber-cpp/internal/CukeCommands.hpp
  type cucumber (line 16) | namespace cucumber {
    type internal (line 17) | namespace internal {
      function CukeCommands (line 22) | class CUCUMBER_CPP_EXPORT CukeCommands {

FILE: include/cucumber-cpp/internal/CukeEngine.hpp
  type cucumber (line 10) | namespace cucumber {
    type internal (line 11) | namespace internal {
      function StepMatchArg (line 13) | class CUCUMBER_CPP_EXPORT StepMatchArg {
      function StepMatch (line 19) | class CUCUMBER_CPP_EXPORT StepMatch {
      function InvokeException (line 27) | class CUCUMBER_CPP_EXPORT InvokeException {
      function InvokeFailureException (line 40) | class CUCUMBER_CPP_EXPORT InvokeFailureException : public InvokeExce...
      function PendingStepException (line 51) | class CUCUMBER_CPP_EXPORT PendingStepException : public InvokeExcept...
      class CukeEngine (line 63) | class CukeEngine {
        method CUCUMBER_CPP_EXPORT (line 106) | CUCUMBER_CPP_EXPORT virtual ~CukeEngine() = default;

FILE: include/cucumber-cpp/internal/CukeEngineImpl.hpp
  type cucumber (line 8) | namespace cucumber {
    type internal (line 9) | namespace internal {
      function CukeEngineImpl (line 17) | class CUCUMBER_CPP_EXPORT CukeEngineImpl : public CukeEngine {

FILE: include/cucumber-cpp/internal/Scenario.hpp
  type cucumber (line 6) | namespace cucumber {
    type internal (line 7) | namespace internal {
      class Scenario (line 9) | class Scenario {

FILE: include/cucumber-cpp/internal/Table.hpp
  type cucumber (line 11) | namespace cucumber {
    type internal (line 12) | namespace internal {
      function Table (line 14) | class CUCUMBER_CPP_EXPORT Table {

FILE: include/cucumber-cpp/internal/connectors/wire/ProtocolHandler.hpp
  type cucumber (line 6) | namespace cucumber {
    type internal (line 7) | namespace internal {
      class ProtocolHandler (line 12) | class ProtocolHandler {

FILE: include/cucumber-cpp/internal/connectors/wire/WireProtocol.hpp
  type cucumber (line 10) | namespace cucumber {
    type internal (line 11) | namespace internal {
      class WireResponseVisitor (line 17) | class WireResponseVisitor
      class CUCUMBER_CPP_EXPORT (line 19) | class CUCUMBER_CPP_EXPORT
    function SuccessResponse (line 28) | class CUCUMBER_CPP_EXPORT SuccessResponse : public WireResponse {
    function FailureResponse (line 33) | class CUCUMBER_CPP_EXPORT FailureResponse : public WireResponse {
    function PendingResponse (line 46) | class CUCUMBER_CPP_EXPORT PendingResponse : public WireResponse {
    function StepMatchesResponse (line 58) | class CUCUMBER_CPP_EXPORT StepMatchesResponse : public WireResponse {
    function SnippetTextResponse (line 69) | class CUCUMBER_CPP_EXPORT SnippetTextResponse : public WireResponse {
    function WireResponseVisitor (line 81) | class CUCUMBER_CPP_EXPORT WireResponseVisitor {
    function WireCommand (line 95) | class CUCUMBER_CPP_EXPORT WireCommand {
    class CUCUMBER_CPP_EXPORT (line 109) | class CUCUMBER_CPP_EXPORT
    function WireMessageCodec (line 126) | class CUCUMBER_CPP_EXPORT WireMessageCodec {
    function JsonWireMessageCodec (line 154) | class CUCUMBER_CPP_EXPORT JsonWireMessageCodec : public WireMessageCod...
    function WireProtocolHandler (line 165) | class CUCUMBER_CPP_EXPORT WireProtocolHandler : public ProtocolHandler {

FILE: include/cucumber-cpp/internal/connectors/wire/WireProtocolCommands.hpp
  type cucumber (line 7) | namespace cucumber {
    type internal (line 8) | namespace internal {
      class ScenarioCommand (line 10) | class ScenarioCommand : public WireCommand {
      class BeginScenarioCommand (line 17) | class BeginScenarioCommand : public ScenarioCommand {
      class EndScenarioCommand (line 24) | class EndScenarioCommand : public ScenarioCommand {
      class StepMatchesCommand (line 31) | class StepMatchesCommand : public WireCommand {
      class InvokeCommand (line 41) | class InvokeCommand : public WireCommand {
      class SnippetTextCommand (line 57) | class SnippetTextCommand : public WireCommand {
      class FailingCommand (line 69) | class FailingCommand : public WireCommand {

FILE: include/cucumber-cpp/internal/connectors/wire/WireServer.hpp
  type cucumber (line 11) | namespace cucumber {
    type internal (line 12) | namespace internal {
      function SocketServer (line 17) | class CUCUMBER_CPP_EXPORT SocketServer {
      function TCPSocketServer (line 46) | class CUCUMBER_CPP_EXPORT TCPSocketServer : public SocketServer {
      function UnixSocketServer (line 87) | class CUCUMBER_CPP_EXPORT UnixSocketServer : public SocketServer {

FILE: include/cucumber-cpp/internal/drivers/BoostDriver.hpp
  type cucumber (line 7) | namespace cucumber {
    type internal (line 8) | namespace internal {
      class CukeBoostLogInterceptor (line 10) | class CukeBoostLogInterceptor
      function BoostStep (line 12) | class CUCUMBER_CPP_EXPORT BoostStep : public BasicStep {

FILE: include/cucumber-cpp/internal/drivers/GTestDriver.hpp
  type cucumber (line 9) | namespace cucumber {
    type internal (line 10) | namespace internal {
      function GTestStep (line 12) | class CUCUMBER_CPP_EXPORT GTestStep : public BasicStep {

FILE: include/cucumber-cpp/internal/drivers/GenericDriver.hpp
  type cucumber (line 7) | namespace cucumber {
    type internal (line 8) | namespace internal {
      function GenericStep (line 10) | class CUCUMBER_CPP_EXPORT GenericStep : public BasicStep {

FILE: include/cucumber-cpp/internal/drivers/QtTestDriver.hpp
  type cucumber (line 8) | namespace cucumber {
    type internal (line 9) | namespace internal {
      function QtTestStep (line 11) | class CUCUMBER_CPP_EXPORT QtTestStep : public BasicStep {
      class QtTestObject (line 25) | class QtTestObject : public QObject {
        method Q_OBJECT (line 26) | Q_OBJECT
        method test (line 36) | void test() const {

FILE: include/cucumber-cpp/internal/hook/HookRegistrar.hpp
  type cucumber (line 12) | namespace cucumber {
    type internal (line 13) | namespace internal {
      function CallableStep (line 15) | class CUCUMBER_CPP_EXPORT CallableStep {
      function Hook (line 20) | class CUCUMBER_CPP_EXPORT Hook {
      class CUCUMBER_CPP_EXPORT (line 41) | class CUCUMBER_CPP_EXPORT
      function AroundStepHook (line 43) | class CUCUMBER_CPP_EXPORT AroundStepHook : public Hook {
      class CUCUMBER_CPP_EXPORT (line 52) | class CUCUMBER_CPP_EXPORT
      class CUCUMBER_CPP_EXPORT (line 54) | class CUCUMBER_CPP_EXPORT
      function UnconditionalHook (line 56) | class CUCUMBER_CPP_EXPORT UnconditionalHook : public Hook {
      class CUCUMBER_CPP_EXPORT (line 61) | class CUCUMBER_CPP_EXPORT
      class CUCUMBER_CPP_EXPORT (line 63) | class CUCUMBER_CPP_EXPORT
      function HookRegistrar (line 65) | class CUCUMBER_CPP_EXPORT HookRegistrar {
      function StepCallChain (line 106) | class CUCUMBER_CPP_EXPORT StepCallChain {
      function CallableStepChain (line 129) | class CUCUMBER_CPP_EXPORT CallableStepChain : public CallableStep {
      function registerBeforeHook (line 139) | static int registerBeforeHook(const std::string& csvTagNotation) {
      function registerAroundStepHook (line 147) | static int registerAroundStepHook(const std::string& csvTagNotation) {
      function registerAfterStepHook (line 155) | static int registerAfterStepHook(const std::string& csvTagNotation) {
      function registerAfterHook (line 163) | static int registerAfterHook(const std::string& csvTagNotation) {
      function registerBeforeAllHook (line 171) | static int registerBeforeAllHook() {
      function registerAfterAllHook (line 177) | static int registerAfterAllHook() {

FILE: include/cucumber-cpp/internal/hook/Tag.hpp
  type cucumber (line 10) | namespace cucumber {
    type internal (line 11) | namespace internal {
      function TagExpression (line 13) | class CUCUMBER_CPP_EXPORT TagExpression {
      function OrTagExpression (line 21) | class CUCUMBER_CPP_EXPORT OrTagExpression : public TagExpression {
      function AndTagExpression (line 34) | class CUCUMBER_CPP_EXPORT AndTagExpression : public TagExpression {

FILE: include/cucumber-cpp/internal/step/StepManager.hpp
  type cucumber (line 17) | namespace cucumber {
    type internal (line 18) | namespace internal {
      class StepInfo (line 22) | class StepInfo
      function SingleStepMatch (line 24) | class CUCUMBER_CPP_EXPORT SingleStepMatch {
      function MatchResult (line 34) | class CUCUMBER_CPP_EXPORT MatchResult {
      function InvokeArgs (line 47) | class CUCUMBER_CPP_EXPORT InvokeArgs {
      type InvokeResultType (line 67) | enum InvokeResultType {
      function InvokeResult (line 73) | class CUCUMBER_CPP_EXPORT InvokeResult {
      class CUCUMBER_CPP_EXPORT (line 96) | class CUCUMBER_CPP_EXPORT
      function BasicStep (line 114) | class CUCUMBER_CPP_EXPORT BasicStep {
      class StepInvoker (line 154) | class StepInvoker : public StepInfo {
      function StepManager (line 161) | class CUCUMBER_CPP_EXPORT StepManager {
      function toSourceString (line 178) | static inline std::string toSourceString(const char* filePath, const...
      function registerStep (line 193) | static int registerStep(const std::string& stepMatcher, const char* ...
      function T (line 200) | T fromString(const std::string& s) {
      function fromString (line 211) | inline std::string fromString(const std::string& s) {
      function toString (line 216) | std::string toString(T arg) {
      function T (line 223) | T InvokeArgs::getInvokeArg(size_type i) const {
      function T (line 231) | const T BasicStep::getInvokeArg() {
      function InvokeResult (line 241) | InvokeResult StepInvoker<T>::invokeStep(const InvokeArgs* pArgs) con...

FILE: include/cucumber-cpp/internal/utils/IndexSequence.hpp
  type cucumber (line 6) | namespace cucumber {
    type internal (line 7) | namespace internal {

FILE: include/cucumber-cpp/internal/utils/Regex.hpp
  type cucumber (line 9) | namespace cucumber {
    type internal (line 10) | namespace internal {
      type RegexSubmatch (line 12) | struct RegexSubmatch {
      class RegexMatch (line 17) | class RegexMatch {
      class FindRegexMatch (line 31) | class FindRegexMatch : public RegexMatch {
      class FindAllRegexMatch (line 36) | class FindAllRegexMatch : public RegexMatch {
      class Regex (line 41) | class Regex {

FILE: src/ContextManager.cpp
  type cucumber (line 3) | namespace cucumber {
    type internal (line 4) | namespace internal {

FILE: src/CukeCommands.cpp
  type cucumber (line 6) | namespace cucumber {
    type internal (line 7) | namespace internal {
      function MatchResult (line 70) | MatchResult CukeCommands::stepMatches(const std::string description)...
      function InvokeResult (line 74) | InvokeResult CukeCommands::invoke(step_id_type id, const InvokeArgs*...

FILE: src/CukeEngine.cpp
  type cucumber (line 3) | namespace cucumber {
    type internal (line 4) | namespace internal {

FILE: src/CukeEngineImpl.cpp
  type cucumber (line 3) | namespace cucumber {
    type internal (line 4) | namespace internal {
      function convertId (line 8) | std::string convertId(step_id_type id) {
      function step_id_type (line 14) | step_id_type convertId(const std::string& stringid) {

FILE: src/HookRegistrar.cpp
  type cucumber (line 4) | namespace cucumber {
    type internal (line 5) | namespace internal {
      function InvokeResult (line 61) | InvokeResult HookRegistrar::execStepChain(
      function InvokeResult (line 140) | InvokeResult StepCallChain::exec() {

FILE: src/Regex.cpp
  type cucumber (line 5) | namespace cucumber {
    type internal (line 6) | namespace internal {
      function isUtf8CodeUnitStartOfCodepoint (line 30) | bool isUtf8CodeUnitStartOfCodepoint(unsigned int i) {
      function utf8CodepointOffset (line 34) | std::ptrdiff_t utf8CodepointOffset(

FILE: src/Scenario.cpp
  type cucumber (line 3) | namespace cucumber {
    type internal (line 4) | namespace internal {

FILE: src/StepManager.cpp
  type cucumber (line 3) | namespace cucumber {
    type internal (line 4) | namespace internal {
      function SingleStepMatch (line 13) | SingleStepMatch StepInfo::matches(const std::string& stepDescription...
      function Table (line 43) | const Table& InvokeArgs::getTableArg() const {
      function Table (line 47) | Table& InvokeArgs::getVariableTableArg() {
      function InvokeResult (line 67) | InvokeResult& InvokeResult::operator=(const InvokeResult& rhs) {
      function InvokeResult (line 73) | InvokeResult InvokeResult::success() {
      function InvokeResult (line 77) | InvokeResult InvokeResult::failure(const char* description) {
      function InvokeResult (line 81) | InvokeResult InvokeResult::failure(const std::string& description) {
      function InvokeResult (line 85) | InvokeResult InvokeResult::pending(const char* description) {
      function InvokeResultType (line 97) | InvokeResultType InvokeResult::getType() const {
      function step_id_type (line 105) | step_id_type StepManager::addStep(std::shared_ptr<StepInfo> stepInfo) {
      function MatchResult (line 109) | MatchResult StepManager::stepMatches(const std::string& stepDescript...
      function StepInfo (line 121) | const StepInfo* StepManager::getStep(step_id_type id) {
      function InvokeResult (line 138) | InvokeResult BasicStep::invoke(const InvokeArgs* pArgs) {
      function InvokeArgs (line 169) | const InvokeArgs* BasicStep::getArgs() {

FILE: src/Table.cpp
  type cucumber (line 3) | namespace cucumber {
    type internal (line 4) | namespace internal {

FILE: src/Tag.cpp
  type cucumber (line 4) | namespace cucumber {
    type internal (line 5) | namespace internal {
      function Regex (line 7) | Regex& AndTagExpression::csvTagNotationRegex() {
      function Regex (line 33) | Regex& OrTagExpression::csvTagNotationRegex() {

FILE: src/connectors/wire/WireProtocol.cpp
  type cucumber (line 12) | namespace cucumber {
    type internal (line 13) | namespace internal {
      function getScenarioTags (line 83) | CukeEngine::tags_type getScenarioTags(const json& jsonArgs) {
      function BeginScenarioDecoder (line 94) | std::shared_ptr<WireCommand> BeginScenarioDecoder(const json& jsonAr...
      function EndScenarioDecoder (line 98) | std::shared_ptr<WireCommand> EndScenarioDecoder(const json& jsonArgs) {
      function StepMatchesDecoder (line 102) | std::shared_ptr<WireCommand> StepMatchesDecoder(const json& jsonArgs) {
      function fillTableArg (line 107) | void fillTableArg(const json& jsonTableArg, CukeEngine::invoke_table...
      function fillInvokeArgs (line 127) | void fillInvokeArgs(
      function InvokeDecoder (line 142) | std::shared_ptr<WireCommand> InvokeDecoder(const json& jsonArgs) {
      function SnippetTextDecoder (line 152) | std::shared_ptr<WireCommand> SnippetTextDecoder(const json& jsonArgs) {
      class WireResponseEncoder (line 190) | class WireResponseEncoder : public WireResponseVisitor {
        method success (line 194) | void success(const json* detail = nullptr) {
        method fail (line 198) | void fail(const json* detail = nullptr) {
        method output (line 202) | void output(const std::string& responseType, const json* detail = ...
        method encode (line 211) | std::string encode(const WireResponse& response) {
        method visit (line 217) | void visit(const SuccessResponse& /*response*/) override {
        method visit (line 221) | void visit(const FailureResponse& response) override {
        method visit (line 237) | void visit(const PendingResponse& response) override {
        method visit (line 242) | void visit(const StepMatchesResponse& response) override {
        method visit (line 267) | void visit(const SnippetTextResponse& response) override {

FILE: src/connectors/wire/WireProtocolCommands.cpp
  type cucumber (line 3) | namespace cucumber {
    type internal (line 4) | namespace internal {

FILE: src/connectors/wire/WireServer.cpp
  type cucumber (line 4) | namespace cucumber {
    type internal (line 5) | namespace internal {

FILE: src/drivers/BoostDriver.cpp
  type cucumber (line 14) | namespace cucumber {
    type internal (line 15) | namespace internal {
      function exec_test_body (line 22) | void exec_test_body() {
      function boost_test_init (line 28) | bool boost_test_init() {
      class CukeBoostLogInterceptor (line 40) | class CukeBoostLogInterceptor : public ::boost::unit_test::unit_test...
        method entry_context_start (line 64) | void entry_context_start(std::ostream&, log_level /*l*/) override {
        method log_entry_context (line 66) | void log_entry_context(std::ostream&, log_level /*l*/, const_strin...
        method entry_context_finish (line 68) | void entry_context_finish(std::ostream&, log_level /*l*/) override {
      function InvokeResult (line 90) | const InvokeResult CukeBoostLogInterceptor::getResult() const {
      function InvokeResult (line 99) | const InvokeResult BoostStep::invokeStepBody() {

FILE: src/drivers/GTestDriver.cpp
  type cucumber (line 5) | namespace cucumber {
    type internal (line 6) | namespace internal {
      function InvokeResult (line 10) | const InvokeResult GTestStep::invokeStepBody() {

FILE: src/drivers/GenericDriver.cpp
  type cucumber (line 3) | namespace cucumber {
    type internal (line 4) | namespace internal {
      function InvokeResult (line 6) | const InvokeResult GenericStep::invokeStepBody() {

FILE: src/drivers/QtTestDriver.cpp
  type cucumber (line 7) | namespace cucumber {
    type internal (line 8) | namespace internal {
      class TemporaryFileWrapper (line 15) | class TemporaryFileWrapper {
        method exists (line 21) | bool exists() const {
        method QString (line 25) | QString name() const {
        method QString (line 29) | QString read() const {
        method QString (line 40) | static QString getTmpFileName() {
      function InvokeResult (line 49) | const InvokeResult QtTestStep::invokeStepBody() {

FILE: src/main.cpp
  function acceptWireProtocol (line 11) | void acceptWireProtocol(

FILE: tests/integration/ContextHandlingTest.cpp
  class ContextHandlingTest (line 8) | class ContextHandlingTest : public ::testing::Test {
    method ContextHandlingTest (line 10) | ContextHandlingTest() :
    method TearDown (line 18) | void TearDown() override {
  type Context1 (line 23) | struct Context1 {
  type Context2 (line 26) | struct Context2 {}
  function TEST_F (line 28) | TEST_F(ContextHandlingTest, contextsAreCreatedWhenNeeded) {
  function TEST_F (line 36) | TEST_F(ContextHandlingTest, sameContextTypesShareTheSamePointer) {
  function TEST_F (line 43) | TEST_F(ContextHandlingTest, theSameContextIsNotCreatedTwice) {
  function TEST_F (line 51) | TEST_F(ContextHandlingTest, contextsArePurgedExplicitlyOnly) {

FILE: tests/integration/HookRegistrationTest.cpp
  function BEFORE_ALL (line 10) | BEFORE_ALL() {
  function BEFORE_ALL (line 13) | BEFORE_ALL() {
  function BEFORE_ALL (line 16) | BEFORE_ALL() {
  function BEFORE (line 23) | BEFORE() {
  function BEFORE (line 26) | BEFORE() {
  function BEFORE (line 29) | BEFORE() {
  function AROUND_STEP (line 39) | AROUND_STEP() {
  function AROUND_STEP (line 46) | AROUND_STEP() {
  function AROUND_STEP (line 53) | AROUND_STEP() {
  function AFTER_STEP (line 64) | AFTER_STEP() {
  function AFTER_STEP (line 68) | AFTER_STEP() {
  function AFTER_STEP (line 72) | AFTER_STEP() {
  function AFTER (line 80) | AFTER() {
  function AFTER (line 83) | AFTER() {
  function AFTER (line 86) | AFTER() {
  function AFTER_ALL (line 93) | AFTER_ALL() {
  function AFTER_ALL (line 96) | AFTER_ALL() {
  function AFTER_ALL (line 99) | AFTER_ALL() {
  function BEFORE (line 104) | BEFORE() {
  function AFTER (line 108) | AFTER() {
  function TEST_F (line 126) | TEST_F(HookRegistrationTest, hooksAreRegisteredByTheMacros) {
  function TEST_F (line 135) | TEST_F(HookRegistrationTest, beforeHooksAreInvokedInAnyOrder) {
  function TEST_F (line 144) | TEST_F(HookRegistrationTest, aroundStepHooksAreInvokedInAnyOrderButNeste...
  function TEST_F (line 155) | TEST_F(HookRegistrationTest, afterStepHooksAreInvokedInAnyOrder) {
  function TEST_F (line 164) | TEST_F(HookRegistrationTest, afterHooksAreInvokedInAnyOrder) {
  function TEST_F (line 173) | TEST_F(HookRegistrationTest, contextIsAccessibleInAfterHooks) {
  function TEST_F (line 179) | TEST_F(HookRegistrationTest, afterStepHooksAreInvokedAfterAroundStepHook...
  function TEST_F (line 191) | TEST_F(HookRegistrationTest, beforeAllHooksAreInvokedInAnyOrderDuringFir...
  function TEST_F (line 206) | TEST_F(HookRegistrationTest, beforeAllHooksAreNotInvokedIfNoScenariosRun) {
  function TEST_F (line 217) | TEST_F(HookRegistrationTest, afterAllHooksAreNotInvokedIfNoScenariosRun) {
  function TEST_F (line 228) | TEST_F(HookRegistrationTest, afterAllHooksAreInvokedOnceDuringDestructio...

FILE: tests/integration/StepRegistrationTest.cpp
  class ManualStep (line 11) | class ManualStep : public GenericStep {
  function TEST (line 21) | TEST(StepRegistrationTest, manualRegistration) {
  function GIVEN (line 32) | GIVEN(GIVEN_MATCHER) {
  function WHEN (line 34) | WHEN(WHEN_MATCHER) {
  function THEN (line 36) | THEN(THEN_MATCHER) {
  function TEST (line 39) | TEST(StepRegistrationTest, macroRegistration) {

FILE: tests/integration/TaggedHookRegistrationTest.cpp
  function TEST_F (line 49) | TEST_F(HookRegistrationTest, noTaggedHooksAreInvokedIfNoScenarioTag) {
  function TEST_F (line 59) | TEST_F(HookRegistrationTest, orTagsAreEnforced) {
  function TEST_F (line 70) | TEST_F(HookRegistrationTest, andTagsAreEnforced) {

FILE: tests/integration/WireProtocolTest.cpp
  class MockCukeEngine (line 12) | class MockCukeEngine : public CukeEngine {
  class WireMessageCodecTest (line 34) | class WireMessageCodecTest : public Test {
    method WireCommand (line 38) | WireCommand& decode(const char* jsonStr) {
    method encode (line 43) | std::string encode(const WireResponse& response) const {
  function TEST_F (line 55) | TEST_F(WireMessageCodecTest, decodesUnknownOrMalformedMessage) {
  function TEST_F (line 65) | TEST_F(WireMessageCodecTest, handlesStepMatchesMessage) {
  function TEST_F (line 79) | TEST_F(WireMessageCodecTest, handlesBeginScenarioMessageWithoutArgument) {
  function TEST_F (line 89) | TEST_F(WireMessageCodecTest, handlesBeginScenarioMessageWithTagsArgument) {
  function TEST_F (line 101) | TEST_F(WireMessageCodecTest, handlesBeginScenarioMessageWithNullArgument) {
  function TEST_F (line 112) | TEST_F(WireMessageCodecTest, handlesInvokeMessageWithNoArgs) {
  function TEST_F (line 125) | TEST_F(WireMessageCodecTest, handlesInvokeMessageWithoutTableArgs) {
  function TEST_F (line 138) | TEST_F(WireMessageCodecTest, handlesInvokeMessageWithTableArgs) {
  function TEST_F (line 172) | TEST_F(WireMessageCodecTest, handlesInvokeMessageWithNullArg) {
  function TEST_F (line 185) | TEST_F(WireMessageCodecTest, handlesEndScenarioMessageWithoutArgument) {
  function TEST_F (line 195) | TEST_F(WireMessageCodecTest, handlesEndScenarioMessageWithNullArgument) {
  function TEST_F (line 206) | TEST_F(WireMessageCodecTest, handlesEndScenarioMessageWithTagsArgument) {
  function TEST_F (line 222) | TEST_F(WireMessageCodecTest, handlesSnippetTextMessage) {
  function TEST_F (line 240) | TEST_F(WireMessageCodecTest, handlesSuccessResponse) {
  function TEST_F (line 245) | TEST_F(WireMessageCodecTest, handlesSimpleFailureResponse) {
  function TEST_F (line 250) | TEST_F(WireMessageCodecTest, handlesDetailedFailureResponse) {
  function TEST_F (line 261) | TEST_F(WireMessageCodecTest, handlesPendingResponse) {
  function TEST_F (line 266) | TEST_F(WireMessageCodecTest, handlesEmptyStepMatchesResponse) {
  function TEST_F (line 271) | TEST_F(WireMessageCodecTest, handlesStepMatchesResponse) {
  function TEST_F (line 305) | TEST_F(WireMessageCodecTest, handlesSnippetTextResponse) {
  function TEST_F (line 310) | TEST_F(WireMessageCodecTest, encodesResponseUsingRawUtf8) {
  function TEST (line 346) | TEST(WireCommandsTest, succesfulInvokeReturnsSuccess) {
  function TEST (line 357) | TEST(WireCommandsTest, throwingFailureInvokeReturnsFailure) {
  function TEST (line 371) | TEST(WireCommandsTest, throwingPendingStepReturnsPending) {
  function TEST (line 383) | TEST(WireCommandsTest, throwingAnythingInvokeReturnsFailure) {

FILE: tests/integration/WireServerTest.cpp
  class MockProtocolHandler (line 51) | class MockProtocolHandler : public ProtocolHandler {
  class SocketServerTest (line 56) | class SocketServerTest : public Test {
    method SetUp (line 62) | void SetUp() override {
    method TearDown (line 67) | void TearDown() override {
  class TCPSocketServerTest (line 76) | class TCPSocketServerTest : public SocketServerTest {
    method SocketServer (line 80) | SocketServer* createListeningServer() override {
    method destroyListeningServer (line 86) | void destroyListeningServer() override {
  function TEST_F (line 91) | TEST_F(TCPSocketServerTest, exitsOnFirstConnectionClosed) {
  function TEST_F (line 104) | TEST_F(TCPSocketServerTest, moreThanOneClientCanConnect) {
  function TEST_F (line 116) | TEST_F(TCPSocketServerTest, receiveAndSendsSingleLineMassages) {
  class TCPSocketServerLocalhostTest (line 138) | class TCPSocketServerLocalhostTest : public SocketServerTest {
    method SocketServer (line 142) | SocketServer* createListeningServer() override {
    method destroyListeningServer (line 148) | void destroyListeningServer() override {
  function TEST_F (line 153) | TEST_F(TCPSocketServerLocalhostTest, listensOnLocalhost) {
  class UnixSocketServerTest (line 167) | class UnixSocketServerTest : public SocketServerTest {
    method SocketServer (line 171) | SocketServer* createListeningServer() override {
    method destroyListeningServer (line 178) | void destroyListeningServer() override {
    method randomString (line 187) | std::string randomString() {
  function TEST_F (line 202) | TEST_F(UnixSocketServerTest, fullLifecycle) {

FILE: tests/integration/drivers/BoostDriverTest.cpp
  function THEN (line 9) | THEN(SUCCEED_MATCHER) {
  function THEN (line 14) | THEN(FAIL_MATCHER) {
  function THEN (line 19) | THEN(PENDING_MATCHER_1) {
  function THEN (line 23) | THEN(PENDING_MATCHER_2) {
  type boost (line 29) | namespace boost {
    type unit_test (line 30) | namespace unit_test {
      type framework (line 31) | namespace framework {
        function is_initialized (line 32) | bool is_initialized() {
  class BoostStepDouble (line 39) | class BoostStepDouble : public BoostStep {
    method InvokeResult (line 41) | const InvokeResult invokeStepBody() override {
  class BoostDriverTest (line 48) | class BoostDriverTest : public DriverTest {
    method runAllTests (line 50) | void runAllTests() override {
    method stepInvocationInitsBoostTest (line 56) | void stepInvocationInitsBoostTest() {
  function main (line 68) | int main() {

FILE: tests/integration/drivers/GTestDriverTest.cpp
  function THEN (line 8) | THEN(SUCCEED_MATCHER) {
  function THEN (line 13) | THEN(FAIL_MATCHER) {
  function THEN (line 18) | THEN(PENDING_MATCHER_1) {
  function THEN (line 22) | THEN(PENDING_MATCHER_2) {
  class GTestStepDouble (line 28) | class GTestStepDouble : public GTestStep {
    method isInitialized (line 30) | bool isInitialized() {
    method InvokeResult (line 34) | const InvokeResult invokeStepBody() override {
  class GTestDriverTest (line 41) | class GTestDriverTest : public DriverTest {
    method runAllTests (line 43) | void runAllTests() override {
    method stepInvocationInitsGTest (line 49) | void stepInvocationInitsGTest() {
  function main (line 60) | int main() {

FILE: tests/integration/drivers/GenericDriverTest.cpp
  function THEN (line 7) | THEN(SUCCEED_MATCHER) {
  function THEN (line 12) | THEN(FAIL_MATCHER) {
  function THEN (line 17) | THEN(PENDING_MATCHER_1) {
  function THEN (line 21) | THEN(PENDING_MATCHER_2) {
  function main (line 27) | int main() {

FILE: tests/integration/drivers/QtTestDriverTest.cpp
  function THEN (line 8) | THEN(SUCCEED_MATCHER) {
  function THEN (line 13) | THEN(FAIL_MATCHER) {
  function THEN (line 18) | THEN(PENDING_MATCHER_1) {
  function THEN (line 22) | THEN(PENDING_MATCHER_2) {
  class QtTestStepDouble (line 28) | class QtTestStepDouble : public QtTestStep {
    method QtTestStepDouble (line 30) | QtTestStepDouble() :
    method InvokeResult (line 35) | const InvokeResult invokeStepBody() override {
    method body (line 39) | void body() override {
  class QtTestDriverTest (line 46) | class QtTestDriverTest : public DriverTest {
    method runAllTests (line 48) | void runAllTests() override {
    method stepInvocationRunsStepBody (line 54) | void stepInvocationRunsStepBody() {
  function main (line 62) | int main() {

FILE: tests/unit/BasicStepTest.cpp
  class PendingStep (line 9) | class PendingStep : public GenericStep {
    method body (line 10) | void body() override {
  class PendingStepWithDescription (line 15) | class PendingStepWithDescription : public GenericStep {
    method body (line 16) | void body() override {
  function TEST (line 23) | TEST(BasicStepTest, handlesPendingSteps) {

FILE: tests/unit/ContextManagerTest.cpp
  class ContextManagerTest (line 9) | class ContextManagerTest : public ::testing::Test {
    method ContextManagerTest (line 13) | ContextManagerTest() :
    method TearDown (line 19) | void TearDown() override {
  class Context1 (line 24) | class Context1 {}
  class Context2 (line 25) | class Context2 {}
  function TEST_F (line 27) | TEST_F(ContextManagerTest, createsValidContextPointers) {
  function TEST_F (line 36) | TEST_F(ContextManagerTest, allowsCreatingTheSameContextTypeTwice) {
  function TEST_F (line 46) | TEST_F(ContextManagerTest, purgesContexts) {

FILE: tests/unit/CukeCommandsTest.cpp
  class CukeCommandsTest (line 10) | class CukeCommandsTest : public CukeCommandsFixture {
    method addStepWithMatcher (line 12) | void addStepWithMatcher(const std::string& matcher) {
  class CheckAllParameters (line 17) | class CheckAllParameters : public GenericStep {
    method InvokeArgs (line 25) | static InvokeArgs buildInvokeArgs() {
  class CheckAllParametersWithoutMacro (line 40) | class CheckAllParametersWithoutMacro : public CheckAllParameters {
    method body (line 42) | void body() override {
  class CheckAllParametersWithMacro (line 61) | class CheckAllParametersWithMacro : public CheckAllParameters {
    method body (line 63) | void body() override {
  class CheckAllParametersWithFuncArgs (line 78) | class CheckAllParametersWithFuncArgs : public CheckAllParameters {
    method bodyWithArgs (line 80) | void bodyWithArgs(
    method body (line 92) | void body() override {
  function TEST_F (line 97) | TEST_F(CukeCommandsTest, invokeHandlesParametersWithFuncArgs) {
  function TEST_F (line 102) | TEST_F(CukeCommandsTest, matchesCorrectly) {
  function TEST_F (line 108) | TEST_F(CukeCommandsTest, invokeHandlesParametersWithoutMacro) {
  function TEST_F (line 113) | TEST_F(CukeCommandsTest, invokeHandlesParametersWithMacro) {
  function TEST_F (line 118) | TEST_F(CukeCommandsTest, producesSnippetsEscapingTitle) {
  function TEST_F (line 127) | TEST_F(CukeCommandsTest, escapesCaractersInRegexes) {
  function TEST_F (line 134) | TEST_F(CukeCommandsTest, escapesCharactersInCStrings) {

FILE: tests/unit/RegexTest.cpp
  function TEST (line 8) | TEST(RegexTest, matchesSimpleRegex) {
  function TEST (line 20) | TEST(RegexTest, matchesRegexWithoutSubmatches) {
  function TEST (line 30) | TEST(RegexTest, matchesRegexWithSubmatches) {
  function TEST (line 44) | TEST(RegexTest, matchesRegexWithOptionalSubmatches) {
  function TEST (line 60) | TEST(RegexTest, findAllDoesNotMatchIfNoTokens) {
  function TEST (line 68) | TEST(RegexTest, findReportsCodepointPositions) {
  function TEST (line 78) | TEST(RegexTest, findAllExtractsTheFirstGroupOfEveryToken) {

FILE: tests/unit/StepCallChainTest.cpp
  class FakeStepInfo (line 7) | class FakeStepInfo : public StepInfo {
    method FakeStepInfo (line 9) | FakeStepInfo(std::stringstream* markersPtr, const InvokeResult& result) :
    method InvokeResult (line 16) | InvokeResult invokeStep(const InvokeArgs* pArgs) const override {
    method InvokeArgs (line 22) | const InvokeArgs* getLatestArgsPassed() const {
  class MarkingAroundStepHook (line 32) | class MarkingAroundStepHook : public AroundStepHook {
    method MarkingAroundStepHook (line 34) | MarkingAroundStepHook(std::string id, std::stringstream* markersPtr) :
    method MarkingAroundStepHook (line 38) | MarkingAroundStepHook() :
    method body (line 42) | void body() override {
    method doCall (line 53) | virtual void doCall() {
  class BlockingAroundStepHook (line 62) | class BlockingAroundStepHook : public MarkingAroundStepHook {
    method BlockingAroundStepHook (line 64) | BlockingAroundStepHook(std::string id, std::stringstream* markersPtr) :
    method doCall (line 68) | void doCall() override {
  class StepCallChainTest (line 74) | class StepCallChainTest : public ::testing::Test {
    method InvokeResult (line 79) | InvokeResult execStep(const InvokeResult& result) {
    method execStepAndCheckSuccess (line 85) | void execStepAndCheckSuccess() {
  function TEST_F (line 94) | TEST_F(StepCallChainTest, failsIfNoStep) {
  function TEST_F (line 100) | TEST_F(StepCallChainTest, stepExecutionReturnsTheExpectedResult) {
  function TEST_F (line 115) | TEST_F(StepCallChainTest, aroundHooksAreInvokedInTheCorrectOrder) {
  function TEST_F (line 131) | TEST_F(StepCallChainTest, argsArePassedToTheStep) {
  function TEST_F (line 140) | TEST_F(StepCallChainTest, aroundHooksCanStopTheCallChain) {

FILE: tests/unit/StepManagerTest.cpp
  class StepManagerTest (line 10) | class StepManagerTest : public ::testing::Test {
    method StepManagerTest (line 15) | StepManagerTest() {
    method getUniqueMatchIdOrZeroFor (line 23) | int getUniqueMatchIdOrZeroFor(const string& stepMatch) {
    method countMatches (line 32) | size_t countMatches(const string& stepMatch) {
    method matchesOnce (line 36) | bool matchesOnce(const string& stepMatch) {
    method matchesAtLeastOnce (line 40) | bool matchesAtLeastOnce(const string& stepMatch) {
    method extractedParamsAre (line 44) | bool extractedParamsAre(const string stepMatch, map<std::ptrdiff_t, st...
    method getResultSetFor (line 65) | MatchResult::match_results_type getResultSetFor(const string& stepMatc...
    method TearDown (line 68) | void TearDown() override {
  function TEST_F (line 78) | TEST_F(StepManagerTest, holdsNonConflictingSteps) {
  function TEST_F (line 86) | TEST_F(StepManagerTest, holdsConflictingSteps) {
  function TEST_F (line 94) | TEST_F(StepManagerTest, matchesStepsWithNonRegExMatchers) {
  function TEST_F (line 103) | TEST_F(StepManagerTest, matchesStepsWithRegExMatchers) {
  function TEST_F (line 110) | TEST_F(StepManagerTest, extractsParamsFromRegExMatchers) {
  function TEST_F (line 123) | TEST_F(StepManagerTest, handlesMultipleMatches) {
  function TEST_F (line 130) | TEST_F(StepManagerTest, matchesStepsWithNonAsciiMatchers) {

FILE: tests/unit/TableTest.cpp
  function TEST (line 6) | TEST(TableTest, forbidsRowsNotMatchingTableColumnsSize) {
  function TEST (line 23) | TEST(TableTest, rowsCannotBeAddedBeforeColumnsAreSet) {
  function TEST (line 35) | TEST(TableTest, columnsCannotBeChangesAfterRowsAreAdded) {
  function TEST (line 43) | TEST(TableTest, addedRowsMatchColumnDefinition) {

FILE: tests/unit/TagTest.cpp
  function TEST (line 7) | TEST(TagTest, emptyOrExpressionMatchesNoTag) {
  function TEST (line 13) | TEST(TagTest, orExpressionsMatchTheTagSpecified) {
  function TEST (line 19) | TEST(TagTest, orExpressionsMatchAnyTagSpecified) {
  function TEST (line 31) | TEST(TagTest, orExpressionsAllowSpaces) {
  function TEST (line 37) | TEST(TagTest, emptyAndExpressionMatchesAnyTag) {
  function TEST (line 43) | TEST(TagTest, singleAndExpressionMatchesTheTagSpecified) {
  function TEST (line 49) | TEST(TagTest, andExpressionsMatchEveryTagSpecified) {
  function TEST (line 60) | TEST(TagTest, andExpressionsAllowSpaces) {
  function TEST (line 66) | TEST(TagTest, compositeTagExpressionsAreHandled) {

FILE: tests/utils/ContextManagerTestDouble.hpp
  type cucumber (line 6) | namespace cucumber {
    type internal (line 7) | namespace internal {
      class ContextManagerTestDouble (line 9) | class ContextManagerTestDouble : public ContextManager {
        method countContexts (line 11) | contexts_type::size_type countContexts() {

FILE: tests/utils/CukeCommandsFixture.hpp
  class EmptyStep (line 13) | class EmptyStep : public GenericStep {
    method body (line 14) | void body() override {
  class CukeCommandsFixture (line 18) | class CukeCommandsFixture : public ::testing::Test, public CukeCommands {
    method runStepBodyTest (line 28) | void runStepBodyTest() {
    method addStepToManager (line 35) | void addStepToManager(const std::string& matcher) {
    method TearDown (line 39) | void TearDown() override {

FILE: tests/utils/DriverTestRunner.hpp
  class ContextListener (line 11) | class ContextListener {
    method getCreatedContexts (line 17) | int getCreatedContexts() {
    method getDestroyedContexts (line 20) | int getDestroyedContexts() {
    method notifyCreation (line 23) | void notifyCreation() {
    method notifyDestruction (line 26) | void notifyDestruction() {
    method reset (line 29) | void reset() {
  class SomeContext (line 38) | class SomeContext {
    method SomeContext (line 43) | SomeContext() {
  type cucumber (line 51) | namespace cucumber {
    type internal (line 52) | namespace internal {
      class DriverTest (line 63) | class DriverTest {
        method run (line 65) | int run() {
        method DriverTest (line 70) | DriverTest() {
        method expectTrue (line 77) | void expectTrue(const char* description, bool condition) {
        method expectFalse (line 81) | void expectFalse(const char* description, bool condition) {
        method expectEqual (line 86) | void expectEqual(const char* description, T val1, T val2) {
        method expectStrEqual (line 90) | void expectStrEqual(const char* description, const char* val1, con...
        method runAllTests (line 94) | virtual void runAllTests() {
        method updateState (line 108) | void updateState(const char* description, bool testSuccessState) {
        method step_id_type (line 114) | step_id_type getStepIdFromMatcher(const std::string& stepMatcher) {
        method invokeRunsTests (line 118) | void invokeRunsTests() {
        method contextConstructorAndDesctructorGetCalled (line 152) | void contextConstructorAndDesctructorGetCalled() {
        method contextConstructorAndDesctructorGetCalledOn (line 158) | void contextConstructorAndDesctructorGetCalledOn(const std::string...
        method failureDescriptionIsResetOnEachRun (line 170) | void failureDescriptionIsResetOnEachRun() {

FILE: tests/utils/HookRegistrationFixture.hpp
  function clearHookCallMarkers (line 26) | void clearHookCallMarkers() {
  function getHookCallMarkers (line 38) | std::string getHookCallMarkers() {
  class EmptyCallableStep (line 44) | class EmptyCallableStep : public CallableStep {
  class HookRegistrarDouble (line 49) | class HookRegistrarDouble : public HookRegistrar {
    method execAroundStepHooks (line 51) | static void execAroundStepHooks(Scenario* scenario) {
  class HookRegistrationTest (line 63) | class HookRegistrationTest : public CukeCommandsFixture {
    method HookRegistrationTest (line 67) | HookRegistrationTest() {
    method Scenario (line 71) | Scenario* getEmptyScenario() {
    method beforeHookOrder (line 75) | std::string beforeHookOrder() {
    method aroundStepHookOrder (line 81) | std::string aroundStepHookOrder() {
    method afterStepHookOrder (line 87) | std::string afterStepHookOrder() {
    method afterHookOrder (line 93) | std::string afterHookOrder() {
    method beginScenario (line 99) | void beginScenario(const TagExpression::tag_list& tags = TagExpression...
    method invokeStep (line 103) | void invokeStep() {
    method endScenario (line 107) | void endScenario() {
    method sort (line 111) | std::string sort(std::string str) {
    method SetUp (line 116) | void SetUp() override {

FILE: tests/utils/StepManagerTestDouble.hpp
  type cucumber (line 6) | namespace cucumber {
    type internal (line 7) | namespace internal {
      class StepInfoNoOp (line 9) | class StepInfoNoOp : public StepInfo {
        method StepInfoNoOp (line 11) | StepInfoNoOp(const std::string& stepMatcher, const std::string sou...
        method InvokeResult (line 14) | InvokeResult invokeStep(const InvokeArgs*) const override {
      class StepInfoPending (line 19) | class StepInfoPending : public StepInfo {
        method StepInfoPending (line 24) | StepInfoPending(const std::string& stepMatcher, const char* descri...
        method InvokeResult (line 29) | InvokeResult invokeStep(const InvokeArgs*) const override {
      class StepInfoWithTableArg (line 37) | class StepInfoWithTableArg : public StepInfo {
        method StepInfoWithTableArg (line 41) | StepInfoWithTableArg(const std::string& stepMatcher, const unsigne...
        method InvokeResult (line 46) | InvokeResult invokeStep(const InvokeArgs* pArgs) const override {
      class StepManagerTestDouble (line 55) | class StepManagerTestDouble : public StepManager {
        method clearSteps (line 57) | static void clearSteps() {
        method count (line 61) | static steps_type::size_type count() {
        method step_id_type (line 65) | static step_id_type addStepDefinition(const std::string& stepMatch...
        method step_id_type (line 69) | static step_id_type addStepDefinitionWithId(
        method step_id_type (line 75) | static step_id_type addStepDefinitionWithId(
        method step_id_type (line 83) | static step_id_type addPendingStepDefinitionWithId(
        method step_id_type (line 89) | static step_id_type addPendingStepDefinitionWithId(
        method step_id_type (line 99) | static step_id_type addTableStepDefinitionWithId(
        method step_id_type (line 109) | static step_id_type getStepId(const std::string& stepMatcher) {
Condensed preview — 129 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (270K chars).
[
  {
    "path": ".clang-format",
    "chars": 1079,
    "preview": "---\nLanguage: Cpp\nAccessModifierOffset: -4\nAlignAfterOpenBracket: BlockIndent\nAlignEscapedNewlinesLeft: true\nAllowShortE"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "chars": 1872,
    "preview": "<!-- These sections are meant as guidance for you, to help you give the kind of information we'll need to help with your"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "chars": 1976,
    "preview": "<!-- These sections are meant as guidance for you. If something doesn't fit, you can just skip it. -->\n\n## Summary\n\n<!--"
  },
  {
    "path": ".github/workflows/format.yml",
    "chars": 759,
    "preview": "name: check format\n\npermissions: {}\n\non:\n  pull_request:\n    branches: [ main ]\n  workflow_dispatch:\n  push:\n    branche"
  },
  {
    "path": ".github/workflows/linux-build.yml",
    "chars": 1791,
    "preview": "name: Linux build\n\npermissions: {}\n\non:\n  pull_request:\n    branches: [ main ]\n  workflow_dispatch:\n  push:\n    branches"
  },
  {
    "path": ".github/workflows/qt5.yml",
    "chars": 1996,
    "preview": "name: build and test with Qt5\n\npermissions: {}\n\non:\n  pull_request:\n    branches: [ main ]\n  workflow_dispatch:\n  push:\n"
  },
  {
    "path": ".github/workflows/run-all.yml",
    "chars": 1778,
    "preview": "name: run all\n\npermissions: {}\n\non:\n  pull_request:\n    branches: [ main ]\n  workflow_dispatch:\n  push:\n    branches:\n  "
  },
  {
    "path": ".github/workflows/windows-build.yml",
    "chars": 3475,
    "preview": "name: Windows build\n\npermissions: {}\n\non:\n  pull_request:\n    branches: [ main ]\n  workflow_dispatch:\n  push:\n    branch"
  },
  {
    "path": ".github/workflows/zizmor-analysis.yaml",
    "chars": 601,
    "preview": "name: GitHub Actions Security Analysis\n\non:\n  push:\n    branches:\n      - main\n      - 'releases/**'\n    paths:\n      - "
  },
  {
    "path": ".gitignore",
    "chars": 220,
    "preview": "# Bundler\n/Gemfile.lock\n\n# rvm\n/.ruby-version\n/.ruby-gemset\n\n# Build artifacts\n/build/\n/coverage/\n/.local/\n\n# vim swap f"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 13133,
    "preview": "Please see [CONTRIBUTING.md](https://github.com/cucumber/cucumber/blob/main/CONTRIBUTING.md) on how to contribute to Cuc"
  },
  {
    "path": "CMakeLists.txt",
    "chars": 9052,
    "preview": "cmake_minimum_required(VERSION 3.16)\n\ncmake_policy(SET CMP0063 NEW)\n\n# CMP0077: option() honors normal variables\n# https"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 4488,
    "preview": "## About to create a new Github Issue?\n\nWe appreciate that. But before you do, please learn our basic rules:\n\n* Do you h"
  },
  {
    "path": "Gemfile",
    "chars": 110,
    "preview": "source 'https://rubygems.org'\n\ngroup :test do\n  gem 'cucumber', \"=7.1.0\"\n  gem 'cucumber-wire', \"=6.2.1\"\nend\n\n"
  },
  {
    "path": "LICENSE",
    "chars": 1071,
    "preview": "MIT License\n\nCopyright (c) 2010 Paolo Ambrosio\n\nPermission is hereby granted, free of charge, to any person obtaining a "
  },
  {
    "path": "README.md",
    "chars": 5642,
    "preview": "# Cucumber-CPP\n\n## Overview\n\nCucumber-Cpp allows Cucumber to support step definitions written in C++.\n\n* [Cucumber-Cpp W"
  },
  {
    "path": "cmake/modules/FindAsio.cmake",
    "chars": 239,
    "preview": "find_path(ASIO_INCLUDE_DIR asio.hpp)\n\nif (ASIO_INCLUDE_DIR)\n    set(ASIO_FOUND TRUE)\nelse ()\n    set(ASIO_FOUND FALSE)\ne"
  },
  {
    "path": "cmake/modules/FindTCLAP.cmake",
    "chars": 252,
    "preview": "find_path(TCLAP_INCLUDE_DIR tclap/CmdLine.h)\n\nif (TCLAP_INCLUDE_DIR)\n    set(TCLAP_FOUND TRUE)\nelse ()\n    set(TCLAP_FOU"
  },
  {
    "path": "cmake/modules/FindValgrind.cmake",
    "chars": 4090,
    "preview": "#.rst:\n# FindValgrind\n# -------\n#\n# The module defines the following variables:\n#\n# ``VALGRIND_EXECUTABLE``\n#   Path to "
  },
  {
    "path": "cmake/modules/GitVersion.cmake",
    "chars": 1010,
    "preview": "function(git_get_version VERSION_VARIABLE)\n    find_program(GIT_EXECUTABLE git)\n\n    if(NOT GIT_EXECUTABLE)\n        mess"
  },
  {
    "path": "examples/CMakeLists.txt",
    "chars": 82,
    "preview": "add_subdirectory(Calc)\nadd_subdirectory(CalcQt)\nadd_subdirectory(FeatureShowcase)\n"
  },
  {
    "path": "examples/Calc/CMakeLists.txt",
    "chars": 946,
    "preview": "project(Calc)\n\nadd_library(Calc STATIC src/Calculator.cpp)\ntarget_include_directories(Calc INTERFACE src)\n\nif(TARGET GTe"
  },
  {
    "path": "examples/Calc/README.txt",
    "chars": 44,
    "preview": "This was inspired by Cuke4Nuke Calc sample\n\n"
  },
  {
    "path": "examples/Calc/features/addition.feature",
    "chars": 543,
    "preview": "# language: en\nFeature: Addition\n  In order to avoid silly mistakes\n  As a math idiot \n  I want to be told the sum of tw"
  },
  {
    "path": "examples/Calc/features/division.feature",
    "chars": 309,
    "preview": "# language: en\nFeature: Division\n  In order to avoid silly mistakes\n  Cashiers must be able to calculate a fraction\n\n  S"
  },
  {
    "path": "examples/Calc/features/step_definitions/BoostCalculatorSteps.cpp",
    "chars": 126,
    "preview": "#include <boost/test/unit_test.hpp>\n// Pretend to be GTest\n#define EXPECT_EQ BOOST_CHECK_EQUAL\n#include \"CalculatorSteps"
  },
  {
    "path": "examples/Calc/features/step_definitions/CalculatorSteps.cpp",
    "chars": 696,
    "preview": "#include <cucumber-cpp/autodetect.hpp>\n\n#include <Calculator.hpp>\n\nusing cucumber::ScenarioScope;\n\nstruct CalcCtx {\n    "
  },
  {
    "path": "examples/Calc/features/step_definitions/FuncArgsCalculatorSteps.cpp",
    "chars": 701,
    "preview": "#include <gtest/gtest.h>\n#include <cucumber-cpp/autodetect.hpp>\n\n#include <Calculator.hpp>\n\nusing cucumber::ScenarioScop"
  },
  {
    "path": "examples/Calc/features/step_definitions/GTestCalculatorSteps.cpp",
    "chars": 56,
    "preview": "#include <gtest/gtest.h>\n#include \"CalculatorSteps.cpp\"\n"
  },
  {
    "path": "examples/Calc/features/step_definitions/QtTestCalculatorSteps.cpp",
    "chars": 98,
    "preview": "#include <QTest>\n// Pretend to be GTest\n#define EXPECT_EQ QCOMPARE\n#include \"CalculatorSteps.cpp\"\n"
  },
  {
    "path": "examples/Calc/features/step_definitions/cucumber.wire",
    "chars": 27,
    "preview": "host: localhost\nport: 3902\n"
  },
  {
    "path": "examples/Calc/src/Calculator.cpp",
    "chars": 617,
    "preview": "#include <limits>\n#include \"Calculator.hpp\"\n\nvoid Calculator::push(double n) {\n    values.push_back(n);\n}\n\ndouble Calcul"
  },
  {
    "path": "examples/Calc/src/Calculator.hpp",
    "chars": 163,
    "preview": "#pragma once\n\n#include <list>\n\nclass Calculator {\nprivate:\n    std::list<double> values;\n\npublic:\n    void push(double);"
  },
  {
    "path": "examples/CalcQt/CMakeLists.txt",
    "chars": 1301,
    "preview": "project(CalcQt)\n\nif(TARGET Qt::Core AND TARGET Qt::Gui AND TARGET Qt::Widgets AND TARGET Qt::Test)\n    set(CMAKE_AUTOMOC"
  },
  {
    "path": "examples/CalcQt/README.txt",
    "chars": 205,
    "preview": "This sample shows how to test a QT GUI. The environment variable\nCALCQT_STEP_DELAY allows to introduce delays in the ste"
  },
  {
    "path": "examples/CalcQt/features/addition.feature",
    "chars": 503,
    "preview": "# language: en\nFeature: Addition\n  In order to avoid silly mistakes\n  As a math idiot \n  I want to be told the sum of tw"
  },
  {
    "path": "examples/CalcQt/features/behavior.feature",
    "chars": 1919,
    "preview": "# language: en\nFeature: GUI behavior\n  tests for buttons\n\n  Scenario Outline: Digit buttons\n    Given I just turned on t"
  },
  {
    "path": "examples/CalcQt/features/initialization.feature",
    "chars": 194,
    "preview": "# language: en\nFeature: GUI initalization\n  test the initial status of the calculator\n\n  Scenario: Initialization\n    Gi"
  },
  {
    "path": "examples/CalcQt/features/step_definitions/BoostCalculatorQtSteps.cpp",
    "chars": 162,
    "preview": "#include <boost/test/unit_test.hpp>\n// Pretend to be GTest\n#define EXPECT_EQ BOOST_CHECK_EQUAL\n#define ASSERT_TRUE BOOST"
  },
  {
    "path": "examples/CalcQt/features/step_definitions/CalculatorQtSteps.cpp",
    "chars": 1527,
    "preview": "#include <cucumber-cpp/autodetect.hpp>\n\n#include \"Calculator.hpp\"\n\nclass CalculatorCtx {\npublic:\n    CalculatorCtx() {\n "
  },
  {
    "path": "examples/CalcQt/features/step_definitions/GTestCalculatorQtSteps.cpp",
    "chars": 58,
    "preview": "#include <gtest/gtest.h>\n#include \"CalculatorQtSteps.cpp\"\n"
  },
  {
    "path": "examples/CalcQt/features/step_definitions/QtTestCalculatorQtSteps.cpp",
    "chars": 128,
    "preview": "#include <QTest>\n// Pretend to be GTest\n#define EXPECT_EQ QCOMPARE\n#define ASSERT_TRUE QVERIFY\n#include \"CalculatorQtSte"
  },
  {
    "path": "examples/CalcQt/features/step_definitions/cucumber.wire",
    "chars": 27,
    "preview": "host: localhost\nport: 3902\n"
  },
  {
    "path": "examples/CalcQt/features/subtraction.feature",
    "chars": 523,
    "preview": "# language: en\nFeature: Subtraction\n  In order to avoid silly mistakes\n  As a math idiot \n  I want to be told the differ"
  },
  {
    "path": "examples/CalcQt/src/CalcQt.cpp",
    "chars": 313,
    "preview": "#include <QApplication>\n\n#include \"Calculator.hpp\"\n#include \"CalculatorWidget.hpp\"\n\nint main(int argc, char* argv[]) {\n "
  },
  {
    "path": "examples/CalcQt/src/Calculator.cpp",
    "chars": 1294,
    "preview": "#include \"Calculator.hpp\"\n\n#include <QRegularExpression>\n\nQString Calculator::calculate(const QString& expression) const"
  },
  {
    "path": "examples/CalcQt/src/Calculator.hpp",
    "chars": 375,
    "preview": "#pragma once\n\n#include <QObject>\n\nclass Calculator : public QObject {\n    Q_OBJECT\n\npublic:\n    using QObject::QObject;\n"
  },
  {
    "path": "examples/CalcQt/src/CalculatorWidget.cpp",
    "chars": 3485,
    "preview": "#include \"CalculatorWidget.hpp\"\n\n#include \"Calculator.hpp\"\n#include <QGridLayout>\n#include <QKeyEvent>\n#include <QLabel>"
  },
  {
    "path": "examples/CalcQt/src/CalculatorWidget.hpp",
    "chars": 653,
    "preview": "#pragma once\n\nclass QLabel;\nclass QPushButton;\nclass Calculator;\n\n#include <QString>\n#include <QWidget>\n\nclass Calculato"
  },
  {
    "path": "examples/FeatureShowcase/CMakeLists.txt",
    "chars": 621,
    "preview": "project(FeatureShowcase)\n\nif(TARGET GTest::gtest)\n    function(add_cucumber_executable)\n        add_executable(FeatureSh"
  },
  {
    "path": "examples/FeatureShowcase/README.txt",
    "chars": 70,
    "preview": "This sample shows a few advanced features: tags and table arguments.\n\n"
  },
  {
    "path": "examples/FeatureShowcase/features/step_definitions/TableSteps.cpp",
    "chars": 1861,
    "preview": "#include <gtest/gtest.h>\n#include <cucumber-cpp/autodetect.hpp>\n\n#include <string>\n#include <map>\n\nusing cucumber::Scena"
  },
  {
    "path": "examples/FeatureShowcase/features/step_definitions/TagSteps.cpp",
    "chars": 1410,
    "preview": "#include <gtest/gtest.h>\n#include <cucumber-cpp/autodetect.hpp>\n\n#include <iostream>\n\nusing std::cout;\nusing std::endl;\n"
  },
  {
    "path": "examples/FeatureShowcase/features/step_definitions/cucumber.wire",
    "chars": 27,
    "preview": "host: localhost\nport: 3902\n"
  },
  {
    "path": "examples/FeatureShowcase/features/table.feature",
    "chars": 413,
    "preview": "# language: en\nFeature: Table\n  In order to explain how to use tables\n  I have to make this silly example\n\n  Scenario: N"
  },
  {
    "path": "examples/FeatureShowcase/features/tag.feature",
    "chars": 1372,
    "preview": "# language: en\nFeature: Tags\n  In order to explain how to use tags\n  I have to make this silly example\n\n  Scenario: No t"
  },
  {
    "path": "include/cucumber-cpp/autodetect.hpp",
    "chars": 177,
    "preview": "#include \"internal/defs.hpp\"\n#ifndef STEP_INHERITANCE\n    #error No test framework found: please include a testing frame"
  },
  {
    "path": "include/cucumber-cpp/defs.hpp",
    "chars": 422,
    "preview": "#ifdef __GNUC__\n    #warning \"Use of defs.hpp is deprecated, please use either autodetect.hpp or generic.hpp\"\n#else\n    "
  },
  {
    "path": "include/cucumber-cpp/generic.hpp",
    "chars": 217,
    "preview": "#include \"internal/defs.hpp\"\n#ifdef STEP_INHERITANCE\n    #error Test framework found: please include autodetect.hpp or r"
  },
  {
    "path": "include/cucumber-cpp/internal/ContextManager.hpp",
    "chars": 1457,
    "preview": "#ifndef CUKE_CONTEXTMANAGER_HPP_\n#define CUKE_CONTEXTMANAGER_HPP_\n\n#include <cucumber-cpp/internal/CukeExport.hpp>\n\n#inc"
  },
  {
    "path": "include/cucumber-cpp/internal/CukeCommands.hpp",
    "chars": 1197,
    "preview": "#ifndef CUKE_CUKECOMMANDS_HPP_\n#define CUKE_CUKECOMMANDS_HPP_\n\n#include \"ContextManager.hpp\"\n#include <cucumber-cpp/inte"
  },
  {
    "path": "include/cucumber-cpp/internal/CukeEngine.hpp",
    "chars": 2708,
    "preview": "#ifndef CUKE_CUKEENGINE_HPP_\n#define CUKE_CUKEENGINE_HPP_\n\n#include <cstddef>\n#include <string>\n#include <vector>\n\n#incl"
  },
  {
    "path": "include/cucumber-cpp/internal/CukeEngineImpl.hpp",
    "chars": 1009,
    "preview": "#ifndef CUKE_CUKEENGINE_IMPL_HPP_\n#define CUKE_CUKEENGINE_IMPL_HPP_\n\n#include \"CukeEngine.hpp\"\n#include <cucumber-cpp/in"
  },
  {
    "path": "include/cucumber-cpp/internal/Macros.hpp",
    "chars": 178,
    "preview": "#ifndef CUKE_MACROS_HPP_\n#define CUKE_MACROS_HPP_\n\n#include \"RegistrationMacros.hpp\"\n#include \"step/StepMacros.hpp\"\n#inc"
  },
  {
    "path": "include/cucumber-cpp/internal/RegistrationMacros.hpp",
    "chars": 2181,
    "preview": "#ifndef CUKE_REGISTRATIONMACROS_HPP_\n#define CUKE_REGISTRATIONMACROS_HPP_\n\n// ******************************************"
  },
  {
    "path": "include/cucumber-cpp/internal/Scenario.hpp",
    "chars": 365,
    "preview": "#ifndef CUKE_SCENARIO_HPP_\n#define CUKE_SCENARIO_HPP_\n\n#include \"hook/Tag.hpp\"\n\nnamespace cucumber {\nnamespace internal "
  },
  {
    "path": "include/cucumber-cpp/internal/Table.hpp",
    "chars": 1004,
    "preview": "#ifndef CUKE_TABLE_HPP_\n#define CUKE_TABLE_HPP_\n\n#include <cucumber-cpp/internal/CukeExport.hpp>\n\n#include <vector>\n#inc"
  },
  {
    "path": "include/cucumber-cpp/internal/connectors/wire/ProtocolHandler.hpp",
    "chars": 387,
    "preview": "#ifndef CUKE_PROTOCOLHANDLER_HPP_\n#define CUKE_PROTOCOLHANDLER_HPP_\n\n#include <string>\n\nnamespace cucumber {\nnamespace i"
  },
  {
    "path": "include/cucumber-cpp/internal/connectors/wire/WireProtocol.hpp",
    "chars": 4548,
    "preview": "#ifndef CUKE_WIREPROTOCOL_HPP_\n#define CUKE_WIREPROTOCOL_HPP_\n\n#include <cucumber-cpp/internal/CukeExport.hpp>\n#include "
  },
  {
    "path": "include/cucumber-cpp/internal/connectors/wire/WireProtocolCommands.hpp",
    "chars": 1890,
    "preview": "#ifndef CUKE_WIREPROTOCOL_COMMANDS_HPP_\n#define CUKE_WIREPROTOCOL_COMMANDS_HPP_\n\n#include \"WireProtocol.hpp\"\n#include <m"
  },
  {
    "path": "include/cucumber-cpp/internal/connectors/wire/WireServer.hpp",
    "chars": 2738,
    "preview": "#ifndef CUKE_WIRESERVER_HPP_\n#define CUKE_WIRESERVER_HPP_\n\n#include <cucumber-cpp/internal/CukeExport.hpp>\n#include \"Pro"
  },
  {
    "path": "include/cucumber-cpp/internal/defs.hpp",
    "chars": 156,
    "preview": "#include \"step/StepManager.hpp\"\n#include \"hook/HookRegistrar.hpp\"\n#include \"ContextManager.hpp\"\n#include \"Macros.hpp\"\n#i"
  },
  {
    "path": "include/cucumber-cpp/internal/drivers/BoostDriver.hpp",
    "chars": 525,
    "preview": "#ifndef CUKE_BOOSTDRIVER_HPP_\n#define CUKE_BOOSTDRIVER_HPP_\n\n#include \"../step/StepManager.hpp\"\n#include <cucumber-cpp/i"
  },
  {
    "path": "include/cucumber-cpp/internal/drivers/DriverSelector.hpp",
    "chars": 243,
    "preview": "#if defined(GTEST_INCLUDE_GTEST_GTEST_H_) || defined(GOOGLETEST_INCLUDE_GTEST_GTEST_H_)\n    #include \"GTestDriver.hpp\"\n#"
  },
  {
    "path": "include/cucumber-cpp/internal/drivers/GTestDriver.hpp",
    "chars": 535,
    "preview": "#ifndef CUKE_GTESTDRIVER_HPP_\n#define CUKE_GTESTDRIVER_HPP_\n\n#include <cucumber-cpp/internal/CukeExport.hpp>\n#include \"."
  },
  {
    "path": "include/cucumber-cpp/internal/drivers/GenericDriver.hpp",
    "chars": 437,
    "preview": "#ifndef CUKE_GENERICDRIVER_HPP_\n#define CUKE_GENERICDRIVER_HPP_\n\n#include \"../step/StepManager.hpp\"\n#include <cucumber-c"
  },
  {
    "path": "include/cucumber-cpp/internal/drivers/QtTestDriver.hpp",
    "chars": 772,
    "preview": "#ifndef CUKE_QTTESTDRIVER_HPP_\n#define CUKE_QTTESTDRIVER_HPP_\n\n#include \"../step/StepManager.hpp\"\n#include <cucumber-cpp"
  },
  {
    "path": "include/cucumber-cpp/internal/hook/HookMacros.hpp",
    "chars": 5873,
    "preview": "#ifndef CUKE_HOOKMACROS_HPP_\n#define CUKE_HOOKMACROS_HPP_\n\n#include \"../RegistrationMacros.hpp\"\n\n// ********************"
  },
  {
    "path": "include/cucumber-cpp/internal/hook/HookRegistrar.hpp",
    "chars": 5006,
    "preview": "#ifndef CUKE_HOOKREGISTRAR_HPP_\n#define CUKE_HOOKREGISTRAR_HPP_\n\n#include <cucumber-cpp/internal/CukeExport.hpp>\n#includ"
  },
  {
    "path": "include/cucumber-cpp/internal/hook/Tag.hpp",
    "chars": 1170,
    "preview": "#ifndef CUKE_TAG_HPP_\n#define CUKE_TAG_HPP_\n\n#include <string>\n#include <vector>\n\n#include <cucumber-cpp/internal/CukeEx"
  },
  {
    "path": "include/cucumber-cpp/internal/step/StepMacros.hpp",
    "chars": 2132,
    "preview": "#ifndef CUKE_STEPMACROS_HPP_\n#define CUKE_STEPMACROS_HPP_\n\n#include \"../RegistrationMacros.hpp\"\n\n// ********************"
  },
  {
    "path": "include/cucumber-cpp/internal/step/StepManager.hpp",
    "chars": 6143,
    "preview": "#ifndef CUKE_STEPMANAGER_HPP_\n#define CUKE_STEPMANAGER_HPP_\n\n#include <map>\n#include <sstream>\n#include <stdexcept>\n#inc"
  },
  {
    "path": "include/cucumber-cpp/internal/utils/IndexSequence.hpp",
    "chars": 218,
    "preview": "#ifndef CUKE_INDEXSEQ_HPP_\n#define CUKE_INDEXSEQ_HPP_\n\n#include <utility>\n\nnamespace cucumber {\nnamespace internal {\n\nus"
  },
  {
    "path": "include/cucumber-cpp/internal/utils/Regex.hpp",
    "chars": 1104,
    "preview": "#ifndef CUKE_REGEX_HPP_\n#define CUKE_REGEX_HPP_\n\n#include <cstddef>\n#include <vector>\n\n#include <regex>\n\nnamespace cucum"
  },
  {
    "path": "run-linux.sh",
    "chars": 1616,
    "preview": "#!/bin/sh\nset -e #break script on non-zero exitcode from any command\nset -x #display command being executed\n\nCTEST_OUTPU"
  },
  {
    "path": "run-windows.ps1",
    "chars": 1769,
    "preview": "# --- Function definitions ---\nfunction Invoke-CMake {\n    param (\n        $Arguments\n    )\n    $process = Start-Process"
  },
  {
    "path": "src/CMakeLists.txt",
    "chars": 5302,
    "preview": "include(GenerateExportHeader)\n\nfind_package(nlohmann_json 3.10.5 REQUIRED)\nfind_package(Asio REQUIRED)\nfind_package(TCLA"
  },
  {
    "path": "src/ContextManager.cpp",
    "chars": 205,
    "preview": "#include \"cucumber-cpp/internal/ContextManager.hpp\"\n\nnamespace cucumber {\nnamespace internal {\n\ncontexts_type ContextMan"
  },
  {
    "path": "src/CukeCommands.cpp",
    "chars": 2346,
    "preview": "#include \"cucumber-cpp/internal/CukeCommands.hpp\"\n#include \"cucumber-cpp/internal/hook/HookRegistrar.hpp\"\n\n#include <sst"
  },
  {
    "path": "src/CukeEngine.cpp",
    "chars": 1037,
    "preview": "#include \"cucumber-cpp/internal/CukeEngine.hpp\"\n\nnamespace cucumber {\nnamespace internal {\n\nInvokeException::InvokeExcep"
  },
  {
    "path": "src/CukeEngineImpl.cpp",
    "chars": 2968,
    "preview": "#include \"cucumber-cpp/internal/CukeEngineImpl.hpp\"\n\nnamespace cucumber {\nnamespace internal {\n\nnamespace {\n\nstd::string"
  },
  {
    "path": "src/HookRegistrar.cpp",
    "chars": 4330,
    "preview": "#include <cucumber-cpp/internal/hook/HookRegistrar.hpp>\n#include <cucumber-cpp/internal/CukeCommands.hpp>\n\nnamespace cuc"
  },
  {
    "path": "src/Regex.cpp",
    "chars": 2232,
    "preview": "#include <cucumber-cpp/internal/utils/Regex.hpp>\n\n#include <algorithm>\n\nnamespace cucumber {\nnamespace internal {\n\nRegex"
  },
  {
    "path": "src/Scenario.cpp",
    "chars": 245,
    "preview": "#include <cucumber-cpp/internal/Scenario.hpp>\n\nnamespace cucumber {\nnamespace internal {\n\nScenario::Scenario(const TagEx"
  },
  {
    "path": "src/StepManager.cpp",
    "chars": 4410,
    "preview": "#include \"cucumber-cpp/internal/step/StepManager.hpp\"\n\nnamespace cucumber {\nnamespace internal {\n\nStepInfo::StepInfo(con"
  },
  {
    "path": "src/Table.cpp",
    "chars": 971,
    "preview": "#include <cucumber-cpp/internal/Table.hpp>\n\nnamespace cucumber {\nnamespace internal {\n\nvoid Table::addColumn(const std::"
  },
  {
    "path": "src/Tag.cpp",
    "chars": 2092,
    "preview": "#include <cucumber-cpp/internal/hook/Tag.hpp>\n#include <memory>\n\nnamespace cucumber {\nnamespace internal {\n\nRegex& AndTa"
  },
  {
    "path": "src/connectors/wire/WireProtocol.cpp",
    "chars": 9064,
    "preview": "#include <cucumber-cpp/internal/connectors/wire/WireProtocol.hpp>\n#include <cucumber-cpp/internal/connectors/wire/WirePr"
  },
  {
    "path": "src/connectors/wire/WireProtocolCommands.cpp",
    "chars": 2383,
    "preview": "#include <cucumber-cpp/internal/connectors/wire/WireProtocolCommands.hpp>\n\nnamespace cucumber {\nnamespace internal {\n\nSc"
  },
  {
    "path": "src/connectors/wire/WireServer.cpp",
    "chars": 2679,
    "preview": "#include <cucumber-cpp/internal/connectors/wire/WireServer.hpp>\n#include <filesystem>\n\nnamespace cucumber {\nnamespace in"
  },
  {
    "path": "src/drivers/BoostDriver.cpp",
    "chars": 3672,
    "preview": "#include <cucumber-cpp/internal/drivers/BoostDriver.hpp>\n\n#include <sstream>\n\n#include <boost/function.hpp>\n#include <bo"
  },
  {
    "path": "src/drivers/GTestDriver.cpp",
    "chars": 992,
    "preview": "#include <cucumber-cpp/internal/drivers/GTestDriver.hpp>\n\n#include <gtest/gtest.h>\n\nnamespace cucumber {\nnamespace inter"
  },
  {
    "path": "src/drivers/GenericDriver.cpp",
    "chars": 293,
    "preview": "#include \"cucumber-cpp/internal/drivers/GenericDriver.hpp\"\n\nnamespace cucumber {\nnamespace internal {\n\nconst InvokeResul"
  },
  {
    "path": "src/drivers/QtTestDriver.cpp",
    "chars": 1540,
    "preview": "#include \"cucumber-cpp/internal/drivers/QtTestDriver.hpp\"\n\n#include <QTest>\n#include <QTemporaryFile>\n#include <QTextStr"
  },
  {
    "path": "src/main.cpp",
    "chars": 2732,
    "preview": "#include <cucumber-cpp/internal/CukeEngineImpl.hpp>\n#include <cucumber-cpp/internal/CukeExport.hpp>\n#include <cucumber-c"
  },
  {
    "path": "tests/CMakeLists.txt",
    "chars": 2593,
    "preview": "find_package(GTest REQUIRED)\n\nadd_library(utils INTERFACE\n    utils/HookRegistrationFixture.hpp\n    utils/ContextManager"
  },
  {
    "path": "tests/integration/ContextHandlingTest.cpp",
    "chars": 1853,
    "preview": "#include <gtest/gtest.h>\n\n#include \"utils/ContextManagerTestDouble.hpp\"\n\nusing namespace std;\nusing namespace cucumber::"
  },
  {
    "path": "tests/integration/HookRegistrationTest.cpp",
    "chars": 7814,
    "preview": "#include <gtest/gtest.h>\n\n#include \"utils/HookRegistrationFixture.hpp\"\n\n#include <cucumber-cpp/internal/hook/HookMacros."
  },
  {
    "path": "tests/integration/StepRegistrationTest.cpp",
    "chars": 1380,
    "preview": "#include <gtest/gtest.h>\n\n#include <cucumber-cpp/internal/step/StepManager.hpp>\n#include <cucumber-cpp/internal/step/Ste"
  },
  {
    "path": "tests/integration/TaggedHookRegistrationTest.cpp",
    "chars": 2024,
    "preview": "#include <gtest/gtest.h>\n\n#include \"utils/HookRegistrationFixture.hpp\"\n#include <cucumber-cpp/internal/hook/HookMacros.h"
  },
  {
    "path": "tests/integration/WireProtocolTest.cpp",
    "chars": 11057,
    "preview": "#include <cucumber-cpp/internal/connectors/wire/WireProtocol.hpp>\n#include <cucumber-cpp/internal/connectors/wire/WirePr"
  },
  {
    "path": "tests/integration/WireServerTest.cpp",
    "chars": 6502,
    "preview": "#include <cucumber-cpp/internal/connectors/wire/WireServer.hpp>\n\n#include <gmock/gmock.h>\n\n#include <filesystem>\n#includ"
  },
  {
    "path": "tests/integration/drivers/BoostDriverTest.cpp",
    "chars": 1502,
    "preview": "#include <boost/version.hpp>\n#include <boost/test/unit_test.hpp>\n#include <cucumber-cpp/autodetect.hpp>\n\n#include \"utils"
  },
  {
    "path": "tests/integration/drivers/GTestDriverTest.cpp",
    "chars": 1326,
    "preview": "#include <gtest/gtest.h>\n#include <cucumber-cpp/autodetect.hpp>\n\n#include \"utils/DriverTestRunner.hpp\"\n\nusing namespace "
  },
  {
    "path": "tests/integration/drivers/GenericDriverTest.cpp",
    "chars": 503,
    "preview": "#include <cucumber-cpp/generic.hpp>\n\n#include \"utils/DriverTestRunner.hpp\"\n\nusing namespace cucumber;\n\nTHEN(SUCCEED_MATC"
  },
  {
    "path": "tests/integration/drivers/QtTestDriverTest.cpp",
    "chars": 1251,
    "preview": "#include <QtTest>\n#include <cucumber-cpp/autodetect.hpp>\n\n#include \"utils/DriverTestRunner.hpp\"\n\nusing namespace cucumbe"
  },
  {
    "path": "tests/unit/BasicStepTest.cpp",
    "chars": 928,
    "preview": "#include <gtest/gtest.h>\n\n#include <cucumber-cpp/internal/drivers/GenericDriver.hpp>\n\nusing namespace cucumber::internal"
  },
  {
    "path": "tests/unit/ContextManagerTest.cpp",
    "chars": 1565,
    "preview": "#include <gtest/gtest.h>\n\n#include \"utils/ContextManagerTestDouble.hpp\"\n\n#include <memory>\n\nusing namespace cucumber::in"
  },
  {
    "path": "tests/unit/CukeCommandsTest.cpp",
    "chars": 4583,
    "preview": "#include <gtest/gtest.h>\n\n#include <cucumber-cpp/internal/step/StepMacros.hpp>\n#include \"utils/CukeCommandsFixture.hpp\"\n"
  },
  {
    "path": "tests/unit/RegexTest.cpp",
    "chars": 3043,
    "preview": "#include <gtest/gtest.h>\n\n#include <cucumber-cpp/internal/utils/Regex.hpp>\nusing namespace cucumber::internal;\n\n#include"
  },
  {
    "path": "tests/unit/StepCallChainTest.cpp",
    "chars": 4149,
    "preview": "#include <gtest/gtest.h>\n\n#include <cucumber-cpp/internal/hook/HookRegistrar.hpp>\n\nusing namespace cucumber::internal;\n\n"
  },
  {
    "path": "tests/unit/StepManagerTest.cpp",
    "chars": 4951,
    "preview": "#include <gtest/gtest.h>\n\n#include \"utils/StepManagerTestDouble.hpp\"\n\n#include <map>\n\nusing namespace std;\nusing namespa"
  },
  {
    "path": "tests/unit/TableTest.cpp",
    "chars": 1526,
    "preview": "#include <gtest/gtest.h>\n\n#include <cucumber-cpp/internal/Table.hpp>\nusing namespace cucumber::internal;\n\nTEST(TableTest"
  },
  {
    "path": "tests/unit/TagTest.cpp",
    "chars": 2283,
    "preview": "#include <gtest/gtest.h>\n\n#include <cucumber-cpp/internal/hook/Tag.hpp>\n\nusing namespace cucumber::internal;\n\nTEST(TagTe"
  },
  {
    "path": "tests/utils/ContextManagerTestDouble.hpp",
    "chars": 406,
    "preview": "#ifndef CUKE_CONTEXTMANAGERTESTDOUBLE_HPP_\n#define CUKE_CONTEXTMANAGERTESTDOUBLE_HPP_\n\n#include <cucumber-cpp/internal/C"
  },
  {
    "path": "tests/utils/CukeCommandsFixture.hpp",
    "chars": 1142,
    "preview": "#ifndef CUKE_CUKECOMMANDSFIXTURE_HPP_\n#define CUKE_CUKECOMMANDSFIXTURE_HPP_\n\n#include <cucumber-cpp/internal/CukeCommand"
  },
  {
    "path": "tests/utils/DriverTestRunner.hpp",
    "chars": 5785,
    "preview": "#ifndef CUKE_DRIVERTESTRUNNER_HPP_\n#define CUKE_DRIVERTESTRUNNER_HPP_\n\n#include \"StepManagerTestDouble.hpp\"\n#include <cu"
  },
  {
    "path": "tests/utils/HookRegistrationFixture.hpp",
    "chars": 3466,
    "preview": "#ifndef CUKE_HOOKREGISTRATIONFIXTURE_HPP_\n#define CUKE_HOOKREGISTRATIONFIXTURE_HPP_\n\n#include <cucumber-cpp/internal/hoo"
  },
  {
    "path": "tests/utils/StepManagerTestDouble.hpp",
    "chars": 3700,
    "preview": "#ifndef CUKE_STEPMANAGERTESTDOUBLE_HPP_\n#define CUKE_STEPMANAGERTESTDOUBLE_HPP_\n\n#include <cucumber-cpp/internal/step/St"
  }
]

About this extraction

This page contains the full source code of the cucumber/cucumber-cpp GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 129 files (244.6 KB), approximately 64.6k tokens, and a symbol index with 540 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!