diff --git a/ruby/.gitignore b/ruby/.gitignore new file mode 100644 index 00000000..7ae6fcfb --- /dev/null +++ b/ruby/.gitignore @@ -0,0 +1,2 @@ +Gemfile.lock +*.gem diff --git a/ruby/.rspec b/ruby/.rspec new file mode 100644 index 00000000..3687797e --- /dev/null +++ b/ruby/.rspec @@ -0,0 +1,2 @@ +--require spec_helper +--color diff --git a/ruby/.rubocop.yml b/ruby/.rubocop.yml new file mode 100644 index 00000000..4c19d3f7 --- /dev/null +++ b/ruby/.rubocop.yml @@ -0,0 +1,21 @@ +inherit_from: .rubocop_todo.yml + +plugins: + - rubocop-performance + - rubocop-rspec + +inherit_mode: + merge: + - Exclude + +AllCops: + TargetRubyVersion: 3.2 + NewCops: enable + +# Stylistic preference for cucumber +Gemspec/DevelopmentDependencies: + Enabled: false + +# Disabled on our repo's to enable polyglot-release +Gemspec/RequireMFA: + Enabled: false diff --git a/ruby/.rubocop_todo.yml b/ruby/.rubocop_todo.yml new file mode 100644 index 00000000..4f132b72 --- /dev/null +++ b/ruby/.rubocop_todo.yml @@ -0,0 +1,128 @@ +# This configuration was generated by +# `rubocop --auto-gen-config` +# on 2025-09-05 19:34:38 UTC using RuboCop version 1.80.2. +# The point is for the user to remove these configuration records +# one by one as the offenses are removed from the code base. +# Note that changes in the inspected code, or installation of new +# versions of RuboCop, may require this file to be generated again. + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: EnforcedStyle. +# SupportedStyles: empty_lines, empty_lines_except_namespace, empty_lines_special, no_empty_lines +Layout/EmptyLinesAroundModuleBody: + Exclude: + - 'spec/support/runner_helper.rb' + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: AllowInHeredoc. +Layout/TrailingWhitespace: + Exclude: + - 'spec/cucumber/query/legacy/step_definitions_by_test_step_spec.rb' + +# Offense count: 8 +# Configuration parameters: AllowComments, AllowEmptyLambdas. +Lint/EmptyBlock: + Exclude: + - 'spec/cucumber/query/legacy/hook_by_test_step_spec.rb' + - 'spec/cucumber/query/legacy/step_definitions_by_test_step_spec.rb' + +# Offense count: 8 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods, IgnoreNotImplementedMethods, NotImplementedExceptions. +# NotImplementedExceptions: NotImplementedError +Lint/UnusedMethodArgument: + Exclude: + - 'lib/cucumber/query/query.rb' + +# Offense count: 4 +# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes. +Metrics/AbcSize: + Max: 43 + +# Offense count: 1 +# Configuration parameters: AllowedMethods, AllowedPatterns. +Metrics/CyclomaticComplexity: + Max: 14 + +# Offense count: 3 +# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns. +Metrics/MethodLength: + Max: 24 + +# Offense count: 1 +# Configuration parameters: AllowedMethods, AllowedPatterns. +Metrics/PerceivedComplexity: + Max: 14 + +# Offense count: 8 +Performance/MethodObjectAsBlock: + Exclude: + - 'lib/cucumber/query/legacy/hook_by_test_step.rb' + - 'lib/cucumber/query/legacy/pickle_by_test.rb' + - 'lib/cucumber/query/legacy/pickle_step_by_test_step.rb' + - 'lib/cucumber/query/legacy/step_definitions_by_test_step.rb' + - 'lib/cucumber/query/legacy/test_case_started_by_test_case.rb' + +# Offense count: 1 +# Configuration parameters: Prefixes, AllowedPatterns. +# Prefixes: when, with, without +RSpec/ContextWording: + Exclude: + - 'spec/cucumber/query/legacy/hook_by_test_step_spec.rb' + +# Offense count: 1 +# Configuration parameters: CountAsOne. +RSpec/ExampleLength: + Max: 7 + +# Offense count: 32 +# Configuration parameters: AssignmentOnly. +RSpec/InstanceVariable: + Exclude: + - 'spec/cucumber/query/legacy/hook_by_test_step_spec.rb' + - 'spec/cucumber/query/legacy/pickle_by_test_spec.rb' + - 'spec/cucumber/query/legacy/pickle_step_by_test_step_spec.rb' + - 'spec/cucumber/query/legacy/step_definitions_by_test_step_spec.rb' + - 'spec/cucumber/query/legacy/test_case_started_by_test_case_spec.rb' + +# Offense count: 3 +RSpec/MultipleExpectations: + Max: 3 + +# Offense count: 12 +# Configuration parameters: AllowedGroups. +RSpec/NestedGroups: + Max: 5 + +# Offense count: 8 +# Configuration parameters: AllowedConstants. +Style/Documentation: + Exclude: + - 'lib/cucumber/query/helpers.rb' + - 'lib/cucumber/query/legacy/hook_by_test_step.rb' + - 'lib/cucumber/query/legacy/pickle_by_test.rb' + - 'lib/cucumber/query/legacy/pickle_step_by_test_step.rb' + - 'lib/cucumber/query/legacy/step_definitions_by_test_step.rb' + - 'lib/cucumber/query/legacy/test_case_started_by_test_case.rb' + - 'lib/cucumber/query/legacy/test_run_started.rb' + - 'lib/cucumber/query/query.rb' + +# Offense count: 4 +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: EnforcedStyle. +# SupportedStyles: always, always_true, never +Style/FrozenStringLiteralComment: + Exclude: + - 'lib/cucumber/query/helpers.rb' + - 'lib/cucumber/query/query.rb' + - 'spec/support/gherkin_helper.rb' + - 'spec/support/runner_helper.rb' + +# Offense count: 8 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, IgnoreCopDirectives, AllowedPatterns, SplitStrings. +# URISchemes: http, https +Layout/LineLength: + Max: 198 diff --git a/ruby/Gemfile b/ruby/Gemfile new file mode 100644 index 00000000..7f4f5e95 --- /dev/null +++ b/ruby/Gemfile @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +source 'https://rubygems.org' + +gemspec diff --git a/ruby/Gemfile.lock b/ruby/Gemfile.lock new file mode 100644 index 00000000..a65432fe --- /dev/null +++ b/ruby/Gemfile.lock @@ -0,0 +1,112 @@ +PATH + remote: . + specs: + cucumber-query (21.0.0) + cucumber-messages (> 25, < 30) + +GEM + remote: https://rubygems.org/ + specs: + ast (2.4.2) + base64 (0.3.0) + bigdecimal (3.2.3) + builder (3.3.0) + cucumber (10.1.0) + base64 (~> 0.2) + builder (~> 3.2) + cucumber-ci-environment (> 9, < 11) + cucumber-core (> 15, < 17) + cucumber-cucumber-expressions (> 17, < 19) + cucumber-html-formatter (> 20.3, < 22) + diff-lcs (~> 1.5) + logger (~> 1.6) + mini_mime (~> 1.1) + multi_test (~> 1.1) + sys-uname (~> 1.3) + cucumber-ci-environment (10.0.1) + cucumber-core (15.2.1) + cucumber-gherkin (> 27, < 33) + cucumber-messages (> 26, < 30) + cucumber-tag-expressions (> 5, < 7) + cucumber-cucumber-expressions (18.0.1) + bigdecimal + cucumber-gherkin (32.2.0) + cucumber-messages (> 25, < 28) + cucumber-html-formatter (21.14.0) + cucumber-messages (> 19, < 28) + cucumber-messages (27.2.0) + cucumber-tag-expressions (6.1.2) + diff-lcs (1.5.1) + ffi (1.17.2) + ffi (1.17.2-x86_64-linux-gnu) + json (2.9.1) + language_server-protocol (3.17.0.4) + lint_roller (1.1.0) + logger (1.7.0) + memoist3 (1.0.0) + mini_mime (1.1.5) + multi_test (1.1.0) + parallel (1.26.3) + parser (3.3.9.0) + ast (~> 2.4.1) + racc + prism (1.4.0) + racc (1.8.1) + rainbow (3.1.1) + regexp_parser (2.10.0) + rspec (3.13.0) + rspec-core (~> 3.13.0) + rspec-expectations (~> 3.13.0) + rspec-mocks (~> 3.13.0) + rspec-core (3.13.2) + rspec-support (~> 3.13.0) + rspec-expectations (3.13.3) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.13.0) + rspec-mocks (3.13.2) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.13.0) + rspec-support (3.13.2) + rubocop (1.80.2) + json (~> 2.3) + language_server-protocol (~> 3.17.0.2) + lint_roller (~> 1.1.0) + parallel (~> 1.10) + parser (>= 3.3.0.2) + rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 2.9.3, < 3.0) + rubocop-ast (>= 1.46.0, < 2.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 2.4.0, < 4.0) + rubocop-ast (1.46.0) + parser (>= 3.3.7.2) + prism (~> 1.4) + rubocop-performance (1.25.0) + lint_roller (~> 1.1) + rubocop (>= 1.75.0, < 2.0) + rubocop-ast (>= 1.38.0, < 2.0) + rubocop-rspec (3.7.0) + lint_roller (~> 1.1) + rubocop (~> 1.72, >= 1.72.1) + ruby-progressbar (1.13.0) + sys-uname (1.4.1) + ffi (~> 1.1) + memoist3 (~> 1.0.0) + unicode-display_width (3.1.4) + unicode-emoji (~> 4.0, >= 4.0.4) + unicode-emoji (4.0.4) + +PLATFORMS + ruby + x86_64-linux + +DEPENDENCIES + cucumber (~> 10.1) + cucumber-query! + rspec (~> 3.13) + rubocop (~> 1.80.0) + rubocop-performance (~> 1.25.0) + rubocop-rspec (~> 3.7.0) + +BUNDLED WITH + 2.6.2 diff --git a/ruby/LICENSE b/ruby/LICENSE new file mode 100644 index 00000000..d23a133d --- /dev/null +++ b/ruby/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Cucumber Ltd and contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/ruby/VERSION b/ruby/VERSION new file mode 100644 index 00000000..fb5b5130 --- /dev/null +++ b/ruby/VERSION @@ -0,0 +1 @@ +21.0.0 diff --git a/ruby/cucumber-query.gemspec b/ruby/cucumber-query.gemspec new file mode 100644 index 00000000..e58f47e2 --- /dev/null +++ b/ruby/cucumber-query.gemspec @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +Gem::Specification.new do |s| + s.name = 'cucumber-query' + s.version = File.read(File.expand_path('VERSION', __dir__)).strip + s.authors = ['Luke Hill'] + s.description = 'Cucumber Query - query messages' + s.summary = "#{s.name}-#{s.version}" + s.email = 'cukebot@cucumber.io' + s.homepage = 'https://github.com/cucumber/query' + s.platform = Gem::Platform::RUBY + s.license = 'MIT' + s.required_ruby_version = '>= 3.2' + s.required_rubygems_version = '>= 3.2.8' + + s.metadata = { + 'bug_tracker_uri' => 'https://github.com/cucumber/query/issues', + 'changelog_uri' => 'https://github.com/cucumber/query/blob/main/CHANGELOG.md', + 'documentation_uri' => 'https://github.com/cucumber/query/blob/main/README.md', + 'mailing_list_uri' => 'https://groups.google.com/forum/#!forum/cukes', + 'source_code_uri' => 'https://github.com/cucumber/query/blob/main/ruby' + } + + s.add_dependency 'cucumber-messages', '> 25', '< 30' + + s.add_development_dependency 'rspec', '~> 3.13' + s.add_development_dependency 'rubocop', '~> 1.80.0' + s.add_development_dependency 'rubocop-performance', '~> 1.25.0' + s.add_development_dependency 'rubocop-rspec', '~> 3.7.0' + + s.files = Dir['LICENSE', 'lib/**/*'] + s.rdoc_options = ['--charset=UTF-8'] + s.require_path = 'lib' +end diff --git a/ruby/lib/cucumber/error.rb b/ruby/lib/cucumber/error.rb new file mode 100644 index 00000000..c8343cad --- /dev/null +++ b/ruby/lib/cucumber/error.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +module Cucumber + module Error + TestCaseUnknownError = Class.new(StandardError) + TestStepUnknownError = Class.new(StandardError) + end +end diff --git a/ruby/lib/cucumber/query.rb b/ruby/lib/cucumber/query.rb new file mode 100644 index 00000000..0e7530b8 --- /dev/null +++ b/ruby/lib/cucumber/query.rb @@ -0,0 +1,80 @@ +require_relative '../ry_helpers' + +module Cucumber + class Query + def initialize + @test_step_result_by_pickle_id = [{}] + @test_step_results_by_pickle_step_id = [[]] + @test_case_by_pickle_id = [] + @pickle_id_by_test_step_id = [] + @pickle_step_id_by_test_step_id = [] + @test_step_results_by_test_step_id = [[]] + @test_step_ids_by_pickle_step_id = [{}] + @hooks_by_id = {} + @attachments_by_test_step_id = [] + @step_match_arguments_lists_by_pickle_step_id = [{}] + @meta = :not_sure_on_this + @test_run_started = :not_sure_on_this + @test_run_finished = :not_sure_on_this + @test_case_started_by_id = [] + @lineage_by_id = [] + @step_by_id = [] + @pickle_by_id = [] + @pickle_step_by_id = [] + @step_definition_by_id = {} + @test_case_by_id = [] + @test_case_finished_by_test_case_started_id = [[]] + @test_step_started_by_test_case_started_id = [[]] + @test_step_finished_by_test_case_started_id = [[]] + @attachments_by_test_case_started_id = [[]] + end + + def update(envelope) + @meta = envelope.meta if envelope.meta + update_gherkin_document(envelope.gherkin_document) if envelope.gherkin_document + update_pickle(envelope.pickle) if envelope.gherkin_document + @hooks_by_id[envelope.hook.id] = envelope.hook if envelope.hook + @step_definition_by_id[envelope.step_definition.id] = envelope.step_definition if envelope.step_definition + @test_run_started = envelope.test_run_started if envelope.test_run_started + update_test_case(envelope.test_case) if envelope.test_case + update_test_case_started(envelope.test_case_started) if envelope.test_case_started + update_test_step_started(envelope.test_step_started) if envelope.test_step_started + update_attachment(envelope.attachment) if envelope.attachment + update_test_step_finished(envelope.test_step_finished) if envelope.test_step_finished + update_test_case_finished(envelope.test_case_finished) if envelope.test_case_finished + @test_run_finished = envelope.test_run_finished if envelope.test_run_finished + end + + def update_gherkin_document(gherkin_document) + :not_yet_implemented + end + + def update_pickle(pickle) + :not_yet_implemented + end + + def update_test_case(test_case) + :not_yet_implemented + end + + def update_test_case_started(test_case_started) + :not_yet_implemented + end + + def update_test_step_started(test_step_started) + :not_yet_implemented + end + + def update_attachment(attachment) + :not_yet_implemented + end + + def update_test_step_finished(test_step_finished) + :not_yet_implemented + end + + def update_test_case_finished(test_case_finished) + :not_yet_implemented + end + end +end diff --git a/ruby/lib/cucumber/query_helpers.rb b/ruby/lib/cucumber/query_helpers.rb new file mode 100644 index 00000000..296fb4a7 --- /dev/null +++ b/ruby/lib/cucumber/query_helpers.rb @@ -0,0 +1,23 @@ +require 'cucumber/messages/test_step_result_status' + +module Cucumber + module Query + module QueryHelpers + def status_ordinal(status) + [ + TestStepResultStatus::UNKNOWN, + TestStepResultStatus::PASSED, + TestStepResultStatus::SKIPPED, + TestStepResultStatus::PENDING, + TestStepResultStatus::UNDEFINED, + TestStepResultStatus::AMBIGUOUS, + TestStepResultStatus::FAILED + ].index(status) + end + + def assert(target, failure_message) + raise StandardError, failure_message unless target + end + end + end +end diff --git a/ruby/spec/spec_helper.rb b/ruby/spec/spec_helper.rb new file mode 100644 index 00000000..d0b601fc --- /dev/null +++ b/ruby/spec/spec_helper.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +RSpec.configure do |c| + :no_op +end diff --git a/testdata/README.md b/testdata/README.md index ed981627..b2136edc 100644 --- a/testdata/README.md +++ b/testdata/README.md @@ -4,7 +4,7 @@ Query uses the examples from the [cucumber compatibility kit](https://github.com for acceptance testing. These examples consist of `.ndjson` files created by the [`fake-cucumber` reference implementation](https://github.com/cucumber/fake-cucumber). -* The `.njdon` files are copied in by running `npm install`. +* The `.ndjson` files are copied in by running `npm install`. * The expected `.xml` files are created by running the `QueryTest#updateExpectedXmlReportFiles` test.