-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
feature: Implement Cucumber::Query in-line with Java/JS implementations #1801
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
luke-hill
wants to merge
57
commits into
main
Choose a base branch
from
feature/new_query
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 36 commits
Commits
Show all changes
57 commits
Select commit
Hold shift + click to select a range
c69b584
Add blank query object and remove all junit formatter implementations
luke-hill 72b0f16
Comment out the rerun formatter instead
luke-hill 23f7452
C+P for existing query
luke-hill 4616d2e
WIP - create a simultaneous new run formatter to try get the new enve…
luke-hill 875d40d
Remove trace
luke-hill 3157de5
Alphabeticise the iVars in query
luke-hill 958abdb
Note to self on first two items that are required
luke-hill ba1a767
Store test case started by id in query
luke-hill c6b0f4e
Add in implementation for next query method
luke-hill fdd9c45
Comment WIP about getting the iVar from query
luke-hill 1a3700b
Add third implementor and add notes for implemented ones
luke-hill 5b3abf4
Early terminate in #update as only one call is ever valid
luke-hill f4a53da
Add readerss
luke-hill 2615ff7
WIP - more guesswork
luke-hill 10466da
WIP: Implement new repository / query interface
luke-hill 7daf0f2
Staging point. We now have 3 complex finders and 1 simple finder inte…
luke-hill 19ccbff
Reached a checkpoint where we have 2 tests (running for minimal and e…
luke-hill 2c02397
Extend query to run against 4 sample ndjson files with expected answers
luke-hill 6456f44
More tidy and added a 5th example for findAllPickles
luke-hill ec538b8
Implement two more sub-update methods for generic update for hooks;
luke-hill 7e79823
Complete initial iteration for update in repository
luke-hill a3c7254
Tidy up to use ruby writers;
luke-hill 583d342
Have ChatGPT write a much more optimal iterator
luke-hill 832a76b
Use the new test iterator
luke-hill de47515
Final tidy for specs;
luke-hill c66f47b
Update remaining items for the TODO markers for the enumerable items …
luke-hill 1659c70
Mark the 2*TODO items as ready for sign-off
luke-hill 5e2323b
Re-order #update according to Java impl
luke-hill c8b3842
Add in TODO markers for count and findAll methods
luke-hill 30f817f
1 all method complete
luke-hill 64d20a6
Complete 3 more findAll methods ported from java
luke-hill 92f629d
Add in 2 new queries to test the implementation
luke-hill a052e70
Add in assertion files for findAllTestSteps and findAllTestCases for …
luke-hill 623caf9
Fix rubocop
luke-hill 710fb26
Remove redundant line
luke-hill ddce394
Split event handlers from initializer in new implementation of rerun …
luke-hill 592d5b6
CR: Make plurality caches store by default as a hash. Which has each …
luke-hill 4365b91
Clarify all items should be good to go now
luke-hill fc2ae13
Reduce LOC and memoizations by using initializer for state
luke-hill d819b69
findAllTestStepStarted needs to reduce the multi-dimensional construc…
luke-hill 60eb849
Add in 2 new queries and then complete some re-ordering
luke-hill d0c35ae
Add in 2 findAll methods for hooks based on repository;
luke-hill fbf9c09
Add in one more find_by one more find_all and one new count_ queries.
luke-hill 7649e52
Fix up findAllTestCaseStarted
luke-hill 21b1783
Add in 2 new queries for findTestCaseBy and findPickleBy
luke-hill f4d33b6
Add in supporting files to support 2 new queries
luke-hill d59a08c
Add in the new query findAllTestCaseFinished
luke-hill 8bf7bd1
Replace outdated erroneous hooks file
luke-hill dfc11d5
Replace outdated erroneous hooks test data files
luke-hill 53279c9
Fix up completion metrics
luke-hill f3d8422
Add update gherkin document and sub updates update feature and gherki…
luke-hill fd0b888
Fix alphabeticising by placing started before finished before each pa…
luke-hill 47816eb
Add in upate_steps which requires step_by_id store
luke-hill 3f4ac03
Add update_step_definition as well as step_definition_by_id hash stor…
luke-hill bcc3696
Add / copy top level doc
luke-hill 2503c3d
Classify initial state for new target - migrate majority of By finders
luke-hill c91944b
Updated current status quo 3 fully complete 1 partially complete
luke-hill File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| require 'cucumber/formatter/io' | ||
| require 'cucumber/query' | ||
| require 'cucumber/formatter/message_builder' | ||
|
|
||
| module Cucumber | ||
| module Formatter | ||
| class NewRerun | ||
| include Formatter::Io | ||
|
|
||
| def initialize(config) | ||
| @io = ensure_io(config.out_stream, config.error_stream) | ||
| @config = config | ||
| @failures = {} | ||
| config.on_event :test_case_finished, &method(:on_test_case_finished) | ||
| config.on_event :test_run_finished, &method(:on_test_run_finished) | ||
| end | ||
|
|
||
| def on_test_case_finished(event) | ||
| test_case, result = *event.attributes | ||
| if @config.strict.strict?(:flaky) | ||
| next if result.ok?(strict: @config.strict) | ||
|
|
||
| add_to_failures(test_case) | ||
| else | ||
| unless @latest_failed_test_case.nil? | ||
| if @latest_failed_test_case != test_case | ||
| add_to_failures(@latest_failed_test_case) | ||
| @latest_failed_test_case = nil | ||
| elsif result.ok?(strict: @config.strict) | ||
| @latest_failed_test_case = nil | ||
| end | ||
| end | ||
| @latest_failed_test_case = test_case unless result.ok?(strict: @config.strict) | ||
| end | ||
| end | ||
|
|
||
| def on_test_run_finished(_event) | ||
| add_to_failures(@latest_failed_test_case) unless @latest_failed_test_case.nil? | ||
| next if @failures.empty? | ||
|
|
||
| @io.print file_failures.join("\n") | ||
| end | ||
|
|
||
| private | ||
|
|
||
| def file_failures | ||
| @failures.map { |file, lines| [file, lines].join(':') } | ||
| end | ||
|
|
||
| def add_to_failures(test_case) | ||
| location = test_case.location | ||
| @failures[location.file] ||= [] | ||
| @failures[location.file] << location.lines.max unless @failures[location.file].include?(location.lines.max) | ||
| end | ||
| end | ||
| end | ||
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| require 'cucumber/repository' | ||
|
|
||
| module Cucumber | ||
| class Query | ||
| attr_reader :repository | ||
| private :repository | ||
|
|
||
| def initialize(repository) | ||
| @repository = repository | ||
| end | ||
|
|
||
| # TODO: count methods (0/2) Complete | ||
| # Missing: countMostSevereTestStepResultStatus / countTestCasesStarted | ||
| # Completed: N/A | ||
|
|
||
| # TODO: findAll methods (4/12) Complete | ||
| # Missing: findAllPickleSteps / findAllTestCaseStarted / findAllStepDefinitions / findAllTestCaseFinished | ||
| # Missing: findAllTestStepFinished / findAllTestRunHookStarted / findAllTestRunHookFinished | ||
| # Missing: findAllUndefinedParameterTypes | ||
| # Completed: findAllPickles / findAllTestCases / findAllTestSteps / findAllTestStepStarted | ||
|
|
||
| def find_all_pickles | ||
| repository.pickle_by_id.values | ||
| end | ||
|
|
||
| def find_all_test_cases | ||
| repository.test_case_by_id.values | ||
| end | ||
|
|
||
| def find_all_test_step_started | ||
| # Java impl | ||
| # repository.testStepsStartedByTestCaseStartedId.values().stream().flatMap(Collection::stream).collect(toList()); | ||
| repository.test_steps_started_by_test_case_started_id.values | ||
| end | ||
|
|
||
| def find_all_test_steps | ||
| repository.test_step_by_id.values | ||
| end | ||
|
|
||
| # This method will be called with 1 of these 3 messages | ||
| # TestCaseStarted | TestCaseFinished | TestStepStarted | ||
| def find_pickle_by(element) | ||
| test_case = find_test_case_by(element) | ||
| raise 'Expected to find TestCase from TestCaseStarted' unless test_case | ||
|
|
||
| repository.pickle_by_id[test_case.pickle_id] | ||
| end | ||
|
|
||
| # This method will be called with 1 of these 4 messages | ||
| # TestCaseStarted | TestCaseFinished | TestStepStarted | TestStepFinished | ||
| def find_test_case_by(element) | ||
| test_case_started = element.respond_to?(:test_case_started_id) ? find_test_case_started_by(element) : element | ||
| raise 'Expected to find TestCaseStarted by TestStepStarted' unless test_case_started | ||
|
|
||
| repository.test_case_by_id[test_case_started.test_case_id] | ||
| end | ||
|
|
||
| # This method will be called with 1 of these 3 messages | ||
| # TestCaseFinished | TestStepStarted | TestStepFinished | ||
| def find_test_case_started_by(element) | ||
| repository.test_case_started_by_id[element.test_case_started_id] | ||
| end | ||
| end | ||
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,110 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| module Cucumber | ||
| # In memory repository i.e. a thread based link to cucumber-query | ||
| class Repository | ||
| attr_accessor :meta, :test_run_started, :test_run_finished | ||
|
|
||
| def update(envelope) | ||
| return self.meta = envelope.meta if envelope.meta | ||
| return self.test_run_started = envelope.test_run_started if envelope.test_run_started | ||
| return self.test_run_finished = envelope.test_run_finished if envelope.test_run_finished | ||
|
|
||
| # TODO: These items are completed AS IS. Should be good to sign off | ||
| return update_test_run_hook_started(envelope.test_run_hook_started) if envelope.test_run_hook_started | ||
| return update_test_run_hook_finished(envelope.test_run_hook_finished) if envelope.test_run_hook_finished | ||
| return update_test_case_started(envelope.test_case_started) if envelope.test_case_started | ||
| return update_test_case_finished(envelope.test_case_finished) if envelope.test_case_finished | ||
|
|
||
| # TODO: Check these two items in terms of LinkedHashMap in Java | ||
| return update_test_step_started(envelope.test_step_started) if envelope.test_step_started | ||
| return update_test_step_finished(envelope.test_step_finished) if envelope.test_step_finished | ||
|
|
||
| # TODO: These items are completed AS IS. Should be good to sign off | ||
| return update_pickle(envelope.pickle) if envelope.pickle | ||
| return update_test_case(envelope.test_case) if envelope.test_case | ||
|
|
||
| nil | ||
| end | ||
|
|
||
| def pickle_by_id | ||
| @pickle_by_id ||= {} | ||
| end | ||
|
|
||
| def pickle_step_by_id | ||
| @pickle_step_by_id ||= {} | ||
| end | ||
|
|
||
| def test_case_by_id | ||
| @test_case_by_id ||= {} | ||
| end | ||
|
|
||
| def test_case_finished_by_test_case_started_id | ||
| @test_case_finished_by_test_case_started_id ||= {} | ||
| end | ||
|
|
||
| def test_case_started_by_id | ||
| @test_case_started_by_id ||= {} | ||
| end | ||
|
|
||
| def test_run_hook_started_by_id | ||
| @test_run_hook_started_by_id ||= {} | ||
| end | ||
|
|
||
| def test_run_hook_finished_by_test_run_hook_started_id | ||
| @test_run_hook_finished_by_test_run_hook_started_id ||= {} | ||
| end | ||
|
|
||
| def test_step_by_id | ||
| @test_step_by_id ||= {} | ||
| end | ||
|
|
||
| def test_steps_finished_by_test_case_started_id | ||
| @test_steps_finished_by_test_case_started_id ||= {} | ||
| end | ||
|
|
||
| def test_steps_started_by_test_case_started_id | ||
| @test_steps_started_by_test_case_started_id ||= {} | ||
| end | ||
|
|
||
| private | ||
|
|
||
| def update_pickle(pickle) | ||
| pickle_by_id[pickle.id] = pickle | ||
| pickle.steps.each { |pickle_step| pickle_step_by_id[pickle_step.id] = pickle_step } | ||
| end | ||
|
|
||
| def update_test_case(test_case) | ||
| test_case_by_id[test_case.id] = test_case | ||
| test_case.test_steps.each { |test_step| test_step_by_id[test_step.id] = test_step } | ||
| end | ||
|
|
||
| def update_test_case_finished(test_case_finished) | ||
| test_case_finished_by_test_case_started_id[test_case_finished.test_case_started_id] = test_case_finished | ||
| end | ||
|
|
||
| def update_test_case_started(test_case_started) | ||
| test_case_started_by_id[test_case_started.id] = test_case_started | ||
| end | ||
|
|
||
| def update_test_run_hook_finished(test_run_hook_finished) | ||
| test_run_hook_finished_by_test_run_hook_started_id[test_run_hook_finished.test_run_hook_started_id] = test_run_hook_finished | ||
| end | ||
|
|
||
| def update_test_run_hook_started(test_run_hook_started) | ||
| test_run_hook_started_by_id[test_run_hook_started.id] = test_run_hook_started | ||
| end | ||
|
|
||
| def update_test_step_finished(test_step_finished) | ||
| # Java impl: | ||
| # this.testStepsFinishedByTestCaseStartedId.compute(event.getTestCaseStartedId(), updateList(event)); | ||
| test_steps_finished_by_test_case_started_id[test_step_finished.test_case_started_id] = test_step_finished | ||
| end | ||
|
|
||
| def update_test_step_started(test_step_started) | ||
| # Java impl | ||
| # this.testStepsStartedByTestCaseStartedId.compute(event.getTestCaseStartedId(), updateList(event)); | ||
| test_steps_started_by_test_case_started_id[test_step_started.test_case_started_id] = test_step_started | ||
| end | ||
| end | ||
| end | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| def source_names | ||
| %w[attachments empty hooks minimal rules] | ||
| end | ||
|
|
||
| def sources | ||
| source_names.map { |name| "#{Dir.pwd}/spec/support/#{name}.ndjson" } | ||
| end | ||
|
|
||
| def queries | ||
| { | ||
| 'findAllPickles' => ->(query) { query.find_all_pickles.length }, | ||
| 'findAllTestCases' => ->(query) { query.find_all_test_cases.length }, | ||
| 'findAllTestSteps' => ->(query) { query.find_all_test_steps.length } | ||
| } | ||
| end | ||
|
|
||
| def list_of_tests | ||
| sources.flat_map do |source| | ||
| queries.map do |query_name, query_proc| | ||
| { cck_spec: source, query_name:, query_proc: } | ||
| end | ||
| end | ||
| end | ||
|
|
||
| require 'cucumber/query' | ||
| require 'cucumber/messages' | ||
| require_relative '../../compatibility/support/cck/helpers' | ||
|
|
||
| describe Cucumber::Query do | ||
| include CCK::Helpers | ||
|
|
||
| subject(:query) { described_class.new(repository) } | ||
|
|
||
| let(:repository) { Cucumber::Repository.new } | ||
|
|
||
| list_of_tests.each do |test| | ||
| describe "executes the query '#{test[:query_name]}' against the CCK definition '#{test[:cck_spec]}'" do | ||
| let(:cck_messages) { parse_ndjson_file(test[:cck_spec]).map.itself } | ||
| let(:filename_to_check) { test[:cck_spec].sub('.ndjson', ".#{test[:query_name]}.results.json") } | ||
|
|
||
| before { cck_messages.each { |message| repository.update(message) } } | ||
|
|
||
| it 'returns the expected query result' do | ||
| evaluated_query = test[:query_proc].call(query) | ||
| expected_query_result = JSON.parse(File.read(filename_to_check)) | ||
|
|
||
| expect(evaluated_query).to eq(expected_query_result) | ||
| end | ||
| end | ||
| end | ||
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| 7 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| 7 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| 7 |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The relationship here is a one to many relationship
test_case_started_id (1) --> (*) test_step_finished.So the data structure should look like