├── cpp ├── VERSION ├── .gitignore ├── src │ ├── CMakeLists.txt │ └── lib │ │ ├── CMakeLists.txt │ │ └── messages │ │ ├── link.yaml │ │ └── cucumber │ │ └── messages │ │ ├── utils.cpp │ │ ├── attachment_content_encoding.cpp │ │ ├── source_media_type.cpp │ │ ├── pickle_step_type.cpp │ │ ├── step_definition_pattern_type.cpp │ │ ├── step_keyword_type.cpp │ │ ├── hook_type.cpp │ │ ├── pickle_table.cpp │ │ ├── pickle_table_row.cpp │ │ ├── pickle_table_cell.cpp │ │ ├── test_step_result_status.cpp │ │ ├── location.cpp │ │ ├── product.cpp │ │ ├── comment.cpp │ │ ├── snippet.cpp │ │ ├── duration.cpp │ │ ├── timestamp.cpp │ │ ├── data_table.cpp │ │ ├── table_cell.cpp │ │ ├── parse_error.cpp │ │ ├── pickle_tag.cpp │ │ ├── rule_child.cpp │ │ ├── step_match_arguments_list.cpp │ │ └── test_run_started.cpp ├── deps.txt ├── cmake │ └── cucumber_messages-config.cmake.in ├── project.yaml ├── include │ └── messages │ │ └── cucumber │ │ └── messages │ │ ├── pickle_step_type.hpp │ │ ├── attachment_content_encoding.hpp │ │ ├── source_media_type.hpp │ │ ├── step_keyword_type.hpp │ │ ├── step_definition_pattern_type.hpp │ │ ├── hook_type.hpp │ │ ├── test_step_result_status.hpp │ │ ├── snippet.hpp │ │ ├── timestamp.hpp │ │ ├── pickle_table_cell.hpp │ │ ├── pickle_tag.hpp │ │ ├── pickle_doc_string.hpp │ │ ├── product.hpp │ │ ├── location.hpp │ │ ├── java_method.hpp │ │ ├── undefined_parameter_type.hpp │ │ ├── pickle_table.hpp │ │ ├── tag.hpp │ │ ├── parse_error.hpp │ │ ├── pickle_table_row.hpp │ │ ├── comment.hpp │ │ ├── group.hpp │ │ ├── java_stack_trace_element.hpp │ │ ├── table_cell.hpp │ │ ├── duration.hpp │ │ ├── test_run_started.hpp │ │ ├── exception.hpp │ │ ├── ci.hpp │ │ ├── data_table.hpp │ │ ├── doc_string.hpp │ │ ├── git.hpp │ │ ├── test_step_started.hpp │ │ ├── step_match_arguments_list.hpp │ │ ├── test_case_finished.hpp │ │ ├── step_definition_pattern.hpp │ │ ├── source.hpp │ │ ├── suggestion.hpp │ │ ├── table_row.hpp │ │ ├── test_case_started.hpp │ │ ├── rule_child.hpp │ │ ├── test_case.hpp │ │ ├── step_definition.hpp │ │ ├── test_run_hook_started.hpp │ │ ├── background.hpp │ │ ├── test_run_hook_finished.hpp │ │ ├── hook.hpp │ │ ├── test_step_finished.hpp │ │ ├── pickle_step_argument.hpp │ │ ├── parameter_type.hpp │ │ ├── test_run_finished.hpp │ │ ├── feature_child.hpp │ │ ├── rule.hpp │ │ └── pickle_step.hpp ├── README.md ├── Dockerfile └── LICENSE ├── perl ├── VERSION ├── README.md ├── .gitignore ├── t │ ├── 01-load.t │ └── 02-instantiation.t ├── cpanfile └── Makefile ├── ruby ├── VERSION ├── .rspec ├── Gemfile ├── README.md ├── .gitignore ├── lib │ └── cucumber │ │ ├── messages │ │ ├── helpers │ │ │ ├── id_generator.rb │ │ │ ├── id_generator │ │ │ │ ├── uuid.rb │ │ │ │ └── incrementing.rb │ │ │ ├── ndjson_to_message_enumerator.rb │ │ │ └── time_conversion.rb │ │ ├── attachment_content_encoding.rb │ │ ├── pickle_step_type.rb │ │ ├── step_definition_pattern_type.rb │ │ ├── source_media_type.rb │ │ ├── step_keyword_type.rb │ │ ├── test_step_result_status.rb │ │ ├── hook_type.rb │ │ ├── pickle_table_cell.rb │ │ └── pickle_table.rb │ │ └── messages.rb ├── spec │ ├── support │ │ ├── enum_message.rb │ │ ├── simple_message.rb │ │ └── comprehensive_message.rb │ ├── spec_helper.rb │ └── cucumber │ │ └── messages │ │ ├── helpers │ │ └── id_generator │ │ │ ├── uuid_spec.rb │ │ │ └── incrementing_spec.rb │ │ └── acceptance_spec.rb └── Rakefile ├── javascript ├── schema │ ├── .gitkeep │ ├── .gitignore │ └── .npmignore ├── README.md ├── package.cjs.json ├── src │ ├── version.ts │ ├── IdGenerator.ts │ ├── index.ts │ ├── parseEnvelope.ts │ └── getWorstTestStepResult.ts ├── .mocharc.json ├── tsconfig.build-cjs.json ├── tsconfig.build-esm.json ├── .gitignore ├── tsconfig.build.json ├── test │ ├── IdGeneratorTest.ts │ └── getWorstTestStepResultsTest.ts ├── tsconfig.json └── Makefile ├── .gitignore ├── dotnet ├── Cucumber.Messages │ ├── .releaseable │ ├── .gitignore │ ├── Cucumber.Messages.snk │ ├── Resources │ │ └── cucumber-mark-green-128.png │ ├── ProtocolVersion.cs │ └── generated │ │ ├── AttachmentContentEncoding.cs │ │ ├── StepDefinitionPatternType.cs │ │ ├── SourceMediaType.cs │ │ └── PickleStepType.cs ├── .vs │ └── ProjectEvaluation │ │ └── cucumber.messages.strings.v8.bin ├── Cucumber.Messages.Specs │ ├── NdJsonMessageReaderSUT.cs │ ├── ProtocolVersionTest.cs │ ├── MessageToNdjsonWriterSUT.cs │ ├── Cucumber.Messages.Specs.csproj │ ├── MessagesTest.cs │ └── ConvertersTests.cs └── .devcontainer │ └── devcontainer.json ├── jsonschema ├── .gitignore ├── messages.png ├── messages.monopic ├── package.json ├── validate.cjs └── src │ ├── TestRunStarted.json │ ├── ParseError.json │ ├── UndefinedParameterType.json │ ├── Location.json │ ├── TestStepStarted.json │ ├── TestCaseFinished.json │ ├── TestRunHookFinished.json │ ├── TestStepFinished.json │ ├── Duration.json │ ├── Timestamp.json │ ├── Hook.json │ ├── Exception.json │ ├── ParameterType.json │ ├── Source.json │ ├── StepDefinition.json │ ├── TestStepResult.json │ └── TestRunFinished.json ├── elixir ├── test │ ├── test_helper.exs │ └── cucumber_message_test.exs ├── lib │ ├── cucumber_messages │ │ └── generated │ │ │ └── .gitignore │ └── cucumber_message.ex ├── README.md ├── .gitignore ├── Makefile └── mix.exs ├── RELEASING.md ├── java ├── src │ ├── main │ │ ├── resources │ │ │ └── io │ │ │ │ └── cucumber │ │ │ │ └── messages │ │ │ │ └── version.properties │ │ └── java │ │ │ └── io │ │ │ └── cucumber │ │ │ └── messages │ │ │ ├── IdGenerator.java │ │ │ ├── ProtocolVersion.java │ │ │ ├── TestStepResultStatusComparator.java │ │ │ ├── DurationComparator.java │ │ │ ├── TimestampComparator.java │ │ │ ├── LocationComparator.java │ │ │ └── TimeConversion.java │ ├── test │ │ └── java │ │ │ └── io │ │ │ └── cucumber │ │ │ └── messages │ │ │ └── ProtocolVersionTest.java │ └── generated │ │ └── java │ │ └── io │ │ └── cucumber │ │ └── messages │ │ └── types │ │ ├── AttachmentContentEncoding.java │ │ ├── PickleStepType.java │ │ ├── SourceMediaType.java │ │ ├── StepDefinitionPatternType.java │ │ ├── StepKeywordType.java │ │ ├── HookType.java │ │ └── TestStepResultStatus.java ├── .gitignore └── README.md ├── python ├── README.md ├── src │ └── cucumber_messages │ │ └── __init__.py ├── .gitignore └── tests │ └── test_model_load.py ├── php ├── .gitignore ├── src │ ├── Id │ │ ├── IdGenerator.php │ │ └── IncrementingIdGenerator.php │ ├── DecodingException.php │ ├── Streams │ │ ├── StreamReader.php │ │ ├── StreamWriter.php │ │ ├── WithFileHandleTrait.php │ │ └── NdJson │ │ │ ├── NdJsonStreamWriter.php │ │ │ └── NdJsonStreamReader.php │ └── DecodingException │ │ ├── MalformedJsonException.php │ │ ├── SchemaViolationException.php │ │ └── UnexpectedDecodingException.php ├── .php-cs-fixer.php ├── src-generated │ ├── Attachment │ │ └── ContentEncoding.php │ ├── PickleStep │ │ └── Type.php │ ├── StepDefinitionPattern │ │ └── Type.php │ ├── Source │ │ └── MediaType.php │ ├── Step │ │ └── KeywordType.php │ ├── TestStepResult │ │ └── Status.php │ └── Hook │ │ └── Type.php ├── tests │ ├── Id │ │ ├── IdGeneratorTestTrait.php │ │ ├── IncrementingIdGeneratorTest.php │ │ └── UuidIdGeneratorTest.php │ └── EnvelopeTest.php ├── psalm.xml ├── phpunit.xml ├── composer.json └── LICENSE ├── .github ├── renovate.json └── workflows │ ├── release-github.yml │ ├── release-cpan.yml │ ├── release-php.yml │ ├── release-rubygem.yml │ ├── release-nuget.yml │ ├── test-dotnet.yml │ ├── release-npm.yml │ ├── release-pypi.yml │ ├── release-mvn.yml │ ├── test-perl.yml │ ├── release-hex.yml │ ├── test-elixir.yml │ ├── test-ruby.yml │ ├── test-go.yml │ └── test-java.yml ├── codegen ├── .rubocop.yml ├── templates │ ├── markdown.enum.md.erb │ ├── typescript.enum.ts.erb │ ├── ruby.enum.rb.erb │ ├── python.enum.py.erb │ ├── php.enum.php.erb │ ├── go.enum.go.erb │ ├── markdown.md.erb │ ├── go.go.erb │ ├── typescript.ts.erb │ ├── java.enum.java.erb │ └── dotnet.enum.dotnet.erb ├── generators │ ├── typescript.rb │ ├── go.rb │ ├── text_helpers.rb │ ├── markdown.rb │ ├── dotnet.rb │ ├── cpp.rb │ └── java.rb └── codegen.rb ├── go ├── .gitignore ├── go.mod ├── id_generator_test.go ├── id_generator.go ├── time_conversion.go ├── Makefile └── LICENSE ├── testdata └── README.md ├── Makefile ├── .pre-commit-config.yaml └── LICENSE /cpp/VERSION: -------------------------------------------------------------------------------- 1 | 31.0.1 2 | -------------------------------------------------------------------------------- /perl/VERSION: -------------------------------------------------------------------------------- 1 | 31.0.1 2 | -------------------------------------------------------------------------------- /ruby/VERSION: -------------------------------------------------------------------------------- 1 | 31.0.1 2 | -------------------------------------------------------------------------------- /javascript/schema/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.iml 3 | -------------------------------------------------------------------------------- /dotnet/Cucumber.Messages/.releaseable: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /javascript/schema/.gitignore: -------------------------------------------------------------------------------- 1 | *.json -------------------------------------------------------------------------------- /jsonschema/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /cpp/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | stage/ 3 | .cenv/ 4 | -------------------------------------------------------------------------------- /cpp/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(lib) 2 | -------------------------------------------------------------------------------- /elixir/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /ruby/.rspec: -------------------------------------------------------------------------------- 1 | --require spec_helper 2 | --color 3 | -------------------------------------------------------------------------------- /elixir/lib/cucumber_messages/generated/.gitignore: -------------------------------------------------------------------------------- 1 | /*.ex -------------------------------------------------------------------------------- /cpp/deps.txt: -------------------------------------------------------------------------------- 1 | nlohmann/json@v3.11.3 -DJSON_BuildTests=OFF 2 | -------------------------------------------------------------------------------- /cpp/src/lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(cucumber-messages) 2 | -------------------------------------------------------------------------------- /javascript/schema/.npmignore: -------------------------------------------------------------------------------- 1 | .gitkeep 2 | .gitignore 3 | !*.json 4 | -------------------------------------------------------------------------------- /perl/README.md: -------------------------------------------------------------------------------- 1 | # Cucumber Messages for Perl (JSON schema) 2 | 3 | -------------------------------------------------------------------------------- /javascript/README.md: -------------------------------------------------------------------------------- 1 | # Cucumber Messages for JavaScript (JSON schema) 2 | 3 | -------------------------------------------------------------------------------- /dotnet/Cucumber.Messages/.gitignore: -------------------------------------------------------------------------------- 1 | # protoc-generated file 2 | Messages.cs 3 | 4 | -------------------------------------------------------------------------------- /RELEASING.md: -------------------------------------------------------------------------------- 1 | See [.github/RELEASING](https://github.com/cucumber/.github/blob/main/RELEASING.md). 2 | -------------------------------------------------------------------------------- /cpp/src/lib/messages/link.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | libs: 3 | public: 4 | - nlohmann_json::nlohmann_json 5 | -------------------------------------------------------------------------------- /java/src/main/resources/io/cucumber/messages/version.properties: -------------------------------------------------------------------------------- 1 | messages.version=${project.version} 2 | -------------------------------------------------------------------------------- /jsonschema/messages.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cucumber/messages/HEAD/jsonschema/messages.png -------------------------------------------------------------------------------- /ruby/Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source 'https://rubygems.org' 4 | 5 | gemspec 6 | -------------------------------------------------------------------------------- /ruby/README.md: -------------------------------------------------------------------------------- 1 | # Cucumber Messages for Ruby (JSON schema) 2 | 3 | See main [README](../README.md) 4 | -------------------------------------------------------------------------------- /javascript/package.cjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cucumber/messages", 3 | "type": "commonjs" 4 | } 5 | -------------------------------------------------------------------------------- /jsonschema/messages.monopic: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cucumber/messages/HEAD/jsonschema/messages.monopic -------------------------------------------------------------------------------- /python/README.md: -------------------------------------------------------------------------------- 1 | # Messages 2 | 3 | Cucumber Messages for Python https://github.com/cucumber/messages 4 | -------------------------------------------------------------------------------- /ruby/.gitignore: -------------------------------------------------------------------------------- 1 | Gemfile.lock 2 | coverage/ 3 | acceptance/ 4 | pkg/ 5 | *.gem 6 | .compared 7 | *.iml 8 | -------------------------------------------------------------------------------- /javascript/src/version.ts: -------------------------------------------------------------------------------- 1 | // This file is automatically generated using npm scripts 2 | export const version = '31.0.1' 3 | -------------------------------------------------------------------------------- /php/.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | composer.lock 3 | .phpunit.cache 4 | .php-cs-fixer.cache 5 | .codegen 6 | .deps 7 | .tested 8 | 9 | build -------------------------------------------------------------------------------- /cpp/cmake/cucumber_messages-config.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | include("${CMAKE_CURRENT_LIST_DIR}/cucumber_messages-targets.cmake") 3 | -------------------------------------------------------------------------------- /elixir/test/cucumber_message_test.exs: -------------------------------------------------------------------------------- 1 | defmodule CucumberMessagesTest do 2 | use ExUnit.Case 3 | 4 | # No testdata for now 5 | end 6 | -------------------------------------------------------------------------------- /dotnet/Cucumber.Messages/Cucumber.Messages.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cucumber/messages/HEAD/dotnet/Cucumber.Messages/Cucumber.Messages.snk -------------------------------------------------------------------------------- /javascript/.mocharc.json: -------------------------------------------------------------------------------- 1 | { 2 | "loader": "ts-node/esm", 3 | "extension": ["ts", "tsx"], 4 | "recursive": true, 5 | "timeout": 10000 6 | } 7 | -------------------------------------------------------------------------------- /perl/.gitignore: -------------------------------------------------------------------------------- 1 | .build/ 2 | .built 3 | acceptance/ 4 | Cucumber-Messages-* 5 | perl5/ 6 | .cpanfile_dependencies 7 | cpanfile.snapshot 8 | CHANGELOG.md 9 | -------------------------------------------------------------------------------- /java/src/main/java/io/cucumber/messages/IdGenerator.java: -------------------------------------------------------------------------------- 1 | package io.cucumber.messages; 2 | 3 | public interface IdGenerator { 4 | String newId(); 5 | } 6 | -------------------------------------------------------------------------------- /php/src/Id/IdGenerator.php: -------------------------------------------------------------------------------- 1 | cucumber/renovate-config", 5 | ":enablePreCommit" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /codegen/.rubocop.yml: -------------------------------------------------------------------------------- 1 | require: 2 | - rubocop-performance 3 | 4 | AllCops: 5 | TargetRubyVersion: 3.0 6 | NewCops: enable 7 | 8 | Style/RegexpLiteral: 9 | AllowInnerSlashes: true 10 | -------------------------------------------------------------------------------- /perl/t/01-load.t: -------------------------------------------------------------------------------- 1 | #!perl 2 | 3 | use Test2::V0; 4 | 5 | use Cucumber::Messages::Message; 6 | use Cucumber::Messages; 7 | 8 | pass 'Both libraries loaded fine'; 9 | 10 | done_testing; 11 | -------------------------------------------------------------------------------- /ruby/spec/support/enum_message.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Cucumber 4 | module Messages 5 | class EnumMessage 6 | ENUM = 'an enum' 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /javascript/tsconfig.build-cjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.build.json", 3 | "compilerOptions": { 4 | "outDir": "dist/cjs", 5 | "target": "ES5", 6 | "module": "CommonJS", 7 | }, 8 | } 9 | -------------------------------------------------------------------------------- /codegen/templates/markdown.enum.md.erb: -------------------------------------------------------------------------------- 1 | <% @enums.each do |enum| -%> 2 | ## <%= enum[:name] %> 3 | 4 | One of the following: 5 | 6 | <% enum[:values].each do |value| -%> 7 | * `"<%= value %>"` 8 | <% end %> 9 | 10 | <% end -%> 11 | -------------------------------------------------------------------------------- /python/src/cucumber_messages/__init__.py: -------------------------------------------------------------------------------- 1 | from . import _messages, json_converter 2 | from ._messages import * 3 | 4 | message_converter: json_converter.JsonDataclassConverter = json_converter.JsonDataclassConverter(module_scope=_messages) 5 | -------------------------------------------------------------------------------- /codegen/templates/typescript.enum.ts.erb: -------------------------------------------------------------------------------- 1 | <% @enums.each do |enum| -%> 2 | export enum <%= enum[:name] %> { 3 | <% enum[:values].each do |value| -%> 4 | <%= enum_constant(value) %> = '<%= value %>', 5 | <% end -%> 6 | } 7 | 8 | <% end -%> 9 | -------------------------------------------------------------------------------- /jsonschema/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@cucumber/messages-validation-kit", 3 | "version": "0.0.0", 4 | "private": true, 5 | "description": "Allow to validate the schemas", 6 | "devDependencies": { 7 | "ajv": "8.17.1" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /javascript/tsconfig.build-esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.build.json", 3 | "compilerOptions": { 4 | "lib": [ 5 | "ES2019" 6 | ], 7 | "target": "ES6", 8 | "module": "ES6", 9 | "outDir": "dist/esm" 10 | }, 11 | } 12 | -------------------------------------------------------------------------------- /php/src/DecodingException.php: -------------------------------------------------------------------------------- 1 | string 2 | 3 | export function uuid(): NewId { 4 | return () => crypto.randomUUID() 5 | } 6 | 7 | export function incrementing(): NewId { 8 | let next = 0 9 | return () => (next++).toString() 10 | } 11 | -------------------------------------------------------------------------------- /javascript/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | .idea/ 3 | .nyc_output/ 4 | coverage/ 5 | node_modules/ 6 | yarn.lock 7 | *.log 8 | .deps 9 | .tested* 10 | .linted 11 | .built* 12 | .compared 13 | .codegen 14 | acceptance/ 15 | storybook-static 16 | *-go 17 | *.iml 18 | .vscode-test 19 | -------------------------------------------------------------------------------- /php/.php-cs-fixer.php: -------------------------------------------------------------------------------- 1 | in([ 4 | __DIR__ . '/src', 5 | __DIR__ . '/src-generated', 6 | __DIR__ . '/tests', 7 | ]) 8 | ; 9 | 10 | $config = new PhpCsFixer\Config(); 11 | return $config->setFinder($finder); 12 | -------------------------------------------------------------------------------- /cpp/project.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: cucumber_messages 3 | version_file: VERSION 4 | namespace: cucumber 5 | std: 17 6 | packages: 7 | cmake: 8 | - nlohmann_json: 9 | deps: 10 | - nlohmann/json@v3.11.3: 11 | args: 12 | - -DJSON_BuildTests=OFF 13 | - -DJSON_Install=ON 14 | -------------------------------------------------------------------------------- /go/.gitignore: -------------------------------------------------------------------------------- 1 | .built 2 | .compared 3 | .deps 4 | .dist 5 | .dist-compressed 6 | .go-get 7 | .gofmt 8 | .linted 9 | .tested* 10 | acceptance/ 11 | bin/ 12 | dist/ 13 | dist_compressed/ 14 | *.bin 15 | *.iml 16 | # upx dist/cucumber-gherkin-openbsd-386 fails with a core dump 17 | core.*.!usr!bin!upx-ucl 18 | -------------------------------------------------------------------------------- /java/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | *.iml 3 | target/ 4 | release.properties 5 | pom.xml.releaseBackup 6 | pom.xml.versionsBackup 7 | dependency-reduced-pom.xml 8 | .classpath 9 | .deps 10 | .project 11 | .settings/ 12 | .tested* 13 | .compared 14 | .built 15 | .codegen 16 | # Approval tests 17 | acceptance/ 18 | -------------------------------------------------------------------------------- /ruby/spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rspec' 4 | 5 | require 'cucumber/messages' 6 | require 'cucumber/messages/message' 7 | 8 | require_relative 'support/comprehensive_message' 9 | require_relative 'support/enum_message' 10 | require_relative 'support/simple_message' 11 | -------------------------------------------------------------------------------- /php/src/Streams/StreamReader.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | public function envelopes(): iterable; 15 | } 16 | -------------------------------------------------------------------------------- /javascript/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "composite": true, 5 | "declaration": true, 6 | "declarationMap": true, 7 | "sourceMap": true, 8 | "rootDir": ".", 9 | "noEmit": false 10 | }, 11 | "include": [ 12 | "src", 13 | "test" 14 | ], 15 | } -------------------------------------------------------------------------------- /php/src/DecodingException/MalformedJsonException.php: -------------------------------------------------------------------------------- 1 | next++; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /go/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/cucumber/messages/go/v31 2 | 3 | require ( 4 | github.com/google/uuid v1.6.0 5 | github.com/stretchr/testify v1.11.1 6 | ) 7 | 8 | require ( 9 | github.com/davecgh/go-spew v1.1.1 // indirect 10 | github.com/pmezard/go-difflib v1.0.0 // indirect 11 | gopkg.in/yaml.v3 v3.0.1 // indirect 12 | ) 13 | 14 | go 1.19 15 | -------------------------------------------------------------------------------- /php/src/Streams/StreamWriter.php: -------------------------------------------------------------------------------- 1 | $envelopes 13 | */ 14 | public function writeEnvelopes(iterable $envelopes): void; 15 | } 16 | -------------------------------------------------------------------------------- /perl/cpanfile: -------------------------------------------------------------------------------- 1 | 2 | requires "perl", "5.14.4"; 3 | 4 | requires "JSON::MaybeXS"; 5 | requires "Moo"; 6 | 7 | 8 | on 'test' => sub { 9 | requires "File::Find::Rule"; 10 | requires "Test2::Tools::ClassicCompare"; 11 | requires "Test2::V0"; 12 | 13 | }; 14 | 15 | 16 | on 'develop' => sub { 17 | # There are no specific development dependencies 18 | } -------------------------------------------------------------------------------- /php/src/DecodingException/SchemaViolationException.php: -------------------------------------------------------------------------------- 1 | 4 | 5 | namespace cucumber::messages { 6 | 7 | enum class pickle_step_type 8 | { 9 | UNKNOWN, 10 | CONTEXT, 11 | ACTION, 12 | OUTCOME 13 | }; 14 | 15 | std::string_view 16 | to_string(pickle_step_type v); 17 | 18 | std::ostream& 19 | operator<<(std::ostream& os, pickle_step_type v); 20 | 21 | } 22 | -------------------------------------------------------------------------------- /ruby/lib/cucumber/messages/pickle_step_type.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # The code was auto-generated by {this script}[https://github.com/cucumber/messages/blob/main/codegen/codegen.rb] 4 | module Cucumber 5 | module Messages 6 | class PickleStepType 7 | UNKNOWN = 'Unknown' 8 | CONTEXT = 'Context' 9 | ACTION = 'Action' 10 | OUTCOME = 'Outcome' 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/attachment_content_encoding.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace cucumber::messages { 6 | 7 | enum class attachment_content_encoding 8 | { 9 | IDENTITY, 10 | BASE64 11 | }; 12 | 13 | std::string_view 14 | to_string(attachment_content_encoding v); 15 | 16 | std::ostream& 17 | operator<<(std::ostream& os, attachment_content_encoding v); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /jsonschema/src/ParseError.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "ParseError.json", 4 | "additionalProperties": false, 5 | "required": [ 6 | "source", 7 | "message" 8 | ], 9 | "properties": { 10 | "source": { 11 | "$ref": "./SourceReference.json" 12 | }, 13 | "message": { 14 | "type": "string" 15 | } 16 | }, 17 | "type": "object" 18 | } 19 | -------------------------------------------------------------------------------- /ruby/lib/cucumber/messages/step_definition_pattern_type.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # The code was auto-generated by {this script}[https://github.com/cucumber/messages/blob/main/codegen/codegen.rb] 4 | module Cucumber 5 | module Messages 6 | class StepDefinitionPatternType 7 | CUCUMBER_EXPRESSION = 'CUCUMBER_EXPRESSION' 8 | REGULAR_EXPRESSION = 'REGULAR_EXPRESSION' 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/source_media_type.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace cucumber::messages { 6 | 7 | enum class source_media_type 8 | { 9 | TEXT_X_CUCUMBER_GHERKIN_PLAIN, 10 | TEXT_X_CUCUMBER_GHERKIN_MARKDOWN 11 | }; 12 | 13 | std::string_view 14 | to_string(source_media_type v); 15 | 16 | std::ostream& 17 | operator<<(std::ostream& os, source_media_type v); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /javascript/src/index.ts: -------------------------------------------------------------------------------- 1 | import * as TimeConversion from './TimeConversion.js' 2 | import * as IdGenerator from './IdGenerator.js' 3 | import { parseEnvelope } from './parseEnvelope.js' 4 | import { getWorstTestStepResult } from './getWorstTestStepResult.js' 5 | import { version } from './version.js' 6 | 7 | export * from './messages.js' 8 | 9 | export { TimeConversion, IdGenerator, version, parseEnvelope, getWorstTestStepResult } 10 | -------------------------------------------------------------------------------- /jsonschema/src/UndefinedParameterType.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "UndefinedParameterType.json", 4 | "additionalProperties": false, 5 | "required": [ 6 | "expression", 7 | "name" 8 | ], 9 | "properties": { 10 | "expression": { 11 | "type": "string" 12 | }, 13 | "name": { 14 | "type": "string" 15 | } 16 | }, 17 | "type": "object" 18 | } 19 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/step_keyword_type.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace cucumber::messages { 6 | 7 | enum class step_keyword_type 8 | { 9 | UNKNOWN, 10 | CONTEXT, 11 | ACTION, 12 | OUTCOME, 13 | CONJUNCTION 14 | }; 15 | 16 | std::string_view 17 | to_string(step_keyword_type v); 18 | 19 | std::ostream& 20 | operator<<(std::ostream& os, step_keyword_type v); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /php/src-generated/PickleStep/Type.php: -------------------------------------------------------------------------------- 1 | 4 | 5 | namespace cucumber::messages { 6 | 7 | enum class step_definition_pattern_type 8 | { 9 | CUCUMBER_EXPRESSION, 10 | REGULAR_EXPRESSION 11 | }; 12 | 13 | std::string_view 14 | to_string(step_definition_pattern_type v); 15 | 16 | std::ostream& 17 | operator<<(std::ostream& os, step_definition_pattern_type v); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /jsonschema/src/Location.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "Location.json", 4 | "additionalProperties": false, 5 | "description": "Points to a line and a column in a text file", 6 | "properties": { 7 | "line": { 8 | "type": "integer" 9 | }, 10 | "column": { 11 | "type": "integer" 12 | } 13 | }, 14 | "required": [ 15 | "line" 16 | ], 17 | "type": "object" 18 | } 19 | -------------------------------------------------------------------------------- /ruby/lib/cucumber/messages/source_media_type.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # The code was auto-generated by {this script}[https://github.com/cucumber/messages/blob/main/codegen/codegen.rb] 4 | module Cucumber 5 | module Messages 6 | class SourceMediaType 7 | TEXT_X_CUCUMBER_GHERKIN_PLAIN = 'text/x.cucumber.gherkin+plain' 8 | TEXT_X_CUCUMBER_GHERKIN_MARKDOWN = 'text/x.cucumber.gherkin+markdown' 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /ruby/lib/cucumber/messages/step_keyword_type.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # The code was auto-generated by {this script}[https://github.com/cucumber/messages/blob/main/codegen/codegen.rb] 4 | module Cucumber 5 | module Messages 6 | class StepKeywordType 7 | UNKNOWN = 'Unknown' 8 | CONTEXT = 'Context' 9 | ACTION = 'Action' 10 | OUTCOME = 'Outcome' 11 | CONJUNCTION = 'Conjunction' 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /ruby/lib/cucumber/messages/helpers/id_generator/incrementing.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Cucumber 4 | module Messages 5 | module Helpers 6 | module IdGenerator 7 | class Incrementing 8 | def initialize 9 | @index = -1 10 | end 11 | 12 | def new_id 13 | @index += 1 14 | @index.to_s 15 | end 16 | end 17 | end 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/hook_type.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace cucumber::messages { 6 | 7 | enum class hook_type 8 | { 9 | BEFORE_TEST_RUN, 10 | AFTER_TEST_RUN, 11 | BEFORE_TEST_CASE, 12 | AFTER_TEST_CASE, 13 | BEFORE_TEST_STEP, 14 | AFTER_TEST_STEP 15 | }; 16 | 17 | std::string_view 18 | to_string(hook_type v); 19 | 20 | std::ostream& 21 | operator<<(std::ostream& os, hook_type v); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /php/src-generated/Source/MediaType.php: -------------------------------------------------------------------------------- 1 | 4 | 5 | namespace cucumber::messages { 6 | 7 | enum class test_step_result_status 8 | { 9 | UNKNOWN, 10 | PASSED, 11 | SKIPPED, 12 | PENDING, 13 | UNDEFINED, 14 | AMBIGUOUS, 15 | FAILED 16 | }; 17 | 18 | std::string_view 19 | to_string(test_step_result_status v); 20 | 21 | std::ostream& 22 | operator<<(std::ostream& os, test_step_result_status v); 23 | 24 | } 25 | -------------------------------------------------------------------------------- /java/README.md: -------------------------------------------------------------------------------- 1 | [![Maven Central](https://img.shields.io/maven-central/v/io.cucumber/messages.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22io.cucumber%22%20AND%20a:%22messages%22) 2 | 3 | # Cucumber Messages for Java (JSON schema) 4 | 5 | ```java 6 | Iterable envelopes = new io.cucumber.messages.NdjsonToMessageIterable(inputStream) 7 | for (Envelope envelope : envelopes) { 8 | // Do something with the message 9 | } 10 | ``` 11 | 12 | See Unit tests for more examples. 13 | -------------------------------------------------------------------------------- /ruby/spec/support/simple_message.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Cucumber 4 | module Messages 5 | class SimpleMessage < Message 6 | attr_reader :is_nil, :is_string, :is_array, :is_number 7 | 8 | def initialize(is_nil: nil, is_string: '', is_array: [], is_number: 0) 9 | @is_nil = is_nil 10 | @is_string = is_string 11 | @is_array = is_array 12 | @is_number = is_number 13 | super() 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /.github/workflows/release-github.yml: -------------------------------------------------------------------------------- 1 | name: Release on GitHub 2 | 3 | on: 4 | push: 5 | branches: [release/*] 6 | 7 | jobs: 8 | create-github-release: 9 | name: Create GitHub Release and Git tag 10 | runs-on: ubuntu-latest 11 | environment: Release 12 | permissions: 13 | contents: write 14 | steps: 15 | - uses: actions/checkout@v6 16 | - uses: cucumber/action-create-github-release@v1.1.1 17 | with: 18 | github-token: ${{ secrets.GITHUB_TOKEN }} 19 | -------------------------------------------------------------------------------- /codegen/templates/ruby.enum.rb.erb: -------------------------------------------------------------------------------- 1 | <%- @enums.each do |enum| -%> 2 | <%= underscore(enum[:name]) %>.rb 3 | # frozen_string_literal: true 4 | 5 | # The code was auto-generated by {this script}[https://github.com/cucumber/messages/blob/main/codegen/codegen.rb] 6 | module Cucumber 7 | module Messages 8 | class <%= enum[:name] %> 9 | <%- enum[:values].each do |value| -%> 10 | <%= enum_constant(value) %> = '<%= value %>' 11 | <%- end -%> 12 | end 13 | end 14 | end 15 | <% end -%> 16 | -------------------------------------------------------------------------------- /javascript/src/parseEnvelope.ts: -------------------------------------------------------------------------------- 1 | import { Envelope } from './messages.js' 2 | import { plainToClass } from 'class-transformer' 3 | 4 | /** 5 | * Parses JSON into an Envelope object. The difference from JSON.parse 6 | * is that the resulting objects will have default values (defined in the JSON Schema) 7 | * for properties that are absent from the JSON. 8 | */ 9 | export function parseEnvelope(json: string): Envelope { 10 | const plain = JSON.parse(json) 11 | return plainToClass(Envelope, plain) 12 | } 13 | -------------------------------------------------------------------------------- /go/id_generator.go: -------------------------------------------------------------------------------- 1 | package messages 2 | 3 | import ( 4 | "strconv" 5 | 6 | "github.com/google/uuid" 7 | ) 8 | 9 | type IdGenerator interface { 10 | newId() func() string 11 | } 12 | 13 | type Incrementing struct { 14 | next int 15 | } 16 | 17 | func (self *Incrementing) NewId() string { 18 | result := strconv.Itoa(self.next) 19 | self.next++ 20 | return result 21 | } 22 | 23 | type UUID struct { 24 | next int 25 | } 26 | 27 | func (i UUID) NewId() string { 28 | return uuid.New().String() 29 | } 30 | -------------------------------------------------------------------------------- /ruby/lib/cucumber/messages.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'cucumber/messages/helpers/ndjson_to_message_enumerator' 4 | require 'cucumber/messages/helpers/time_conversion' 5 | require 'cucumber/messages/helpers/id_generator' 6 | require 'cucumber/messages/message' 7 | 8 | Dir["#{File.dirname(__FILE__)}/messages/*.rb"].each { |file| require file } 9 | 10 | module Cucumber 11 | module Messages 12 | VERSION = File.read(File.expand_path('../../VERSION', __dir__)).strip 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /dotnet/Cucumber.Messages.Specs/NdJsonMessageReaderSUT.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Cucumber.Messages.Specs 9 | { 10 | internal class NdjsonMessageReaderSUT : NdjsonMessageReader 11 | { 12 | public NdjsonMessageReaderSUT(Stream inputStream) : base(inputStream, (string line) => NdjsonSerializer.Deserialize(line)) 13 | { 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ruby/lib/cucumber/messages/test_step_result_status.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # The code was auto-generated by {this script}[https://github.com/cucumber/messages/blob/main/codegen/codegen.rb] 4 | module Cucumber 5 | module Messages 6 | class TestStepResultStatus 7 | UNKNOWN = 'UNKNOWN' 8 | PASSED = 'PASSED' 9 | SKIPPED = 'SKIPPED' 10 | PENDING = 'PENDING' 11 | UNDEFINED = 'UNDEFINED' 12 | AMBIGUOUS = 'AMBIGUOUS' 13 | FAILED = 'FAILED' 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /ruby/spec/cucumber/messages/helpers/id_generator/incrementing_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | describe Cucumber::Messages::Helpers::IdGenerator::Incrementing do 4 | subject(:generator) { described_class.new } 5 | 6 | describe '#new_id' do 7 | it 'returns 0 the first time' do 8 | expect(generator.new_id).to eq('0') 9 | end 10 | 11 | it 'increments on every call' do 12 | rand(2..5).times do |value| 13 | expect(generator.new_id).to eq(value.to_s) 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /javascript/test/IdGeneratorTest.ts: -------------------------------------------------------------------------------- 1 | import assert from "node:assert" 2 | import {IdGenerator} from "../src/index.js" 3 | 4 | describe('IdGenerator', () => { 5 | it('generates uuids', () => { 6 | const generator = IdGenerator.uuid() 7 | const result = generator() 8 | assert.equal(result.length, 36) 9 | }); 10 | 11 | it('increments ids', () => { 12 | const generator = IdGenerator.incrementing() 13 | assert.equal(generator(), '0') 14 | assert.equal(generator(), '1') 15 | assert.equal(generator(), '2') 16 | }) 17 | }) -------------------------------------------------------------------------------- /jsonschema/src/TestStepStarted.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "TestStepStarted.json", 4 | "additionalProperties": false, 5 | "required": [ 6 | "testCaseStartedId", 7 | "testStepId", 8 | "timestamp" 9 | ], 10 | "properties": { 11 | "testCaseStartedId": { 12 | "type": "string" 13 | }, 14 | "testStepId": { 15 | "type": "string" 16 | }, 17 | "timestamp": { 18 | "$ref": "./Timestamp.json" 19 | } 20 | }, 21 | "type": "object" 22 | } 23 | -------------------------------------------------------------------------------- /codegen/templates/python.enum.py.erb: -------------------------------------------------------------------------------- 1 | # This code was generated using the code generator from cucumber-messages. 2 | # Manual changes will be lost if the code is regenerated. 3 | # Generator: cucumber-messages-python 4 | 5 | from enum import Enum 6 | 7 | 8 | <%- @enums.each_with_index do |enum, index| -%> 9 | class <%= enum[:name] %>(Enum): 10 | <%- enum[:values].each do |value| -%> 11 | <%= format_enum_value(value) %> = "<%= value %>" 12 | <%- end -%> 13 | <%- if index < @enums.length - 1 -%> 14 | 15 | 16 | <%- end -%> 17 | <%- end -%> 18 | -------------------------------------------------------------------------------- /jsonschema/src/TestCaseFinished.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "TestCaseFinished.json", 4 | "additionalProperties": false, 5 | "required": [ 6 | "testCaseStartedId", 7 | "timestamp", 8 | "willBeRetried" 9 | ], 10 | "properties": { 11 | "testCaseStartedId": { 12 | "type": "string" 13 | }, 14 | "timestamp": { 15 | "$ref": "./Timestamp.json" 16 | }, 17 | "willBeRetried": { 18 | "type": "boolean" 19 | } 20 | }, 21 | "type": "object" 22 | } 23 | -------------------------------------------------------------------------------- /.github/workflows/release-cpan.yml: -------------------------------------------------------------------------------- 1 | name: Release Perl 2 | 3 | on: 4 | push: 5 | branches: [release/*] 6 | 7 | jobs: 8 | publish-cpan: 9 | name: Publish to CPAN 10 | runs-on: ubuntu-latest 11 | environment: Release 12 | permissions: 13 | contents: write 14 | steps: 15 | - uses: actions/checkout@v6 16 | - uses: cucumber/action-publish-cpan@v1.0.1 17 | with: 18 | cpan-user: ${{ secrets.CPAN_USER }} 19 | cpan-password: ${{ secrets.CPAN_PASSWORD }} 20 | working-directory: 'perl' 21 | -------------------------------------------------------------------------------- /codegen/generators/typescript.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Generator 4 | # Generator::TypeScript 5 | # Automatic Code generation overrides for the TypeScript programming language 6 | class TypeScript < Base 7 | def array_type_for(type_name) 8 | "readonly #{type_name}[]" 9 | end 10 | 11 | private 12 | 13 | def language_translations_for_data_types 14 | { 15 | 'integer' => 'number', 16 | 'string' => 'string', 17 | 'boolean' => 'boolean' 18 | } 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /java/src/main/java/io/cucumber/messages/TestStepResultStatusComparator.java: -------------------------------------------------------------------------------- 1 | package io.cucumber.messages; 2 | 3 | import io.cucumber.messages.types.TestStepResultStatus; 4 | 5 | import java.util.Comparator; 6 | 7 | /** 8 | * Orders test step results from least to most severe. 9 | */ 10 | public final class TestStepResultStatusComparator implements Comparator { 11 | @Override 12 | public int compare(TestStepResultStatus a, TestStepResultStatus b) { 13 | return Integer.compare(a.ordinal(), b.ordinal()); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /php/tests/Id/IdGeneratorTestTrait.php: -------------------------------------------------------------------------------- 1 | idGenerator->newId()); 12 | } 13 | 14 | public function testItDoesNotRepeatIds(): void 15 | { 16 | $id1 = $this->idGenerator->newId(); 17 | $id2 = $this->idGenerator->newId(); 18 | 19 | self::assertNotEquals($id1, $id2); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /php/src-generated/TestStepResult/Status.php: -------------------------------------------------------------------------------- 1 | 'int64', 20 | 'string' => 'string', 21 | 'boolean' => 'bool' 22 | } 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /dotnet/Cucumber.Messages.Specs/MessageToNdjsonWriterSUT.cs: -------------------------------------------------------------------------------- 1 | using Io.Cucumber.Messages.Types; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Cucumber.Messages.Specs 10 | { 11 | internal class MessageToNdjsonWriterSUT : MessageToNdjsonWriter 12 | { 13 | public MessageToNdjsonWriterSUT(Stream stream) : base(stream, (StreamWriter streamWriter, Envelope envelope) => streamWriter.Write(NdjsonSerializer.Serialize(envelope))) 14 | { 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /java/src/main/java/io/cucumber/messages/DurationComparator.java: -------------------------------------------------------------------------------- 1 | package io.cucumber.messages; 2 | 3 | import io.cucumber.messages.types.Duration; 4 | 5 | import java.util.Comparator; 6 | 7 | /** 8 | * Orders durations by their natural order. 9 | */ 10 | public final class DurationComparator implements Comparator { 11 | @Override 12 | public int compare(Duration a, Duration b) { 13 | int c = a.getSeconds().compareTo(b.getSeconds()); 14 | if (c != 0) { 15 | return c; 16 | } 17 | return a.getNanos().compareTo(b.getNanos()); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /codegen/templates/php.enum.php.erb: -------------------------------------------------------------------------------- 1 | <% @enums.each do |enum| -%> 2 | <%= enum[:name].split('\\').join('/') %>.php 3 | 12 | namespace Cucumber\Messages\<%= namespaces.slice(0,1)[0] %>; 13 | 14 | enum <%= namespaces[-1] %>: string 15 | { 16 | <%- enum[:values].each do |value| -%> 17 | case <%= enum_constant(value) %> = '<%= value %>'; 18 | <%- end -%> 19 | } 20 | <%- end -%> 21 | -------------------------------------------------------------------------------- /java/src/main/java/io/cucumber/messages/TimestampComparator.java: -------------------------------------------------------------------------------- 1 | package io.cucumber.messages; 2 | 3 | import io.cucumber.messages.types.Timestamp; 4 | 5 | import java.util.Comparator; 6 | 7 | /** 8 | * Orders timestamps by their natural order. 9 | */ 10 | public final class TimestampComparator implements Comparator { 11 | @Override 12 | public int compare(Timestamp a, Timestamp b) { 13 | int c = a.getSeconds().compareTo(b.getSeconds()); 14 | if (c != 0) { 15 | return c; 16 | } 17 | return a.getNanos().compareTo(b.getNanos()); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /testdata/README.md: -------------------------------------------------------------------------------- 1 | Test Data 2 | ========= 3 | 4 | This folder contains (one) interesting samples to test serialization and 5 | deserialization. It covers attribute casing, enum representation, optional 6 | values and numbers. 7 | 8 | This sample set is intentionally not exhaustive. As the message implementations 9 | are generated we are only interested in structural problems. A more exhaustive 10 | set of test data can be found in the [compatibility-kit](https://github.com/cucumber/compatibility-kit). 11 | 12 | Note: because the compatibility-kit depends on messages, we can't use it 13 | to test itself. 14 | -------------------------------------------------------------------------------- /javascript/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "declaration": true, 5 | "sourceMap": true, 6 | "allowJs": false, 7 | "resolveJsonModule": true, 8 | "esModuleInterop": true, 9 | "noImplicitAny": true, 10 | "downlevelIteration": true, 11 | "skipLibCheck": true, 12 | "strictNullChecks": true, 13 | "experimentalDecorators": true, 14 | "module": "ESNext", 15 | "lib": [ 16 | "ES6" 17 | ], 18 | "target": "ES6", 19 | "moduleResolution": "node", 20 | "allowSyntheticDefaultImports": true, 21 | "noEmit": true, 22 | } 23 | } -------------------------------------------------------------------------------- /.github/workflows/release-nuget.yml: -------------------------------------------------------------------------------- 1 | name: Release dotNET 2 | 3 | on: 4 | push: 5 | branches: 6 | - "release/*" 7 | 8 | jobs: 9 | publish-nuget: 10 | name: Publish package to NuGet.org 11 | runs-on: ubuntu-latest 12 | environment: Release 13 | steps: 14 | - uses: actions/checkout@v6 15 | - name: Setup .NET 16 | uses: actions/setup-dotnet@v5 17 | with: 18 | dotnet-version: 8.0.x 19 | - uses: cucumber/action-publish-nuget@v1.0.0 20 | with: 21 | nuget-api-key: ${{ secrets.NUGET_API_KEY }} 22 | working-directory: "dotnet" 23 | -------------------------------------------------------------------------------- /cpp/README.md: -------------------------------------------------------------------------------- 1 | # Cucumber Messages for C++ (JSON schema) 2 | 3 | ## Requirements 4 | 5 | This library requires: 6 | - A C++ 17 compiler (tested with GCC 10, 12) 7 | - [JSON for Modern C++](https://json.nlohmann.me/) 8 | 9 | ## Installing from Git repository 10 | 11 | ```shell 12 | $ git clone https://github.com/cucumber/messages 13 | $ cd messages/cpp 14 | $ cmake -S . -B build 15 | $ cmake --build build 16 | $ cmake --install build 17 | ``` 18 | 19 | ## CMake integration 20 | 21 | ```cmake 22 | find_package(cucumber-messages CONFIG REQUIRED) 23 | 24 | target_link_libraries(mylib PRIVATE cucumber::messages) 25 | ``` 26 | -------------------------------------------------------------------------------- /jsonschema/src/TestRunHookFinished.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "TestRunHookFinished.json", 4 | "additionalProperties": false, 5 | "required": [ 6 | "testRunHookStartedId", 7 | "result", 8 | "timestamp" 9 | ], 10 | "properties": { 11 | "testRunHookStartedId": { 12 | "description": "Identifier for the hook execution that has finished", 13 | "type": "string" 14 | }, 15 | "result": { 16 | "$ref": "./TestStepResult.json" 17 | }, 18 | "timestamp": { 19 | "$ref": "./Timestamp.json" 20 | } 21 | }, 22 | "type": "object" 23 | } -------------------------------------------------------------------------------- /jsonschema/src/TestStepFinished.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "TestStepFinished.json", 4 | "additionalProperties": false, 5 | "required": [ 6 | "testCaseStartedId", 7 | "testStepId", 8 | "testStepResult", 9 | "timestamp" 10 | ], 11 | "properties": { 12 | "testCaseStartedId": { 13 | "type": "string" 14 | }, 15 | "testStepId": { 16 | "type": "string" 17 | }, 18 | "testStepResult": { 19 | "$ref": "./TestStepResult.json" 20 | }, 21 | "timestamp": { 22 | "$ref": "./Timestamp.json" 23 | } 24 | }, 25 | "type": "object" 26 | } 27 | -------------------------------------------------------------------------------- /codegen/codegen.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'generators/text_helpers' 4 | 5 | require_relative 'generators/base' 6 | 7 | require_relative 'generators/cpp' 8 | require_relative 'generators/dotnet' 9 | require_relative 'generators/go' 10 | require_relative 'generators/java' 11 | require_relative 'generators/markdown' 12 | require_relative 'generators/perl' 13 | require_relative 'generators/php' 14 | require_relative 'generators/python' 15 | require_relative 'generators/ruby' 16 | require_relative 'generators/typescript' 17 | 18 | clazz = Object.const_get(ARGV[0]) 19 | template_name = ARGV[1] 20 | clazz.new.generate(template_name) 21 | -------------------------------------------------------------------------------- /php/src/Streams/NdJson/NdJsonStreamWriter.php: -------------------------------------------------------------------------------- 1 | $envelopes 17 | */ 18 | public function writeEnvelopes(iterable $envelopes): void 19 | { 20 | foreach ($envelopes as $envelope) { 21 | fputs($this->fileHandle, $envelope->asJson() . "\n"); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /perl/t/02-instantiation.t: -------------------------------------------------------------------------------- 1 | #!perl 2 | 3 | use Test2::V0; 4 | no strict 'refs'; 5 | 6 | use Cucumber::Messages; 7 | 8 | # Go over all subpackages of the Cucumber::Messages package; 9 | # each subpackage should also be a Moo class, which we can instantiate. 10 | # Verify that each class can be instantiated without supplying arguments 11 | # (all required parameters have a default value; this tests the execution 12 | # of the subs that provide the default values) 13 | for my $pkg ( grep { m/::$/ } keys %{ "Cucumber::Messages::" }) { 14 | my $class = ($pkg =~ s/::$//r); 15 | 16 | ok lives { "Cucumber::Messages::$class"->new() } 17 | or diag $@; 18 | } 19 | 20 | 21 | done_testing; 22 | -------------------------------------------------------------------------------- /php/src/Streams/NdJson/NdJsonStreamReader.php: -------------------------------------------------------------------------------- 1 | 18 | */ 19 | public function envelopes(): Generator 20 | { 21 | while (!feof($this->fileHandle) && ($line = fgets($this->fileHandle))) { 22 | yield Envelope::fromJson($line); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /elixir/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.toptal.com/developers/gitignore/api/elixir,vscode 3 | # Edit at https://www.toptal.com/developers/gitignore?templates=elixir,vscode 4 | 5 | ### Elixir ### 6 | /_build 7 | /cover 8 | /deps 9 | /doc 10 | /.fetch 11 | erl_crash.dump 12 | *.ez 13 | *.beam 14 | /config/*.secret.exs 15 | .elixir_ls/ 16 | 17 | ### Elixir Patch ### 18 | 19 | ### vscode ### 20 | .vscode/* 21 | !.vscode/settings.json 22 | !.vscode/tasks.json 23 | !.vscode/launch.json 24 | !.vscode/extensions.json 25 | *.code-workspace 26 | 27 | # End of https://www.toptal.com/developers/gitignore/api/elixir,vscode 28 | 29 | .deps 30 | .tested 31 | .compile_messages 32 | .setup_mix_and_get_dependencies 33 | -------------------------------------------------------------------------------- /.github/workflows/test-dotnet.yml: -------------------------------------------------------------------------------- 1 | name: test-dotnet 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - renovate/** 8 | paths: 9 | - dotnet/** 10 | - Makefile 11 | - .github/** 12 | pull_request: 13 | branches: 14 | - main 15 | paths: 16 | - dotnet/** 17 | - Makefile 18 | - .github/** 19 | workflow_call: 20 | 21 | jobs: 22 | test-dotnet: 23 | runs-on: ubuntu-latest 24 | 25 | steps: 26 | - uses: actions/checkout@v6 27 | - uses: actions/setup-dotnet@v5 28 | with: 29 | dotnet-version: '8.0.x' 30 | 31 | - name: run tests 32 | run: | 33 | dotnet test 34 | working-directory: dotnet 35 | -------------------------------------------------------------------------------- /php/psalm.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /php/tests/Id/IncrementingIdGeneratorTest.php: -------------------------------------------------------------------------------- 1 | idGenerator = new IncrementingIdGenerator(); 16 | } 17 | 18 | public function testItIncrementsFromZero(): void 19 | { 20 | self::assertSame('0', $this->idGenerator->newId()); 21 | self::assertSame('1', $this->idGenerator->newId()); 22 | self::assertSame('2', $this->idGenerator->newId()); 23 | self::assertSame('3', $this->idGenerator->newId()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /.github/workflows/release-npm.yml: -------------------------------------------------------------------------------- 1 | name: Release NPM 2 | 3 | on: 4 | push: 5 | branches: [release/*] 6 | 7 | permissions: 8 | id-token: write 9 | contents: read 10 | 11 | jobs: 12 | publish-npm: 13 | name: Publish NPM module 14 | runs-on: ubuntu-latest 15 | environment: Release 16 | steps: 17 | - uses: actions/checkout@v6 18 | - uses: actions/setup-node@v6 19 | with: 20 | node-version: '24.x' 21 | cache: 'npm' 22 | cache-dependency-path: javascript/package-lock.json 23 | registry-url: 'https://registry.npmjs.org' 24 | - run: npm install-ci-test 25 | working-directory: javascript 26 | - run: npm publish 27 | working-directory: javascript 28 | -------------------------------------------------------------------------------- /cpp/src/lib/messages/cucumber/messages/utils.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace cucumber::messages { 4 | 5 | // https://codereview.stackexchange.com/questions/263749/codewars-kata-converting-snake-case-identifiers-to-camelcase-in-c 6 | std::string 7 | camelize(std::string s, bool initial_tail) 8 | { 9 | std::size_t n = 0; 10 | bool tail = initial_tail; 11 | 12 | for (unsigned char c : s) { 13 | if (c == '-' || c == '_') { 14 | tail = false; 15 | } else if (tail) { 16 | s[n++] = c; 17 | } else { 18 | tail = true; 19 | s[n++] = std::toupper(c); 20 | } 21 | } 22 | 23 | s.resize(n); 24 | 25 | return s; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /dotnet/Cucumber.Messages/ProtocolVersion.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | using System.Text; 5 | 6 | namespace Cucumber.Messages 7 | { 8 | public class ProtocolVersion 9 | { 10 | public static string Version 11 | { 12 | get 13 | { 14 | return GetPackageVersion(typeof(ProtocolVersion).GetTypeInfo().Assembly); 15 | } 16 | } 17 | 18 | private static string GetPackageVersion(Assembly assembly) 19 | { 20 | var version = assembly.GetCustomAttribute()?.InformationalVersion; 21 | return version?.Split(new char['+'], 2)[0]; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ruby/spec/support/comprehensive_message.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'simple_message' 4 | 5 | module Cucumber 6 | module Messages 7 | class ComprehensiveMessage < Message 8 | attr_reader :simple_message, :message_array, :is_enum 9 | 10 | def initialize( 11 | simple_message: SimpleMessage.new, 12 | message_array: [SimpleMessage.new, SimpleMessage.new], 13 | is_enum: EnumMessage::ENUM 14 | ) 15 | @simple_message = simple_message 16 | @message_array = message_array 17 | @is_enum = is_enum 18 | super() 19 | end 20 | 21 | def self.message_array_from_h(hash) 22 | SimpleMessage.from_h(hash) 23 | end 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /jsonschema/src/Duration.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "Duration.json", 4 | "additionalProperties": false, 5 | "description": "The structure is pretty close of the Timestamp one. For clarity, a second type\nof message is used.", 6 | "required": [ 7 | "seconds", 8 | "nanos" 9 | ], 10 | "properties": { 11 | "seconds": { 12 | "type": "integer" 13 | }, 14 | "nanos": { 15 | "description": "Non-negative fractions of a second at nanosecond resolution. Negative\nsecond values with fractions must still have non-negative nanos values\nthat count forward in time. Must be from 0 to 999,999,999\ninclusive.", 16 | "type": "integer" 17 | } 18 | }, 19 | "type": "object" 20 | } 21 | -------------------------------------------------------------------------------- /cpp/src/lib/messages/cucumber/messages/attachment_content_encoding.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | namespace cucumber::messages { 7 | 8 | std::string_view 9 | to_string(attachment_content_encoding v) 10 | { 11 | using map_type = std::unordered_map; 12 | 13 | static const map_type m = { 14 | { attachment_content_encoding::IDENTITY, "IDENTITY" }, 15 | { attachment_content_encoding::BASE64, "BASE64" } 16 | }; 17 | 18 | return m.at(v); 19 | } 20 | 21 | std::ostream& 22 | operator<<(std::ostream& os, attachment_content_encoding v) 23 | { 24 | os << to_string(v); 25 | 26 | return os; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /.github/workflows/release-pypi.yml: -------------------------------------------------------------------------------- 1 | name: Release Python 2 | 3 | on: 4 | push: 5 | branches: [release/*] 6 | 7 | jobs: 8 | publish-pypi: 9 | name: Publish PyPI Package 10 | runs-on: ubuntu-latest 11 | environment: Release 12 | permissions: 13 | id-token: write 14 | defaults: 15 | run: 16 | working-directory: python 17 | steps: 18 | - uses: actions/checkout@v6 19 | 20 | - name: Install uv and set the python version 21 | uses: astral-sh/setup-uv@v7 22 | with: 23 | enable-cache: true 24 | python-version: "3.13" 25 | version: "0.9.18" 26 | 27 | - name: Build package 28 | run: uv build 29 | 30 | - name: Publish package 31 | run: uv publish --trusted-publishing=always 32 | -------------------------------------------------------------------------------- /python/.gitignore: -------------------------------------------------------------------------------- 1 | *.rej 2 | *.py[cod] 3 | /.env 4 | *.orig 5 | **/__pycache__ 6 | 7 | # C extensions 8 | *.so 9 | 10 | # Packages 11 | *.egg 12 | *.egg-info 13 | dist 14 | build 15 | _build 16 | eggs 17 | parts 18 | bin 19 | var 20 | sdist 21 | develop-eggs 22 | .installed.cfg 23 | lib 24 | lib64 25 | 26 | # Installer logs 27 | pip-log.txt 28 | 29 | # Unit test / coverage reports 30 | .coverage 31 | coverage.xml 32 | .tox 33 | nosetests.xml 34 | 35 | # Translations 36 | *.mo 37 | 38 | # Mr Developer 39 | .mr.developer.cfg 40 | .project 41 | .pydevproject 42 | .pytest_cache 43 | .ropeproject 44 | 45 | # Sublime 46 | /*.sublime-* 47 | 48 | #PyCharm 49 | /.idea 50 | 51 | # virtualenv 52 | /.Python 53 | /lib 54 | /include 55 | /share 56 | /local 57 | .venv/ 58 | 59 | .mypy_cache/ 60 | .ruff_cache/ 61 | -------------------------------------------------------------------------------- /.github/workflows/release-mvn.yml: -------------------------------------------------------------------------------- 1 | name: Release Java 2 | 3 | on: 4 | push: 5 | branches: [release/*] 6 | 7 | jobs: 8 | publish-mvn: 9 | name: Publish Maven Package 10 | runs-on: ubuntu-latest 11 | environment: Release 12 | steps: 13 | - uses: actions/checkout@v6 14 | - uses: actions/setup-java@v5 15 | with: 16 | distribution: 'temurin' 17 | java-version: '17' 18 | cache: 'maven' 19 | - uses: cucumber/action-publish-mvn@v3.0.0 20 | with: 21 | gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} 22 | gpg-passphrase: ${{ secrets.GPG_PASSPHRASE }} 23 | nexus-username: ${{ secrets.SONATYPE_USERNAME }} 24 | nexus-password: ${{ secrets.SONATYPE_PASSWORD }} 25 | working-directory: java 26 | -------------------------------------------------------------------------------- /codegen/templates/go.enum.go.erb: -------------------------------------------------------------------------------- 1 | <% @enums.each_with_index do |enum, index| -%> 2 | type <%= enum[:name] %> string 3 | 4 | const ( 5 | <%- 6 | enum_constant_max_length = enum[:values].max_by { |value| enum_constant(value).length }.length 7 | -%> 8 | <% enum[:values].each do |value| -%> 9 | <%=enum[:name] %>_<%= enum_constant(value).ljust(enum_constant_max_length) %> <%= enum[:name] %> = "<%= value %>" 10 | <% end -%> 11 | ) 12 | 13 | func (e <%= enum[:name] %>) String() string { 14 | switch e { 15 | <%- enum[:values].each do |value| -%> 16 | case <%= enum[:name] %>_<%= enum_constant(value) %>: 17 | return "<%= value %>" 18 | <%- end -%> 19 | default: 20 | panic("Bad enum value for <%= enum[:name] %>") 21 | } 22 | } 23 | <%- if index != @enums.size - 1 -%> 24 | 25 | <%- end -%> 26 | <%- end -%> 27 | -------------------------------------------------------------------------------- /cpp/src/lib/messages/cucumber/messages/source_media_type.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | namespace cucumber::messages { 7 | 8 | std::string_view 9 | to_string(source_media_type v) 10 | { 11 | using map_type = std::unordered_map; 12 | 13 | static const map_type m = { 14 | { source_media_type::TEXT_X_CUCUMBER_GHERKIN_PLAIN, "text/x.cucumber.gherkin+plain" }, 15 | { source_media_type::TEXT_X_CUCUMBER_GHERKIN_MARKDOWN, "text/x.cucumber.gherkin+markdown" } 16 | }; 17 | 18 | return m.at(v); 19 | } 20 | 21 | std::ostream& 22 | operator<<(std::ostream& os, source_media_type v) 23 | { 24 | os << to_string(v); 25 | 26 | return os; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /php/phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | tests 13 | 14 | 15 | 16 | 17 | 18 | src 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /cpp/src/lib/messages/cucumber/messages/pickle_step_type.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | namespace cucumber::messages { 7 | 8 | std::string_view 9 | to_string(pickle_step_type v) 10 | { 11 | using map_type = std::unordered_map; 12 | 13 | static const map_type m = { 14 | { pickle_step_type::UNKNOWN, "Unknown" }, 15 | { pickle_step_type::CONTEXT, "Context" }, 16 | { pickle_step_type::ACTION, "Action" }, 17 | { pickle_step_type::OUTCOME, "Outcome" } 18 | }; 19 | 20 | return m.at(v); 21 | } 22 | 23 | std::ostream& 24 | operator<<(std::ostream& os, pickle_step_type v) 25 | { 26 | os << to_string(v); 27 | 28 | return os; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /jsonschema/src/Timestamp.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "Timestamp.json", 4 | "additionalProperties": false, 5 | "required": [ 6 | "seconds", 7 | "nanos" 8 | ], 9 | "properties": { 10 | "seconds": { 11 | "description": "Represents seconds of UTC time since Unix epoch\n1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to\n9999-12-31T23:59:59Z inclusive.", 12 | "type": "integer" 13 | }, 14 | "nanos": { 15 | "description": "Non-negative fractions of a second at nanosecond resolution. Negative\nsecond values with fractions must still have non-negative nanos values\nthat count forward in time. Must be from 0 to 999,999,999\ninclusive.", 16 | "type": "integer" 17 | } 18 | }, 19 | "type": "object" 20 | } 21 | -------------------------------------------------------------------------------- /.github/workflows/test-perl.yml: -------------------------------------------------------------------------------- 1 | name: test-perl 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - renovate/** 8 | paths: 9 | - perl/** 10 | - Makefile 11 | - .github/** 12 | pull_request: 13 | branches: 14 | - main 15 | paths: 16 | - perl/** 17 | - Makefile 18 | - .github/** 19 | workflow_call: 20 | 21 | jobs: 22 | test-perl: 23 | runs-on: ubuntu-latest 24 | 25 | steps: 26 | - uses: actions/checkout@v6 27 | 28 | - name: install cpanm and multiple modules 29 | uses: perl-actions/install-with-cpanm@v1 30 | with: 31 | cpanfile: "perl/cpanfile" 32 | 33 | - name: run tests 34 | run: | 35 | prove -l 36 | AUTHOR_TESTS=1 prove -l 37 | working-directory: perl 38 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/snippet.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace cucumber::messages { 10 | 11 | using json = nlohmann::json; 12 | 13 | // 14 | // Represents the Snippet message in Cucumber's message protocol 15 | // @see Github - Cucumber - Messages 16 | // 17 | // Generated code 18 | 19 | struct snippet 20 | { 21 | std::string language; 22 | std::string code; 23 | 24 | std::string to_string() const; 25 | 26 | void to_json(json& j) const; 27 | std::string to_json() const; 28 | }; 29 | 30 | std::ostream& 31 | operator<<(std::ostream& os, const snippet& msg); 32 | 33 | void to_json(json& j, const snippet& m); 34 | 35 | } 36 | -------------------------------------------------------------------------------- /codegen/generators/text_helpers.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Generator 4 | # Generator::TextHelpers 5 | # A few handy text helpers for converting text strings into different formats 6 | module TextHelpers 7 | private 8 | 9 | def capitalize(string) 10 | string.sub(/./, &:upcase) 11 | end 12 | 13 | # Adapted from rails -> https://github.com/rails/rails/blob/v6.1.3.2/activesupport/lib/active_support/inflector/methods.rb#L92 14 | def underscore(camel_cased_word) 15 | return camel_cased_word unless /[A-Z-]/.match?(camel_cased_word) 16 | 17 | camel_cased_word.gsub(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2') 18 | .gsub(/([a-z\d])([A-Z])/, '\1_\2') 19 | .tr('-', '_') 20 | .downcase 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /elixir/Makefile: -------------------------------------------------------------------------------- 1 | include default.mk 2 | 3 | clean: 4 | rm -rf _build deps .deps .tested 5 | rm -rf lib/cucumber_messages/generated/* 6 | 7 | .deps: setup_mix_and_get_dependencies update_proto_file compile_messages revert_proto_file 8 | touch .deps 9 | 10 | setup_mix_and_get_dependencies: 11 | mix local.hex --force 12 | mix deps.get 13 | .PHONY: setup_mix_and_get_dependencies 14 | 15 | update_proto_file: messages.proto 16 | mv $< $<.bak 17 | cat $<.bak | sed "s/package io.cucumber.messages/package cucumber_messages/" > $< 18 | 19 | compile_messages: 20 | MIX_ENV=prod mix protox.generate --multiple-files --output-path=lib/cucumber_messages/generated messages.proto 21 | .PHONY: compile_messages 22 | 23 | revert_proto_file: messages.proto.bak 24 | mv messages.proto.bak messages.proto 25 | .PHONY: revert_proto_file 26 | -------------------------------------------------------------------------------- /python/tests/test_model_load.py: -------------------------------------------------------------------------------- 1 | import json 2 | from pathlib import Path 3 | 4 | from cucumber_messages import Envelope, message_converter 5 | 6 | 7 | # Analog of "ruby/spec/cucumber/messages/acceptance_spec.rb" test 8 | def test_simple_load_model(): 9 | for ast_path in (Path(__file__).resolve().parent / "testdata" / "src").rglob("*.ndjson"): 10 | print(f"Checking ${ast_path}") 11 | with ast_path.open(mode="r") as ast_file: 12 | for ast_line in ast_file: 13 | model_datum = json.loads(ast_line) 14 | model = message_converter.from_dict(model_datum, Envelope) 15 | 16 | assert isinstance(model, Envelope) 17 | 18 | dumped_ast_datum = message_converter.to_dict(model) 19 | 20 | assert model_datum == dumped_ast_datum 21 | -------------------------------------------------------------------------------- /ruby/lib/cucumber/messages/helpers/ndjson_to_message_enumerator.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'cucumber/messages' 4 | 5 | module Cucumber 6 | module Messages 7 | module Helpers 8 | class NdjsonToMessageEnumerator < Enumerator 9 | def initialize(io) 10 | super() do |yielder| 11 | io.each_line do |line| 12 | next if line.strip.empty? 13 | 14 | message = extract_message(line) 15 | yielder.yield(message) 16 | end 17 | end 18 | end 19 | 20 | private 21 | 22 | def extract_message(json_line) 23 | Envelope.from_json(json_line) 24 | rescue StandardError 25 | raise "Not JSON: #{json_line.strip}" 26 | end 27 | end 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /codegen/templates/markdown.md.erb: -------------------------------------------------------------------------------- 1 | # Cucumber Messages 2 | 3 | Each message is an instance of [Envelope](#envelope). The `Envelope` message 4 | will only have one of its fields set, which indicates the payload of the message. 5 | 6 | <% @schemas.each do |key, schema| -%> 7 | ## <%= class_name(key) %> 8 | 9 | <%= schema['description'] %> 10 | <%- schema['properties'].each do |property_name, property| -%> 11 | <%- 12 | type_name = type_for(class_name(key), property_name, property) 13 | required = (schema['required'] || []).index(property_name) 14 | description = ( property['description'] || '') 15 | -%> 16 | 17 | #### <%= class_name(key) %>.<%= property_name %> 18 | 19 | * Type: <%= type_name %> 20 | * Required: <%= required ? 'yes' : 'no' %> 21 | 22 | <%= description -%> 23 | 24 | <%- end -%> 25 | 26 | <%- end -%> 27 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/timestamp.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace cucumber::messages { 10 | 11 | using json = nlohmann::json; 12 | 13 | // 14 | // Represents the Timestamp message in Cucumber's message protocol 15 | // @see Github - Cucumber - Messages 16 | // 17 | // Generated code 18 | 19 | struct timestamp 20 | { 21 | std::size_t seconds; 22 | std::size_t nanos; 23 | 24 | std::string to_string() const; 25 | 26 | void to_json(json& j) const; 27 | std::string to_json() const; 28 | }; 29 | 30 | std::ostream& 31 | operator<<(std::ostream& os, const timestamp& msg); 32 | 33 | void to_json(json& j, const timestamp& m); 34 | 35 | } 36 | -------------------------------------------------------------------------------- /dotnet/Cucumber.Messages.Specs/Cucumber.Messages.Specs.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | False 6 | 7 | 8 | 9 | 10 | 11 | 12 | all 13 | runtime; build; native; contentfiles; analyzers; buildtransitive 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /jsonschema/src/Hook.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "Hook.json", 4 | "additionalProperties": false, 5 | "required": [ 6 | "id", 7 | "sourceReference" 8 | ], 9 | "properties": { 10 | "id": { 11 | "type": "string" 12 | }, 13 | "name": { 14 | "type": "string" 15 | }, 16 | "sourceReference": { 17 | "$ref": "./SourceReference.json" 18 | }, 19 | "tagExpression": { 20 | "type": "string" 21 | }, 22 | "type": { 23 | "type": "string", 24 | "enum": [ 25 | "BEFORE_TEST_RUN", 26 | "AFTER_TEST_RUN", 27 | "BEFORE_TEST_CASE", 28 | "AFTER_TEST_CASE", 29 | "BEFORE_TEST_STEP", 30 | "AFTER_TEST_STEP" 31 | ] 32 | } 33 | }, 34 | "type": "object" 35 | } 36 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | languages = jsonschema cpp dotnet go java javascript perl php python ruby 2 | 3 | .DEFAULT_GOAL = help 4 | 5 | help: ## Show this help 6 | @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \n\nWhere is one of:\n"} /^[$$()% a-zA-Z_-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) 7 | 8 | generate: $(patsubst %,generate-%,$(languages)) ## Generate documentation and code for all supported languages 9 | .PHONY: generate 10 | 11 | generate-%: % 12 | $(MAKE) --directory=$< generate 13 | .PHONY: generate-% 14 | 15 | clean: $(patsubst %,clean-%,$(languages)) ## Clean generated documentation and code of all supported languages 16 | .PHONY: clean 17 | 18 | clean-%: % 19 | $(MAKE) --directory=$< clean 20 | .PHONY: clean-% 21 | -------------------------------------------------------------------------------- /cpp/src/lib/messages/cucumber/messages/step_definition_pattern_type.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | namespace cucumber::messages { 7 | 8 | std::string_view 9 | to_string(step_definition_pattern_type v) 10 | { 11 | using map_type = std::unordered_map; 12 | 13 | static const map_type m = { 14 | { step_definition_pattern_type::CUCUMBER_EXPRESSION, "CUCUMBER_EXPRESSION" }, 15 | { step_definition_pattern_type::REGULAR_EXPRESSION, "REGULAR_EXPRESSION" } 16 | }; 17 | 18 | return m.at(v); 19 | } 20 | 21 | std::ostream& 22 | operator<<(std::ostream& os, step_definition_pattern_type v) 23 | { 24 | os << to_string(v); 25 | 26 | return os; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/pickle_table_cell.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace cucumber::messages { 10 | 11 | using json = nlohmann::json; 12 | 13 | // 14 | // Represents the PickleTableCell message in Cucumber's message protocol 15 | // @see Github - Cucumber - Messages 16 | // 17 | // Generated code 18 | 19 | struct pickle_table_cell 20 | { 21 | std::string value; 22 | 23 | std::string to_string() const; 24 | 25 | void to_json(json& j) const; 26 | std::string to_json() const; 27 | }; 28 | 29 | std::ostream& 30 | operator<<(std::ostream& os, const pickle_table_cell& msg); 31 | 32 | void to_json(json& j, const pickle_table_cell& m); 33 | 34 | } 35 | -------------------------------------------------------------------------------- /codegen/generators/markdown.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Generator 4 | # Generator::Markdown 5 | # Automatic Code generation overrides for the 'Cucumber with Markdown' programming language 6 | # NB: This is based on the cucumber-js implementation 7 | class Markdown < Base 8 | 9 | def array_type_for(type_name) 10 | "#{type_name}[]" 11 | end 12 | 13 | def property_type_from_enum(enum) 14 | "[#{enum}](##{enum.downcase})" 15 | end 16 | 17 | def property_type_from_ref(ref) 18 | "[#{class_name(ref)}](##{class_name(ref).downcase})" 19 | end 20 | 21 | private 22 | 23 | def language_translations_for_data_types 24 | { 25 | 'integer' => 'integer', 26 | 'string' => 'string', 27 | 'boolean' => 'boolean' 28 | } 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /javascript/test/getWorstTestStepResultsTest.ts: -------------------------------------------------------------------------------- 1 | import { getWorstTestStepResult } from '../src/getWorstTestStepResult.js' 2 | import { TestStepResultStatus } from '../src/messages.js' 3 | import assert from 'assert' 4 | 5 | describe('getWorstTestStepResult', () => { 6 | it('returns a FAILED result for PASSED,FAILED,PASSED', () => { 7 | const result = getWorstTestStepResult([ 8 | { 9 | status: TestStepResultStatus.PASSED, 10 | duration: { seconds: 0, nanos: 0 }, 11 | }, 12 | { 13 | status: TestStepResultStatus.FAILED, 14 | duration: { seconds: 0, nanos: 0 }, 15 | }, 16 | { 17 | status: TestStepResultStatus.PASSED, 18 | duration: { seconds: 0, nanos: 0 }, 19 | }, 20 | ]) 21 | assert.strictEqual(result.status, TestStepResultStatus.FAILED) 22 | }) 23 | }) 24 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/pickle_tag.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace cucumber::messages { 10 | 11 | using json = nlohmann::json; 12 | 13 | // 14 | // Represents the PickleTag message in Cucumber's message protocol 15 | // @see Github - Cucumber - Messages 16 | // 17 | // A tag 18 | // 19 | // Generated code 20 | 21 | struct pickle_tag 22 | { 23 | std::string name; 24 | std::string ast_node_id; 25 | 26 | std::string to_string() const; 27 | 28 | void to_json(json& j) const; 29 | std::string to_json() const; 30 | }; 31 | 32 | std::ostream& 33 | operator<<(std::ostream& os, const pickle_tag& msg); 34 | 35 | void to_json(json& j, const pickle_tag& m); 36 | 37 | } 38 | -------------------------------------------------------------------------------- /jsonschema/src/Exception.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "Exception.json", 4 | "additionalProperties": false, 5 | "description": "A simplified representation of an exception", 6 | "required": [ 7 | "type" 8 | ], 9 | "properties": { 10 | "type": { 11 | "type": "string", 12 | "description": "The type of the exception that caused this result. E.g. \"Error\" or \"org.opentest4j.AssertionFailedError\"" 13 | }, 14 | "message": { 15 | "type": "string", 16 | "description": "The message of exception that caused this result. E.g. expected: \"a\" but was: \"b\"" 17 | }, 18 | "stackTrace": { 19 | "type": "string", 20 | "description": "The stringified stack trace of the exception that caused this result" 21 | } 22 | }, 23 | "type": "object" 24 | } 25 | -------------------------------------------------------------------------------- /codegen/generators/dotnet.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Generator 4 | # Generator::Dotnet 5 | # Automatic Code generation overrides for the .NET programming language 6 | class Dotnet < Base 7 | def array_type_for(type_name) 8 | "List<#{type_name}>" 9 | end 10 | 11 | def format_description(raw_description, indent_string: '') 12 | return '' if raw_description.nil? 13 | 14 | raw_description 15 | .split("\n") 16 | .map(&:strip) 17 | .reject { |line| line == '*' } 18 | .map { |line| " * #{line}".rstrip } 19 | .join("\n#{indent_string}") 20 | end 21 | 22 | private 23 | 24 | def language_translations_for_data_types 25 | { 26 | 'integer' => 'long', 27 | 'string' => 'string', 28 | 'boolean' => 'bool' 29 | } 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /codegen/templates/go.go.erb: -------------------------------------------------------------------------------- 1 | package messages 2 | 3 | <% @schemas.each do |key, schema| -%> 4 | type <%= class_name(key) %> struct { 5 | <%- 6 | property_name_max_length = schema['properties'].max_by{ |property_name,_| property_name.length }[0].length 7 | type_names = schema['properties'].map { |property_name, property| [property_name, type_for(class_name(key), property_name, property)] } 8 | type_name_max_length = type_names.max_by{ |_,type_name| type_name.length }[1].length 9 | -%> 10 | <%- type_names.each do |property_name, type_name| -%> 11 | <%- 12 | required = (schema['required'] || []).index(property_name) 13 | -%> 14 | <%- %> <%= capitalize(property_name).ljust(property_name_max_length) %> <%= type_name.ljust(type_name_max_length) %> `json:"<%= property_name %><%= required ? '' : ',omitempty' %>"` 15 | <%- end -%> 16 | } 17 | 18 | <% end -%> -------------------------------------------------------------------------------- /codegen/templates/typescript.ts.erb: -------------------------------------------------------------------------------- 1 | import { Type } from 'class-transformer' 2 | import 'reflect-metadata' 3 | 4 | <% @schemas.each do |key, schema| -%> 5 | export class <%= class_name(key) -%> { 6 | <%- schema['properties'].each do |property_name, property| -%> 7 | 8 | <%- ref = property['$ref'] || property['items'] && property['items']['$ref'] -%> 9 | <%- if ref -%> 10 | <%- %> @Type(() => <%= class_name(ref) -%>) 11 | <%- end -%> 12 | <%- if (schema['required'] || []).index(property_name) -%> 13 | <%- %> <%= property_name %>: <%= type_for(class_name(key), property_name, property) -%> = <%= default_value(class_name(key), property_name, property) -%> 14 | <%- else -%> 15 | <%- %> <%= property_name %>?: <%= type_for(class_name(key), property_name, property) -%> 16 | <%- end -%> 17 | 18 | <%- end -%> 19 | } 20 | 21 | <% end -%> 22 | -------------------------------------------------------------------------------- /ruby/spec/cucumber/messages/acceptance_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'json' 4 | 5 | module Cucumber 6 | module Messages 7 | describe 'messages acceptance tests' do 8 | Dir.entries('../testdata/src').filter { |file| File.extname(file) == ".ndjson" }.each do |example| 9 | context "with the '#{example}'" do 10 | it 'deserializes and serializes messages in the ndjson file' do 11 | File.open("../testdata/src/#{example}", 'r:utf-8') do |file| 12 | file.each_line do |message| 13 | # Check that the Envelope re-generated message equals the originally parsed message 14 | expect(JSON.parse(Envelope.from_json(message).to_json)).to eq(JSON.parse(message)) 15 | end 16 | end 17 | end 18 | end 19 | end 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /codegen/generators/cpp.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Generator 4 | # Generator::Cpp 5 | # Automatic Code generation overrides for the C++ programming language 6 | class Cpp < Base 7 | def array_type_for(type_name) 8 | "std::vector<#{type_name}>" 9 | end 10 | 11 | def format_description(raw_description, indent_string: '') 12 | return '' if raw_description.nil? 13 | 14 | raw_description 15 | .split("\n") 16 | .map(&:strip) 17 | .reject { |line| line == '*' } 18 | .map { |line| "// #{line}".rstrip } 19 | .join("\n#{indent_string}") 20 | end 21 | 22 | private 23 | 24 | def language_translations_for_data_types 25 | { 26 | 'integer' => 'std::size_t', 27 | 'string' => 'std::string', 28 | 'boolean' => 'bool' 29 | } 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/pickle_doc_string.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace cucumber::messages { 10 | 11 | using json = nlohmann::json; 12 | 13 | // 14 | // Represents the PickleDocString message in Cucumber's message protocol 15 | // @see Github - Cucumber - Messages 16 | // 17 | // Generated code 18 | 19 | struct pickle_doc_string 20 | { 21 | std::optional media_type; 22 | std::string content; 23 | 24 | std::string to_string() const; 25 | 26 | void to_json(json& j) const; 27 | std::string to_json() const; 28 | }; 29 | 30 | std::ostream& 31 | operator<<(std::ostream& os, const pickle_doc_string& msg); 32 | 33 | void to_json(json& j, const pickle_doc_string& m); 34 | 35 | } 36 | -------------------------------------------------------------------------------- /cpp/src/lib/messages/cucumber/messages/step_keyword_type.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | namespace cucumber::messages { 7 | 8 | std::string_view 9 | to_string(step_keyword_type v) 10 | { 11 | using map_type = std::unordered_map; 12 | 13 | static const map_type m = { 14 | { step_keyword_type::UNKNOWN, "Unknown" }, 15 | { step_keyword_type::CONTEXT, "Context" }, 16 | { step_keyword_type::ACTION, "Action" }, 17 | { step_keyword_type::OUTCOME, "Outcome" }, 18 | { step_keyword_type::CONJUNCTION, "Conjunction" } 19 | }; 20 | 21 | return m.at(v); 22 | } 23 | 24 | std::ostream& 25 | operator<<(std::ostream& os, step_keyword_type v) 26 | { 27 | os << to_string(v); 28 | 29 | return os; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /.github/workflows/release-hex.yml: -------------------------------------------------------------------------------- 1 | name: Release Elixir 2 | 3 | on: 4 | push: 5 | branches: [release/*] 6 | 7 | jobs: 8 | publish-hex: 9 | name: Publish to hex.pm 10 | runs-on: ubuntu-latest 11 | environment: Release 12 | permissions: 13 | contents: write 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v6 17 | - name: Setup Beam 18 | uses: erlef/setup-beam@v1 19 | with: 20 | otp-version: '27.1' 21 | elixir-version: '1.17' 22 | - name: Install Protoc 23 | uses: arduino/setup-protoc@v1 24 | - name: Run Tests 25 | run: make 26 | working-directory: elixir 27 | - name: Publish to hex.pm 28 | uses: cucumber/action-publish-hex@v1.0.0 29 | with: 30 | hex-api-key: ${{ secrets.HEX_API_KEY }} 31 | working-directory: 'elixir' 32 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/product.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace cucumber::messages { 10 | 11 | using json = nlohmann::json; 12 | 13 | // 14 | // Represents the Product message in Cucumber's message protocol 15 | // @see Github - Cucumber - Messages 16 | // 17 | // Used to describe various properties of Meta 18 | // 19 | // Generated code 20 | 21 | struct product 22 | { 23 | std::string name; 24 | std::optional version; 25 | 26 | std::string to_string() const; 27 | 28 | void to_json(json& j) const; 29 | std::string to_json() const; 30 | }; 31 | 32 | std::ostream& 33 | operator<<(std::ostream& os, const product& msg); 34 | 35 | void to_json(json& j, const product& m); 36 | 37 | } 38 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/location.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace cucumber::messages { 10 | 11 | using json = nlohmann::json; 12 | 13 | // 14 | // Represents the Location message in Cucumber's message protocol 15 | // @see Github - Cucumber - Messages 16 | // 17 | // Points to a line and a column in a text file 18 | // 19 | // Generated code 20 | 21 | struct location 22 | { 23 | std::size_t line; 24 | std::optional column; 25 | 26 | std::string to_string() const; 27 | 28 | void to_json(json& j) const; 29 | std::string to_json() const; 30 | }; 31 | 32 | std::ostream& 33 | operator<<(std::ostream& os, const location& msg); 34 | 35 | void to_json(json& j, const location& m); 36 | 37 | } 38 | -------------------------------------------------------------------------------- /.github/workflows/test-elixir.yml: -------------------------------------------------------------------------------- 1 | name: test-elixir 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - renovate/** 8 | paths: 9 | - elixir/** 10 | - Makefile 11 | - .github/** 12 | pull_request: 13 | branches: 14 | - main 15 | paths: 16 | - elixir/** 17 | - Makefile 18 | - .github/** 19 | workflow_call: 20 | 21 | jobs: 22 | test-elixir: 23 | name: Test Elixir 24 | runs-on: ubuntu-latest 25 | 26 | steps: 27 | - name: Checkout 28 | uses: actions/checkout@v6 29 | - name: Setup Beam 30 | uses: erlef/setup-beam@v1 31 | with: 32 | otp-version: '27.1' 33 | elixir-version: '1.17' 34 | 35 | - name: Install Protoc 36 | uses: arduino/setup-protoc@v1 37 | 38 | - name: Run Tests 39 | run: make 40 | working-directory: elixir 41 | 42 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/java_method.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace cucumber::messages { 10 | 11 | using json = nlohmann::json; 12 | 13 | // 14 | // Represents the JavaMethod message in Cucumber's message protocol 15 | // @see Github - Cucumber - Messages 16 | // 17 | // Generated code 18 | 19 | struct java_method 20 | { 21 | std::string class_name; 22 | std::string method_name; 23 | std::vector method_parameter_types; 24 | 25 | std::string to_string() const; 26 | 27 | void to_json(json& j) const; 28 | std::string to_json() const; 29 | }; 30 | 31 | std::ostream& 32 | operator<<(std::ostream& os, const java_method& msg); 33 | 34 | void to_json(json& j, const java_method& m); 35 | 36 | } 37 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/undefined_parameter_type.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace cucumber::messages { 10 | 11 | using json = nlohmann::json; 12 | 13 | // 14 | // Represents the UndefinedParameterType message in Cucumber's message protocol 15 | // @see Github - Cucumber - Messages 16 | // 17 | // Generated code 18 | 19 | struct undefined_parameter_type 20 | { 21 | std::string expression; 22 | std::string name; 23 | 24 | std::string to_string() const; 25 | 26 | void to_json(json& j) const; 27 | std::string to_json() const; 28 | }; 29 | 30 | std::ostream& 31 | operator<<(std::ostream& os, const undefined_parameter_type& msg); 32 | 33 | void to_json(json& j, const undefined_parameter_type& m); 34 | 35 | } 36 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/pickle_table.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | namespace cucumber::messages { 12 | 13 | using json = nlohmann::json; 14 | 15 | // 16 | // Represents the PickleTable message in Cucumber's message protocol 17 | // @see Github - Cucumber - Messages 18 | // 19 | // Generated code 20 | 21 | struct pickle_table 22 | { 23 | std::vector rows; 24 | 25 | std::string to_string() const; 26 | 27 | void to_json(json& j) const; 28 | std::string to_json() const; 29 | }; 30 | 31 | std::ostream& 32 | operator<<(std::ostream& os, const pickle_table& msg); 33 | 34 | void to_json(json& j, const pickle_table& m); 35 | 36 | } 37 | -------------------------------------------------------------------------------- /java/src/main/java/io/cucumber/messages/LocationComparator.java: -------------------------------------------------------------------------------- 1 | package io.cucumber.messages; 2 | 3 | import io.cucumber.messages.types.Location; 4 | 5 | import java.util.Comparator; 6 | 7 | /** 8 | * Orders locations by their natural order. 9 | *

10 | * Locations on the same line, but with a missing column come before locations 11 | * with a column. 12 | */ 13 | public final class LocationComparator implements Comparator { 14 | @Override 15 | public int compare(Location a, Location b) { 16 | int c = a.getLine().compareTo(b.getLine()); 17 | if (c != 0) { 18 | return c; 19 | } 20 | Long aColumn = a.getColumn().orElse(null); 21 | Long bColumn = b.getColumn().orElse(null); 22 | // null first. 23 | return aColumn == null ? bColumn == null ? 0 : -1 : bColumn == null ? 1 : aColumn.compareTo(bColumn); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/tag.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | namespace cucumber::messages { 12 | 13 | using json = nlohmann::json; 14 | 15 | // 16 | // Represents the Tag message in Cucumber's message protocol 17 | // @see Github - Cucumber - Messages 18 | // 19 | // A tag 20 | // 21 | // Generated code 22 | 23 | struct tag 24 | { 25 | cucumber::messages::location location; 26 | std::string name; 27 | std::string id; 28 | 29 | std::string to_string() const; 30 | 31 | void to_json(json& j) const; 32 | std::string to_json() const; 33 | }; 34 | 35 | std::ostream& 36 | operator<<(std::ostream& os, const tag& msg); 37 | 38 | void to_json(json& j, const tag& m); 39 | 40 | } 41 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/parse_error.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | namespace cucumber::messages { 12 | 13 | using json = nlohmann::json; 14 | 15 | // 16 | // Represents the ParseError message in Cucumber's message protocol 17 | // @see Github - Cucumber - Messages 18 | // 19 | // Generated code 20 | 21 | struct parse_error 22 | { 23 | cucumber::messages::source_reference source; 24 | std::string message; 25 | 26 | std::string to_string() const; 27 | 28 | void to_json(json& j) const; 29 | std::string to_json() const; 30 | }; 31 | 32 | std::ostream& 33 | operator<<(std::ostream& os, const parse_error& msg); 34 | 35 | void to_json(json& j, const parse_error& m); 36 | 37 | } 38 | -------------------------------------------------------------------------------- /java/src/generated/java/io/cucumber/messages/types/AttachmentContentEncoding.java: -------------------------------------------------------------------------------- 1 | package io.cucumber.messages.types; 2 | 3 | // Generated code 4 | @SuppressWarnings("unused") 5 | public enum AttachmentContentEncoding { 6 | 7 | IDENTITY("IDENTITY"), 8 | 9 | BASE64("BASE64"); 10 | 11 | private final String value; 12 | 13 | AttachmentContentEncoding(String value) { 14 | this.value = value; 15 | } 16 | 17 | @Override 18 | public String toString() { 19 | return this.value; 20 | } 21 | 22 | public String value() { 23 | return this.value; 24 | } 25 | 26 | public static AttachmentContentEncoding fromValue(String value) { 27 | for (AttachmentContentEncoding v : values()) { 28 | if (v.value.equals(value)) { 29 | return v; 30 | } 31 | } 32 | throw new IllegalArgumentException(value); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/pickle_table_row.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | namespace cucumber::messages { 12 | 13 | using json = nlohmann::json; 14 | 15 | // 16 | // Represents the PickleTableRow message in Cucumber's message protocol 17 | // @see Github - Cucumber - Messages 18 | // 19 | // Generated code 20 | 21 | struct pickle_table_row 22 | { 23 | std::vector cells; 24 | 25 | std::string to_string() const; 26 | 27 | void to_json(json& j) const; 28 | std::string to_json() const; 29 | }; 30 | 31 | std::ostream& 32 | operator<<(std::ostream& os, const pickle_table_row& msg); 33 | 34 | void to_json(json& j, const pickle_table_row& m); 35 | 36 | } 37 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/comment.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | namespace cucumber::messages { 12 | 13 | using json = nlohmann::json; 14 | 15 | // 16 | // Represents the Comment message in Cucumber's message protocol 17 | // @see Github - Cucumber - Messages 18 | // 19 | // A comment in a Gherkin document 20 | // 21 | // Generated code 22 | 23 | struct comment 24 | { 25 | cucumber::messages::location location; 26 | std::string text; 27 | 28 | std::string to_string() const; 29 | 30 | void to_json(json& j) const; 31 | std::string to_json() const; 32 | }; 33 | 34 | std::ostream& 35 | operator<<(std::ostream& os, const comment& msg); 36 | 37 | void to_json(json& j, const comment& m); 38 | 39 | } 40 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/group.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | namespace cucumber::messages { 12 | 13 | using json = nlohmann::json; 14 | 15 | // 16 | // Represents the Group message in Cucumber's message protocol 17 | // @see Github - Cucumber - Messages 18 | // 19 | // Generated code 20 | 21 | struct group 22 | { 23 | std::vector children; 24 | std::optional start; 25 | std::optional value; 26 | 27 | std::string to_string() const; 28 | 29 | void to_json(json& j) const; 30 | std::string to_json() const; 31 | }; 32 | 33 | std::ostream& 34 | operator<<(std::ostream& os, const group& msg); 35 | 36 | void to_json(json& j, const group& m); 37 | 38 | } 39 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/java_stack_trace_element.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace cucumber::messages { 10 | 11 | using json = nlohmann::json; 12 | 13 | // 14 | // Represents the JavaStackTraceElement message in Cucumber's message protocol 15 | // @see Github - Cucumber - Messages 16 | // 17 | // Generated code 18 | 19 | struct java_stack_trace_element 20 | { 21 | std::string class_name; 22 | std::string file_name; 23 | std::string method_name; 24 | 25 | std::string to_string() const; 26 | 27 | void to_json(json& j) const; 28 | std::string to_json() const; 29 | }; 30 | 31 | std::ostream& 32 | operator<<(std::ostream& os, const java_stack_trace_element& msg); 33 | 34 | void to_json(json& j, const java_stack_trace_element& m); 35 | 36 | } 37 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/table_cell.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | namespace cucumber::messages { 12 | 13 | using json = nlohmann::json; 14 | 15 | // 16 | // Represents the TableCell message in Cucumber's message protocol 17 | // @see Github - Cucumber - Messages 18 | // 19 | // A cell in a `TableRow` 20 | // 21 | // Generated code 22 | 23 | struct table_cell 24 | { 25 | cucumber::messages::location location; 26 | std::string value; 27 | 28 | std::string to_string() const; 29 | 30 | void to_json(json& j) const; 31 | std::string to_json() const; 32 | }; 33 | 34 | std::ostream& 35 | operator<<(std::ostream& os, const table_cell& msg); 36 | 37 | void to_json(json& j, const table_cell& m); 38 | 39 | } 40 | -------------------------------------------------------------------------------- /dotnet/Cucumber.Messages.Specs/MessagesTest.cs: -------------------------------------------------------------------------------- 1 | using Io.Cucumber.Messages.Types; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using Xunit; 8 | 9 | namespace Cucumber.Messages.Specs 10 | { 11 | public class MessagesTest 12 | { 13 | 14 | [Fact] 15 | public void ThrowsWhenRequiredFieldsAreMissing() 16 | { 17 | Assert.Throws(() => new Background(null, null, null, null, null, null)); 18 | } 19 | 20 | [Fact] 21 | public void IsValidWhenNoRequiredFieldsAreMissing() 22 | { 23 | // This should succeed as no constructor arguments to an Envelope are required. 24 | var env = new Envelope(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /java/src/generated/java/io/cucumber/messages/types/PickleStepType.java: -------------------------------------------------------------------------------- 1 | package io.cucumber.messages.types; 2 | 3 | // Generated code 4 | @SuppressWarnings("unused") 5 | public enum PickleStepType { 6 | 7 | UNKNOWN("Unknown"), 8 | 9 | CONTEXT("Context"), 10 | 11 | ACTION("Action"), 12 | 13 | OUTCOME("Outcome"); 14 | 15 | private final String value; 16 | 17 | PickleStepType(String value) { 18 | this.value = value; 19 | } 20 | 21 | @Override 22 | public String toString() { 23 | return this.value; 24 | } 25 | 26 | public String value() { 27 | return this.value; 28 | } 29 | 30 | public static PickleStepType fromValue(String value) { 31 | for (PickleStepType v : values()) { 32 | if (v.value.equals(value)) { 33 | return v; 34 | } 35 | } 36 | throw new IllegalArgumentException(value); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/duration.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace cucumber::messages { 10 | 11 | using json = nlohmann::json; 12 | 13 | // 14 | // Represents the Duration message in Cucumber's message protocol 15 | // @see Github - Cucumber - Messages 16 | // 17 | // The structure is pretty close of the Timestamp one. For clarity, a second type 18 | // of message is used. 19 | // 20 | // Generated code 21 | 22 | struct duration 23 | { 24 | std::size_t seconds; 25 | std::size_t nanos; 26 | 27 | std::string to_string() const; 28 | 29 | void to_json(json& j) const; 30 | std::string to_json() const; 31 | }; 32 | 33 | std::ostream& 34 | operator<<(std::ostream& os, const duration& msg); 35 | 36 | void to_json(json& j, const duration& m); 37 | 38 | } 39 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/test_run_started.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | namespace cucumber::messages { 12 | 13 | using json = nlohmann::json; 14 | 15 | // 16 | // Represents the TestRunStarted message in Cucumber's message protocol 17 | // @see Github - Cucumber - Messages 18 | // 19 | // Generated code 20 | 21 | struct test_run_started 22 | { 23 | cucumber::messages::timestamp timestamp; 24 | std::optional id; 25 | 26 | std::string to_string() const; 27 | 28 | void to_json(json& j) const; 29 | std::string to_json() const; 30 | }; 31 | 32 | std::ostream& 33 | operator<<(std::ostream& os, const test_run_started& msg); 34 | 35 | void to_json(json& j, const test_run_started& m); 36 | 37 | } 38 | -------------------------------------------------------------------------------- /cpp/src/lib/messages/cucumber/messages/hook_type.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | namespace cucumber::messages { 7 | 8 | std::string_view 9 | to_string(hook_type v) 10 | { 11 | using map_type = std::unordered_map; 12 | 13 | static const map_type m = { 14 | { hook_type::BEFORE_TEST_RUN, "BEFORE_TEST_RUN" }, 15 | { hook_type::AFTER_TEST_RUN, "AFTER_TEST_RUN" }, 16 | { hook_type::BEFORE_TEST_CASE, "BEFORE_TEST_CASE" }, 17 | { hook_type::AFTER_TEST_CASE, "AFTER_TEST_CASE" }, 18 | { hook_type::BEFORE_TEST_STEP, "BEFORE_TEST_STEP" }, 19 | { hook_type::AFTER_TEST_STEP, "AFTER_TEST_STEP" } 20 | }; 21 | 22 | return m.at(v); 23 | } 24 | 25 | std::ostream& 26 | operator<<(std::ostream& os, hook_type v) 27 | { 28 | os << to_string(v); 29 | 30 | return os; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /go/time_conversion.go: -------------------------------------------------------------------------------- 1 | package messages 2 | 3 | import "time" 4 | 5 | const nanosPerSecond = 1000000000 6 | 7 | func DurationToGoDuration(duration Duration) time.Duration { 8 | secondNanos := duration.Seconds * nanosPerSecond 9 | return time.Duration(secondNanos + int64(duration.Nanos)) 10 | } 11 | 12 | func GoDurationToDuration(goDuration time.Duration) Duration { 13 | seconds := int64(goDuration / nanosPerSecond) 14 | nanos := int64(goDuration % nanosPerSecond) 15 | return Duration{ 16 | Seconds: seconds, 17 | Nanos: nanos, 18 | } 19 | } 20 | 21 | func TimestampToGoTime(timestamp Timestamp) time.Time { 22 | return time.Unix(timestamp.Seconds, timestamp.Nanos) 23 | } 24 | 25 | func GoTimeToTimestamp(t time.Time) Timestamp { 26 | unixNanos := t.UnixNano() 27 | seconds := unixNanos / nanosPerSecond 28 | nanos := unixNanos % nanosPerSecond 29 | 30 | return Timestamp{ 31 | Seconds: seconds, 32 | Nanos: nanos, 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/exception.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace cucumber::messages { 10 | 11 | using json = nlohmann::json; 12 | 13 | // 14 | // Represents the Exception message in Cucumber's message protocol 15 | // @see Github - Cucumber - Messages 16 | // 17 | // A simplified representation of an exception 18 | // 19 | // Generated code 20 | 21 | struct exception 22 | { 23 | std::string type; 24 | std::optional message; 25 | std::optional stack_trace; 26 | 27 | std::string to_string() const; 28 | 29 | void to_json(json& j) const; 30 | std::string to_json() const; 31 | }; 32 | 33 | std::ostream& 34 | operator<<(std::ostream& os, const exception& msg); 35 | 36 | void to_json(json& j, const exception& m); 37 | 38 | } 39 | -------------------------------------------------------------------------------- /java/src/main/java/io/cucumber/messages/TimeConversion.java: -------------------------------------------------------------------------------- 1 | package io.cucumber.messages; 2 | 3 | import io.cucumber.messages.types.Duration; 4 | import io.cucumber.messages.types.Timestamp; 5 | 6 | @Deprecated 7 | @SuppressWarnings("unused") 8 | public final class TimeConversion { 9 | 10 | private TimeConversion(){ 11 | 12 | } 13 | 14 | public static Timestamp javaInstantToTimestamp(java.time.Instant instant) { 15 | return Convertor.toMessage(instant); 16 | } 17 | 18 | public static Duration javaDurationToDuration(java.time.Duration duration) { 19 | return Convertor.toMessage(duration); 20 | } 21 | 22 | public static java.time.Instant timestampToJavaInstant(Timestamp timestamp) { 23 | return Convertor.toInstant(timestamp); 24 | } 25 | 26 | public static java.time.Duration durationToJavaDuration(Duration duration) { 27 | return Convertor.toDuration(duration); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /codegen/generators/java.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Generator 4 | # Generator::Java 5 | # Automatic Code generation overrides for the Java programming language 6 | class Java < Base 7 | def array_type_for(type_name) 8 | "java.util.List<#{type_name}>" 9 | end 10 | 11 | def format_description(raw_description, indent_string: '') 12 | return '' if raw_description.nil? 13 | 14 | raw_description 15 | .split("\n") 16 | .map(&:strip) 17 | .reject { |line| line == '*' } 18 | .map { |line| line.rstrip } 19 | .map { |line| line.empty? ? "

" : line } 20 | .map { |line| " * #{line}"} 21 | .join("\n#{indent_string}") 22 | end 23 | 24 | private 25 | 26 | def language_translations_for_data_types 27 | { 28 | 'integer' => 'Long', 29 | 'string' => 'String', 30 | 'boolean' => 'Boolean' 31 | } 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /javascript/src/getWorstTestStepResult.ts: -------------------------------------------------------------------------------- 1 | import { TestStepResult, TestStepResultStatus } from './messages.js' 2 | import { millisecondsToDuration } from './TimeConversion.js' 3 | 4 | /** 5 | * Gets the worst result 6 | * @param testStepResults 7 | */ 8 | export function getWorstTestStepResult(testStepResults: readonly TestStepResult[]): TestStepResult { 9 | return ( 10 | testStepResults.slice().sort((r1, r2) => ordinal(r2.status) - ordinal(r1.status))[0] || { 11 | status: TestStepResultStatus.UNKNOWN, 12 | duration: millisecondsToDuration(0), 13 | } 14 | ) 15 | } 16 | 17 | function ordinal(status: TestStepResultStatus) { 18 | return [ 19 | TestStepResultStatus.UNKNOWN, 20 | TestStepResultStatus.PASSED, 21 | TestStepResultStatus.SKIPPED, 22 | TestStepResultStatus.PENDING, 23 | TestStepResultStatus.UNDEFINED, 24 | TestStepResultStatus.AMBIGUOUS, 25 | TestStepResultStatus.FAILED, 26 | ].indexOf(status) 27 | } 28 | -------------------------------------------------------------------------------- /cpp/Dockerfile: -------------------------------------------------------------------------------- 1 | #syntax=docker/dockerfile:1.20 2 | 3 | # Base image 4 | FROM debian:bullseye-slim AS cpp 5 | 6 | RUN <idGenerator = new UuidIdGenerator(); 18 | } 19 | 20 | public function testItGeneratesUuids(): void 21 | { 22 | $uuid = $this->idGenerator->newId(); 23 | 24 | self::assertTrue(Uuid::isValid($uuid)); 25 | } 26 | 27 | public function testItGeneratesV4Uuids(): void 28 | { 29 | $uuid = $this->idGenerator->newId(); 30 | 31 | $fields = (Uuid::fromString($uuid))->getFields(); 32 | 33 | self::assertInstanceOf(FieldsInterface::class, $fields); 34 | self::assertSame(4, $fields->getVersion()); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /jsonschema/src/ParameterType.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "ParameterType.json", 4 | "additionalProperties": false, 5 | "required": [ 6 | "id", 7 | "name", 8 | "preferForRegularExpressionMatch", 9 | "regularExpressions", 10 | "useForSnippets" 11 | ], 12 | "properties": { 13 | "name": { 14 | "description": "The name is unique, so we don't need an id.", 15 | "type": "string" 16 | }, 17 | "regularExpressions": { 18 | "items": { 19 | "type": "string" 20 | }, 21 | "type": "array", 22 | "minItems": 1 23 | }, 24 | "preferForRegularExpressionMatch": { 25 | "type": "boolean" 26 | }, 27 | "useForSnippets": { 28 | "type": "boolean" 29 | }, 30 | "id": { 31 | "type": "string" 32 | }, 33 | "sourceReference": { 34 | "$ref": "./SourceReference.json" 35 | } 36 | }, 37 | "type": "object" 38 | } 39 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/ci.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | namespace cucumber::messages { 12 | 13 | using json = nlohmann::json; 14 | 15 | // 16 | // Represents the Ci message in Cucumber's message protocol 17 | // @see Github - Cucumber - Messages 18 | // 19 | // CI environment 20 | // 21 | // Generated code 22 | 23 | struct ci 24 | { 25 | std::string name; 26 | std::optional url; 27 | std::optional build_number; 28 | std::optional git; 29 | 30 | std::string to_string() const; 31 | 32 | void to_json(json& j) const; 33 | std::string to_json() const; 34 | }; 35 | 36 | std::ostream& 37 | operator<<(std::ostream& os, const ci& msg); 38 | 39 | void to_json(json& j, const ci& m); 40 | 41 | } 42 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/data_table.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | namespace cucumber::messages { 13 | 14 | using json = nlohmann::json; 15 | 16 | // 17 | // Represents the DataTable message in Cucumber's message protocol 18 | // @see Github - Cucumber - Messages 19 | // 20 | // Generated code 21 | 22 | struct data_table 23 | { 24 | cucumber::messages::location location; 25 | std::vector rows; 26 | 27 | std::string to_string() const; 28 | 29 | void to_json(json& j) const; 30 | std::string to_json() const; 31 | }; 32 | 33 | std::ostream& 34 | operator<<(std::ostream& os, const data_table& msg); 35 | 36 | void to_json(json& j, const data_table& m); 37 | 38 | } 39 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/doc_string.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | namespace cucumber::messages { 12 | 13 | using json = nlohmann::json; 14 | 15 | // 16 | // Represents the DocString message in Cucumber's message protocol 17 | // @see Github - Cucumber - Messages 18 | // 19 | // Generated code 20 | 21 | struct doc_string 22 | { 23 | cucumber::messages::location location; 24 | std::optional media_type; 25 | std::string content; 26 | std::string delimiter; 27 | 28 | std::string to_string() const; 29 | 30 | void to_json(json& j) const; 31 | std::string to_json() const; 32 | }; 33 | 34 | std::ostream& 35 | operator<<(std::ostream& os, const doc_string& msg); 36 | 37 | void to_json(json& j, const doc_string& m); 38 | 39 | } 40 | -------------------------------------------------------------------------------- /.github/workflows/test-ruby.yml: -------------------------------------------------------------------------------- 1 | name: test-ruby 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - renovate/** 8 | paths: 9 | - ruby/** 10 | - Makefile 11 | - .github/** 12 | pull_request: 13 | branches: 14 | - main 15 | paths: 16 | - ruby/** 17 | - Makefile 18 | - .github/** 19 | workflow_call: 20 | 21 | jobs: 22 | test-ruby: 23 | runs-on: ${{ matrix.os }} 24 | strategy: 25 | fail-fast: false 26 | matrix: 27 | os: 28 | - ubuntu-latest 29 | ruby: ['3.2', '3.3', '3.4', '3.5'] 30 | include: 31 | - os: macos-latest 32 | ruby: '3.4' 33 | 34 | steps: 35 | - uses: actions/checkout@v6 36 | - uses: ruby/setup-ruby@v1 37 | with: 38 | ruby-version: ${{ matrix.ruby }} 39 | bundler-cache: true 40 | working-directory: ruby 41 | - run: bundle exec rake 42 | working-directory: ruby 43 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/git.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace cucumber::messages { 10 | 11 | using json = nlohmann::json; 12 | 13 | // 14 | // Represents the Git message in Cucumber's message protocol 15 | // @see Github - Cucumber - Messages 16 | // 17 | // Information about Git, provided by the Build/CI server as environment 18 | // variables. 19 | // 20 | // Generated code 21 | 22 | struct git 23 | { 24 | std::string remote; 25 | std::string revision; 26 | std::optional branch; 27 | std::optional tag; 28 | 29 | std::string to_string() const; 30 | 31 | void to_json(json& j) const; 32 | std::string to_json() const; 33 | }; 34 | 35 | std::ostream& 36 | operator<<(std::ostream& os, const git& msg); 37 | 38 | void to_json(json& j, const git& m); 39 | 40 | } 41 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/test_step_started.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | namespace cucumber::messages { 12 | 13 | using json = nlohmann::json; 14 | 15 | // 16 | // Represents the TestStepStarted message in Cucumber's message protocol 17 | // @see Github - Cucumber - Messages 18 | // 19 | // Generated code 20 | 21 | struct test_step_started 22 | { 23 | std::string test_case_started_id; 24 | std::string test_step_id; 25 | cucumber::messages::timestamp timestamp; 26 | 27 | std::string to_string() const; 28 | 29 | void to_json(json& j) const; 30 | std::string to_json() const; 31 | }; 32 | 33 | std::ostream& 34 | operator<<(std::ostream& os, const test_step_started& msg); 35 | 36 | void to_json(json& j, const test_step_started& m); 37 | 38 | } 39 | -------------------------------------------------------------------------------- /java/src/generated/java/io/cucumber/messages/types/StepKeywordType.java: -------------------------------------------------------------------------------- 1 | package io.cucumber.messages.types; 2 | 3 | // Generated code 4 | @SuppressWarnings("unused") 5 | public enum StepKeywordType { 6 | 7 | UNKNOWN("Unknown"), 8 | 9 | CONTEXT("Context"), 10 | 11 | ACTION("Action"), 12 | 13 | OUTCOME("Outcome"), 14 | 15 | CONJUNCTION("Conjunction"); 16 | 17 | private final String value; 18 | 19 | StepKeywordType(String value) { 20 | this.value = value; 21 | } 22 | 23 | @Override 24 | public String toString() { 25 | return this.value; 26 | } 27 | 28 | public String value() { 29 | return this.value; 30 | } 31 | 32 | public static StepKeywordType fromValue(String value) { 33 | for (StepKeywordType v : values()) { 34 | if (v.value.equals(value)) { 35 | return v; 36 | } 37 | } 38 | throw new IllegalArgumentException(value); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/step_match_arguments_list.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | namespace cucumber::messages { 12 | 13 | using json = nlohmann::json; 14 | 15 | // 16 | // Represents the StepMatchArgumentsList message in Cucumber's message protocol 17 | // @see Github - Cucumber - Messages 18 | // 19 | // Generated code 20 | 21 | struct step_match_arguments_list 22 | { 23 | std::vector step_match_arguments; 24 | 25 | std::string to_string() const; 26 | 27 | void to_json(json& j) const; 28 | std::string to_json() const; 29 | }; 30 | 31 | std::ostream& 32 | operator<<(std::ostream& os, const step_match_arguments_list& msg); 33 | 34 | void to_json(json& j, const step_match_arguments_list& m); 35 | 36 | } 37 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/test_case_finished.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | namespace cucumber::messages { 12 | 13 | using json = nlohmann::json; 14 | 15 | // 16 | // Represents the TestCaseFinished message in Cucumber's message protocol 17 | // @see Github - Cucumber - Messages 18 | // 19 | // Generated code 20 | 21 | struct test_case_finished 22 | { 23 | std::string test_case_started_id; 24 | cucumber::messages::timestamp timestamp; 25 | bool will_be_retried; 26 | 27 | std::string to_string() const; 28 | 29 | void to_json(json& j) const; 30 | std::string to_json() const; 31 | }; 32 | 33 | std::ostream& 34 | operator<<(std::ostream& os, const test_case_finished& msg); 35 | 36 | void to_json(json& j, const test_case_finished& m); 37 | 38 | } 39 | -------------------------------------------------------------------------------- /cpp/src/lib/messages/cucumber/messages/pickle_table.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace cucumber::messages { 7 | 8 | std::string 9 | pickle_table::to_string() const 10 | { 11 | std::ostringstream oss; 12 | 13 | cucumber::messages::to_string(oss, "rows=", rows); 14 | 15 | return oss.str(); 16 | } 17 | 18 | void 19 | pickle_table::to_json(json& j) const 20 | { 21 | cucumber::messages::to_json(j, camelize("rows"), rows); 22 | } 23 | 24 | std::string 25 | pickle_table::to_json() const 26 | { 27 | std::ostringstream oss; 28 | json j; 29 | 30 | to_json(j); 31 | 32 | oss << j; 33 | 34 | return oss.str(); 35 | } 36 | 37 | std::ostream& 38 | operator<<(std::ostream& os, const pickle_table& msg) 39 | { 40 | os << msg.to_string(); 41 | 42 | return os; 43 | } 44 | 45 | void to_json(json& j, const pickle_table& m) 46 | { m.to_json(j); } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/step_definition_pattern.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | namespace cucumber::messages { 12 | 13 | using json = nlohmann::json; 14 | 15 | // 16 | // Represents the StepDefinitionPattern message in Cucumber's message protocol 17 | // @see Github - Cucumber - Messages 18 | // 19 | // Generated code 20 | 21 | struct step_definition_pattern 22 | { 23 | std::string source; 24 | cucumber::messages::step_definition_pattern_type type; 25 | 26 | std::string to_string() const; 27 | 28 | void to_json(json& j) const; 29 | std::string to_json() const; 30 | }; 31 | 32 | std::ostream& 33 | operator<<(std::ostream& os, const step_definition_pattern& msg); 34 | 35 | void to_json(json& j, const step_definition_pattern& m); 36 | 37 | } 38 | -------------------------------------------------------------------------------- /dotnet/.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the 2 | // README at: https://github.com/devcontainers/templates/tree/main/src/ruby 3 | { 4 | "name": "Ruby", 5 | // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile 6 | "image": "mcr.microsoft.com/devcontainers/ruby:1-3.3-bullseye", 7 | "features": { 8 | "ghcr.io/jungaretti/features/make:1": {}, 9 | "ghcr.io/devcontainers/features/dotnet:2": { 10 | "version": "8.0" 11 | } 12 | } 13 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 14 | // "forwardPorts": [], 15 | // Use 'postCreateCommand' to run commands after the container is created. 16 | // "postCreateCommand": "ruby --version", 17 | // Configure tool-specific properties. 18 | // "customizations": {}, 19 | // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. 20 | // "remoteUser": "root" 21 | } -------------------------------------------------------------------------------- /perl/Makefile: -------------------------------------------------------------------------------- 1 | schemas = $(shell find ../jsonschema/src -name "*.json") 2 | 3 | .DEFAULT_GOAL = help 4 | 5 | help: ## Show this help 6 | @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \n\nWhere is one of:\n"} /^[$$()% a-zA-Z_-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) 7 | 8 | generate: require lib/Cucumber/Messages.pm ## Generate perl code based on the schemas found in ../jsonschema and using the scripts in ../jsonschema/scripts for the generation 9 | 10 | require: ## Check requirements for the code generation (ruby is required) 11 | @ruby --version >/dev/null 2>&1 || (echo "ERROR: ruby is required."; exit 1) 12 | 13 | clean: ## Remove automatically generated files and related artifacts 14 | rm -f lib/Cucumber/Messages.pm 15 | 16 | lib/Cucumber/Messages.pm: $(schemas) ../codegen/codegen.rb ../codegen/templates/perl.pm.erb 17 | ruby ../codegen/codegen.rb Generator::Perl perl.pm.erb > $@ 18 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/source.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | namespace cucumber::messages { 12 | 13 | using json = nlohmann::json; 14 | 15 | // 16 | // Represents the Source message in Cucumber's message protocol 17 | // @see Github - Cucumber - Messages 18 | // 19 | // A source file, typically a Gherkin document or Java/Ruby/JavaScript source code 20 | // 21 | // Generated code 22 | 23 | struct source 24 | { 25 | std::string uri; 26 | std::string data; 27 | cucumber::messages::source_media_type media_type; 28 | 29 | std::string to_string() const; 30 | 31 | void to_json(json& j) const; 32 | std::string to_json() const; 33 | }; 34 | 35 | std::ostream& 36 | operator<<(std::ostream& os, const source& msg); 37 | 38 | void to_json(json& j, const source& m); 39 | 40 | } 41 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/suggestion.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | namespace cucumber::messages { 12 | 13 | using json = nlohmann::json; 14 | 15 | // 16 | // Represents the Suggestion message in Cucumber's message protocol 17 | // @see Github - Cucumber - Messages 18 | // 19 | // A suggested fragment of code to implement an undefined step 20 | // 21 | // Generated code 22 | 23 | struct suggestion 24 | { 25 | std::string id; 26 | std::string pickle_step_id; 27 | std::vector snippets; 28 | 29 | std::string to_string() const; 30 | 31 | void to_json(json& j) const; 32 | std::string to_json() const; 33 | }; 34 | 35 | std::ostream& 36 | operator<<(std::ostream& os, const suggestion& msg); 37 | 38 | void to_json(json& j, const suggestion& m); 39 | 40 | } 41 | -------------------------------------------------------------------------------- /cpp/src/lib/messages/cucumber/messages/pickle_table_row.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace cucumber::messages { 7 | 8 | std::string 9 | pickle_table_row::to_string() const 10 | { 11 | std::ostringstream oss; 12 | 13 | cucumber::messages::to_string(oss, "cells=", cells); 14 | 15 | return oss.str(); 16 | } 17 | 18 | void 19 | pickle_table_row::to_json(json& j) const 20 | { 21 | cucumber::messages::to_json(j, camelize("cells"), cells); 22 | } 23 | 24 | std::string 25 | pickle_table_row::to_json() const 26 | { 27 | std::ostringstream oss; 28 | json j; 29 | 30 | to_json(j); 31 | 32 | oss << j; 33 | 34 | return oss.str(); 35 | } 36 | 37 | std::ostream& 38 | operator<<(std::ostream& os, const pickle_table_row& msg) 39 | { 40 | os << msg.to_string(); 41 | 42 | return os; 43 | } 44 | 45 | void to_json(json& j, const pickle_table_row& m) 46 | { m.to_json(j); } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /cpp/src/lib/messages/cucumber/messages/pickle_table_cell.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace cucumber::messages { 7 | 8 | std::string 9 | pickle_table_cell::to_string() const 10 | { 11 | std::ostringstream oss; 12 | 13 | cucumber::messages::to_string(oss, "value=", value); 14 | 15 | return oss.str(); 16 | } 17 | 18 | void 19 | pickle_table_cell::to_json(json& j) const 20 | { 21 | cucumber::messages::to_json(j, camelize("value"), value); 22 | } 23 | 24 | std::string 25 | pickle_table_cell::to_json() const 26 | { 27 | std::ostringstream oss; 28 | json j; 29 | 30 | to_json(j); 31 | 32 | oss << j; 33 | 34 | return oss.str(); 35 | } 36 | 37 | std::ostream& 38 | operator<<(std::ostream& os, const pickle_table_cell& msg) 39 | { 40 | os << msg.to_string(); 41 | 42 | return os; 43 | } 44 | 45 | void to_json(json& j, const pickle_table_cell& m) 46 | { m.to_json(j); } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /php/tests/EnvelopeTest.php: -------------------------------------------------------------------------------- 1 | gherkinDocument); 16 | } 17 | 18 | public function testItCanBeConstructedWithASubsetOfProperties(): void 19 | { 20 | $envelope = new Envelope( 21 | gherkinDocument: new GherkinDocument( 22 | feature: new Feature( 23 | location: new Location( 24 | line: 21 25 | ) 26 | ) 27 | ) 28 | ); 29 | 30 | self::assertSame( 31 | 21, 32 | $envelope->gherkinDocument?->feature?->location?->line 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/table_row.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | namespace cucumber::messages { 13 | 14 | using json = nlohmann::json; 15 | 16 | // 17 | // Represents the TableRow message in Cucumber's message protocol 18 | // @see Github - Cucumber - Messages 19 | // 20 | // A row in a table 21 | // 22 | // Generated code 23 | 24 | struct table_row 25 | { 26 | cucumber::messages::location location; 27 | std::vector cells; 28 | std::string id; 29 | 30 | std::string to_string() const; 31 | 32 | void to_json(json& j) const; 33 | std::string to_json() const; 34 | }; 35 | 36 | std::ostream& 37 | operator<<(std::ostream& os, const table_row& msg); 38 | 39 | void to_json(json& j, const table_row& m); 40 | 41 | } 42 | -------------------------------------------------------------------------------- /php/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cucumber/messages", 3 | "description": "JSON schema-based messages for Cucumber's inter-process communication", 4 | "author": "Cucumber Limited ", 5 | "license": "MIT", 6 | "type": "library", 7 | "require": { 8 | "php": "^8.1", 9 | "ext-json": "*" 10 | }, 11 | "require-dev": { 12 | "vimeo/psalm": "^5.5", 13 | "phpunit/phpunit": "^10.3||^11.0", 14 | "psalm/plugin-phpunit": "^0.19.0", 15 | "friendsofphp/php-cs-fixer": "^3.5", 16 | "ramsey/uuid": "^4.5.0" 17 | }, 18 | "autoload": { 19 | "psr-4": { 20 | "Cucumber\\Messages\\": [ 21 | "src", 22 | "src-generated" 23 | ] 24 | } 25 | }, 26 | "autoload-dev": { 27 | "psr-4": { 28 | "Cucumber\\Messages\\": [ 29 | "src", 30 | "src-generated", 31 | "tests" 32 | ] 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /codegen/templates/java.enum.java.erb: -------------------------------------------------------------------------------- 1 | <% @enums.each do |enum| -%> 2 | <%= enum[:name] %>.java 3 | package io.cucumber.messages.types; 4 | 5 | // Generated code 6 | @SuppressWarnings("unused") 7 | public enum <%= enum[:name] %> { 8 | <% enum[:values].each_with_index do |value, index| -%> 9 | 10 | <%= enum_constant(value) %>("<%= value %>")<%= index < enum[:values].length - 1 ? ',' : ';' %> 11 | <% end -%> 12 | 13 | private final String value; 14 | 15 | <%= enum[:name] %>(String value) { 16 | this.value = value; 17 | } 18 | 19 | @Override 20 | public String toString() { 21 | return this.value; 22 | } 23 | 24 | public String value() { 25 | return this.value; 26 | } 27 | 28 | public static <%= enum[:name] %> fromValue(String value) { 29 | for (<%= enum[:name] %> v : values()) { 30 | if (v.value.equals(value)) { 31 | return v; 32 | } 33 | } 34 | throw new IllegalArgumentException(value); 35 | } 36 | } 37 | <% end -%> 38 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/test_case_started.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | namespace cucumber::messages { 12 | 13 | using json = nlohmann::json; 14 | 15 | // 16 | // Represents the TestCaseStarted message in Cucumber's message protocol 17 | // @see Github - Cucumber - Messages 18 | // 19 | // Generated code 20 | 21 | struct test_case_started 22 | { 23 | std::size_t attempt; 24 | std::string id; 25 | std::string test_case_id; 26 | std::optional worker_id; 27 | cucumber::messages::timestamp timestamp; 28 | 29 | std::string to_string() const; 30 | 31 | void to_json(json& j) const; 32 | std::string to_json() const; 33 | }; 34 | 35 | std::ostream& 36 | operator<<(std::ostream& os, const test_case_started& msg); 37 | 38 | void to_json(json& j, const test_case_started& m); 39 | 40 | } 41 | -------------------------------------------------------------------------------- /dotnet/Cucumber.Messages/generated/AttachmentContentEncoding.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Reflection; 4 | 5 | namespace Io.Cucumber.Messages.Types; 6 | 7 | // ------------------------------------------------------------------------------ 8 | // This code was generated based on the Cucumber JSON schema 9 | // Changes to this file may cause incorrect behavior and will be lost if 10 | // the code is regenerated. 11 | // ------------------------------------------------------------------------------ 12 | 13 | public enum AttachmentContentEncoding { 14 | 15 | [Description("IDENTITY")] 16 | IDENTITY, 17 | 18 | [Description("BASE64")] 19 | BASE64 20 | } 21 | 22 | public static class AttachmentContentEncodingExtensions 23 | { 24 | public static string Value(this AttachmentContentEncoding v) { 25 | var attribute = v.GetType().GetField(v.ToString()).GetCustomAttribute(); 26 | return attribute == null ? v.ToString() : attribute.Description; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/rule_child.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | namespace cucumber::messages { 13 | 14 | using json = nlohmann::json; 15 | 16 | // 17 | // Represents the RuleChild message in Cucumber's message protocol 18 | // @see Github - Cucumber - Messages 19 | // 20 | // A child node of a `Rule` node 21 | // 22 | // Generated code 23 | 24 | struct rule_child 25 | { 26 | std::optional background; 27 | std::optional scenario; 28 | 29 | std::string to_string() const; 30 | 31 | void to_json(json& j) const; 32 | std::string to_json() const; 33 | }; 34 | 35 | std::ostream& 36 | operator<<(std::ostream& os, const rule_child& msg); 37 | 38 | void to_json(json& j, const rule_child& m); 39 | 40 | } 41 | -------------------------------------------------------------------------------- /elixir/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule CucumberMessages.MixProject do 2 | @moduledoc false 3 | use Mix.Project 4 | 5 | @github "https://github.com/cucumber/messages" 6 | 7 | def project do 8 | [ 9 | app: :cucumber_messages, 10 | version: "31.0.1", 11 | name: "CucumberMessages", 12 | description: description(), 13 | package: package(), 14 | elixir: "~> 1.10", 15 | start_permanent: Mix.env() == :prod, 16 | deps: deps() 17 | ] 18 | end 19 | 20 | def application do 21 | [ 22 | extra_applications: [:logger] 23 | ] 24 | end 25 | 26 | defp deps do 27 | [ 28 | {:protox, "~> 2.0"}, 29 | {:jason, "~> 1.4"}, 30 | {:ex_doc, "~> 0.39", only: :dev, runtime: false} 31 | ] 32 | end 33 | 34 | defp description() do 35 | "Elixir implementation of the cucumber messages protobuf schema" 36 | end 37 | 38 | defp package() do 39 | [ 40 | licenses: ["MIT"], 41 | source_url: @github, 42 | links: %{"GitHub" => @github} 43 | ] 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /jsonschema/src/Source.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "Source.json", 4 | "additionalProperties": false, 5 | "description": "A source file, typically a Gherkin document or Java/Ruby/JavaScript source code", 6 | "required": [ 7 | "uri", 8 | "data", 9 | "mediaType" 10 | ], 11 | "properties": { 12 | "uri": { 13 | "description": "The [URI](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier)\nof the source, typically a file path relative to the root directory", 14 | "type": "string" 15 | }, 16 | "data": { 17 | "description": "The contents of the file", 18 | "type": "string" 19 | }, 20 | "mediaType": { 21 | "description": "The media type of the file. Can be used to specify custom types, such as\ntext/x.cucumber.gherkin+plain", 22 | "type": "string", 23 | "enum": [ 24 | "text/x.cucumber.gherkin+plain", 25 | "text/x.cucumber.gherkin+markdown" 26 | ] 27 | } 28 | }, 29 | "type": "object" 30 | } 31 | -------------------------------------------------------------------------------- /cpp/src/lib/messages/cucumber/messages/test_step_result_status.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | namespace cucumber::messages { 7 | 8 | std::string_view 9 | to_string(test_step_result_status v) 10 | { 11 | using map_type = std::unordered_map; 12 | 13 | static const map_type m = { 14 | { test_step_result_status::UNKNOWN, "UNKNOWN" }, 15 | { test_step_result_status::PASSED, "PASSED" }, 16 | { test_step_result_status::SKIPPED, "SKIPPED" }, 17 | { test_step_result_status::PENDING, "PENDING" }, 18 | { test_step_result_status::UNDEFINED, "UNDEFINED" }, 19 | { test_step_result_status::AMBIGUOUS, "AMBIGUOUS" }, 20 | { test_step_result_status::FAILED, "FAILED" } 21 | }; 22 | 23 | return m.at(v); 24 | } 25 | 26 | std::ostream& 27 | operator<<(std::ostream& os, test_step_result_status v) 28 | { 29 | os << to_string(v); 30 | 31 | return os; 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/test_case.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | namespace cucumber::messages { 12 | 13 | using json = nlohmann::json; 14 | 15 | // 16 | // Represents the TestCase message in Cucumber's message protocol 17 | // @see Github - Cucumber - Messages 18 | // 19 | // A `TestCase` contains a sequence of `TestStep`s. 20 | // 21 | // Generated code 22 | 23 | struct test_case 24 | { 25 | std::string id; 26 | std::string pickle_id; 27 | std::vector test_steps; 28 | std::optional test_run_started_id; 29 | 30 | std::string to_string() const; 31 | 32 | void to_json(json& j) const; 33 | std::string to_json() const; 34 | }; 35 | 36 | std::ostream& 37 | operator<<(std::ostream& os, const test_case& msg); 38 | 39 | void to_json(json& j, const test_case& m); 40 | 41 | } 42 | -------------------------------------------------------------------------------- /ruby/lib/cucumber/messages/helpers/time_conversion.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Cucumber 4 | module Messages 5 | module Helpers 6 | module TimeConversion 7 | NANOSECONDS_PER_SECOND = 1_000_000_000 8 | 9 | def time_to_timestamp(time) 10 | { 'seconds' => time.to_i, 'nanos' => time.nsec } 11 | end 12 | 13 | def timestamp_to_time(timestamp) 14 | Time.at(timestamp['seconds'] + (timestamp['nanos'].to_f / NANOSECONDS_PER_SECOND)) 15 | end 16 | 17 | def seconds_to_duration(seconds_float) 18 | seconds, second_modulus = seconds_float.divmod(1) 19 | nanos = second_modulus * NANOSECONDS_PER_SECOND 20 | { 'seconds' => seconds, 'nanos' => nanos.to_i } 21 | end 22 | 23 | def duration_to_seconds(duration) 24 | seconds_part = duration['seconds'] 25 | nanos_part = duration['nanos'].to_f / NANOSECONDS_PER_SECOND 26 | seconds_part + nanos_part 27 | end 28 | end 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/step_definition.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | namespace cucumber::messages { 13 | 14 | using json = nlohmann::json; 15 | 16 | // 17 | // Represents the StepDefinition message in Cucumber's message protocol 18 | // @see Github - Cucumber - Messages 19 | // 20 | // Generated code 21 | 22 | struct step_definition 23 | { 24 | std::string id; 25 | cucumber::messages::step_definition_pattern pattern; 26 | cucumber::messages::source_reference source_reference; 27 | 28 | std::string to_string() const; 29 | 30 | void to_json(json& j) const; 31 | std::string to_json() const; 32 | }; 33 | 34 | std::ostream& 35 | operator<<(std::ostream& os, const step_definition& msg); 36 | 37 | void to_json(json& j, const step_definition& m); 38 | 39 | } 40 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/test_run_hook_started.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | namespace cucumber::messages { 12 | 13 | using json = nlohmann::json; 14 | 15 | // 16 | // Represents the TestRunHookStarted message in Cucumber's message protocol 17 | // @see Github - Cucumber - Messages 18 | // 19 | // Generated code 20 | 21 | struct test_run_hook_started 22 | { 23 | std::string id; 24 | std::string test_run_started_id; 25 | std::string hook_id; 26 | std::optional worker_id; 27 | cucumber::messages::timestamp timestamp; 28 | 29 | std::string to_string() const; 30 | 31 | void to_json(json& j) const; 32 | std::string to_json() const; 33 | }; 34 | 35 | std::ostream& 36 | operator<<(std::ostream& os, const test_run_hook_started& msg); 37 | 38 | void to_json(json& j, const test_run_hook_started& m); 39 | 40 | } 41 | -------------------------------------------------------------------------------- /elixir/lib/cucumber_message.ex: -------------------------------------------------------------------------------- 1 | defmodule CucumberMessages do 2 | @moduledoc """ 3 | This small library its sole purpose is to convert the protobuf schema to Elixir code. In order to use this library, you do not need protoc installed at all! 4 | """ 5 | 6 | @doc """ 7 | Convert a list of envelopes to the passed format. At the moment only ndjson is supported until there is binary test data. 8 | 9 | Because the underlying Protox library doesn't support JSON conversion, we had to write a manual implementation. ndjson formatting is, at the moment, only supported for the `cucumber_gherkin` library. Other messages will not properly be formatted according to protobuf protocols. 10 | """ 11 | def convert_envelopes_to(envelopes, :ndjson) do 12 | Enum.map(envelopes, &CucumberMessages.Writer.envelope_to_ndjson!/1) 13 | |> Enum.map(&Jason.encode!(&1)) 14 | |> Enum.join("\n") 15 | |> case do 16 | "" -> "" 17 | result -> result <> "\n" 18 | end 19 | end 20 | 21 | # def convert_envelopes_to(envelopes, :binary) do 22 | # end 23 | end 24 | -------------------------------------------------------------------------------- /dotnet/Cucumber.Messages.Specs/ConvertersTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Xunit; 7 | 8 | namespace Cucumber.Messages.Specs 9 | { 10 | public class ConvertersTests 11 | { 12 | 13 | [Fact] 14 | public void ConvertsToAndFromTimestamp() 15 | { 16 | var current = DateTime.Parse("2024-06-29T17:29:47.1537257Z", null, System.Globalization.DateTimeStyles.RoundtripKind); 17 | var timestamp = Converters.ToTimestamp(current); 18 | 19 | var dt = Converters.ToDateTime(timestamp); 20 | 21 | Assert.Equal(current, dt); 22 | } 23 | 24 | [Fact] 25 | public void ConvertsToAndFromDuration() 26 | { 27 | var current = TimeSpan.FromSeconds(3.000161); 28 | var duration = Converters.ToDuration(current); 29 | 30 | var ts = Converters.ToTimeSpan(duration); 31 | 32 | Assert.Equal(current, ts); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /java/src/generated/java/io/cucumber/messages/types/HookType.java: -------------------------------------------------------------------------------- 1 | package io.cucumber.messages.types; 2 | 3 | // Generated code 4 | @SuppressWarnings("unused") 5 | public enum HookType { 6 | 7 | BEFORE_TEST_RUN("BEFORE_TEST_RUN"), 8 | 9 | AFTER_TEST_RUN("AFTER_TEST_RUN"), 10 | 11 | BEFORE_TEST_CASE("BEFORE_TEST_CASE"), 12 | 13 | AFTER_TEST_CASE("AFTER_TEST_CASE"), 14 | 15 | BEFORE_TEST_STEP("BEFORE_TEST_STEP"), 16 | 17 | AFTER_TEST_STEP("AFTER_TEST_STEP"); 18 | 19 | private final String value; 20 | 21 | HookType(String value) { 22 | this.value = value; 23 | } 24 | 25 | @Override 26 | public String toString() { 27 | return this.value; 28 | } 29 | 30 | public String value() { 31 | return this.value; 32 | } 33 | 34 | public static HookType fromValue(String value) { 35 | for (HookType v : values()) { 36 | if (v.value.equals(value)) { 37 | return v; 38 | } 39 | } 40 | throw new IllegalArgumentException(value); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /java/src/generated/java/io/cucumber/messages/types/TestStepResultStatus.java: -------------------------------------------------------------------------------- 1 | package io.cucumber.messages.types; 2 | 3 | // Generated code 4 | @SuppressWarnings("unused") 5 | public enum TestStepResultStatus { 6 | 7 | UNKNOWN("UNKNOWN"), 8 | 9 | PASSED("PASSED"), 10 | 11 | SKIPPED("SKIPPED"), 12 | 13 | PENDING("PENDING"), 14 | 15 | UNDEFINED("UNDEFINED"), 16 | 17 | AMBIGUOUS("AMBIGUOUS"), 18 | 19 | FAILED("FAILED"); 20 | 21 | private final String value; 22 | 23 | TestStepResultStatus(String value) { 24 | this.value = value; 25 | } 26 | 27 | @Override 28 | public String toString() { 29 | return this.value; 30 | } 31 | 32 | public String value() { 33 | return this.value; 34 | } 35 | 36 | public static TestStepResultStatus fromValue(String value) { 37 | for (TestStepResultStatus v : values()) { 38 | if (v.value.equals(value)) { 39 | return v; 40 | } 41 | } 42 | throw new IllegalArgumentException(value); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /jsonschema/src/StepDefinition.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "StepDefinition.json", 4 | "additionalProperties": false, 5 | "definitions": { 6 | "StepDefinitionPattern": { 7 | "additionalProperties": false, 8 | "required": [ 9 | "source", 10 | "type" 11 | ], 12 | "properties": { 13 | "source": { 14 | "type": "string" 15 | }, 16 | "type": { 17 | "enum": [ 18 | "CUCUMBER_EXPRESSION", 19 | "REGULAR_EXPRESSION" 20 | ], 21 | "type": "string" 22 | } 23 | }, 24 | "type": "object" 25 | } 26 | }, 27 | "required": [ 28 | "id", 29 | "pattern", 30 | "sourceReference" 31 | ], 32 | "properties": { 33 | "id": { 34 | "type": "string" 35 | }, 36 | "pattern": { 37 | "$ref": "#/definitions/StepDefinitionPattern" 38 | }, 39 | "sourceReference": { 40 | "$ref": "./SourceReference.json" 41 | } 42 | }, 43 | "type": "object" 44 | } 45 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/background.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | namespace cucumber::messages { 13 | 14 | using json = nlohmann::json; 15 | 16 | // 17 | // Represents the Background message in Cucumber's message protocol 18 | // @see Github - Cucumber - Messages 19 | // 20 | // Generated code 21 | 22 | struct background 23 | { 24 | cucumber::messages::location location; 25 | std::string keyword; 26 | std::string name; 27 | std::string description; 28 | std::vector steps; 29 | std::string id; 30 | 31 | std::string to_string() const; 32 | 33 | void to_json(json& j) const; 34 | std::string to_json() const; 35 | }; 36 | 37 | std::ostream& 38 | operator<<(std::ostream& os, const background& msg); 39 | 40 | void to_json(json& j, const background& m); 41 | 42 | } 43 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/test_run_hook_finished.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | namespace cucumber::messages { 13 | 14 | using json = nlohmann::json; 15 | 16 | // 17 | // Represents the TestRunHookFinished message in Cucumber's message protocol 18 | // @see Github - Cucumber - Messages 19 | // 20 | // Generated code 21 | 22 | struct test_run_hook_finished 23 | { 24 | std::string test_run_hook_started_id; 25 | cucumber::messages::test_step_result result; 26 | cucumber::messages::timestamp timestamp; 27 | 28 | std::string to_string() const; 29 | 30 | void to_json(json& j) const; 31 | std::string to_json() const; 32 | }; 33 | 34 | std::ostream& 35 | operator<<(std::ostream& os, const test_run_hook_finished& msg); 36 | 37 | void to_json(json& j, const test_run_hook_finished& m); 38 | 39 | } 40 | -------------------------------------------------------------------------------- /jsonschema/src/TestStepResult.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "TestStepResult.json", 4 | "additionalProperties": false, 5 | "required": [ 6 | "duration", 7 | "status" 8 | ], 9 | "properties": { 10 | "duration": { 11 | "$ref": "./Duration.json" 12 | }, 13 | "message": { 14 | "type": "string", 15 | "description": "An arbitrary bit of information that explains this result. If there was an exception, this should include a stringified representation of it including type, message and stack trace (the exact format will vary by platform)." 16 | }, 17 | "status": { 18 | "enum": [ 19 | "UNKNOWN", 20 | "PASSED", 21 | "SKIPPED", 22 | "PENDING", 23 | "UNDEFINED", 24 | "AMBIGUOUS", 25 | "FAILED" 26 | ], 27 | "type": "string" 28 | }, 29 | "exception": { 30 | "$ref": "./Exception.json", 31 | "description": "Exception thrown while executing this step, if any." 32 | } 33 | }, 34 | "type": "object" 35 | } 36 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/hook.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | namespace cucumber::messages { 13 | 14 | using json = nlohmann::json; 15 | 16 | // 17 | // Represents the Hook message in Cucumber's message protocol 18 | // @see Github - Cucumber - Messages 19 | // 20 | // Generated code 21 | 22 | struct hook 23 | { 24 | std::string id; 25 | std::optional name; 26 | cucumber::messages::source_reference source_reference; 27 | std::optional tag_expression; 28 | std::optional type; 29 | 30 | std::string to_string() const; 31 | 32 | void to_json(json& j) const; 33 | std::string to_json() const; 34 | }; 35 | 36 | std::ostream& 37 | operator<<(std::ostream& os, const hook& msg); 38 | 39 | void to_json(json& j, const hook& m); 40 | 41 | } 42 | -------------------------------------------------------------------------------- /cpp/src/lib/messages/cucumber/messages/location.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace cucumber::messages { 7 | 8 | std::string 9 | location::to_string() const 10 | { 11 | std::ostringstream oss; 12 | 13 | cucumber::messages::to_string(oss, "line=", line); 14 | cucumber::messages::to_string(oss, ", column=", column); 15 | 16 | return oss.str(); 17 | } 18 | 19 | void 20 | location::to_json(json& j) const 21 | { 22 | cucumber::messages::to_json(j, camelize("line"), line); 23 | cucumber::messages::to_json(j, camelize("column"), column); 24 | } 25 | 26 | std::string 27 | location::to_json() const 28 | { 29 | std::ostringstream oss; 30 | json j; 31 | 32 | to_json(j); 33 | 34 | oss << j; 35 | 36 | return oss.str(); 37 | } 38 | 39 | std::ostream& 40 | operator<<(std::ostream& os, const location& msg) 41 | { 42 | os << msg.to_string(); 43 | 44 | return os; 45 | } 46 | 47 | void to_json(json& j, const location& m) 48 | { m.to_json(j); } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /cpp/src/lib/messages/cucumber/messages/product.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace cucumber::messages { 7 | 8 | std::string 9 | product::to_string() const 10 | { 11 | std::ostringstream oss; 12 | 13 | cucumber::messages::to_string(oss, "name=", name); 14 | cucumber::messages::to_string(oss, ", version=", version); 15 | 16 | return oss.str(); 17 | } 18 | 19 | void 20 | product::to_json(json& j) const 21 | { 22 | cucumber::messages::to_json(j, camelize("name"), name); 23 | cucumber::messages::to_json(j, camelize("version"), version); 24 | } 25 | 26 | std::string 27 | product::to_json() const 28 | { 29 | std::ostringstream oss; 30 | json j; 31 | 32 | to_json(j); 33 | 34 | oss << j; 35 | 36 | return oss.str(); 37 | } 38 | 39 | std::ostream& 40 | operator<<(std::ostream& os, const product& msg) 41 | { 42 | os << msg.to_string(); 43 | 44 | return os; 45 | } 46 | 47 | void to_json(json& j, const product& m) 48 | { m.to_json(j); } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /dotnet/Cucumber.Messages/generated/StepDefinitionPatternType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Reflection; 4 | 5 | namespace Io.Cucumber.Messages.Types; 6 | 7 | // ------------------------------------------------------------------------------ 8 | // This code was generated based on the Cucumber JSON schema 9 | // Changes to this file may cause incorrect behavior and will be lost if 10 | // the code is regenerated. 11 | // ------------------------------------------------------------------------------ 12 | 13 | public enum StepDefinitionPatternType { 14 | 15 | [Description("CUCUMBER_EXPRESSION")] 16 | CUCUMBER_EXPRESSION, 17 | 18 | [Description("REGULAR_EXPRESSION")] 19 | REGULAR_EXPRESSION 20 | } 21 | 22 | public static class StepDefinitionPatternTypeExtensions 23 | { 24 | public static string Value(this StepDefinitionPatternType v) { 25 | var attribute = v.GetType().GetField(v.ToString()).GetCustomAttribute(); 26 | return attribute == null ? v.ToString() : attribute.Description; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /cpp/src/lib/messages/cucumber/messages/comment.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace cucumber::messages { 7 | 8 | std::string 9 | comment::to_string() const 10 | { 11 | std::ostringstream oss; 12 | 13 | cucumber::messages::to_string(oss, "location=", location); 14 | cucumber::messages::to_string(oss, ", text=", text); 15 | 16 | return oss.str(); 17 | } 18 | 19 | void 20 | comment::to_json(json& j) const 21 | { 22 | cucumber::messages::to_json(j, camelize("location"), location); 23 | cucumber::messages::to_json(j, camelize("text"), text); 24 | } 25 | 26 | std::string 27 | comment::to_json() const 28 | { 29 | std::ostringstream oss; 30 | json j; 31 | 32 | to_json(j); 33 | 34 | oss << j; 35 | 36 | return oss.str(); 37 | } 38 | 39 | std::ostream& 40 | operator<<(std::ostream& os, const comment& msg) 41 | { 42 | os << msg.to_string(); 43 | 44 | return os; 45 | } 46 | 47 | void to_json(json& j, const comment& m) 48 | { m.to_json(j); } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /cpp/src/lib/messages/cucumber/messages/snippet.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace cucumber::messages { 7 | 8 | std::string 9 | snippet::to_string() const 10 | { 11 | std::ostringstream oss; 12 | 13 | cucumber::messages::to_string(oss, "language=", language); 14 | cucumber::messages::to_string(oss, ", code=", code); 15 | 16 | return oss.str(); 17 | } 18 | 19 | void 20 | snippet::to_json(json& j) const 21 | { 22 | cucumber::messages::to_json(j, camelize("language"), language); 23 | cucumber::messages::to_json(j, camelize("code"), code); 24 | } 25 | 26 | std::string 27 | snippet::to_json() const 28 | { 29 | std::ostringstream oss; 30 | json j; 31 | 32 | to_json(j); 33 | 34 | oss << j; 35 | 36 | return oss.str(); 37 | } 38 | 39 | std::ostream& 40 | operator<<(std::ostream& os, const snippet& msg) 41 | { 42 | os << msg.to_string(); 43 | 44 | return os; 45 | } 46 | 47 | void to_json(json& j, const snippet& m) 48 | { m.to_json(j); } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /dotnet/Cucumber.Messages/generated/SourceMediaType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Reflection; 4 | 5 | namespace Io.Cucumber.Messages.Types; 6 | 7 | // ------------------------------------------------------------------------------ 8 | // This code was generated based on the Cucumber JSON schema 9 | // Changes to this file may cause incorrect behavior and will be lost if 10 | // the code is regenerated. 11 | // ------------------------------------------------------------------------------ 12 | 13 | public enum SourceMediaType { 14 | 15 | [Description("text/x.cucumber.gherkin+plain")] 16 | TEXT_X_CUCUMBER_GHERKIN_PLAIN, 17 | 18 | [Description("text/x.cucumber.gherkin+markdown")] 19 | TEXT_X_CUCUMBER_GHERKIN_MARKDOWN 20 | } 21 | 22 | public static class SourceMediaTypeExtensions 23 | { 24 | public static string Value(this SourceMediaType v) { 25 | var attribute = v.GetType().GetField(v.ToString()).GetCustomAttribute(); 26 | return attribute == null ? v.ToString() : attribute.Description; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /cpp/src/lib/messages/cucumber/messages/duration.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace cucumber::messages { 7 | 8 | std::string 9 | duration::to_string() const 10 | { 11 | std::ostringstream oss; 12 | 13 | cucumber::messages::to_string(oss, "seconds=", seconds); 14 | cucumber::messages::to_string(oss, ", nanos=", nanos); 15 | 16 | return oss.str(); 17 | } 18 | 19 | void 20 | duration::to_json(json& j) const 21 | { 22 | cucumber::messages::to_json(j, camelize("seconds"), seconds); 23 | cucumber::messages::to_json(j, camelize("nanos"), nanos); 24 | } 25 | 26 | std::string 27 | duration::to_json() const 28 | { 29 | std::ostringstream oss; 30 | json j; 31 | 32 | to_json(j); 33 | 34 | oss << j; 35 | 36 | return oss.str(); 37 | } 38 | 39 | std::ostream& 40 | operator<<(std::ostream& os, const duration& msg) 41 | { 42 | os << msg.to_string(); 43 | 44 | return os; 45 | } 46 | 47 | void to_json(json& j, const duration& m) 48 | { m.to_json(j); } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/test_step_finished.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | namespace cucumber::messages { 13 | 14 | using json = nlohmann::json; 15 | 16 | // 17 | // Represents the TestStepFinished message in Cucumber's message protocol 18 | // @see Github - Cucumber - Messages 19 | // 20 | // Generated code 21 | 22 | struct test_step_finished 23 | { 24 | std::string test_case_started_id; 25 | std::string test_step_id; 26 | cucumber::messages::test_step_result test_step_result; 27 | cucumber::messages::timestamp timestamp; 28 | 29 | std::string to_string() const; 30 | 31 | void to_json(json& j) const; 32 | std::string to_json() const; 33 | }; 34 | 35 | std::ostream& 36 | operator<<(std::ostream& os, const test_step_finished& msg); 37 | 38 | void to_json(json& j, const test_step_finished& m); 39 | 40 | } 41 | -------------------------------------------------------------------------------- /cpp/src/lib/messages/cucumber/messages/timestamp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace cucumber::messages { 7 | 8 | std::string 9 | timestamp::to_string() const 10 | { 11 | std::ostringstream oss; 12 | 13 | cucumber::messages::to_string(oss, "seconds=", seconds); 14 | cucumber::messages::to_string(oss, ", nanos=", nanos); 15 | 16 | return oss.str(); 17 | } 18 | 19 | void 20 | timestamp::to_json(json& j) const 21 | { 22 | cucumber::messages::to_json(j, camelize("seconds"), seconds); 23 | cucumber::messages::to_json(j, camelize("nanos"), nanos); 24 | } 25 | 26 | std::string 27 | timestamp::to_json() const 28 | { 29 | std::ostringstream oss; 30 | json j; 31 | 32 | to_json(j); 33 | 34 | oss << j; 35 | 36 | return oss.str(); 37 | } 38 | 39 | std::ostream& 40 | operator<<(std::ostream& os, const timestamp& msg) 41 | { 42 | os << msg.to_string(); 43 | 44 | return os; 45 | } 46 | 47 | void to_json(json& j, const timestamp& m) 48 | { m.to_json(j); } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/pickle_step_argument.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | namespace cucumber::messages { 13 | 14 | using json = nlohmann::json; 15 | 16 | // 17 | // Represents the PickleStepArgument message in Cucumber's message protocol 18 | // @see Github - Cucumber - Messages 19 | // 20 | // An optional argument 21 | // 22 | // Generated code 23 | 24 | struct pickle_step_argument 25 | { 26 | std::optional doc_string; 27 | std::optional data_table; 28 | 29 | std::string to_string() const; 30 | 31 | void to_json(json& j) const; 32 | std::string to_json() const; 33 | }; 34 | 35 | std::ostream& 36 | operator<<(std::ostream& os, const pickle_step_argument& msg); 37 | 38 | void to_json(json& j, const pickle_step_argument& m); 39 | 40 | } 41 | -------------------------------------------------------------------------------- /dotnet/Cucumber.Messages/generated/PickleStepType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Reflection; 4 | 5 | namespace Io.Cucumber.Messages.Types; 6 | 7 | // ------------------------------------------------------------------------------ 8 | // This code was generated based on the Cucumber JSON schema 9 | // Changes to this file may cause incorrect behavior and will be lost if 10 | // the code is regenerated. 11 | // ------------------------------------------------------------------------------ 12 | 13 | public enum PickleStepType { 14 | 15 | [Description("Unknown")] 16 | UNKNOWN, 17 | 18 | [Description("Context")] 19 | CONTEXT, 20 | 21 | [Description("Action")] 22 | ACTION, 23 | 24 | [Description("Outcome")] 25 | OUTCOME 26 | } 27 | 28 | public static class PickleStepTypeExtensions 29 | { 30 | public static string Value(this PickleStepType v) { 31 | var attribute = v.GetType().GetField(v.ToString()).GetCustomAttribute(); 32 | return attribute == null ? v.ToString() : attribute.Description; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/parameter_type.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | namespace cucumber::messages { 12 | 13 | using json = nlohmann::json; 14 | 15 | // 16 | // Represents the ParameterType message in Cucumber's message protocol 17 | // @see Github - Cucumber - Messages 18 | // 19 | // Generated code 20 | 21 | struct parameter_type 22 | { 23 | std::string name; 24 | std::vector regular_expressions; 25 | bool prefer_for_regular_expression_match; 26 | bool use_for_snippets; 27 | std::string id; 28 | std::optional source_reference; 29 | 30 | std::string to_string() const; 31 | 32 | void to_json(json& j) const; 33 | std::string to_json() const; 34 | }; 35 | 36 | std::ostream& 37 | operator<<(std::ostream& os, const parameter_type& msg); 38 | 39 | void to_json(json& j, const parameter_type& m); 40 | 41 | } 42 | -------------------------------------------------------------------------------- /cpp/src/lib/messages/cucumber/messages/data_table.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace cucumber::messages { 7 | 8 | std::string 9 | data_table::to_string() const 10 | { 11 | std::ostringstream oss; 12 | 13 | cucumber::messages::to_string(oss, "location=", location); 14 | cucumber::messages::to_string(oss, ", rows=", rows); 15 | 16 | return oss.str(); 17 | } 18 | 19 | void 20 | data_table::to_json(json& j) const 21 | { 22 | cucumber::messages::to_json(j, camelize("location"), location); 23 | cucumber::messages::to_json(j, camelize("rows"), rows); 24 | } 25 | 26 | std::string 27 | data_table::to_json() const 28 | { 29 | std::ostringstream oss; 30 | json j; 31 | 32 | to_json(j); 33 | 34 | oss << j; 35 | 36 | return oss.str(); 37 | } 38 | 39 | std::ostream& 40 | operator<<(std::ostream& os, const data_table& msg) 41 | { 42 | os << msg.to_string(); 43 | 44 | return os; 45 | } 46 | 47 | void to_json(json& j, const data_table& m) 48 | { m.to_json(j); } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /cpp/src/lib/messages/cucumber/messages/table_cell.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace cucumber::messages { 7 | 8 | std::string 9 | table_cell::to_string() const 10 | { 11 | std::ostringstream oss; 12 | 13 | cucumber::messages::to_string(oss, "location=", location); 14 | cucumber::messages::to_string(oss, ", value=", value); 15 | 16 | return oss.str(); 17 | } 18 | 19 | void 20 | table_cell::to_json(json& j) const 21 | { 22 | cucumber::messages::to_json(j, camelize("location"), location); 23 | cucumber::messages::to_json(j, camelize("value"), value); 24 | } 25 | 26 | std::string 27 | table_cell::to_json() const 28 | { 29 | std::ostringstream oss; 30 | json j; 31 | 32 | to_json(j); 33 | 34 | oss << j; 35 | 36 | return oss.str(); 37 | } 38 | 39 | std::ostream& 40 | operator<<(std::ostream& os, const table_cell& msg) 41 | { 42 | os << msg.to_string(); 43 | 44 | return os; 45 | } 46 | 47 | void to_json(json& j, const table_cell& m) 48 | { m.to_json(j); } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /cpp/src/lib/messages/cucumber/messages/parse_error.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace cucumber::messages { 7 | 8 | std::string 9 | parse_error::to_string() const 10 | { 11 | std::ostringstream oss; 12 | 13 | cucumber::messages::to_string(oss, "source=", source); 14 | cucumber::messages::to_string(oss, ", message=", message); 15 | 16 | return oss.str(); 17 | } 18 | 19 | void 20 | parse_error::to_json(json& j) const 21 | { 22 | cucumber::messages::to_json(j, camelize("source"), source); 23 | cucumber::messages::to_json(j, camelize("message"), message); 24 | } 25 | 26 | std::string 27 | parse_error::to_json() const 28 | { 29 | std::ostringstream oss; 30 | json j; 31 | 32 | to_json(j); 33 | 34 | oss << j; 35 | 36 | return oss.str(); 37 | } 38 | 39 | std::ostream& 40 | operator<<(std::ostream& os, const parse_error& msg) 41 | { 42 | os << msg.to_string(); 43 | 44 | return os; 45 | } 46 | 47 | void to_json(json& j, const parse_error& m) 48 | { m.to_json(j); } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /cpp/src/lib/messages/cucumber/messages/pickle_tag.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace cucumber::messages { 7 | 8 | std::string 9 | pickle_tag::to_string() const 10 | { 11 | std::ostringstream oss; 12 | 13 | cucumber::messages::to_string(oss, "name=", name); 14 | cucumber::messages::to_string(oss, ", ast_node_id=", ast_node_id); 15 | 16 | return oss.str(); 17 | } 18 | 19 | void 20 | pickle_tag::to_json(json& j) const 21 | { 22 | cucumber::messages::to_json(j, camelize("name"), name); 23 | cucumber::messages::to_json(j, camelize("ast_node_id"), ast_node_id); 24 | } 25 | 26 | std::string 27 | pickle_tag::to_json() const 28 | { 29 | std::ostringstream oss; 30 | json j; 31 | 32 | to_json(j); 33 | 34 | oss << j; 35 | 36 | return oss.str(); 37 | } 38 | 39 | std::ostream& 40 | operator<<(std::ostream& os, const pickle_tag& msg) 41 | { 42 | os << msg.to_string(); 43 | 44 | return os; 45 | } 46 | 47 | void to_json(json& j, const pickle_tag& m) 48 | { m.to_json(j); } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /.github/workflows/test-go.yml: -------------------------------------------------------------------------------- 1 | name: test-go 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - renovate/** 8 | paths: 9 | - go/** 10 | - Makefile 11 | - .github/** 12 | pull_request: 13 | branches: 14 | - main 15 | paths: 16 | - go/** 17 | - Makefile 18 | - .github/** 19 | workflow_call: 20 | 21 | jobs: 22 | test-go: 23 | runs-on: ${{ matrix.os }} 24 | strategy: 25 | fail-fast: false 26 | matrix: 27 | os: 28 | - ubuntu-latest 29 | go: ['1.20.x', '1.21.x'] 30 | include: 31 | - os: windows-latest 32 | go: '1.21.x' 33 | - os: macos-latest 34 | go: '1.21.x' 35 | 36 | steps: 37 | - uses: actions/checkout@v6 38 | - name: Set up Go 39 | uses: actions/setup-go@v6 40 | with: 41 | go-version: ${{ matrix.go }} 42 | cache-dependency-path: go/go.sum 43 | 44 | - name: lint 45 | working-directory: go 46 | run: gofmt -w . 47 | 48 | - name: test 49 | working-directory: go 50 | run: go test --v ./... 51 | -------------------------------------------------------------------------------- /javascript/Makefile: -------------------------------------------------------------------------------- 1 | schemas = $(shell find ../jsonschema/src -name "*.json") 2 | 3 | .DEFAULT_GOAL = help 4 | 5 | help: ## Show this help 6 | @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \n\nWhere is one of:\n"} /^[$$()% a-zA-Z_-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) 7 | 8 | generate: require src/messages.ts ## Generate typescript code based on the schemas found in ../jsonschema and using the scripts in ../jsonschema/scripts for the generation 9 | 10 | require: ## Check requirements for the code generation (ruby is required) 11 | @ruby --version >/dev/null 2>&1 || (echo "ERROR: ruby is required."; exit 1) 12 | 13 | clean: ## Remove automatically generated files and related artifacts 14 | rm -f src/messages.ts 15 | 16 | src/messages.ts: $(schemas) ../codegen/codegen.rb ../codegen/templates/typescript.ts.erb ../codegen/templates/typescript.enum.ts.erb 17 | ruby ../codegen/codegen.rb Generator::TypeScript typescript.ts.erb > $@ 18 | ruby ../codegen/codegen.rb Generator::TypeScript typescript.enum.ts.erb >> $@ 19 | -------------------------------------------------------------------------------- /ruby/lib/cucumber/messages/pickle_table_cell.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # The code was auto-generated by {this script}[https://github.com/cucumber/messages/blob/main/codegen/codegen.rb] 4 | module Cucumber 5 | module Messages 6 | ## 7 | # Represents the PickleTableCell message in Cucumber's {message protocol}[https://github.com/cucumber/messages]. 8 | ## 9 | ## 10 | class PickleTableCell < Message 11 | attr_reader :value 12 | 13 | def initialize( 14 | value: '' 15 | ) 16 | @value = value 17 | super() 18 | end 19 | 20 | ## 21 | # Returns a new PickleTableCell from the given hash. 22 | # If the hash keys are camelCased, they are properly assigned to the 23 | # corresponding snake_cased attributes. 24 | # 25 | # Cucumber::Messages::PickleTableCell.from_h(some_hash) # => # 26 | ## 27 | def self.from_h(hash) 28 | return nil if hash.nil? 29 | 30 | new( 31 | value: hash[:value] 32 | ) 33 | end 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/test_run_finished.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | namespace cucumber::messages { 13 | 14 | using json = nlohmann::json; 15 | 16 | // 17 | // Represents the TestRunFinished message in Cucumber's message protocol 18 | // @see Github - Cucumber - Messages 19 | // 20 | // Generated code 21 | 22 | struct test_run_finished 23 | { 24 | std::optional message; 25 | bool success; 26 | cucumber::messages::timestamp timestamp; 27 | std::optional exception; 28 | std::optional test_run_started_id; 29 | 30 | std::string to_string() const; 31 | 32 | void to_json(json& j) const; 33 | std::string to_json() const; 34 | }; 35 | 36 | std::ostream& 37 | operator<<(std::ostream& os, const test_run_finished& msg); 38 | 39 | void to_json(json& j, const test_run_finished& m); 40 | 41 | } 42 | -------------------------------------------------------------------------------- /cpp/src/lib/messages/cucumber/messages/rule_child.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace cucumber::messages { 7 | 8 | std::string 9 | rule_child::to_string() const 10 | { 11 | std::ostringstream oss; 12 | 13 | cucumber::messages::to_string(oss, "background=", background); 14 | cucumber::messages::to_string(oss, ", scenario=", scenario); 15 | 16 | return oss.str(); 17 | } 18 | 19 | void 20 | rule_child::to_json(json& j) const 21 | { 22 | cucumber::messages::to_json(j, camelize("background"), background); 23 | cucumber::messages::to_json(j, camelize("scenario"), scenario); 24 | } 25 | 26 | std::string 27 | rule_child::to_json() const 28 | { 29 | std::ostringstream oss; 30 | json j; 31 | 32 | to_json(j); 33 | 34 | oss << j; 35 | 36 | return oss.str(); 37 | } 38 | 39 | std::ostream& 40 | operator<<(std::ostream& os, const rule_child& msg) 41 | { 42 | os << msg.to_string(); 43 | 44 | return os; 45 | } 46 | 47 | void to_json(json& j, const rule_child& m) 48 | { m.to_json(j); } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /cpp/src/lib/messages/cucumber/messages/step_match_arguments_list.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace cucumber::messages { 7 | 8 | std::string 9 | step_match_arguments_list::to_string() const 10 | { 11 | std::ostringstream oss; 12 | 13 | cucumber::messages::to_string(oss, "step_match_arguments=", step_match_arguments); 14 | 15 | return oss.str(); 16 | } 17 | 18 | void 19 | step_match_arguments_list::to_json(json& j) const 20 | { 21 | cucumber::messages::to_json(j, camelize("step_match_arguments"), step_match_arguments); 22 | } 23 | 24 | std::string 25 | step_match_arguments_list::to_json() const 26 | { 27 | std::ostringstream oss; 28 | json j; 29 | 30 | to_json(j); 31 | 32 | oss << j; 33 | 34 | return oss.str(); 35 | } 36 | 37 | std::ostream& 38 | operator<<(std::ostream& os, const step_match_arguments_list& msg) 39 | { 40 | os << msg.to_string(); 41 | 42 | return os; 43 | } 44 | 45 | void to_json(json& j, const step_match_arguments_list& m) 46 | { m.to_json(j); } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /go/Makefile: -------------------------------------------------------------------------------- 1 | schemas = $(shell find ../jsonschema/src -name "*.json") 2 | 3 | .DEFAULT_GOAL = help 4 | 5 | help: ## Show this help 6 | @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \n\nWhere is one of:\n"} /^[$$()% a-zA-Z_-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) 7 | 8 | generate: require messages.go ## Generate go code based on the schemas found in ../jsonschema and using the scripts in ../jsonschema/scripts for the generation 9 | 10 | require: ## Check requirements for the code generation (ruby and go are required) 11 | @ruby --version >/dev/null 2>&1 || (echo "ERROR: ruby is required."; exit 1) 12 | @go version >/dev/null 2>&1 || (echo "ERROR: go is required."; exit 1) 13 | 14 | clean: ## Remove automatically generated files and related artifacts 15 | rm -f messages.go 16 | 17 | messages.go: $(schemas) ../codegen/codegen.rb ../codegen/templates/go.go.erb ../codegen/templates/go.enum.go.erb 18 | ruby ../codegen/codegen.rb Generator::Go go.go.erb > $@ 19 | ruby ../codegen/codegen.rb Generator::Go go.enum.go.erb >> $@ 20 | -------------------------------------------------------------------------------- /jsonschema/src/TestRunFinished.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "TestRunFinished.json", 4 | "additionalProperties": false, 5 | "required": [ 6 | "success", 7 | "timestamp" 8 | ], 9 | "properties": { 10 | "message": { 11 | "description": "An informative message about the test run. Typically additional information about failure, but not necessarily.", 12 | "type": "string" 13 | }, 14 | "success": { 15 | "description": "A test run is successful if all steps are either passed or skipped, all before/after hooks passed and no other exceptions where thrown.", 16 | "type": "boolean" 17 | }, 18 | "timestamp": { 19 | "$ref": "./Timestamp.json", 20 | "description": "Timestamp when the TestRun is finished" 21 | }, 22 | "exception": { 23 | "$ref": "./Exception.json", 24 | "description": "Any exception thrown during the test run, if any. Does not include exceptions thrown while executing steps." 25 | }, 26 | "testRunStartedId": { 27 | "type": "string" 28 | } 29 | }, 30 | "type": "object" 31 | } 32 | -------------------------------------------------------------------------------- /cpp/src/lib/messages/cucumber/messages/test_run_started.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace cucumber::messages { 7 | 8 | std::string 9 | test_run_started::to_string() const 10 | { 11 | std::ostringstream oss; 12 | 13 | cucumber::messages::to_string(oss, "timestamp=", timestamp); 14 | cucumber::messages::to_string(oss, ", id=", id); 15 | 16 | return oss.str(); 17 | } 18 | 19 | void 20 | test_run_started::to_json(json& j) const 21 | { 22 | cucumber::messages::to_json(j, camelize("timestamp"), timestamp); 23 | cucumber::messages::to_json(j, camelize("id"), id); 24 | } 25 | 26 | std::string 27 | test_run_started::to_json() const 28 | { 29 | std::ostringstream oss; 30 | json j; 31 | 32 | to_json(j); 33 | 34 | oss << j; 35 | 36 | return oss.str(); 37 | } 38 | 39 | std::ostream& 40 | operator<<(std::ostream& os, const test_run_started& msg) 41 | { 42 | os << msg.to_string(); 43 | 44 | return os; 45 | } 46 | 47 | void to_json(json& j, const test_run_started& m) 48 | { m.to_json(j); } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /ruby/lib/cucumber/messages/pickle_table.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # The code was auto-generated by {this script}[https://github.com/cucumber/messages/blob/main/codegen/codegen.rb] 4 | module Cucumber 5 | module Messages 6 | ## 7 | # Represents the PickleTable message in Cucumber's {message protocol}[https://github.com/cucumber/messages]. 8 | ## 9 | ## 10 | class PickleTable < Message 11 | attr_reader :rows 12 | 13 | def initialize( 14 | rows: [] 15 | ) 16 | @rows = rows 17 | super() 18 | end 19 | 20 | ## 21 | # Returns a new PickleTable from the given hash. 22 | # If the hash keys are camelCased, they are properly assigned to the 23 | # corresponding snake_cased attributes. 24 | # 25 | # Cucumber::Messages::PickleTable.from_h(some_hash) # => # 26 | ## 27 | def self.from_h(hash) 28 | return nil if hash.nil? 29 | 30 | new( 31 | rows: hash[:rows]&.map { |item| PickleTableRow.from_h(item) } 32 | ) 33 | end 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | # See https://pre-commit.com for more information 2 | # See https://pre-commit.com/hooks.html for more hooks 3 | --- 4 | files: ^python/ 5 | exclude: .*python/src/cucumber_messages/_messages\.py 6 | repos: 7 | - repo: https://github.com/pre-commit/pre-commit-hooks 8 | rev: v6.0.0 9 | hooks: 10 | - id: trailing-whitespace 11 | - id: end-of-file-fixer 12 | - id: check-added-large-files 13 | - repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks 14 | rev: v2.15.0 15 | hooks: 16 | - id: pretty-format-toml 17 | args: [--autofix] 18 | - repo: https://github.com/astral-sh/ruff-pre-commit 19 | rev: v0.14.10 20 | hooks: 21 | - id: ruff-check 22 | args: [--fix] 23 | - id: ruff-format 24 | - repo: https://github.com/pre-commit/mirrors-mypy 25 | rev: v1.19.1 26 | hooks: 27 | - id: mypy 28 | - repo: https://github.com/astral-sh/uv-pre-commit 29 | rev: 0.9.18 30 | hooks: 31 | # Ensure the uv lock file is up to date 32 | - id: uv-lock 33 | files: python/pyproject.toml 34 | args: [--project, python] 35 | -------------------------------------------------------------------------------- /.github/workflows/test-java.yml: -------------------------------------------------------------------------------- 1 | name: test-java 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - renovate/** 8 | paths: 9 | - java/** 10 | - Makefile 11 | - .github/** 12 | pull_request: 13 | branches: 14 | - main 15 | paths: 16 | - java/** 17 | - Makefile 18 | - .github/** 19 | workflow_call: 20 | 21 | jobs: 22 | test-java: 23 | name: Java ${{ matrix.java }} ${{ matrix.os }} 24 | runs-on: ${{ matrix.os }} 25 | strategy: 26 | fail-fast: true 27 | matrix: 28 | os: 29 | - ubuntu-latest 30 | java: ['17', '21'] 31 | include: 32 | - os: windows-latest 33 | java: "17" 34 | - os: macos-latest 35 | java: "17" 36 | 37 | steps: 38 | - uses: actions/checkout@v6 39 | 40 | - uses: actions/setup-java@v5 41 | with: 42 | distribution: 'temurin' 43 | java-version: ${{ matrix.java }} 44 | cache: 'maven' 45 | 46 | - run: mvn install 47 | working-directory: java 48 | 49 | - run: mvn test 50 | working-directory: java 51 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/feature_child.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | namespace cucumber::messages { 14 | 15 | using json = nlohmann::json; 16 | 17 | // 18 | // Represents the FeatureChild message in Cucumber's message protocol 19 | // @see Github - Cucumber - Messages 20 | // 21 | // A child node of a `Feature` node 22 | // 23 | // Generated code 24 | 25 | struct feature_child 26 | { 27 | std::optional rule; 28 | std::optional background; 29 | std::optional scenario; 30 | 31 | std::string to_string() const; 32 | 33 | void to_json(json& j) const; 34 | std::string to_json() const; 35 | }; 36 | 37 | std::ostream& 38 | operator<<(std::ostream& os, const feature_child& msg); 39 | 40 | void to_json(json& j, const feature_child& m); 41 | 42 | } 43 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/rule.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | namespace cucumber::messages { 14 | 15 | using json = nlohmann::json; 16 | 17 | // 18 | // Represents the Rule message in Cucumber's message protocol 19 | // @see Github - Cucumber - Messages 20 | // 21 | // Generated code 22 | 23 | struct rule 24 | { 25 | cucumber::messages::location location; 26 | std::vector tags; 27 | std::string keyword; 28 | std::string name; 29 | std::string description; 30 | std::vector children; 31 | std::string id; 32 | 33 | std::string to_string() const; 34 | 35 | void to_json(json& j) const; 36 | std::string to_json() const; 37 | }; 38 | 39 | std::ostream& 40 | operator<<(std::ostream& os, const rule& msg); 41 | 42 | void to_json(json& j, const rule& m); 43 | 44 | } 45 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Cucumber Ltd and contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /codegen/templates/dotnet.enum.dotnet.erb: -------------------------------------------------------------------------------- 1 | <% @enums.each do |enum| -%> 2 | <%= enum[:name] %>.cs 3 | using System; 4 | using System.ComponentModel; 5 | using System.Reflection; 6 | 7 | namespace Io.Cucumber.Messages.Types; 8 | 9 | // ------------------------------------------------------------------------------ 10 | // This code was generated based on the Cucumber JSON schema 11 | // Changes to this file may cause incorrect behavior and will be lost if 12 | // the code is regenerated. 13 | // ------------------------------------------------------------------------------ 14 | 15 | public enum <%= enum[:name] %> { 16 | <% enum[:values].each.with_index(1) do |value, index| -%> 17 | 18 | [Description("<%= value%>")] 19 | <%= enum_constant(value) %><%= index < enum[:values].length ? ',' : '' %> 20 | <% end -%> 21 | } 22 | 23 | public static class <%= enum[:name] %>Extensions 24 | { 25 | public static string Value(this <%= enum[:name] %> v) { 26 | var attribute = v.GetType().GetField(v.ToString()).GetCustomAttribute(); 27 | return attribute == null ? v.ToString() : attribute.Description; 28 | } 29 | } 30 | <% end -%> 31 | -------------------------------------------------------------------------------- /cpp/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Cucumber Ltd and contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /go/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Cucumber Ltd and contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /php/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Cucumber Ltd and contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /cpp/include/messages/cucumber/messages/pickle_step.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | namespace cucumber::messages { 13 | 14 | using json = nlohmann::json; 15 | 16 | // 17 | // Represents the PickleStep message in Cucumber's message protocol 18 | // @see Github - Cucumber - Messages 19 | // 20 | // An executable step 21 | // 22 | // Generated code 23 | 24 | struct pickle_step 25 | { 26 | std::optional argument; 27 | std::vector ast_node_ids; 28 | std::string id; 29 | std::optional type; 30 | std::string text; 31 | 32 | std::string to_string() const; 33 | 34 | void to_json(json& j) const; 35 | std::string to_json() const; 36 | }; 37 | 38 | std::ostream& 39 | operator<<(std::ostream& os, const pickle_step& msg); 40 | 41 | void to_json(json& j, const pickle_step& m); 42 | 43 | } 44 | --------------------------------------------------------------------------------