diff --git a/.github/renovate.json b/.github/renovate.json index 782e40af..a0a39bb2 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -3,5 +3,17 @@ "extends": [ "github>cucumber/renovate-config", "github>cucumber/renovate-config:messages-range-strategy-widen" + ], + "customManagers": [ + { + "customType": "regex", + "description": "Update pinned commits of cucumber C++ dependencies in workflow env vars (annotated with a renovate comment).", + "managerFilePatterns": [ + "/^\\.github/workflows/.+\\.ya?ml$/" + ], + "matchStrings": [ + "# renovate: datasource=(?\\S+) depName=(?\\S+) packageName=(?\\S+) currentValue=(?\\S+)\\s+\\w+_REF:\\s*(?[0-9a-f]{7,40})" + ] + } ] } diff --git a/.github/workflows/codeql-cpp.yaml b/.github/workflows/codeql-cpp.yaml new file mode 100644 index 00000000..f31d564b --- /dev/null +++ b/.github/workflows/codeql-cpp.yaml @@ -0,0 +1,70 @@ +name: codeql-cpp + +permissions: {} + +on: + push: + branches: + - main + paths: + - cpp/** + - testdata/** + - .github/** + pull_request: + branches: + - main + paths: + - cpp/** + - testdata/** + - .github/** + schedule: + - cron: '48 5 * * 0' + +concurrency: + # Cancels in-progress runs only for pull requests + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + analyze: + name: Analyze C++ + runs-on: ubuntu-latest + permissions: + security-events: write + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - name: ccache + uses: hendrikmuhs/ccache-action@d62db5f07c26379fc4b4e0916f098a92573c3b03 # v1.2.23 + with: + key: ${{ github.job }}-${{ github.ref }} + append-timestamp: false + save: ${{ github.ref == 'refs/heads/main' }} + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y nlohmann-json3-dev + + - name: Install cucumber/messages + # TODO: Needs a tagged version + uses: cucumber/ci-actions/install-cpp-dep@8bbc6bac84313ef426e8a0e6ffa64659d0dc174b + with: + dependency: dependencies/messages.version + working-directory: cpp + + - uses: github/codeql-action/init@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6 + with: + languages: c-cpp + build-mode: manual + tools: linked + + - name: Configure + working-directory: cpp + run: cmake --workflow --preset host-system + + - uses: github/codeql-action/analyze@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6 + with: + category: "/language:cpp" diff --git a/.github/workflows/test-cpp.yaml b/.github/workflows/test-cpp.yaml new file mode 100644 index 00000000..56f47d84 --- /dev/null +++ b/.github/workflows/test-cpp.yaml @@ -0,0 +1,203 @@ +name: test-cpp + +permissions: {} + +on: + push: + branches: + - main + - renovate/** + paths: + - cpp/** + - testdata/** + - .github/** + pull_request: + paths: + - cpp/** + - testdata/** + - .github/** + +jobs: + test-cpp-system-packages-linux: + runs-on: ${{ matrix.config.os }} + strategy: + fail-fast: false + matrix: + config: + - { os: ubuntu-24.04, cxx: g++, version: 12 } + - { os: ubuntu-24.04, cxx: g++, version: 13 } + - { os: ubuntu-24.04, cxx: clang++, version: 16 } + - { os: ubuntu-24.04, cxx: clang++, version: 17 } + - { os: ubuntu-26.04, cxx: g++, version: 14 } + - { os: ubuntu-26.04, cxx: g++, version: 15 } + - { os: ubuntu-26.04, cxx: clang++, version: 21 } + - { os: ubuntu-26.04, cxx: clang++, version: 22 } + env: + CXX: ${{ matrix.config.cxx }}-${{ matrix.config.version }} + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false + + - name: ccache + uses: hendrikmuhs/ccache-action@d62db5f07c26379fc4b4e0916f098a92573c3b03 # v1.2.23 + with: + key: ${{ github.job }}-${{ matrix.config.os }}-${{ matrix.config.cxx }}-${{ matrix.config.version }}-${{ github.ref }} + append-timestamp: false + save: ${{ github.ref == 'refs/heads/main' }} + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y nlohmann-json3-dev libgtest-dev libgmock-dev + + - name: Install cucumber/messages + # TODO: Needs a tagged version + uses: cucumber/ci-actions/install-cpp-dep@8bbc6bac84313ef426e8a0e6ffa64659d0dc174b + with: + dependency: dependencies/messages.version + working-directory: cpp + + - name: Build and unit test + working-directory: cpp + run: cmake --workflow --preset test-system + + - name: Check testdata coverage + working-directory: cpp + run: cmake --build build/test-system --target check-testdata-coverage + + test-cpp-system-packages-macos: + runs-on: macos-latest + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false + + - name: ccache + uses: hendrikmuhs/ccache-action@d62db5f07c26379fc4b4e0916f098a92573c3b03 # v1.2.23 + with: + key: ${{ github.job }}-${{ github.ref }} + append-timestamp: false + save: ${{ github.ref == 'refs/heads/main' }} + + - name: Install dependencies + run: brew install nlohmann-json googletest + + - name: Install cucumber/messages + # TODO: Needs a tagged version + uses: cucumber/ci-actions/install-cpp-dep@8bbc6bac84313ef426e8a0e6ffa64659d0dc174b + with: + dependency: dependencies/messages.version + working-directory: cpp + + - name: Build and unit test + working-directory: cpp + run: cmake --workflow --preset test-system + + - name: Check testdata coverage + working-directory: cpp + run: cmake --build build/test-system --target check-testdata-coverage + + test-cpp-system-packages-windows: + runs-on: windows-latest + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false + + - name: Install build tools + uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0 + + - name: Install dependencies + shell: pwsh + run: | + vcpkg install nlohmann-json gtest --triplet x64-windows + # Expose the vcpkg toolchain so find_package() locates the packages. + echo "CMAKE_TOOLCHAIN_FILE=$env:VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake" >> $env:GITHUB_ENV + + - name: Install cucumber/messages + # TODO: Needs a tagged version + uses: cucumber/ci-actions/install-cpp-dep@8bbc6bac84313ef426e8a0e6ffa64659d0dc174b + with: + dependency: dependencies/messages.version + working-directory: cpp + + - name: Build and unit test + working-directory: cpp + run: cmake --workflow --preset test-system + + - name: Check testdata coverage + working-directory: cpp + run: cmake --build build/test-system --target check-testdata-coverage + + test-cpp-coverage: + runs-on: ubuntu-26.04 + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false + + - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: '3.12' + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y nlohmann-json3-dev libgtest-dev libgmock-dev + python -m pip install gcovr==8.6 + gcovr --version + + - name: ccache + uses: hendrikmuhs/ccache-action@d62db5f07c26379fc4b4e0916f098a92573c3b03 # v1.2.23 + with: + key: ${{ github.job }}-${{ github.ref }} + append-timestamp: false + save: ${{ github.ref == 'refs/heads/main' }} + + - name: Install cucumber/messages + # TODO: Needs a tagged version + uses: cucumber/ci-actions/install-cpp-dep@8bbc6bac84313ef426e8a0e6ffa64659d0dc174b + with: + dependency: dependencies/messages.version + working-directory: cpp + + - name: Coverage + working-directory: cpp + run: cmake --workflow --preset coverage + + - name: Show coverage summary + working-directory: cpp + run: cat build/coverage/coverage-summary.md + + test-cpp-lint: + runs-on: ubuntu-26.04 + env: + CXX: clang++ + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y clang clang-tidy nlohmann-json3-dev libgtest-dev libgmock-dev + + - name: ccache + uses: hendrikmuhs/ccache-action@d62db5f07c26379fc4b4e0916f098a92573c3b03 # v1.2.23 + with: + key: ${{ github.job }}-${{ github.ref }} + append-timestamp: false + save: ${{ github.ref == 'refs/heads/main' }} + + - name: Install cucumber/messages + # TODO: Needs a tagged version + uses: cucumber/ci-actions/install-cpp-dep@8bbc6bac84313ef426e8a0e6ffa64659d0dc174b + with: + dependency: dependencies/messages.version + working-directory: cpp + + - name: Lint + working-directory: cpp + run: cmake --workflow --preset tidy diff --git a/CHANGELOG.md b/CHANGELOG.md index ca9b0802..edd186ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Added +- [CPP] Initial C++ implementation ([#201](https://github.com/cucumber/query/pull/201)) ## [16.1.1] - 2026-08-05 ### Fixed diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b2ee5e2d..fdbe7492 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,6 +12,7 @@ Currently, the list is: - JavaScript - C# (.NET) - Ruby +- c++ Java is the reference implementation in the sense that it is responsible for generating the fixtures that are used in the acceptance tests to verify all @@ -39,11 +40,11 @@ UPDATE_SAMPLES=true mvn test Choosing which type to use in another language based on what we did in Java is an inexact science. This table defines all the decisions we've made so far: -| Java | JavaScript | C# | Ruby | -|---------------|----------------------|--------------------|--------------| -| `Optional` | `T \| undefined`[^1] | `T?` | `T \| nil` | -| `List` | `ReadonlyArray` | `List` | `Array` | -| `Map` | `Map` | `Dictionary` | `Hash` | -| `Map` | `Record` | `Dictionary` | `Hash` | +| Java | JavaScript | C# | Ruby | Cpp | +| ------------- | -------------------- | ------------------ | ------------ | ----------------------- | +| `Optional` | `T \| undefined`[^1] | `T?` | `T \| nil` | std::optional | +| `List` | `ReadonlyArray` | `List` | `Array` | std::vector | +| `Map` | `Map` | `Dictionary` | `Hash` | std::unordered_map | +| `Map` | `Record` | `Dictionary` | `Hash` | std::unordered_map | [^1]: See diff --git a/cpp/.clang-format b/cpp/.clang-format new file mode 100644 index 00000000..e221c2e8 --- /dev/null +++ b/cpp/.clang-format @@ -0,0 +1,164 @@ +--- +Language: Cpp +AccessModifierOffset: -4 +AlignAfterOpenBracket: DontAlign +AlignArrayOfStructures: None +AlignConsecutiveMacros: None +AlignConsecutiveAssignments: None +AlignConsecutiveBitFields: None +AlignConsecutiveDeclarations: None +AlignEscapedNewlines: Right +AlignOperands: Align +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortEnumsOnASingleLine: false +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortLambdasOnASingleLine: Empty +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterCaseLabel: true + AfterClass: true + AfterControlStatement: Always + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + AfterExternBlock: true + BeforeCatch: true + BeforeElse: true + BeforeLambdaBody: true + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: false +BreakBeforeBinaryOperators: None +BreakBeforeConceptDeclarations: true +BreakBeforeBraces: Custom +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeComma +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeComma +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 140 +CommentPragmas: "^ IWYU pragma:|^NOSONAR" +QualifierAlignment: Leave +CompactNamespaces: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: false +DeriveLineEnding: true +DerivePointerAlignment: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: false +PackConstructorInitializers: Never +FixNamespaceComments: false +IncludeBlocks: Merge +IncludeCategories: + - Regex: ^(<|"(gtest|gmock)/) + Priority: 2 + - Regex: ^(:-fno-elide-constructors> + ) + + if(CMAKE_C_COMPILER_ID STREQUAL "GNU") + link_libraries(gcov) + else() + add_link_options(--coverage) + endif() +endif() + +if(CUCUMBER_QUERY_ENABLE_SANITIZERS) + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + add_compile_options(-fsanitize=address -fsanitize=undefined) + add_link_options(-fsanitize=address -fsanitize=undefined) + endif() +endif() + +# Targets +add_library(cucumber_query_lib) +add_library(cucumber::query ALIAS cucumber_query_lib) + +target_sources( + cucumber_query_lib + PRIVATE + include/cucumber/query/EnvelopeArchive.hpp + include/cucumber/query/Lineage.hpp + include/cucumber/query/NdjsonEnvelopeReader.hpp + include/cucumber/query/Query.hpp + src/query/EnvelopeArchive.cpp + src/query/Lineage.cpp + src/query/NdjsonEnvelopeReader.cpp + src/query/Query.cpp + include/cucumber/query/NamingStrategy.hpp + src/query/NamingStrategy.cpp + include/cucumber/query/View.hpp +) + +target_include_directories( + cucumber_query_lib + PUBLIC + $ + $ + PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/src/query +) + +target_link_libraries( + cucumber_query_lib + PUBLIC + nlohmann_json::nlohmann_json + cucumber::messages +) + +set_target_properties( + cucumber_query_lib + PROPERTIES + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR} + EXPORT_NAME query + OUTPUT_NAME cucumber_query +) + +# Installation support +include(CMakePackageConfigHelpers) + +configure_package_config_file( + "cmake/cucumber_query-config.cmake.in" + "${PROJECT_BINARY_DIR}/cucumber_query-config.cmake" + INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/cucumber_query" + PATH_VARS CMAKE_INSTALL_INCLUDEDIR CMAKE_INSTALL_LIBDIR +) + +write_basic_package_version_file( + "${PROJECT_BINARY_DIR}/cucumber_query-config-version.cmake" + COMPATIBILITY AnyNewerVersion +) + +install( + TARGETS cucumber_query_lib + EXPORT cucumber_query-targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} +) + +install( + EXPORT cucumber_query-targets + FILE cucumber_query-targets.cmake + NAMESPACE cucumber:: + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/cucumber_query" +) + +install( + FILES + "${PROJECT_BINARY_DIR}/cucumber_query-config.cmake" + "${PROJECT_BINARY_DIR}/cucumber_query-config-version.cmake" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/cucumber_query" +) + +install( + DIRECTORY "${PROJECT_SOURCE_DIR}/include/" + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} +) + +# Optional: tests +if(CUCUMBER_QUERY_BUILD_TESTS) + find_package(GTest REQUIRED) + include(CTest) + enable_testing() + add_subdirectory(test) +endif() diff --git a/cpp/CMakePresets.json b/cpp/CMakePresets.json new file mode 100644 index 00000000..c2b24eb3 --- /dev/null +++ b/cpp/CMakePresets.json @@ -0,0 +1,169 @@ +{ + "version": 6, + "cmakeMinimumRequired": { + "major": 3, + "minor": 21 + }, + "configurePresets": [ + { + "name": "base", + "hidden": true, + "binaryDir": "${sourceDir}/build/${presetName}", + "generator": "Ninja", + "cacheVariables": { + "CMAKE_EXPORT_COMPILE_COMMANDS": "On" + } + }, + { + "name": "host-system", + "displayName": "Host build (system dependencies)", + "description": "Build and install the library using C++ dependencies already installed on the system.", + "inherits": "base", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "test-system", + "displayName": "Test build (system dependencies)", + "description": "Build with unit tests and sanitizers enabled using system dependencies. Used by CI to build and run the test suite.", + "inherits": "base", + "cacheVariables": { + "CUCUMBER_QUERY_BUILD_TESTS": "On", + "CUCUMBER_QUERY_ENABLE_SANITIZERS": "On", + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "tidy", + "displayName": "Lint build (clang-tidy, system dependencies)", + "description": "Build with unit tests and clang-tidy enabled using system dependencies.", + "inherits": "base", + "cacheVariables": { + "CUCUMBER_QUERY_BUILD_TESTS": "On", + "CUCUMBER_QUERY_ENABLE_CLANG_TIDY": "On", + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "coverage", + "displayName": "Coverage build (system dependencies)", + "description": "Build with unit tests and code coverage instrumentation using system dependencies.", + "inherits": "base", + "cacheVariables": { + "CUCUMBER_QUERY_BUILD_TESTS": "On", + "CUCUMBER_QUERY_ENABLE_COVERAGE": "On", + "CMAKE_BUILD_TYPE": "Debug" + } + } + ], + "buildPresets": [ + { + "name": "host-system", + "configurePreset": "host-system" + }, + { + "name": "test-system", + "configurePreset": "test-system" + }, + { + "name": "tidy", + "configurePreset": "tidy" + }, + { + "name": "coverage", + "configurePreset": "coverage" + }, + { + "name": "coverage-report", + "configurePreset": "coverage", + "targets": [ + "generate-lcov-report" + ] + } + ], + "testPresets": [ + { + "name": "test-system", + "configurePreset": "test-system", + "output": { + "outputOnFailure": true + }, + "execution": { + "noTestsAction": "error", + "jobs": 8 + } + }, + { + "name": "coverage", + "configurePreset": "coverage", + "inherits": "test-system" + } + ], + "workflowPresets": [ + { + "name": "host-system", + "steps": [ + { + "name": "host-system", + "type": "configure" + }, + { + "name": "host-system", + "type": "build" + } + ] + }, + { + "name": "test-system", + "steps": [ + { + "name": "test-system", + "type": "configure" + }, + { + "name": "test-system", + "type": "build" + }, + { + "name": "test-system", + "type": "test" + } + ] + }, + { + "name": "tidy", + "steps": [ + { + "name": "tidy", + "type": "configure" + }, + { + "name": "tidy", + "type": "build" + } + ] + }, + { + "name": "coverage", + "steps": [ + { + "name": "coverage", + "type": "configure" + }, + { + "name": "coverage", + "type": "build" + }, + { + "name": "coverage", + "type": "test" + }, + { + "name": "coverage-report", + "type": "build" + } + ] + } + ] +} diff --git a/cpp/VERSION b/cpp/VERSION new file mode 100644 index 00000000..1afe54c7 --- /dev/null +++ b/cpp/VERSION @@ -0,0 +1 @@ +16.1.1 diff --git a/cpp/cmake/cucumber_query-config.cmake.in b/cpp/cmake/cucumber_query-config.cmake.in new file mode 100644 index 00000000..6861f92f --- /dev/null +++ b/cpp/cmake/cucumber_query-config.cmake.in @@ -0,0 +1,8 @@ +@PACKAGE_INIT@ + +include(CMakeFindDependencyMacro) + +find_dependency(cucumber_messages) +find_dependency(nlohmann_json) + +include("${CMAKE_CURRENT_LIST_DIR}/cucumber_query-targets.cmake") diff --git a/cpp/compile_commands.json b/cpp/compile_commands.json new file mode 100644 index 00000000..57dcfbbd --- /dev/null +++ b/cpp/compile_commands.json @@ -0,0 +1,578 @@ +[ +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Attachment.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Attachment.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Attachment.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Attachment.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/AttachmentContentEncoding.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/AttachmentContentEncoding.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/AttachmentContentEncoding.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/AttachmentContentEncoding.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Background.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Background.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Background.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Background.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Ci.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Ci.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Ci.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Ci.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Comment.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Comment.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Comment.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Comment.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/DataTable.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/DataTable.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/DataTable.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/DataTable.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/DocString.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/DocString.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/DocString.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/DocString.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Duration.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Duration.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Duration.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Duration.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Envelope.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Envelope.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Envelope.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Envelope.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Examples.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Examples.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Examples.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Examples.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Exception.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Exception.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Exception.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Exception.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/ExternalAttachment.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/ExternalAttachment.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/ExternalAttachment.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/ExternalAttachment.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Feature.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Feature.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Feature.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Feature.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/FeatureChild.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/FeatureChild.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/FeatureChild.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/FeatureChild.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/GherkinDocument.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/GherkinDocument.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/GherkinDocument.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/GherkinDocument.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Git.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Git.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Git.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Git.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Group.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Group.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Group.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Group.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Hook.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Hook.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Hook.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Hook.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/HookType.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/HookType.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/HookType.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/HookType.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/JavaMethod.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/JavaMethod.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/JavaMethod.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/JavaMethod.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/JavaStackTraceElement.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/JavaStackTraceElement.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/JavaStackTraceElement.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/JavaStackTraceElement.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Location.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Location.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Location.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Location.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Meta.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Meta.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Meta.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Meta.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/ParameterType.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/ParameterType.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/ParameterType.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/ParameterType.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/ParseError.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/ParseError.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/ParseError.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/ParseError.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Pickle.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Pickle.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Pickle.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Pickle.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/PickleDocString.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/PickleDocString.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/PickleDocString.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/PickleDocString.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/PickleStep.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/PickleStep.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/PickleStep.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/PickleStep.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/PickleStepArgument.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/PickleStepArgument.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/PickleStepArgument.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/PickleStepArgument.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/PickleStepType.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/PickleStepType.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/PickleStepType.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/PickleStepType.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/PickleTable.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/PickleTable.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/PickleTable.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/PickleTable.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/PickleTableCell.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/PickleTableCell.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/PickleTableCell.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/PickleTableCell.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/PickleTableRow.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/PickleTableRow.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/PickleTableRow.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/PickleTableRow.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/PickleTag.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/PickleTag.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/PickleTag.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/PickleTag.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Product.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Product.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Product.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Product.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Rule.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Rule.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Rule.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Rule.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/RuleChild.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/RuleChild.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/RuleChild.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/RuleChild.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Scenario.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Scenario.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Scenario.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Scenario.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Snippet.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Snippet.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Snippet.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Snippet.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Source.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Source.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Source.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Source.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/SourceMediaType.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/SourceMediaType.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/SourceMediaType.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/SourceMediaType.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/SourceReference.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/SourceReference.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/SourceReference.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/SourceReference.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Step.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Step.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Step.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Step.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/StepDefinition.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/StepDefinition.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/StepDefinition.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/StepDefinition.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/StepDefinitionPattern.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/StepDefinitionPattern.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/StepDefinitionPattern.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/StepDefinitionPattern.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/StepDefinitionPatternType.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/StepDefinitionPatternType.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/StepDefinitionPatternType.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/StepDefinitionPatternType.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/StepKeywordType.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/StepKeywordType.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/StepKeywordType.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/StepKeywordType.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/StepMatchArgument.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/StepMatchArgument.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/StepMatchArgument.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/StepMatchArgument.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/StepMatchArgumentsList.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/StepMatchArgumentsList.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/StepMatchArgumentsList.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/StepMatchArgumentsList.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Suggestion.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Suggestion.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Suggestion.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Suggestion.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/TableCell.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/TableCell.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/TableCell.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/TableCell.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/TableRow.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/TableRow.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/TableRow.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/TableRow.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Tag.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Tag.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Tag.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Tag.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/TestCase.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/TestCase.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/TestCase.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/TestCase.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/TestCaseFinished.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/TestCaseFinished.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/TestCaseFinished.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/TestCaseFinished.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/TestCaseStarted.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/TestCaseStarted.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/TestCaseStarted.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/TestCaseStarted.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/TestRunFinished.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/TestRunFinished.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/TestRunFinished.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/TestRunFinished.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/TestRunHookFinished.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/TestRunHookFinished.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/TestRunHookFinished.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/TestRunHookFinished.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/TestRunHookStarted.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/TestRunHookStarted.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/TestRunHookStarted.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/TestRunHookStarted.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/TestRunStarted.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/TestRunStarted.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/TestRunStarted.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/TestRunStarted.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/TestStep.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/TestStep.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/TestStep.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/TestStep.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/TestStepFinished.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/TestStepFinished.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/TestStepFinished.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/TestStepFinished.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/TestStepResult.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/TestStepResult.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/TestStepResult.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/TestStepResult.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/TestStepResultStatus.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/TestStepResultStatus.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/TestStepResultStatus.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/TestStepResultStatus.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/TestStepStarted.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/TestStepStarted.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/TestStepStarted.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/TestStepStarted.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Timestamp.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Timestamp.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/Timestamp.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/Timestamp.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/UndefinedParameterType.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/UndefinedParameterType.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/generated/cucumber/messages/UndefinedParameterType.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/generated/cucumber/messages/UndefinedParameterType.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -I/workspaces/cucumber-cpp-development/messages/cpp/src/messages -O3 -DNDEBUG -std=c++17 -o messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/messages/cucumber/messages/DurationUtil.cpp.o -c /workspaces/cucumber-cpp-development/messages/cpp/src/messages/cucumber/messages/DurationUtil.cpp", + "file": "/workspaces/cucumber-cpp-development/messages/cpp/src/messages/cucumber/messages/DurationUtil.cpp", + "output": "messages/cpp/CMakeFiles/cucumber_messages_lib.dir/src/messages/cucumber/messages/DurationUtil.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/gherkin/cpp/include/gherkin -I/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -O3 -DNDEBUG -std=c++17 -o gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/App.cpp.o -c /workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/App.cpp", + "file": "/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/App.cpp", + "output": "gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/App.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/gherkin/cpp/include/gherkin -I/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -O3 -DNDEBUG -std=c++17 -o gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/AstBuilder.cpp.o -c /workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/AstBuilder.cpp", + "file": "/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/AstBuilder.cpp", + "output": "gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/AstBuilder.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/gherkin/cpp/include/gherkin -I/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -O3 -DNDEBUG -std=c++17 -o gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/AstNode.cpp.o -c /workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/AstNode.cpp", + "file": "/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/AstNode.cpp", + "output": "gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/AstNode.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/gherkin/cpp/include/gherkin -I/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -O3 -DNDEBUG -std=c++17 -o gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/Demangle.cpp.o -c /workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/Demangle.cpp", + "file": "/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/Demangle.cpp", + "output": "gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/Demangle.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/gherkin/cpp/include/gherkin -I/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -O3 -DNDEBUG -std=c++17 -o gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/Dialect.cpp.o -c /workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/Dialect.cpp", + "file": "/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/Dialect.cpp", + "output": "gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/Dialect.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/gherkin/cpp/include/gherkin -I/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -O3 -DNDEBUG -std=c++17 -o gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/Exceptions.cpp.o -c /workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/Exceptions.cpp", + "file": "/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/Exceptions.cpp", + "output": "gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/Exceptions.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/gherkin/cpp/include/gherkin -I/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -O3 -DNDEBUG -std=c++17 -o gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/IdGenerator.cpp.o -c /workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/IdGenerator.cpp", + "file": "/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/IdGenerator.cpp", + "output": "gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/IdGenerator.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/gherkin/cpp/include/gherkin -I/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -O3 -DNDEBUG -std=c++17 -o gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/Keywords.cpp.o -c /workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/Keywords.cpp", + "file": "/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/Keywords.cpp", + "output": "gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/Keywords.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/gherkin/cpp/include/gherkin -I/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -O3 -DNDEBUG -std=c++17 -o gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/Line.cpp.o -c /workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/Line.cpp", + "file": "/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/Line.cpp", + "output": "gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/Line.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/gherkin/cpp/include/gherkin -I/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -O3 -DNDEBUG -std=c++17 -o gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/ParseError.cpp.o -c /workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/ParseError.cpp", + "file": "/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/ParseError.cpp", + "output": "gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/ParseError.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/gherkin/cpp/include/gherkin -I/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -O3 -DNDEBUG -std=c++17 -o gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/PickleCompiler.cpp.o -c /workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/PickleCompiler.cpp", + "file": "/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/PickleCompiler.cpp", + "output": "gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/PickleCompiler.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/gherkin/cpp/include/gherkin -I/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -O3 -DNDEBUG -std=c++17 -o gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/PickleCompilerContext.cpp.o -c /workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/PickleCompilerContext.cpp", + "file": "/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/PickleCompilerContext.cpp", + "output": "gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/PickleCompilerContext.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/gherkin/cpp/include/gherkin -I/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -O3 -DNDEBUG -std=c++17 -o gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/Regex.cpp.o -c /workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/Regex.cpp", + "file": "/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/Regex.cpp", + "output": "gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/Regex.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/gherkin/cpp/include/gherkin -I/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -O3 -DNDEBUG -std=c++17 -o gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/RuleType.cpp.o -c /workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/RuleType.cpp", + "file": "/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/RuleType.cpp", + "output": "gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/RuleType.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/gherkin/cpp/include/gherkin -I/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -O3 -DNDEBUG -std=c++17 -o gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/Token.cpp.o -c /workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/Token.cpp", + "file": "/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/Token.cpp", + "output": "gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/Token.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/gherkin/cpp/include/gherkin -I/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -O3 -DNDEBUG -std=c++17 -o gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/TokenFormatterBuilder.cpp.o -c /workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/TokenFormatterBuilder.cpp", + "file": "/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/TokenFormatterBuilder.cpp", + "output": "gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/TokenFormatterBuilder.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/gherkin/cpp/include/gherkin -I/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -O3 -DNDEBUG -std=c++17 -o gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/TokenMatcher.cpp.o -c /workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/TokenMatcher.cpp", + "file": "/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/TokenMatcher.cpp", + "output": "gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/TokenMatcher.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/gherkin/cpp/include/gherkin -I/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -O3 -DNDEBUG -std=c++17 -o gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/TokenScanner.cpp.o -c /workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/TokenScanner.cpp", + "file": "/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/TokenScanner.cpp", + "output": "gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/TokenScanner.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/gherkin/cpp/include/gherkin -I/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -O3 -DNDEBUG -std=c++17 -o gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/Utils.cpp.o -c /workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/Utils.cpp", + "file": "/workspaces/cucumber-cpp-development/gherkin/cpp/src/lib/gherkin/cucumber/gherkin/Utils.cpp", + "output": "gherkin/cpp/src/lib/gherkin/CMakeFiles/cucumber_gherkin_lib.dir/cucumber/gherkin/Utils.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/gherkin/cpp/src/bin/gherkin -I/workspaces/cucumber-cpp-development/gherkin/cpp/include/gherkin -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -O3 -DNDEBUG -std=c++17 -o gherkin/cpp/src/bin/gherkin/CMakeFiles/cucumber_gherkin_bin.dir/Gherkin.cpp.o -c /workspaces/cucumber-cpp-development/gherkin/cpp/src/bin/gherkin/Gherkin.cpp", + "file": "/workspaces/cucumber-cpp-development/gherkin/cpp/src/bin/gherkin/Gherkin.cpp", + "output": "gherkin/cpp/src/bin/gherkin/CMakeFiles/cucumber_gherkin_bin.dir/Gherkin.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/gherkin/cpp/src/bin/gherkin-generate-tokens -I/workspaces/cucumber-cpp-development/gherkin/cpp/include/gherkin -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -O3 -DNDEBUG -std=c++17 -o gherkin/cpp/src/bin/gherkin-generate-tokens/CMakeFiles/cucumber_gherkin_generate_tokens_bin.dir/GherkinGenerateTokens.cpp.o -c /workspaces/cucumber-cpp-development/gherkin/cpp/src/bin/gherkin-generate-tokens/GherkinGenerateTokens.cpp", + "file": "/workspaces/cucumber-cpp-development/gherkin/cpp/src/bin/gherkin-generate-tokens/GherkinGenerateTokens.cpp", + "output": "gherkin/cpp/src/bin/gherkin-generate-tokens/CMakeFiles/cucumber_gherkin_generate_tokens_bin.dir/GherkinGenerateTokens.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/query/cpp/include -I/workspaces/cucumber-cpp-development/query/cpp/src/query -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -O3 -DNDEBUG -std=c++17 -o query/cpp/CMakeFiles/cucumber_query_lib.dir/src/query/Lineage.cpp.o -c /workspaces/cucumber-cpp-development/query/cpp/src/query/Lineage.cpp", + "file": "/workspaces/cucumber-cpp-development/query/cpp/src/query/Lineage.cpp", + "output": "query/cpp/CMakeFiles/cucumber_query_lib.dir/src/query/Lineage.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/query/cpp/include -I/workspaces/cucumber-cpp-development/query/cpp/src/query -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -O3 -DNDEBUG -std=c++17 -o query/cpp/CMakeFiles/cucumber_query_lib.dir/src/query/Query.cpp.o -c /workspaces/cucumber-cpp-development/query/cpp/src/query/Query.cpp", + "file": "/workspaces/cucumber-cpp-development/query/cpp/src/query/Query.cpp", + "output": "query/cpp/CMakeFiles/cucumber_query_lib.dir/src/query/Query.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/query/cpp/include -I/workspaces/cucumber-cpp-development/query/cpp/src/query -I/workspaces/cucumber-cpp-development/messages/cpp/include/util -I/workspaces/cucumber-cpp-development/messages/cpp/include/generated -O3 -DNDEBUG -std=c++17 -o query/cpp/CMakeFiles/cucumber_query_lib.dir/src/query/NamingStrategy.cpp.o -c /workspaces/cucumber-cpp-development/query/cpp/src/query/NamingStrategy.cpp", + "file": "/workspaces/cucumber-cpp-development/query/cpp/src/query/NamingStrategy.cpp", + "output": "query/cpp/CMakeFiles/cucumber_query_lib.dir/src/query/NamingStrategy.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/tag-expressions/cpp/include -I/workspaces/cucumber-cpp-development/tag-expressions/cpp/src -O3 -DNDEBUG -std=c++17 -o tag-expressions/cpp/CMakeFiles/cucumber_tag_expressions_lib.dir/src/cucumber/tag-expressions/Error.cpp.o -c /workspaces/cucumber-cpp-development/tag-expressions/cpp/src/cucumber/tag-expressions/Error.cpp", + "file": "/workspaces/cucumber-cpp-development/tag-expressions/cpp/src/cucumber/tag-expressions/Error.cpp", + "output": "tag-expressions/cpp/CMakeFiles/cucumber_tag_expressions_lib.dir/src/cucumber/tag-expressions/Error.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/tag-expressions/cpp/include -I/workspaces/cucumber-cpp-development/tag-expressions/cpp/src -O3 -DNDEBUG -std=c++17 -o tag-expressions/cpp/CMakeFiles/cucumber_tag_expressions_lib.dir/src/cucumber/tag-expressions/Model.cpp.o -c /workspaces/cucumber-cpp-development/tag-expressions/cpp/src/cucumber/tag-expressions/Model.cpp", + "file": "/workspaces/cucumber-cpp-development/tag-expressions/cpp/src/cucumber/tag-expressions/Model.cpp", + "output": "tag-expressions/cpp/CMakeFiles/cucumber_tag_expressions_lib.dir/src/cucumber/tag-expressions/Model.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/tag-expressions/cpp/include -I/workspaces/cucumber-cpp-development/tag-expressions/cpp/src -O3 -DNDEBUG -std=c++17 -o tag-expressions/cpp/CMakeFiles/cucumber_tag_expressions_lib.dir/src/cucumber/tag-expressions/Parser.cpp.o -c /workspaces/cucumber-cpp-development/tag-expressions/cpp/src/cucumber/tag-expressions/Parser.cpp", + "file": "/workspaces/cucumber-cpp-development/tag-expressions/cpp/src/cucumber/tag-expressions/Parser.cpp", + "output": "tag-expressions/cpp/CMakeFiles/cucumber_tag_expressions_lib.dir/src/cucumber/tag-expressions/Parser.cpp.o" +}, +{ + "directory": "/workspaces/cucumber-cpp-development/build/host-system", + "command": "/usr/bin/c++ -I/workspaces/cucumber-cpp-development/tag-expressions/cpp/include -I/workspaces/cucumber-cpp-development/tag-expressions/cpp/src -O3 -DNDEBUG -std=c++17 -o tag-expressions/cpp/CMakeFiles/cucumber_tag_expressions_lib.dir/src/cucumber/tag-expressions/Token.cpp.o -c /workspaces/cucumber-cpp-development/tag-expressions/cpp/src/cucumber/tag-expressions/Token.cpp", + "file": "/workspaces/cucumber-cpp-development/tag-expressions/cpp/src/cucumber/tag-expressions/Token.cpp", + "output": "tag-expressions/cpp/CMakeFiles/cucumber_tag_expressions_lib.dir/src/cucumber/tag-expressions/Token.cpp.o" +} +] \ No newline at end of file diff --git a/cpp/dependencies/messages.version b/cpp/dependencies/messages.version new file mode 100644 index 00000000..8020cfbe --- /dev/null +++ b/cpp/dependencies/messages.version @@ -0,0 +1 @@ +cucumber/messages@e97fc9505bf8e0f000306cd811f2ab8183835c2f # main diff --git a/cpp/include/cucumber/query/EnvelopeArchive.hpp b/cpp/include/cucumber/query/EnvelopeArchive.hpp new file mode 100644 index 00000000..815f1ddb --- /dev/null +++ b/cpp/include/cucumber/query/EnvelopeArchive.hpp @@ -0,0 +1,18 @@ +#ifndef CUCUMBER_QUERY_ENVELOPE_ARCHIVE_HPP +#define CUCUMBER_QUERY_ENVELOPE_ARCHIVE_HPP + +#include "cucumber/messages/Envelope.hpp" +#include + +namespace cucumber::query +{ + struct EnvelopeArchive + { + const messages::Envelope& Store(messages::Envelope&& envelope); + + private: + std::deque envelopes; + }; +} + +#endif diff --git a/cpp/include/cucumber/query/Lineage.hpp b/cpp/include/cucumber/query/Lineage.hpp new file mode 100644 index 00000000..3dc2ea29 --- /dev/null +++ b/cpp/include/cucumber/query/Lineage.hpp @@ -0,0 +1,33 @@ +#ifndef CUCUMBER_QUERY_LINEAGE_HPP +#define CUCUMBER_QUERY_LINEAGE_HPP + +#include "cucumber/messages/Background.hpp" +#include "cucumber/messages/Examples.hpp" +#include "cucumber/messages/Feature.hpp" +#include "cucumber/messages/GherkinDocument.hpp" +#include "cucumber/messages/Rule.hpp" +#include "cucumber/messages/Scenario.hpp" +#include "cucumber/messages/TableRow.hpp" +#include +#include + +namespace cucumber::query +{ + struct Lineage + { + const messages::GherkinDocument* gherkinDocument{ nullptr }; + const messages::Feature* feature{ nullptr }; + const messages::Background* background{ nullptr }; + const messages::Rule* rule{ nullptr }; + const messages::Background* ruleBackground{ nullptr }; + const messages::Scenario* scenario{ nullptr }; + const messages::Examples* examples{ nullptr }; + std::optional examplesIndex; + const messages::TableRow* example{ nullptr }; + std::optional exampleIndex; + + Lineage operator+(const Lineage& other) const; + }; +} + +#endif diff --git a/cpp/include/cucumber/query/NamingStrategy.hpp b/cpp/include/cucumber/query/NamingStrategy.hpp new file mode 100644 index 00000000..dcbf4e21 --- /dev/null +++ b/cpp/include/cucumber/query/NamingStrategy.hpp @@ -0,0 +1,61 @@ +#ifndef CUCUMBER_QUERY_NAMING_STRATEGY_HPP +#define CUCUMBER_QUERY_NAMING_STRATEGY_HPP + +#include "cucumber/messages/Pickle.hpp" +#include "cucumber/query/Lineage.hpp" +#include +#include +#include + +namespace cucumber::query +{ + struct NamingStrategy + { + NamingStrategy() = default; + + NamingStrategy(const NamingStrategy&) = default; + NamingStrategy(NamingStrategy&&) = default; + NamingStrategy& operator=(const NamingStrategy&) = default; + NamingStrategy& operator=(NamingStrategy&&) = default; + + virtual ~NamingStrategy() = default; + + [[nodiscard]] virtual std::string Reduce(const Lineage& lineage, const messages::Pickle& pickle) const = 0; + }; + + enum class NamingStrategyLength : std::uint8_t + { + longName, + shortName, + }; + + enum class NamingStrategyFeatureName : std::uint8_t + { + include, + exclude, + }; + + enum class NamingStrategyExampleName : std::uint8_t + { + number, + pickle, + numberAndPickleIfParameterized, + }; + + struct BuiltinNamingStrategy : NamingStrategy + { + BuiltinNamingStrategy(NamingStrategyLength length, NamingStrategyFeatureName featureName, NamingStrategyExampleName exampleName); + + [[nodiscard]] std::string Reduce(const Lineage& lineage, const messages::Pickle& pickle) const override; + + private: + NamingStrategyLength length; + NamingStrategyFeatureName featureName; + NamingStrategyExampleName exampleName; + }; + + std::unique_ptr CreateNamingStrategy(NamingStrategyLength length, NamingStrategyFeatureName featureName = NamingStrategyFeatureName::include, + NamingStrategyExampleName exampleName = NamingStrategyExampleName::numberAndPickleIfParameterized); +} + +#endif diff --git a/cpp/include/cucumber/query/NdjsonEnvelopeReader.hpp b/cpp/include/cucumber/query/NdjsonEnvelopeReader.hpp new file mode 100644 index 00000000..a57899ed --- /dev/null +++ b/cpp/include/cucumber/query/NdjsonEnvelopeReader.hpp @@ -0,0 +1,27 @@ +#ifndef CUCUMBER_QUERY_NDJSON_ENVELOPE_READER_HPP +#define CUCUMBER_QUERY_NDJSON_ENVELOPE_READER_HPP + +#include "cucumber/messages/Envelope.hpp" +#include "cucumber/query/EnvelopeArchive.hpp" +#include +#include +#include + +namespace cucumber::query +{ + namespace detail + { + std::optional TryReadNextEnvelope(std::istream& input); + } + + template + void LoadNdjson(EnvelopeArchive& archive, std::istream& input, Observer&& observer) + { + while (auto envelope = detail::TryReadNextEnvelope(input)) + { + std::forward(observer)(archive.Store(std::move(*envelope))); + } + } +} + +#endif diff --git a/cpp/include/cucumber/query/Query.hpp b/cpp/include/cucumber/query/Query.hpp new file mode 100644 index 00000000..be8486ca --- /dev/null +++ b/cpp/include/cucumber/query/Query.hpp @@ -0,0 +1,293 @@ +#ifndef CUCUMBER_QUERY_QUERY_HPP +#define CUCUMBER_QUERY_QUERY_HPP + +#include "cucumber/messages/All.hpp" +#include "cucumber/messages/Envelope.hpp" +#include "cucumber/messages/Feature.hpp" +#include "cucumber/messages/GherkinDocument.hpp" +#include "cucumber/messages/Pickle.hpp" +#include "cucumber/messages/Rule.hpp" +#include "cucumber/messages/TestCase.hpp" +#include "cucumber/messages/TestCaseStarted.hpp" +#include "cucumber/messages/TestStepFinished.hpp" +#include "cucumber/messages/TestStepResultStatus.hpp" +#include "cucumber/query/Lineage.hpp" +#include "cucumber/query/View.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace cucumber::query +{ + struct LineageAndPickle + { + const Lineage* lineage; + const messages::Pickle* pickle; + }; + + struct TestStepFinishedAndTestStep + { + const messages::TestStepFinished* testStepFinished; + const messages::TestStep* testStep; + }; + + struct StringIdCompare + { + bool operator()(const std::string& lhs, const std::string& rhs) const + { + return std::stoi(lhs) < std::stoi(rhs); + } + }; + + template + using Pointers = std::vector; + + template + using ById = std::map; + + template + using ManyById = std::map, StringIdCompare>; + + template + using Predicate = std::function; + + // All views below are lazy and non-owning, except OwningView, and yield `const T&` on iteration. + template + using ElementsView = TransformView>, views::SelectPointee>; + + template + using FilteredElementsView = FilterView, Predicate>; + + template + using ValuesView = TransformView>, views::SelectSecond>, views::SelectPointee>; + + template + using FilteredValuesView = FilterView, Predicate>; + + template + using JoinedValuesView = TransformView>, views::SelectSecond>>, views::SelectPointee>; + + template + using OwningView = TransformView, views::SelectPointee>; + + class Query + { + public: + void Update(const std::shared_ptr& envelope); + void Update(const cucumber::messages::Envelope& envelope); + + [[nodiscard]] std::unordered_map CountMostSevereTestStepResultStatus() const; + + [[nodiscard]] std::size_t CountTestCasesStarted() const; + + [[nodiscard]] ValuesView FindAllPickles() const; + + [[nodiscard]] ValuesView FindAllPickleSteps() const; + + [[nodiscard]] ValuesView FindAllStepDefinitions() const; + + [[nodiscard]] FilteredValuesView FindAllTestCaseStarted() const; + + [[nodiscard]] FilteredValuesView FindAllTestCaseFinished() const; + + template + [[nodiscard]] OwningView FindAllTestCaseStartedOrderBy(Transform&& findOrderBy, Cmp order) const; + + template + [[nodiscard]] OwningView FindAllTestCaseFinishedOrderBy(Transform&& findOrderBy, Cmp order) const; + + [[nodiscard]] ValuesView FindAllTestSteps() const; + + [[nodiscard]] ValuesView FindAllTestCases() const; + + [[nodiscard]] JoinedValuesView FindAllTestStepStarted() const; + + [[nodiscard]] JoinedValuesView FindAllTestStepFinished() const; + + [[nodiscard]] ValuesView FindAllTestRunHookStarted() const; + + [[nodiscard]] ValuesView FindAllTestRunHookFinished() const; + + [[nodiscard]] ElementsView FindAllUndefinedParameterTypes() const; + + [[nodiscard]] FilteredElementsView FindAttachmentsBy(const messages::TestStepFinished& element) const; + [[nodiscard]] ElementsView FindAttachmentsBy(const messages::TestRunHookFinished& element) const; + + [[nodiscard]] const messages::Hook* FindHookBy(const messages::TestStep& element) const; + [[nodiscard]] const messages::Hook* FindHookBy(const messages::TestRunHookStarted& element) const; + [[nodiscard]] const messages::Hook* FindHookBy(const messages::TestRunHookFinished& element) const; + + [[nodiscard]] const messages::Meta* FindMeta() const; + + [[nodiscard]] const messages::TestStepResult* FindMostSevereTestStepResultBy(const messages::TestCaseStarted& element) const; + [[nodiscard]] const messages::TestStepResult* FindMostSevereTestStepResultBy(const messages::TestCaseFinished& element) const; + + [[nodiscard]] const messages::Location* FindLocationOf(const messages::Pickle& pickle) const; + + [[nodiscard]] const messages::Pickle* FindPickleBy(const messages::TestCaseStarted& element) const; + [[nodiscard]] const messages::Pickle* FindPickleBy(const messages::TestCaseFinished& element) const; + [[nodiscard]] const messages::Pickle* FindPickleBy(const messages::TestStepStarted& element) const; + [[nodiscard]] const messages::Pickle* FindPickleBy(const messages::TestStepFinished& element) const; + + [[nodiscard]] const messages::PickleStep* FindPickleStepBy(const messages::TestStep& testStep) const; + + [[nodiscard]] const messages::Step* FindStepBy(const messages::PickleStep& pickleStep) const; + + [[nodiscard]] OwningView FindStepDefinitionsBy(const messages::TestStep& testStep) const; + + [[nodiscard]] OwningView FindSuggestionsBy(const messages::PickleStep& element) const; + [[nodiscard]] OwningView FindSuggestionsBy(const messages::Pickle& element) const; + + [[nodiscard]] const messages::StepDefinition* FindUnambiguousStepDefinitionBy(const messages::TestStep& testStep) const; + + [[nodiscard]] const messages::TestCase* FindTestCaseBy(const messages::TestCaseStarted& element) const; + [[nodiscard]] const messages::TestCase* FindTestCaseBy(const messages::TestCaseFinished& element) const; + [[nodiscard]] const messages::TestCase* FindTestCaseBy(const messages::TestStepStarted& element) const; + [[nodiscard]] const messages::TestCase* FindTestCaseBy(const messages::TestStepFinished& element) const; + + [[nodiscard]] std::optional FindTestCaseDurationBy(const messages::TestCaseStarted& element) const; + + [[nodiscard]] std::optional FindTestCaseDurationBy(const messages::TestCaseFinished& element) const; + + [[nodiscard]] const messages::TestCaseStarted* FindTestCaseStartedBy(const messages::TestCaseFinished& element) const; + [[nodiscard]] const messages::TestCaseStarted* FindTestCaseStartedBy(const messages::TestStepStarted& element) const; + [[nodiscard]] const messages::TestCaseStarted* FindTestCaseStartedBy(const messages::TestStepFinished& element) const; + + [[nodiscard]] const messages::TestCaseFinished* FindTestCaseFinishedBy(const messages::TestCaseStarted& testCaseStarted) const; + + [[nodiscard]] const messages::TestRunHookStarted* FindTestRunHookStartedBy(const messages::TestRunHookFinished& testRunHookFinished) const; + + [[nodiscard]] const messages::TestRunHookFinished* FindTestRunHookFinishedBy(const messages::TestRunHookStarted& testRunHookStarted) const; + + [[nodiscard]] std::optional FindTestRunDuration() const; + + [[nodiscard]] const messages::TestRunFinished* FindTestRunFinished() const; + + [[nodiscard]] const messages::TestRunStarted* FindTestRunStarted() const; + + [[nodiscard]] const messages::TestStep* FindTestStepBy(const messages::TestStepStarted& element) const; + [[nodiscard]] const messages::TestStep* FindTestStepBy(const messages::TestStepFinished& element) const; + + [[nodiscard]] ElementsView FindTestStepsStartedBy(const messages::TestCaseStarted& testCaseStarted) const; + [[nodiscard]] ElementsView FindTestStepsStartedBy(const messages::TestCaseFinished& testCaseFinished) const; + + [[nodiscard]] ElementsView FindTestStepsFinishedBy(const messages::TestCaseStarted& element) const; + [[nodiscard]] ElementsView FindTestStepsFinishedBy(const messages::TestCaseFinished& element) const; + + [[nodiscard]] std::vector FindTestStepFinishedAndTestStepBy(const messages::TestCaseStarted& testCaseStarted) const; + + [[nodiscard]] std::optional FindLineageBy(const messages::Pickle& element) const; + [[nodiscard]] std::optional FindLineageBy(const messages::TestCaseStarted& element) const; + [[nodiscard]] std::optional FindLineageBy(const messages::TestCaseFinished& element) const; + + private: + [[nodiscard]] std::vector AllTestCaseStarted() const; + [[nodiscard]] std::vector AllTestCaseFinished() const; + + void UpdateGherkinDocument(const messages::GherkinDocument& gherkinDocument); + void UpdateFeature(const messages::Feature& feature, Lineage lineage); + void UpdateRule(const messages::Rule& rule, Lineage lineage); + void UpdateScenario(const messages::Scenario& scenario, const Lineage& lineage); + void UpdateSteps(const std::vector& steps); + void UpdatePickle(const messages::Pickle& pickle); + void UpdateTestRunHookStarted(const messages::TestRunHookStarted& testRunHookStarted); + void UpdateTestRunHookFinished(const messages::TestRunHookFinished& testRunHookFinished); + void UpdateTestCase(const messages::TestCase& testCase); + void UpdateTestCaseStarted(const messages::TestCaseStarted& testCaseStarted); + void UpdateAttachment(const messages::Attachment& attachment); + void UpdateTestStepFinished(const messages::TestStepFinished& testStepFinished); + void UpdateTestCaseFinished(const messages::TestCaseFinished& testCaseFinished); + + const messages::Meta* meta{ nullptr }; + + const messages::TestRunStarted* testRunStarted{ nullptr }; + const messages::TestRunFinished* testRunFinished{ nullptr }; + + ById testCaseStartedById; + std::map lineageById; + ById stepById; + ById pickleById; + ById pickleStepById; + ById hookById; + ById stepDefinitionById; + ById testCaseById; + ById testStepById; + ById testCaseFinishedByTestCaseStartedId; + ById testRunHookStartedById; + ById testRunHookFinishedByTestRunHookStartedId; + ManyById testStepStartedByTestCaseStartedId; + ManyById testStepFinishedByTestCaseStartedId; + ManyById attachmentsByTestCaseStartedId; + ManyById attachmentsByTestRunHookStartedId; + ById suggestionsByPickleStepId; + Pointers undefinedParameterTypes; + }; + + static inline const messages::Pickle* (query::Query::* const findPickleByTestCaseFinished)(const messages::TestCaseFinished&) const = &query::Query::FindPickleBy; + + namespace detail + { + template + [[nodiscard]] OwningView FindAllOrderBy(const Query& query, std::vector allElements, Transform findOrderBy, Cmp order) + { + using TransformResult = decltype(std::invoke(findOrderBy, query, std::declval())); + + std::vector> transformed; + transformed.reserve(allElements.size()); + + for (const auto* element : allElements) + { + transformed.emplace_back(element, std::invoke(findOrderBy, query, *element)); + } + + std::sort(transformed.begin(), transformed.end(), + [&](const auto& lhs, const auto& rhs) + { + if (lhs.second == nullptr && rhs.second == nullptr) + { + return false; + } + if (lhs.second == nullptr) + { + return true; + } + if (rhs.second == nullptr) + { + return false; + } + + return std::invoke(order, *lhs.second, *rhs.second) < 0; + }); + + std::vector result; + result.reserve(transformed.size()); + for (const auto& pair : transformed) + { + result.push_back(pair.first); + } + + return OwningView{ std::move(result), views::SelectPointee{} }; + } + } + + template + [[nodiscard]] OwningView Query::FindAllTestCaseStartedOrderBy(Transform&& findOrderBy, Cmp order) const + { + return detail::FindAllOrderBy(*this, AllTestCaseStarted(), std::forward(findOrderBy), std::move(order)); + } + + template + [[nodiscard]] OwningView Query::FindAllTestCaseFinishedOrderBy(Transform&& findOrderBy, Cmp order) const + { + return detail::FindAllOrderBy(*this, AllTestCaseFinished(), std::forward(findOrderBy), std::move(order)); + } +} + +#endif diff --git a/cpp/include/cucumber/query/View.hpp b/cpp/include/cucumber/query/View.hpp new file mode 100644 index 00000000..a4c0a729 --- /dev/null +++ b/cpp/include/cucumber/query/View.hpp @@ -0,0 +1,680 @@ +#ifndef CUCUMBER_QUERY_VIEW_HPP +#define CUCUMBER_QUERY_VIEW_HPP + +#include +#include +#include +#include +#include + +namespace cucumber::query +{ + namespace detail + { + struct ViewBase + {}; + + template + using IsView = std::is_base_of>; + + template + struct IsRange : std::false_type + {}; + + template + struct IsRange())), decltype(std::end(std::declval()))>> : std::true_type + {}; + + template + struct HasData : std::false_type + {}; + + template + struct HasData().data()), decltype(std::declval().size())>> : std::true_type + {}; + + // Operations shared by all lazy views; Derived provides Begin() and End(). + template + class ViewInterface : public ViewBase + { + public: + [[nodiscard]] auto begin() const + { + return Self().Begin(); + } + + [[nodiscard]] auto end() const + { + return Self().End(); + } + + [[nodiscard]] std::size_t size() const + { + return static_cast(std::distance(begin(), end())); + } + + [[nodiscard]] bool empty() const + { + return begin() == end(); + } + + [[nodiscard]] decltype(auto) front() const + { + return *begin(); + } + + private: + [[nodiscard]] const Derived& Self() const + { + return static_cast(*this); + } + }; + } + + // Non-owning view over a contiguous sequence. + template + class Span : public detail::ViewBase + { + public: + using element_type = T; + using value_type = std::remove_cv_t; + using size_type = std::size_t; + using reference = T&; + using pointer = T*; + using iterator = T*; + using const_iterator = T*; + + constexpr Span() noexcept = default; + + constexpr Span(T* first, size_type count) noexcept + : first(first) + , count(count) + {} + + constexpr Span(T* first, T* last) noexcept + : first(first) + , count(static_cast(last - first)) + {} + + template, Span> && detail::HasData::value && std::is_convertible_v().data()), T*>>> + constexpr Span(Container& container) noexcept // NOLINT(google-explicit-constructor) + : first(container.data()) + , count(container.size()) + {} + + [[nodiscard]] constexpr T* data() const noexcept + { + return first; + } + + [[nodiscard]] constexpr size_type size() const noexcept + { + return count; + } + + [[nodiscard]] constexpr bool empty() const noexcept + { + return count == 0; + } + + [[nodiscard]] constexpr iterator begin() const noexcept + { + return first; + } + + [[nodiscard]] constexpr iterator end() const noexcept + { + return first + count; + } + + [[nodiscard]] constexpr reference front() const + { + return *first; + } + + [[nodiscard]] constexpr reference back() const + { + return *(first + count - 1); + } + + [[nodiscard]] constexpr reference operator[](size_type index) const + { + return *(first + index); + } + + [[nodiscard]] constexpr Span Subspan(size_type offset, size_type length) const + { + return Span{ first + offset, length }; + } + + [[nodiscard]] constexpr Span Subspan(size_type offset) const + { + return Subspan(offset, count - offset); + } + + private: + T* first{ nullptr }; + size_type count{ 0 }; + }; + + template::value>> + Span(Container& container) -> Span().data())>>; + + // Non-owning view over an existing range, so that any range can be composed by value. + template + class RefView : public detail::ViewInterface> + { + public: + explicit RefView(Range& range) + : range(&range) + {} + + [[nodiscard]] auto Begin() const + { + return std::begin(*range); + } + + [[nodiscard]] auto End() const + { + return std::end(*range); + } + + private: + Range* range; + }; + + namespace detail + { + template::value>> + std::decay_t MakeAllView(Range&& range) + { + return std::forward(range); + } + + template::value>> + RefView MakeAllView(Range& range) + { + static_assert(IsRange::value, "the argument is not a range"); + return RefView{ range }; + } + + template + class FilterIterator + { + using Traits = std::iterator_traits; + + public: + using iterator_category = std::forward_iterator_tag; + using value_type = typename Traits::value_type; + using difference_type = typename Traits::difference_type; + using reference = typename Traits::reference; + using pointer = typename Traits::pointer; + + FilterIterator() = default; + + FilterIterator(BaseIterator current, BaseIterator last, const Predicate* predicate) + : current(std::move(current)) + , last(std::move(last)) + , predicate(predicate) + { + SkipToMatch(); + } + + reference operator*() const + { + return *current; + } + + pointer operator->() const + { + return std::addressof(*current); + } + + FilterIterator& operator++() + { + ++current; + SkipToMatch(); + return *this; + } + + FilterIterator operator++(int) + { + auto copy = *this; + ++*this; + return copy; + } + + friend bool operator==(const FilterIterator& lhs, const FilterIterator& rhs) + { + return lhs.current == rhs.current; + } + + friend bool operator!=(const FilterIterator& lhs, const FilterIterator& rhs) + { + return !(lhs == rhs); + } + + private: + void SkipToMatch() + { + while (current != last && !(*predicate)(*current)) + { + ++current; + } + } + + BaseIterator current{}; + BaseIterator last{}; + const Predicate* predicate{ nullptr }; + }; + + template + class TransformIterator + { + using Traits = std::iterator_traits; + + public: + using iterator_category = std::forward_iterator_tag; + using reference = decltype(std::declval()(*std::declval())); + using value_type = std::decay_t; + using difference_type = typename Traits::difference_type; + using pointer = void; + + TransformIterator() = default; + + TransformIterator(BaseIterator current, const Projection* projection) + : current(std::move(current)) + , projection(projection) + {} + + reference operator*() const + { + return (*projection)(*current); + } + + TransformIterator& operator++() + { + ++current; + return *this; + } + + TransformIterator operator++(int) + { + auto copy = *this; + ++*this; + return copy; + } + + friend bool operator==(const TransformIterator& lhs, const TransformIterator& rhs) + { + return lhs.current == rhs.current; + } + + friend bool operator!=(const TransformIterator& lhs, const TransformIterator& rhs) + { + return !(lhs == rhs); + } + + private: + BaseIterator current{}; + const Projection* projection{ nullptr }; + }; + + template + class JoinIterator + { + public: + using iterator_category = std::forward_iterator_tag; + using reference = decltype(*std::declval()); + using value_type = std::decay_t; + using difference_type = typename std::iterator_traits::difference_type; + using pointer = typename std::iterator_traits::pointer; + + JoinIterator() = default; + + JoinIterator(OuterIterator current, OuterIterator last) + : currentOuter(std::move(current)) + , lastOuter(std::move(last)) + { + SkipToNonEmpty(); + } + + reference operator*() const + { + return *currentInner; + } + + pointer operator->() const + { + return std::addressof(*currentInner); + } + + JoinIterator& operator++() + { + ++currentInner; + if (currentInner == lastInner) + { + ++currentOuter; + SkipToNonEmpty(); + } + return *this; + } + + JoinIterator operator++(int) + { + auto copy = *this; + ++*this; + return copy; + } + + friend bool operator==(const JoinIterator& lhs, const JoinIterator& rhs) + { + return lhs.currentOuter == rhs.currentOuter && lhs.currentInner == rhs.currentInner; + } + + friend bool operator!=(const JoinIterator& lhs, const JoinIterator& rhs) + { + return !(lhs == rhs); + } + + private: + void SkipToNonEmpty() + { + while (currentOuter != lastOuter) + { + currentInner = std::begin(*currentOuter); + lastInner = std::end(*currentOuter); + if (currentInner != lastInner) + { + return; + } + ++currentOuter; + } + + currentInner = InnerIterator{}; + lastInner = InnerIterator{}; + } + + OuterIterator currentOuter{}; + OuterIterator lastOuter{}; + InnerIterator currentInner{}; + InnerIterator lastInner{}; + }; + + // Applies the predicate to the projection of an element, so that filtering on a member is possible. + template + class ProjectedPredicate + { + public: + ProjectedPredicate(Predicate predicate, Projection projection) + : predicate(std::move(predicate)) + , projection(std::move(projection)) + {} + + template + bool operator()(Element&& element) const + { + return predicate(projection(std::forward(element))); + } + + private: + Predicate predicate; + Projection projection; + }; + } + + template + class FilterView : public detail::ViewInterface> + { + using BaseIterator = decltype(std::begin(std::declval())); + + public: + using iterator = detail::FilterIterator; + + FilterView(Range range, Predicate predicate) + : range(std::move(range)) + , predicate(std::move(predicate)) + {} + + [[nodiscard]] iterator Begin() const + { + return iterator{ std::begin(range), std::end(range), &predicate }; + } + + [[nodiscard]] iterator End() const + { + return iterator{ std::end(range), std::end(range), &predicate }; + } + + private: + Range range; + Predicate predicate; + }; + + template + class TransformView : public detail::ViewInterface> + { + using BaseIterator = decltype(std::begin(std::declval())); + + public: + using iterator = detail::TransformIterator; + + TransformView(Range range, Projection projection) + : range(std::move(range)) + , projection(std::move(projection)) + {} + + [[nodiscard]] iterator Begin() const + { + return iterator{ std::begin(range), &projection }; + } + + [[nodiscard]] iterator End() const + { + return iterator{ std::end(range), &projection }; + } + + private: + Range range; + Projection projection; + }; + + // Concatenates the elements of a range of ranges. + template + class JoinView : public detail::ViewInterface> + { + using OuterIterator = decltype(std::begin(std::declval())); + using InnerRange = std::remove_reference_t())>; + + static_assert(std::is_reference_v())>, "the outer range must yield references, not temporaries"); + + public: + using iterator = detail::JoinIterator()))>; + + explicit JoinView(Range range) + : range(std::move(range)) + {} + + [[nodiscard]] iterator Begin() const + { + return iterator{ std::begin(range), std::end(range) }; + } + + [[nodiscard]] iterator End() const + { + return iterator{ std::end(range), std::end(range) }; + } + + private: + Range range; + }; + + namespace views + { + struct SelectFirst + { + template + decltype(auto) operator()(Pair&& pair) const + { + return (std::forward(pair).first); + } + }; + + struct SelectSecond + { + template + decltype(auto) operator()(Pair&& pair) const + { + return (std::forward(pair).second); + } + }; + + struct SelectPointee + { + template + decltype(auto) operator()(const Pointer& pointer) const + { + return (*pointer); + } + }; + + namespace detail + { + // A partially applied adaptor, enabling `range | Filter(predicate)`. + template + class Closure + { + public: + explicit Closure(Adaptor adaptor) + : adaptor(std::move(adaptor)) + {} + + template + decltype(auto) operator()(Range&& range) const + { + return adaptor(std::forward(range)); + } + + private: + Adaptor adaptor; + }; + + template + Closure MakeClosure(Adaptor adaptor) + { + return Closure{ std::move(adaptor) }; + } + } + + template>::value>> + auto All(Range&& range) + { + return query::detail::MakeAllView(std::forward(range)); + } + + template>::value>> + auto Filter(Range&& range, Predicate predicate) + { + auto view = All(std::forward(range)); + return FilterView{ std::move(view), std::move(predicate) }; + } + + template>::value>> + auto Filter(Range&& range, Predicate predicate, Projection projection) + { + return Filter(std::forward(range), query::detail::ProjectedPredicate{ std::move(predicate), std::move(projection) }); + } + + template>::value>> + auto Filter(Predicate predicate) + { + return detail::MakeClosure( + [predicate = std::move(predicate)](auto&& range) + { + return Filter(std::forward(range), predicate); + }); + } + + template>::value>> + auto Filter(Predicate predicate, Projection projection) + { + return Filter(query::detail::ProjectedPredicate{ std::move(predicate), std::move(projection) }); + } + + template>::value>> + auto Transform(Range&& range, Projection projection) + { + auto view = All(std::forward(range)); + return TransformView{ std::move(view), std::move(projection) }; + } + + template>::value>> + auto Transform(Projection projection) + { + return detail::MakeClosure( + [projection = std::move(projection)](auto&& range) + { + return Transform(std::forward(range), projection); + }); + } + + template>::value>> + auto Keys(Range&& range) + { + return Transform(std::forward(range), SelectFirst{}); + } + + inline auto Keys() + { + return Transform(SelectFirst{}); + } + + template>::value>> + auto Values(Range&& range) + { + return Transform(std::forward(range), SelectSecond{}); + } + + inline auto Values() + { + return Transform(SelectSecond{}); + } + + template>::value>> + auto Dereference(Range&& range) + { + return Transform(std::forward(range), SelectPointee{}); + } + + inline auto Dereference() + { + return Transform(SelectPointee{}); + } + + template>::value>> + auto Join(Range&& range) + { + auto view = All(std::forward(range)); + return JoinView{ std::move(view) }; + } + + inline auto Join() + { + return detail::MakeClosure( + [](auto&& range) + { + return Join(std::forward(range)); + }); + } + } + + // Declared outside `views` so that ordinary lookup finds it anywhere in cucumber::query. + template>::value>> + decltype(auto) operator|(Range&& range, const views::detail::Closure& closure) + { + return closure(std::forward(range)); + } +} + +#endif diff --git a/cpp/src/query/EnvelopeArchive.cpp b/cpp/src/query/EnvelopeArchive.cpp new file mode 100644 index 00000000..a7a64cb1 --- /dev/null +++ b/cpp/src/query/EnvelopeArchive.cpp @@ -0,0 +1,11 @@ +#include "cucumber/query/EnvelopeArchive.hpp" +#include "cucumber/messages/Envelope.hpp" +#include + +namespace cucumber::query +{ + const messages::Envelope& EnvelopeArchive::Store(messages::Envelope&& envelope) + { + return envelopes.emplace_back(std::move(envelope)); + } +} diff --git a/cpp/src/query/Lineage.cpp b/cpp/src/query/Lineage.cpp new file mode 100644 index 00000000..9f748463 --- /dev/null +++ b/cpp/src/query/Lineage.cpp @@ -0,0 +1,22 @@ +#include "cucumber/query/Lineage.hpp" + +namespace cucumber::query +{ + Lineage Lineage::operator+(const Lineage& other) const + { + Lineage combined; + + combined.gherkinDocument = (other.gherkinDocument != nullptr) ? other.gherkinDocument : gherkinDocument; + combined.feature = (other.feature != nullptr) ? other.feature : feature; + combined.background = (other.background != nullptr) ? other.background : background; + combined.rule = (other.rule != nullptr) ? other.rule : rule; + combined.ruleBackground = (other.ruleBackground != nullptr) ? other.ruleBackground : ruleBackground; + combined.scenario = (other.scenario != nullptr) ? other.scenario : scenario; + combined.examples = (other.examples != nullptr) ? other.examples : examples; + combined.examplesIndex = other.examplesIndex ? other.examplesIndex : examplesIndex; + combined.example = (other.example != nullptr) ? other.example : example; + combined.exampleIndex = other.exampleIndex ? other.exampleIndex : exampleIndex; + + return combined; + } +} diff --git a/cpp/src/query/NamingStrategy.cpp b/cpp/src/query/NamingStrategy.cpp new file mode 100644 index 00000000..13e7a062 --- /dev/null +++ b/cpp/src/query/NamingStrategy.cpp @@ -0,0 +1,99 @@ +#include "cucumber/query/NamingStrategy.hpp" +#include "cucumber/query/Lineage.hpp" +#include +#include +#include +#include +#include +#include + +namespace cucumber::query +{ + BuiltinNamingStrategy::BuiltinNamingStrategy(NamingStrategyLength length, NamingStrategyFeatureName featureName, NamingStrategyExampleName exampleName) + : length{ length } + , featureName{ featureName } + , exampleName{ exampleName } + {} + + std::string BuiltinNamingStrategy::Reduce(const Lineage& lineage, const messages::Pickle& pickle) const + { + static constexpr std::size_t namingStrategyPartsCount = 8; + + std::vector parts(namingStrategyPartsCount); + + if (lineage.feature && !lineage.feature->name.empty() && featureName == NamingStrategyFeatureName::include) + { + parts.emplace_back(lineage.feature->name); + } + + if (lineage.rule && !lineage.rule->name.empty()) + { + parts.emplace_back(lineage.rule->name); + } + + if (lineage.scenario && !lineage.scenario->name.empty()) + { + parts.emplace_back(lineage.scenario->name); + } + else + { + parts.emplace_back(pickle.name); + } + + if (lineage.examples && !lineage.examples->name.empty()) + { + parts.emplace_back(lineage.examples->name); + } + + if (lineage.example) + { + const auto exampleNumber = "#" + std::to_string(lineage.examplesIndex.value_or(0) + 1) + "." + std::to_string(lineage.exampleIndex.value_or(0) + 1); + + switch (exampleName) + { + case NamingStrategyExampleName::number: + parts.emplace_back(exampleNumber); + break; + case NamingStrategyExampleName::pickle: + parts.emplace_back(pickle.name); + break; + case NamingStrategyExampleName::numberAndPickleIfParameterized: + if (lineage.scenario && lineage.scenario->name != pickle.name) + { + parts.emplace_back(exampleNumber + ": " + pickle.name); + } + else + { + parts.emplace_back(exampleNumber); + } + break; + } + } + + if (this->length == NamingStrategyLength::shortName) + { + return parts.back(); + } + + return std::accumulate(parts.begin(), parts.end(), std::string{}, + [](const std::string& cumulative, const std::string& element) -> std::string + { + if (element.empty()) + { + return cumulative; + } + + if (cumulative.empty()) + { + return element; + } + + return cumulative + " - " + element; + }); + } + + std::unique_ptr CreateNamingStrategy(NamingStrategyLength length, NamingStrategyFeatureName featureName, NamingStrategyExampleName exampleName) + { + return std::make_unique(length, featureName, exampleName); + } +} diff --git a/cpp/src/query/NdjsonEnvelopeReader.cpp b/cpp/src/query/NdjsonEnvelopeReader.cpp new file mode 100644 index 00000000..a475fd26 --- /dev/null +++ b/cpp/src/query/NdjsonEnvelopeReader.cpp @@ -0,0 +1,23 @@ +#include "cucumber/query/NdjsonEnvelopeReader.hpp" +#include "cucumber/messages/Envelope.hpp" +#include +#include +#include +#include +#include + +namespace cucumber::query::detail +{ + std::optional TryReadNextEnvelope(std::istream& input) + { + std::string line; + if (!std::getline(input, line)) + { + return std::nullopt; + } + + messages::Envelope envelope{}; + envelope.from_json(nlohmann::json::parse(line)); + return envelope; + } +} diff --git a/cpp/src/query/Query.cpp b/cpp/src/query/Query.cpp new file mode 100644 index 00000000..d4f39e75 --- /dev/null +++ b/cpp/src/query/Query.cpp @@ -0,0 +1,783 @@ +#include "cucumber/query/Query.hpp" +#include "cucumber/messages/All.hpp" +#include "cucumber/messages/DurationUtil.hpp" +#include "cucumber/messages/TestStepResultStatus.hpp" +#include "cucumber/query/Lineage.hpp" +#include "cucumber/query/View.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace cucumber::query +{ + namespace + { + void SortBySeverity(std::vector& container) + { + std::sort(container.begin(), container.end(), + [](const auto& lhs, const auto& rhs) + { + using underlying_type = std::underlying_type_t; + return static_cast(lhs.testStepFinished->testStepResult.status) > static_cast(rhs.testStepFinished->testStepResult.status); + }); + } + + template + const Pointers& Empty() + { + static const Pointers empty; + return empty; + } + + template + const T* FindOne(const ById& container, const std::string& id) + { + const auto iter = container.find(id); + return iter != container.end() ? iter->second : nullptr; + } + + const Lineage* FindOne(const std::map& container, const std::string& id) + { + const auto iter = container.find(id); + return iter != container.end() ? &iter->second : nullptr; + } + + template + const Pointers& FindMany(const ManyById& container, const std::string& id) + { + const auto iter = container.find(id); + return iter != container.end() ? iter->second : Empty(); + } + } + + void Query::Update(const std::shared_ptr& envelope) + { + Update(*envelope); + } + + void Query::Update(const cucumber::messages::Envelope& envelope) + { + if (envelope.meta) + { + meta = std::addressof(*envelope.meta); + } + if (envelope.gherkinDocument) + { + UpdateGherkinDocument(*envelope.gherkinDocument); + } + if (envelope.pickle) + { + UpdatePickle(*envelope.pickle); + } + if (envelope.hook) + { + hookById[envelope.hook->id] = std::addressof(*envelope.hook); + } + if (envelope.stepDefinition) + { + stepDefinitionById[envelope.stepDefinition->id] = std::addressof(*envelope.stepDefinition); + } + if (envelope.testRunStarted) + { + testRunStarted = std::addressof(*envelope.testRunStarted); + } + if (envelope.testRunHookStarted) + { + UpdateTestRunHookStarted(*envelope.testRunHookStarted); + } + if (envelope.testRunHookFinished) + { + UpdateTestRunHookFinished(*envelope.testRunHookFinished); + } + if (envelope.testCase) + { + UpdateTestCase(*envelope.testCase); + } + if (envelope.testCaseStarted) + { + UpdateTestCaseStarted(*envelope.testCaseStarted); + } + if (envelope.testStepStarted) + { + testStepStartedByTestCaseStartedId[envelope.testStepStarted->testCaseStartedId].push_back(std::addressof(*envelope.testStepStarted)); + } + if (envelope.attachment) + { + UpdateAttachment(*envelope.attachment); + } + if (envelope.testStepFinished) + { + UpdateTestStepFinished(*envelope.testStepFinished); + } + if (envelope.testCaseFinished) + { + UpdateTestCaseFinished(*envelope.testCaseFinished); + } + if (envelope.testRunFinished) + { + testRunFinished = std::addressof(*envelope.testRunFinished); + } + if (envelope.suggestion) + { + suggestionsByPickleStepId[envelope.suggestion->pickleStepId] = std::addressof(*envelope.suggestion); + } + if (envelope.undefinedParameterType) + { + undefinedParameterTypes.push_back(std::addressof(*envelope.undefinedParameterType)); + } + } + + std::unordered_map Query::CountMostSevereTestStepResultStatus() const + { + std::unordered_map result{ + { messages::TestStepResultStatus::AMBIGUOUS, 0 }, + { messages::TestStepResultStatus::FAILED, 0 }, + { messages::TestStepResultStatus::PASSED, 0 }, + { messages::TestStepResultStatus::PENDING, 0 }, + { messages::TestStepResultStatus::SKIPPED, 0 }, + { messages::TestStepResultStatus::UNDEFINED, 0 }, + { messages::TestStepResultStatus::UNKNOWN, 0 }, + }; + + for (const auto& testCaseStarted : FindAllTestCaseStarted()) + { + auto testStepFinishedAndTestStep = FindTestStepFinishedAndTestStepBy(testCaseStarted); + if (!testStepFinishedAndTestStep.empty()) + { + SortBySeverity(testStepFinishedAndTestStep); + + ++result[testStepFinishedAndTestStep.front().testStepFinished->testStepResult.status]; + } + } + + return result; + } + + std::size_t Query::CountTestCasesStarted() const + { + return FindAllTestCaseStarted().size(); + } + + ValuesView Query::FindAllPickles() const + { + return pickleById | views::Values() | views::Dereference(); + } + + ValuesView Query::FindAllPickleSteps() const + { + return pickleStepById | views::Values() | views::Dereference(); + } + + ValuesView Query::FindAllStepDefinitions() const + { + return stepDefinitionById | views::Values() | views::Dereference(); + } + + FilteredValuesView Query::FindAllTestCaseStarted() const + { + return testCaseStartedById | views::Values() | views::Dereference() | + views::Filter(Predicate{ [this](const messages::TestCaseStarted& testCaseStarted) + { + const auto* testCaseFinished = FindTestCaseFinishedBy(testCaseStarted); + return testCaseFinished == nullptr || !testCaseFinished->willBeRetried; + } }); + } + + FilteredValuesView Query::FindAllTestCaseFinished() const + { + return testCaseFinishedByTestCaseStartedId | views::Values() | views::Dereference() | + views::Filter(Predicate{ [](const messages::TestCaseFinished& testCaseFinished) + { + return !testCaseFinished.willBeRetried; + } }); + } + + ValuesView Query::FindAllTestSteps() const + { + return testStepById | views::Values() | views::Dereference(); + } + + ValuesView Query::FindAllTestCases() const + { + return testCaseById | views::Values() | views::Dereference(); + } + + JoinedValuesView Query::FindAllTestStepStarted() const + { + return testStepStartedByTestCaseStartedId | views::Values() | views::Join() | views::Dereference(); + } + + JoinedValuesView Query::FindAllTestStepFinished() const + { + return testStepFinishedByTestCaseStartedId | views::Values() | views::Join() | views::Dereference(); + } + + ValuesView Query::FindAllTestRunHookStarted() const + { + return testRunHookStartedById | views::Values() | views::Dereference(); + } + + ValuesView Query::FindAllTestRunHookFinished() const + { + return testRunHookFinishedByTestRunHookStartedId | views::Values() | views::Dereference(); + } + + ElementsView Query::FindAllUndefinedParameterTypes() const + { + return undefinedParameterTypes | views::Dereference(); + } + + FilteredElementsView Query::FindAttachmentsBy(const messages::TestStepFinished& element) const + { + return FindMany(attachmentsByTestCaseStartedId, element.testCaseStartedId) | views::Dereference() | + views::Filter(Predicate{ [testStepId = element.testStepId](const messages::Attachment& attachment) + { + return attachment.testStepId == testStepId; + } }); + } + + ElementsView Query::FindAttachmentsBy(const messages::TestRunHookFinished& element) const + { + return FindMany(attachmentsByTestRunHookStartedId, element.testRunHookStartedId) | views::Dereference(); + } + + const messages::Hook* Query::FindHookBy(const messages::TestStep& element) const + { + if (element.hookId) + { + return FindOne(hookById, *element.hookId); + } + return nullptr; + } + + const messages::Hook* Query::FindHookBy(const messages::TestRunHookStarted& element) const + { + return FindOne(hookById, element.hookId); + } + + const messages::Hook* Query::FindHookBy(const messages::TestRunHookFinished& element) const + { + const auto* testRunHookStarted = FindTestRunHookStartedBy(element); + if (testRunHookStarted != nullptr) + { + return FindHookBy(*testRunHookStarted); + } + return nullptr; + } + + const messages::Meta* Query::FindMeta() const + { + return meta; + } + + const messages::TestStepResult* Query::FindMostSevereTestStepResultBy(const messages::TestCaseStarted& element) const + { + auto testStepFinishedAndTestStep = FindTestStepFinishedAndTestStepBy(element); + if (!testStepFinishedAndTestStep.empty()) + { + SortBySeverity(testStepFinishedAndTestStep); + + return std::addressof(testStepFinishedAndTestStep.front().testStepFinished->testStepResult); + } + return nullptr; + } + + const messages::TestStepResult* Query::FindMostSevereTestStepResultBy(const messages::TestCaseFinished& element) const + { + const auto* testCaseStarted = FindTestCaseStartedBy(element); + if (testCaseStarted != nullptr) + { + return FindMostSevereTestStepResultBy(*testCaseStarted); + } + return nullptr; + } + + const messages::Location* Query::FindLocationOf(const messages::Pickle& pickle) const + { + if (pickle.location) + { + return std::addressof(*pickle.location); + } + + const auto lineageAndPickle = FindLineageBy(pickle); + + if (lineageAndPickle) + { + const auto* lineage = lineageAndPickle->lineage; + + if (lineage->example) + { + return std::addressof(lineage->example->location); + } + + if (lineage->scenario) + { + return std::addressof(lineage->scenario->location); + } + } + + return nullptr; + } + + const messages::Pickle* Query::FindPickleBy(const messages::TestCaseStarted& element) const + { + const auto* testCase = FindTestCaseBy(element); + if (testCase != nullptr) + { + return FindOne(pickleById, testCase->pickleId); + } + return nullptr; + } + + const messages::Pickle* Query::FindPickleBy(const messages::TestCaseFinished& element) const + { + const auto* testCase = FindTestCaseBy(element); + if (testCase != nullptr) + { + return FindOne(pickleById, testCase->pickleId); + } + return nullptr; + } + + const messages::Pickle* Query::FindPickleBy(const messages::TestStepStarted& element) const + { + const auto* testCase = FindTestCaseBy(element); + if (testCase != nullptr) + { + return FindOne(pickleById, testCase->pickleId); + } + return nullptr; + } + + const messages::Pickle* Query::FindPickleBy(const messages::TestStepFinished& element) const + { + const auto* testCase = FindTestCaseBy(element); + if (testCase != nullptr) + { + return FindOne(pickleById, testCase->pickleId); + } + return nullptr; + } + + const messages::PickleStep* Query::FindPickleStepBy(const messages::TestStep& testStep) const + { + if (testStep.pickleStepId) + { + return FindOne(pickleStepById, *testStep.pickleStepId); + } + return nullptr; + } + + const messages::Step* Query::FindStepBy(const messages::PickleStep& pickleStep) const + { + return FindOne(stepById, pickleStep.astNodeIds.front()); + } + + OwningView Query::FindStepDefinitionsBy(const messages::TestStep& testStep) const + { + std::vector result; + + if (testStep.stepDefinitionIds) + { + for (const auto& stepDefinitionId : *testStep.stepDefinitionIds) + { + const auto* stepDefinition = FindOne(stepDefinitionById, stepDefinitionId); + if (stepDefinition != nullptr) + { + result.push_back(stepDefinition); + } + } + } + + return OwningView{ std::move(result), views::SelectPointee{} }; + } + + OwningView Query::FindSuggestionsBy(const messages::PickleStep& element) const + { + std::vector result; + + const auto* suggestion = FindOne(suggestionsByPickleStepId, element.id); + if (suggestion != nullptr) + { + result.push_back(suggestion); + } + + return OwningView{ std::move(result), views::SelectPointee{} }; + } + + OwningView Query::FindSuggestionsBy(const messages::Pickle& element) const + { + std::vector result; + + for (const auto& pickleStep : element.steps) + { + const auto* suggestion = FindOne(suggestionsByPickleStepId, pickleStep.id); + if (suggestion != nullptr) + { + result.push_back(suggestion); + } + } + + return OwningView{ std::move(result), views::SelectPointee{} }; + } + + const messages::StepDefinition* Query::FindUnambiguousStepDefinitionBy(const messages::TestStep& testStep) const + { + if (testStep.stepDefinitionIds && testStep.stepDefinitionIds->size() == 1) + { + return FindOne(stepDefinitionById, testStep.stepDefinitionIds->front()); + } + return nullptr; + } + + const messages::TestCase* Query::FindTestCaseBy(const messages::TestCaseStarted& element) const + { + return FindOne(testCaseById, element.testCaseId); + } + + const messages::TestCase* Query::FindTestCaseBy(const messages::TestCaseFinished& element) const + { + const auto* testCaseStarted = FindTestCaseStartedBy(element); + if (testCaseStarted != nullptr) + { + return FindTestCaseBy(*testCaseStarted); + } + return nullptr; + } + + const messages::TestCase* Query::FindTestCaseBy(const messages::TestStepStarted& element) const + { + const auto* testCaseStarted = FindTestCaseStartedBy(element); + if (testCaseStarted != nullptr) + { + return FindTestCaseBy(*testCaseStarted); + } + return nullptr; + } + + const messages::TestCase* Query::FindTestCaseBy(const messages::TestStepFinished& element) const + { + const auto* testCaseStarted = FindTestCaseStartedBy(element); + if (testCaseStarted != nullptr) + { + return FindTestCaseBy(*testCaseStarted); + } + return nullptr; + } + + std::optional Query::FindTestCaseDurationBy(const messages::TestCaseStarted& element) const + { + const auto* testCaseFinished = FindTestCaseFinishedBy(element); + if (testCaseFinished != nullptr) + { + return testCaseFinished->timestamp - element.timestamp; + } + return std::nullopt; + } + + std::optional Query::FindTestCaseDurationBy(const messages::TestCaseFinished& element) const + { + const auto* testCaseStarted = FindTestCaseStartedBy(element); + + if (testCaseStarted != nullptr) + { + return FindTestCaseDurationBy(*testCaseStarted); + } + + return std::nullopt; + } + + const messages::TestCaseStarted* Query::FindTestCaseStartedBy(const messages::TestCaseFinished& element) const + { + return FindOne(testCaseStartedById, element.testCaseStartedId); + } + + const messages::TestCaseStarted* Query::FindTestCaseStartedBy(const messages::TestStepStarted& element) const + { + return FindOne(testCaseStartedById, element.testCaseStartedId); + } + + const messages::TestCaseStarted* Query::FindTestCaseStartedBy(const messages::TestStepFinished& element) const + { + return FindOne(testCaseStartedById, element.testCaseStartedId); + } + + const messages::TestCaseFinished* Query::FindTestCaseFinishedBy(const messages::TestCaseStarted& testCaseStarted) const + { + return FindOne(testCaseFinishedByTestCaseStartedId, testCaseStarted.id); + } + + const messages::TestRunHookStarted* Query::FindTestRunHookStartedBy(const messages::TestRunHookFinished& testRunHookFinished) const + { + return FindOne(testRunHookStartedById, testRunHookFinished.testRunHookStartedId); + } + + const messages::TestRunHookFinished* Query::FindTestRunHookFinishedBy(const messages::TestRunHookStarted& testRunHookStarted) const + { + return FindOne(testRunHookFinishedByTestRunHookStartedId, testRunHookStarted.id); + } + + std::optional Query::FindTestRunDuration() const + { + if (testRunStarted != nullptr && testRunFinished != nullptr) + { + return testRunFinished->timestamp - testRunStarted->timestamp; + } + + return std::nullopt; + } + + const messages::TestRunFinished* Query::FindTestRunFinished() const + { + return testRunFinished; + } + + const messages::TestRunStarted* Query::FindTestRunStarted() const + { + return testRunStarted; + } + + const messages::TestStep* Query::FindTestStepBy(const messages::TestStepStarted& element) const + { + return FindOne(testStepById, element.testStepId); + } + + const messages::TestStep* Query::FindTestStepBy(const messages::TestStepFinished& element) const + { + return FindOne(testStepById, element.testStepId); + } + + ElementsView Query::FindTestStepsStartedBy(const messages::TestCaseStarted& testCaseStarted) const + { + return FindMany(testStepStartedByTestCaseStartedId, testCaseStarted.id) | views::Dereference(); + } + + ElementsView Query::FindTestStepsStartedBy(const messages::TestCaseFinished& testCaseFinished) const + { + return FindMany(testStepStartedByTestCaseStartedId, testCaseFinished.testCaseStartedId) | views::Dereference(); + } + + ElementsView Query::FindTestStepsFinishedBy(const messages::TestCaseStarted& element) const + { + return FindMany(testStepFinishedByTestCaseStartedId, element.id) | views::Dereference(); + } + + ElementsView Query::FindTestStepsFinishedBy(const messages::TestCaseFinished& element) const + { + return FindMany(testStepFinishedByTestCaseStartedId, element.testCaseStartedId) | views::Dereference(); + } + + std::vector Query::FindTestStepFinishedAndTestStepBy(const messages::TestCaseStarted& testCaseStarted) const + { + std::vector result; + + for (const auto& testStepFinished : FindTestStepsFinishedBy(testCaseStarted)) + { + const auto* testStep = FindTestStepBy(testStepFinished); + if (testStep != nullptr) + { + result.emplace_back(TestStepFinishedAndTestStep{ &testStepFinished, testStep }); + } + } + + return result; + } + + std::optional Query::FindLineageBy(const messages::Pickle& element) const + { + const auto* lineage = FindOne(lineageById, element.astNodeIds.back()); + + if (lineage != nullptr) + { + return LineageAndPickle{ lineage, &element }; + } + + return std::nullopt; + } + + std::optional Query::FindLineageBy(const messages::TestCaseStarted& element) const + { + const auto* pickle = FindPickleBy(element); + + if (pickle != nullptr) + { + return FindLineageBy(*pickle); + } + + return std::nullopt; + } + + std::optional Query::FindLineageBy(const messages::TestCaseFinished& element) const + { + const auto* pickle = FindPickleBy(element); + + if (pickle != nullptr) + { + return FindLineageBy(*pickle); + } + + return std::nullopt; + } + + std::vector Query::AllTestCaseStarted() const + { + std::vector result; + + for (const auto& testCaseStarted : FindAllTestCaseStarted()) + { + result.push_back(&testCaseStarted); + } + + return result; + } + + std::vector Query::AllTestCaseFinished() const + { + std::vector result; + + for (const auto& testCaseFinished : FindAllTestCaseFinished()) + { + result.push_back(&testCaseFinished); + } + + return result; + } + + void Query::UpdateGherkinDocument(const messages::GherkinDocument& gherkinDocument) + { + if (gherkinDocument.feature) + { + UpdateFeature(*gherkinDocument.feature, Lineage{ &gherkinDocument }); + } + } + + void Query::UpdateFeature(const messages::Feature& feature, Lineage lineage) + { + for (const auto& featureChild : feature.children) + { + if (featureChild.background) + { + lineage.background = std::addressof(*featureChild.background); + UpdateSteps(featureChild.background->steps); + } + + if (featureChild.scenario) + { + UpdateScenario(*featureChild.scenario, lineage + Lineage{ nullptr, &feature }); + } + + if (featureChild.rule) + { + UpdateRule(*featureChild.rule, lineage + Lineage{ nullptr, &feature }); + } + } + } + + void Query::UpdateRule(const messages::Rule& rule, Lineage lineage) + { + for (const auto& ruleChild : rule.children) + { + if (ruleChild.background) + { + lineage.ruleBackground = std::addressof(*ruleChild.background); + UpdateSteps(ruleChild.background->steps); + } + + if (ruleChild.scenario) + { + UpdateScenario(*ruleChild.scenario, lineage + Lineage{ nullptr, nullptr, nullptr, &rule }); + } + } + } + + void Query::UpdateScenario(const messages::Scenario& scenario, const Lineage& lineage) + { + lineageById[scenario.id] = lineage + Lineage{ nullptr, nullptr, nullptr, nullptr, nullptr, &scenario }; + + std::size_t examplesIndex = 0; + for (const auto& examples : scenario.examples) + { + lineageById[examples.id] = lineage + Lineage{ nullptr, nullptr, nullptr, nullptr, nullptr, &scenario, std::addressof(examples), examplesIndex }; + + std::size_t exampleIndex = 0; + for (const auto& example : examples.tableBody) + { + lineageById[example.id] = lineage + Lineage{ nullptr, nullptr, nullptr, nullptr, nullptr, &scenario, std::addressof(examples), examplesIndex, std::addressof(example), exampleIndex }; + ++exampleIndex; + } + ++examplesIndex; + } + + UpdateSteps(scenario.steps); + } + + void Query::UpdateSteps(const std::vector& steps) + { + for (const auto& step : steps) + { + stepById[step.id] = std::addressof(step); + } + } + + void Query::UpdatePickle(const messages::Pickle& pickle) + { + pickleById[pickle.id] = &pickle; + for (const auto& pickleStep : pickle.steps) + { + pickleStepById[pickleStep.id] = std::addressof(pickleStep); + } + } + + void Query::UpdateTestRunHookStarted(const messages::TestRunHookStarted& testRunHookStarted) + { + testRunHookStartedById[testRunHookStarted.id] = &testRunHookStarted; + } + + void Query::UpdateTestRunHookFinished(const messages::TestRunHookFinished& testRunHookFinished) + { + testRunHookFinishedByTestRunHookStartedId[testRunHookFinished.testRunHookStartedId] = &testRunHookFinished; + } + + void Query::UpdateTestCase(const messages::TestCase& testCase) + { + for (const auto& testStep : testCase.testSteps) + { + testStepById[testStep.id] = std::addressof(testStep); + } + testCaseById[testCase.id] = &testCase; + } + + void Query::UpdateTestCaseStarted(const messages::TestCaseStarted& testCaseStarted) + { + testCaseStartedById[testCaseStarted.id] = &testCaseStarted; + } + + void Query::UpdateAttachment(const messages::Attachment& attachment) + { + if (attachment.testCaseStartedId) + { + attachmentsByTestCaseStartedId[*attachment.testCaseStartedId].push_back(&attachment); + } + if (attachment.testRunHookStartedId) + { + attachmentsByTestRunHookStartedId[*attachment.testRunHookStartedId].push_back(&attachment); + } + } + + void Query::UpdateTestStepFinished(const messages::TestStepFinished& testStepFinished) + { + testStepFinishedByTestCaseStartedId[testStepFinished.testCaseStartedId].push_back(&testStepFinished); + } + + void Query::UpdateTestCaseFinished(const messages::TestCaseFinished& testCaseFinished) + { + testCaseFinishedByTestCaseStartedId[testCaseFinished.testCaseStartedId] = &testCaseFinished; + } +} diff --git a/cpp/test/CMakeLists.txt b/cpp/test/CMakeLists.txt new file mode 100644 index 00000000..683be516 --- /dev/null +++ b/cpp/test/CMakeLists.txt @@ -0,0 +1,31 @@ +add_executable(cucumber_query_lib.test) + +target_sources(cucumber_query_lib.test + PRIVATE + TestQuery.cpp + TestView.cpp +) + +target_link_libraries(cucumber_query_lib.test + PRIVATE + cucumber::query + GTest::gmock_main +) + +target_compile_definitions(cucumber_query_lib.test + PRIVATE + TESTDATA_SRC="${PROJECT_SOURCE_DIR}/../testdata/src" +) + +include(GoogleTest) +gtest_discover_tests(cucumber_query_lib.test) + +add_custom_target( + check-testdata-coverage + COMMAND ${CMAKE_COMMAND} + -DTEST_BINARY=$ + -DTESTDATA_SRC=${PROJECT_SOURCE_DIR}/../testdata/src + -P ${CMAKE_CURRENT_SOURCE_DIR}/CheckTestdataCoverage.cmake + DEPENDS cucumber_query_lib.test + COMMENT "Checking testdata coverage in C++ tests" +) diff --git a/cpp/test/CheckTestdataCoverage.cmake b/cpp/test/CheckTestdataCoverage.cmake new file mode 100644 index 00000000..ea047599 --- /dev/null +++ b/cpp/test/CheckTestdataCoverage.cmake @@ -0,0 +1,91 @@ +# Verifies that every query type and naming strategy variant in testdata/src +# has a corresponding TEST_P in the C++ acceptance tests. +# +# Required variables (passed via -D): +# TEST_BINARY — path to the built cucumber_query_lib.test binary +# TESTDATA_SRC — path to testdata/src + +execute_process( + COMMAND "${TEST_BINARY}" --gtest_list_tests + OUTPUT_VARIABLE raw_output + RESULT_VARIABLE result_code + OUTPUT_STRIP_TRAILING_WHITESPACE +) + +if(NOT result_code EQUAL 0) + message(FATAL_ERROR "Failed to list tests: ${TEST_BINARY} --gtest_list_tests") +endif() + +string(REPLACE "\r\n" "\n" raw_output "${raw_output}") +string(REPLACE "\n" ";" lines "${raw_output}") + +set(in_query_suite FALSE) +set(in_naming_suite FALSE) +set(cpp_query_names "") +set(cpp_naming_variants "") + +foreach(line IN LISTS lines) + if(line MATCHES "^Acceptance/QueryAcceptanceTest\\.") + set(in_query_suite TRUE) + set(in_naming_suite FALSE) + elseif(line MATCHES "^Acceptance/NamingStrategyAcceptanceTest\\.") + set(in_query_suite FALSE) + set(in_naming_suite TRUE) + elseif(line MATCHES "^[^ ]") + set(in_query_suite FALSE) + set(in_naming_suite FALSE) + elseif(in_query_suite AND line MATCHES "^ [^ ]") + string(REGEX REPLACE "^ ([^ /]+)/.*$" "\\1" test_name "${line}") + list(APPEND cpp_query_names "${test_name}") + elseif(in_naming_suite AND line MATCHES "^ [^ ]") + string(REGEX REPLACE "^ ([^ /]+)/.*$" "\\1" test_name "${line}") + # gtest uses underscores in test names; testdata file variants use hyphens + string(REPLACE "_" "-" variant_name "${test_name}") + list(APPEND cpp_naming_variants "${variant_name}") + endif() +endforeach() + +list(REMOVE_DUPLICATES cpp_query_names) +list(REMOVE_DUPLICATES cpp_naming_variants) + +file(GLOB result_files "${TESTDATA_SRC}/*.results.json") +set(testdata_query_names "") +foreach(f IN LISTS result_files) + get_filename_component(filename "${f}" NAME) + string(REGEX REPLACE "^[^.]+\\.(.+)\\.results\\.json$" "\\1" query_name "${filename}") + list(APPEND testdata_query_names "${query_name}") +endforeach() +list(REMOVE_DUPLICATES testdata_query_names) + +file(GLOB naming_files "${TESTDATA_SRC}/*.naming-strategy.*.txt") +set(testdata_naming_variants "") +foreach(f IN LISTS naming_files) + get_filename_component(filename "${f}" NAME) + string(REGEX REPLACE "^[^.]+\\.naming-strategy\\.(.+)\\.txt$" "\\1" variant "${filename}") + list(APPEND testdata_naming_variants "${variant}") +endforeach() +list(REMOVE_DUPLICATES testdata_naming_variants) + +set(found_gaps FALSE) + +foreach(name IN LISTS testdata_query_names) + list(FIND cpp_query_names "${name}" query_index) + if(query_index EQUAL -1) + message(WARNING "Query type '${name}' exists in testdata but has no TEST_P in QueryAcceptanceTest") + set(found_gaps TRUE) + endif() +endforeach() + +foreach(variant IN LISTS testdata_naming_variants) + list(FIND cpp_naming_variants "${variant}" variant_index) + if(variant_index EQUAL -1) + message(WARNING "Naming strategy variant '${variant}' exists in testdata but has no TEST_P in NamingStrategyAcceptanceTest") + set(found_gaps TRUE) + endif() +endforeach() + +if(found_gaps) + message(FATAL_ERROR "C++ tests are missing coverage for new testdata. Add TEST_P entries to TestQuery.cpp.") +endif() + +message(STATUS "All testdata query types and naming strategy variants are covered.") diff --git a/cpp/test/TestQuery.cpp b/cpp/test/TestQuery.cpp new file mode 100644 index 00000000..135d4545 --- /dev/null +++ b/cpp/test/TestQuery.cpp @@ -0,0 +1,884 @@ +#include "cucumber/messages/All.hpp" +#include "cucumber/messages/TestStepResultStatus.hpp" +#include "cucumber/query/EnvelopeArchive.hpp" +#include "cucumber/query/NamingStrategy.hpp" +#include "cucumber/query/NdjsonEnvelopeReader.hpp" +#include "cucumber/query/Query.hpp" +#include "nlohmann/json.hpp" +#include "nlohmann/json_fwd.hpp" +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace cucumber::query +{ + namespace + { + bool EndsWith(std::string_view value, std::string_view suffix) + { + return value.size() >= suffix.size() && value.compare(value.size() - suffix.size(), suffix.size(), suffix) == 0; + } + + template + nlohmann::json ToJson(const std::optional& value) + { + return value.has_value() ? nlohmann::json(*value) : nlohmann::json(nullptr); + } + + struct Expectation + { + std::string_view infix; + std::string_view suffix; + }; + + struct DataSet + { + std::filesystem::path source; + }; + + // Determines how ctest names the generated tests. + void PrintTo(const DataSet& dataSet, std::ostream* stream) + { + *stream << dataSet.source.stem().string(); + } + + // Data sets are `.ndjson`, their expectations ``. + std::vector GetDataSets(const Expectation& expectation) + { + std::vector sources; + std::vector expectations; + + for (const auto& entry : std::filesystem::directory_iterator{ std::filesystem::path{ TESTDATA_SRC } }) + { + auto fileName = entry.path().filename().string(); + + if (entry.path().extension() == ".ndjson") + { + sources.push_back(entry.path()); + } + else if (EndsWith(fileName, expectation.suffix)) + { + expectations.push_back(std::move(fileName)); + } + } + + std::vector dataSets; + + for (auto& source : sources) + { + const auto prefix = source.stem().string() + std::string{ expectation.infix }; + const auto hasExpectations = std::any_of(expectations.begin(), expectations.end(), + [&prefix](const std::string& expectation) -> bool + { + return expectation.compare(0, prefix.size(), prefix) == 0; + }); + + if (hasExpectations) + { + dataSets.push_back(DataSet{ std::move(source) }); + } + } + + std::sort(dataSets.begin(), dataSets.end(), + [](const DataSet& lhs, const DataSet& rhs) -> bool + { + return lhs.source < rhs.source; + }); + + return dataSets; + } + + std::filesystem::path ExpectedPath(const std::filesystem::path& dataSet, const std::string& suffix) + { + return dataSet.parent_path() / (dataSet.stem().string() + suffix); + } + + std::string DataSetName(const testing::TestParamInfo& info) + { + auto name = info.param.source.stem().string(); + + std::replace_if( + name.begin(), name.end(), + [](unsigned char character) -> bool + { + return std::isalnum(character) == 0; + }, + '_'); + + return name; + } + + void LoadQuery(const std::filesystem::path& source, EnvelopeArchive& archive, Query& query) + { + std::ifstream ifstream{ source }; + LoadNdjson(archive, ifstream, + [&query](const messages::Envelope& envelope) -> void + { + query.Update(envelope); + }); + } + + std::int32_t ReversePickleComparator(const messages::Pickle& lhs, const messages::Pickle& rhs) + { + if (lhs.uri != rhs.uri) + { + return static_cast(lhs.uri.compare(rhs.uri)); + } + if (!lhs.location || !rhs.location) + { + return 0; + } + if (lhs.location->line != rhs.location->line) + { + return static_cast(rhs.location->line) - static_cast(lhs.location->line); + } + return static_cast(rhs.location->column.value_or(0)) - static_cast(lhs.location->column.value_or(0)); + } + + struct QueryAcceptanceTest : testing::TestWithParam + { + protected: + void SetUp() override + { + LoadQuery(GetParam().source, archive, query); + } + + static void Verify(std::string_view queryName, const nlohmann::json& actual) + { + const auto expected = ExpectedPath(GetParam().source, "." + std::string{ queryName } + ".results.json"); + + if (!std::filesystem::exists(expected)) + { + GTEST_SKIP() << "No expected results at " << expected; + } + + std::ifstream ifstream{ expected }; + EXPECT_THAT(actual, testing::Eq(nlohmann::json::parse(ifstream))); + } + + EnvelopeArchive archive; + Query query; + }; + + INSTANTIATE_TEST_SUITE_P(Acceptance, QueryAcceptanceTest, testing::ValuesIn(GetDataSets({ ".", ".results.json" })), DataSetName); + + TEST_P(QueryAcceptanceTest, findAllPickles) + { + Verify("findAllPickles", query.FindAllPickles().size()); + } + + TEST_P(QueryAcceptanceTest, findAllPickleSteps) + { + Verify("findAllPickleSteps", query.FindAllPickleSteps().size()); + } + + TEST_P(QueryAcceptanceTest, findAllStepDefinitions) + { + Verify("findAllStepDefinitions", query.FindAllStepDefinitions().size()); + } + + TEST_P(QueryAcceptanceTest, findAllTestCaseFinished) + { + Verify("findAllTestCaseFinished", query.FindAllTestCaseFinished().size()); + } + + TEST_P(QueryAcceptanceTest, findAllTestCases) + { + Verify("findAllTestCases", query.FindAllTestCases().size()); + } + + TEST_P(QueryAcceptanceTest, findAllTestCaseStarted) + { + Verify("findAllTestCaseStarted", query.FindAllTestCaseStarted().size()); + } + + TEST_P(QueryAcceptanceTest, findAllTestRunHookFinished) + { + Verify("findAllTestRunHookFinished", query.FindAllTestRunHookFinished().size()); + } + + TEST_P(QueryAcceptanceTest, findAllTestRunHookStarted) + { + Verify("findAllTestRunHookStarted", query.FindAllTestRunHookStarted().size()); + } + + TEST_P(QueryAcceptanceTest, findAllTestStepFinished) + { + Verify("findAllTestStepFinished", query.FindAllTestStepFinished().size()); + } + + TEST_P(QueryAcceptanceTest, findAllTestSteps) + { + Verify("findAllTestSteps", query.FindAllTestSteps().size()); + } + + TEST_P(QueryAcceptanceTest, findAllTestStepStarted) + { + Verify("findAllTestStepStarted", query.FindAllTestStepStarted().size()); + } + + TEST_P(QueryAcceptanceTest, countMostSevereTestStepResultStatus) + { + nlohmann::json actual; + + for (const auto& [status, count] : query.CountMostSevereTestStepResultStatus()) + { + actual[to_string(status)] = count; + } + + Verify("countMostSevereTestStepResultStatus", actual); + } + + TEST_P(QueryAcceptanceTest, countTestCasesStarted) + { + Verify("countTestCasesStarted", query.CountTestCasesStarted()); + } + + TEST_P(QueryAcceptanceTest, findAllTestCaseFinishedOrderBy) + { + const auto allResults = query.FindAllTestCaseFinishedOrderBy( + [](const query::Query& query, const auto& element) + { + return query.FindPickleBy(element); + }, + ReversePickleComparator); + + nlohmann::json actual; + for (const auto& testCaseFinished : allResults) + { + actual.push_back(testCaseFinished.testCaseStartedId); + } + + Verify("findAllTestCaseFinishedOrderBy", actual); + } + + TEST_P(QueryAcceptanceTest, findAllTestCaseStartedOrderBy) + { + const auto allResults = query.FindAllTestCaseStartedOrderBy( + [](const query::Query& query, const auto& element) + { + return query.FindPickleBy(element); + }, + ReversePickleComparator); + + nlohmann::json actual; + for (const auto& testCaseStarted : allResults) + { + actual.push_back(testCaseStarted.id); + } + + Verify("findAllTestCaseStartedOrderBy", actual); + } + + TEST_P(QueryAcceptanceTest, findAllUndefinedParameterTypes) + { + nlohmann::json actual = nlohmann::json::array(); + + for (const auto& undefinedParameterType : query.FindAllUndefinedParameterTypes()) + { + actual.push_back({ undefinedParameterType.name, undefinedParameterType.expression }); + } + + Verify("findAllUndefinedParameterTypes", actual); + } + + TEST_P(QueryAcceptanceTest, findAttachmentsBy) + { + nlohmann::json actual = { { "testStepFinished", nlohmann::json::array() }, { "testRunHookFinished", nlohmann::json::array() } }; + + const auto& allTestCaseStarted = query.FindAllTestCaseStarted(); + for (const auto& testCaseStarted : allTestCaseStarted) + { + const auto& allFinishedSteps = query.FindTestStepsFinishedBy(testCaseStarted); + for (const auto& testStepFinished : allFinishedSteps) + { + const auto& attachments = query.FindAttachmentsBy(testStepFinished); + + for (const auto& attachment : attachments) + { + actual["testStepFinished"].push_back({ ToJson(attachment.testStepId), ToJson(attachment.testCaseStartedId), attachment.mediaType, attachment.contentEncoding }); + } + } + } + + const auto& allTestRunHookFinished = query.FindAllTestRunHookFinished(); + for (const auto& testRunHookFinished : allTestRunHookFinished) + { + const auto& attachments = query.FindAttachmentsBy(testRunHookFinished); + + for (const auto& attachment : attachments) + { + actual["testRunHookFinished"].push_back({ ToJson(attachment.testRunHookStartedId), attachment.mediaType, attachment.contentEncoding }); + } + } + + Verify("findAttachmentsBy", actual); + } + + TEST_P(QueryAcceptanceTest, findHookBy) + { + const auto findHookBy = [this](const auto& testSteps) + { + nlohmann::json actual = nlohmann::json::array(); + + for (const auto& testStep : testSteps) + { + const auto* hook = query.FindHookBy(testStep); + if (hook != nullptr) + { + actual.push_back(hook->id); + } + } + + return actual; + }; + + nlohmann::json actual; + + actual["testStep"] = findHookBy(query.FindAllTestSteps()); + actual["testRunHookStarted"] = findHookBy(query.FindAllTestRunHookStarted()); + actual["testRunHookFinished"] = findHookBy(query.FindAllTestRunHookFinished()); + + Verify("findHookBy", actual); + } + + TEST_P(QueryAcceptanceTest, findLineageBy) + { + const auto namingStrategy = CreateNamingStrategy(NamingStrategyLength::longName, NamingStrategyFeatureName::include, NamingStrategyExampleName::number); + + const auto findLineageBy = [this, &namingStrategy](const auto& items) + { + nlohmann::json actual = nlohmann::json::array(); + + for (const auto& item : items) + { + const auto& lineageAndPickle = query.FindLineageBy(item); + if (lineageAndPickle) + { + const auto& [lineage, pickle] = *lineageAndPickle; + actual.push_back(namingStrategy->Reduce(*lineage, *pickle)); + } + } + + return actual; + }; + + nlohmann::json actual; + + actual["testCaseStarted"] = findLineageBy(query.FindAllTestCaseStarted()); + actual["testCaseFinished"] = findLineageBy(query.FindAllTestCaseFinished()); + actual["pickle"] = findLineageBy(query.FindAllPickles()); + + Verify("findLineageBy", actual); + } + + TEST_P(QueryAcceptanceTest, findLocationOf) + { + nlohmann::json actual = nlohmann::json::array(); + + for (const auto& pickle : query.FindAllPickles()) + { + const auto* location = query.FindLocationOf(pickle); + if (location != nullptr) + { + actual.push_back({ { "line", location->line }, { "column", ToJson(location->column) } }); + } + } + + Verify("findLocationOf", actual); + } + + TEST_P(QueryAcceptanceTest, findMeta) + { + const auto* meta = query.FindMeta(); + + nlohmann::json actual; + if (meta != nullptr) + { + actual = meta->implementation.name; + } + + Verify("findMeta", actual); + } + + TEST_P(QueryAcceptanceTest, findMostSevereTestStepResultBy) + { + const auto findMostSevereTestStepResultBy = [this](const auto& items) + { + nlohmann::json actual = nlohmann::json::array(); + + for (const auto& item : items) + { + const auto* mostSevereTestStepResult = query.FindMostSevereTestStepResultBy(item); + if (mostSevereTestStepResult != nullptr) + { + actual.emplace_back(to_string(mostSevereTestStepResult->status)); + } + } + + return actual; + }; + + nlohmann::json actual; + + actual["testCaseStarted"] = findMostSevereTestStepResultBy(query.FindAllTestCaseStarted()); + actual["testCaseFinished"] = findMostSevereTestStepResultBy(query.FindAllTestCaseFinished()); + + Verify("findMostSevereTestStepResultBy", actual); + } + + TEST_P(QueryAcceptanceTest, findPickleBy) + { + const auto findPickleBy = [this](const auto& items) + { + nlohmann::json actual = nlohmann::json::array(); + + for (const auto& item : items) + { + const auto* pickle = query.FindPickleBy(item); + if (pickle != nullptr) + { + actual.push_back(pickle->name); + } + } + + return actual; + }; + + nlohmann::json actual; + + actual["testCaseStarted"] = findPickleBy(query.FindAllTestCaseStarted()); + actual["testCaseFinished"] = findPickleBy(query.FindAllTestCaseFinished()); + actual["testStepStarted"] = findPickleBy(query.FindAllTestStepStarted()); + actual["testStepFinished"] = findPickleBy(query.FindAllTestStepFinished()); + + Verify("findPickleBy", actual); + } + + TEST_P(QueryAcceptanceTest, findPickleStepBy) + { + nlohmann::json actual = nlohmann::json::array(); + + for (const auto& testStep : query.FindAllTestSteps()) + { + const auto* pickleStep = query.FindPickleStepBy(testStep); + if (pickleStep != nullptr) + { + actual.emplace_back(pickleStep->text); + } + } + + Verify("findPickleStepBy", actual); + } + + TEST_P(QueryAcceptanceTest, findStepBy) + { + nlohmann::json actual = nlohmann::json::array(); + + for (const auto& pickleStep : query.FindAllPickleSteps()) + { + const auto* step = query.FindStepBy(pickleStep); + if (step != nullptr) + { + actual.emplace_back(step->text); + } + } + + Verify("findStepBy", actual); + } + + TEST_P(QueryAcceptanceTest, findStepDefinitionsBy) + { + nlohmann::json actual = nlohmann::json::array(); + + for (const auto& testStep : query.FindAllTestSteps()) + { + auto& actualIds = actual.emplace_back(nlohmann::json::array()); + + for (const auto& stepDefinition : query.FindStepDefinitionsBy(testStep)) + { + actualIds.emplace_back(stepDefinition.id); + } + } + + Verify("findStepDefinitionsBy", actual); + } + + TEST_P(QueryAcceptanceTest, findSuggestionsBy) + { + const auto findSuggestionsBy = [this](const auto& items) + { + nlohmann::json actual = nlohmann::json::array(); + + for (const auto& item : items) + { + for (const auto& suggestion : query.FindSuggestionsBy(item)) + { + actual.emplace_back(suggestion.id); + } + } + + return actual; + }; + + nlohmann::json actual; + + actual["pickleStep"] = findSuggestionsBy(query.FindAllPickleSteps()); + actual["pickle"] = findSuggestionsBy(query.FindAllPickles()); + + Verify("findSuggestionsBy", actual); + } + + TEST_P(QueryAcceptanceTest, findTestCaseBy) + { + const auto findTestCaseBy = [this](const auto& items) + { + nlohmann::json actual = nlohmann::json::array(); + + for (const auto& item : items) + { + const auto* testCase = query.FindTestCaseBy(item); + if (testCase != nullptr) + { + actual.push_back(testCase->id); + } + } + return actual; + }; + + nlohmann::json actual; + + actual["testCaseStarted"] = findTestCaseBy(query.FindAllTestCaseStarted()); + actual["testCaseFinished"] = findTestCaseBy(query.FindAllTestCaseFinished()); + actual["testStepStarted"] = findTestCaseBy(query.FindAllTestStepStarted()); + actual["testStepFinished"] = findTestCaseBy(query.FindAllTestStepFinished()); + + Verify("findTestCaseBy", actual); + } + + TEST_P(QueryAcceptanceTest, findTestCaseDurationBy) + { + const auto findTestCaseDurationBy = [this](const auto& items) + { + nlohmann::json actual = nlohmann::json::array(); + + for (const auto& item : items) + { + const auto& testCase = query.FindTestCaseDurationBy(item); + if (testCase) + { + testCase->to_json(actual.emplace_back()); + } + } + return actual; + }; + + nlohmann::json actual; + + actual["testCaseStarted"] = findTestCaseDurationBy(query.FindAllTestCaseStarted()); + actual["testCaseFinished"] = findTestCaseDurationBy(query.FindAllTestCaseFinished()); + + Verify("findTestCaseDurationBy", actual); + } + + TEST_P(QueryAcceptanceTest, findTestCaseFinishedBy) + { + nlohmann::json actual = nlohmann::json::array(); + + for (const auto& testCaseStarted : query.FindAllTestCaseStarted()) + { + const auto* testCaseFinished = query.FindTestCaseFinishedBy(testCaseStarted); + if (testCaseFinished != nullptr) + { + actual.push_back(testCaseFinished->testCaseStartedId); + } + } + + Verify("findTestCaseFinishedBy", actual); + } + + TEST_P(QueryAcceptanceTest, findTestCaseStartedBy) + { + const auto findTestCaseStartedBy = [this](const auto& items) + { + nlohmann::json actual = nlohmann::json::array(); + for (const auto& testCaseFinished : items) + { + const auto* testCaseStarted = query.FindTestCaseStartedBy(testCaseFinished); + if (testCaseStarted != nullptr) + { + actual.push_back(testCaseStarted->id); + } + } + + return actual; + }; + + nlohmann::json actual; + + actual["testCaseFinished"] = findTestCaseStartedBy(query.FindAllTestCaseFinished()); + actual["testStepStarted"] = findTestCaseStartedBy(query.FindAllTestStepStarted()); + actual["testStepFinished"] = findTestCaseStartedBy(query.FindAllTestStepFinished()); + + Verify("findTestCaseStartedBy", actual); + } + + TEST_P(QueryAcceptanceTest, findTestRunDuration) + { + nlohmann::json actual; + + const auto testRunDuration = query.FindTestRunDuration(); + if (testRunDuration) + { + testRunDuration->to_json(actual); + } + + Verify("findTestRunDuration", actual); + } + + TEST_P(QueryAcceptanceTest, findTestRunFinished) + { + nlohmann::json actual; + + const auto* testRunFinished = query.FindTestRunFinished(); + if (testRunFinished != nullptr) + { + testRunFinished->to_json(actual); + } + + Verify("findTestRunFinished", actual); + } + + TEST_P(QueryAcceptanceTest, findTestRunHookFinishedBy) + { + nlohmann::json actual = nlohmann::json::array(); + + for (const auto& testRunHookStarted : query.FindAllTestRunHookStarted()) + { + const auto* testRunHookFinished = query.FindTestRunHookFinishedBy(testRunHookStarted); + if (testRunHookFinished != nullptr) + { + actual.emplace_back(testRunHookFinished->testRunHookStartedId); + } + } + + Verify("findTestRunHookFinishedBy", actual); + } + + TEST_P(QueryAcceptanceTest, findTestRunHookStartedBy) + { + nlohmann::json actual = nlohmann::json::array(); + + for (const auto& testRunHookFinished : query.FindAllTestRunHookFinished()) + { + const auto* testRunHookStarted = query.FindTestRunHookStartedBy(testRunHookFinished); + if (testRunHookStarted != nullptr) + { + actual.emplace_back(testRunHookStarted->id); + } + } + + Verify("findTestRunHookStartedBy", actual); + } + + TEST_P(QueryAcceptanceTest, findTestRunStarted) + { + nlohmann::json actual; + + const auto* testRunStarted = query.FindTestRunStarted(); + if (testRunStarted != nullptr) + { + testRunStarted->to_json(actual); + } + + Verify("findTestRunStarted", actual); + } + + TEST_P(QueryAcceptanceTest, findTestStepBy) + { + nlohmann::json actual{ + { "testStepStarted", nlohmann::json::array() }, + { "testStepFinished", nlohmann::json::array() }, + }; + + const auto findTestStepBy = [&](const auto& testSteps, const char* key) + { + for (const auto& testStepEvent : testSteps) + { + const auto* testStep = query.FindTestStepBy(testStepEvent); + if (testStep != nullptr) + { + actual[key].emplace_back(testStep->id); + } + } + }; + + for (const auto& item : query.FindAllTestCaseStarted()) + { + findTestStepBy(query.FindTestStepsStartedBy(item), "testStepStarted"); + findTestStepBy(query.FindTestStepsFinishedBy(item), "testStepFinished"); + } + + Verify("findTestStepBy", actual); + } + + TEST_P(QueryAcceptanceTest, findTestStepFinishedAndTestStepBy) + { + nlohmann::json actual = nlohmann::json::array(); + + for (const auto& testCaseStarted : query.FindAllTestCaseStarted()) + { + for (const auto& [testStepFinished, testStep] : query.FindTestStepFinishedAndTestStepBy(testCaseStarted)) + { + actual.push_back({ testStepFinished->testStepId, testStep->id }); + } + } + + Verify("findTestStepFinishedAndTestStepBy", actual); + } + + TEST_P(QueryAcceptanceTest, findTestStepsFinishedBy) + { + const auto findTestStepsFinishedBy = [&](const auto& items) + { + auto actual = nlohmann::json::array(); + + for (const auto& item : items) + { + auto& nested = actual.emplace_back(nlohmann::json::array()); + const auto& testStepsFinished = query.FindTestStepsFinishedBy(item); + + for (const auto& testStepFinished : testStepsFinished) + { + nested.push_back(testStepFinished.testStepId); + } + } + + return actual; + }; + + nlohmann::json actual; + + actual["testCaseStarted"] = findTestStepsFinishedBy(query.FindAllTestCaseStarted()); + actual["testCaseFinished"] = findTestStepsFinishedBy(query.FindAllTestCaseFinished()); + + Verify("findTestStepsFinishedBy", actual); + } + + TEST_P(QueryAcceptanceTest, findTestStepsStartedBy) + { + const auto findTestStepsStartedBy = [&](const auto& items) + { + auto actual = nlohmann::json::array(); + + for (const auto& item : items) + { + auto& nested = actual.emplace_back(nlohmann::json::array()); + const auto& testStepsFinished = query.FindTestStepsStartedBy(item); + + for (const auto& testStepFinished : testStepsFinished) + { + nested.push_back(testStepFinished.testStepId); + } + } + + return actual; + }; + + nlohmann::json actual; + + actual["testCaseStarted"] = findTestStepsStartedBy(query.FindAllTestCaseStarted()); + actual["testCaseFinished"] = findTestStepsStartedBy(query.FindAllTestCaseFinished()); + + Verify("findTestStepsStartedBy", actual); + } + + TEST_P(QueryAcceptanceTest, findUnambiguousStepDefinitionBy) + { + nlohmann::json actual = nlohmann::json::array(); + + for (const auto& testStep : query.FindAllTestSteps()) + { + const auto* stepDefinition = query.FindUnambiguousStepDefinitionBy(testStep); + if (stepDefinition != nullptr) + { + actual.push_back(stepDefinition->id); + } + } + + Verify("findUnambiguousStepDefinitionBy", actual); + } + + struct NamingStrategyAcceptanceTest : testing::TestWithParam + { + protected: + void SetUp() override + { + LoadQuery(GetParam().source, archive, query); + } + + void Verify(std::string_view variant, const NamingStrategy& strategy) const + { + std::string actual; + + for (const auto& pickle : query.FindAllPickles()) + { + const auto lineageAndPickle = query.FindLineageBy(pickle); + if (lineageAndPickle) + { + actual += strategy.Reduce(*lineageAndPickle->lineage, *lineageAndPickle->pickle) + "\n"; + } + } + + const auto expected = ExpectedPath(GetParam().source, ".naming-strategy." + std::string{ variant } + ".txt"); + + std::ifstream ifstream{ expected, std::ios::binary }; + EXPECT_EQ(actual, std::string(std::istreambuf_iterator{ ifstream }, std::istreambuf_iterator{})); + } + + EnvelopeArchive archive; + Query query; + }; + + INSTANTIATE_TEST_SUITE_P(Acceptance, NamingStrategyAcceptanceTest, testing::ValuesIn(GetDataSets({ ".naming-strategy.", ".txt" })), DataSetName); + + TEST_P(NamingStrategyAcceptanceTest, long) + { + Verify("long", *CreateNamingStrategy(NamingStrategyLength::longName)); + } + + TEST_P(NamingStrategyAcceptanceTest, long_exclude_feature_name) + { + Verify("long-exclude-feature-name", *CreateNamingStrategy(NamingStrategyLength::longName, NamingStrategyFeatureName::exclude)); + } + + TEST_P(NamingStrategyAcceptanceTest, long_with_pickle_name) + { + Verify("long-with-pickle-name", *CreateNamingStrategy(NamingStrategyLength::longName, NamingStrategyFeatureName::include, NamingStrategyExampleName::pickle)); + } + + TEST_P(NamingStrategyAcceptanceTest, long_with_pickle_name_if_parameterized) + { + Verify("long-with-pickle-name-if-parameterized", + *CreateNamingStrategy(NamingStrategyLength::longName, NamingStrategyFeatureName::include, NamingStrategyExampleName::numberAndPickleIfParameterized)); + } + + TEST_P(NamingStrategyAcceptanceTest, short) + { + Verify("short", *CreateNamingStrategy(NamingStrategyLength::shortName)); + } + } +} diff --git a/cpp/test/TestView.cpp b/cpp/test/TestView.cpp new file mode 100644 index 00000000..cd494ab0 --- /dev/null +++ b/cpp/test/TestView.cpp @@ -0,0 +1,274 @@ +#include "cucumber/query/View.hpp" +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include +#include +#include +#include +#include +#include + +namespace cucumber::query +{ + namespace + { + struct Element + { + std::string name; + int value{ 0 }; + }; + + // A range that is not a standard container, only providing begin() and end(). + class CustomRange + { + public: + explicit CustomRange(std::vector values) + : values(std::move(values)) + {} + + [[nodiscard]] auto begin() const + { + return values.begin(); + } + + [[nodiscard]] auto end() const + { + return values.end(); + } + + private: + std::vector values; + }; + + template + auto ToVector(const Range& range) + { + std::vector> result; + for (const auto& element : range) + { + result.push_back(element); + } + return result; + } + } + + TEST(TestSpan, IteratesOverAVector) + { + std::vector values{ 1, 2, 3 }; + const Span span{ values }; + + ASSERT_FALSE(span.empty()); + ASSERT_THAT(span.size(), testing::Eq(3)); + ASSERT_THAT(span.front(), testing::Eq(1)); + ASSERT_THAT(span.back(), testing::Eq(3)); + ASSERT_THAT(span[1], testing::Eq(2)); + ASSERT_THAT(ToVector(span), testing::ElementsAre(1, 2, 3)); + } + + TEST(TestSpan, IsEmptyByDefault) + { + const Span span; + + ASSERT_TRUE(span.empty()); + ASSERT_THAT(span.size(), testing::Eq(0)); + ASSERT_THAT(span.begin(), testing::Eq(span.end())); + } + + TEST(TestSpan, SubspanSelectsPartOfTheSequence) + { + std::vector values{ 1, 2, 3, 4 }; + const Span span{ values }; + + ASSERT_THAT(ToVector(span.Subspan(1, 2)), testing::ElementsAre(2, 3)); + ASSERT_THAT(ToVector(span.Subspan(2)), testing::ElementsAre(3, 4)); + } + + TEST(TestSpan, ReferencesTheUnderlyingElements) + { + std::vector values{ 1, 2, 3 }; + const Span span{ values }; + + span[0] = 42; + + ASSERT_THAT(values.front(), testing::Eq(42)); + } + + TEST(TestView, IteratesOverACustomRange) + { + const CustomRange range{ { 1, 2, 3 } }; + + ASSERT_THAT(ToVector(views::All(range)), testing::ElementsAre(1, 2, 3)); + ASSERT_THAT(views::All(range).size(), testing::Eq(3)); + } + + TEST(TestView, FiltersByPredicate) + { + const CustomRange range{ { 1, 2, 3, 4 } }; + + const auto even = views::Filter(range, + [](int value) + { + return value % 2 == 0; + }); + + ASSERT_THAT(ToVector(even), testing::ElementsAre(2, 4)); + ASSERT_THAT(even.size(), testing::Eq(2)); + ASSERT_FALSE(even.empty()); + ASSERT_THAT(even.front(), testing::Eq(2)); + } + + TEST(TestView, FiltersByPredicateWithoutMatches) + { + const std::vector values{ 1, 3 }; + + const auto even = values | views::Filter( + [](int value) + { + return value % 2 == 0; + }); + + ASSERT_TRUE(even.empty()); + ASSERT_THAT(even.size(), testing::Eq(0)); + } + + TEST(TestView, FiltersByProjection) + { + const std::vector elements{ { "a", 1 }, { "b", 2 }, { "c", 3 } }; + + const auto filtered = views::Filter( + elements, + [](int value) + { + return value > 1; + }, + [](const Element& element) + { + return element.value; + }); + + std::vector names; + for (const auto& element : filtered) + { + names.push_back(element.name); + } + + ASSERT_THAT(names, testing::ElementsAre("b", "c")); + } + + TEST(TestView, TransformsByProjection) + { + const std::vector elements{ { "a", 1 }, { "b", 2 } }; + + const auto names = views::Transform(elements, + [](const Element& element) -> const std::string& + { + return element.name; + }); + + ASSERT_THAT(ToVector(names), testing::ElementsAre("a", "b")); + } + + TEST(TestView, IteratesOverTheKeysOfAMap) + { + const std::map map{ { "a", 1 }, { "b", 2 } }; + + ASSERT_THAT(ToVector(views::Keys(map)), testing::ElementsAre("a", "b")); + ASSERT_THAT(ToVector(map | views::Keys()), testing::ElementsAre("a", "b")); + } + + TEST(TestView, IteratesOverTheValuesOfAMap) + { + const std::map map{ { "a", 1 }, { "b", 2 } }; + + ASSERT_THAT(ToVector(views::Values(map)), testing::ElementsAre(1, 2)); + ASSERT_THAT(ToVector(map | views::Values()), testing::ElementsAre(1, 2)); + } + + TEST(TestView, IteratesOverTheDereferencedValuesOfAMap) + { + const std::map> map{ + { "a", std::make_shared(Element{ "a", 1 }) }, + { "b", std::make_shared(Element{ "b", 2 }) }, + }; + + const auto elements = map | views::Values() | views::Dereference(); + + std::vector values; + for (const Element& element : elements) + { + values.push_back(element.value); + ASSERT_THAT(std::addressof(element), testing::Eq(map.at(element.name).get())); + } + + ASSERT_THAT(values, testing::ElementsAre(1, 2)); + } + + TEST(TestView, DereferencesTheElementsOfAVector) + { + const std::vector> elements{ + std::make_shared(Element{ "a", 1 }), + std::make_shared(Element{ "b", 2 }), + }; + + const auto dereferenced = views::Dereference(elements); + + ASSERT_THAT(dereferenced.size(), testing::Eq(2)); + ASSERT_THAT(std::addressof(dereferenced.front()), testing::Eq(elements.front().get())); + + static_assert(std::is_same_v, "iteration must yield a reference"); + } + + TEST(TestView, JoinsTheValuesOfAMapOfVectors) + { + const std::map> map{ { "a", { 1, 2 } }, { "b", {} }, { "c", { 3 } } }; + + const auto joined = map | views::Values() | views::Join(); + + ASSERT_THAT(ToVector(joined), testing::ElementsAre(1, 2, 3)); + ASSERT_THAT(joined.size(), testing::Eq(3)); + } + + TEST(TestView, JoinsAnEmptyRangeOfRanges) + { + const std::map> map{ { "a", {} }, { "b", {} } }; + + const auto joined = views::Join(map | views::Values()); + + ASSERT_TRUE(joined.empty()); + ASSERT_THAT(joined.begin(), testing::Eq(joined.end())); + } + + TEST(TestView, ComposesFilterAndTransform) + { + const std::map map{ { "a", { "a", 1 } }, { "b", { "b", 2 } }, { "c", { "c", 3 } } }; + + const auto names = map | views::Values() | + views::Filter( + [](int value) + { + return value % 2 == 1; + }, + [](const Element& element) + { + return element.value; + }) | + views::Transform( + [](const Element& element) -> const std::string& + { + return element.name; + }); + + ASSERT_THAT(ToVector(names), testing::ElementsAre("a", "c")); + } + + TEST(TestView, DoesNotCopyTheUnderlyingElements) + { + std::vector elements{ { "a", 1 }, { "b", 2 } }; + + const auto all = views::All(elements); + elements.front().value = 42; + + ASSERT_THAT(all.front().value, testing::Eq(42)); + ASSERT_THAT(std::addressof(all.front()), testing::Eq(elements.data())); + } +} diff --git a/testdata/.gitattributes b/testdata/.gitattributes new file mode 100644 index 00000000..ddddd013 --- /dev/null +++ b/testdata/.gitattributes @@ -0,0 +1,3 @@ +*.ndjson text eol=lf +*.json text eol=lf +*.txt text eol=lf