[
  {
    "path": ".clang-format",
    "content": "---\nLanguage: Cpp\nAccessModifierOffset: -4\nAlignAfterOpenBracket: BlockIndent\nAlignEscapedNewlinesLeft: true\nAllowShortEnumsOnASingleLine: false\nAllowShortFunctionsOnASingleLine: None\nAlwaysBreakTemplateDeclarations: true\nBinPackArguments: false\nBinPackParameters: false\nBreakBeforeBinaryOperators: All\nBreakBeforeBraces: Attach\nBreakConstructorInitializers: AfterColon\nColumnLimit: 100\nFixNamespaceComments: true\nIncludeCategories: \n  # The autodetect header should always be included last\n  - Regex:           '^<cucumber-cpp/autodetect\\.hpp>$'\n    Priority:        3\n  - Regex:           '^[\"<]cucumber-cpp/'\n    Priority:        1\n  - Regex:           '.*'\n    Priority:        2\nIndentPPDirectives: BeforeHash\nIndentWidth: 4\nNamespaceIndentation: None\nPackConstructorInitializers: Never\nPenaltyBreakString: 1000\nPenaltyExcessCharacter: 10000\nPenaltyReturnTypeOnItsOwnLine: 1000\nPointerAlignment: Left\nShortNamespaceLines: 200\nSortIncludes: false\nSpaceAfterTemplateKeyword: false\nSpaceBeforeAssignmentOperators: true\nSpaceBeforeParens: ControlStatements\nStandard: Cpp11\n...\n\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "content": "<!-- 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.\n\nThis 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/).\n\nIn general: Please provide as much information as you can to help us solving your problem -->\n\n## Summary\n\n<!--- Provide a general summary description of the issue -->\n\n## Expected Behavior\n\n<!--- If you're describing a bug, tell us what should happen -->\n<!--- If you're suggesting a change/improvement, tell us how it should work -->\n<!--- Feel free to use Given / When / Then if that helps, but please add some plain-language context too -->\n\n## Current Behavior\n\n<!--- If describing a bug, tell us what happens instead of the expected behavior -->\n<!--- If suggesting a change/improvement, explain the difference from current behavior -->\n\n<!--- If you have got some output place it in the code block below. Otherwise remove it. -->\n~~~\n~~~\n\n## Possible Solution\n\n<!--- Not obligatory, but suggest a fix/reason for the bug, -->\n<!--- or ideas how to implement the addition or change -->\n\n## Steps to Reproduce (for bugs)\n\n<!--- Provide a link to a live example, or an unambiguous set of steps to -->\n<!--- reproduce this bug. Include code to reproduce, if relevant -->\n1.\n2.\n3.\n4.\n\n## Context & Motivation\n\n<!--- How has this issue affected you? What are you trying to accomplish? -->\n<!--- Providing context helps us come up with a solution that is most useful in the real world -->\n\n## Your Environment\n\n<!--- If you're reporting a bug, include as many relevant details about the environment you experienced the bug in -->\n* Version used:\n* Operating System and version:\n* Link to your project:\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "<!-- These sections are meant as guidance for you. If something doesn't fit, you can just skip it. -->\n\n## Summary\n\n<!--- Provide a general summary description of your changes -->\n\n## Details\n\n<!--- Describe your changes in detail -->\n\n## Motivation and Context\n\n<!--- Why is this change required? What problem does it solve? -->\n<!--- If it fixes an open issue, please link to the issue here. -->\n\n## How Has This Been Tested?\n\n<!--- Please add tests for changes to the code, otherwise we probably won't merge it -->\n\n<!--- Please describe in detail how you tested your changes. -->\n<!--- Include details of your testing environment, tests ran to see how -->\n<!--- your change affects other areas of the code, etc. -->\n\n## Types of changes\n\n<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->\n- [ ] Bug fix (non-breaking change which fixes an issue).\n- [ ] New feature (non-breaking change which adds functionality).\n- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected).\n\n## Checklist:\n\n<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->\n<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->\n- [ ] 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.\n- [ ] I'm using the same code standards as the existing code (indentation, spacing, variable naming, ...).\n- [ ] I've added tests for my code.\n- [ ] I have verified whether my change requires changes to the documentation\n- [ ] My change either requires no documentation change or I've updated the documentation accordingly.\n- [ ] My branch has been rebased to main, keeping only relevant commits.\n"
  },
  {
    "path": ".github/workflows/format.yml",
    "content": "name: check format\n\npermissions: {}\n\non:\n  pull_request:\n    branches: [ main ]\n  workflow_dispatch:\n  push:\n    branches:\n      - main\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.head_ref || github.ref || github.run_id }}\n  cancel-in-progress: true\n\njobs:\n  build:\n    runs-on: ubuntu-22.04\n\n    steps:\n    - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n      with:\n        persist-credentials: false\n\n    - name: setup environment\n      run: |\n        sudo apt-get install --no-install-recommends \\\n        clang-format-15\n\n    - name: check code format\n      run: |\n        clang-format-15 --style=file --Werror --dry-run --verbose `find . -type d \\( -name '3rdparty' \\) -prune -o -regex '.*\\.\\(cpp\\|hpp\\)' -print`\n"
  },
  {
    "path": ".github/workflows/linux-build.yml",
    "content": "name: Linux build\n\npermissions: {}\n\non:\n  pull_request:\n    branches: [ main ]\n  workflow_dispatch:\n  push:\n    branches:\n      - main\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.head_ref || github.ref || github.run_id }}\n  cancel-in-progress: true\n\n\njobs:\n  build:\n    strategy:\n      matrix:\n        cpp-compiler:\n          - g++\n          - clang++-15\n        cpp-standard:\n          - 17\n          - 20\n\n    runs-on: ubuntu-22.04\n\n    steps:\n    - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n      with:\n        persist-credentials: false\n\n    - name: setup environment\n      run: |\n        sudo apt-get install --no-install-recommends \\\n          clang-15 \\\n          cmake \\\n          g++ \\\n          git \\\n          libasio-dev \\\n          libboost-test-dev \\\n          libgl1-mesa-dev \\\n          libtclap-dev \\\n          ninja-build \\\n          nlohmann-json3-dev \\\n          qt6-base-dev\n\n    - name: install gtest\n      run: |\n        git clone https://github.com/google/googletest.git\n        cd googletest\n        mkdir build\n        cd build\n        cmake \\\n          ..\n        cmake --build . --parallel\n        sudo cmake --install .\n\n    - name: build\n      run: |\n        cmake -E make_directory build\n        cmake -E chdir build cmake \\\n          -DCMAKE_CXX_COMPILER=${{ matrix.cpp-compiler }} \\\n          -DCMAKE_CXX_STANDARD=${{ matrix.cpp-standard }} \\\n          -G Ninja \\\n          -DCUKE_STRICT=on \\\n          -DCUKE_ENABLE_BOOST_TEST=on \\\n          -DCUKE_ENABLE_GTEST=on \\\n          -DCUKE_ENABLE_QT_6=on \\\n          -DCUKE_ENABLE_EXAMPLES=on \\\n          -DCUKE_TESTS_UNIT=on \\\n          ..\n        cmake --build build --parallel --verbose\n\n    - name: unit tests\n      run: |\n        cmake --build build --target test\n"
  },
  {
    "path": ".github/workflows/qt5.yml",
    "content": "name: build and test with Qt5\n\npermissions: {}\n\non:\n  pull_request:\n    branches: [ main ]\n  workflow_dispatch:\n  push:\n    branches:\n      - main\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.head_ref || github.ref || github.run_id }}\n  cancel-in-progress: true\n\njobs:\n  build:\n    runs-on: ubuntu-22.04\n\n    steps:\n    - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n      with:\n        persist-credentials: false\n\n    - name: setup environment\n      run: |\n        sudo apt-get install --no-install-recommends \\\n          cmake \\\n          g++ \\\n          git \\\n          libasio-dev \\\n          libboost-test-dev \\\n          libtclap-dev \\\n          ninja-build \\\n          nlohmann-json3-dev \\\n          qtbase5-dev \\\n          ruby \\\n          ruby-dev\n\n    - name: install ruby tools\n      run: |\n        sudo gem install bundler\n        sudo bundle install\n\n    - name: install gtest\n      run: |\n        git clone https://github.com/google/googletest.git\n        cd googletest\n        mkdir build\n        cd build\n        cmake ../\n        cmake --build . --parallel\n        sudo cmake --install .\n\n    - name: build\n      run: |\n        cmake -E make_directory build\n        cmake -E chdir build cmake \\\n          -G Ninja \\\n          -DCUKE_STRICT=on \\\n          -DCUKE_ENABLE_BOOST_TEST=on \\\n          -DCUKE_ENABLE_GTEST=on \\\n          -DCUKE_ENABLE_QT_5=on \\\n          -DCUKE_ENABLE_EXAMPLES=on \\\n          -DCUKE_TESTS_UNIT=on \\\n          ..\n        cmake --build build --parallel --verbose\n\n    - name: unit tests\n      run: |\n        cmake --build build --target test\n\n    - name: QtCalc examples\n      run: |\n        for TEST in \\\n          build/examples/CalcQt/GTestCalculatorQtSteps \\\n          build/examples/CalcQt/QtTestCalculatorQtSteps \\\n          build/examples/CalcQt/BoostCalculatorQtSteps \\\n        ; do\n          \"${TEST}\" 2> /dev/null &\n          sleep 1\n          (cd examples/CalcQt; cucumber)\n          wait %\n        done\n"
  },
  {
    "path": ".github/workflows/run-all.yml",
    "content": "name: run all\n\npermissions: {}\n\non:\n  pull_request:\n    branches: [ main ]\n  workflow_dispatch:\n  push:\n    branches:\n      - main\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.head_ref || github.ref || github.run_id }}\n  cancel-in-progress: true\n\njobs:\n  build-linux:\n    runs-on: ubuntu-22.04\n\n    steps:\n    - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n      with:\n        persist-credentials: false\n\n    - name: update package index\n      run: sudo apt-get -y update\n\n    - name: setup environment\n      run: |\n        sudo apt-get install --no-install-recommends \\\n          cmake \\\n          g++ \\\n          gcovr \\\n          git \\\n          libasio-dev \\\n          libboost-test-dev \\\n          libgl1-mesa-dev \\\n          libtclap-dev \\\n          ninja-build \\\n          nlohmann-json3-dev \\\n          qt6-base-dev \\\n          ruby \\\n          ruby-dev\n\n    - name: install ruby tools\n      run: |\n        sudo gem install bundler\n        sudo bundle install\n\n    - name: install gtest\n      run: |\n        git clone https://github.com/google/googletest.git\n        cd googletest\n        mkdir build\n        cd build\n        cmake ../\n        cmake --build . --parallel\n        sudo cmake --install .\n\n    - name: build and run\n      run: |\n        ./run-linux.sh\n\n    - name: code coverage summary report\n      uses: irongut/CodeCoverageSummary@51cc3a756ddcd398d447c044c02cb6aa83fdae95 #v1.3.0\n      with:\n        filename: coverage/cobertura.xml\n        indicators: false\n        hide_complexity: true\n        format: markdown\n        output: file\n\n    - name: publish code coverage summary\n      run: |\n        echo '# Code Coverage Report' >> $GITHUB_STEP_SUMMARY\n        cat code-coverage-results.md >> $GITHUB_STEP_SUMMARY\n"
  },
  {
    "path": ".github/workflows/windows-build.yml",
    "content": "name: Windows build\n\npermissions: {}\n\non:\n  pull_request:\n    branches: [ main ]\n  workflow_dispatch:\n  push:\n    branches:\n      - main\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.head_ref || github.ref || github.run_id }}\n  cancel-in-progress: true\n\njobs:\n  build:\n    strategy:\n      matrix:\n        cpp-standard:\n          - 17\n          - 20\n    # You can find specific tool versions for Windows builds in the Runner specification:\n    # https://github.com/actions/runner-images/blob/main/images/windows/Windows2022-Readme.md\n    # In particular, this build uses:\n    # cmake: 3.27.9\n    # VSCode: 2022 Enterprise Edition (corresponding C++ version: https://blog.knatten.org/2022/08/26/microsoft-c-versions-explained/)\n    # Ruby: 3.0.6p216\n    # boost: 1.82.0\n    runs-on: windows-2022\n    env:\n      BOOST_VERSION: 1.82.0\n      NLOHMANN_CLONE_DIR: nlohmann\n      NLOHMANN_TAG: v3.11.3\n      ASIO_CLONE_DIR: asio\n      ASIO_TAG: asio-1-29-0\n      TCLAP_CLONE_DIR: tclap\n      TCLAP_TAG: v1.2.5\n\n    steps:\n    - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n      with:\n        persist-credentials: false\n\n    - name: install ruby tools\n      run: |\n        gem install bundler\n        bundle install\n\n    # - name: Install Google Test\n    #   uses: MarkusJx/googletest-installer@v1.1\n\n    - name: Restore cached boost dependencies\n      id: cache-boost-deps\n      uses: actions/cache@6f8efc29b200d32929f49075959781ed54ec270c #v3.5.0\n      with:\n        path: |\n          boost_1_82_0\n        key: ${{ runner.os }}-boost-1820\n\n    - name: install boost\n      if: steps.cache-boost-deps.outputs.cache-hit != 'true'\n      run: |\n        $boost_version_str = ${Env:BOOST_VERSION}.Replace(\".\",\"_\")\n        $boost_url = \"https://archives.boost.io/release/${Env:BOOST_VERSION}/source/boost_${boost_version_str}.zip\"\n        $ProgressPreference = 'SilentlyContinue'\n        Write-Host \"Downloading Boost from $boost_url\"\n        Invoke-WebRequest -Uri $boost_url -OutFile boost_${boost_version_str}.zip\n        7z x boost_${boost_version_str}.zip\n        Write-Host \"Unzipped directory content:\"\n        Get-ChildItem -Directory\n        cd boost_${boost_version_str}\n        cmd /C bootstrap\n        ./b2.exe --build-type=complete toolset=msvc --with-regex --with-program_options --with-system --with-test\n\n    - name: Get and build nlohmann-json\n      run: |\n        Start-Process \"git\" -ArgumentList \"clone https://github.com/nlohmann/json.git $Env:NLOHMANN_CLONE_DIR --depth 1 --branch $Env:NLOHMANN_TAG\" -PassThru -NoNewWindow -Wait\n        cd $Env:NLOHMANN_CLONE_DIR\n        cmake -B build -S .\n        cd ..\n\n    - name: Get ASIO\n      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\n\n    - name: Get TCLAP\n      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\n\n    - name: build and run\n      run: |\n        $current_script_dir = Get-Location | Select-Object -Expand \"Path\"\n        $Env:nlohmann_json_DIR = \"${current_script_dir}/$Env:NLOHMANN_CLONE_DIR/build\"\n        $Env:Asio_ROOT = \"${current_script_dir}/$Env:ASIO_CLONE_DIR/asio\"\n        $Env:TCLAP_ROOT = \"${current_script_dir}/$Env:TCLAP_CLONE_DIR\"\n        $Env:cpp_standard = ${{ matrix.cpp-standard }}\n        ./run-windows.ps1\n"
  },
  {
    "path": ".github/workflows/zizmor-analysis.yaml",
    "content": "name: GitHub Actions Security Analysis\n\non:\n  push:\n    branches:\n      - main\n      - 'releases/**'\n    paths:\n      - '.github/**'\n  pull_request:\n    paths:\n      - '.github/**'\n\npermissions: {}\n\njobs:\n  zizmor:\n    name: Run Zizmor\n    runs-on: ubuntu-latest\n    permissions:\n      security-events: write\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          persist-credentials: false\n\n      - name: Run Zizmor\n        uses: zizmorcore/zizmor-action@71321a20a9ded102f6e9ce5718a2fcec2c4f70d8 # v0.5.2\n"
  },
  {
    "path": ".gitignore",
    "content": "# 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 files\n*.swp\n\n# CLion\n/.idea\n/cmake-build-*/\n\n# Qt Creator\n/CMakeLists.txt.user\n\n# build folder\nbuild\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "Please see [CONTRIBUTING.md](https://github.com/cucumber/cucumber/blob/main/CONTRIBUTING.md) on how to contribute to Cucumber.\n\n## [0.8.0](https://github.com/cucumber/cucumber-cpp/compare/v0.7.0...v0.8.0) (07 January 2026)\n\n### Added\n\n* Qt6 support ([#283](https://github.com/cucumber/cucumber-cpp/pull/283) Urs Fässler)\n* Windows CI support ([#288](https://github.com/cucumber/cucumber-cpp/pull/288) Christoph Wellm)\n* Test compilation with different compilers and language standards on Linux ([#282](https://github.com/cucumber/cucumber-cpp/pull/282) Urs Fässler)\n* Test to fail the build for deprecated asio features ([72e5fa9](https://github.com/cucumber/cucumber-cpp/commit/72e5fa9ff643d90a513bff57f7322606ecaf4270) Shirzart Enwer)\n\n### Changed\n\n* Only enable minimal set of CMake options by default ([#281](https://github.com/cucumber/cucumber-cpp/pull/281) Urs Fässler)\n* Use CMake option for strict checks ([#310](https://github.com/cucumber/cucumber-cpp/pull/310) Joerg Kreuzberger)\n* Only treat compilation warnings as error in CI ([#301](https://github.com/cucumber/cucumber-cpp/pull/301) Joerg Kreuzberger)\n* Remove support for Qt4 ([#283](https://github.com/cucumber/cucumber-cpp/pull/283) Urs Fässler)\n* CalcQt example improvements ([#283](https://github.com/cucumber/cucumber-cpp/pull/283) Urs Fässler)\n* Update README with explanation how it works ([#291](https://github.com/cucumber/cucumber-cpp/pull/291) erichstuder)\n* Adjust links and information regarding where to get help ([#306](https://github.com/cucumber/cucumber-cpp/pull/306) Joerg Kreuzberger)\n* Use https for all links in README ([0911bd2](https://github.com/cucumber/cucumber-cpp/commit/0911bd265bf0b484d5661f4163074714868cc77b) Joerg Kreuzberger)\n\n### Fixed\n\n* Support asio 1.33 ([#308](https://github.com/cucumber/cucumber-cpp/pull/308) Shirzart Enwer)\n* Boost download source fixed ([#309](https://github.com/cucumber/cucumber-cpp/pull/309) Shirzart Enwer)\n* Windows QtTestDriver ([#305](https://github.com/cucumber/cucumber-cpp/pull/305) Joerg Kreuzberger)\n* Flaky QtTestDriver test ([#296](https://github.com/cucumber/cucumber-cpp/pull/296) Joerg Kreuzberger)\n* Links to website and discussion group in README ([#299](https://github.com/cucumber/cucumber-cpp/pull/299) Joerg Kreuzberger)\n* Compile error with C++20 ([ea089a6](https://github.com/cucumber/cucumber-cpp/commit/ea089a6369641445dc52099298779cef6affdb8f) Urs Fässler)\n\n## [0.7.0](https://github.com/cucumber/cucumber-cpp/compare/v0.6...v0.7.0) (30 December 2023)\n\n### Added\n\n* add version info to cucumber-cpp-main ([8a0d16b8](https://github.com/cucumber/cucumber-cpp/pull/275/commits/8a0d16b8f59dd1c9d75045aa016d9ce235257311) Urs Fässler)\n* Remove dependency to Boost ([#275](https://github.com/cucumber/cucumber-cpp/pull/275) Urs Fässler)\n* List headers in cmake ([#274](https://github.com/cucumber/cucumber-cpp/pull/274) Urs Fässler)\n* Check code format on PR and main branch ([#268](https://github.com/cucumber/cucumber-cpp/pull/268) Urs Fässler)\n\n### Changed\n\n* use semantic versioning ([#280](https://github.com/cucumber/cucumber-cpp/pull/280) Urs Fässler)\n* No googletest auto-download ([#279](https://github.com/cucumber/cucumber-cpp/pull/279) Urs Fässler)\n* Remove dependency to Boost ([#275](https://github.com/cucumber/cucumber-cpp/pull/275) Urs Fässler)\n  * use asio without boost  ([d131ae39](https://github.com/cucumber/cucumber-cpp/pull/275/commits/d131ae3951b9aeb03dd787bf6fee4a06a81c1f04))\n  * use TCLAP to parse program options ([b688cf41](https://github.com/cucumber/cucumber-cpp/pull/275/commits/b688cf41647803daa8a7656595b0d1bcbabf2310))\n* use nlohmann/json library ([#273](https://github.com/cucumber/cucumber-cpp/pull/273) Urs Fässler)\n* remove boost::multi_array ([#269](https://github.com/cucumber/cucumber-cpp/pull/269) Urs Fässler)\n* Modernize overloading ([#267](https://github.com/cucumber/cucumber-cpp/pull/267) Urs Fässler)\n* refactoring: use stl regex instead of boost::regex ([#266](https://github.com/cucumber/cucumber-cpp/pull/266) Urs Fässler)\n\n### Fixed\n\n* mention CI scripts for details about dependency installation ([#278](https://github.com/cucumber/cucumber-cpp/pull/278) Urs Fässler)\n* remove broken E2E tests ([#272](https://github.com/cucumber/cucumber-cpp/pull/272) Urs Fässler)\n* remove broken AppVeyor build ([#271](https://github.com/cucumber/cucumber-cpp/pull/271) Urs Fässler)\n\n## [0.6](https://github.com/cucumber/cucumber-cpp/compare/v0.5...v0.6) (17 December 2023)\n\n### Added\n\n### Changed\n\n* Using C++ standard library where possible instead of boost ([#264](https://github.com/cucumber/cucumber-cpp/pull/264) Urs Fässler)\n\n### Fixed\n\n* Statically linking `boost_system` ([#197](https://github.com/cucumber/cucumber-cpp/pull/197) Matthieu Longo)\n* Unable to `add_subdirectory(cucumber-cpp)` ([#211](https://github.com/cucumber/cucumber-cpp/pull/211) Sergey Bon)\n* Warning C4265 on Visual Studio ([#195](https://github.com/cucumber/cucumber-cpp/pull/195) Matthieu Longo)\n* Fix handling of optional regex captures ([#221](https://github.com/cucumber/cucumber-cpp/pull/221) Alain Martin)\n* Fix compilation with Boost 1.70.0 ([#225](https://github.com/cucumber/cucumber-cpp/pull/225) Krystian Młynarczyk)\n* Support step definitions with multi-byte characters ([#224](https://github.com/cucumber/cucumber-cpp/pull/224) Spencer Rudnick)\n* Supress warning about deprecated QSignalMapper ([#228](https://github.com/cucumber/cucumber-cpp/pull/228) Lukas Woodtli)\n* Remove CACHE FORCE arguments from CMAKE_CXX_FLAG on colored terminal output ([#232](https://github.com/cucumber/cucumber-cpp/pull/232)  Alex Cani)\n* Enable compiling with clang's -Wsuggest-override ([#244](https://github.com/cucumber/cucumber-cpp/pull/244) Tobias Hahn)\n* Add posibility to build with sanitizers enabled ([#247](https://github.com/cucumber/cucumber-cpp/pull/247) Lukas Woodtli)\n* Add support for latest GoogleTest and Boost ([#249](https://github.com/cucumber/cucumber-cpp/pull/249) Canmor Lam)\n* add file extensions to adhere to policy CMP0115 ([#250](https://github.com/cucumber/cucumber-cpp/pull/250) Urs Fässler)\n* Support latest Qt and test on Ubuntu 22.04 ([#253](https://github.com/cucumber/cucumber-cpp/pull/253) Urs Fässler)\n* Update table.feature ([#258](https://github.com/cucumber/cucumber-cpp/pull/258) mbed101)\n\n## [0.5](https://github.com/cucumber/cucumber-cpp/compare/v0.4...v0.5) (2 July 2018)\n\n### Added\n\n* QtTest based test driver for cucumber-cpp ([#165](https://github.com/cucumber/cucumber-cpp/pull/165) Kamil Strzempowicz)\n* Listen on localhost by default to avoid firewall warnings ([#158](https://github.com/cucumber/cucumber-cpp/pull/158) Nik Reiman)\n* 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)\n* Support taking regex captures as arguments to the step definition's function ([#159](https://github.com/cucumber/cucumber-cpp/pull/159) Giel van Schijndel)\n* 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))\n* Support installing library targets along with headers ([#182](https://github.com/cucumber/cucumber-cpp/pull/182) [Matthieu](https://github.com/matlo607))\n\n### Changed\n\n* 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))\n\n### Fixed\n\n* 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))\n* Add missing virtual destructor in base class SocketServer used by TCPSocketServer and UnixSocketServer ([#183](https://github.com/cucumber/cucumber-cpp/pull/183) Matthieu Longo)\n* Fix breaking changes in API of boost-1.66.0 ([#180](https://github.com/cucumber/cucumber-cpp/pull/180)  Matthieu Longo)\n* Fix conflicting \"using std\" declaration with \"using boost::thread\" ([#181](https://github.com/cucumber/cucumber-cpp/pull/181)  Matthieu Longo)\n* Fix building with boost > 1.64 by adding 2 new methods to BoostLogInterceptor ([#175](https://github.com/cucumber/cucumber-cpp/pull/175) Kamil Strzempowicz)\n* Fixing Visual Studio 2013 error: no appropriate default constructor available ([#188](https://github.com/cucumber/cucumber-cpp/pull/188) Antoine Allard)\n* Fix issue #81 by intercepting messages from BOOST_*_MESSAGE macros ([#164](https://github.com/cucumber/cucumber-cpp/pull/164) Kamil Strzempowicz)\n* Allow running all GTest cases without filter separation ([#144](https://github.com/cucumber/cucumber-cpp/pull/144) Giel van Schijndel)\n* Fix QNX build by depending on standard C++ instead of specific implementation ([#156](https://github.com/cucumber/cucumber-cpp/issues/156) Giel van Schijndel)\n* 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)\n* Fix crash during termination of the CalcQt example's step definitions ([#62](https://github.com/cucumber/cucumber-cpp/issues/62) Giel van Schijndel)\n\n## [0.4](https://github.com/cucumber/cucumber-cpp/compare/v0.3.1...v0.4) (31 March 2017)\n\n### New Features\n\n* Support for MinGW build ([#130](https://github.com/cucumber/cucumber-cpp/pull/130) Michel Estermann)\n* Add support for Unix sockets ([#126](https://github.com/cucumber/cucumber-cpp/pull/126) Giel van Schijndel)\n* Add support for using ephemeral ports ([#131](https://github.com/cucumber/cucumber-cpp/pull/131) Giel van Schijndel)\n* Removed CppSpec support ([#118](https://github.com/cucumber/cucumber-cpp/pull/118) Paolo Ambrosio)\n* Support for GoogleTest 1.8 ([#120](https://github.com/cucumber/cucumber-cpp/pull/120) Kamil Strzempowicz)\n* Disable Nagle on TCP socket ([#125](https://github.com/cucumber/cucumber-cpp/pull/125) Giel van Schijndel)\n\n### Bugfixes\n\n* 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)\n* Fixed `defs.hpp` deprecation warning on MSVC ([#124](https://github.com/cucumber/cucumber-cpp/pull/124) Antoine Allard)\n* Fixed parallel build ([#135](https://github.com/cucumber/cucumber-cpp/pull/135) Giel van Schijndel)\n* Fixed memory leaks and better memory management ([#134](https://github.com/cucumber/cucumber-cpp/pull/134) Giel van Schijndel)\n* Fixed clang warning about bad `typeid` usage ([#138](https://github.com/cucumber/cucumber-cpp/pull/138) Kamil Strzempowicz)\n\n## [0.3.1](https://github.com/cucumber/cucumber-cpp/compare/v0.3...v0.3.1) (11 April 2016)\n\n### New Features\n\n* Support for Boost 1.60 ([#101](https://github.com/cucumber/cucumber-cpp/pull/101) Kai Unger)\n* Support for CMake inclusion in other projects ([#76](https://github.com/cucumber/cucumber-cpp/pull/76) Eric Brayet)\n* Added Qt5 support in CalcQt example ([#98](https://github.com/cucumber/cucumber-cpp/pull/98) Kamil Strzempowicz)\n* Improved Generic Driver to write steps without testing framework ([#99](https://github.com/cucumber/cucumber-cpp/pull/99) Kamil Strzempowicz)\n\n### Bugfixes\n\nNone\n\n## [0.3](https://github.com/cucumber/cucumber-cpp/compare/v0.2...v0.3) (22 December 2013)\n\n### New Features\n\n* Added BEFORE_ALL and AFTER_ALL macros ([#65](https://github.com/cucumber/cucumber-cpp/pull/65) Larry Price)\n* Added CalcQt example ([#58](https://github.com/cucumber/cucumber-cpp/pull/58) Gianni Ambrosio)\n* Replaced USING_CONTEXT with ScenarioScope<T> ([27256e9](https://github.com/cucumber/cucumber-cpp/commit/27256e932c75e9d4d57d4839042317e6a04cfe46) Paolo Ambrosio)\n* Changed include name from core.hpp to defs.hpp ([5bbac06](https://github.com/cucumber/cucumber-cpp/commit/5bbac062e19dcf9de2761f4ded115aa7212c14d7) Paolo Ambrosio)\n* Project rename from CukeBins to Cucumber-Cpp ([efecfd0](https://github.com/cucumber/cucumber-cpp/commit/efecfd0813efa1b6d406c2fd0cd03d8a84bed3ff) Paolo Ambrosio)\n\n### Bugfixes\n\n* 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)\n* Fixed crashes on some architectures ([#52](https://github.com/cucumber/cucumber-cpp/pull/52) Sabst)\n* Fixed AFTER hook ordering issue ([#43](https://github.com/cucumber/cucumber-cpp/pull/43) Greg Williams)\n* Added default empty constructor to work with less permissive gcc 4.6 settings ([#38](https://github.com/cucumber/cucumber-cpp/pull/38) Hugo Ferreira)\n\n\n## [0.2](https://github.com/cucumber/cucumber-cpp/compare/v0.1...v0.2) (25 June 2011)\n\nTODO\n\n\n## [0.1](https://github.com/cucumber/cucumber-cpp/commits/v0.1) (03 May 2010)\n\n* Initial implementation\n\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\n\ncmake_policy(SET CMP0063 NEW)\n\n# CMP0077: option() honors normal variables\n# https://cmake.org/cmake/help/latest/policy/CMP0077.html\ncmake_policy(SET CMP0077 NEW)\n\n# CMP0074: find_package() makes use of <PackageName>_ROOT variables\n# https://cmake.org/cmake/help/latest/policy/CMP0074.html\ncmake_policy(SET CMP0074 NEW)\n\nproject(Cucumber-Cpp)\n\noption(CUKE_ENABLE_BOOST_TEST   \"Enable Boost.Test framework\" OFF)\noption(CUKE_ENABLE_GTEST        \"Enable Google Test framework\" OFF)\noption(CUKE_ENABLE_QT_5         \"Enable Qt5 framework\" OFF)\noption(CUKE_ENABLE_QT_6         \"Enable Qt6 framework\" OFF)\n\noption(CUKE_ENABLE_EXAMPLES     \"Build examples\" OFF)\noption(CUKE_TESTS_UNIT          \"Enable unit tests\" OFF)\n\noption(BUILD_SHARED_LIBS        \"Generate shared libraries\" OFF)\noption(CUKE_CODE_COVERAGE       \"Enable instrumentation for code coverage\" OFF)\nset(CUKE_ENABLE_SANITIZER       \"OFF\" CACHE STRING \"Sanitizer to use for checking\")\nset_property(CACHE CUKE_ENABLE_SANITIZER PROPERTY STRINGS OFF \"address\" \"thread\" \"undefined\")\noption(CUKE_TESTS_VALGRIND      \"Enable tests within Valgrind\" OFF)\noption(CUKE_STRICT              \"Additional and more strict checks\" OFF)\n\nif(NOT DEFINED CMAKE_CXX_STANDARD)\n    set(CMAKE_CXX_STANDARD 17)\n    set(CMAKE_CXX_STANDARD_REQUIRED ON)\n    set(CMAKE_CXX_EXTENSIONS OFF)\nelseif(CMAKE_CXX_STANDARD LESS 17)\n    message(FATAL_ERROR \"C++17 (above) is required\")\nendif()\n\nif(CUKE_CODE_COVERAGE)\n    set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} --coverage\")\nendif()\n\nif(CUKE_STRICT)\n    set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -Werror\")\n    set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -DASIO_NO_DEPRECATED\")\nendif()\n\nset(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/modules)\n\n#\n# Option deprecation: if deprecated option is defined\n# then print a warning and use its value instead\n#\n\nfunction(option_depr_message old prefer)\n    message (DEPRECATION \"${old} is deprecated in favor of ${prefer}\")\nendfunction()\n\nfunction(option_depr old prefer)\n    if(DEFINED ${old})\n        option_depr_message(${old} ${prefer})\n        set (${prefer} ${${old}} CACHE BOOL \"Set from deprecated ${old}\" FORCE)\n    endif()\nendfunction()\n\nfunction(option_depr_invert old prefer)\n    if(DEFINED ${old})\n        option_depr_message(${old} ${prefer})\n        set (${prefer} $<NOT:${${old}}> CACHE BOOL \"Set from deprecated ${old}\" FORCE)\n    endif()\nendfunction()\n\n\noption_depr_invert (CUKE_DISABLE_BOOST_TEST   CUKE_ENABLE_BOOST_TEST)\noption_depr_invert (CUKE_DISABLE_GTEST        CUKE_ENABLE_GTEST)\noption_depr_invert (CUKE_DISABLE_QT_5         CUKE_ENABLE_QT_5)\noption_depr_invert (CUKE_DISABLE_QT_6         CUKE_ENABLE_QT_6)\noption_depr_invert (CUKE_DISABLE_UNIT_TESTS   CUKE_TESTS_UNIT)\noption_depr        (VALGRIND_TESTS            CUKE_TESTS_VALGRIND)\n\n#\n# Check that at least one test framework is enabled\n#\n\nset(CUKE_TEST_FRAMEWORKS\n    CUKE_ENABLE_BOOST_TEST\n    CUKE_ENABLE_GTEST\n    CUKE_ENABLE_QT_5\n    CUKE_ENABLE_QT_6\n)\n\nset(TEST_FRAMEWORK_FOUND FALSE)\nforeach(test_framework ${CUKE_TEST_FRAMEWORKS})\n    if(${test_framework})\n        set(TEST_FRAMEWORK_FOUND TRUE)\n    endif()\nendforeach()\n\nif(NOT TEST_FRAMEWORK_FOUND)\n    message(WARNING \"No test framework enabled. At least one should be enabled. Options are: ${CUKE_TEST_FRAMEWORKS}.\")\nendif()\n\n#\n# Generic Compiler Flags\n#\n\nif(CMAKE_CXX_COMPILER_ID MATCHES \"Clang|GNU\")\n    set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS_INIT} -Wall -Wextra -Wsuggest-override ${CMAKE_CXX_FLAGS}\")\n    # TODO: A better fix should handle ld's --as-needed flag\n    if(UNIX AND NOT APPLE)\n        set(CMAKE_EXE_LINKER_FLAGS \"${CMAKE_EXE_LINKER_FLAGS} -Xlinker '--no-as-needed'\")\n    endif()\nelseif(MSVC)\n    set(CMAKE_CXX_FLAGS \"-DNOMINMAX ${CMAKE_CXX_FLAGS}\") # exclude M$ min/max macros\n    set(CMAKE_CXX_FLAGS \"/wd4996 ${CMAKE_CXX_FLAGS}\") # don't warn about use of plain C functions without (non-portable) \"_s\" suffix\n    #set(CMAKE_CXX_FLAGS_DEBUG \"/analyze ${CMAKE_CXX_FLAGS_DEBUG}\")\nendif()\n\n#\n# Colored Terminal Output\n#\n\nif(UNIX AND (\n       (CMAKE_CXX_COMPILER_ID MATCHES \"Clang\")\n    OR (CMAKE_CXX_COMPILER_ID STREQUAL \"GNU\" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9))\n    AND CMAKE_GENERATOR STREQUAL \"Ninja\")\n  # These compilers generate coloured output, but by default only when their output channel is a\n  # terminal (TTY/PTY). Ninja however captures all output in a pipe (per-subprocess), disabling\n  # coloured compiler diagnostics. We forcefully enable it because Ninja, since 1.0.0\n  # (ninja-build/ninja#198) takes care to strip VT100 CSI control sequences from the output if Ninja\n  # itself is writing to a pipe instead of a terminal. As a result this should give us the best of\n  # both worlds: coloured output when we're running in a terminal, plain output for editors, IDEs,\n  # etc.\n  set(CMAKE_CXX_FLAGS \"-fdiagnostics-color=always ${CMAKE_CXX_FLAGS}\")\nendif()\n\n#\n# Boost\n#\n\nset(Boost_USE_STATIC_RUNTIME OFF)\nif(CUKE_ENABLE_BOOST_TEST)\n    # \"An external test runner utility is required to link with dynamic library\" (Boost User's Guide)\n    set(CMAKE_CXX_FLAGS \"-DBOOST_TEST_DYN_LINK ${CMAKE_CXX_FLAGS}\")\n    find_package(Boost 1.70 COMPONENTS unit_test_framework REQUIRED)\nendif()\n\n#\n# GTest\n#\n\nif(CUKE_ENABLE_GTEST)\n    find_package(GTest 1.11.0 REQUIRED)\nendif()\n\n#\n# Qt\n#\n\nif(CUKE_ENABLE_QT_5 AND CUKE_ENABLE_QT_6)\n    message(FATAL_ERROR \"Qt version 5 and 6 enabled, please select at most one\")\nendif()\n\n\nif(CUKE_ENABLE_QT_5)\n    find_package(Qt5 REQUIRED COMPONENTS\n        Core\n        Gui\n        Widgets\n        Test\n    )\n\n    message(STATUS \"Found Qt version: ${Qt5Core_VERSION_STRING}\")\n    if(Qt5Core_VERSION_STRING VERSION_LESS 5.15.0)\n        add_library(Qt::Core    INTERFACE IMPORTED)\n        add_library(Qt::Gui     INTERFACE IMPORTED)\n        add_library(Qt::Widgets INTERFACE IMPORTED)\n        add_library(Qt::Test    INTERFACE IMPORTED)\n        set_target_properties(Qt::Core    PROPERTIES INTERFACE_LINK_LIBRARIES Qt5::Core   )\n        set_target_properties(Qt::Gui     PROPERTIES INTERFACE_LINK_LIBRARIES Qt5::Gui    )\n        set_target_properties(Qt::Widgets PROPERTIES INTERFACE_LINK_LIBRARIES Qt5::Widgets)\n        set_target_properties(Qt::Test    PROPERTIES INTERFACE_LINK_LIBRARIES Qt5::Test   )\n    endif()\nendif()\n\nif(CUKE_ENABLE_QT_6)\n    find_package(Qt6 REQUIRED COMPONENTS\n        Core\n        Gui\n        Widgets\n        Test\n    )\n\n    message(STATUS \"Found Qt version: ${Qt6Core_VERSION}\")\nendif()\n\n\n#\n# Sanitizers\n#\n\nif(CUKE_ENABLE_SANITIZER AND NOT ${CUKE_ENABLE_SANITIZER} EQUAL \"OFF\")\n    message(\"Disabling valgrind when a sanitizer is enabled\")\n    set(CUKE_TESTS_VALGRIND OFF)\n\n    if (WIN32)\n        message(WARNING \"The use of the sanatizers on Windows is not tested\")\n    endif()\n\n    add_compile_options(\"-fsanitize=${CUKE_ENABLE_SANITIZER}\")\n    add_link_options(\"-fsanitize=${CUKE_ENABLE_SANITIZER}\")\nendif()\n\n\n\n#\n# Valgrind\n#\n\nif(CUKE_TESTS_VALGRIND)\n    find_package(Valgrind REQUIRED)\n    set(VALGRIND_ARGS --error-exitcode=2 --leak-check=full --undef-value-errors=no)\n    if(NOT VALGRIND_VERSION_STRING VERSION_LESS 3.9)\n        # Valgrind 3.9 no longer shows all leaks unless asked to\n        list(APPEND VALGRIND_ARGS --show-leak-kinds=all)\n    endif()\n    function(add_test name)\n        if(NOT name STREQUAL \"NAME\")\n            _add_test(${VALGRIND_EXECUTABLE} ${VALGRIND_ARGS} ${ARGV})\n            return()\n        endif()\n\n        set(TEST_ARGS ${ARGV})\n        list(FIND TEST_ARGS COMMAND COMMAND_IDX)\n        if(COMMAND_IDX EQUAL -1)\n            message(AUTHOR_WARNING \"Weird command-line given to add_test(), not injecting valgrind\")\n            _add_test(${ARGV})\n            return()\n        endif()\n\n        # We want to operate on the COMMAND, not the 'COMMAND' keyword preceding it\n        math(EXPR COMMAND_IDX \"${COMMAND_IDX} + 1\")\n\n        # Keep add_test() behaviour of replacing COMMANDs, when executable targets, with their output files\n        list(GET TEST_ARGS ${COMMAND_IDX} COMMAND)\n        if(TARGET ${COMMAND})\n            get_target_property(COMMAND_TYPE ${COMMAND} TYPE)\n            if(COMMAND_TYPE STREQUAL \"EXECUTABLE\")\n                # Inserting first, removing the original only after that, because inserting to the end of the list doesn't work\n                math(EXPR ORIG_COMMAND_IDX \"${COMMAND_IDX} + 1\")\n                list(INSERT TEST_ARGS ${COMMAND_IDX} \"$<TARGET_FILE:${COMMAND}>\")\n                list(REMOVE_AT TEST_ARGS ${ORIG_COMMAND_IDX})\n            endif()\n        endif()\n\n        # Insert the valgrind command line, before the command to execute\n        list(INSERT TEST_ARGS ${COMMAND_IDX} ${VALGRIND_EXECUTABLE} ${VALGRIND_ARGS})\n\n        _add_test(${TEST_ARGS})\n    endfunction()\nendif()\n\n#\n# Cucumber-Cpp\n#\n\nset(CUKE_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include)\nadd_subdirectory(src)\n\n#\n# Tests\n#\n\nif(CUKE_TESTS_UNIT)\n    enable_testing()\n    add_subdirectory(tests)\nelse()\n    message(STATUS \"Skipping unit tests\")\nendif()\n\n#\n# Examples\n#\n\nif(CUKE_ENABLE_EXAMPLES)\n    add_subdirectory(examples)\nendif()\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "## About to create a new Github Issue?\n\nWe appreciate that. But before you do, please learn our basic rules:\n\n* 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).\n* 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.\n* 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.\n* 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.\n* 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.\n\n## Contributing\n\nBefore you can contribute, you have to be able to build the source and run tests.\n\n### The Github Process\n\nThe process for using git/github is similar to the [Github-Flow](http://scottchacon.com/2011/08/31/github-flow.html)\n\n* **Anything** in the main branch is good enough to release\n* Working on nontrivial features\n    + Create a descriptively named branch off of main\n    + Commit to that branch locally and regularly\n    + Push your work to the same named branch on the server\n    + Regularly rebase this branch from main to keep it up to date\n* Open a pull request\n    + When you need feedback or help\n    + You think the branch is ready for merging (you can use the [hub](https://github.com/defunkt/hub#git-pull-request) command-line tool)\n* 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\n\nHere is an [Example](https://github.com/cucumber/bool/pull/12) of this process in action\n\n#### Tips for good commits\n\n1. Read up on [Github Flavored Markdown](https://help.github.com/articles/github-flavored-markdown)\n    + 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\n2. Close tickets with commits if you can\n    + 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.\n    + Use [this script](https://gist.github.com/aslakhellesoy/4754009) to compile and view GFM locally\n3. Subscribe to ticket feeds so you stay in the loop and get a chance to provide feedback on tickets\n4. The code standard is the existing code\n    + Use the same indentation, spacing, line ending, ASCII for source code, UTF-8 everywhere else\n5. Use git diff (or git diff --cached if you have staged) before every commit\n    + This helps you avoid committing changes you didn't mean to\n\n## Maintainers' guide\n\n### Merge a PR\n\n- Verify that:\n  - All checks have passed\n  - At least one maintainer has approved any non-trivial change, and a\n    discussion has occurred for any breaking change\n  - The branch does not need rebasing or squashing of commits\n- To merge:\n  - Follow the command line instructions on GitHub\n  - If it is either a new feature or a bugfix, specify the `--no-commit`\n    flag when merging and add a line to `CHANGELOG.md` following the\n    current convention. Add this file to the changes to be committed and\n    commit the merge.\n  - Commit message should follow the current convention:\n    `Merge #42 'Description of the change usually from the PR description'`\n\n### Do a release\n\n- Release commit (e.g. [fdf8a5c](https://github.com/cucumber/cucumber-cpp/commit/fdf8a5c4ef4c51dfa7ea82077f706414a4c6322d)):\n  - Change `CHANGELOG.md` renaming the \"In Git\" section with the release number and date\n  - Commit with message `Update changelog for the X.Y.Z release`\n  - Create an annotated tag for this commit named `vX.Y.Z`\n- New development branch commit (e.g. [da60995](https://github.com/cucumber/cucumber-cpp/commit/da609956fcd42046e5182c6226acd7e53dd7754e)):\n  - Add new \"In Git\" section to `CHANGELOG.md`\n  - Commit with message `Preparing history file for next development release`\n- Push commits and tags to main\n"
  },
  {
    "path": "Gemfile",
    "content": "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",
    "content": "MIT License\n\nCopyright (c) 2010 Paolo Ambrosio\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Cucumber-CPP\n\n## Overview\n\nCucumber-Cpp allows Cucumber to support step definitions written in C++.\n\n* [Cucumber-Cpp Website](https://github.com/cucumber/cucumber-cpp)\n* [Cucumber-Cpp Documentation](https://github.com/cucumber/cucumber-cpp/wiki/)\n* [Cucumber Website](https://cucumber.io/)\n* [Get in touch](https://cucumber.io/docs/community/get-in-touch/)\n\nIf you need to ask a question, post on the [Cucumber discussion group](https://github.com/orgs/cucumber/discussions).\n\nIf you want to contribute code to the project, guidelines are in [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## Dependencies\n\nIt relies on a few executables:\n\n* [cmake](https://cmake.org/download/) 3.16 or later.\n  Required to setup environment and build software\n\nIt relies on a few libraries:\n\n* [Asio](https://think-async.com/Asio/) 1.18.1 or later.\n* [Boost.Test](https://www.boost.org/) 1.70. Optional for the Boost Test driver.\n* [GTest](https://github.com/google/googletest) 1.11.0 or later. Optional for the GTest driver.\n* [GMock](https://github.com/google/googletest) 1.11.0 or later. Optional for the internal test suite.\n* [nlohmann-json](https://github.com/nlohmann/json) 3.10.5 or later.\n* [Qt6 or Qt5](https://qt-project.org/). Optional for the CalcQt example and QtTest driver.\n* [TCLAP](https://tclap.sourceforge.net/) 1.2.5 or later.\n\nIt might work with earlier versions of the libraries, but it was not tested with them.\nSee the [CI scripts](.github/workflows/run-all.yml) for details about dependency installation.\n\nCucumber-Cpp uses the wire protocol at the moment, so you will need\nCucumber-Ruby installed and available on the path. It is also needed\nto run the functional test suite.\n\nPlease mind that Cucumber-Cpp is not compatible with Cucumber-Ruby 3.x\ndue to a [bug in its wire protocol](https://github.com/cucumber/cucumber-ruby/issues/1183)\nimplementation.\n\nTo install the Ruby prerequisites:\n\n```\ngem install bundler // For windows: gem install bundle\nbundle install\n```\n\n### Windows vs. Linux\n\nTo 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\nworkflow files [for Windows](.github/workflows/windows-build.yml) and [for Linux](.github/workflows/linux-build.yml).\n\n\n## Build\n\nBuilding Cucumber-Cpp with tests and samples:\n\n```\n# Create build directory\ncmake -E make_directory build\n\n# Generate Makefiles\ncmake -E chdir build cmake \\\n    -DCUKE_ENABLE_BOOST_TEST=on \\\n    -DCUKE_ENABLE_GTEST=on \\\n    -DCUKE_ENABLE_QT_6=on \\\n    -DCUKE_TESTS_UNIT=on \\\n    -DCUKE_ENABLE_EXAMPLES=on \\\n    ..\n\n# Build cucumber-cpp\ncmake --build build\n\n# Run unit tests\ncmake --build build --target test\n\n# Run install\ncmake --install build\n```\n\nRunning the Calc example on Unix:\n\n```\nbuild/examples/Calc/BoostCalculatorSteps >/dev/null &\n(cd examples/Calc; cucumber)\n```\n\nRunning the Calc example on Windows (NMake):\n\n```\nstart build\\examples\\Calc\\BoostCalculatorSteps.exe\ncucumber examples\\Calc\n```\n\n## The way it works\n(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))\n\nThe 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.\n\nC++ 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).\n\n```\n                    +------------------------------------------+\n                    |                                          |\n+----------+        | +----------+  +----------+  +----------+ |\n|          |        | |          |  |          |  |          | |\n| Cucumber |        | | Cucumber |  | C++ Step |  | Your     | |\n| Ruby     |--------->| CPP Wire |--| Defs     |--| CPP App  | |\n|          |        | | Server   |  |          |  |          | |\n|          |        | |          |  |          |  |          | |\n+----------+        | +----------+  +----------+  +----------+ |\n                    |                                          |\n                    +------------------------------------------+\n```\n\n## Getting started\n\nHere is a basic example on how to get started with *cucumber-cpp*. First you need to create the basic feature structure:\n\n```\ncucumber --init\n```\n\nThen create a *cucumber.wire* file in the *features/step_definitions* folder with the following content:\n\n```\nhost: localhost\nport: 3902\n```\n\nCreate your first feature (an example is available [here](examples/Calc/features/addition.feature)).\n\nThen 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).\n\nRun 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.\n"
  },
  {
    "path": "cmake/modules/FindAsio.cmake",
    "content": "find_path(ASIO_INCLUDE_DIR asio.hpp)\n\nif (ASIO_INCLUDE_DIR)\n    set(ASIO_FOUND TRUE)\nelse ()\n    set(ASIO_FOUND FALSE)\nendif ()\n\ninclude(FindPackageHandleStandardArgs)\nFIND_PACKAGE_HANDLE_STANDARD_ARGS(Asio REQUIRED_VARS ASIO_INCLUDE_DIR)\n"
  },
  {
    "path": "cmake/modules/FindTCLAP.cmake",
    "content": "find_path(TCLAP_INCLUDE_DIR tclap/CmdLine.h)\n\nif (TCLAP_INCLUDE_DIR)\n    set(TCLAP_FOUND TRUE)\nelse ()\n    set(TCLAP_FOUND FALSE)\nendif ()\n\ninclude(FindPackageHandleStandardArgs)\nFIND_PACKAGE_HANDLE_STANDARD_ARGS(TCLAP REQUIRED_VARS TCLAP_INCLUDE_DIR)\n"
  },
  {
    "path": "cmake/modules/FindValgrind.cmake",
    "content": "#.rst:\n# FindValgrind\n# -------\n#\n# The module defines the following variables:\n#\n# ``VALGRIND_EXECUTABLE``\n#   Path to Valgrind command-line client.\n# ``Valgrind_FOUND``\n#   True if the Valgrind command-line client was found.\n# ``VALGRIND_VERSION_STRING``\n#   The version of Valgrind found.\n#\n# Example usage:\n#\n# .. code-block:: cmake\n#\n#    find_package(Valgrind)\n#    if(Valgrind_FOUND)\n#      message(\"Valgrind found: ${VALGRIND_EXECUTABLE}\")\n#    endif()\n\n#=============================================================================\n# Copyright (c) 2017 Giel van Schijndel\n#\n# CMake - Cross Platform Makefile Generator\n# All rights reserved.\n#\n# Redistribution and use in source and binary forms, with or without\n# modification, are permitted provided that the following conditions\n# are met:\n#\n# * Redistributions of source code must retain the above copyright\n#   notice, this list of conditions and the following disclaimer.\n#\n# * Redistributions in binary form must reproduce the above copyright\n#   notice, this list of conditions and the following disclaimer in the\n#   documentation and/or other materials provided with the distribution.\n#\n# * Neither the names of Kitware, Inc., the Insight Software Consortium,\n#   nor the names of their contributors may be used to endorse or promote\n#   products derived from this software without specific prior written\n#   permission.\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n# \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n#\n# ------------------------------------------------------------------------------\n#\n# The above copyright and license notice applies to distributions of\n# CMake in source and binary form.  Some source files contain additional\n# notices of original copyright by their contributors; see each source\n# for details.  Third-party software packages supplied with CMake under\n# compatible licenses provide their own copyright notices documented in\n# corresponding subdirectories.\n#\n# ------------------------------------------------------------------------------\n#\n# CMake was initially developed by Kitware with the following sponsorship:\n#\n#  * National Library of Medicine at the National Institutes of Health\n#    as part of the Insight Segmentation and Registration Toolkit (ITK).\n#\n#  * US National Labs (Los Alamos, Livermore, Sandia) ASC Parallel\n#    Visualization Initiative.\n#\n#  * National Alliance for Medical Image Computing (NAMIC) is funded by the\n#    National Institutes of Health through the NIH Roadmap for Medical Research,\n#    Grant U54 EB005149.\n#\n#  * Kitware, Inc.\n#=============================================================================\n\nfind_program(VALGRIND_EXECUTABLE\n  NAMES valgrind\n  DOC \"Valgrind command line executable\"\n)\nmark_as_advanced(VALGRIND_EXECUTABLE)\n\nif(VALGRIND_EXECUTABLE)\n    execute_process(COMMAND ${VALGRIND_EXECUTABLE} --version\n                    OUTPUT_VARIABLE VALGRIND_VERSION_STRING\n                    ERROR_QUIET\n                    OUTPUT_STRIP_TRAILING_WHITESPACE)\n    if (VALGRIND_VERSION_STRING MATCHES \"^valgrind-[0-9]\")\n        string(REPLACE \"valgrind-\" \"\" VALGRIND_VERSION_STRING \"${VALGRIND_VERSION_STRING}\")\n    endif()\nendif()\n\ninclude(FindPackageHandleStandardArgs)\nfind_package_handle_standard_args(Valgrind\n                                  REQUIRED_VARS VALGRIND_EXECUTABLE\n                                  VERSION_VAR VALGRIND_VERSION_STRING)\n"
  },
  {
    "path": "cmake/modules/GitVersion.cmake",
    "content": "function(git_get_version VERSION_VARIABLE)\n    find_program(GIT_EXECUTABLE git)\n\n    if(NOT GIT_EXECUTABLE)\n        message(FATAL_ERROR \"Git not found. Please install Git and make sure it is in your system's PATH.\")\n    endif()\n\n    execute_process(\n        COMMAND ${GIT_EXECUTABLE} describe --always --dirty\n        OUTPUT_VARIABLE VERSION_STRING\n        OUTPUT_STRIP_TRAILING_WHITESPACE\n        WORKING_DIRECTORY \"${PROJECT_SOURCE_DIR}\"\n        ERROR_VARIABLE GIT_DESCRIBE_ERROR\n        RESULT_VARIABLE GIT_DESCRIBE_RESULT\n    )\n\n    if(NOT GIT_DESCRIBE_RESULT EQUAL 0)\n        message(FATAL_ERROR \"Error running 'git describe': ${GIT_DESCRIBE_ERROR}\")\n    endif()\n\n    string(LENGTH \"${VERSION_STRING}\" VERSION_STRING_LENGTH)\n    string(SUBSTRING \"${VERSION_STRING}\" 0 1 FIRST_CHARACTER)\n\n    if(\"${FIRST_CHARACTER}\" STREQUAL \"v\")\n        string(SUBSTRING \"${VERSION_STRING}\" 1 ${VERSION_STRING_LENGTH} VERSION_STRING)\n    endif()\n\n    set(${VERSION_VARIABLE} ${VERSION_STRING} PARENT_SCOPE)\nendfunction()\n"
  },
  {
    "path": "examples/CMakeLists.txt",
    "content": "add_subdirectory(Calc)\nadd_subdirectory(CalcQt)\nadd_subdirectory(FeatureShowcase)\n"
  },
  {
    "path": "examples/Calc/CMakeLists.txt",
    "content": "project(Calc)\n\nadd_library(Calc STATIC src/Calculator.cpp)\ntarget_include_directories(Calc INTERFACE src)\n\nif(TARGET GTest::gtest)\n    add_executable(GTestCalculatorSteps features/step_definitions/GTestCalculatorSteps.cpp)\n    target_link_libraries(GTestCalculatorSteps PRIVATE Calc cucumber-cpp GTest::gtest)\n\n    add_executable(FuncArgsCalculatorSteps features/step_definitions/FuncArgsCalculatorSteps.cpp)\n    target_link_libraries(FuncArgsCalculatorSteps PRIVATE Calc cucumber-cpp GTest::gtest)\nendif()\n\nif(TARGET Boost::unit_test_framework)\n    add_executable(BoostCalculatorSteps features/step_definitions/BoostCalculatorSteps.cpp)\n    target_link_libraries(BoostCalculatorSteps PRIVATE Calc cucumber-cpp Boost::unit_test_framework)\nendif()\n\nif(TARGET Qt::Test)\n    add_executable(QtTestCalculatorSteps features/step_definitions/QtTestCalculatorSteps.cpp)\n    target_link_libraries(QtTestCalculatorSteps Calc Qt::Test cucumber-cpp)\nendif()\n"
  },
  {
    "path": "examples/Calc/README.txt",
    "content": "This was inspired by Cuke4Nuke Calc sample\n\n"
  },
  {
    "path": "examples/Calc/features/addition.feature",
    "content": "# 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 two numbers\n\n  Scenario Outline: Add two numbers\n    Given I have entered <input_1> into the calculator\n    And I have entered <input_2> into the calculator\n    When I press <button>\n    Then the result should be <output> on the screen\n\n  Examples:\n    | input_1 | input_2 | button | output |\n    | 20      | 30      | add    | 50     |\n    | 2       | 5       | add    | 7      |\n    | 0       | 40      | add    | 40     |\n"
  },
  {
    "path": "examples/Calc/features/division.feature",
    "content": "# language: en\nFeature: Division\n  In order to avoid silly mistakes\n  Cashiers must be able to calculate a fraction\n\n  Scenario: Regular numbers\n    Given I have entered 3 into the calculator\n    And I have entered 2 into the calculator\n    When I press divide\n    Then the result should be 1.5 on the screen\n"
  },
  {
    "path": "examples/Calc/features/step_definitions/BoostCalculatorSteps.cpp",
    "content": "#include <boost/test/unit_test.hpp>\n// Pretend to be GTest\n#define EXPECT_EQ BOOST_CHECK_EQUAL\n#include \"CalculatorSteps.cpp\"\n"
  },
  {
    "path": "examples/Calc/features/step_definitions/CalculatorSteps.cpp",
    "content": "#include <cucumber-cpp/autodetect.hpp>\n\n#include <Calculator.hpp>\n\nusing cucumber::ScenarioScope;\n\nstruct CalcCtx {\n    Calculator calc;\n    double result;\n};\n\nGIVEN(\"^I have entered (\\\\d+) into the calculator$\") {\n    REGEX_PARAM(double, n);\n    ScenarioScope<CalcCtx> context;\n\n    context->calc.push(n);\n}\n\nWHEN(\"^I press add\") {\n    ScenarioScope<CalcCtx> context;\n\n    context->result = context->calc.add();\n}\n\nWHEN(\"^I press divide\") {\n    ScenarioScope<CalcCtx> context;\n\n    context->result = context->calc.divide();\n}\n\nTHEN(\"^the result should be (.*) on the screen$\") {\n    REGEX_PARAM(double, expected);\n    ScenarioScope<CalcCtx> context;\n\n    EXPECT_EQ(expected, context->result);\n}\n"
  },
  {
    "path": "examples/Calc/features/step_definitions/FuncArgsCalculatorSteps.cpp",
    "content": "#include <gtest/gtest.h>\n#include <cucumber-cpp/autodetect.hpp>\n\n#include <Calculator.hpp>\n\nusing cucumber::ScenarioScope;\n\nstruct CalcCtx {\n    Calculator calc;\n    double result;\n};\n\nGIVEN(\"^I have entered (\\\\d+) into the calculator$\", (const double n)) {\n    ScenarioScope<CalcCtx> context;\n\n    context->calc.push(n);\n}\n\nWHEN(\"^I press add\") {\n    ScenarioScope<CalcCtx> context;\n\n    context->result = context->calc.add();\n}\n\nWHEN(\"^I press divide\") {\n    ScenarioScope<CalcCtx> context;\n\n    context->result = context->calc.divide();\n}\n\nTHEN(\"^the result should be (.*) on the screen$\", (const double expected)) {\n    ScenarioScope<CalcCtx> context;\n\n    EXPECT_EQ(expected, context->result);\n}\n"
  },
  {
    "path": "examples/Calc/features/step_definitions/GTestCalculatorSteps.cpp",
    "content": "#include <gtest/gtest.h>\n#include \"CalculatorSteps.cpp\"\n"
  },
  {
    "path": "examples/Calc/features/step_definitions/QtTestCalculatorSteps.cpp",
    "content": "#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",
    "content": "host: localhost\nport: 3902\n"
  },
  {
    "path": "examples/Calc/src/Calculator.cpp",
    "content": "#include <limits>\n#include \"Calculator.hpp\"\n\nvoid Calculator::push(double n) {\n    values.push_back(n);\n}\n\ndouble Calculator::add() {\n    double result = 0;\n    for (std::list<double>::const_iterator i = values.begin(); i != values.end(); ++i) {\n        result += *i;\n    }\n    return result;\n}\n\ndouble Calculator::divide() {\n    double result = std::numeric_limits<double>::quiet_NaN();\n    for (std::list<double>::const_iterator i = values.begin(); i != values.end(); ++i) {\n        if (i == values.begin()) {\n            result = *i;\n        } else {\n            result /= *i;\n        }\n    }\n    return result;\n}\n"
  },
  {
    "path": "examples/Calc/src/Calculator.hpp",
    "content": "#pragma once\n\n#include <list>\n\nclass Calculator {\nprivate:\n    std::list<double> values;\n\npublic:\n    void push(double);\n    double add();\n    double divide();\n};\n"
  },
  {
    "path": "examples/CalcQt/CMakeLists.txt",
    "content": "project(CalcQt)\n\nif(TARGET Qt::Core AND TARGET Qt::Gui AND TARGET Qt::Widgets AND TARGET Qt::Test)\n    set(CMAKE_AUTOMOC ON)\n\n    add_library(libcalcqt STATIC src/Calculator.cpp src/Calculator.hpp)\n    target_include_directories(libcalcqt INTERFACE src)\n    target_link_libraries(libcalcqt\n        PUBLIC\n            Qt::Core\n    )\n\n    add_executable(calcqt\n        src/CalcQt.cpp\n        src/CalculatorWidget.cpp\n        src/CalculatorWidget.hpp\n    )\n    target_link_libraries(calcqt\n        PRIVATE\n            libcalcqt\n            Qt::Core\n            Qt::Gui\n            Qt::Widgets\n    )\n\n    add_executable(QtTestCalculatorQtSteps features/step_definitions/QtTestCalculatorQtSteps.cpp)\n    target_link_libraries(QtTestCalculatorQtSteps PRIVATE libcalcqt Qt::Test cucumber-cpp)\n\n    if(TARGET Boost::unit_test_framework)\n        add_executable(BoostCalculatorQtSteps features/step_definitions/BoostCalculatorQtSteps.cpp)\n        target_link_libraries(BoostCalculatorQtSteps PRIVATE libcalcqt Boost::unit_test_framework cucumber-cpp)\n    endif()\n\n    if(TARGET GTest::gtest)\n        add_executable(GTestCalculatorQtSteps features/step_definitions/GTestCalculatorQtSteps.cpp)\n        target_link_libraries(GTestCalculatorQtSteps PRIVATE libcalcqt GTest::gtest cucumber-cpp)\n    endif()\n\nendif()\n"
  },
  {
    "path": "examples/CalcQt/README.txt",
    "content": "This sample shows how to test a QT GUI. The environment variable\nCALCQT_STEP_DELAY allows to introduce delays in the step execution for\ndemo purposes (i.e. CALCQT_STEP_DELAY=100 ./BoostCalculatorQtSteps)\n\n"
  },
  {
    "path": "examples/CalcQt/features/addition.feature",
    "content": "# 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 two numbers\n\n  Scenario Outline: Add two numbers\n    Given I just turned on the calculator\n    When I press <button1>\n    And I press add\n    And I press <button2>\n    And I press calculate\n    Then the display should show <result>\n\n  Examples:\n    | button1 | button2 | result |\n    | 2       | 3       | 5      |\n    | 7       | 5       | 12     |\n    | 9       | 1       | 10     |\n"
  },
  {
    "path": "examples/CalcQt/features/behavior.feature",
    "content": "# language: en\nFeature: GUI behavior\n  tests for buttons\n\n  Scenario Outline: Digit buttons\n    Given I just turned on the calculator\n    When I press <button>\n    Then the display should show <output>\n\n  Examples:\n    | button | output |\n    | 0      | 0      |\n    | 1      | 1      |\n    | 2      | 2      |\n    | 3      | 3      |\n    | 4      | 4      |\n    | 5      | 5      |\n    | 6      | 6      |\n    | 7      | 7      |\n    | 8      | 8      |\n    | 9      | 9      |\n\n  Scenario: Clear button\n    Given I just turned on the calculator\n    When I press 2\n    And I press clear\n    Then the display should be empty\n\n  Scenario: Addition button\n    Given I just turned on the calculator\n    When I press add\n    Then the display should show +\n\n  Scenario: Subtraction button\n    Given I just turned on the calculator\n    When I press subtract\n    Then the display should show -\n\n  Scenario Outline: Digit sequence\n    Given I just turned on the calculator\n    When I press <button1>\n    And I press <button2>\n    Then the display should show <output>\n\n  Examples:\n    | button1 | button2 | output |\n    | 2       | 2       | 22     |\n    | 7       | 4       | 74     |\n    | 3       | 8       | 38     |\n\n  Scenario Outline: Addition operation\n    Given I just turned on the calculator\n    When I press <button1>\n\t And I press add\n    And I press <button2>\n    Then the display should show <output>\n\n  Examples:\n    | button1 | button2 | output |\n    | 2       | 2       | 2+2    |\n    | 7       | 4       | 7+4    |\n    | 3       | 8       | 3+8    |\n\n\n  Scenario Outline: Subtraction operation\n    Given I just turned on the calculator\n    When I press <button1>\n\t And I press subtract\n    And I press <button2>\n    Then the display should show <output>\n\n  Examples:\n    | button1 | button2 | output |\n    | 2       | 2       | 2-2    |\n    | 7       | 4       | 7-4    |\n    | 3       | 8       | 3-8    |\n\n"
  },
  {
    "path": "examples/CalcQt/features/initialization.feature",
    "content": "# language: en\nFeature: GUI initalization\n  test the initial status of the calculator\n\n  Scenario: Initialization\n    Given I just turned on the calculator\n    Then the display should be empty\n\n"
  },
  {
    "path": "examples/CalcQt/features/step_definitions/BoostCalculatorQtSteps.cpp",
    "content": "#include <boost/test/unit_test.hpp>\n// Pretend to be GTest\n#define EXPECT_EQ BOOST_CHECK_EQUAL\n#define ASSERT_TRUE BOOST_REQUIRE\n#include \"CalculatorQtSteps.cpp\"\n"
  },
  {
    "path": "examples/CalcQt/features/step_definitions/CalculatorQtSteps.cpp",
    "content": "#include <cucumber-cpp/autodetect.hpp>\n\n#include \"Calculator.hpp\"\n\nclass CalculatorCtx {\npublic:\n    CalculatorCtx() {\n        QObject::connect(&calculator, &Calculator::updateDisplay, [this](QString value) {\n            display = value;\n        });\n    }\n\n    Calculator calculator{};\n    QString display{};\n};\n\nstd::istream& operator>>(std::istream& in, QString& val) {\n    std::string s;\n    in >> s;\n    val = s.c_str();\n    return in;\n}\nstd::ostream& operator<<(std::ostream& out, const QString& val) {\n    out << val.toLatin1().data();\n    return out;\n}\n\nGIVEN(\"^I just turned on the calculator$\") {\n    cucumber::ScenarioScope<CalculatorCtx> ctx;\n}\n\nWHEN(\"^I press (\\\\d+)$\") {\n    REGEX_PARAM(unsigned int, n);\n    cucumber::ScenarioScope<CalculatorCtx> ctx;\n    ctx->calculator.number(n);\n}\n\nWHEN(\"^I press add\") {\n    cucumber::ScenarioScope<CalculatorCtx> ctx;\n    ctx->calculator.add();\n}\n\nWHEN(\"^I press calculate\") {\n    cucumber::ScenarioScope<CalculatorCtx> ctx;\n    ctx->calculator.calculate();\n}\n\nWHEN(\"^I press clear\") {\n    cucumber::ScenarioScope<CalculatorCtx> ctx;\n    ctx->calculator.clear();\n}\n\nWHEN(\"^I press subtract\") {\n    cucumber::ScenarioScope<CalculatorCtx> ctx;\n    ctx->calculator.subtract();\n}\n\nTHEN(\"^the display should be empty$\") {\n    cucumber::ScenarioScope<CalculatorCtx> ctx;\n    EXPECT_EQ(QString{}, ctx->display);\n}\n\nTHEN(\"^the display should show (.*)$\") {\n    REGEX_PARAM(QString, expected);\n    cucumber::ScenarioScope<CalculatorCtx> ctx;\n    EXPECT_EQ(expected, ctx->display);\n}\n"
  },
  {
    "path": "examples/CalcQt/features/step_definitions/GTestCalculatorQtSteps.cpp",
    "content": "#include <gtest/gtest.h>\n#include \"CalculatorQtSteps.cpp\"\n"
  },
  {
    "path": "examples/CalcQt/features/step_definitions/QtTestCalculatorQtSteps.cpp",
    "content": "#include <QTest>\n// Pretend to be GTest\n#define EXPECT_EQ QCOMPARE\n#define ASSERT_TRUE QVERIFY\n#include \"CalculatorQtSteps.cpp\"\n"
  },
  {
    "path": "examples/CalcQt/features/step_definitions/cucumber.wire",
    "content": "host: localhost\nport: 3902\n"
  },
  {
    "path": "examples/CalcQt/features/subtraction.feature",
    "content": "# language: en\nFeature: Subtraction\n  In order to avoid silly mistakes\n  As a math idiot \n  I want to be told the difference of two numbers\n\n  Scenario Outline: Subtract two numbers\n    Given I just turned on the calculator\n    When I press <button1>\n    And I press subtract\n    And I press <button2>\n    And I press calculate\n    Then the display should show <result>\n\n  Examples:\n    | button1 | button2 | result |\n    | 2       | 3       | -1     |\n    | 7       | 5       | 2      |\n    | 9       | 1       | 8      |\n"
  },
  {
    "path": "examples/CalcQt/src/CalcQt.cpp",
    "content": "#include <QApplication>\n\n#include \"Calculator.hpp\"\n#include \"CalculatorWidget.hpp\"\n\nint main(int argc, char* argv[]) {\n    QApplication app(argc, argv);\n    app.setApplicationName(\"Qt Calculator\");\n    Calculator calculator{};\n    CalculatorWidget widget{&calculator};\n    widget.show();\n    return app.exec();\n}\n"
  },
  {
    "path": "examples/CalcQt/src/Calculator.cpp",
    "content": "#include \"Calculator.hpp\"\n\n#include <QRegularExpression>\n\nQString Calculator::calculate(const QString& expression) const {\n    int result = 0;\n    char operation = '+';\n    const QRegularExpression regexp(\"(\\\\d+)\");\n    QRegularExpressionMatchIterator matches = regexp.globalMatch(expression);\n\n    while (matches.hasNext()) {\n        const auto match = matches.next();\n        const int value = match.captured(1).toInt();\n\n        switch (operation) {\n        case '+':\n            result += value;\n            break;\n        case '-':\n            result -= value;\n            break;\n        }\n\n        const int pos = match.capturedEnd();\n        if (pos < expression.length()) {\n            operation = expression.at(pos).toLatin1();\n        }\n    }\n\n    return QString::number(result);\n}\n\nvoid Calculator::number(quint8 number) {\n    expression += QString::number(number);\n    emit updateDisplay(expression);\n}\n\nvoid Calculator::add() {\n    expression += \"+\";\n    emit updateDisplay(expression);\n}\n\nvoid Calculator::subtract() {\n    expression += \"-\";\n    emit updateDisplay(expression);\n}\n\nvoid Calculator::calculate() {\n    expression = calculate(expression);\n    emit updateDisplay(expression);\n}\n\nvoid Calculator::clear() {\n    expression.clear();\n    emit updateDisplay(expression);\n}\n"
  },
  {
    "path": "examples/CalcQt/src/Calculator.hpp",
    "content": "#pragma once\n\n#include <QObject>\n\nclass Calculator : public QObject {\n    Q_OBJECT\n\npublic:\n    using QObject::QObject;\n\npublic slots:\n    void number(quint8);\n    void add();\n    void subtract();\n    void calculate();\n    void clear();\n\nsignals:\n    void updateDisplay(QString);\n\nprivate:\n    QString expression{};\n    QString calculate(const QString& expression) const;\n};\n"
  },
  {
    "path": "examples/CalcQt/src/CalculatorWidget.cpp",
    "content": "#include \"CalculatorWidget.hpp\"\n\n#include \"Calculator.hpp\"\n#include <QGridLayout>\n#include <QKeyEvent>\n#include <QLabel>\n#include <QPushButton>\n\nCalculatorWidget::CalculatorWidget(Calculator* calculator, QWidget* parent) :\n    QWidget(parent) {\n    QGridLayout* layout = new QGridLayout(this);\n    layout->setSizeConstraint(QLayout::SetFixedSize);\n    setLayout(layout);\n\n    QSizePolicy policy = sizePolicy();\n\n    displayLabel = new QLabel(this);\n    layout->addWidget(displayLabel, 0, 0, 1, 3);\n    displayLabel->setAutoFillBackground(true);\n    displayLabel->setBackgroundRole(QPalette::Base);\n    displayLabel->setAlignment(Qt::AlignRight);\n    policy = displayLabel->sizePolicy();\n    policy.setVerticalPolicy(QSizePolicy::Fixed);\n    displayLabel->setSizePolicy(policy);\n    QObject::connect(calculator, &Calculator::updateDisplay, displayLabel, &QLabel::setText);\n\n    QPushButton* button = new QPushButton(QString::number(0), this);\n    QObject::connect(button, &QPushButton::clicked, calculator, [calculator] {\n        calculator->number(0);\n    });\n    layout->addWidget(button, 4, 1);\n    digitButtons.push_back(button);\n    for (unsigned int i = 1; i < 10; ++i) {\n        QPushButton* button = new QPushButton(QString::number(i), this);\n        QObject::connect(button, &QPushButton::clicked, calculator, [i, calculator] {\n            calculator->number(i);\n        });\n        layout->addWidget(button, 1 + (9 - i) / 3, (i - 1) % 3);\n        digitButtons.push_back(button);\n    }\n\n    clearButton = new QPushButton(\"C\", this);\n    layout->addWidget(clearButton, 1, 4);\n    QObject::connect(clearButton, &QPushButton::clicked, calculator, [calculator] {\n        calculator->clear();\n    });\n\n    additionButton = new QPushButton(\"+\", this);\n    layout->addWidget(additionButton, 2, 4);\n    QObject::connect(additionButton, &QPushButton::clicked, calculator, [calculator] {\n        calculator->add();\n    });\n\n    subtractionButton = new QPushButton(\"-\", this);\n    layout->addWidget(subtractionButton, 3, 4);\n    QObject::connect(subtractionButton, &QPushButton::clicked, calculator, [calculator] {\n        calculator->subtract();\n    });\n\n    calculateButton = new QPushButton(\"=\", this);\n    layout->addWidget(calculateButton, 4, 4);\n    QObject::connect(calculateButton, &QPushButton::clicked, calculator, [calculator] {\n        calculator->calculate();\n    });\n}\n\nvoid CalculatorWidget::keyPressEvent(QKeyEvent* event) {\n    keyclickedButton = nullptr;\n    int key = event->key();\n    if (key >= Qt::Key_0 && key <= Qt::Key_9) {\n        keyclickedButton = digitButtons[key - Qt::Key_0];\n    } else {\n        switch (key) {\n        case Qt::Key_Plus:\n            keyclickedButton = additionButton;\n            break;\n        case Qt::Key_Minus:\n            keyclickedButton = subtractionButton;\n            break;\n        case Qt::Key_Return:\n        case Qt::Key_Enter:\n        case Qt::Key_Equal:\n            keyclickedButton = calculateButton;\n            break;\n        case Qt::Key_Escape:\n            keyclickedButton = clearButton;\n            break;\n        }\n    }\n    if (keyclickedButton) {\n        keyclickedButton->click();\n        keyclickedButton->setDown(true);\n    }\n}\n\nvoid CalculatorWidget::keyReleaseEvent(QKeyEvent* event) {\n    Q_UNUSED(event)\n    if (keyclickedButton) {\n        keyclickedButton->setDown(false);\n        keyclickedButton = nullptr;\n    }\n}\n\nvoid CalculatorWidget::updateDisplay(QString text) {\n    displayLabel->setText(text);\n}\n"
  },
  {
    "path": "examples/CalcQt/src/CalculatorWidget.hpp",
    "content": "#pragma once\n\nclass QLabel;\nclass QPushButton;\nclass Calculator;\n\n#include <QString>\n#include <QWidget>\n\nclass CalculatorWidget : public QWidget {\n    Q_OBJECT\n\npublic:\n    CalculatorWidget(Calculator* calculator, QWidget* parent = 0);\n\nprotected:\n    void keyPressEvent(QKeyEvent* event) override;\n    void keyReleaseEvent(QKeyEvent* event) override;\n\nprivate:\n    QLabel* displayLabel;\n    QVector<QPushButton*> digitButtons;\n    QPushButton* additionButton;\n    QPushButton* calculateButton;\n    QPushButton* clearButton;\n    QPushButton* subtractionButton;\n\n    QPushButton* keyclickedButton{};\n\nprivate Q_SLOTS:\n    void updateDisplay(QString);\n};\n"
  },
  {
    "path": "examples/FeatureShowcase/CMakeLists.txt",
    "content": "project(FeatureShowcase)\n\nif(TARGET GTest::gtest)\n    function(add_cucumber_executable)\n        add_executable(FeatureShowcaseSteps ${ARGV})\n        target_link_libraries(FeatureShowcaseSteps PRIVATE cucumber-cpp GTest::gtest)\n        foreach(_arg ${ARGN})\n            get_filename_component(OBJECT_PREFIX ${_arg} NAME_WE)\n            set_source_files_properties(${_arg} PROPERTIES COMPILE_FLAGS \"-DCUKE_OBJECT_PREFIX=${OBJECT_PREFIX}\")\n        endforeach(_arg)\n    endfunction()\n\n    add_cucumber_executable(\n        features/step_definitions/TagSteps.cpp\n        features/step_definitions/TableSteps.cpp\n    )\nendif()\n\n"
  },
  {
    "path": "examples/FeatureShowcase/README.txt",
    "content": "This sample shows a few advanced features: tags and table arguments.\n\n"
  },
  {
    "path": "examples/FeatureShowcase/features/step_definitions/TableSteps.cpp",
    "content": "#include <gtest/gtest.h>\n#include <cucumber-cpp/autodetect.hpp>\n\n#include <string>\n#include <map>\n\nusing cucumber::ScenarioScope;\n\nclass ActiveActors {\npublic:\n    typedef std::string actor_name_type;\n    typedef unsigned short actor_year_type;\n\nprivate:\n    typedef std::map<actor_name_type, actor_year_type> actors_type;\n\n    actors_type actors;\n\npublic:\n    void addActor(const actor_name_type name, const actor_year_type year) {\n        actors[name] = year;\n    }\n\n    void retireActor(const actor_name_type name) {\n        actors.erase(actors.find(name));\n    }\n\n    actor_name_type getOldestActor() {\n        actors_type::iterator it = actors.begin();\n        actor_name_type name = it->first;\n        actor_year_type year = it->second;\n        while (++it != actors.end()) {\n            actor_year_type currentYear = it->second;\n            if (year > currentYear) {\n                name = it->first;\n            }\n        }\n        return name;\n    }\n};\n\nGIVEN(\"^the following actors are still active\") {\n    TABLE_PARAM(actorsParam);\n    ScenarioScope<ActiveActors> context;\n\n    const table_hashes_type& actors = actorsParam.hashes();\n    for (table_hashes_type::const_iterator ait = actors.begin(); ait != actors.end(); ++ait) {\n        std::string name(ait->at(\"name\"));\n        std::string yearString(ait->at(\"born\"));\n        const ActiveActors::actor_year_type year\n            = ::cucumber::internal::fromString<ActiveActors::actor_year_type>(yearString);\n        context->addActor(name, year);\n    }\n}\n\nWHEN(\"^(.+) retires\") {\n    REGEX_PARAM(std::string, retiringActor);\n    ScenarioScope<ActiveActors> context;\n\n    context->retireActor(retiringActor);\n}\n\nTHEN(\"^the oldest actor should be (.+)$\") {\n    REGEX_PARAM(std::string, oldestActor);\n    ScenarioScope<ActiveActors> context;\n\n    ASSERT_EQ(oldestActor, context->getOldestActor());\n}\n"
  },
  {
    "path": "examples/FeatureShowcase/features/step_definitions/TagSteps.cpp",
    "content": "#include <gtest/gtest.h>\n#include <cucumber-cpp/autodetect.hpp>\n\n#include <iostream>\n\nusing std::cout;\nusing std::endl;\nusing std::string;\n\nBEFORE_ALL() {\n    cout << \"-------------------- (Before all scenarios)\" << endl;\n}\n\nAFTER_ALL() {\n    cout << \"-------------------- (After all scenarios)\" << endl;\n}\n\nBEFORE() {\n    cout << \"-------------------- (Before any scenario)\" << endl;\n}\n\nBEFORE(\"@foo,@bar\", \"@baz\") {\n    cout << \"Before scenario (\\\"@foo,@baz\\\",\\\"@bar\\\")\" << endl;\n}\n\nAROUND_STEP(\"@baz\") {\n    cout << \"Around step (\\\"@baz\\\") ...before\" << endl;\n    step->call();\n    cout << \"Around step (\\\"@baz\\\") ..after\" << endl;\n}\n\nAFTER_STEP(\"@bar\") {\n    cout << \"After step (\\\"@bar\\\")\" << endl;\n}\n\nAFTER(\"@foo\") {\n    cout << \"After scenario (\\\"@foo\\\")\" << endl;\n}\n\nAFTER(\"@gherkin\") {\n    cout << \"After scenario (\\\"@gherkin\\\")\" << endl;\n}\n\n/*\n * CUKE_STEP_ is used just because the feature does not convey any\n * business value. It should NEVER be used in real step definitions!\n */\n\nCUKE_STEP_(\"^I'm running a step from a scenario not tagged$\") {\n    cout << \"Running step from scenario without tags\" << endl;\n    EXPECT_TRUE(true); // To fix a problem at link time\n}\n\nCUKE_STEP_(\"^I'm running a step from a scenario tagged with (.*)$\") {\n    REGEX_PARAM(string, tags);\n    cout << \"Running step from scenario with tags: \" << tags << endl;\n    EXPECT_TRUE(true); // To fix a problem at link time\n}\n"
  },
  {
    "path": "examples/FeatureShowcase/features/step_definitions/cucumber.wire",
    "content": "host: localhost\nport: 3902\n"
  },
  {
    "path": "examples/FeatureShowcase/features/table.feature",
    "content": "# language: en\nFeature: Table\n  In order to explain how to use tables\n  I have to make this silly example\n\n  Scenario: No tag\n    Given the following actors are still active:\n      | name           | born |\n      | Al Pacino      | 1940 |\n      | Robert De Niro | 1943 |\n      | George Clooney | 1961 |\n      | Morgan Freeman | 1937 |\n    When Morgan Freeman retires\n    Then the oldest actor should be Al Pacino\n"
  },
  {
    "path": "examples/FeatureShowcase/features/tag.feature",
    "content": "# 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 tag\n    Given I'm running a step from a scenario not tagged\n    When I'm running a step from a scenario not tagged\n    Then I'm running a step from a scenario not tagged\n\n  @foo\n  Scenario: Foo\n    Given I'm running a step from a scenario tagged with @foo\n    When I'm running a step from a scenario tagged with @foo\n    Then I'm running a step from a scenario tagged with @foo\n\n  @bar\n  Scenario: Bar\n    Given I'm running a step from a scenario tagged with @bar\n    When I'm running a step from a scenario tagged with @bar\n    Then I'm running a step from a scenario tagged with @bar\n\n  @baz\n  Scenario: Baz\n    Given I'm running a step from a scenario tagged with @baz\n    When I'm running a step from a scenario tagged with @baz\n    Then I'm running a step from a scenario tagged with @baz\n\n  @bar @foo\n  Scenario: Bar and Foo\n    Given I'm running a step from a scenario tagged with @bar,@foo\n    When I'm running a step from a scenario tagged with @bar,@foo\n    Then I'm running a step from a scenario tagged with @bar,@foo\n\n  @pickle\n  Scenario: Pickle\n    Given I'm running a step from a scenario tagged with @pickle\n    When I'm running a step from a scenario tagged with @pickle\n    Then I'm running a step from a scenario tagged with @pickle\n"
  },
  {
    "path": "include/cucumber-cpp/autodetect.hpp",
    "content": "#include \"internal/defs.hpp\"\n#ifndef STEP_INHERITANCE\n    #error No test framework found: please include a testing framework before autodetect.hpp or include generic.hpp\n#endif\n"
  },
  {
    "path": "include/cucumber-cpp/defs.hpp",
    "content": "#ifdef __GNUC__\n    #warning \"Use of defs.hpp is deprecated, please use either autodetect.hpp or generic.hpp\"\n#else\n    #pragma message(                                                                     \\\n        \"Use of defs.hpp is deprecated, please use either autodetect.hpp or generic.hpp\" \\\n    )\n#endif\n#include \"internal/defs.hpp\"\n#ifndef STEP_INHERITANCE\n    #include \"internal/drivers/GenericDriver.hpp\"\n#endif\n"
  },
  {
    "path": "include/cucumber-cpp/generic.hpp",
    "content": "#include \"internal/defs.hpp\"\n#ifdef STEP_INHERITANCE\n    #error Test framework found: please include autodetect.hpp or remove the test framework includes\n#else\n    #include \"internal/drivers/GenericDriver.hpp\"\n#endif\n"
  },
  {
    "path": "include/cucumber-cpp/internal/ContextManager.hpp",
    "content": "#ifndef CUKE_CONTEXTMANAGER_HPP_\n#define CUKE_CONTEXTMANAGER_HPP_\n\n#include <cucumber-cpp/internal/CukeExport.hpp>\n\n#include <vector>\n\n#include <memory>\n\nnamespace cucumber {\n\nnamespace internal {\n\ntypedef std::vector<std::shared_ptr<void>> contexts_type;\n\nclass CUCUMBER_CPP_EXPORT ContextManager {\npublic:\n    void purgeContexts();\n    template<class T>\n    std::weak_ptr<T> addContext();\n\nprotected:\n    static contexts_type contexts;\n};\n\ntemplate<class T>\nstd::weak_ptr<T> ContextManager::addContext() {\n    std::shared_ptr<T> shared(std::make_shared<T>());\n    contexts.push_back(shared);\n    return std::weak_ptr<T>(shared);\n}\n\n}\n\ntemplate<class T>\nclass ScenarioScope {\npublic:\n    ScenarioScope();\n\n    T& operator*();\n    T* operator->();\n    T* get();\n\nprivate:\n    internal::ContextManager contextManager;\n    std::shared_ptr<T> context;\n    static std::weak_ptr<T> contextReference;\n};\n\ntemplate<class T>\nstd::weak_ptr<T> ScenarioScope<T>::contextReference;\n\ntemplate<class T>\nScenarioScope<T>::ScenarioScope() {\n    if (contextReference.expired()) {\n        contextReference = contextManager.addContext<T>();\n    }\n    context = contextReference.lock();\n}\n\ntemplate<class T>\nT& ScenarioScope<T>::operator*() {\n    return *(context.get());\n}\n\ntemplate<class T>\nT* ScenarioScope<T>::operator->() {\n    return (context.get());\n}\n\ntemplate<class T>\nT* ScenarioScope<T>::get() {\n    return context.get();\n}\n\n}\n\n#endif /* CUKE_CONTEXTMANAGER_HPP_ */\n"
  },
  {
    "path": "include/cucumber-cpp/internal/CukeCommands.hpp",
    "content": "#ifndef CUKE_CUKECOMMANDS_HPP_\n#define CUKE_CUKECOMMANDS_HPP_\n\n#include \"ContextManager.hpp\"\n#include <cucumber-cpp/internal/CukeExport.hpp>\n#include \"Scenario.hpp\"\n#include \"Table.hpp\"\n#include \"step/StepManager.hpp\"\n\n#include <map>\n#include <string>\n#include <sstream>\n\n#include <memory>\n\nnamespace cucumber {\nnamespace internal {\n\n/**\n * Legacy class to be removed when feature #31 is complete, substituted by CukeEngineImpl.\n */\nclass CUCUMBER_CPP_EXPORT CukeCommands {\npublic:\n    CukeCommands();\n    virtual ~CukeCommands();\n\n    void beginScenario(const TagExpression::tag_list& tags = TagExpression::tag_list());\n    void endScenario();\n    const std::string snippetText(const std::string stepKeyword, const std::string stepName) const;\n    MatchResult stepMatches(const std::string description) const;\n    InvokeResult invoke(step_id_type id, const InvokeArgs* pArgs);\n\nprotected:\n    const std::string escapeRegex(const std::string regex) const;\n    const std::string escapeCString(const std::string str) const;\n\nprivate:\n    ContextManager contextManager;\n    bool hasStarted;\n\nprivate:\n    static std::shared_ptr<Scenario> currentScenario;\n};\n\n}\n}\n\n#endif /* CUKE_CUKECOMMANDS_HPP_ */\n"
  },
  {
    "path": "include/cucumber-cpp/internal/CukeEngine.hpp",
    "content": "#ifndef CUKE_CUKEENGINE_HPP_\n#define CUKE_CUKEENGINE_HPP_\n\n#include <cstddef>\n#include <string>\n#include <vector>\n\n#include <cucumber-cpp/internal/CukeExport.hpp>\n\nnamespace cucumber {\nnamespace internal {\n\nclass CUCUMBER_CPP_EXPORT StepMatchArg {\npublic:\n    std::string value;\n    std::ptrdiff_t position;\n};\n\nclass CUCUMBER_CPP_EXPORT StepMatch {\npublic:\n    std::string id;\n    std::vector<StepMatchArg> args;\n    std::string source;\n    std::string regexp;\n};\n\nclass CUCUMBER_CPP_EXPORT InvokeException {\nprivate:\n    const std::string message;\n\npublic:\n    InvokeException(const std::string& message);\n    InvokeException(const InvokeException& rhs);\n\n    const std::string getMessage() const;\n\n    virtual ~InvokeException() = default;\n};\n\nclass CUCUMBER_CPP_EXPORT InvokeFailureException : public InvokeException {\nprivate:\n    const std::string exceptionType;\n\npublic:\n    InvokeFailureException(const std::string& message, const std::string& exceptionType);\n    InvokeFailureException(const InvokeFailureException& rhs);\n\n    const std::string getExceptionType() const;\n};\n\nclass CUCUMBER_CPP_EXPORT PendingStepException : public InvokeException {\npublic:\n    PendingStepException(const std::string& message);\n    PendingStepException(const PendingStepException& rhs);\n};\n\n/**\n * The entry point to Cucumber.\n *\n * It uses standard types (as much as possible) to be easier to call.\n * Returns standard types if possible.\n */\nclass CukeEngine {\nprivate:\n    typedef std::vector<std::string> string_array;\n    typedef std::vector<std::vector<std::string>> string_2d_array;\n\npublic:\n    typedef string_array tags_type;\n    typedef string_array invoke_args_type;\n    typedef string_2d_array invoke_table_type;\n\n    /**\n     * Finds steps whose regexp match some text.\n     */\n    virtual std::vector<StepMatch> stepMatches(const std::string& name) const = 0;\n\n    /**\n     * Starts a scenario.\n     */\n    virtual void beginScenario(const tags_type& tags) = 0;\n\n    /**\n     * Invokes a step passing arguments to it.\n     *\n     * @throws InvokeException if the test fails or it is pending\n     */\n    virtual void invokeStep(\n        const std::string& id, const invoke_args_type& args, const invoke_table_type& tableArg\n    ) = 0;\n\n    /**\n     * Ends a scenario.\n     */\n    virtual void endScenario(const tags_type& tags) = 0;\n\n    /**\n     * Returns the step definition for a pending step.\n     */\n    virtual std::string snippetText(\n        const std::string& keyword, const std::string& name, const std::string& multilineArgClass\n    ) const\n        = 0;\n\n    CUCUMBER_CPP_EXPORT CukeEngine();\n    CUCUMBER_CPP_EXPORT virtual ~CukeEngine() = default;\n};\n\n}\n}\n\n#endif /* CUKE_CUKEENGINE_HPP_ */\n"
  },
  {
    "path": "include/cucumber-cpp/internal/CukeEngineImpl.hpp",
    "content": "#ifndef CUKE_CUKEENGINE_IMPL_HPP_\n#define CUKE_CUKEENGINE_IMPL_HPP_\n\n#include \"CukeEngine.hpp\"\n#include <cucumber-cpp/internal/CukeExport.hpp>\n#include \"CukeCommands.hpp\"\n\nnamespace cucumber {\nnamespace internal {\n\n/**\n * Default Engine Implementation\n *\n * Currently it is a wrapper around CukeCommands. It will have its own\n * implementation when feature #31 is complete.\n */\nclass CUCUMBER_CPP_EXPORT CukeEngineImpl : public CukeEngine {\nprivate:\n    CukeCommands cukeCommands;\n\npublic:\n    std::vector<StepMatch> stepMatches(const std::string& name) const override;\n    void beginScenario(const tags_type& tags) override;\n    void invokeStep(\n        const std::string& id, const invoke_args_type& args, const invoke_table_type& tableArg\n    ) override;\n    void endScenario(const tags_type& tags) override;\n    std::string snippetText(\n        const std::string& keyword, const std::string& name, const std::string& multilineArgClass\n    ) const override;\n};\n\n}\n}\n\n#endif /* CUKE_CUKEENGINE_IMPL_HPP_ */\n"
  },
  {
    "path": "include/cucumber-cpp/internal/Macros.hpp",
    "content": "#ifndef CUKE_MACROS_HPP_\n#define CUKE_MACROS_HPP_\n\n#include \"RegistrationMacros.hpp\"\n#include \"step/StepMacros.hpp\"\n#include \"hook/HookMacros.hpp\"\n\n#endif /* CUKE_MACROS_HPP_ */\n"
  },
  {
    "path": "include/cucumber-cpp/internal/RegistrationMacros.hpp",
    "content": "#ifndef CUKE_REGISTRATIONMACROS_HPP_\n#define CUKE_REGISTRATIONMACROS_HPP_\n\n// ************************************************************************** //\n// **************            OBJECT NAMING MACROS              ************** //\n// ************************************************************************** //\n\n// from https://www.boost.org/doc/libs/1_84_0/boost/config/helper_macros.hpp\n#define CUKE_JOIN(X, Y) CUKE_DO_JOIN(X, Y)\n#define CUKE_DO_JOIN(X, Y) CUKE_DO_JOIN2(X, Y)\n#define CUKE_DO_JOIN2(X, Y) X##Y\n\n#ifndef CUKE_OBJECT_PREFIX\n    #define CUKE_OBJECT_PREFIX CukeObject\n#endif\n\n#ifdef __COUNTER__\n    #define CUKE_GEN_OBJECT_NAME_ CUKE_JOIN(CUKE_OBJECT_PREFIX, __COUNTER__)\n#else\n    // Use a counter to be incremented every time cucumber-cpp is included\n    // in case this does not suffice (possible with multiple files only)\n    #define CUKE_GEN_OBJECT_NAME_ CUKE_JOIN(CUKE_OBJECT_PREFIX, __LINE__)\n#endif\n\n// ************************************************************************** //\n// **************                 CUKE OBJECTS                 ************** //\n// ************************************************************************** //\n\n#define CUKE_OBJECT_(class_name, parent_class, registration_fn, args)                     \\\n    class class_name : public parent_class {                                              \\\n    public:                                                                               \\\n        void body() override { return invokeWithArgs(*this, &class_name::bodyWithArgs); } \\\n        void bodyWithArgs args;                                                           \\\n                                                                                          \\\n    private:                                                                              \\\n        static const int cukeRegId;                                                       \\\n    };                                                                                    \\\n    const int class_name ::cukeRegId = registration_fn;                                   \\\n    void class_name ::bodyWithArgs args /**/\n\n#endif /* CUKE_REGISTRATIONMACROS_HPP_ */\n"
  },
  {
    "path": "include/cucumber-cpp/internal/Scenario.hpp",
    "content": "#ifndef CUKE_SCENARIO_HPP_\n#define CUKE_SCENARIO_HPP_\n\n#include \"hook/Tag.hpp\"\n\nnamespace cucumber {\nnamespace internal {\n\nclass Scenario {\npublic:\n    Scenario(const TagExpression::tag_list& tags = TagExpression::tag_list());\n\n    const TagExpression::tag_list& getTags();\n\nprivate:\n    const TagExpression::tag_list tags;\n};\n\n}\n}\n\n#endif /* CUKE_SCENARIO_HPP_ */\n"
  },
  {
    "path": "include/cucumber-cpp/internal/Table.hpp",
    "content": "#ifndef CUKE_TABLE_HPP_\n#define CUKE_TABLE_HPP_\n\n#include <cucumber-cpp/internal/CukeExport.hpp>\n\n#include <vector>\n#include <map>\n#include <string>\n#include <stdexcept>\n\nnamespace cucumber {\nnamespace internal {\n\nclass CUCUMBER_CPP_EXPORT Table {\nprivate:\n    typedef std::vector<std::string> basic_type;\n\npublic:\n    typedef std::map<std::string, std::string> hash_row_type;\n    typedef basic_type columns_type;\n    typedef basic_type row_type;\n    typedef std::vector<hash_row_type> hashes_type;\n\n    /**\n     * @brief addColumn\n     * @param column\n     *\n     * @throws std::runtime_error\n     */\n    void addColumn(const std::string column);\n\n    /**\n     * @brief addRow\n     * @param row\n     *\n     * @throws std::range_error\n     * @throws std::runtime_error\n     */\n    void addRow(const row_type& row);\n    const hashes_type& hashes() const;\n\nprivate:\n    hash_row_type buildHashRow(const row_type& row);\n\n    columns_type columns;\n    hashes_type rows;\n};\n\n}\n}\n\n#endif /* CUKE_TABLE_HPP_ */\n"
  },
  {
    "path": "include/cucumber-cpp/internal/connectors/wire/ProtocolHandler.hpp",
    "content": "#ifndef CUKE_PROTOCOLHANDLER_HPP_\n#define CUKE_PROTOCOLHANDLER_HPP_\n\n#include <string>\n\nnamespace cucumber {\nnamespace internal {\n\n/**\n * Protocol that reads one command for each input line.\n */\nclass ProtocolHandler {\npublic:\n    virtual std::string handle(const std::string& request) const = 0;\n    virtual ~ProtocolHandler() = default;\n};\n\n}\n}\n\n#endif /* CUKE_PROTOCOLHANDLER_HPP_ */\n"
  },
  {
    "path": "include/cucumber-cpp/internal/connectors/wire/WireProtocol.hpp",
    "content": "#ifndef CUKE_WIREPROTOCOL_HPP_\n#define CUKE_WIREPROTOCOL_HPP_\n\n#include <cucumber-cpp/internal/CukeExport.hpp>\n#include \"ProtocolHandler.hpp\"\n#include \"../../CukeEngine.hpp\"\n\n#include <memory>\n\nnamespace cucumber {\nnamespace internal {\n\n/*\n * Response messages\n */\n\nclass WireResponseVisitor;\n\nclass CUCUMBER_CPP_EXPORT WireResponse {\npublic:\n    WireResponse(){};\n\n    virtual void accept(WireResponseVisitor& visitor) const = 0;\n\n    virtual ~WireResponse() = default;\n};\n\nclass CUCUMBER_CPP_EXPORT SuccessResponse : public WireResponse {\npublic:\n    void accept(WireResponseVisitor& visitor) const override;\n};\n\nclass CUCUMBER_CPP_EXPORT FailureResponse : public WireResponse {\nprivate:\n    const std::string message, exceptionType;\n\npublic:\n    FailureResponse(const std::string& message = \"\", const std::string& exceptionType = \"\");\n\n    const std::string getMessage() const;\n    const std::string getExceptionType() const;\n\n    void accept(WireResponseVisitor& visitor) const override;\n};\n\nclass CUCUMBER_CPP_EXPORT PendingResponse : public WireResponse {\nprivate:\n    const std::string message;\n\npublic:\n    PendingResponse(const std::string& message);\n\n    const std::string getMessage() const;\n\n    void accept(WireResponseVisitor& visitor) const override;\n};\n\nclass CUCUMBER_CPP_EXPORT StepMatchesResponse : public WireResponse {\nprivate:\n    const std::vector<StepMatch> matchingSteps;\n\npublic:\n    StepMatchesResponse(const std::vector<StepMatch>& matchingSteps);\n    const std::vector<StepMatch>& getMatchingSteps() const;\n\n    void accept(WireResponseVisitor& visitor) const override;\n};\n\nclass CUCUMBER_CPP_EXPORT SnippetTextResponse : public WireResponse {\nprivate:\n    const std::string stepSnippet;\n\npublic:\n    SnippetTextResponse(const std::string& stepSnippet);\n\n    const std::string getStepSnippet() const;\n\n    void accept(WireResponseVisitor& visitor) const override;\n};\n\nclass CUCUMBER_CPP_EXPORT WireResponseVisitor {\npublic:\n    virtual void visit(const SuccessResponse& response) = 0;\n    virtual void visit(const FailureResponse& response) = 0;\n    virtual void visit(const PendingResponse& response) = 0;\n    virtual void visit(const StepMatchesResponse& response) = 0;\n    virtual void visit(const SnippetTextResponse& response) = 0;\n\n    virtual ~WireResponseVisitor() = default;\n};\n\n/**\n * Wire protocol request command.\n */\nclass CUCUMBER_CPP_EXPORT WireCommand {\npublic:\n    /**\n     * Runs the command on the provided engine\n     *\n     * @param The engine\n     *\n     * @return The command response (ownership passed to the caller)\n     */\n    virtual std::shared_ptr<WireResponse> run(CukeEngine& engine) const = 0;\n\n    virtual ~WireCommand() = default;\n};\n\nclass CUCUMBER_CPP_EXPORT WireMessageCodecException : public std::exception {\nprivate:\n    const char* description;\n\npublic:\n    WireMessageCodecException(const char* description) :\n        description(description) {\n    }\n\n    const char* what() const throw() override {\n        return description;\n    }\n};\n\n/**\n * Transforms wire messages into commands and responses to messages.\n */\nclass CUCUMBER_CPP_EXPORT WireMessageCodec {\npublic:\n    /**\n     * Decodes a wire message into a command.\n     *\n     * @param One single message to decode\n     *\n     * @return The decoded command (ownership passed to the caller)\n     *\n     * @throws WireMessageCodecException\n     */\n    virtual std::shared_ptr<WireCommand> decode(const std::string& request) const = 0;\n\n    /**\n     * Encodes a response to wire format.\n     *\n     * @param Response to encode\n     *\n     * @return The encoded string\n     */\n    virtual const std::string encode(const WireResponse& response) const = 0;\n\n    virtual ~WireMessageCodec() = default;\n};\n\n/**\n * WireMessageCodec implementation with Json.\n */\nclass CUCUMBER_CPP_EXPORT JsonWireMessageCodec : public WireMessageCodec {\npublic:\n    JsonWireMessageCodec() = default;\n    std::shared_ptr<WireCommand> decode(const std::string& request) const override;\n    const std::string encode(const WireResponse& response) const override;\n};\n\n/**\n * Wire protocol handler, delegating JSON encoding and decoding to a\n * codec object and running commands on a provided engine instance.\n */\nclass CUCUMBER_CPP_EXPORT WireProtocolHandler : public ProtocolHandler {\nprivate:\n    const WireMessageCodec& codec;\n    CukeEngine& engine;\n\npublic:\n    WireProtocolHandler(const WireMessageCodec& codec, CukeEngine& engine);\n\n    std::string handle(const std::string& request) const override;\n};\n\n}\n}\n\n#endif /* CUKE_WIREPROTOCOL_HPP_ */\n"
  },
  {
    "path": "include/cucumber-cpp/internal/connectors/wire/WireProtocolCommands.hpp",
    "content": "#ifndef CUKE_WIREPROTOCOL_COMMANDS_HPP_\n#define CUKE_WIREPROTOCOL_COMMANDS_HPP_\n\n#include \"WireProtocol.hpp\"\n#include <memory>\n\nnamespace cucumber {\nnamespace internal {\n\nclass ScenarioCommand : public WireCommand {\nprotected:\n    const CukeEngine::tags_type tags;\n\n    ScenarioCommand(const CukeEngine::tags_type& tags);\n};\n\nclass BeginScenarioCommand : public ScenarioCommand {\npublic:\n    BeginScenarioCommand(const CukeEngine::tags_type& tags);\n\n    std::shared_ptr<WireResponse> run(CukeEngine& engine) const override;\n};\n\nclass EndScenarioCommand : public ScenarioCommand {\npublic:\n    EndScenarioCommand(const CukeEngine::tags_type& tags);\n\n    std::shared_ptr<WireResponse> run(CukeEngine& engine) const override;\n};\n\nclass StepMatchesCommand : public WireCommand {\nprivate:\n    const std::string stepName;\n\npublic:\n    StepMatchesCommand(const std::string& stepName);\n\n    std::shared_ptr<WireResponse> run(CukeEngine& engine) const override;\n};\n\nclass InvokeCommand : public WireCommand {\nprivate:\n    const std::string stepId;\n    const CukeEngine::invoke_args_type args;\n    const CukeEngine::invoke_table_type tableArg;\n\npublic:\n    InvokeCommand(\n        const std::string& stepId,\n        const CukeEngine::invoke_args_type& args,\n        const CukeEngine::invoke_table_type& tableArg\n    );\n\n    std::shared_ptr<WireResponse> run(CukeEngine& engine) const override;\n};\n\nclass SnippetTextCommand : public WireCommand {\nprivate:\n    std::string keyword, name, multilineArgClass;\n\npublic:\n    SnippetTextCommand(\n        const std::string& keyword, const std::string& name, const std::string& multilineArgClass\n    );\n\n    std::shared_ptr<WireResponse> run(CukeEngine& engine) const override;\n};\n\nclass FailingCommand : public WireCommand {\npublic:\n    std::shared_ptr<WireResponse> run(CukeEngine& engine) const override;\n};\n\n}\n}\n\n#endif /* CUKE_WIREPROTOCOL_COMMANDS_HPP_ */\n"
  },
  {
    "path": "include/cucumber-cpp/internal/connectors/wire/WireServer.hpp",
    "content": "#ifndef CUKE_WIRESERVER_HPP_\n#define CUKE_WIRESERVER_HPP_\n\n#include <cucumber-cpp/internal/CukeExport.hpp>\n#include \"ProtocolHandler.hpp\"\n\n#include <string>\n\n#include <asio.hpp>\n\nnamespace cucumber {\nnamespace internal {\n\n/**\n * Socket server that calls a protocol handler line by line\n */\nclass CUCUMBER_CPP_EXPORT SocketServer {\npublic:\n    /**\n     * Constructor for DI\n     */\n    SocketServer(const ProtocolHandler* protocolHandler);\n    virtual ~SocketServer() = default;\n\n    /**\n     * Accept one connection\n     */\n    virtual void acceptOnce() = 0;\n\nprotected:\n    const ProtocolHandler* protocolHandler;\n    asio::io_context ios;\n\n    template<typename Protocol>\n    void doListen(\n        asio::basic_socket_acceptor<Protocol>& acceptor, const typename Protocol::endpoint& endpoint\n    );\n    template<typename Protocol>\n    void doAcceptOnce(asio::basic_socket_acceptor<Protocol>& acceptor);\n    void processStream(std::iostream& stream);\n};\n\n/**\n * Socket server that calls a protocol handler line by line\n */\nclass CUCUMBER_CPP_EXPORT TCPSocketServer : public SocketServer {\npublic:\n    /**\n     * Type definition for TCP port\n     */\n    typedef unsigned short port_type;\n\n    /**\n     * Constructor for DI\n     */\n    TCPSocketServer(const ProtocolHandler* protocolHandler);\n\n    /**\n     * Bind and listen to a TCP port\n     */\n    void listen(const port_type port);\n\n    /**\n     * Bind and listen to a TCP port on the given endpoint\n     */\n    void listen(const asio::ip::tcp::endpoint endpoint);\n\n    /**\n     * Endpoint (IP address and port number) that this server is currently\n     * listening on.\n     *\n     * @throw std::system_error when not listening on any socket or\n     *        the endpoint cannot be determined.\n     */\n    asio::ip::tcp::endpoint listenEndpoint() const;\n\n    void acceptOnce() override;\n\nprivate:\n    asio::ip::tcp::acceptor acceptor;\n};\n\n#if defined(ASIO_HAS_LOCAL_SOCKETS)\n/**\n * Socket server that calls a protocol handler line by line\n */\nclass CUCUMBER_CPP_EXPORT UnixSocketServer : public SocketServer {\npublic:\n    /**\n     * Constructor for DI\n     */\n    UnixSocketServer(const ProtocolHandler* protocolHandler);\n\n    /**\n     * Bind and listen on a local stream socket\n     */\n    void listen(const std::string& unixPath);\n\n    /**\n     * Port number that this server is currently listening on.\n     *\n     * @throw std::system_error when not listening on any socket or\n     *        the endpoint cannot be determined.\n     */\n    asio::local::stream_protocol::endpoint listenEndpoint() const;\n\n    void acceptOnce() override;\n\n    ~UnixSocketServer() override;\n\nprivate:\n    asio::local::stream_protocol::acceptor acceptor;\n};\n#endif\n\n}\n}\n\n#endif /* CUKE_WIRESERVER_HPP_ */\n"
  },
  {
    "path": "include/cucumber-cpp/internal/defs.hpp",
    "content": "#include \"step/StepManager.hpp\"\n#include \"hook/HookRegistrar.hpp\"\n#include \"ContextManager.hpp\"\n#include \"Macros.hpp\"\n#include \"drivers/DriverSelector.hpp\"\n"
  },
  {
    "path": "include/cucumber-cpp/internal/drivers/BoostDriver.hpp",
    "content": "#ifndef CUKE_BOOSTDRIVER_HPP_\n#define CUKE_BOOSTDRIVER_HPP_\n\n#include \"../step/StepManager.hpp\"\n#include <cucumber-cpp/internal/CukeExport.hpp>\n\nnamespace cucumber {\nnamespace internal {\n\nclass CukeBoostLogInterceptor;\n\nclass CUCUMBER_CPP_EXPORT BoostStep : public BasicStep {\nprotected:\n    const InvokeResult invokeStepBody() override;\n\nprivate:\n    static void initBoostTest();\n    void runWithMasterSuite();\n};\n\n#define STEP_INHERITANCE(step_name) ::cucumber::internal::BoostStep\n\n}\n}\n\n#endif /* CUKE_BOOSTDRIVER_HPP_ */\n"
  },
  {
    "path": "include/cucumber-cpp/internal/drivers/DriverSelector.hpp",
    "content": "#if defined(GTEST_INCLUDE_GTEST_GTEST_H_) || defined(GOOGLETEST_INCLUDE_GTEST_GTEST_H_)\n    #include \"GTestDriver.hpp\"\n#elif defined(BOOST_TEST_CASE)\n    #include \"BoostDriver.hpp\"\n#elif defined(QTEST_H)\n    #include \"QtTestDriver.hpp\"\n#endif\n"
  },
  {
    "path": "include/cucumber-cpp/internal/drivers/GTestDriver.hpp",
    "content": "#ifndef CUKE_GTESTDRIVER_HPP_\n#define CUKE_GTESTDRIVER_HPP_\n\n#include <cucumber-cpp/internal/CukeExport.hpp>\n#include \"../step/StepManager.hpp\"\n\n#include <iostream>\n\nnamespace cucumber {\nnamespace internal {\n\nclass CUCUMBER_CPP_EXPORT GTestStep : public BasicStep {\nprotected:\n    const InvokeResult invokeStepBody() override;\n\nprivate:\n    void initGTest();\n    void initFlags();\n\nprotected:\n    static bool initialized;\n};\n\n#define STEP_INHERITANCE(step_name) ::cucumber::internal::GTestStep\n\n}\n}\n\n#endif /* CUKE_GTESTDRIVER_HPP_ */\n"
  },
  {
    "path": "include/cucumber-cpp/internal/drivers/GenericDriver.hpp",
    "content": "#ifndef CUKE_GENERICDRIVER_HPP_\n#define CUKE_GENERICDRIVER_HPP_\n\n#include \"../step/StepManager.hpp\"\n#include <cucumber-cpp/internal/CukeExport.hpp>\n\nnamespace cucumber {\nnamespace internal {\n\nclass CUCUMBER_CPP_EXPORT GenericStep : public BasicStep {\nprotected:\n    const InvokeResult invokeStepBody() override;\n};\n\n#define STEP_INHERITANCE(step_name) virtual ::cucumber::internal::GenericStep\n\n}\n}\n\n#endif /* CUKE_GENERICDRIVER_HPP_ */\n"
  },
  {
    "path": "include/cucumber-cpp/internal/drivers/QtTestDriver.hpp",
    "content": "#ifndef CUKE_QTTESTDRIVER_HPP_\n#define CUKE_QTTESTDRIVER_HPP_\n\n#include \"../step/StepManager.hpp\"\n#include <cucumber-cpp/internal/CukeExport.hpp>\n#include <QObject>\n\nnamespace cucumber {\nnamespace internal {\n\nclass CUCUMBER_CPP_EXPORT QtTestStep : public BasicStep {\n    friend class QtTestObject;\n\npublic:\n    QtTestStep() :\n        BasicStep() {\n    }\n\nprotected:\n    const InvokeResult invokeStepBody() override;\n};\n\n#define STEP_INHERITANCE(step_name) ::cucumber::internal::QtTestStep\n\nclass QtTestObject : public QObject {\n    Q_OBJECT\npublic:\n    QtTestObject(QtTestStep* qtTestStep) :\n        step(qtTestStep) {\n    }\n\nprotected:\n    QtTestStep* step;\n\nprivate slots:\n    void test() const {\n        step->body();\n    }\n};\n\n}\n}\n\n#endif /* CUKE_QTTESTDRIVER_HPP_ */\n"
  },
  {
    "path": "include/cucumber-cpp/internal/hook/HookMacros.hpp",
    "content": "#ifndef CUKE_HOOKMACROS_HPP_\n#define CUKE_HOOKMACROS_HPP_\n\n#include \"../RegistrationMacros.hpp\"\n\n// ************************************************************************** //\n// **************                 BEFORE HOOK                  ************** //\n// ************************************************************************** //\n\n#define BEFORE(...)                                           \\\n    BEFORE_WITH_NAME_(CUKE_GEN_OBJECT_NAME_, \"\" #__VA_ARGS__) \\\n    /**/\n\n#define BEFORE_WITH_NAME_(step_name, tag_expression)          \\\n    CUKE_OBJECT_(                                             \\\n        step_name,                                            \\\n        ::cucumber::internal::BeforeHook,                     \\\n        BEFORE_HOOK_REGISTRATION_(step_name, tag_expression), \\\n        ()                                                    \\\n    )                                                         \\\n    /**/\n\n#define BEFORE_HOOK_REGISTRATION_(step_name, tag_expression) \\\n    ::cucumber::internal::registerBeforeHook<step_name>(tag_expression) /**/\n\n// ************************************************************************** //\n// **************              AROUND_STEP HOOK                ************** //\n// ************************************************************************** //\n\n#define AROUND_STEP(...)                                           \\\n    AROUND_STEP_WITH_NAME_(CUKE_GEN_OBJECT_NAME_, \"\" #__VA_ARGS__) \\\n    /**/\n\n#define AROUND_STEP_WITH_NAME_(step_name, tag_expression)          \\\n    CUKE_OBJECT_(                                                  \\\n        step_name,                                                 \\\n        ::cucumber::internal::AroundStepHook,                      \\\n        AROUND_STEP_HOOK_REGISTRATION_(step_name, tag_expression), \\\n        ()                                                         \\\n    )                                                              \\\n    /**/\n\n#define AROUND_STEP_HOOK_REGISTRATION_(step_name, tag_expression) \\\n    ::cucumber::internal::registerAroundStepHook<step_name>(tag_expression) /**/\n\n// ************************************************************************** //\n// **************               AFTER_STEP HOOK                ************** //\n// ************************************************************************** //\n\n#define AFTER_STEP(...)                                           \\\n    AFTER_STEP_WITH_NAME_(CUKE_GEN_OBJECT_NAME_, \"\" #__VA_ARGS__) \\\n    /**/\n\n#define AFTER_STEP_WITH_NAME_(step_name, tag_expression)          \\\n    CUKE_OBJECT_(                                                 \\\n        step_name,                                                \\\n        ::cucumber::internal::AfterStepHook,                      \\\n        AFTER_STEP_HOOK_REGISTRATION_(step_name, tag_expression), \\\n        ()                                                        \\\n    )                                                             \\\n    /**/\n\n#define AFTER_STEP_HOOK_REGISTRATION_(step_name, tag_expression) \\\n    ::cucumber::internal::registerAfterStepHook<step_name>(tag_expression) /**/\n\n// ************************************************************************** //\n// **************                  AFTER HOOK                  ************** //\n// ************************************************************************** //\n\n#define AFTER(...)                                           \\\n    AFTER_WITH_NAME_(CUKE_GEN_OBJECT_NAME_, \"\" #__VA_ARGS__) \\\n    /**/\n\n#define AFTER_WITH_NAME_(step_name, tag_expression)          \\\n    CUKE_OBJECT_(                                            \\\n        step_name,                                           \\\n        ::cucumber::internal::AfterHook,                     \\\n        AFTER_HOOK_REGISTRATION_(step_name, tag_expression), \\\n        ()                                                   \\\n    )                                                        \\\n    /**/\n\n#define AFTER_HOOK_REGISTRATION_(step_name, tag_expression) \\\n    ::cucumber::internal::registerAfterHook<step_name>(tag_expression) /**/\n\n// ************************************************************************** //\n// **************                BEFORE_ALL HOOK               ************** //\n// ************************************************************************** //\n\n#define BEFORE_ALL()                             \\\n    BEFORE_ALL_WITH_NAME_(CUKE_GEN_OBJECT_NAME_) \\\n    /**/\n\n#define BEFORE_ALL_WITH_NAME_(step_name)          \\\n    CUKE_OBJECT_(                                 \\\n        step_name,                                \\\n        ::cucumber::internal::BeforeAllHook,      \\\n        BEFORE_ALL_HOOK_REGISTRATION_(step_name), \\\n        ()                                        \\\n    )                                             \\\n    /**/\n\n#define BEFORE_ALL_HOOK_REGISTRATION_(step_name) \\\n    ::cucumber::internal::registerBeforeAllHook<step_name>() /**/\n\n// ************************************************************************** //\n// **************                 AFTER_ALL HOOK               ************** //\n// ************************************************************************** //\n\n#define AFTER_ALL()                             \\\n    AFTER_ALL_WITH_NAME_(CUKE_GEN_OBJECT_NAME_) \\\n    /**/\n\n#define AFTER_ALL_WITH_NAME_(step_name)                                                            \\\n    CUKE_OBJECT_(                                                                                  \\\n        step_name, ::cucumber::internal::AfterAllHook, AFTER_ALL_HOOK_REGISTRATION_(step_name), () \\\n    )                                                                                              \\\n    /**/\n\n#define AFTER_ALL_HOOK_REGISTRATION_(step_name) \\\n    ::cucumber::internal::registerAfterAllHook<step_name>() /**/\n\n#endif /* CUKE_HOOKMACROS_HPP_ */\n"
  },
  {
    "path": "include/cucumber-cpp/internal/hook/HookRegistrar.hpp",
    "content": "#ifndef CUKE_HOOKREGISTRAR_HPP_\n#define CUKE_HOOKREGISTRAR_HPP_\n\n#include <cucumber-cpp/internal/CukeExport.hpp>\n#include \"Tag.hpp\"\n#include \"../Scenario.hpp\"\n#include \"../step/StepManager.hpp\"\n\n#include <memory>\n#include <list>\n\nnamespace cucumber {\nnamespace internal {\n\nclass CUCUMBER_CPP_EXPORT CallableStep {\npublic:\n    virtual void call() = 0;\n};\n\nclass CUCUMBER_CPP_EXPORT Hook {\npublic:\n    virtual ~Hook() = default;\n\n    void setTags(const std::string& csvTagNotation);\n    virtual void invokeHook(Scenario* scenario, CallableStep* step);\n    virtual void skipHook();\n    virtual void body() = 0;\n\nprotected:\n    bool tagsMatch(Scenario* scenario);\n\n    template<typename Derived, typename R>\n    static R invokeWithArgs(Derived& that, R (Derived::*f)()) {\n        return (that.*f)();\n    }\n\nprivate:\n    AndTagExpression tagExpression;\n};\n\nclass CUCUMBER_CPP_EXPORT BeforeHook : public Hook {};\n\nclass CUCUMBER_CPP_EXPORT AroundStepHook : public Hook {\npublic:\n    void invokeHook(Scenario* scenario, CallableStep* step) override;\n    void skipHook() override;\n\nprotected:\n    CallableStep* step;\n};\n\nclass CUCUMBER_CPP_EXPORT AfterStepHook : public Hook {};\n\nclass CUCUMBER_CPP_EXPORT AfterHook : public Hook {};\n\nclass CUCUMBER_CPP_EXPORT UnconditionalHook : public Hook {\npublic:\n    void invokeHook(Scenario* scenario, CallableStep* step) override;\n};\n\nclass CUCUMBER_CPP_EXPORT BeforeAllHook : public UnconditionalHook {};\n\nclass CUCUMBER_CPP_EXPORT AfterAllHook : public UnconditionalHook {};\n\nclass CUCUMBER_CPP_EXPORT HookRegistrar {\npublic:\n    typedef std::list<std::shared_ptr<Hook>> hook_list_type;\n    typedef std::list<std::shared_ptr<AroundStepHook>> aroundhook_list_type;\n\n    static void addBeforeHook(std::shared_ptr<BeforeHook> afterHook);\n    static void execBeforeHooks(Scenario* scenario);\n\n    static void addAroundStepHook(std::shared_ptr<AroundStepHook> aroundStepHook);\n    static InvokeResult execStepChain(\n        Scenario* scenario, const StepInfo* stepInfo, const InvokeArgs* pArgs\n    );\n\n    static void addAfterStepHook(std::shared_ptr<AfterStepHook> afterStepHook);\n    static void execAfterStepHooks(Scenario* scenario);\n\n    static void addAfterHook(std::shared_ptr<AfterHook> afterHook);\n    static void execAfterHooks(Scenario* scenario);\n\n    static void addBeforeAllHook(std::shared_ptr<BeforeAllHook> beforeAllHook);\n    static void execBeforeAllHooks();\n\n    static void addAfterAllHook(std::shared_ptr<AfterAllHook> afterAllHook);\n    static void execAfterAllHooks();\n\nprivate:\n    static void execHooks(HookRegistrar::hook_list_type& hookList, Scenario* scenario);\n\nprotected:\n    static hook_list_type& beforeAllHooks();\n    static hook_list_type& beforeHooks();\n    static aroundhook_list_type& aroundStepHooks();\n    static hook_list_type& afterStepHooks();\n    static hook_list_type& afterHooks();\n    static hook_list_type& afterAllHooks();\n\nprivate:\n    // We're a singleton so don't allow instances\n    HookRegistrar() = delete;\n};\n\nclass CUCUMBER_CPP_EXPORT StepCallChain {\npublic:\n    StepCallChain(\n        Scenario* scenario,\n        const StepInfo* stepInfo,\n        const InvokeArgs* pStepArgs,\n        HookRegistrar::aroundhook_list_type& aroundHooks\n    );\n    InvokeResult exec();\n    void execNext();\n\nprivate:\n    void execStep();\n\n    Scenario* scenario;\n    const StepInfo* stepInfo;\n    const InvokeArgs* pStepArgs;\n\n    HookRegistrar::aroundhook_list_type::iterator nextHook;\n    HookRegistrar::aroundhook_list_type::iterator hookEnd;\n    InvokeResult result;\n};\n\nclass CUCUMBER_CPP_EXPORT CallableStepChain : public CallableStep {\npublic:\n    CallableStepChain(StepCallChain* scc);\n    void call() override;\n\nprivate:\n    StepCallChain* scc;\n};\n\ntemplate<class T>\nstatic int registerBeforeHook(const std::string& csvTagNotation) {\n    std::shared_ptr<T> hook(std::make_shared<T>());\n    hook->setTags(csvTagNotation);\n    HookRegistrar::addBeforeHook(hook);\n    return 0; // We are not interested in the ID at this time\n}\n\ntemplate<class T>\nstatic int registerAroundStepHook(const std::string& csvTagNotation) {\n    std::shared_ptr<T> hook(std::make_shared<T>());\n    hook->setTags(csvTagNotation);\n    HookRegistrar::addAroundStepHook(hook);\n    return 0;\n}\n\ntemplate<class T>\nstatic int registerAfterStepHook(const std::string& csvTagNotation) {\n    std::shared_ptr<T> hook(std::make_shared<T>());\n    hook->setTags(csvTagNotation);\n    HookRegistrar::addAfterStepHook(hook);\n    return 0;\n}\n\ntemplate<class T>\nstatic int registerAfterHook(const std::string& csvTagNotation) {\n    std::shared_ptr<T> hook(std::make_shared<T>());\n    hook->setTags(csvTagNotation);\n    HookRegistrar::addAfterHook(hook);\n    return 0;\n}\n\ntemplate<class T>\nstatic int registerBeforeAllHook() {\n    HookRegistrar::addBeforeAllHook(std::make_shared<T>());\n    return 0;\n}\n\ntemplate<class T>\nstatic int registerAfterAllHook() {\n    HookRegistrar::addAfterAllHook(std::make_shared<T>());\n    return 0;\n}\n\n}\n}\n\n#endif /* CUKE_HOOKREGISTRAR_HPP_ */\n"
  },
  {
    "path": "include/cucumber-cpp/internal/hook/Tag.hpp",
    "content": "#ifndef CUKE_TAG_HPP_\n#define CUKE_TAG_HPP_\n\n#include <string>\n#include <vector>\n\n#include <cucumber-cpp/internal/CukeExport.hpp>\n#include \"../utils/Regex.hpp\"\n\nnamespace cucumber {\nnamespace internal {\n\nclass CUCUMBER_CPP_EXPORT TagExpression {\npublic:\n    typedef std::vector<std::string> tag_list;\n\n    virtual ~TagExpression() = default;\n    virtual bool matches(const tag_list& tags) const = 0;\n};\n\nclass CUCUMBER_CPP_EXPORT OrTagExpression : public TagExpression {\npublic:\n    OrTagExpression(const std::string& csvTagNotation);\n    bool matches(const tag_list& tags) const override;\n\nprivate:\n    bool orTagMatchesTagList(const std::string& currentOrTag, const tag_list& tags) const;\n\n    tag_list orTags;\n\n    static Regex& csvTagNotationRegex();\n};\n\nclass CUCUMBER_CPP_EXPORT AndTagExpression : public TagExpression {\npublic:\n    AndTagExpression() = default;\n    AndTagExpression(const std::string& csvTagNotation);\n    bool matches(const tag_list& tags) const override;\n\nprivate:\n    typedef std::vector<OrTagExpression> or_expressions_type;\n    or_expressions_type orExpressions;\n\n    static Regex& csvTagNotationRegex();\n};\n\n}\n}\n\n#endif /* CUKE_TAG_HPP_ */\n"
  },
  {
    "path": "include/cucumber-cpp/internal/step/StepMacros.hpp",
    "content": "#ifndef CUKE_STEPMACROS_HPP_\n#define CUKE_STEPMACROS_HPP_\n\n#include \"../RegistrationMacros.hpp\"\n\n// ************************************************************************** //\n// **************                     STEP                     ************** //\n// ************************************************************************** //\n\n#define CUKE_STEP_GET_MATCHER_(step_matcher, ...) step_matcher\n#define CUKE_STEP_GET_ARGS_(step_matcher, args, ...) args\n\n#define CUKE_STEP_(...)                          \\\n    CUKE_STEP_WITH_NAME_(                        \\\n        CUKE_GEN_OBJECT_NAME_,                   \\\n        CUKE_STEP_GET_MATCHER_(__VA_ARGS__, ()), \\\n        CUKE_STEP_GET_ARGS_(__VA_ARGS__, (), ()) \\\n    )                                            \\\n    /**/\n\n#define CUKE_STEP_WITH_NAME_(step_name, step_matcher, args) \\\n    CUKE_OBJECT_(                                           \\\n        step_name,                                          \\\n        STEP_INHERITANCE(step_name),                        \\\n        CUKE_STEP_REGISTRATION_(step_name, step_matcher),   \\\n        args                                                \\\n    )                                                       \\\n    /**/\n\n#define CUKE_STEP_REGISTRATION_(step_name, step_matcher) \\\n    ::cucumber::internal::registerStep<step_name>(step_matcher, __FILE__, __LINE__) /**/\n\n// ************************************************************************** //\n// **************               GIVEN/WHEN/THEN                ************** //\n// ************************************************************************** //\n\n#define GIVEN CUKE_STEP_\n#define WHEN CUKE_STEP_\n#define THEN CUKE_STEP_\n\n// ************************************************************************** //\n// **************                 REGEX_PARAM                  ************** //\n// ************************************************************************** //\n\n#define REGEX_PARAM(type, name) const type name(getInvokeArg<type>())\n#define TABLE_PARAM(name) const ::cucumber::internal::Table& name = getArgs()->getTableArg()\n\n#endif /* CUKE_STEPMACROS_HPP_ */\n"
  },
  {
    "path": "include/cucumber-cpp/internal/step/StepManager.hpp",
    "content": "#ifndef CUKE_STEPMANAGER_HPP_\n#define CUKE_STEPMANAGER_HPP_\n\n#include <map>\n#include <sstream>\n#include <stdexcept>\n#include <string>\n#include <vector>\n#include <memory>\n#include <type_traits>\n\n#include <cucumber-cpp/internal/CukeExport.hpp>\n#include \"../Table.hpp\"\n#include \"../utils/IndexSequence.hpp\"\n#include \"../utils/Regex.hpp\"\n\nnamespace cucumber {\nnamespace internal {\n\ntypedef unsigned int step_id_type;\n\nclass StepInfo;\n\nclass CUCUMBER_CPP_EXPORT SingleStepMatch {\npublic:\n    typedef RegexMatch::submatches_type submatches_type;\n\n    operator const void*() const;\n\n    std::shared_ptr<const StepInfo> stepInfo;\n    submatches_type submatches;\n};\n\nclass CUCUMBER_CPP_EXPORT MatchResult {\npublic:\n    typedef std::vector<SingleStepMatch> match_results_type;\n\n    const match_results_type& getResultSet();\n    void addMatch(SingleStepMatch match);\n\n    explicit operator bool() const;\n\nprivate:\n    match_results_type resultSet;\n};\n\nclass CUCUMBER_CPP_EXPORT InvokeArgs {\n    typedef std::vector<std::string> args_type;\n\npublic:\n    typedef args_type::size_type size_type;\n\n    InvokeArgs() = default;\n\n    void addArg(const std::string arg);\n    Table& getVariableTableArg();\n\n    template<class T>\n    T getInvokeArg(size_type i) const;\n    const Table& getTableArg() const;\n\nprivate:\n    Table tableArg;\n    args_type args;\n};\n\nenum InvokeResultType {\n    SUCCESS,\n    FAILURE,\n    PENDING\n};\n\nclass CUCUMBER_CPP_EXPORT InvokeResult {\nprivate:\n    InvokeResultType type;\n    std::string description;\n\n    InvokeResult(const InvokeResultType type, const char* description);\n\npublic:\n    InvokeResult();\n    InvokeResult(const InvokeResult& ir);\n    InvokeResult& operator=(const InvokeResult& rhs);\n\n    static InvokeResult success();\n    static InvokeResult failure(const char* description);\n    static InvokeResult failure(const std::string& description);\n    static InvokeResult pending(const char* description);\n\n    bool isSuccess() const;\n    bool isPending() const;\n    InvokeResultType getType() const;\n    const std::string& getDescription() const;\n};\n\nclass CUCUMBER_CPP_EXPORT StepInfo : public std::enable_shared_from_this<StepInfo> {\npublic:\n    StepInfo(const std::string& stepMatcher, const std::string source);\n\n    virtual ~StepInfo() = default;\n\n    SingleStepMatch matches(const std::string& stepDescription) const;\n    virtual InvokeResult invokeStep(const InvokeArgs* pArgs) const = 0;\n\n    step_id_type id;\n    Regex regex;\n    const std::string source;\n\nprivate:\n    // Shut up MSVC warning C4512: assignment operator could not be generated\n    StepInfo& operator=(const StepInfo& other);\n};\n\nclass CUCUMBER_CPP_EXPORT BasicStep {\npublic:\n    virtual ~BasicStep() = default;\n\n    InvokeResult invoke(const InvokeArgs* pArgs);\n\nprotected:\n    typedef const Table table_type;\n    typedef const Table::hashes_type table_hashes_type;\n\n    virtual const InvokeResult invokeStepBody() = 0;\n    virtual void body() = 0;\n\n    void pending(const char* description);\n    void pending();\n\n    template<class T>\n    const T getInvokeArg();\n    const InvokeArgs* getArgs();\n\n    template<typename Derived, typename R, typename... Args, std::size_t... N>\n    static R invokeWithIndexedArgs(Derived& that, R (Derived::*f)(Args...), index_sequence<N...>) {\n        return (that.*f)(that.pArgs->template getInvokeArg<typename std::decay<Args>::type>(N)...);\n    }\n\n    template<typename Derived, typename R, typename... Args>\n    static R invokeWithArgs(Derived& that, R (Derived::*f)(Args...)) {\n        that.currentArgIndex = sizeof...(Args);\n        return invokeWithIndexedArgs(that, f, index_sequence_for<Args...>{});\n    }\n\nprivate:\n    // FIXME: awful hack because of Boost::Test\n    InvokeResult currentResult;\n\n    const InvokeArgs* pArgs;\n    InvokeArgs::size_type currentArgIndex;\n};\n\ntemplate<class T>\nclass StepInvoker : public StepInfo {\npublic:\n    StepInvoker(const std::string& stepMatcher, const std::string source);\n\n    InvokeResult invokeStep(const InvokeArgs* args) const override;\n};\n\nclass CUCUMBER_CPP_EXPORT StepManager {\nprotected:\n    typedef std::map<step_id_type, std::shared_ptr<const StepInfo>> steps_type;\n\npublic:\n    static step_id_type addStep(std::shared_ptr<StepInfo> stepInfo);\n    static MatchResult stepMatches(const std::string& stepDescription);\n    static const StepInfo* getStep(step_id_type id);\n\nprotected:\n    static steps_type& steps();\n\nprivate:\n    // We're a singleton so don't allow instances\n    StepManager() = delete;\n};\n\nstatic inline std::string toSourceString(const char* filePath, const int line) {\n    using namespace std;\n    stringstream s;\n    string file(filePath);\n    string::size_type pos = file.find_last_of(\"/\\\\\");\n    if (pos == string::npos) {\n        s << file;\n    } else {\n        s << file.substr(++pos);\n    }\n    s << \":\" << line;\n    return s.str();\n}\n\ntemplate<class T>\nstatic int registerStep(const std::string& stepMatcher, const char* file, const int line) {\n    return StepManager::addStep(\n        std::make_shared<StepInvoker<T>>(stepMatcher, toSourceString(file, line))\n    );\n}\n\ntemplate<typename T>\nT fromString(const std::string& s) {\n    std::istringstream stream(s);\n    T t;\n    stream >> t;\n    if (stream.fail()) {\n        throw std::invalid_argument(\"Cannot convert parameter\");\n    }\n    return t;\n}\n\ntemplate<>\ninline std::string fromString(const std::string& s) {\n    return s;\n}\n\ntemplate<typename T>\nstd::string toString(T arg) {\n    std::stringstream s;\n    s << arg;\n    return s.str();\n}\n\ntemplate<typename T>\nT InvokeArgs::getInvokeArg(size_type i) const {\n    if (i >= args.size()) {\n        throw std::invalid_argument(\"Parameter not found\");\n    }\n    return fromString<T>(args.at(i));\n}\n\ntemplate<typename T>\nconst T BasicStep::getInvokeArg() {\n    return pArgs->getInvokeArg<T>(currentArgIndex++);\n}\n\ntemplate<class T>\nStepInvoker<T>::StepInvoker(const std::string& stepMatcher, const std::string source) :\n    StepInfo(stepMatcher, source) {\n}\n\ntemplate<class T>\nInvokeResult StepInvoker<T>::invokeStep(const InvokeArgs* pArgs) const {\n    T t;\n    return t.invoke(pArgs);\n}\n\n}\n}\n\n#endif /* CUKE_STEPMANAGER_HPP_ */\n"
  },
  {
    "path": "include/cucumber-cpp/internal/utils/IndexSequence.hpp",
    "content": "#ifndef CUKE_INDEXSEQ_HPP_\n#define CUKE_INDEXSEQ_HPP_\n\n#include <utility>\n\nnamespace cucumber {\nnamespace internal {\n\nusing ::std::index_sequence;\nusing ::std::index_sequence_for;\n\n}\n}\n\n#endif /* CUKE_INDEXSEQ_HPP_ */\n"
  },
  {
    "path": "include/cucumber-cpp/internal/utils/Regex.hpp",
    "content": "#ifndef CUKE_REGEX_HPP_\n#define CUKE_REGEX_HPP_\n\n#include <cstddef>\n#include <vector>\n\n#include <regex>\n\nnamespace cucumber {\nnamespace internal {\n\nstruct RegexSubmatch {\n    std::string value;\n    std::ptrdiff_t position;\n};\n\nclass RegexMatch {\npublic:\n    typedef std::vector<RegexSubmatch> submatches_type;\n\n    virtual ~RegexMatch() = default;\n\n    bool matches();\n    const submatches_type& getSubmatches();\n\nprotected:\n    bool regexMatched;\n    submatches_type submatches;\n};\n\nclass FindRegexMatch : public RegexMatch {\npublic:\n    FindRegexMatch(const std::regex& regexImpl, const std::string& expression);\n};\n\nclass FindAllRegexMatch : public RegexMatch {\npublic:\n    FindAllRegexMatch(const std::regex& regexImpl, const std::string& expression);\n};\n\nclass Regex {\nprivate:\n    std::regex regexImpl;\n    const std::string regexString;\n\npublic:\n    Regex(std::string expr);\n\n    std::shared_ptr<RegexMatch> find(const std::string& expression) const;\n    std::shared_ptr<RegexMatch> findAll(const std::string& expression) const;\n\n    std::string str() const;\n};\n\n}\n}\n\n#endif /* CUKE_REGEX_HPP_ */\n"
  },
  {
    "path": "run-linux.sh",
    "content": "#!/bin/sh\nset -e #break script on non-zero exitcode from any command\nset -x #display command being executed\n\nCTEST_OUTPUT_ON_FAILURE=ON\nexport CTEST_OUTPUT_ON_FAILURE\n\ncmake -E make_directory build\ncmake -E chdir build cmake \\\n    -G Ninja \\\n    -DCUKE_STRICT=on \\\n    -DCUKE_ENABLE_BOOST_TEST=on \\\n    -DCUKE_ENABLE_GTEST=on \\\n    -DCUKE_ENABLE_QT_6=on \\\n    -DCUKE_ENABLE_EXAMPLES=on \\\n    -DCUKE_TESTS_UNIT=on \\\n    -DCUKE_CODE_COVERAGE=on \\\n    ..\ncmake --build build --parallel --verbose\n\n#\n# Run tests\n#\n\ncmake --build build --target test\n\n#\n# Execute Calc examples\n#\n\nfor TEST in \\\n    build/examples/Calc/GTestCalculatorSteps \\\n    build/examples/Calc/QtTestCalculatorSteps \\\n    build/examples/Calc/BoostCalculatorSteps \\\n    build/examples/Calc/FuncArgsCalculatorSteps \\\n; do\n    \"${TEST}\" > /dev/null &\n    sleep 1\n    (cd examples/Calc; cucumber)\n    wait %\ndone\n\n#\n# Execute QtCalc examples\n#\n\nfor TEST in \\\n    build/examples/CalcQt/GTestCalculatorQtSteps \\\n    build/examples/CalcQt/QtTestCalculatorQtSteps \\\n    build/examples/CalcQt/BoostCalculatorQtSteps \\\n; do\n    \"${TEST}\" 2> /dev/null &\n    sleep 1\n    (cd examples/CalcQt; cucumber)\n    wait %\ndone\n\n#\n# Execute feature showcase on Unix socket\n#\n\nSOCK=`pwd`/cucumber.wire.sock\nTEST=build/examples/FeatureShowcase/FeatureShowcaseSteps\necho \"unix: ${SOCK}\" > examples/FeatureShowcase/features/step_definitions/cucumber.wire\n\"${TEST}\" --unix \"${SOCK}\" > /dev/null &\n(cd examples/FeatureShowcase; cucumber)\nwait %\n\nmkdir -p coverage\ngcovr build/ --html-details --output coverage/index.html --xml coverage/cobertura.xml\n\nsudo cmake --install build\n"
  },
  {
    "path": "run-windows.ps1",
    "content": "# --- Function definitions ---\nfunction Invoke-CMake {\n    param (\n        $Arguments\n    )\n    $process = Start-Process \"cmake\" -ArgumentList \"$Arguments\" -NoNewWindow -Wait -PassThru\n    If ($process.ExitCode -ne 0) {\n        Write-Host \"Abort script execution due to CMake error.\"\n        Exit(42)\n    }\n}\n\nfunction Get-VariableOrEnv {\n    param (\n        [string]$Name\n    )\n\n    $envValue = [Environment]::GetEnvironmentVariable($Name)\n    if ($envValue -ne $null) {\n        return $envValue\n    }\n\n    if (Get-Variable -Name $Name -ErrorAction SilentlyContinue) {\n        return (Get-Variable -Name $Name).Value\n    }\n\n    return $null\n}\n\n# --- Variable definitions ---\n$cpp_standard = Get-VariableOrEnv -Name \"cpp_standard\"\n\n$nlohmann_json_DIR = Get-VariableOrEnv -Name \"nlohmann_json_DIR\"\n$Asio_ROOT = Get-VariableOrEnv -Name \"Asio_ROOT\"\n$TCLAP_ROOT = Get-VariableOrEnv -Name \"TCLAP_ROOT\"\n$Env:BOOST_ROOT = \"boost_${Env:BOOST_VERSION}\".Replace(\".\",\"_\")\n\n$Env:CTEST_OUTPUT_ON_FAILURE=\"ON\"\n\n\n# --- Script ---\n\nInvoke-CMake \"-E\",\"make_directory\",\"build\"\n\n$cmake_params = \"-E chdir build cmake\",\n    \"-DBUILD_SHARED_LIBS=`\"${BUILD_SHARED_LIBS}`\"\",\n    \"-DCMAKE_INSTALL_PREFIX=${HOME}/.local\"\n\n$cmake_params += \"-DCMAKE_CXX_STANDARD=${cpp_standard}\"\n\n$cmake_params += \"-DCUKE_ENABLE_BOOST_TEST=OFF\"\n$cmake_params += \"-DCUKE_ENABLE_GTEST=OFF\"\n$cmake_params += \"-DCUKE_ENABLE_QT_6=OFF\"\n$cmake_params += \"-DCUKE_ENABLE_EXAMPLES=OFF\"\n$cmake_params += \"-DCUKE_TESTS_UNIT=OFF\"\n$cmake_params += \"-DCUKE_CODE_COVERAGE=OFF\"\n\n$cmake_params += \"-Dnlohmann_json_DIR=${nlohmann_json_DIR}\"\n$cmake_params += \"-DAsio_ROOT=${Asio_ROOT}\"\n$cmake_params += \"-DTCLAP_ROOT=${TCLAP_ROOT}\"\n\n$cmake_params += \"..\"\n\n\nInvoke-CMake \"$cmake_params\"\nInvoke-CMake \"--build\",\"build\" #,\"--parallel\"\n"
  },
  {
    "path": "src/CMakeLists.txt",
    "content": "include(GenerateExportHeader)\n\nfind_package(nlohmann_json 3.10.5 REQUIRED)\nfind_package(Asio REQUIRED)\nfind_package(TCLAP REQUIRED)\ninclude(../cmake/modules/GitVersion.cmake)\n\nset(CUKE_SOURCES\n    drivers/GenericDriver.cpp\n    ContextManager.cpp\n    CukeCommands.cpp\n    CukeEngine.cpp\n    CukeEngineImpl.cpp\n    StepManager.cpp\n    HookRegistrar.cpp\n    Regex.cpp\n    Scenario.cpp\n    Table.cpp\n    Tag.cpp\n    connectors/wire/WireServer.cpp\n    connectors/wire/WireProtocol.cpp\n    connectors/wire/WireProtocolCommands.cpp\n    )\n\nif(TARGET GTest::gtest)\n    list(APPEND CUKE_EXTRA_PRIVATE_LIBRARIES GTest::gtest)\n    list(APPEND CUKE_SOURCES drivers/GTestDriver.cpp)\nendif()\n\nif(TARGET Boost::unit_test_framework)\n    list(APPEND CUKE_EXTRA_PRIVATE_LIBRARIES Boost::unit_test_framework)\n    list(APPEND CUKE_SOURCES drivers/BoostDriver.cpp)\n    list(APPEND CUKE_DEP_LIBRARIES ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})\nendif()\n\nif(TARGET Qt::Test)\n    qt_wrap_cpp(MOC_FILE ../include/cucumber-cpp/internal/drivers/QtTestDriver.hpp)\n    list(APPEND CUKE_SOURCES ${MOC_FILE})\n    list(APPEND CUKE_SOURCES drivers/QtTestDriver.cpp)\n    list(APPEND CUKE_EXTRA_PRIVATE_LIBRARIES Qt::Test)\nendif()\n\nmessage(STATUS \"Adding header files to project\")\nset(CUKE_HEADERS\n    ../include/cucumber-cpp/autodetect.hpp\n    ../include/cucumber-cpp/defs.hpp\n    ../include/cucumber-cpp/generic.hpp\n    ../include/cucumber-cpp/internal/ContextManager.hpp\n    ../include/cucumber-cpp/internal/CukeCommands.hpp\n    ../include/cucumber-cpp/internal/CukeEngine.hpp\n    ../include/cucumber-cpp/internal/CukeEngineImpl.hpp\n    ../include/cucumber-cpp/internal/Macros.hpp\n    ../include/cucumber-cpp/internal/RegistrationMacros.hpp\n    ../include/cucumber-cpp/internal/Scenario.hpp\n    ../include/cucumber-cpp/internal/Table.hpp\n    ../include/cucumber-cpp/internal/connectors/wire/ProtocolHandler.hpp\n    ../include/cucumber-cpp/internal/connectors/wire/WireProtocol.hpp\n    ../include/cucumber-cpp/internal/connectors/wire/WireProtocolCommands.hpp\n    ../include/cucumber-cpp/internal/connectors/wire/WireServer.hpp\n    ../include/cucumber-cpp/internal/defs.hpp\n    ../include/cucumber-cpp/internal/drivers/BoostDriver.hpp\n    ../include/cucumber-cpp/internal/drivers/DriverSelector.hpp\n    ../include/cucumber-cpp/internal/drivers/GTestDriver.hpp\n    ../include/cucumber-cpp/internal/drivers/GenericDriver.hpp\n    ../include/cucumber-cpp/internal/drivers/QtTestDriver.hpp\n    ../include/cucumber-cpp/internal/hook/HookMacros.hpp\n    ../include/cucumber-cpp/internal/hook/HookRegistrar.hpp\n    ../include/cucumber-cpp/internal/hook/Tag.hpp\n    ../include/cucumber-cpp/internal/step/StepMacros.hpp\n    ../include/cucumber-cpp/internal/step/StepManager.hpp\n    ../include/cucumber-cpp/internal/utils/IndexSequence.hpp\n    ../include/cucumber-cpp/internal/utils/Regex.hpp\n)\nif(MSVC_IDE)\n    source_group(\"Header Files\" FILES ${CUKE_HEADERS})\nendif()\nlist(APPEND CUKE_SOURCES ${CUKE_HEADERS})\n\n# Library for unit tests relying on internals\nadd_library(cucumber-cpp-internal STATIC ${CUKE_SOURCES})\n\nadd_library(cucumber-cpp-nomain ${CUKE_SOURCES})\nadd_library(cucumber-cpp ${CUKE_SOURCES} main.cpp)\n\nset_target_properties(\n    cucumber-cpp-internal\n    cucumber-cpp\n    cucumber-cpp-nomain\n    PROPERTIES\n        DEFINE_SYMBOL cucumber_cpp_EXPORTS\n        CXX_VISIBILITY_PRESET hidden\n        VISIBILITY_INLINES_HIDDEN ON\n)\n\ngenerate_export_header(cucumber-cpp\n    EXPORT_FILE_NAME \"cucumber-cpp/internal/CukeExport.hpp\"\n)\n\nforeach(TARGET\n        cucumber-cpp-internal\n        cucumber-cpp-nomain\n        cucumber-cpp\n)\n    target_include_directories(${TARGET}\n        PUBLIC\n            $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>\n            $<BUILD_INTERFACE:${CUKE_INCLUDE_DIR}>\n            $<BUILD_INTERFACE:${ASIO_INCLUDE_DIR}>\n            $<BUILD_INTERFACE:${TCLAP_INCLUDE_DIR}>\n            $<INSTALL_INTERFACE:$<INSTALL_PREFIX>/include>\n    )\n    target_link_libraries(${TARGET}\n        PRIVATE\n            ${CUKE_EXTRA_PRIVATE_LIBRARIES}\n            nlohmann_json::nlohmann_json\n    )\n    # Don't export or import symbols for statically linked libraries\n    get_property(type TARGET ${TARGET} PROPERTY TYPE)\n    if(NOT \"${type}\" MATCHES \"^(SHARED|MODULE)_LIBRARY$\")\n        target_compile_definitions(${TARGET} PUBLIC CUCUMBER_CPP_STATIC_DEFINE)\n    endif()\n    if(MINGW)\n        target_link_libraries(${TARGET}\n            PRIVATE\n                ws2_32\n        )\n    endif(MINGW)\nendforeach()\n\ngit_get_version(CUKE_VERSION)\nmessage(STATUS \"Version: ${CUKE_VERSION}\")\ntarget_compile_definitions(cucumber-cpp PRIVATE\n    CUKE_VERSION=\"${CUKE_VERSION}\"\n)\n\ninclude(GNUInstallDirs)\ninstall(DIRECTORY ${CUKE_INCLUDE_DIR}/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})\ninstall(\n    FILES\n        \"${CMAKE_CURRENT_BINARY_DIR}/cucumber-cpp/internal/CukeExport.hpp\"\n    DESTINATION \"${CMAKE_INSTALL_INCLUDEDIR}/cucumber-cpp/internal\"\n)\ninstall(\n    TARGETS\n        cucumber-cpp-nomain\n        cucumber-cpp\n    EXPORT   CucumberCpp\n    ARCHIVE  DESTINATION ${CMAKE_INSTALL_LIBDIR}\n    LIBRARY  DESTINATION ${CMAKE_INSTALL_LIBDIR}\n    RUNTIME  DESTINATION ${CMAKE_INSTALL_BINDIR}\n)\ninstall(\n    EXPORT      CucumberCpp\n    NAMESPACE   CucumberCpp::\n    DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake\n    FILE        CucumberCppConfig.cmake\n)\n"
  },
  {
    "path": "src/ContextManager.cpp",
    "content": "#include \"cucumber-cpp/internal/ContextManager.hpp\"\n\nnamespace cucumber {\nnamespace internal {\n\ncontexts_type ContextManager::contexts;\n\nvoid ContextManager::purgeContexts() {\n    contexts.clear();\n}\n\n}\n}\n"
  },
  {
    "path": "src/CukeCommands.cpp",
    "content": "#include \"cucumber-cpp/internal/CukeCommands.hpp\"\n#include \"cucumber-cpp/internal/hook/HookRegistrar.hpp\"\n\n#include <sstream>\n\nnamespace cucumber {\nnamespace internal {\n\nstd::shared_ptr<Scenario> CukeCommands::currentScenario;\n\nCukeCommands::CukeCommands() :\n    hasStarted(false) {\n}\n\nCukeCommands::~CukeCommands() {\n    if (hasStarted) {\n        HookRegistrar::execAfterAllHooks();\n    }\n}\n\nvoid CukeCommands::beginScenario(const TagExpression::tag_list& tags) {\n    if (!hasStarted) {\n        hasStarted = true;\n        HookRegistrar::execBeforeAllHooks();\n    }\n\n    currentScenario = std::make_shared<Scenario>(tags);\n    HookRegistrar::execBeforeHooks(currentScenario.get());\n}\n\nvoid CukeCommands::endScenario() {\n    HookRegistrar::execAfterHooks(currentScenario.get());\n    contextManager.purgeContexts();\n    currentScenario.reset();\n}\n\nconst std::string CukeCommands::snippetText(\n    const std::string stepKeyword, const std::string stepName\n) const {\n    std::stringstream text;\n    std::string stepKeywordUpperCase;\n    std::transform(\n        stepKeyword.begin(), stepKeyword.end(), std::back_inserter(stepKeywordUpperCase), ::toupper\n    );\n    text << stepKeywordUpperCase << \"(\\\"\" << escapeCString(\"^\" + escapeRegex(stepName) + \"$\")\n         << \"\\\") {\\n\"\n         << \"    pending();\\n\"\n         << \"}\\n\";\n    return text.str();\n}\n\nconst std::string CukeCommands::escapeRegex(const std::string reg) const {\n    return regex_replace(\n        reg,\n        std::regex(\"[\\\\|\\\\(\\\\)\\\\[\\\\]\\\\{\\\\}\\\\^\\\\$\\\\*\\\\+\\\\?\\\\.\\\\\\\\]\"),\n        \"\\\\\\\\&\",\n        std::regex_constants::match_default | std::regex_constants::format_sed\n    );\n}\n\nconst std::string CukeCommands::escapeCString(const std::string str) const {\n    return regex_replace(\n        str,\n        std::regex(\"[\\\"\\\\\\\\]\"),\n        \"\\\\\\\\&\",\n        std::regex_constants::match_default | std::regex_constants::format_sed\n    );\n}\n\nMatchResult CukeCommands::stepMatches(const std::string description) const {\n    return StepManager::stepMatches(description);\n}\n\nInvokeResult CukeCommands::invoke(step_id_type id, const InvokeArgs* pArgs) {\n    const StepInfo* const stepInfo = StepManager::getStep(id);\n    InvokeResult result = HookRegistrar::execStepChain(currentScenario.get(), stepInfo, pArgs);\n    HookRegistrar::execAfterStepHooks(currentScenario.get());\n    return result;\n}\n\n}\n}\n"
  },
  {
    "path": "src/CukeEngine.cpp",
    "content": "#include \"cucumber-cpp/internal/CukeEngine.hpp\"\n\nnamespace cucumber {\nnamespace internal {\n\nInvokeException::InvokeException(const std::string& message) :\n    message(message) {\n}\n\nInvokeException::InvokeException(const InvokeException& rhs) :\n    message(rhs.message) {\n}\n\nconst std::string InvokeException::getMessage() const {\n    return message;\n}\n\nInvokeFailureException::InvokeFailureException(\n    const std::string& message, const std::string& exceptionType\n) :\n    InvokeException(message),\n    exceptionType(exceptionType) {\n}\n\nInvokeFailureException::InvokeFailureException(const InvokeFailureException& rhs) :\n    InvokeException(rhs),\n    exceptionType(rhs.exceptionType) {\n}\n\nconst std::string InvokeFailureException::getExceptionType() const {\n    return exceptionType;\n}\n\nPendingStepException::PendingStepException(const std::string& message) :\n    InvokeException(message) {\n}\n\nPendingStepException::PendingStepException(const PendingStepException& rhs) :\n    InvokeException(rhs) {\n}\n\nCukeEngine::CukeEngine() {\n}\n\n}\n}\n"
  },
  {
    "path": "src/CukeEngineImpl.cpp",
    "content": "#include \"cucumber-cpp/internal/CukeEngineImpl.hpp\"\n\nnamespace cucumber {\nnamespace internal {\n\nnamespace {\n\nstd::string convertId(step_id_type id) {\n    std::stringstream ss;\n    ss << id;\n    return ss.str();\n}\n\nstep_id_type convertId(const std::string& stringid) {\n    std::stringstream ss(stringid);\n    step_id_type id;\n    ss >> id;\n    return id;\n}\n}\n\nstd::vector<StepMatch> CukeEngineImpl::stepMatches(const std::string& name) const {\n    std::vector<StepMatch> engineResult;\n    MatchResult commandResult = cukeCommands.stepMatches(name);\n    for (const SingleStepMatch& commandMatch : commandResult.getResultSet()) {\n        StepMatch engineMatch;\n        engineMatch.id = convertId(commandMatch.stepInfo->id);\n        engineMatch.source = commandMatch.stepInfo->source;\n        engineMatch.regexp = commandMatch.stepInfo->regex.str();\n        for (const RegexSubmatch& commandMatchArg : commandMatch.submatches) {\n            StepMatchArg engineMatchArg;\n            engineMatchArg.value = commandMatchArg.value;\n            engineMatchArg.position = commandMatchArg.position;\n            engineMatch.args.push_back(engineMatchArg);\n        }\n        engineResult.push_back(engineMatch);\n    }\n    return engineResult;\n}\n\nvoid CukeEngineImpl::beginScenario(const tags_type& tags) {\n    cukeCommands.beginScenario(tags);\n}\n\nvoid CukeEngineImpl::invokeStep(\n    const std::string& id, const invoke_args_type& args, const invoke_table_type& tableArg\n) {\n    InvokeArgs commandArgs;\n    try {\n        for (const std::string& a : args) {\n            commandArgs.addArg(a);\n        }\n\n        if (!tableArg.empty() && !tableArg.front().empty()) {\n            Table& commandTableArg = commandArgs.getVariableTableArg();\n            for (const auto& arg : tableArg[0]) {\n                commandTableArg.addColumn(arg);\n            }\n\n            for (std::size_t i = 1; i < tableArg.size(); ++i) {\n                Table::row_type row;\n                for (const auto& arg : tableArg[i]) {\n                    row.push_back(arg);\n                }\n                commandTableArg.addRow(row);\n            }\n        }\n    } catch (...) {\n        throw InvokeException(\"Unable to decode arguments\");\n    }\n\n    InvokeResult commandResult;\n    try {\n        commandResult = cukeCommands.invoke(convertId(id), &commandArgs);\n    } catch (...) {\n        throw InvokeException(\"Uncatched exception\");\n    }\n    switch (commandResult.getType()) {\n    case SUCCESS:\n        return;\n    case FAILURE:\n        throw InvokeFailureException(commandResult.getDescription(), \"\");\n    case PENDING:\n        throw PendingStepException(commandResult.getDescription());\n    }\n}\n\nvoid CukeEngineImpl::endScenario(const tags_type& /*tags*/) {\n    cukeCommands.endScenario();\n}\n\nstd::string CukeEngineImpl::snippetText(\n    const std::string& keyword, const std::string& name, const std::string& /*multilineArgClass*/\n) const {\n    return cukeCommands.snippetText(keyword, name);\n}\n\n}\n}\n"
  },
  {
    "path": "src/HookRegistrar.cpp",
    "content": "#include <cucumber-cpp/internal/hook/HookRegistrar.hpp>\n#include <cucumber-cpp/internal/CukeCommands.hpp>\n\nnamespace cucumber {\nnamespace internal {\n\nvoid Hook::invokeHook(Scenario* scenario, CallableStep*) {\n    if (tagsMatch(scenario)) {\n        body();\n    } else {\n        skipHook();\n    }\n}\n\nvoid Hook::skipHook() {\n}\n\nvoid Hook::setTags(const std::string& csvTagNotation) {\n    tagExpression = AndTagExpression(csvTagNotation);\n}\n\nbool Hook::tagsMatch(Scenario* scenario) {\n    return !scenario || tagExpression.matches(scenario->getTags());\n}\n\nvoid AroundStepHook::invokeHook(Scenario* scenario, CallableStep* step) {\n    this->step = step;\n    Hook::invokeHook(scenario, NULL);\n}\n\nvoid AroundStepHook::skipHook() {\n    step->call();\n}\n\nvoid UnconditionalHook::invokeHook(Scenario*, CallableStep*) {\n    body();\n}\n\nvoid HookRegistrar::addBeforeHook(std::shared_ptr<BeforeHook> beforeHook) {\n    beforeHooks().push_back(beforeHook);\n}\n\nHookRegistrar::hook_list_type& HookRegistrar::beforeHooks() {\n    static hook_list_type beforeHooks;\n    return beforeHooks;\n}\n\nvoid HookRegistrar::execBeforeHooks(Scenario* scenario) {\n    execHooks(beforeHooks(), scenario);\n}\n\nvoid HookRegistrar::addAroundStepHook(std::shared_ptr<AroundStepHook> aroundStepHook) {\n    aroundStepHooks().push_front(aroundStepHook);\n}\n\nHookRegistrar::aroundhook_list_type& HookRegistrar::aroundStepHooks() {\n    static aroundhook_list_type aroundStepHooks;\n    return aroundStepHooks;\n}\n\nInvokeResult HookRegistrar::execStepChain(\n    Scenario* scenario, const StepInfo* const stepInfo, const InvokeArgs* pArgs\n) {\n    StepCallChain scc(scenario, stepInfo, pArgs, aroundStepHooks());\n    return scc.exec();\n}\n\nvoid HookRegistrar::addAfterStepHook(std::shared_ptr<AfterStepHook> afterStepHook) {\n    afterStepHooks().push_front(afterStepHook);\n}\n\nHookRegistrar::hook_list_type& HookRegistrar::afterStepHooks() {\n    static hook_list_type afterStepHooks;\n    return afterStepHooks;\n}\n\nvoid HookRegistrar::execAfterStepHooks(Scenario* scenario) {\n    execHooks(afterStepHooks(), scenario);\n}\n\nvoid HookRegistrar::addAfterHook(std::shared_ptr<AfterHook> afterHook) {\n    afterHooks().push_front(afterHook);\n}\n\nHookRegistrar::hook_list_type& HookRegistrar::afterHooks() {\n    static hook_list_type afterHooks;\n    return afterHooks;\n}\n\nvoid HookRegistrar::execAfterHooks(Scenario* scenario) {\n    execHooks(afterHooks(), scenario);\n}\n\nvoid HookRegistrar::execHooks(HookRegistrar::hook_list_type& hookList, Scenario* scenario) {\n    for (HookRegistrar::hook_list_type::iterator hook = hookList.begin(); hook != hookList.end();\n         ++hook) {\n        (*hook)->invokeHook(scenario, NULL);\n    }\n}\n\nHookRegistrar::hook_list_type& HookRegistrar::beforeAllHooks() {\n    static hook_list_type beforeAllHooks;\n    return beforeAllHooks;\n}\n\nvoid HookRegistrar::addBeforeAllHook(std::shared_ptr<BeforeAllHook> beforeAllHook) {\n    beforeAllHooks().push_back(beforeAllHook);\n}\n\nvoid HookRegistrar::execBeforeAllHooks() {\n    execHooks(beforeAllHooks(), NULL);\n}\n\nHookRegistrar::hook_list_type& HookRegistrar::afterAllHooks() {\n    static hook_list_type afterAllHooks;\n    return afterAllHooks;\n}\n\nvoid HookRegistrar::addAfterAllHook(std::shared_ptr<AfterAllHook> afterAllHook) {\n    afterAllHooks().push_back(afterAllHook);\n}\n\nvoid HookRegistrar::execAfterAllHooks() {\n    execHooks(afterAllHooks(), NULL);\n}\n\nStepCallChain::StepCallChain(\n    Scenario* scenario,\n    const StepInfo* const stepInfo,\n    const InvokeArgs* pStepArgs,\n    HookRegistrar::aroundhook_list_type& aroundHooks\n) :\n    scenario(scenario),\n    stepInfo(stepInfo),\n    pStepArgs(pStepArgs) {\n    nextHook = aroundHooks.begin();\n    hookEnd = aroundHooks.end();\n}\n\nInvokeResult StepCallChain::exec() {\n    execNext();\n    return result;\n}\n\nvoid StepCallChain::execNext() {\n    if (nextHook == hookEnd) {\n        execStep();\n    } else {\n        HookRegistrar::aroundhook_list_type::iterator currentHook = nextHook++;\n        CallableStepChain callableStepChain(this);\n        (*currentHook)->invokeHook(scenario, &callableStepChain);\n    }\n}\n\nvoid StepCallChain::execStep() {\n    if (stepInfo) {\n        result = stepInfo->invokeStep(pStepArgs);\n    }\n}\n\nCallableStepChain::CallableStepChain(StepCallChain* scc) :\n    scc(scc) {\n}\n\nvoid CallableStepChain::call() {\n    scc->execNext();\n}\n\n}\n}\n"
  },
  {
    "path": "src/Regex.cpp",
    "content": "#include <cucumber-cpp/internal/utils/Regex.hpp>\n\n#include <algorithm>\n\nnamespace cucumber {\nnamespace internal {\n\nRegex::Regex(std::string regularExpression) :\n    regexImpl(regularExpression),\n    regexString(regularExpression) {\n}\n\nbool RegexMatch::matches() {\n    return regexMatched;\n}\n\nconst RegexMatch::submatches_type& RegexMatch::getSubmatches() {\n    return submatches;\n}\n\nstd::string Regex::str() const {\n    return regexString;\n}\n\nstd::shared_ptr<RegexMatch> Regex::find(const std::string& expression) const {\n    return std::make_shared<FindRegexMatch>(regexImpl, expression);\n}\n\nnamespace {\nbool isUtf8CodeUnitStartOfCodepoint(unsigned int i) {\n    return (i & 0xc0) != 0x80;\n}\n\nstd::ptrdiff_t utf8CodepointOffset(\n    const std::string& expression, const std::string::const_iterator& it\n) {\n    return count_if(expression.begin(), it, &isUtf8CodeUnitStartOfCodepoint);\n}\n} // namespace\n\nFindRegexMatch::FindRegexMatch(const std::regex& regexImpl, const std::string& expression) {\n    std::smatch matchResults;\n    regexMatched = std::regex_search(expression, matchResults, regexImpl);\n    if (regexMatched) {\n        std::smatch::const_iterator i = matchResults.begin();\n        if (i != matchResults.end())\n            // Skip capture group 0 which is the whole match, not a user marked sub-expression\n            ++i;\n        for (; i != matchResults.end(); ++i) {\n            if (i->matched) {\n                RegexSubmatch s = {*i, utf8CodepointOffset(expression, i->first)};\n                submatches.push_back(s);\n            } else {\n                submatches.push_back(RegexSubmatch());\n            }\n        }\n    }\n}\n\nstd::shared_ptr<RegexMatch> Regex::findAll(const std::string& expression) const {\n    return std::make_shared<FindAllRegexMatch>(regexImpl, expression);\n}\n\nFindAllRegexMatch::FindAllRegexMatch(const std::regex& regexImpl, const std::string& expression) {\n    std::sregex_token_iterator i(\n        expression.begin(), expression.end(), regexImpl, 1, std::regex_constants::match_continuous\n    );\n    const std::sregex_token_iterator end;\n    for (; i != end; ++i) {\n        RegexSubmatch s = {*i, -1};\n        submatches.push_back(s);\n    }\n    regexMatched = !submatches.empty();\n}\n\n}\n}\n"
  },
  {
    "path": "src/Scenario.cpp",
    "content": "#include <cucumber-cpp/internal/Scenario.hpp>\n\nnamespace cucumber {\nnamespace internal {\n\nScenario::Scenario(const TagExpression::tag_list& tags) :\n    tags(tags) {\n}\n\nconst TagExpression::tag_list& Scenario::getTags() {\n    return tags;\n}\n\n}\n}\n"
  },
  {
    "path": "src/StepManager.cpp",
    "content": "#include \"cucumber-cpp/internal/step/StepManager.hpp\"\n\nnamespace cucumber {\nnamespace internal {\n\nStepInfo::StepInfo(const std::string& stepMatcher, const std::string source) :\n    regex(stepMatcher),\n    source(source) {\n    static step_id_type currentId = 0;\n    id = ++currentId;\n}\n\nSingleStepMatch StepInfo::matches(const std::string& stepDescription) const {\n    SingleStepMatch stepMatch;\n    std::shared_ptr<RegexMatch> regexMatch(regex.find(stepDescription));\n    if (regexMatch->matches()) {\n        stepMatch.stepInfo = shared_from_this();\n        stepMatch.submatches = regexMatch->getSubmatches();\n    }\n    return stepMatch;\n}\n\nSingleStepMatch::operator const void*() const {\n    return stepInfo.get();\n}\n\nMatchResult::operator bool() const {\n    return !resultSet.empty();\n}\n\nconst MatchResult::match_results_type& MatchResult::getResultSet() {\n    return resultSet;\n}\n\nvoid MatchResult::addMatch(SingleStepMatch match) {\n    resultSet.push_back(match);\n}\n\nvoid InvokeArgs::addArg(const std::string arg) {\n    args.push_back(arg);\n}\n\nconst Table& InvokeArgs::getTableArg() const {\n    return tableArg;\n}\n\nTable& InvokeArgs::getVariableTableArg() {\n    return tableArg;\n}\n\nInvokeResult::InvokeResult(const InvokeResultType type, const char* description) :\n    type(type) {\n    if (description) {\n        this->description = description;\n    };\n}\n\nInvokeResult::InvokeResult() :\n    type(FAILURE) {\n}\n\nInvokeResult::InvokeResult(const InvokeResult& ir) :\n    type(ir.type),\n    description(ir.description) {\n}\n\nInvokeResult& InvokeResult::operator=(const InvokeResult& rhs) {\n    this->type = rhs.type;\n    this->description = rhs.description;\n    return *this;\n}\n\nInvokeResult InvokeResult::success() {\n    return InvokeResult(SUCCESS, 0);\n}\n\nInvokeResult InvokeResult::failure(const char* description) {\n    return InvokeResult(FAILURE, description);\n}\n\nInvokeResult InvokeResult::failure(const std::string& description) {\n    return InvokeResult(FAILURE, description.c_str());\n}\n\nInvokeResult InvokeResult::pending(const char* description) {\n    return InvokeResult(PENDING, description);\n}\n\nbool InvokeResult::isSuccess() const {\n    return (type == SUCCESS);\n}\n\nbool InvokeResult::isPending() const {\n    return (type == PENDING);\n}\n\nInvokeResultType InvokeResult::getType() const {\n    return type;\n}\n\nconst std::string& InvokeResult::getDescription() const {\n    return description;\n}\n\nstep_id_type StepManager::addStep(std::shared_ptr<StepInfo> stepInfo) {\n    return steps().insert(std::make_pair(stepInfo->id, stepInfo)).first->first;\n}\n\nMatchResult StepManager::stepMatches(const std::string& stepDescription) {\n    MatchResult matchResult;\n    for (steps_type::iterator iter = steps().begin(); iter != steps().end(); ++iter) {\n        const std::shared_ptr<const StepInfo>& stepInfo = iter->second;\n        SingleStepMatch currentMatch = stepInfo->matches(stepDescription);\n        if (currentMatch) {\n            matchResult.addMatch(currentMatch);\n        }\n    }\n    return matchResult;\n}\n\nconst StepInfo* StepManager::getStep(step_id_type id) {\n    const steps_type::const_iterator step = steps().find(id);\n    if (step == steps().end()) {\n        return NULL;\n    }\n    return step->second.get();\n}\n\n/**\n * Needed to fix the \"static initialization order fiasco\"\n * http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.12\n */\nStepManager::steps_type& StepManager::steps() {\n    static steps_type steps;\n    return steps;\n}\n\nInvokeResult BasicStep::invoke(const InvokeArgs* pArgs) {\n    this->pArgs = pArgs;\n    currentArgIndex = 0;\n    currentResult = InvokeResult::success();\n    try {\n        InvokeResult returnedResult = invokeStepBody();\n        if (currentResult.isPending()) {\n            return currentResult;\n        } else {\n            return returnedResult;\n        }\n    } catch (const std::exception& ex) {\n        return InvokeResult::failure(ex.what());\n    } catch (const std::string& ex) {\n        return InvokeResult::failure(ex);\n    } catch (const char* ex) {\n        return InvokeResult::failure(ex);\n    } catch (...) {\n        // Cucumber needs a description here\n        return InvokeResult::failure(\"Unknown exception\");\n    }\n}\n\nvoid BasicStep::pending() {\n    pending(0);\n}\n\nvoid BasicStep::pending(const char* description) {\n    currentResult = InvokeResult::pending(description);\n}\n\nconst InvokeArgs* BasicStep::getArgs() {\n    return pArgs;\n}\n\n}\n}\n"
  },
  {
    "path": "src/Table.cpp",
    "content": "#include <cucumber-cpp/internal/Table.hpp>\n\nnamespace cucumber {\nnamespace internal {\n\nvoid Table::addColumn(const std::string column) {\n    if (rows.empty()) {\n        columns.push_back(column);\n    } else {\n        throw std::runtime_error(\"Cannot alter columns after rows have been added\");\n    }\n}\n\nvoid Table::addRow(const row_type& row) {\n    const basic_type::size_type colSize = columns.size();\n    if (colSize == 0) {\n        throw std::runtime_error(\"No column defined yet\");\n    } else if (colSize != row.size()) {\n        throw std::range_error(\"Row size does not match the table column size\");\n    } else {\n        rows.push_back(buildHashRow(row));\n    }\n}\n\nTable::hash_row_type Table::buildHashRow(const row_type& row) {\n    hash_row_type hashRow;\n    for (columns_type::size_type i = 0; i < columns.size(); ++i) {\n        hashRow[columns[i]] = row[i];\n    }\n    return hashRow;\n}\n\nconst Table::hashes_type& Table::hashes() const {\n    return rows;\n}\n\n}\n}\n"
  },
  {
    "path": "src/Tag.cpp",
    "content": "#include <cucumber-cpp/internal/hook/Tag.hpp>\n#include <memory>\n\nnamespace cucumber {\nnamespace internal {\n\nRegex& AndTagExpression::csvTagNotationRegex() {\n    static Regex r(\"\\\\s*\\\"([^\\\"]+)\\\"\\\\s*(?:,|$)\");\n    return r;\n}\n\nAndTagExpression::AndTagExpression(const std::string& csvTagNotation) {\n    const std::shared_ptr<RegexMatch> match(csvTagNotationRegex().findAll(csvTagNotation));\n    const RegexMatch::submatches_type submatches = match->getSubmatches();\n    orExpressions.reserve(submatches.size());\n    for (RegexMatch::submatches_type::const_iterator i = submatches.begin(); i != submatches.end();\n         ++i) {\n        const std::string orCsvTagNotation = i->value;\n        orExpressions.push_back(OrTagExpression(orCsvTagNotation));\n    }\n}\n\nbool AndTagExpression::matches(const tag_list& tags) const {\n    bool match = true;\n    for (or_expressions_type::const_iterator i = orExpressions.begin();\n         i != orExpressions.end() && match;\n         ++i) {\n        match &= i->matches(tags);\n    }\n    return match;\n}\n\nRegex& OrTagExpression::csvTagNotationRegex() {\n    static Regex r(\"\\\\s*@(\\\\w+)\\\\s*(?:,|$)\");\n    return r;\n}\n\nOrTagExpression::OrTagExpression(const std::string& csvTagNotation) {\n    const std::shared_ptr<RegexMatch> match(csvTagNotationRegex().findAll(csvTagNotation));\n    const RegexMatch::submatches_type submatches = match->getSubmatches();\n    orTags.reserve(submatches.size());\n    for (RegexMatch::submatches_type::const_iterator i = submatches.begin(); i != submatches.end();\n         ++i) {\n        orTags.push_back(i->value);\n    }\n}\n\nbool OrTagExpression::matches(const tag_list& tags) const {\n    for (tag_list::const_iterator i = orTags.begin(); i != orTags.end(); ++i) {\n        if (orTagMatchesTagList(*i, tags))\n            return true;\n    }\n    return false;\n}\n\nbool OrTagExpression::orTagMatchesTagList(const std::string& currentOrTag, const tag_list& tags)\n    const {\n    for (tag_list::const_iterator i = tags.begin(); i != tags.end(); ++i) {\n        if (*i == currentOrTag)\n            return true;\n    }\n    return false;\n}\n\n}\n}\n"
  },
  {
    "path": "src/connectors/wire/WireProtocol.cpp",
    "content": "#include <cucumber-cpp/internal/connectors/wire/WireProtocol.hpp>\n#include <cucumber-cpp/internal/connectors/wire/WireProtocolCommands.hpp>\n\n#include <nlohmann/json.hpp>\n\n#include <iostream>\n#include <string>\n#include <sstream>\n\nusing json = nlohmann::json;\n\nnamespace cucumber {\nnamespace internal {\n\n/*\n * Responses\n */\n\nvoid SuccessResponse::accept(WireResponseVisitor& visitor) const {\n    visitor.visit(*this);\n}\n\nFailureResponse::FailureResponse(const std::string& message, const std::string& exceptionType) :\n    message(message),\n    exceptionType(exceptionType) {\n}\n\nconst std::string FailureResponse::getMessage() const {\n    return message;\n}\n\nconst std::string FailureResponse::getExceptionType() const {\n    return exceptionType;\n}\n\nvoid FailureResponse::accept(WireResponseVisitor& visitor) const {\n    visitor.visit(*this);\n}\n\nPendingResponse::PendingResponse(const std::string& message) :\n    message(message) {\n}\n\nconst std::string PendingResponse::getMessage() const {\n    return message;\n}\n\nvoid PendingResponse::accept(WireResponseVisitor& visitor) const {\n    visitor.visit(*this);\n}\n\nStepMatchesResponse::StepMatchesResponse(const std::vector<StepMatch>& matchingSteps) :\n    matchingSteps(matchingSteps) {\n}\n\nconst std::vector<StepMatch>& StepMatchesResponse::getMatchingSteps() const {\n    return matchingSteps;\n}\n\nvoid StepMatchesResponse::accept(WireResponseVisitor& visitor) const {\n    visitor.visit(*this);\n}\n\nSnippetTextResponse::SnippetTextResponse(const std::string& stepSnippet) :\n    stepSnippet(stepSnippet) {\n}\n\nconst std::string SnippetTextResponse::getStepSnippet() const {\n    return stepSnippet;\n}\n\nvoid SnippetTextResponse::accept(WireResponseVisitor& visitor) const {\n    visitor.visit(*this);\n}\n\n/*\n * Command decoders\n */\n\nnamespace {\ntypedef std::shared_ptr<WireCommand> (*CommandDecoder)(const json& jsonArgs);\n\nCukeEngine::tags_type getScenarioTags(const json& jsonArgs) {\n    CukeEngine::tags_type tags;\n    if (!jsonArgs.is_null()) {\n        const auto& jsonTags = jsonArgs.at(\"tags\");\n        for (const auto& tag : jsonTags) {\n            tags.push_back(tag.get<std::string>());\n        }\n    }\n    return tags;\n}\n\nstd::shared_ptr<WireCommand> BeginScenarioDecoder(const json& jsonArgs) {\n    return std::make_shared<BeginScenarioCommand>(getScenarioTags(jsonArgs));\n}\n\nstd::shared_ptr<WireCommand> EndScenarioDecoder(const json& jsonArgs) {\n    return std::make_shared<EndScenarioCommand>(getScenarioTags(jsonArgs));\n}\n\nstd::shared_ptr<WireCommand> StepMatchesDecoder(const json& jsonArgs) {\n    const std::string& nameToMatch = jsonArgs.at(\"name_to_match\");\n    return std::make_shared<StepMatchesCommand>(nameToMatch);\n}\n\nvoid fillTableArg(const json& jsonTableArg, CukeEngine::invoke_table_type& tableArg) {\n    const std::size_t rows = jsonTableArg.size();\n    if (rows > 0) {\n        const std::size_t columns = jsonTableArg[0].get<std::vector<std::string>>().size();\n        tableArg.resize(rows);\n        for (std::size_t i = 0; i < rows; ++i) {\n            const auto& jsonRow(jsonTableArg[i].get<std::vector<std::string>>());\n            if (jsonRow.size() == columns) {\n                for (std::size_t j = 0; j < columns; ++j) {\n                    tableArg[i].push_back(jsonRow[j]);\n                }\n            } else {\n                // TODO: Invalid row\n            }\n        }\n    } else {\n        // TODO: Invalid table (no column specified)\n    }\n}\n\nvoid fillInvokeArgs(\n    const json& invokeParams,\n    CukeEngine::invoke_args_type& args,\n    CukeEngine::invoke_table_type& tableArg\n) {\n    const auto& jsonArgs = invokeParams.at(\"args\");\n    for (const auto& arg : jsonArgs) {\n        if (arg.is_string()) {\n            args.push_back(arg.get<std::string>());\n        } else if (arg.is_array()) {\n            fillTableArg(arg, tableArg);\n        }\n    }\n}\n\nstd::shared_ptr<WireCommand> InvokeDecoder(const json& jsonArgs) {\n    const auto& invokeParams = jsonArgs.get<json::object_t>();\n\n    CukeEngine::invoke_args_type args;\n    CukeEngine::invoke_table_type tableArg;\n    const std::string& id = invokeParams.at(\"id\");\n    fillInvokeArgs(invokeParams, args, tableArg);\n    return std::make_shared<InvokeCommand>(id, args, tableArg);\n}\n\nstd::shared_ptr<WireCommand> SnippetTextDecoder(const json& jsonArgs) {\n    const auto& snippetTextArgs = jsonArgs.get<json::object_t>();\n    const std::string& stepKeyword = snippetTextArgs.at(\"step_keyword\");\n    const std::string& stepName = snippetTextArgs.at(\"step_name\");\n    const std::string& multilineArgClass = snippetTextArgs.at(\"multiline_arg_class\");\n    return std::make_shared<SnippetTextCommand>(stepKeyword, stepName, multilineArgClass);\n}\n}\n\nstatic const std::map<std::string, CommandDecoder> commandDecodersMap = {\n    {\"begin_scenario\", BeginScenarioDecoder},\n    {\"end_scenario\", EndScenarioDecoder},\n    {\"step_matches\", StepMatchesDecoder},\n    {\"invoke\", InvokeDecoder},\n    {\"snippet_text\", SnippetTextDecoder},\n};\n\nstd::shared_ptr<WireCommand> JsonWireMessageCodec::decode(const std::string& request) const {\n    try {\n        json jsonRequest = json::parse(request);\n        const auto& jsonCommand = jsonRequest.at(0);\n\n        const auto& commandDecoder = commandDecodersMap.find(jsonCommand.get<std::string>());\n        if (commandDecoder != commandDecodersMap.end() && commandDecoder->second) {\n            json jsonArgs;\n            if (jsonRequest.size() > 1) {\n                jsonArgs = jsonRequest.at(1);\n            }\n            return commandDecoder->second(jsonArgs);\n        }\n    } catch (...) {\n        // LOG Error decoding wire protocol command\n    }\n    return std::make_shared<FailingCommand>();\n}\n\nnamespace {\n\nclass WireResponseEncoder : public WireResponseVisitor {\nprivate:\n    json jsonOutput = json::array();\n\n    void success(const json* detail = nullptr) {\n        output(\"success\", detail);\n    }\n\n    void fail(const json* detail = nullptr) {\n        output(\"fail\", detail);\n    }\n\n    void output(const std::string& responseType, const json* detail = nullptr) {\n        jsonOutput.push_back(responseType);\n        if (detail == nullptr || detail->is_null()) {\n            return;\n        }\n        jsonOutput.push_back(*detail);\n    }\n\npublic:\n    std::string encode(const WireResponse& response) {\n        jsonOutput.clear();\n        response.accept(*this);\n        return jsonOutput.dump();\n    }\n\n    void visit(const SuccessResponse& /*response*/) override {\n        success();\n    }\n\n    void visit(const FailureResponse& response) override {\n        json detailObject;\n        if (!response.getMessage().empty()) {\n            detailObject[\"message\"] = response.getMessage();\n        }\n        if (!response.getExceptionType().empty()) {\n            detailObject[\"exception\"] = response.getExceptionType();\n        }\n        if (detailObject.empty()) {\n            fail();\n        } else {\n            const json detail(detailObject);\n            fail(&detail);\n        }\n    }\n\n    void visit(const PendingResponse& response) override {\n        json jsonReponse(response.getMessage());\n        output(\"pending\", &jsonReponse);\n    }\n\n    void visit(const StepMatchesResponse& response) override {\n        json jsonMatches = json::array();\n        for (const StepMatch& m : response.getMatchingSteps()) {\n            json jsonM;\n            jsonM[\"id\"] = m.id;\n            json jsonArgs = json::array();\n            for (const StepMatchArg& ma : m.args) {\n                json jsonMa;\n                jsonMa[\"val\"] = ma.value;\n                jsonMa[\"pos\"] = static_cast<int64_t>(ma.position);\n                jsonArgs.push_back(jsonMa);\n            }\n            jsonM[\"args\"] = jsonArgs;\n            if (!m.source.empty()) {\n                jsonM[\"source\"] = m.source;\n            }\n            if (!m.regexp.empty()) {\n                jsonM[\"regexp\"] = m.regexp;\n            }\n            jsonMatches.push_back(jsonM);\n        }\n        json jsonReponse(jsonMatches);\n        output(\"success\", &jsonReponse);\n    }\n\n    void visit(const SnippetTextResponse& response) override {\n        json jsonReponse(response.getStepSnippet());\n        success(&jsonReponse);\n    }\n};\n\n}\n\nconst std::string JsonWireMessageCodec::encode(const WireResponse& response) const {\n    try {\n        WireResponseEncoder encoder;\n        return encoder.encode(response);\n    } catch (...) {\n        throw WireMessageCodecException(\"Error decoding wire protocol response\");\n    }\n}\n\nWireProtocolHandler::WireProtocolHandler(const WireMessageCodec& codec, CukeEngine& engine) :\n    codec(codec),\n    engine(engine) {\n}\n\nstd::string WireProtocolHandler::handle(const std::string& request) const {\n    std::string response;\n    // LOG request\n    try {\n        std::shared_ptr<const WireCommand> command = codec.decode(request);\n        std::shared_ptr<const WireResponse> wireResponse = command->run(engine);\n        response = codec.encode(*wireResponse);\n    } catch (...) {\n        response = \"[\\\"fail\\\"]\";\n    }\n    // LOG response\n    return response;\n}\n\n} // namespace internal\n} // namespace cucumber\n"
  },
  {
    "path": "src/connectors/wire/WireProtocolCommands.cpp",
    "content": "#include <cucumber-cpp/internal/connectors/wire/WireProtocolCommands.hpp>\n\nnamespace cucumber {\nnamespace internal {\n\nScenarioCommand::ScenarioCommand(const CukeEngine::tags_type& tags) :\n    tags(tags) {\n}\n\nBeginScenarioCommand::BeginScenarioCommand(const CukeEngine::tags_type& tags) :\n    ScenarioCommand(tags) {\n}\n\nstd::shared_ptr<WireResponse> BeginScenarioCommand::run(CukeEngine& engine) const {\n    engine.beginScenario(tags);\n    return std::make_shared<SuccessResponse>();\n}\n\nEndScenarioCommand::EndScenarioCommand(const CukeEngine::tags_type& tags) :\n    ScenarioCommand(tags) {\n}\n\nstd::shared_ptr<WireResponse> EndScenarioCommand::run(CukeEngine& engine) const {\n    engine.endScenario(tags);\n    return std::make_shared<SuccessResponse>();\n}\n\nStepMatchesCommand::StepMatchesCommand(const std::string& stepName) :\n    stepName(stepName) {\n}\n\nstd::shared_ptr<WireResponse> StepMatchesCommand::run(CukeEngine& engine) const {\n    std::vector<StepMatch> matchingSteps = engine.stepMatches(stepName);\n    return std::make_shared<StepMatchesResponse>(matchingSteps);\n}\n\nInvokeCommand::InvokeCommand(\n    const std::string& stepId,\n    const CukeEngine::invoke_args_type& args,\n    const CukeEngine::invoke_table_type& tableArg\n) :\n    stepId(stepId),\n    args(args),\n    tableArg(tableArg) {\n}\n\nstd::shared_ptr<WireResponse> InvokeCommand::run(CukeEngine& engine) const {\n    try {\n        engine.invokeStep(stepId, args, tableArg);\n        return std::make_shared<SuccessResponse>();\n    } catch (const InvokeFailureException& e) {\n        return std::make_shared<FailureResponse>(e.getMessage(), e.getExceptionType());\n    } catch (const PendingStepException& e) {\n        return std::make_shared<PendingResponse>(e.getMessage());\n    } catch (...) {\n        return std::make_shared<FailureResponse>();\n    }\n}\n\nSnippetTextCommand::SnippetTextCommand(\n    const std::string& keyword, const std::string& name, const std::string& multilineArgClass\n) :\n    keyword(keyword),\n    name(name),\n    multilineArgClass(multilineArgClass) {\n}\n\nstd::shared_ptr<WireResponse> SnippetTextCommand::run(CukeEngine& engine) const {\n    return std::make_shared<SnippetTextResponse>(\n        engine.snippetText(keyword, name, multilineArgClass)\n    );\n}\n\nstd::shared_ptr<WireResponse> FailingCommand::run(CukeEngine& /*engine*/) const {\n    return std::make_shared<FailureResponse>();\n}\n\n}\n}\n"
  },
  {
    "path": "src/connectors/wire/WireServer.cpp",
    "content": "#include <cucumber-cpp/internal/connectors/wire/WireServer.hpp>\n#include <filesystem>\n\nnamespace cucumber {\nnamespace internal {\n\nSocketServer::SocketServer(const ProtocolHandler* protocolHandler) :\n    protocolHandler(protocolHandler),\n    ios() {\n}\n\ntemplate<typename Protocol>\nvoid SocketServer::doListen(\n    asio::basic_socket_acceptor<Protocol>& acceptor, const typename Protocol::endpoint& endpoint\n) {\n    if (acceptor.is_open())\n        throw std::system_error(asio::error::already_open);\n    acceptor.open(endpoint.protocol());\n    acceptor.set_option(typename Protocol::acceptor::reuse_address(true));\n    acceptor.bind(endpoint);\n    acceptor.listen(1);\n}\n\ntemplate<typename Protocol>\nvoid SocketServer::doAcceptOnce(asio::basic_socket_acceptor<Protocol>& acceptor) {\n    typename Protocol::socket socket(ios);\n    acceptor.accept(socket);\n    typename Protocol::iostream stream(std::move(socket));\n    processStream(stream);\n}\n\nvoid SocketServer::processStream(std::iostream& stream) {\n    std::string request;\n    while (getline(stream, request)) {\n        stream << protocolHandler->handle(request) << std::endl << std::flush;\n    }\n}\n\nTCPSocketServer::TCPSocketServer(const ProtocolHandler* protocolHandler) :\n    SocketServer(protocolHandler),\n    acceptor(ios) {\n}\n\nvoid TCPSocketServer::listen(const port_type port) {\n    listen(asio::ip::tcp::endpoint(asio::ip::tcp::v4(), port));\n}\n\nvoid TCPSocketServer::listen(const asio::ip::tcp::endpoint endpoint) {\n    doListen(acceptor, endpoint);\n    acceptor.set_option(asio::ip::tcp::no_delay(true));\n}\n\nasio::ip::tcp::endpoint TCPSocketServer::listenEndpoint() const {\n    return acceptor.local_endpoint();\n}\n\nvoid TCPSocketServer::acceptOnce() {\n    doAcceptOnce(acceptor);\n}\n\n#if defined(ASIO_HAS_LOCAL_SOCKETS)\nUnixSocketServer::UnixSocketServer(const ProtocolHandler* protocolHandler) :\n    SocketServer(protocolHandler),\n    acceptor(ios) {\n}\n\nvoid UnixSocketServer::listen(const std::string& unixPath) {\n    if (std::filesystem::status(unixPath).type() == std::filesystem::file_type::socket)\n        std::filesystem::remove(unixPath);\n\n    doListen(acceptor, asio::local::stream_protocol::endpoint(unixPath));\n}\n\nasio::local::stream_protocol::endpoint UnixSocketServer::listenEndpoint() const {\n    return acceptor.local_endpoint();\n}\n\nvoid UnixSocketServer::acceptOnce() {\n    doAcceptOnce(acceptor);\n}\n\nUnixSocketServer::~UnixSocketServer() {\n    if (!acceptor.is_open())\n        return;\n    std::string path = acceptor.local_endpoint().path();\n    // NOTE: this will fail if this path got deleted manually or represents an abstract-namespace\n    // socket\n    std::filesystem::remove(path);\n}\n#endif\n\n}\n}\n"
  },
  {
    "path": "src/drivers/BoostDriver.cpp",
    "content": "#include <cucumber-cpp/internal/drivers/BoostDriver.hpp>\n\n#include <sstream>\n\n#include <boost/function.hpp>\n#include <boost/test/unit_test.hpp>\n#include <boost/test/unit_test_log_formatter.hpp>\n#include <mutex>\n#include <boost/version.hpp>\n\nusing namespace ::boost::unit_test;\nusing ::boost::execution_exception;\n\nnamespace cucumber {\nnamespace internal {\n\nnamespace {\n\ntest_case* testCase = 0;\nboost::function<void()> currentTestBody;\n\nvoid exec_test_body() {\n    if (currentTestBody) {\n        currentTestBody();\n    }\n}\n\nbool boost_test_init() {\n    testCase = BOOST_TEST_CASE(&exec_test_body);\n    framework::master_test_suite().add(testCase);\n\n    return true;\n}\n\n// Freed by Boost's unit test framework on exit\nstatic CukeBoostLogInterceptor* logInterceptor = 0;\n\n}\n\nclass CukeBoostLogInterceptor : public ::boost::unit_test::unit_test_log_formatter {\npublic:\n    const InvokeResult getResult() const;\n    void reset();\n\n    // Formatter\n    void log_start(std::ostream&, counter_t /*test_cases_amount*/) override{};\n    void log_finish(std::ostream&) override{};\n    void log_build_info(std::ostream&, bool /*log_build_info*/) override{};\n\n    void test_unit_start(std::ostream&, test_unit const& /*tu*/) override{};\n    void test_unit_finish(std::ostream&, test_unit const& /*tu*/, unsigned long /*elapsed*/)\n        override{};\n    void test_unit_skipped(std::ostream&, test_unit const& /*tu*/) override{};\n\n    void log_exception_start(std::ostream&, log_checkpoint_data const&, execution_exception const&)\n        override{};\n    void log_exception_finish(std::ostream&) override{};\n\n    void log_entry_start(std::ostream&, log_entry_data const&, log_entry_types /*let*/) override{};\n    void log_entry_value(std::ostream&, const_string value) override;\n    void log_entry_value(std::ostream&, lazy_ostream const& value) override;\n    void log_entry_finish(std::ostream&) override{};\n\n    void entry_context_start(std::ostream&, log_level /*l*/) override {\n    }\n    void log_entry_context(std::ostream&, log_level /*l*/, const_string /*value*/) override {\n    }\n    void entry_context_finish(std::ostream&, log_level /*l*/) override {\n    }\n\nprivate:\n    std::stringstream description;\n};\n\nvoid CukeBoostLogInterceptor::reset() {\n    description.str(\"\");\n}\n\n/*\n * Threshold level set to log_all_errors, so we should be fine logging everything\n */\nvoid CukeBoostLogInterceptor::log_entry_value(std::ostream&, const_string value) {\n    description << value;\n}\n\nvoid CukeBoostLogInterceptor::log_entry_value(std::ostream&, lazy_ostream const& value) {\n    description << value;\n}\n\nconst InvokeResult CukeBoostLogInterceptor::getResult() const {\n    std::string d = description.str();\n    if (d.empty()) {\n        return InvokeResult::success();\n    } else {\n        return InvokeResult::failure(description.str());\n    }\n}\n\nconst InvokeResult BoostStep::invokeStepBody() {\n    static std::once_flag initialized;\n    std::call_once(initialized, BoostStep::initBoostTest);\n\n    logInterceptor->reset();\n    runWithMasterSuite();\n    return logInterceptor->getResult();\n}\n\nvoid BoostStep::initBoostTest() {\n    int argc = 1;\n    char dummyArg[] = \"dummy\";\n    char* argv[] = {dummyArg};\n    framework::init(&boost_test_init, argc, argv);\n    framework::finalize_setup_phase();\n\n    logInterceptor = new CukeBoostLogInterceptor;\n    ::boost::unit_test::unit_test_log.set_formatter(logInterceptor);\n    ::boost::unit_test::unit_test_log.set_threshold_level(log_all_errors);\n}\n\nvoid BoostStep::runWithMasterSuite() {\n    currentTestBody = std::bind(&BoostStep::body, this);\n\n    ::boost::unit_test::framework::run(testCase, false);\n\n    currentTestBody.clear();\n}\n\n}\n}\n"
  },
  {
    "path": "src/drivers/GTestDriver.cpp",
    "content": "#include <cucumber-cpp/internal/drivers/GTestDriver.hpp>\n\n#include <gtest/gtest.h>\n\nnamespace cucumber {\nnamespace internal {\n\nbool GTestStep::initialized(false);\n\nconst InvokeResult GTestStep::invokeStepBody() {\n    if (!initialized) {\n        initGTest();\n        initFlags();\n    }\n    try {\n        body();\n        return InvokeResult::success();\n    } catch (const ::std::runtime_error& e) {\n        // ::testing::GoogleTestFailureException inherits from ::std::runtime_error\n        return InvokeResult::failure(e.what());\n    }\n}\n\nvoid GTestStep::initGTest() {\n    int fake_argc = 1;\n    char* fake_argv[1];\n    fake_argv[0] = (char*)\"cucumber-cpp\";\n    ::testing::InitGoogleTest(&fake_argc, fake_argv);\n    initialized = true;\n}\n\nvoid GTestStep::initFlags() {\n    ::testing::GTEST_FLAG(throw_on_failure) = true;  // let cucumber-cpp drive\n    ::testing::GTEST_FLAG(break_on_failure) = false; // turn off debugger breakpoints\n    ::testing::GTEST_FLAG(catch_exceptions) = true;\n}\n\n}\n}\n"
  },
  {
    "path": "src/drivers/GenericDriver.cpp",
    "content": "#include \"cucumber-cpp/internal/drivers/GenericDriver.hpp\"\n\nnamespace cucumber {\nnamespace internal {\n\nconst InvokeResult GenericStep::invokeStepBody() {\n    // No try/catch block to throw the original exceptions to the testing framework\n    body();\n    return InvokeResult::success();\n}\n\n}\n}\n"
  },
  {
    "path": "src/drivers/QtTestDriver.cpp",
    "content": "#include \"cucumber-cpp/internal/drivers/QtTestDriver.hpp\"\n\n#include <QTest>\n#include <QTemporaryFile>\n#include <QTextStream>\n\nnamespace cucumber {\nnamespace internal {\n\n/**\n * Wraps the QTemporaryFile for Windows.\n *\n * On Windows. the file can not be written as long as QTemporaryFile keeps it open.\n */\nclass TemporaryFileWrapper {\npublic:\n    ~TemporaryFileWrapper() {\n        QFile::remove(filename);\n    }\n\n    bool exists() const {\n        return !filename.isEmpty();\n    }\n\n    QString name() const {\n        return filename;\n    }\n\n    QString read() const {\n        QFile file{filename};\n        if (!file.open(QIODevice::ReadOnly | QIODevice::Text))\n            return QString();\n        QTextStream in(&file);\n        return in.readAll();\n    }\n\nprivate:\n    const QString filename{getTmpFileName()};\n\n    static QString getTmpFileName() {\n        QTemporaryFile tempFile{};\n        if (!tempFile.open()) {\n            return {};\n        }\n        return tempFile.fileName() + \".txt\";\n    }\n};\n\nconst InvokeResult QtTestStep::invokeStepBody() {\n    const TemporaryFileWrapper file{};\n    if (!file.exists()) {\n        return InvokeResult::failure(\"Unable to open temporary file needed for this test\");\n    }\n\n    QtTestObject testObject{this};\n    const QStringList args{\"test\", \"-o\", file.name() + \",tap\"};\n    const int returnValue = QTest::qExec(&testObject, args);\n\n    if (returnValue == 0) {\n        return InvokeResult::success();\n    } else {\n        return InvokeResult::failure(file.read().toLocal8Bit());\n    }\n}\n\n}\n}\n"
  },
  {
    "path": "src/main.cpp",
    "content": "#include <cucumber-cpp/internal/CukeEngineImpl.hpp>\n#include <cucumber-cpp/internal/CukeExport.hpp>\n#include <cucumber-cpp/internal/connectors/wire/WireServer.hpp>\n#include <cucumber-cpp/internal/connectors/wire/WireProtocol.hpp>\n#include <iostream>\n#include <memory>\n#include <tclap/CmdLine.h>\n\nnamespace {\n\nvoid acceptWireProtocol(\n    const std::string& host, int port, const std::string& unixPath, bool verbose\n) {\n    using namespace ::cucumber::internal;\n    CukeEngineImpl cukeEngine;\n    JsonWireMessageCodec wireCodec;\n    WireProtocolHandler protocolHandler(wireCodec, cukeEngine);\n    std::unique_ptr<SocketServer> server;\n#if defined(ASIO_HAS_LOCAL_SOCKETS)\n    if (!unixPath.empty()) {\n        UnixSocketServer* const unixServer = new UnixSocketServer(&protocolHandler);\n        server.reset(unixServer);\n        unixServer->listen(unixPath);\n        if (verbose)\n            std::clog << \"Listening on socket \" << unixServer->listenEndpoint() << std::endl;\n    } else\n#else\n    // Prevent warning about unused parameter\n    static_cast<void>(unixPath);\n#endif\n    {\n        TCPSocketServer* const tcpServer = new TCPSocketServer(&protocolHandler);\n        server.reset(tcpServer);\n        tcpServer->listen(asio::ip::tcp::endpoint(asio::ip::make_address(host), port));\n        if (verbose)\n            std::clog << \"Listening on \" << tcpServer->listenEndpoint() << std::endl;\n    }\n    server->acceptOnce();\n}\n\n}\n\nint CUCUMBER_CPP_EXPORT main(int argc, char** argv) {\n    TCLAP::CmdLine cmd(\"C++ Cucumber wireserver\", ' ', CUKE_VERSION);\n\n    TCLAP::SwitchArg verboseArg(\"v\", \"verbose\", \"Verbose output\", cmd, false);\n    TCLAP::ValueArg<std::string> listenArg(\n        \"l\", \"listen\", \"Listening address of wireserver\", false, \"127.0.0.1\", \"string\"\n    );\n    cmd.add(listenArg);\n    TCLAP::ValueArg<int> portArg(\n        \"p\",\n        \"port\",\n        \"Listening port of wireserver, use '0' (zero) to select an ephemeral port\",\n        false,\n        3902,\n        \"int\"\n    );\n    cmd.add(portArg);\n\n#if defined(ASIO_HAS_LOCAL_SOCKETS)\n    TCLAP::ValueArg<std::string> unixArg(\n        \"u\",\n        \"unix\",\n        \"Listening unix socket of wireserver (disables listening on port)\",\n        false,\n        \"\",\n        \"string\"\n    );\n    cmd.add(unixArg);\n#endif\n\n    cmd.parse(argc, argv);\n\n    std::string unixPath;\n    std::string listenHost = listenArg.getValue();\n    int port = portArg.getValue();\n#if defined(ASIO_HAS_LOCAL_SOCKETS)\n    unixPath = unixArg.getValue();\n#endif\n\n    bool verbose = verboseArg.getValue();\n\n    try {\n        acceptWireProtocol(listenHost, port, unixPath, verbose);\n    } catch (std::exception& e) {\n        std::cerr << e.what() << std::endl;\n        exit(1);\n    }\n    return 0;\n}\n"
  },
  {
    "path": "tests/CMakeLists.txt",
    "content": "find_package(GTest REQUIRED)\n\nadd_library(utils INTERFACE\n    utils/HookRegistrationFixture.hpp\n    utils/ContextManagerTestDouble.hpp\n    utils/DriverTestRunner.hpp\n    utils/CukeCommandsFixture.hpp\n    utils/StepManagerTestDouble.hpp\n)\ntarget_include_directories(utils INTERFACE\n    .\n)\n\nfunction(cuke_add_driver_test TEST_FILE)\n    get_filename_component(TEST_NAME ${TEST_FILE} NAME)\n    message(STATUS \"Adding \" ${TEST_NAME})\n    add_executable(${TEST_NAME} ${TEST_FILE}.cpp)\n    target_link_libraries(${TEST_NAME} PRIVATE cucumber-cpp-internal utils ${ARGN})\n    add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME})\nendfunction()\n\nif(TARGET GTest::gmock_main)\n    function(cuke_add_test TEST_FILE)\n        get_filename_component(TEST_NAME ${TEST_FILE} NAME)\n        message(STATUS \"Adding \" ${TEST_NAME})\n        add_executable(${TEST_NAME} ${TEST_FILE}.cpp)\n        target_link_libraries(${TEST_NAME} PRIVATE cucumber-cpp-internal utils ${ARGN} GTest::gmock_main)\n        gtest_add_tests(${TEST_NAME} \"\" ${TEST_FILE}.cpp)\n        # Run all tests in executable at once too. This ensures that the used fixtures get tested\n        # properly too. Additionally gather the output in jUnit compatible output for CI.\n        add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME} \"--gtest_output=xml:TEST-${TEST_NAME}.xml\")\n    endfunction()\n\n    # TODO Compile tests with the least possible code, not with the entire library\n    cuke_add_test(integration/ContextHandlingTest)\n    cuke_add_test(integration/HookRegistrationTest)\n    cuke_add_test(integration/StepRegistrationTest)\n    cuke_add_test(integration/TaggedHookRegistrationTest)\n    if(NOT WIN32)\n        cuke_add_test(integration/WireServerTest)\n    endif()\n    cuke_add_test(integration/WireProtocolTest)\n    cuke_add_test(unit/BasicStepTest)\n    cuke_add_test(unit/ContextManagerTest)\n    cuke_add_test(unit/CukeCommandsTest)\n    cuke_add_test(unit/RegexTest)\n    cuke_add_test(unit/StepCallChainTest)\n    cuke_add_test(unit/StepManagerTest)\n    cuke_add_test(unit/TableTest)\n    cuke_add_test(unit/TagTest)\nendif()\n\nif(TARGET GTest::gtest_main)\n    cuke_add_driver_test(integration/drivers/GTestDriverTest GTest::gtest_main)\nendif()\n\nif(TARGET Boost::unit_test_framework)\n    cuke_add_driver_test(integration/drivers/BoostDriverTest Boost::unit_test_framework)\nendif()\n\nif((TARGET Qt::Test)\n    # FIXME: not including this in the test suite due to memory leak #190\n    AND (NOT VALGRIND_TESTS)\n    )\n    cuke_add_driver_test(integration/drivers/QtTestDriverTest Qt::Test)\nendif()\n\ncuke_add_driver_test(integration/drivers/GenericDriverTest)\n"
  },
  {
    "path": "tests/integration/ContextHandlingTest.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"utils/ContextManagerTestDouble.hpp\"\n\nusing namespace std;\nusing namespace cucumber::internal;\n\nclass ContextHandlingTest : public ::testing::Test {\npublic:\n    ContextHandlingTest() :\n        contextManager() {\n    }\n\nprotected:\n    ContextManagerTestDouble contextManager;\n\nprivate:\n    void TearDown() override {\n        contextManager.purgeContexts();\n    }\n};\n\nstruct Context1 {\n    int i;\n};\nstruct Context2 {};\n\nTEST_F(ContextHandlingTest, contextsAreCreatedWhenNeeded) {\n    ASSERT_EQ(0, contextManager.countContexts());\n    ::cucumber::ScenarioScope<Context1> context1;\n    ASSERT_EQ(1, contextManager.countContexts());\n    ::cucumber::ScenarioScope<Context2> context2;\n    ASSERT_EQ(2, contextManager.countContexts());\n}\n\nTEST_F(ContextHandlingTest, sameContextTypesShareTheSamePointer) {\n    ::cucumber::ScenarioScope<Context1> context1_a;\n    ::cucumber::ScenarioScope<Context1> context1_b;\n    context1_a->i = 42;\n    ASSERT_EQ(context1_a->i, context1_b->i);\n}\n\nTEST_F(ContextHandlingTest, theSameContextIsNotCreatedTwice) {\n    ASSERT_EQ(0, contextManager.countContexts());\n    ::cucumber::ScenarioScope<Context1> context1_a;\n    ASSERT_EQ(1, contextManager.countContexts());\n    ::cucumber::ScenarioScope<Context1> context1_b;\n    ASSERT_EQ(1, contextManager.countContexts());\n}\n\nTEST_F(ContextHandlingTest, contextsArePurgedExplicitlyOnly) {\n    ASSERT_EQ(0, contextManager.countContexts());\n    ::cucumber::ScenarioScope<Context1> context1_a;\n    ASSERT_EQ(1, contextManager.countContexts());\n    ::cucumber::ScenarioScope<Context2>* context1_b = new ::cucumber::ScenarioScope<Context2>();\n    ASSERT_EQ(2, contextManager.countContexts());\n    delete context1_b;\n    ASSERT_EQ(2, contextManager.countContexts());\n    contextManager.purgeContexts();\n    ASSERT_EQ(0, contextManager.countContexts());\n}\n"
  },
  {
    "path": "tests/integration/HookRegistrationTest.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"utils/HookRegistrationFixture.hpp\"\n\n#include <cucumber-cpp/internal/hook/HookMacros.hpp>\n\n#define BEFORE_ALL_MARKER_1 \"A\"\n#define BEFORE_ALL_MARKER_2 \"B\"\n#define BEFORE_ALL_MARKER_3 \"C\"\nBEFORE_ALL() {\n    beforeAllHookCallMarker << BEFORE_ALL_MARKER_1;\n}\nBEFORE_ALL() {\n    beforeAllHookCallMarker << BEFORE_ALL_MARKER_2;\n}\nBEFORE_ALL() {\n    beforeAllHookCallMarker << BEFORE_ALL_MARKER_3;\n}\n\n#define BEFORE_MARKER_1 \"D\"\n#define BEFORE_MARKER_2 \"E\"\n#define BEFORE_MARKER_3 \"F\"\nBEFORE() {\n    beforeHookCallMarker << BEFORE_MARKER_1;\n}\nBEFORE() {\n    beforeHookCallMarker << BEFORE_MARKER_2;\n}\nBEFORE() {\n    beforeHookCallMarker << BEFORE_MARKER_3;\n}\n\n#define AROUND_STEP_MARKER_BEFORE_1 \"G\"\n#define AROUND_STEP_MARKER_BEFORE_2 \"H\"\n#define AROUND_STEP_MARKER_BEFORE_3 \"I\"\n#define AROUND_STEP_MARKER_AFTER_3 \"g\"\n#define AROUND_STEP_MARKER_AFTER_2 \"h\"\n#define AROUND_STEP_MARKER_AFTER_1 \"i\"\nAROUND_STEP() {\n    beforeAroundStepHookCallMarker << AROUND_STEP_MARKER_BEFORE_1;\n    globalStepHookCallMarker << AROUND_STEP_MARKER_BEFORE_1;\n    step->call();\n    globalStepHookCallMarker << AROUND_STEP_MARKER_AFTER_1;\n    afterAroundStepHookCallMarker << AROUND_STEP_MARKER_AFTER_1;\n}\nAROUND_STEP() {\n    beforeAroundStepHookCallMarker << AROUND_STEP_MARKER_BEFORE_2;\n    globalStepHookCallMarker << AROUND_STEP_MARKER_BEFORE_2;\n    step->call();\n    globalStepHookCallMarker << AROUND_STEP_MARKER_AFTER_2;\n    afterAroundStepHookCallMarker << AROUND_STEP_MARKER_AFTER_2;\n}\nAROUND_STEP() {\n    beforeAroundStepHookCallMarker << AROUND_STEP_MARKER_BEFORE_3;\n    globalStepHookCallMarker << AROUND_STEP_MARKER_BEFORE_3;\n    step->call();\n    globalStepHookCallMarker << AROUND_STEP_MARKER_AFTER_3;\n    afterAroundStepHookCallMarker << AROUND_STEP_MARKER_AFTER_3;\n}\n\n#define AFTER_STEP_MARKER_1 \"J\"\n#define AFTER_STEP_MARKER_2 \"K\"\n#define AFTER_STEP_MARKER_3 \"L\"\nAFTER_STEP() {\n    afterStepHookCallMarker << AFTER_STEP_MARKER_1;\n    globalStepHookCallMarker << AFTER_STEP_MARKER_1;\n}\nAFTER_STEP() {\n    afterStepHookCallMarker << AFTER_STEP_MARKER_2;\n    globalStepHookCallMarker << AFTER_STEP_MARKER_2;\n}\nAFTER_STEP() {\n    afterStepHookCallMarker << AFTER_STEP_MARKER_3;\n    globalStepHookCallMarker << AFTER_STEP_MARKER_3;\n}\n\n#define AFTER_MARKER_1 \"M\"\n#define AFTER_MARKER_2 \"N\"\n#define AFTER_MARKER_3 \"O\"\nAFTER() {\n    afterHookCallMarker << AFTER_MARKER_1;\n}\nAFTER() {\n    afterHookCallMarker << AFTER_MARKER_2;\n}\nAFTER() {\n    afterHookCallMarker << AFTER_MARKER_3;\n}\n\n#define AFTER_ALL_MARKER_1 \"P\"\n#define AFTER_ALL_MARKER_2 \"Q\"\n#define AFTER_ALL_MARKER_3 \"R\"\nAFTER_ALL() {\n    afterAllHookCallMarker << AFTER_ALL_MARKER_1;\n}\nAFTER_ALL() {\n    afterAllHookCallMarker << AFTER_ALL_MARKER_2;\n}\nAFTER_ALL() {\n    afterAllHookCallMarker << AFTER_ALL_MARKER_3;\n}\n\n#define CONTEXT_MARKER \"X\"\nBEFORE() {\n    cucumber::ScenarioScope<std::string> context;\n    *context = CONTEXT_MARKER;\n}\nAFTER() {\n    cucumber::ScenarioScope<std::string> context;\n    contextContents = *context;\n}\n\nconst std::string correctBeforeOrder(BEFORE_MARKER_1 BEFORE_MARKER_2 BEFORE_MARKER_3);\nconst std::string correctBeforeAroundStepOrder(\n    AROUND_STEP_MARKER_BEFORE_1 AROUND_STEP_MARKER_BEFORE_2 AROUND_STEP_MARKER_BEFORE_3\n);\nconst std::string correctAfterAroundStepOrder(AROUND_STEP_MARKER_AFTER_3 AROUND_STEP_MARKER_AFTER_2\n                                                  AROUND_STEP_MARKER_AFTER_1);\nconst std::string correctAfterStepOrder(AFTER_STEP_MARKER_1 AFTER_STEP_MARKER_2 AFTER_STEP_MARKER_3\n);\nconst std::string correctAfterOrder(AFTER_MARKER_1 AFTER_MARKER_2 AFTER_MARKER_3);\nconst std::string correctBeforeAllOrder(BEFORE_ALL_MARKER_1 BEFORE_ALL_MARKER_2 BEFORE_ALL_MARKER_3\n);\nconst std::string correctAfterAllOrder(AFTER_ALL_MARKER_1 AFTER_ALL_MARKER_2 AFTER_ALL_MARKER_3);\n\nTEST_F(HookRegistrationTest, hooksAreRegisteredByTheMacros) {\n    beginScenario();\n    EXPECT_EQ(correctBeforeOrder, sort(beforeHookOrder()));\n    EXPECT_EQ(correctBeforeAroundStepOrder, sort(aroundStepHookOrder()));\n    EXPECT_EQ(correctAfterStepOrder, sort(afterStepHookOrder()));\n    EXPECT_EQ(correctAfterOrder, sort(afterHookOrder()));\n    endScenario();\n}\n\nTEST_F(HookRegistrationTest, beforeHooksAreInvokedInAnyOrder) {\n    EXPECT_EQ(\"\", beforeHookCallMarker.str());\n    beginScenario();\n    EXPECT_EQ(correctBeforeOrder, sort(beforeHookCallMarker.str()));\n    invokeStep();\n    endScenario();\n    EXPECT_EQ(correctBeforeOrder, sort(beforeHookCallMarker.str()));\n}\n\nTEST_F(HookRegistrationTest, aroundStepHooksAreInvokedInAnyOrderButNested) {\n    beginScenario();\n    EXPECT_EQ(\"\", beforeAroundStepHookCallMarker.str());\n    invokeStep();\n    EXPECT_EQ(correctBeforeAroundStepOrder, sort(beforeAroundStepHookCallMarker.str()));\n    EXPECT_EQ(correctAfterAroundStepOrder, sort(afterAroundStepHookCallMarker.str()));\n    endScenario();\n    EXPECT_EQ(correctBeforeAroundStepOrder, sort(beforeAroundStepHookCallMarker.str()));\n    EXPECT_EQ(correctAfterAroundStepOrder, sort(afterAroundStepHookCallMarker.str()));\n}\n\nTEST_F(HookRegistrationTest, afterStepHooksAreInvokedInAnyOrder) {\n    beginScenario();\n    EXPECT_EQ(\"\", afterStepHookCallMarker.str());\n    invokeStep();\n    EXPECT_EQ(correctAfterStepOrder, sort(afterStepHookCallMarker.str()));\n    endScenario();\n    EXPECT_EQ(correctAfterStepOrder, sort(afterStepHookCallMarker.str()));\n}\n\nTEST_F(HookRegistrationTest, afterHooksAreInvokedInAnyOrder) {\n    beginScenario();\n    invokeStep();\n    invokeStep();\n    EXPECT_EQ(\"\", sort(afterHookCallMarker.str()));\n    endScenario();\n    EXPECT_EQ(correctAfterOrder, sort(afterHookCallMarker.str()));\n}\n\nTEST_F(HookRegistrationTest, contextIsAccessibleInAfterHooks) {\n    beginScenario();\n    endScenario();\n    EXPECT_EQ(CONTEXT_MARKER, contextContents);\n}\n\nTEST_F(HookRegistrationTest, afterStepHooksAreInvokedAfterAroundStepHooks) {\n    beginScenario();\n    EXPECT_EQ(\"\", globalStepHookCallMarker.str());\n    invokeStep();\n    EXPECT_EQ(\n        beforeAroundStepHookCallMarker.str() + afterAroundStepHookCallMarker.str()\n            + afterStepHookCallMarker.str(),\n        globalStepHookCallMarker.str()\n    );\n    endScenario();\n}\n\nTEST_F(HookRegistrationTest, beforeAllHooksAreInvokedInAnyOrderDuringFirstScenarioOnly) {\n    EXPECT_EQ(\"\", afterAllHookCallMarker.str());\n    beginScenario();\n    EXPECT_EQ(correctBeforeAllOrder, sort(beforeAllHookCallMarker.str()));\n\n    clearHookCallMarkers();\n    invokeStep();\n    endScenario();\n    EXPECT_EQ(\"\", sort(beforeAllHookCallMarker.str()));\n    beginScenario();\n    invokeStep();\n    endScenario();\n    EXPECT_EQ(\"\", sort(beforeAllHookCallMarker.str()));\n}\n\nTEST_F(HookRegistrationTest, beforeAllHooksAreNotInvokedIfNoScenariosRun) {\n    clearHookCallMarkers();\n    CukeCommands* cukeCommands = new CukeCommands();\n    EXPECT_EQ(\"\", afterAllHookCallMarker.str());\n\n    delete cukeCommands;\n    cukeCommands = NULL;\n\n    EXPECT_EQ(\"\", beforeAllHookCallMarker.str());\n}\n\nTEST_F(HookRegistrationTest, afterAllHooksAreNotInvokedIfNoScenariosRun) {\n    clearHookCallMarkers();\n    CukeCommands* cukeCommands = new CukeCommands();\n    EXPECT_EQ(\"\", afterAllHookCallMarker.str());\n\n    delete cukeCommands;\n    cukeCommands = NULL;\n\n    EXPECT_EQ(\"\", afterAllHookCallMarker.str());\n}\n\nTEST_F(HookRegistrationTest, afterAllHooksAreInvokedOnceDuringDestructionOnly) {\n    clearHookCallMarkers();\n    CukeCommands* cukeCommands = new CukeCommands();\n\n    EXPECT_EQ(\"\", afterAllHookCallMarker.str());\n    cukeCommands->beginScenario();\n    cukeCommands->endScenario();\n    EXPECT_EQ(\"\", afterAllHookCallMarker.str());\n    cukeCommands->beginScenario();\n    cukeCommands->endScenario();\n    EXPECT_EQ(\"\", afterAllHookCallMarker.str());\n\n    delete cukeCommands;\n    cukeCommands = NULL;\n\n    EXPECT_EQ(correctAfterAllOrder, sort(afterAllHookCallMarker.str()));\n}\n"
  },
  {
    "path": "tests/integration/StepRegistrationTest.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <cucumber-cpp/internal/step/StepManager.hpp>\n#include <cucumber-cpp/internal/step/StepMacros.hpp>\n#include <cucumber-cpp/internal/drivers/GenericDriver.hpp>\n\nusing namespace cucumber::internal;\n\n#define MANUAL_STEP_MATCHER \"manual step\"\n\nclass ManualStep : public GenericStep {\npublic:\n    void body() override{};\n    // private:\n    static const int cukeRegId;\n};\nconst int ManualStep::cukeRegId = ::cucumber::internal::registerStep<ManualStep>(\n    MANUAL_STEP_MATCHER, \"C:\\\\Path\\\\With/Barward/And\\\\Forward/Slashes.cpp\", 42\n);\n\nTEST(StepRegistrationTest, manualRegistration) {\n    // static_cast is necessary for GTest <= 1.7 and C++ >= 2011 because it\n    // doesn't support contextually-convertible-to-bool\n    EXPECT_TRUE(static_cast<bool>(StepManager::stepMatches(MANUAL_STEP_MATCHER)));\n    EXPECT_EQ(\"Slashes.cpp:42\", StepManager::getStep(ManualStep::cukeRegId)->source);\n}\n\n#define GIVEN_MATCHER \"given matcher\"\n#define WHEN_MATCHER \"when matcher\"\n#define THEN_MATCHER \"then matcher\"\n\nGIVEN(GIVEN_MATCHER) {\n}\nWHEN(WHEN_MATCHER) {\n}\nTHEN(THEN_MATCHER) {\n}\n\nTEST(StepRegistrationTest, macroRegistration) {\n    EXPECT_TRUE(static_cast<bool>(StepManager::stepMatches(GIVEN_MATCHER)));\n    EXPECT_TRUE(static_cast<bool>(StepManager::stepMatches(WHEN_MATCHER)));\n    EXPECT_TRUE(static_cast<bool>(StepManager::stepMatches(THEN_MATCHER)));\n}\n"
  },
  {
    "path": "tests/integration/TaggedHookRegistrationTest.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"utils/HookRegistrationFixture.hpp\"\n#include <cucumber-cpp/internal/hook/HookMacros.hpp>\n\nBEFORE(\"@a\") {\n    beforeHookCallMarker << \"A\";\n}\nBEFORE(\"@a\", \"@b\") {\n    beforeHookCallMarker << \"B\";\n}\nBEFORE(\"@a,@b\") {\n    beforeHookCallMarker << \"C\";\n}\n\nAROUND_STEP(\"@a\") {\n    afterAroundStepHookCallMarker << \"D\";\n    step->call();\n}\nAROUND_STEP(\"@a\", \"@b\") {\n    afterAroundStepHookCallMarker << \"E\";\n    step->call();\n}\nAROUND_STEP(\"@a,@b\") {\n    afterAroundStepHookCallMarker << \"F\";\n    step->call();\n}\n\nAFTER_STEP(\"@a\") {\n    afterStepHookCallMarker << \"G\";\n}\nAFTER_STEP(\"@a\", \"@b\") {\n    afterStepHookCallMarker << \"H\";\n}\nAFTER_STEP(\"@a,@b\") {\n    afterStepHookCallMarker << \"I\";\n}\n\nAFTER(\"@a\") {\n    afterHookCallMarker << \"J\";\n}\nAFTER(\"@a\", \"@b\") {\n    afterHookCallMarker << \"K\";\n}\nAFTER(\"@a,@b\") {\n    afterHookCallMarker << \"L\";\n}\n\nTEST_F(HookRegistrationTest, noTaggedHooksAreInvokedIfNoScenarioTag) {\n    beginScenario();\n    invokeStep();\n    endScenario();\n    EXPECT_EQ(\"\", sort(beforeHookCallMarker.str()));\n    EXPECT_EQ(\"\", sort(afterAroundStepHookCallMarker.str()));\n    EXPECT_EQ(\"\", sort(afterStepHookCallMarker.str()));\n    EXPECT_EQ(\"\", sort(afterHookCallMarker.str()));\n}\n\nTEST_F(HookRegistrationTest, orTagsAreEnforced) {\n    const TagExpression::tag_list tags = {\"b\"};\n    beginScenario(tags);\n    invokeStep();\n    endScenario();\n    EXPECT_EQ(\"C\", sort(beforeHookCallMarker.str()));\n    EXPECT_EQ(\"F\", sort(afterAroundStepHookCallMarker.str()));\n    EXPECT_EQ(\"I\", sort(afterStepHookCallMarker.str()));\n    EXPECT_EQ(\"L\", sort(afterHookCallMarker.str()));\n}\n\nTEST_F(HookRegistrationTest, andTagsAreEnforced) {\n    const TagExpression::tag_list tags = {\"a\", \"b\"};\n    beginScenario(tags);\n    invokeStep();\n    endScenario();\n    EXPECT_EQ(\"ABC\", sort(beforeHookCallMarker.str()));\n    EXPECT_EQ(\"DEF\", sort(afterAroundStepHookCallMarker.str()));\n    EXPECT_EQ(\"GHI\", sort(afterStepHookCallMarker.str()));\n    EXPECT_EQ(\"JKL\", sort(afterHookCallMarker.str()));\n}\n"
  },
  {
    "path": "tests/integration/WireProtocolTest.cpp",
    "content": "#include <cucumber-cpp/internal/connectors/wire/WireProtocol.hpp>\n#include <cucumber-cpp/internal/connectors/wire/WireProtocolCommands.hpp>\n\n#include <gmock/gmock.h>\n\n#include <typeinfo>\n\nusing namespace cucumber::internal;\nusing namespace std;\nusing namespace testing;\n\nclass MockCukeEngine : public CukeEngine {\npublic:\n    MOCK_METHOD(std::vector<StepMatch>, stepMatches, (const std::string& name), (const, override));\n    MOCK_METHOD(void, endScenario, (const tags_type& tags), (override));\n    MOCK_METHOD(\n        void,\n        invokeStep,\n        (const std::string& id, const invoke_args_type& args, const invoke_table_type& tableArg),\n        (override)\n    );\n    MOCK_METHOD(void, beginScenario, (const tags_type& tags), (override));\n    MOCK_METHOD(\n        std::string,\n        snippetText,\n        (const std::string& keyword, const std::string& name, const std::string& multilineArgClass),\n        (const, override)\n    );\n};\n\n#define EXPECT_PTRTYPE(classname, expression) \\\n    EXPECT_NE(dynamic_cast<const classname*>(expression), (void*)NULL)\n\nclass WireMessageCodecTest : public Test {\nprotected:\n    std::shared_ptr<WireCommand> commandAutoPtr;\n\n    WireCommand& decode(const char* jsonStr) {\n        commandAutoPtr = codec.decode(jsonStr);\n        return *commandAutoPtr;\n    }\n\n    std::string encode(const WireResponse& response) const {\n        return codec.encode(response);\n    }\n\nprotected:\n    const JsonWireMessageCodec codec;\n};\n\n/*\n * Request decoding\n */\n\nTEST_F(WireMessageCodecTest, decodesUnknownOrMalformedMessage) {\n    MockCukeEngine engine;\n\n    EXPECT_EQ(encode(*decode(\"[\\\"unknown_command\\\"]\").run(engine)), \"[\\\"fail\\\"]\");\n    EXPECT_EQ(encode(*decode(\"\").run(engine)), \"[\\\"fail\\\"]\");\n    EXPECT_EQ(encode(*decode(\"rubbish\").run(engine)), \"[\\\"fail\\\"]\");\n    EXPECT_EQ(encode(*decode(\"{\\\"malformed_command\\\"}\").run(engine)), \"[\\\"fail\\\"]\");\n    EXPECT_EQ(encode(*decode(\"[42]\").run(engine)), \"[\\\"fail\\\"]\");\n}\n\nTEST_F(WireMessageCodecTest, handlesStepMatchesMessage) {\n    MockCukeEngine engine;\n    EXPECT_CALL(engine, stepMatches(\"name to match\"))\n        .Times(1)\n        .WillRepeatedly(Return(std::vector<StepMatch>(0)));\n\n    decode(R\"json([\n        \"step_matches\", {\n            \"name_to_match\": \"name to match\"\n        }\n    ])json\")\n        .run(engine);\n}\n\nTEST_F(WireMessageCodecTest, handlesBeginScenarioMessageWithoutArgument) {\n    MockCukeEngine engine;\n    EXPECT_CALL(engine, beginScenario(ElementsAre())).Times(1);\n\n    decode(R\"json([\n        \"begin_scenario\"\n    ])json\")\n        .run(engine);\n}\n\nTEST_F(WireMessageCodecTest, handlesBeginScenarioMessageWithTagsArgument) {\n    MockCukeEngine engine;\n    EXPECT_CALL(engine, beginScenario(ElementsAre(\"bar\", \"baz\", \"foo\"))).Times(1);\n\n    decode(R\"json([\n        \"begin_scenario\", {\n            \"tags\": [\"bar\", \"baz\", \"foo\"]\n        }\n    ])json\")\n        .run(engine);\n}\n\nTEST_F(WireMessageCodecTest, handlesBeginScenarioMessageWithNullArgument) {\n    MockCukeEngine engine;\n    EXPECT_CALL(engine, beginScenario(ElementsAre())).Times(1);\n\n    decode(R\"json([\n        \"begin_scenario\",\n        null\n    ])json\")\n        .run(engine);\n}\n\nTEST_F(WireMessageCodecTest, handlesInvokeMessageWithNoArgs) {\n    MockCukeEngine engine;\n    EXPECT_CALL(engine, invokeStep(\"42\", ElementsAre(), ElementsAre())).Times(1);\n\n    decode(R\"json([\n        \"invoke\", {\n            \"id\": \"42\",\n            \"args\": []\n        }\n    ])json\")\n        .run(engine);\n}\n\nTEST_F(WireMessageCodecTest, handlesInvokeMessageWithoutTableArgs) {\n    MockCukeEngine engine;\n    EXPECT_CALL(engine, invokeStep(\"42\", ElementsAre(\"p1\", \"p2\", \"p3\"), ElementsAre())).Times(1);\n\n    decode(R\"json([\n        \"invoke\", {\n            \"id\": \"42\",\n            \"args\": [\"p1\", \"p2\", \"p3\"]\n        }\n    ])json\")\n        .run(engine);\n}\n\nTEST_F(WireMessageCodecTest, handlesInvokeMessageWithTableArgs) {\n    MockCukeEngine engine;\n    EXPECT_CALL(\n        engine,\n        invokeStep(\n            \"42\",\n            ElementsAre(\"p1\"),\n            ElementsAre(\n                ElementsAre(\"col1\", \"col2\"),\n                ElementsAre(\"r1c1\", \"r1c2\"),\n                ElementsAre(\"r2c1\", \"r2c2\"),\n                ElementsAre(\"r3c1\", \"r3c2\")\n            )\n        )\n    )\n        .Times(1);\n\n    decode(R\"json([\n        \"invoke\", {\n            \"id\": \"42\",\n            \"args\": [\n                \"p1\",\n                [\n                    [\"col1\", \"col2\"],\n                    [\"r1c1\", \"r1c2\"],\n                    [\"r2c1\", \"r2c2\"],\n                    [\"r3c1\", \"r3c2\"]\n                ]\n            ]\n        }\n    ])json\")\n        .run(engine);\n}\n\nTEST_F(WireMessageCodecTest, handlesInvokeMessageWithNullArg) {\n    MockCukeEngine engine;\n    EXPECT_CALL(engine, invokeStep(\"42\", ElementsAre(), ElementsAre())).Times(1);\n\n    decode(R\"json([\n        \"invoke\", {\n            \"id\": \"42\",\n            \"args\": [null]\n        }\n    ])json\")\n        .run(engine);\n}\n\nTEST_F(WireMessageCodecTest, handlesEndScenarioMessageWithoutArgument) {\n    MockCukeEngine engine;\n    EXPECT_CALL(engine, endScenario(ElementsAre())).Times(1);\n\n    decode(R\"json([\n        \"end_scenario\"\n    ])json\")\n        .run(engine);\n}\n\nTEST_F(WireMessageCodecTest, handlesEndScenarioMessageWithNullArgument) {\n    MockCukeEngine engine;\n    EXPECT_CALL(engine, endScenario(ElementsAre())).Times(1);\n\n    decode(R\"json([\n        \"end_scenario\",\n        null\n    ])json\")\n        .run(engine);\n}\n\nTEST_F(WireMessageCodecTest, handlesEndScenarioMessageWithTagsArgument) {\n    MockCukeEngine engine;\n    EXPECT_CALL(engine, endScenario(ElementsAre(\"cu\", \"cum\", \"ber\"))).Times(1);\n\n    decode(R\"json([\n        \"end_scenario\", {\n            \"tags\": [\n                \"cu\",\n                \"cum\",\n                \"ber\"\n            ]\n        }\n    ])json\")\n        .run(engine);\n}\n\nTEST_F(WireMessageCodecTest, handlesSnippetTextMessage) {\n    MockCukeEngine engine;\n    EXPECT_CALL(engine, snippetText(\"Keyword\", \"step description\", \"Some::Class\")).Times(1);\n\n    decode(R\"json([\n        \"snippet_text\", {\n            \"step_keyword\": \"Keyword\",\n            \"multiline_arg_class\": \"Some::Class\",\n            \"step_name\": \"step description\"\n        }\n    ])json\")\n        .run(engine);\n}\n\n/*\n * Response encoding\n */\n\nTEST_F(WireMessageCodecTest, handlesSuccessResponse) {\n    SuccessResponse response;\n    EXPECT_THAT(codec.encode(response), StrEq(\"[\\\"success\\\"]\"));\n}\n\nTEST_F(WireMessageCodecTest, handlesSimpleFailureResponse) {\n    FailureResponse response;\n    EXPECT_THAT(codec.encode(response), StrEq(\"[\\\"fail\\\"]\"));\n}\n\nTEST_F(WireMessageCodecTest, handlesDetailedFailureResponse) {\n    FailureResponse response(\"My message\", \"ExceptionClassName\");\n    EXPECT_THAT(\n        codec.encode(response),\n        StrEq(\"[\\\"fail\\\",{\"\n              \"\\\"exception\\\":\\\"ExceptionClassName\\\",\"\n              \"\\\"message\\\":\\\"My message\\\"\"\n              \"}]\")\n    );\n}\n\nTEST_F(WireMessageCodecTest, handlesPendingResponse) {\n    PendingResponse response(\"I'm lazy!\");\n    EXPECT_THAT(codec.encode(response), StrEq(\"[\\\"pending\\\",\\\"I'm lazy!\\\"]\"));\n}\n\nTEST_F(WireMessageCodecTest, handlesEmptyStepMatchesResponse) {\n    StepMatchesResponse response(std::vector<StepMatch>(0));\n    EXPECT_THAT(codec.encode(response), StrEq(\"[\\\"success\\\",[]]\"));\n}\n\nTEST_F(WireMessageCodecTest, handlesStepMatchesResponse) {\n    std::vector<StepMatch> matches;\n    StepMatch sm1;\n    sm1.id = \"1234\";\n    sm1.source = \"MyClass.cpp:56\";\n    sm1.regexp = \"Some (.*) regexp\";\n    matches.push_back(sm1);\n    StepMatch sm2;\n    sm2.id = \"9876\";\n    StepMatchArg sm2arg1;\n    sm2arg1.value = \"odd\";\n    sm2arg1.position = 5;\n    sm2.args.push_back(sm2arg1);\n    matches.push_back(sm2);\n    StepMatchesResponse response(matches);\n\n    // clang-format off\n    EXPECT_THAT(codec.encode(response), StrEq(\n        \"[\\\"success\\\",[{\"\n            \"\\\"args\\\":[],\"\n            \"\\\"id\\\":\\\"1234\\\",\"\n            \"\\\"regexp\\\":\\\"Some (.*) regexp\\\",\"\n            \"\\\"source\\\":\\\"MyClass.cpp:56\\\"\"\n        \"},{\"\n            \"\\\"args\\\":[{\"\n                \"\\\"pos\\\":5,\"\n                \"\\\"val\\\":\\\"odd\\\"\"\n            \"}],\"\n            \"\\\"id\\\":\\\"9876\\\"\"\n        \"}]]\")\n    );\n    // clang-format on\n}\n\nTEST_F(WireMessageCodecTest, handlesSnippetTextResponse) {\n    SnippetTextResponse response(\"GIVEN(...)\");\n    EXPECT_THAT(codec.encode(response), StrEq(\"[\\\"success\\\",\\\"GIVEN(...)\\\"]\"));\n}\n\nTEST_F(WireMessageCodecTest, encodesResponseUsingRawUtf8) {\n    std::vector<StepMatch> matches;\n    StepMatch sm1;\n    sm1.id = \"1234\";\n    sm1.regexp = \"Some (.+) regexp (.+)\";\n    StepMatchArg sm1arg1;\n    sm1arg1.value = \"カラオケ機\";\n    sm1arg1.position = 5;\n    sm1.args.push_back(sm1arg1);\n    StepMatchArg sm1arg2;\n    sm1arg2.value = \"ASCII\";\n    sm1arg2.position = 18;\n    sm1.args.push_back(sm1arg2);\n    matches.push_back(sm1);\n    StepMatchesResponse response(matches);\n\n    // clang-format off\n    EXPECT_THAT(codec.encode(response), StrEq(\n        \"[\\\"success\\\",[{\"\n            \"\\\"args\\\":[{\"\n                \"\\\"pos\\\":5,\"\n                \"\\\"val\\\":\\\"カラオケ機\\\"\"\n            \"},{\"\n                \"\\\"pos\\\":18,\"\n                \"\\\"val\\\":\\\"ASCII\\\"\"\n            \"}],\"\n            \"\\\"id\\\":\\\"1234\\\",\"\n            \"\\\"regexp\\\":\\\"Some (.+) regexp (.+)\\\"\"\n        \"}]]\"));\n    // clang-format on\n}\n\n/*\n * Command response\n */\n\nTEST(WireCommandsTest, succesfulInvokeReturnsSuccess) {\n    MockCukeEngine engine;\n    InvokeCommand invokeCommand(\n        \"x\", CukeEngine::invoke_args_type(), CukeEngine::invoke_table_type()\n    );\n    EXPECT_CALL(engine, invokeStep(_, _, _)).Times(1);\n\n    std::shared_ptr<const WireResponse> response(invokeCommand.run(engine));\n    EXPECT_PTRTYPE(SuccessResponse, response.get());\n}\n\nTEST(WireCommandsTest, throwingFailureInvokeReturnsFailure) {\n    MockCukeEngine engine;\n    InvokeCommand invokeCommand(\n        \"x\", CukeEngine::invoke_args_type(), CukeEngine::invoke_table_type()\n    );\n    EXPECT_CALL(engine, invokeStep(_, _, _))\n        .Times(1)\n        .WillOnce(Throw(InvokeFailureException(\"A\", \"B\")));\n\n    std::shared_ptr<const WireResponse> response(invokeCommand.run(engine));\n    EXPECT_PTRTYPE(FailureResponse, response.get());\n    // TODO Test A and B\n}\n\nTEST(WireCommandsTest, throwingPendingStepReturnsPending) {\n    MockCukeEngine engine;\n    InvokeCommand invokeCommand(\n        \"x\", CukeEngine::invoke_args_type(), CukeEngine::invoke_table_type()\n    );\n    EXPECT_CALL(engine, invokeStep(_, _, _)).Times(1).WillOnce(Throw(PendingStepException(\"S\")));\n\n    std::shared_ptr<const WireResponse> response(invokeCommand.run(engine));\n    EXPECT_PTRTYPE(PendingResponse, response.get());\n    // TODO Test S\n}\n\nTEST(WireCommandsTest, throwingAnythingInvokeReturnsFailure) {\n    MockCukeEngine engine;\n    InvokeCommand invokeCommand(\n        \"x\", CukeEngine::invoke_args_type(), CukeEngine::invoke_table_type()\n    );\n    EXPECT_CALL(engine, invokeStep(_, _, _)).Times(1).WillOnce(Throw(string(\"something\")));\n\n    std::shared_ptr<const WireResponse> response(invokeCommand.run(engine));\n    EXPECT_PTRTYPE(FailureResponse, response.get());\n    // TODO Test empty\n}\n"
  },
  {
    "path": "tests/integration/WireServerTest.cpp",
    "content": "#include <cucumber-cpp/internal/connectors/wire/WireServer.hpp>\n\n#include <gmock/gmock.h>\n\n#include <filesystem>\n#include <memory>\n#include <random>\n#include <thread>\n#include <chrono>\n\n#include <stdlib.h>\n#include <sstream>\n\nusing namespace cucumber::internal;\nusing namespace testing;\n\nstatic const auto THREAD_TEST_TIMEOUT = std::chrono::milliseconds(4000);\n\nMATCHER(IsConnected, std::string(negation ? \"is not\" : \"is\") + \" connected\") {\n    return arg.good();\n}\n\nMATCHER(HasTerminated, \"\") {\n    return !arg.joinable();\n}\n\nMATCHER(EventuallyTerminates, \"\") {\n    const std::future_status status = arg.wait_for(THREAD_TEST_TIMEOUT);\n    return status == std::future_status::ready;\n}\n\nMATCHER_P(EventuallyReceives, value, \"\") {\n    std::basic_iostream<char>* stream\n        = const_cast<std::basic_iostream<char>*>(static_cast<const std::basic_iostream<char>*>(&arg)\n        );\n    std::string output;\n    // FIXME It should not block\n    (*stream) >> output;\n    //    boost::timer timer;\n    //    double timeout = THREAD_TEST_TIMEOUT.total_milliseconds() / 1000.0;\n    //    while (timer.elapsed() < timeout) {\n    //        if (stream->rdbuf()->available() > 0) { // it is zero even if it doesn't block!\n    //            (*stream) >> output;\n    //            break;\n    //        }\n    //        boost::this_thread::yield();\n    //    }\n    return (output == value);\n}\n\nclass MockProtocolHandler : public ProtocolHandler {\npublic:\n    MOCK_METHOD(std::string, handle, (const std::string& request), (const, override));\n};\n\nclass SocketServerTest : public Test {\n\nprotected:\n    StrictMock<MockProtocolHandler> protocolHandler;\n    std::future<void> serverThread{};\n\n    void SetUp() override {\n        SocketServer* server = createListeningServer();\n        serverThread = std::async(std::launch::async, &SocketServer::acceptOnce, server);\n    }\n\n    void TearDown() override {\n        serverThread.wait_for(THREAD_TEST_TIMEOUT);\n        destroyListeningServer();\n    }\n\n    virtual SocketServer* createListeningServer() = 0;\n    virtual void destroyListeningServer() = 0;\n};\n\nclass TCPSocketServerTest : public SocketServerTest {\nprotected:\n    std::unique_ptr<TCPSocketServer> server;\n\n    SocketServer* createListeningServer() override {\n        server.reset(new TCPSocketServer(&protocolHandler));\n        server->listen(0);\n        return server.get();\n    }\n\n    void destroyListeningServer() override {\n        server.reset();\n    }\n};\n\nTEST_F(TCPSocketServerTest, exitsOnFirstConnectionClosed) {\n    // given\n    asio::ip::tcp::iostream client(server->listenEndpoint());\n    ASSERT_THAT(client, IsConnected());\n    ASSERT_THAT(server->listenEndpoint().address().to_string(), std::string(\"0.0.0.0\"));\n\n    // when\n    client.close();\n\n    // then\n    EXPECT_THAT(serverThread, EventuallyTerminates());\n}\n\nTEST_F(TCPSocketServerTest, moreThanOneClientCanConnect) {\n    // given\n    asio::ip::tcp::iostream client1(server->listenEndpoint());\n    ASSERT_THAT(client1, IsConnected());\n\n    // when\n    asio::ip::tcp::iostream client2(server->listenEndpoint());\n\n    // then\n    ASSERT_THAT(client2, IsConnected());\n}\n\nTEST_F(TCPSocketServerTest, receiveAndSendsSingleLineMassages) {\n    {\n        InSequence s;\n        EXPECT_CALL(protocolHandler, handle(\"12\")).WillRepeatedly(Return(\"A\"));\n        EXPECT_CALL(protocolHandler, handle(\"3\")).WillRepeatedly(Return(\"B\"));\n        EXPECT_CALL(protocolHandler, handle(\"4\")).WillRepeatedly(Return(\"C\"));\n    }\n\n    // given\n    asio::ip::tcp::iostream client(server->listenEndpoint());\n    ASSERT_THAT(client, IsConnected());\n\n    // when\n    client << \"1\" << std::flush << \"2\" << std::endl << std::flush;\n    client << \"3\" << std::endl << \"4\" << std::endl << std::flush;\n\n    // then\n    EXPECT_THAT(client, EventuallyReceives(\"A\"));\n    EXPECT_THAT(client, EventuallyReceives(\"B\"));\n    EXPECT_THAT(client, EventuallyReceives(\"C\"));\n}\n\nclass TCPSocketServerLocalhostTest : public SocketServerTest {\nprotected:\n    std::unique_ptr<TCPSocketServer> server;\n\n    SocketServer* createListeningServer() override {\n        server.reset(new TCPSocketServer(&protocolHandler));\n        server->listen(asio::ip::tcp::endpoint(asio::ip::make_address(\"127.0.0.1\"), 0));\n        return server.get();\n    }\n\n    void destroyListeningServer() override {\n        server.reset();\n    }\n};\n\nTEST_F(TCPSocketServerLocalhostTest, listensOnLocalhost) {\n    // given\n    asio::ip::tcp::iostream client(server->listenEndpoint());\n    ASSERT_THAT(client, IsConnected());\n    ASSERT_THAT(server->listenEndpoint().address().to_string(), std::string(\"127.0.0.1\"));\n\n    // when\n    client.close();\n\n    // then\n    EXPECT_THAT(serverThread, EventuallyTerminates());\n}\n\n#if defined(ASIO_HAS_LOCAL_SOCKETS)\nclass UnixSocketServerTest : public SocketServerTest {\nprotected:\n    std::unique_ptr<UnixSocketServer> server;\n\n    SocketServer* createListeningServer() override {\n        const std::string filename = std::filesystem::temp_directory_path() / randomString();\n        server.reset(new UnixSocketServer(&protocolHandler));\n        server->listen(filename);\n        return server.get();\n    }\n\n    void destroyListeningServer() override {\n        server.reset();\n    }\n\nprivate:\n    std::random_device rd{};\n    std::mt19937 gen{rd()};\n    std::uniform_int_distribution<> distrib{0, 15};\n\n    std::string randomString() {\n        std::stringstream out{};\n        for (std::size_t i = 0; i < 16; i++)\n            out << std::hex << distrib(gen);\n        return out.str();\n    }\n};\n\n/*\n * Tests are flickering on OSX when testing without traffic flowing.\n *\n * This full lifecycle test is not optimal but it should be enough\n * given that the main difference between Unix and TCP is the socket\n * created at startup and removed on shutdown.\n */\nTEST_F(UnixSocketServerTest, fullLifecycle) {\n    asio::local::stream_protocol::endpoint socketName = server->listenEndpoint();\n    EXPECT_CALL(protocolHandler, handle(\"X\")).WillRepeatedly(Return(\"Y\"));\n\n    // socket created at startup\n    ASSERT_TRUE(std::filesystem::exists(socketName.path()));\n\n    // traffic flows\n    asio::local::stream_protocol::iostream client(socketName);\n    client << \"X\" << std::endl << std::flush;\n    EXPECT_THAT(client, EventuallyReceives(\"Y\"));\n\n    // client disconnection terminates server\n    client.close();\n    EXPECT_THAT(serverThread, EventuallyTerminates());\n\n    // socket removed by destructor\n    TearDown();\n    EXPECT_FALSE(std::filesystem::exists(socketName.path()));\n}\n#endif\n"
  },
  {
    "path": "tests/integration/drivers/BoostDriverTest.cpp",
    "content": "#include <boost/version.hpp>\n#include <boost/test/unit_test.hpp>\n#include <cucumber-cpp/autodetect.hpp>\n\n#include \"utils/DriverTestRunner.hpp\"\n\nusing namespace cucumber;\n\nTHEN(SUCCEED_MATCHER) {\n    ScenarioScope<SomeContext> ctx;\n    BOOST_CHECK(true);\n}\n\nTHEN(FAIL_MATCHER) {\n    ScenarioScope<SomeContext> ctx;\n    BOOST_CHECK(false);\n}\n\nTHEN(PENDING_MATCHER_1) {\n    pending();\n}\n\nTHEN(PENDING_MATCHER_2) {\n    pending(PENDING_DESCRIPTION);\n}\n\nusing namespace cucumber::internal;\n\nnamespace boost {\nnamespace unit_test {\nnamespace framework {\nbool is_initialized() {\n    return boost::unit_test::framework::master_test_suite().argc > 0;\n}\n}\n}\n}\n\nclass BoostStepDouble : public BoostStep {\npublic:\n    const InvokeResult invokeStepBody() override {\n        return BoostStep::invokeStepBody();\n    };\n\n    void body() override{};\n};\n\nclass BoostDriverTest : public DriverTest {\npublic:\n    void runAllTests() override {\n        stepInvocationInitsBoostTest();\n        DriverTest::runAllTests();\n    }\n\nprivate:\n    void stepInvocationInitsBoostTest() {\n        std::cout << \"= Init =\" << std::endl;\n        using namespace boost::unit_test;\n        BoostStepDouble step;\n        expectFalse(\n            \"Framework is not initialized before the first test\", framework::is_initialized()\n        );\n        step.invokeStepBody();\n        expectTrue(\"Framework is initialized after the first test\", framework::is_initialized());\n    }\n};\n\nint main() {\n    BoostDriverTest test;\n    return test.run();\n}\n"
  },
  {
    "path": "tests/integration/drivers/GTestDriverTest.cpp",
    "content": "#include <gtest/gtest.h>\n#include <cucumber-cpp/autodetect.hpp>\n\n#include \"utils/DriverTestRunner.hpp\"\n\nusing namespace cucumber;\n\nTHEN(SUCCEED_MATCHER) {\n    ScenarioScope<SomeContext> ctx;\n    ASSERT_TRUE(true);\n}\n\nTHEN(FAIL_MATCHER) {\n    ScenarioScope<SomeContext> ctx;\n    ASSERT_TRUE(false);\n}\n\nTHEN(PENDING_MATCHER_1) {\n    pending();\n}\n\nTHEN(PENDING_MATCHER_2) {\n    pending(PENDING_DESCRIPTION);\n}\n\nusing namespace cucumber::internal;\n\nclass GTestStepDouble : public GTestStep {\npublic:\n    bool isInitialized() {\n        return GTestStep::initialized;\n    }\n\n    const InvokeResult invokeStepBody() override {\n        return GTestStep::invokeStepBody();\n    };\n\n    void body() override{};\n};\n\nclass GTestDriverTest : public DriverTest {\npublic:\n    void runAllTests() override {\n        stepInvocationInitsGTest();\n        DriverTest::runAllTests();\n    }\n\nprivate:\n    void stepInvocationInitsGTest() {\n        std::cout << \"= Init =\" << std::endl;\n        GTestStepDouble framework;\n        expectFalse(\n            \"Framework is not initialized before the first test\", framework.isInitialized()\n        );\n        framework.invokeStepBody();\n        expectTrue(\"Framework is initialized after the first test\", framework.isInitialized());\n    }\n};\n\nint main() {\n    GTestDriverTest test;\n    return test.run();\n}\n"
  },
  {
    "path": "tests/integration/drivers/GenericDriverTest.cpp",
    "content": "#include <cucumber-cpp/generic.hpp>\n\n#include \"utils/DriverTestRunner.hpp\"\n\nusing namespace cucumber;\n\nTHEN(SUCCEED_MATCHER) {\n    ScenarioScope<SomeContext> ctx;\n    // Do not throw for successes\n}\n\nTHEN(FAIL_MATCHER) {\n    ScenarioScope<SomeContext> ctx;\n    throw std::runtime_error(\"Failure description\");\n}\n\nTHEN(PENDING_MATCHER_1) {\n    pending();\n}\n\nTHEN(PENDING_MATCHER_2) {\n    pending(PENDING_DESCRIPTION);\n}\n\nusing namespace cucumber::internal;\n\nint main() {\n    return DriverTest().run();\n}\n"
  },
  {
    "path": "tests/integration/drivers/QtTestDriverTest.cpp",
    "content": "#include <QtTest>\n#include <cucumber-cpp/autodetect.hpp>\n\n#include \"utils/DriverTestRunner.hpp\"\n\nusing namespace cucumber;\n\nTHEN(SUCCEED_MATCHER) {\n    ScenarioScope<SomeContext> ctx;\n    QVERIFY(true);\n}\n\nTHEN(FAIL_MATCHER) {\n    ScenarioScope<SomeContext> ctx;\n    QVERIFY(false);\n}\n\nTHEN(PENDING_MATCHER_1) {\n    pending();\n}\n\nTHEN(PENDING_MATCHER_2) {\n    pending(PENDING_DESCRIPTION);\n}\n\nusing namespace cucumber::internal;\n\nclass QtTestStepDouble : public QtTestStep {\npublic:\n    QtTestStepDouble() :\n        QtTestStep(),\n        testRun(false) {\n    }\n\n    const InvokeResult invokeStepBody() override {\n        return QtTestStep::invokeStepBody();\n    }\n\n    void body() override {\n        testRun = true;\n    }\n\n    bool testRun;\n};\n\nclass QtTestDriverTest : public DriverTest {\npublic:\n    void runAllTests() override {\n        stepInvocationRunsStepBody();\n        DriverTest::runAllTests();\n    }\n\nprivate:\n    void stepInvocationRunsStepBody() {\n        QtTestStepDouble framework;\n        expectFalse(\"The test body has not been run\", framework.testRun);\n        framework.invokeStepBody();\n        expectTrue(\"The test body has been run\", framework.testRun);\n    }\n};\n\nint main() {\n    QtTestDriverTest test;\n    return test.run();\n}\n"
  },
  {
    "path": "tests/unit/BasicStepTest.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <cucumber-cpp/internal/drivers/GenericDriver.hpp>\n\nusing namespace cucumber::internal;\n\n#define PENDING_STEP_DESCRIPTION \"A description\"\n\nclass PendingStep : public GenericStep {\n    void body() override {\n        pending();\n    }\n};\n\nclass PendingStepWithDescription : public GenericStep {\n    void body() override {\n        pending(PENDING_STEP_DESCRIPTION);\n    }\n};\n\nstatic const InvokeArgs NO_INVOKE_ARGS;\n\nTEST(BasicStepTest, handlesPendingSteps) {\n    PendingStep pendingStep;\n    PendingStepWithDescription pendingStepWithDescription;\n    InvokeResult result;\n\n    result = pendingStep.invoke(&NO_INVOKE_ARGS);\n    ASSERT_TRUE(result.isPending());\n    ASSERT_STREQ(\"\", result.getDescription().c_str());\n\n    result = pendingStepWithDescription.invoke(&NO_INVOKE_ARGS);\n    ASSERT_TRUE(result.isPending());\n    ASSERT_STREQ(PENDING_STEP_DESCRIPTION, result.getDescription().c_str());\n}\n"
  },
  {
    "path": "tests/unit/ContextManagerTest.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"utils/ContextManagerTestDouble.hpp\"\n\n#include <memory>\n\nusing namespace cucumber::internal;\n\nclass ContextManagerTest : public ::testing::Test {\npublic:\n    ContextManagerTestDouble contextManager;\n\n    ContextManagerTest() :\n        contextManager() {\n    }\n\nprotected:\nprivate:\n    void TearDown() override {\n        contextManager.purgeContexts();\n    }\n};\n\nclass Context1 {};\nclass Context2 {};\n\nTEST_F(ContextManagerTest, createsValidContextPointers) {\n    std::weak_ptr<Context1> ctx1 = contextManager.addContext<Context1>();\n    ASSERT_EQ(1, contextManager.countContexts());\n    ASSERT_FALSE(ctx1.expired());\n    std::weak_ptr<Context2> ctx2 = contextManager.addContext<Context2>();\n    ASSERT_EQ(2, contextManager.countContexts());\n    ASSERT_FALSE(ctx2.expired());\n}\n\nTEST_F(ContextManagerTest, allowsCreatingTheSameContextTypeTwice) {\n    std::weak_ptr<Context1> ctx1 = contextManager.addContext<Context1>();\n    ASSERT_EQ(1, contextManager.countContexts());\n    ASSERT_FALSE(ctx1.expired());\n    std::weak_ptr<Context1> ctx2 = contextManager.addContext<Context1>();\n    ASSERT_EQ(2, contextManager.countContexts());\n    ASSERT_FALSE(ctx2.expired());\n    ASSERT_NE(ctx1.lock(), ctx2.lock());\n}\n\nTEST_F(ContextManagerTest, purgesContexts) {\n    std::weak_ptr<Context1> ctx1 = contextManager.addContext<Context1>();\n    ASSERT_EQ(1, contextManager.countContexts());\n    ASSERT_FALSE(ctx1.expired());\n    contextManager.purgeContexts();\n    ASSERT_EQ(0, contextManager.countContexts());\n    ASSERT_TRUE(ctx1.expired());\n}\n"
  },
  {
    "path": "tests/unit/CukeCommandsTest.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <cucumber-cpp/internal/step/StepMacros.hpp>\n#include \"utils/CukeCommandsFixture.hpp\"\n\nusing namespace cucumber::internal;\n\nusing std::string;\n\nclass CukeCommandsTest : public CukeCommandsFixture {\nprotected:\n    void addStepWithMatcher(const std::string& matcher) {\n        addStepToManager<EmptyStep>(matcher);\n    }\n};\n\nclass CheckAllParameters : public GenericStep {\nprotected:\n    static const int arg_0_int;\n    static const double arg_1_double;\n    static const string arg_2_string;\n    static const string arg_3_string_with_spaces;\n\npublic:\n    static InvokeArgs buildInvokeArgs() {\n        InvokeArgs mixedArgs;\n        mixedArgs.addArg(toString(arg_0_int));\n        mixedArgs.addArg(toString(arg_1_double));\n        mixedArgs.addArg(toString(arg_2_string));\n        mixedArgs.addArg(toString(arg_3_string_with_spaces));\n        return mixedArgs;\n    }\n};\n\nconst int CheckAllParameters::arg_0_int(42);\nconst double CheckAllParameters::arg_1_double(4.2);\nconst string CheckAllParameters::arg_2_string(\"fortytwo\");\nconst string CheckAllParameters::arg_3_string_with_spaces(\"forty two\");\n\nclass CheckAllParametersWithoutMacro : public CheckAllParameters {\npublic:\n    void body() override {\n        EXPECT_EQ(arg_0_int, getArgs()->getInvokeArg<int>(0));\n        EXPECT_EQ((double)arg_0_int, getArgs()->getInvokeArg<double>(0));\n        EXPECT_NO_THROW(getArgs()->getInvokeArg<string>(0));\n\n        EXPECT_EQ((int)arg_1_double, getArgs()->getInvokeArg<int>(1));\n        EXPECT_EQ(arg_1_double, getArgs()->getInvokeArg<double>(1));\n        EXPECT_NO_THROW(getArgs()->getInvokeArg<string>(1));\n\n        EXPECT_THROW(getArgs()->getInvokeArg<int>(2), std::invalid_argument);\n        EXPECT_THROW(getArgs()->getInvokeArg<double>(2), std::invalid_argument);\n        EXPECT_EQ(arg_2_string, getArgs()->getInvokeArg<string>(2));\n\n        EXPECT_THROW(getArgs()->getInvokeArg<int>(3), std::invalid_argument);\n        EXPECT_THROW(getArgs()->getInvokeArg<double>(3), std::invalid_argument);\n        EXPECT_EQ(arg_3_string_with_spaces, getArgs()->getInvokeArg<string>(3));\n    }\n};\n\nclass CheckAllParametersWithMacro : public CheckAllParameters {\npublic:\n    void body() override {\n        REGEX_PARAM(int, got_arg_0_int);\n        EXPECT_EQ(arg_0_int, got_arg_0_int);\n\n        REGEX_PARAM(double, got_arg_1_double);\n        EXPECT_EQ(arg_1_double, got_arg_1_double);\n\n        REGEX_PARAM(string, got_arg_2_string);\n        EXPECT_EQ(arg_2_string, got_arg_2_string);\n\n        REGEX_PARAM(string, got_arg_3_string_with_spaces);\n        EXPECT_EQ(arg_3_string_with_spaces, got_arg_3_string_with_spaces);\n    }\n};\n\nclass CheckAllParametersWithFuncArgs : public CheckAllParameters {\npublic:\n    void bodyWithArgs(\n        const int got_arg_0_int,\n        const double got_arg_1_double,\n        const std::string got_arg_2_string,\n        const std::string& got_arg_3_string_with_spaces\n    ) {\n        EXPECT_EQ(arg_0_int, got_arg_0_int);\n        EXPECT_EQ(arg_1_double, got_arg_1_double);\n        EXPECT_EQ(arg_2_string, got_arg_2_string);\n        EXPECT_EQ(arg_3_string_with_spaces, got_arg_3_string_with_spaces);\n    }\n\n    void body() override {\n        return invokeWithArgs(*this, &CheckAllParametersWithFuncArgs::bodyWithArgs);\n    }\n};\n\nTEST_F(CukeCommandsTest, invokeHandlesParametersWithFuncArgs) {\n    // The real test is in TestClass::body()\n    runStepBodyTest<CheckAllParametersWithFuncArgs>();\n}\n\nTEST_F(CukeCommandsTest, matchesCorrectly) {\n    addStepWithMatcher(STATIC_MATCHER);\n    MatchResult result = stepMatches(STATIC_MATCHER);\n    EXPECT_EQ(stepId, result.getResultSet().at(0).stepInfo->id);\n}\n\nTEST_F(CukeCommandsTest, invokeHandlesParametersWithoutMacro) {\n    // The real test is in TestClass::body()\n    runStepBodyTest<CheckAllParametersWithoutMacro>();\n}\n\nTEST_F(CukeCommandsTest, invokeHandlesParametersWithMacro) {\n    // The real test is in TestClass::body()\n    runStepBodyTest<CheckAllParametersWithMacro>();\n}\n\nTEST_F(CukeCommandsTest, producesSnippetsEscapingTitle) {\n    EXPECT_EQ(\n        \"THEN(\\\"^x\\\\\\\\|y\\\\\\\"z$\\\") {\\n\"\n        \"    pending();\\n\"\n        \"}\\n\",\n        snippetText(\"then\", \"x|y\\\"z\")\n    );\n}\n\nTEST_F(CukeCommandsTest, escapesCaractersInRegexes) {\n    //  abc|()[]{}^$*+?.\\def  <=  abc\\|\\(\\)\\[\\]\\{\\}\\^\\$\\*\\+\\?\\.\\\\def\n    EXPECT_EQ(\n        \"abc\\\\|\\\\(\\\\)\\\\[\\\\]\\\\{\\\\}\\\\^\\\\$\\\\*\\\\+\\\\?\\\\.\\\\\\\\def\", escapeRegex(\"abc|()[]{}^$*+?.\\\\def\")\n    );\n}\n\nTEST_F(CukeCommandsTest, escapesCharactersInCStrings) {\n    //  abc\\\"def\\\\ghi  <=  abc\"def\\ghi\n    EXPECT_EQ(\"abc\\\\\\\"def\\\\\\\\ghi\", escapeCString(\"abc\\\"def\\\\ghi\"));\n}\n"
  },
  {
    "path": "tests/unit/RegexTest.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <cucumber-cpp/internal/utils/Regex.hpp>\nusing namespace cucumber::internal;\n\n#include <memory>\n\nTEST(RegexTest, matchesSimpleRegex) {\n    Regex exact(\"^cde$\");\n\n    std::shared_ptr<RegexMatch> match(exact.find(\"cde\"));\n    EXPECT_TRUE(match->matches());\n    EXPECT_TRUE(match->getSubmatches().empty());\n\n    match = std::shared_ptr<RegexMatch>(exact.find(\"abcdefg\"));\n    EXPECT_FALSE(match->matches());\n    EXPECT_TRUE(match->getSubmatches().empty());\n}\n\nTEST(RegexTest, matchesRegexWithoutSubmatches) {\n    Regex variable(\"x\\\\d+x\");\n\n    std::shared_ptr<RegexMatch> match(variable.find(\"xxxx123xxx\"));\n    EXPECT_TRUE(match->matches());\n\n    match = std::shared_ptr<RegexMatch>(variable.find(\"xxx\"));\n    EXPECT_FALSE(match->matches());\n}\n\nTEST(RegexTest, matchesRegexWithSubmatches) {\n    Regex sum(\"^(\\\\d+)\\\\+\\\\d+=(\\\\d+)$\");\n\n    std::shared_ptr<RegexMatch> match(sum.find(\"1+2=3 \"));\n    EXPECT_FALSE(match->matches());\n    EXPECT_TRUE(match->getSubmatches().empty());\n\n    match = std::shared_ptr<RegexMatch>(sum.find(\"42+27=69\"));\n    EXPECT_TRUE(match->matches());\n    ASSERT_EQ(2, match->getSubmatches().size());\n    EXPECT_EQ(\"42\", match->getSubmatches()[0].value);\n    EXPECT_EQ(\"69\", match->getSubmatches()[1].value);\n}\n\nTEST(RegexTest, matchesRegexWithOptionalSubmatches) {\n    Regex sum(\"^(\\\\d+)\\\\+(\\\\d+)(?:\\\\+(\\\\d+))?=(\\\\d+)$\");\n\n    std::shared_ptr<RegexMatch> match(sum.find(\"1+2+3=6\"));\n    EXPECT_TRUE(match->matches());\n    ASSERT_EQ(4, match->getSubmatches().size());\n\n    match = std::shared_ptr<RegexMatch>(sum.find(\"42+27=69\"));\n    EXPECT_TRUE(match->matches());\n    ASSERT_EQ(4, match->getSubmatches().size());\n    EXPECT_EQ(\"42\", match->getSubmatches()[0].value);\n    EXPECT_EQ(\"27\", match->getSubmatches()[1].value);\n    EXPECT_EQ(\"\", match->getSubmatches()[2].value);\n    EXPECT_EQ(\"69\", match->getSubmatches()[3].value);\n}\n\nTEST(RegexTest, findAllDoesNotMatchIfNoTokens) {\n    Regex sum(\"([^,]+)(?:,|$)\");\n    std::shared_ptr<RegexMatch> match(sum.findAll(\"\"));\n\n    EXPECT_FALSE(match->matches());\n    EXPECT_EQ(0, match->getSubmatches().size());\n}\n\nTEST(RegexTest, findReportsCodepointPositions) {\n    Regex twoArgs(\"Some (.+) regexp (.+)\");\n    std::shared_ptr<RegexMatch> match(twoArgs.find(\"Some カラオケ機 regexp ASCII\"));\n\n    EXPECT_TRUE(match->matches());\n    ASSERT_EQ(2, match->getSubmatches().size());\n    EXPECT_EQ(5, match->getSubmatches()[0].position);\n    EXPECT_EQ(18, match->getSubmatches()[1].position);\n}\n\nTEST(RegexTest, findAllExtractsTheFirstGroupOfEveryToken) {\n    Regex sum(\"([^,]+)(?:,|$)\");\n    std::shared_ptr<RegexMatch> match(sum.findAll(\"a,b,cc\"));\n\n    EXPECT_TRUE(match->matches());\n    EXPECT_EQ(3, match->getSubmatches().size());\n    // EXPECT_THAT(match.getSubmatches(), ElementsAre(\"a\", \"b\", \"cc\"));\n}\n\n/*\nTEST(RegexTest, findAllHasToMatchTheEntireInput) {\n    Regex sum(\"([^,]+)(?:,|$)\");\n    std::shared_ptr<RegexMatch> match(sum.findAll(\"1 a,b,cc\"));\n\n    EXPECT_FALSE(match->matches());\n    EXPECT_EQ(0, match->getSubmatches().size());\n}\n*/\n"
  },
  {
    "path": "tests/unit/StepCallChainTest.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <cucumber-cpp/internal/hook/HookRegistrar.hpp>\n\nusing namespace cucumber::internal;\n\nclass FakeStepInfo : public StepInfo {\npublic:\n    FakeStepInfo(std::stringstream* markersPtr, const InvokeResult& result) :\n        StepInfo(\"FAKE\", \"\"),\n        latestArgsPtr(0),\n        markersPtr(markersPtr),\n        result(result) {\n    }\n\n    InvokeResult invokeStep(const InvokeArgs* pArgs) const override {\n        latestArgsPtr = pArgs;\n        (*markersPtr) << \"S\";\n        return result;\n    }\n\n    const InvokeArgs* getLatestArgsPassed() const {\n        return latestArgsPtr;\n    }\n\nprivate:\n    mutable const InvokeArgs* latestArgsPtr;\n    std::stringstream* markersPtr;\n    const InvokeResult result;\n};\n\nclass MarkingAroundStepHook : public AroundStepHook {\npublic:\n    MarkingAroundStepHook(std::string id, std::stringstream* markersPtr) :\n        id(id),\n        markersPtr(markersPtr){};\n\n    MarkingAroundStepHook() :\n        id(\"\"),\n        markersPtr(0){};\n\n    void body() override {\n        if (markersPtr) {\n            (*markersPtr) << \"B\" << id;\n        }\n        doCall();\n        if (markersPtr) {\n            (*markersPtr) << \"A\" << id;\n        }\n    }\n\nprotected:\n    virtual void doCall() {\n        step->call();\n    }\n\nprivate:\n    std::string id;\n    std::stringstream* markersPtr;\n};\n\nclass BlockingAroundStepHook : public MarkingAroundStepHook {\npublic:\n    BlockingAroundStepHook(std::string id, std::stringstream* markersPtr) :\n        MarkingAroundStepHook(id, markersPtr){};\n\nprotected:\n    void doCall() override {\n    }\n};\n\nstatic const InvokeArgs NO_INVOKE_ARGS;\n\nclass StepCallChainTest : public ::testing::Test {\nprotected:\n    HookRegistrar::aroundhook_list_type aroundHooks;\n    std::stringstream markers;\n\n    InvokeResult execStep(const InvokeResult& result) {\n        const FakeStepInfo step(&markers, result);\n        StepCallChain scc(0, &step, &NO_INVOKE_ARGS, aroundHooks);\n        return scc.exec();\n    }\n\n    void execStepAndCheckSuccess() {\n        InvokeResult result;\n        result = execStep(InvokeResult::success());\n        EXPECT_TRUE(result.isSuccess());\n        result = execStep(InvokeResult::failure(\"Failed\"));\n        EXPECT_FALSE(result.isSuccess());\n    }\n};\n\nTEST_F(StepCallChainTest, failsIfNoStep) {\n    StepCallChain scc(0, NULL, &NO_INVOKE_ARGS, aroundHooks);\n    EXPECT_FALSE(scc.exec().isSuccess());\n    EXPECT_EQ(\"\", markers.str());\n}\n\nTEST_F(StepCallChainTest, stepExecutionReturnsTheExpectedResult) {\n    std::shared_ptr<MarkingAroundStepHook> hook(std::make_shared<MarkingAroundStepHook>());\n\n    execStepAndCheckSuccess();\n\n    aroundHooks.push_back(hook);\n\n    execStepAndCheckSuccess();\n\n    aroundHooks.push_back(hook);\n    aroundHooks.push_back(hook);\n\n    execStepAndCheckSuccess();\n}\n\nTEST_F(StepCallChainTest, aroundHooksAreInvokedInTheCorrectOrder) {\n    std::shared_ptr<MarkingAroundStepHook> hook1(\n        std::make_shared<MarkingAroundStepHook>(\"1\", &markers)\n    ),\n        hook2(std::make_shared<MarkingAroundStepHook>(\"2\", &markers)),\n        hook3(std::make_shared<MarkingAroundStepHook>(\"3\", &markers));\n\n    aroundHooks.push_back(hook1);\n    aroundHooks.push_back(hook2);\n    aroundHooks.push_back(hook3);\n\n    execStep(InvokeResult::success());\n\n    EXPECT_EQ(\"B1B2B3SA3A2A1\", markers.str());\n}\n\nTEST_F(StepCallChainTest, argsArePassedToTheStep) {\n    const FakeStepInfo step(&markers, InvokeResult::success());\n    StepCallChain scc(0, &step, &NO_INVOKE_ARGS, aroundHooks);\n\n    EXPECT_NE(&NO_INVOKE_ARGS, step.getLatestArgsPassed());\n    scc.exec();\n    EXPECT_EQ(&NO_INVOKE_ARGS, step.getLatestArgsPassed());\n}\n\nTEST_F(StepCallChainTest, aroundHooksCanStopTheCallChain) {\n    std::shared_ptr<MarkingAroundStepHook> hook1(\n        std::make_shared<MarkingAroundStepHook>(\"1\", &markers)\n    ),\n        hook2(std::make_shared<BlockingAroundStepHook>(\"2\", &markers)),\n        hook3(std::make_shared<MarkingAroundStepHook>(\"3\", &markers));\n\n    aroundHooks.push_back(hook1);\n    aroundHooks.push_back(hook2);\n    aroundHooks.push_back(hook3);\n\n    execStep(InvokeResult::success());\n\n    EXPECT_EQ(\"B1B2A2A1\", markers.str());\n}\n"
  },
  {
    "path": "tests/unit/StepManagerTest.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"utils/StepManagerTestDouble.hpp\"\n\n#include <map>\n\nusing namespace std;\nusing namespace cucumber::internal;\n\nclass StepManagerTest : public ::testing::Test {\npublic:\n    typedef StepManagerTestDouble StepManager;\n\nprotected:\n    StepManagerTest() {\n    }\n    const static char* a_matcher;\n    const static char* another_matcher;\n    const static char* no_match;\n    const static char* a_third_matcher;\n    const map<std::ptrdiff_t, string> no_params;\n\n    int getUniqueMatchIdOrZeroFor(const string& stepMatch) {\n        MatchResult::match_results_type resultSet = getResultSetFor(stepMatch);\n        if (resultSet.size() != 1) {\n            return 0;\n        } else {\n            return resultSet.begin()->stepInfo->id;\n        }\n    }\n\n    size_t countMatches(const string& stepMatch) {\n        return getResultSetFor(stepMatch).size();\n    }\n\n    bool matchesOnce(const string& stepMatch) {\n        return (countMatches(stepMatch) == 1);\n    }\n\n    bool matchesAtLeastOnce(const string& stepMatch) {\n        return (countMatches(stepMatch) > 0);\n    }\n\n    bool extractedParamsAre(const string stepMatch, map<std::ptrdiff_t, string> params) {\n        MatchResult::match_results_type resultSet = getResultSetFor(stepMatch);\n        if (resultSet.size() != 1) {\n            return false; // more than one match\n        }\n        SingleStepMatch match = resultSet.front();\n        if (params.size() != match.submatches.size()) {\n            return false;\n        }\n        SingleStepMatch::submatches_type::const_iterator rsi;\n        for (rsi = match.submatches.begin(); rsi != match.submatches.end(); ++rsi) {\n            if (params.find(rsi->position) == params.end())\n                return false;\n            if (rsi->value != params[rsi->position]) {\n                return false;\n            }\n        }\n        return true;\n    }\n\nprivate:\n    MatchResult::match_results_type getResultSetFor(const string& stepMatch) {\n        return StepManager::stepMatches(stepMatch).getResultSet();\n    }\n    void TearDown() override {\n        StepManager::clearSteps();\n    }\n};\n\nconst char* StepManagerTest::a_matcher = \"a matcher\";\nconst char* StepManagerTest::another_matcher = \"another matcher\";\nconst char* StepManagerTest::a_third_matcher = \"a third matcher\";\nconst char* StepManagerTest::no_match = \"no match\";\n\nTEST_F(StepManagerTest, holdsNonConflictingSteps) {\n    ASSERT_EQ(0, StepManager::count());\n    StepManager::addStepDefinition(a_matcher);\n    StepManager::addStepDefinition(another_matcher);\n    StepManager::addStepDefinition(a_third_matcher);\n    ASSERT_EQ(3, StepManager::count());\n}\n\nTEST_F(StepManagerTest, holdsConflictingSteps) {\n    ASSERT_EQ(0, StepManager::count());\n    StepManager::addStepDefinition(a_matcher);\n    StepManager::addStepDefinition(a_matcher);\n    StepManager::addStepDefinition(a_matcher);\n    ASSERT_EQ(3, StepManager::count());\n}\n\nTEST_F(StepManagerTest, matchesStepsWithNonRegExMatchers) {\n    EXPECT_FALSE(matchesAtLeastOnce(no_match));\n    step_id_type aMatcherIndex = StepManager::addStepDefinition(a_matcher);\n    EXPECT_EQ(aMatcherIndex, getUniqueMatchIdOrZeroFor(a_matcher));\n    step_id_type anotherMatcherIndex = StepManager::addStepDefinition(another_matcher);\n    EXPECT_EQ(anotherMatcherIndex, getUniqueMatchIdOrZeroFor(another_matcher));\n    EXPECT_EQ(aMatcherIndex, getUniqueMatchIdOrZeroFor(a_matcher));\n}\n\nTEST_F(StepManagerTest, matchesStepsWithRegExMatchers) {\n    StepManager::addStepDefinition(\"match the number (\\\\d+)\");\n    EXPECT_TRUE(matchesOnce(\"match the number 42\"));\n    EXPECT_FALSE(matchesOnce(\"match the number (\\\\d+)\"));\n    EXPECT_FALSE(matchesOnce(\"match the number one\"));\n}\n\nTEST_F(StepManagerTest, extractsParamsFromRegExMatchers) {\n    StepManager::addStepDefinition(\"match no params\");\n    EXPECT_TRUE(extractedParamsAre(\"match no params\", no_params));\n    StepManager::addStepDefinition(\"match the (\\\\w+) param\");\n    EXPECT_TRUE(extractedParamsAre(\"match the first param\", {{10, \"first\"}}));\n    StepManager::addStepDefinition(\"match a (.+)$\");\n    EXPECT_TRUE(\n        extractedParamsAre(\"match a  string  with  spaces  \", {{8, \" string  with  spaces  \"}})\n    );\n    StepManager::addStepDefinition(\"match params (\\\\w+), (\\\\w+) and (\\\\w+)\");\n    EXPECT_TRUE(extractedParamsAre(\"match params A, B and C\", {{13, \"A\"}, {16, \"B\"}, {22, \"C\"}}));\n}\n\nTEST_F(StepManagerTest, handlesMultipleMatches) {\n    StepManager::addStepDefinition(a_matcher);\n    StepManager::addStepDefinition(another_matcher);\n    StepManager::addStepDefinition(a_matcher);\n    EXPECT_EQ(2, countMatches(a_matcher));\n}\n\nTEST_F(StepManagerTest, matchesStepsWithNonAsciiMatchers) {\n    step_id_type aMatcherIndex = StepManager::addStepDefinition(\"خيار\");\n    EXPECT_EQ(aMatcherIndex, getUniqueMatchIdOrZeroFor(\"خيار\"));\n    EXPECT_FALSE(matchesAtLeastOnce(\"cetriolo\"));\n    EXPECT_FALSE(matchesAtLeastOnce(\"огурец\"));\n    EXPECT_FALSE(matchesAtLeastOnce(\"黄瓜\"));\n}\n"
  },
  {
    "path": "tests/unit/TableTest.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <cucumber-cpp/internal/Table.hpp>\nusing namespace cucumber::internal;\n\nTEST(TableTest, forbidsRowsNotMatchingTableColumnsSize) {\n    Table t;\n    t.addColumn(\"C1\");\n\n    EXPECT_THROW(\n        {\n            Table::row_type row;\n            t.addRow(row);\n        },\n        std::range_error\n    );\n\n    EXPECT_NO_THROW({ t.addRow({\"R1\"}); });\n\n    EXPECT_THROW({ t.addRow({\"R1\", \"R2\"}); }, std::range_error);\n}\n\nTEST(TableTest, rowsCannotBeAddedBeforeColumnsAreSet) {\n    Table t;\n\n    EXPECT_THROW(\n        {\n            Table::row_type row;\n            t.addRow(row);\n        },\n        std::runtime_error\n    );\n}\n\nTEST(TableTest, columnsCannotBeChangesAfterRowsAreAdded) {\n    Table t;\n    t.addColumn(\"C1\");\n    t.addRow({\"R1\"});\n\n    EXPECT_THROW({ t.addColumn(\"C2\"); }, std::runtime_error);\n}\n\nTEST(TableTest, addedRowsMatchColumnDefinition) {\n    Table t;\n    t.addColumn(\"C1\");\n    t.addColumn(\"C2\");\n    t.addColumn(\"C3\");\n\n    ASSERT_EQ(0, t.hashes().size());\n\n    t.addRow({\"R11\", \"R12\", \"R13\"});\n    Table::hashes_type hashes = t.hashes();\n    ASSERT_EQ(1, hashes.size());\n    EXPECT_EQ(\"R11\", hashes[0][\"C1\"]);\n    EXPECT_EQ(\"R12\", hashes[0][\"C2\"]);\n    EXPECT_EQ(\"R13\", hashes[0][\"C3\"]);\n\n    t.addRow({\"R21\", \"R22\", \"R23\"});\n    t.addRow({\"R31\", \"R32\", \"R33\"});\n    t.addRow({\"R41\", \"R42\", \"R43\"});\n    hashes = t.hashes();\n    ASSERT_EQ(4, hashes.size());\n    EXPECT_EQ(\"R21\", hashes[1][\"C1\"]);\n    EXPECT_EQ(\"R32\", hashes[2][\"C2\"]);\n    EXPECT_EQ(\"R43\", hashes[3][\"C3\"]);\n}\n"
  },
  {
    "path": "tests/unit/TagTest.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <cucumber-cpp/internal/hook/Tag.hpp>\n\nusing namespace cucumber::internal;\n\nTEST(TagTest, emptyOrExpressionMatchesNoTag) {\n    OrTagExpression tagExpr(\"\");\n    EXPECT_FALSE(tagExpr.matches({\"x\"}));\n    EXPECT_FALSE(tagExpr.matches({\"a\", \"b\"}));\n}\n\nTEST(TagTest, orExpressionsMatchTheTagSpecified) {\n    OrTagExpression tagExpr(\"@a\");\n    EXPECT_TRUE(tagExpr.matches({\"a\"}));\n    EXPECT_FALSE(tagExpr.matches({\"x\"}));\n}\n\nTEST(TagTest, orExpressionsMatchAnyTagSpecified) {\n    OrTagExpression tagExpr(\"@a,@b,@c\");\n    EXPECT_TRUE(tagExpr.matches({\"a\"}));\n    EXPECT_TRUE(tagExpr.matches({\"b\"}));\n    EXPECT_TRUE(tagExpr.matches({\"a\", \"b\"}));\n    EXPECT_TRUE(tagExpr.matches({\"a\", \"b\", \"c\"}));\n    EXPECT_TRUE(tagExpr.matches({\"x\", \"a\", \"b\"}));\n    EXPECT_TRUE(tagExpr.matches({\"a\", \"y\"}));\n    EXPECT_TRUE(tagExpr.matches({\"x\", \"b\"}));\n    EXPECT_FALSE(tagExpr.matches({\"x\", \"y\", \"z\"}));\n}\n\nTEST(TagTest, orExpressionsAllowSpaces) {\n    OrTagExpression tagExpr(\"@a, @b,@c\");\n    EXPECT_TRUE(tagExpr.matches({\"b\"}));\n    EXPECT_FALSE(tagExpr.matches({\"x\"}));\n}\n\nTEST(TagTest, emptyAndExpressionMatchesAnyTag) {\n    AndTagExpression tagExpr(\"\");\n    EXPECT_TRUE(tagExpr.matches({\"x\"}));\n    EXPECT_TRUE(tagExpr.matches({\"a\", \"b\"}));\n}\n\nTEST(TagTest, singleAndExpressionMatchesTheTagSpecified) {\n    AndTagExpression tagExpr(\"\\\"@a\\\"\");\n    EXPECT_TRUE(tagExpr.matches({\"a\"}));\n    EXPECT_FALSE(tagExpr.matches({\"x\"}));\n}\n\nTEST(TagTest, andExpressionsMatchEveryTagSpecified) {\n    AndTagExpression tagExpr(\"\\\"@a\\\",\\\"@b\\\"\");\n    EXPECT_TRUE(tagExpr.matches({\"a\", \"b\"}));\n    EXPECT_TRUE(tagExpr.matches({\"x\", \"a\", \"b\"}));\n    EXPECT_FALSE(tagExpr.matches({\"a\"}));\n    EXPECT_FALSE(tagExpr.matches({\"b\"}));\n    EXPECT_FALSE(tagExpr.matches({\"a\", \"y\"}));\n    EXPECT_FALSE(tagExpr.matches({\"x\", \"b\"}));\n    EXPECT_FALSE(tagExpr.matches({\"x\", \"y\"}));\n}\n\nTEST(TagTest, andExpressionsAllowSpaces) {\n    AndTagExpression tagExpr(\" \\\"@a\\\" , \\\"@b\\\" \");\n    EXPECT_TRUE(tagExpr.matches({\"a\", \"b\"}));\n    EXPECT_FALSE(tagExpr.matches({\"a\"}));\n}\n\nTEST(TagTest, compositeTagExpressionsAreHandled) {\n    AndTagExpression tagExpr(\"\\\"@a,@b\\\", \\\"@c\\\", \\\"@d,@e,@f\\\"\");\n    EXPECT_TRUE(tagExpr.matches({\"a\", \"c\", \"d\"}));\n    EXPECT_FALSE(tagExpr.matches({\"x\", \"c\", \"f\"}));\n}\n"
  },
  {
    "path": "tests/utils/ContextManagerTestDouble.hpp",
    "content": "#ifndef CUKE_CONTEXTMANAGERTESTDOUBLE_HPP_\n#define CUKE_CONTEXTMANAGERTESTDOUBLE_HPP_\n\n#include <cucumber-cpp/internal/ContextManager.hpp>\n\nnamespace cucumber {\nnamespace internal {\n\nclass ContextManagerTestDouble : public ContextManager {\npublic:\n    contexts_type::size_type countContexts() {\n        return ContextManager::contexts.size();\n    }\n};\n\n}\n}\n\n#endif /* CUKE_CONTEXTMANAGERTESTDOUBLE_HPP_ */\n"
  },
  {
    "path": "tests/utils/CukeCommandsFixture.hpp",
    "content": "#ifndef CUKE_CUKECOMMANDSFIXTURE_HPP_\n#define CUKE_CUKECOMMANDSFIXTURE_HPP_\n\n#include <cucumber-cpp/internal/CukeCommands.hpp>\n#include <cucumber-cpp/internal/drivers/GenericDriver.hpp>\n#include \"StepManagerTestDouble.hpp\"\n\n#include <gtest/gtest.h>\n#include <memory>\n\nusing namespace cucumber::internal;\n\nclass EmptyStep : public GenericStep {\n    void body() override {\n    }\n};\n\nclass CukeCommandsFixture : public ::testing::Test, public CukeCommands {\n    typedef StepManagerTestDouble StepManager;\n\npublic:\n    const static std::string STATIC_MATCHER;\n\nprotected:\n    step_id_type stepId;\n\n    template<class T>\n    void runStepBodyTest() {\n        addStepToManager<T>(STATIC_MATCHER);\n        const InvokeArgs spArgs(T::buildInvokeArgs());\n        invoke(stepId, &spArgs);\n    }\n\n    template<class T>\n    void addStepToManager(const std::string& matcher) {\n        stepId = StepManager::addStep(std::make_shared<StepInvoker<T>>(matcher, \"\"));\n    }\n\n    void TearDown() override {\n        StepManager::clearSteps();\n    }\n};\n\nconst std::string CukeCommandsFixture::STATIC_MATCHER(\"MATCHER\");\n\n#endif /* CUKE_CUKECOMMANDSFIXTURE_HPP_ */\n"
  },
  {
    "path": "tests/utils/DriverTestRunner.hpp",
    "content": "#ifndef CUKE_DRIVERTESTRUNNER_HPP_\n#define CUKE_DRIVERTESTRUNNER_HPP_\n\n#include \"StepManagerTestDouble.hpp\"\n#include <cucumber-cpp/internal/CukeCommands.hpp>\n\n#include <cstring>\n#include <iostream>\n#include <string>\n\nclass ContextListener {\nprivate:\n    static int createdContexts;\n    static int destroyedContexts;\n\npublic:\n    int getCreatedContexts() {\n        return createdContexts;\n    }\n    int getDestroyedContexts() {\n        return destroyedContexts;\n    }\n    void notifyCreation() {\n        ++createdContexts;\n    }\n    void notifyDestruction() {\n        ++destroyedContexts;\n    }\n    void reset() {\n        createdContexts = 0;\n        destroyedContexts = 0;\n    }\n};\n\nint ContextListener::createdContexts = 0;\nint ContextListener::destroyedContexts = 0;\n\nclass SomeContext {\nprivate:\n    ContextListener listener;\n\npublic:\n    SomeContext() {\n        listener.notifyCreation();\n    }\n    ~SomeContext() {\n        listener.notifyDestruction();\n    }\n};\n\nnamespace cucumber {\nnamespace internal {\n\nstatic const InvokeArgs NO_INVOKE_ARGS;\n\n#define SUCCEED_MATCHER \"Succeeding step\"\n#define FAIL_MATCHER \"Failing step\"\n#define PENDING_MATCHER_1 \"Pending step without description\"\n#define PENDING_MATCHER_2 \"Pending step with description\"\n\n#define PENDING_DESCRIPTION \"Describe me!\"\n\nclass DriverTest {\npublic:\n    int run() {\n        runAllTests();\n        return failedTests;\n    }\n\n    DriverTest() {\n        failedTests = 0;\n    }\n\n    virtual ~DriverTest() = default;\n\nprotected:\n    void expectTrue(const char* description, bool condition) {\n        updateState(description, condition);\n    }\n\n    void expectFalse(const char* description, bool condition) {\n        updateState(description, !condition);\n    }\n\n    template<typename T>\n    void expectEqual(const char* description, T val1, T val2) {\n        updateState(description, val1 == val2);\n    }\n\n    void expectStrEqual(const char* description, const char* val1, const char* val2) {\n        updateState(description, strcmp(val1, val2) == 0);\n    }\n\n    virtual void runAllTests() {\n        invokeRunsTests();\n        contextConstructorAndDesctructorGetCalled();\n        failureDescriptionIsResetOnEachRun();\n    }\n\n    CukeCommands cukeCommands;\n\nprivate:\n    typedef StepManagerTestDouble StepManager;\n    ContextListener listener;\n\n    int failedTests;\n\n    void updateState(const char* description, bool testSuccessState) {\n        std::cout << (testSuccessState ? \"SUCCESS\" : \"FAILURE\") << \" (\" << description << \")\"\n                  << std::endl;\n        failedTests += testSuccessState ? 0 : 1;\n    }\n\n    step_id_type getStepIdFromMatcher(const std::string& stepMatcher) {\n        return StepManager::getStepId(stepMatcher);\n    }\n\n    void invokeRunsTests() {\n        std::cout << \"= Step invocation =\" << std::endl;\n\n        InvokeResult result;\n\n        cukeCommands.beginScenario();\n\n        result = cukeCommands.invoke(getStepIdFromMatcher(SUCCEED_MATCHER), &NO_INVOKE_ARGS);\n        expectTrue(\"Succeeding step\", result.isSuccess());\n\n        result = cukeCommands.invoke(getStepIdFromMatcher(FAIL_MATCHER), &NO_INVOKE_ARGS);\n        expectFalse(\"Failing step\", result.isSuccess() || result.isPending());\n        expectFalse(\"Failing step has a message\", result.getDescription().empty());\n\n        result = cukeCommands.invoke(getStepIdFromMatcher(PENDING_MATCHER_1), &NO_INVOKE_ARGS);\n        expectTrue(\"Pending step with no description - result\", result.isPending());\n        expectStrEqual(\n            \"Pending step with no description - description\", \"\", result.getDescription().c_str()\n        );\n\n        result = cukeCommands.invoke(getStepIdFromMatcher(PENDING_MATCHER_2), &NO_INVOKE_ARGS);\n        expectTrue(\"Pending step with description - result\", result.isPending());\n        expectStrEqual(\n            \"Pending step with description - description\",\n            PENDING_DESCRIPTION,\n            result.getDescription().c_str()\n        );\n\n        result = cukeCommands.invoke(42, &NO_INVOKE_ARGS);\n        expectFalse(\"Inexistent step\", result.isSuccess());\n\n        cukeCommands.endScenario();\n    }\n\n    void contextConstructorAndDesctructorGetCalled() {\n        std::cout << \"= Constructors and destructors =\" << std::endl;\n        contextConstructorAndDesctructorGetCalledOn(SUCCEED_MATCHER);\n        contextConstructorAndDesctructorGetCalledOn(FAIL_MATCHER);\n    }\n\n    void contextConstructorAndDesctructorGetCalledOn(const std::string stepMatcher) {\n        std::cout << \"== \" << stepMatcher << \" ==\" << std::endl;\n        listener.reset();\n        cukeCommands.beginScenario();\n        cukeCommands.invoke(getStepIdFromMatcher(stepMatcher), &NO_INVOKE_ARGS);\n        expectEqual(\"Contexts created after invoke\", 1, listener.getCreatedContexts());\n        expectEqual(\"Contexts destroyed after invoke\", 0, listener.getDestroyedContexts());\n        cukeCommands.endScenario();\n        expectEqual(\"Contexts created after end scenario\", 1, listener.getCreatedContexts());\n        expectEqual(\"Contexts destroyed after end scenario\", 1, listener.getDestroyedContexts());\n    }\n\n    void failureDescriptionIsResetOnEachRun() {\n        std::cout << \"= Step failure description is reset =\" << std::endl;\n        InvokeResult result;\n        cukeCommands.beginScenario();\n\n        result = cukeCommands.invoke(getStepIdFromMatcher(FAIL_MATCHER), &NO_INVOKE_ARGS);\n        std::string failureMessage = result.getDescription();\n\n        expectFalse(\"Failing step description is set\", failureMessage.empty());\n\n        result = cukeCommands.invoke(getStepIdFromMatcher(FAIL_MATCHER), &NO_INVOKE_ARGS);\n\n        expectEqual(\n            \"Failing step description is the same\", failureMessage, result.getDescription()\n        );\n    }\n};\n\n}\n}\n\n#endif /* CUKE_DRIVERTESTRUNNER_HPP_ */\n"
  },
  {
    "path": "tests/utils/HookRegistrationFixture.hpp",
    "content": "#ifndef CUKE_HOOKREGISTRATIONFIXTURE_HPP_\n#define CUKE_HOOKREGISTRATIONFIXTURE_HPP_\n\n#include <cucumber-cpp/internal/hook/HookRegistrar.hpp>\n\n#include \"CukeCommandsFixture.hpp\"\n\n#include <memory>\n#include <sstream>\n\nusing namespace cucumber::internal;\n\nnamespace {\n\nstd::stringstream beforeHookCallMarker;\nstd::stringstream aroundStepHookCallMarker;\nstd::stringstream beforeAroundStepHookCallMarker;\nstd::stringstream afterAroundStepHookCallMarker;\nstd::stringstream afterStepHookCallMarker;\nstd::stringstream afterHookCallMarker;\nstd::stringstream globalStepHookCallMarker;\nstd::stringstream beforeAllHookCallMarker;\nstd::stringstream afterAllHookCallMarker;\nstd::string contextContents;\n\nvoid clearHookCallMarkers() {\n    beforeHookCallMarker.str(\"\");\n    beforeAroundStepHookCallMarker.str(\"\");\n    afterAroundStepHookCallMarker.str(\"\");\n    afterStepHookCallMarker.str(\"\");\n    afterHookCallMarker.str(\"\");\n    globalStepHookCallMarker.str(\"\");\n    beforeAllHookCallMarker.str(\"\");\n    afterAllHookCallMarker.str(\"\");\n    contextContents.clear();\n}\n\nstd::string getHookCallMarkers() {\n    return beforeAllHookCallMarker.str() + beforeHookCallMarker.str()\n           + beforeAroundStepHookCallMarker.str() + afterStepHookCallMarker.str()\n           + afterHookCallMarker.str() + afterAllHookCallMarker.str();\n}\n\nclass EmptyCallableStep : public CallableStep {\npublic:\n    void call() override{};\n};\n\nclass HookRegistrarDouble : public HookRegistrar {\npublic:\n    static void execAroundStepHooks(Scenario* scenario) {\n        EmptyCallableStep emptyStep;\n        aroundhook_list_type& ash = aroundStepHooks();\n        for (HookRegistrar::aroundhook_list_type::const_iterator h = ash.begin(); h != ash.end();\n             ++h) {\n            (*h)->invokeHook(scenario, &emptyStep);\n        }\n    }\n};\n\nstatic const InvokeArgs NO_INVOKE_ARGS;\n\nclass HookRegistrationTest : public CukeCommandsFixture {\nprotected:\n    std::shared_ptr<Scenario> emptyScenario;\n\n    HookRegistrationTest() {\n        emptyScenario = std::make_shared<Scenario>();\n    }\n\n    Scenario* getEmptyScenario() {\n        return emptyScenario.get();\n    }\n\n    std::string beforeHookOrder() {\n        clearHookCallMarkers();\n        HookRegistrarDouble::execBeforeHooks(getEmptyScenario());\n        return getHookCallMarkers();\n    }\n\n    std::string aroundStepHookOrder() {\n        clearHookCallMarkers();\n        HookRegistrarDouble::execAroundStepHooks(getEmptyScenario());\n        return getHookCallMarkers();\n    }\n\n    std::string afterStepHookOrder() {\n        clearHookCallMarkers();\n        HookRegistrarDouble::execAfterStepHooks(getEmptyScenario());\n        return getHookCallMarkers();\n    }\n\n    std::string afterHookOrder() {\n        clearHookCallMarkers();\n        HookRegistrarDouble::execAfterHooks(getEmptyScenario());\n        return getHookCallMarkers();\n    }\n\n    void beginScenario(const TagExpression::tag_list& tags = TagExpression::tag_list()) {\n        CukeCommandsFixture::beginScenario(tags);\n    }\n\n    void invokeStep() {\n        invoke(stepId, &NO_INVOKE_ARGS);\n    }\n\n    void endScenario() {\n        CukeCommandsFixture::endScenario();\n    }\n\n    std::string sort(std::string str) {\n        std::sort(str.begin(), str.end());\n        return str;\n    }\n\n    void SetUp() override {\n        CukeCommandsFixture::SetUp();\n        clearHookCallMarkers();\n        addStepToManager<EmptyStep>(STATIC_MATCHER);\n    }\n};\n\n}\n\n#endif /* CUKE_HOOKREGISTRATIONFIXTURE_HPP_ */\n"
  },
  {
    "path": "tests/utils/StepManagerTestDouble.hpp",
    "content": "#ifndef CUKE_STEPMANAGERTESTDOUBLE_HPP_\n#define CUKE_STEPMANAGERTESTDOUBLE_HPP_\n\n#include <cucumber-cpp/internal/step/StepManager.hpp>\n\nnamespace cucumber {\nnamespace internal {\n\nclass StepInfoNoOp : public StepInfo {\npublic:\n    StepInfoNoOp(const std::string& stepMatcher, const std::string source) :\n        StepInfo(stepMatcher, source) {\n    }\n    InvokeResult invokeStep(const InvokeArgs*) const override {\n        return InvokeResult::success();\n    }\n};\n\nclass StepInfoPending : public StepInfo {\nprivate:\n    const char* description;\n\npublic:\n    StepInfoPending(const std::string& stepMatcher, const char* description) :\n        StepInfo(stepMatcher, \"\"),\n        description(description) {\n    }\n\n    InvokeResult invokeStep(const InvokeArgs*) const override {\n        return InvokeResult::pending(description);\n    }\n};\n\n/*\n * FIXME This should be a mock testing it receives a table argument\n */\nclass StepInfoWithTableArg : public StepInfo {\n    const unsigned short expectedSize;\n\npublic:\n    StepInfoWithTableArg(const std::string& stepMatcher, const unsigned short expectedSize) :\n        StepInfo(stepMatcher, \"\"),\n        expectedSize(expectedSize) {\n    }\n\n    InvokeResult invokeStep(const InvokeArgs* pArgs) const override {\n        if (pArgs->getTableArg().hashes().size() == expectedSize) {\n            return InvokeResult::success();\n        } else {\n            return InvokeResult::failure(\"Failed\");\n        }\n    }\n};\n\nclass StepManagerTestDouble : public StepManager {\npublic:\n    static void clearSteps() {\n        steps().clear();\n    }\n\n    static steps_type::size_type count() {\n        return steps().size();\n    }\n\n    static step_id_type addStepDefinition(const std::string& stepMatcher) {\n        return addStep(std::make_shared<StepInfoNoOp>(stepMatcher, \"\"));\n    }\n\n    static step_id_type addStepDefinitionWithId(\n        step_id_type desiredId, const std::string& stepMatcher\n    ) {\n        return addStepDefinitionWithId(desiredId, stepMatcher, \"\");\n    }\n\n    static step_id_type addStepDefinitionWithId(\n        step_id_type desiredId, const std::string& stepMatcher, const std::string source\n    ) {\n        std::shared_ptr<StepInfo> stepInfo(std::make_shared<StepInfoNoOp>(stepMatcher, source));\n        stepInfo->id = desiredId;\n        return addStep(stepInfo);\n    }\n\n    static step_id_type addPendingStepDefinitionWithId(\n        step_id_type desiredId, const std::string& stepMatcher\n    ) {\n        return addPendingStepDefinitionWithId(desiredId, stepMatcher, 0);\n    }\n\n    static step_id_type addPendingStepDefinitionWithId(\n        step_id_type desiredId, const std::string& stepMatcher, const char* description\n    ) {\n        std::shared_ptr<StepInfo> stepInfo(\n            std::make_shared<StepInfoPending>(stepMatcher, description)\n        );\n        stepInfo->id = desiredId;\n        return addStep(stepInfo);\n    }\n\n    static step_id_type addTableStepDefinitionWithId(\n        step_id_type desiredId, const std::string& stepMatcher, const unsigned short expectedSize\n    ) {\n        std::shared_ptr<StepInfo> stepInfo(\n            std::make_shared<StepInfoWithTableArg>(stepMatcher, expectedSize)\n        );\n        stepInfo->id = desiredId;\n        return addStep(stepInfo);\n    }\n\n    static step_id_type getStepId(const std::string& stepMatcher) {\n        step_id_type id = 0;\n        for (steps_type::const_iterator i = steps().begin(); i != steps().end(); ++i) {\n            const StepInfo& stepInfo = *i->second;\n            if (stepInfo.regex.str() == stepMatcher) {\n                id = stepInfo.id;\n                break;\n            }\n        }\n        return id;\n    }\n};\n\n}\n}\n\n#endif /* CUKE_STEPMANAGERTESTDOUBLE_HPP_ */\n"
  }
]