diff --git a/lib/cucumber/core/compiler.rb b/lib/cucumber/core/compiler.rb index fb5fc8ca..1822ba25 100644 --- a/lib/cucumber/core/compiler.rb +++ b/lib/cucumber/core/compiler.rb @@ -18,8 +18,8 @@ def initialize(receiver) @receiver = receiver end - def pickle(pickle) - test_case = create_test_case(pickle) + def pickle(pickle, location_query) + test_case = create_test_case(pickle, location_query) test_case.describe_to(receiver) end @@ -30,35 +30,50 @@ def done private - def create_test_case(pickle) + def create_test_case(pickle, location_query) uri = pickle.uri - test_steps = pickle.steps.map { |step| create_test_step(step, uri) } - lines = pickle.locations.map { |location| location.line }.sort.reverse - tags = pickle.tags.map { |tag| Test::Tag.new(Test::Location.new(uri, tag.location.line), tag.name) } + test_steps = pickle.steps.map { |step| create_test_step(step, uri, location_query) } + + lines = location_query.pickle_locations(pickle).map do |location| + location.line + end.sort.reverse + + tags = pickle.tags.map do |tag| + Test::Tag.new( + Test::Location.new(uri, location_query.pickle_tag_location(tag).line), + tag.name + ) + end + Test::Case.new(pickle.name, test_steps, Test::Location.new(uri, lines), tags, pickle.language) end - def create_test_step(pickle_step, uri) - lines = pickle_step.locations.map { |location| location.line }.sort.reverse - multiline_arg = create_multiline_arg(pickle_step, uri) + def create_test_step(pickle_step, uri, location_query) + lines = location_query.pickle_step_locations(pickle_step).map do |location| + location.line + end.sort.reverse + + multiline_arg = create_multiline_arg(pickle_step, uri, location_query) Test::Step.new(pickle_step.text, Test::Location.new(uri, lines), multiline_arg) end - def create_multiline_arg(pickle_step, uri) + def create_multiline_arg(pickle_step, uri, location_query) + argumentLocation = location_query.pickle_step_argument_location(pickle_step) + line = argumentLocation ? argumentLocation.line : 0 + if pickle_step.argument if pickle_step.argument.doc_string doc_string = pickle_step.argument.doc_string Test::DocString.new( doc_string.content, doc_string.contentType, - Test::Location.new(uri, doc_string.location.line) + Test::Location.new(uri, line) ) elsif pickle_step.argument.data_table data_table = pickle_step.argument.data_table - first_cell = data_table.rows.first.cells.first Test::DataTable.new( data_table.rows.map { |row| row.cells.map { |cell| cell.value } }, - Test::Location.new(uri, first_cell.location.line) + Test::Location.new(uri, line) ) end else diff --git a/lib/cucumber/core/gherkin/location_query.rb b/lib/cucumber/core/gherkin/location_query.rb index 2cd613f2..712ca94d 100644 --- a/lib/cucumber/core/gherkin/location_query.rb +++ b/lib/cucumber/core/gherkin/location_query.rb @@ -19,23 +19,29 @@ def pickles end def pickle_locations(pickle) - scenario = scenario_by_id[pickle.sourceIds[0]] - table_row = table_row_by_id[pickle.sourceIds[1]] - locations = [] - - locations << scenario.location if scenario - locations << table_row.location if table_row - locations + [ + scenario_by_id[pickle.sourceIds[0]], + table_row_by_id[pickle.sourceIds[1]] + ].compact.map(&:location) end def pickle_step_locations(pickle_step) - scenario_step = scenario_step_by_id[pickle_step.sourceIds[0]] - table_row = table_row_by_id[pickle_step.sourceIds[1]] - locations = [] + [ + scenario_step_by_id[pickle_step.sourceIds[0]], + table_row_by_id[pickle_step.sourceIds[1]] + ].compact.map(&:location) + end - locations << scenario_step.location if scenario_step - locations << table_row.location if table_row - locations + def pickle_step_argument_location(pickle_step) + scenario_step = scenario_step_by_id[pickle_step.sourceIds[0]] + if scenario_step + case scenario_step.argument + when :doc_string + return scenario_step.doc_string.location + when :data_table + return scenario_step.data_table.location + end + end end def pickle_tag_location(pickle_tag) @@ -54,7 +60,7 @@ def process_gherkin_document(document) def process_children(children) children.each do |children| process_scenario(children.scenario) if children.scenario - process_children(children.rule.children) if children.rule + process_children(children.rule.children) if children.respond_to?(:rule) && children.rule end end diff --git a/lib/cucumber/core/gherkin/parser.rb b/lib/cucumber/core/gherkin/parser.rb index 2a5f0b91..de36b243 100644 --- a/lib/cucumber/core/gherkin/parser.rb +++ b/lib/cucumber/core/gherkin/parser.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true require 'gherkin' +require 'cucumber/core/gherkin/location_query' module Cucumber module Core @@ -13,15 +14,17 @@ class Parser def initialize(receiver, event_bus) @receiver = receiver @event_bus = event_bus + @location_query = LocationQuery.new end def document(document) messages = ::Gherkin.from_source(document.uri, document.body, gherkin_options(document)) messages.each do |message| + @location_query.process(message) if !message.gherkinDocument.nil? event_bus.gherkin_source_parsed(message.gherkinDocument) elsif !message.pickle.nil? - receiver.pickle(message.pickle) + receiver.pickle(message.pickle, @location_query) elsif !message.attachment.nil? # Parse error raise Core::Gherkin::ParseError.new("#{document.uri}: #{message.attachment.data}") diff --git a/spec/cucumber/core/gherkin/location_query_spec.rb b/spec/cucumber/core/gherkin/location_query_spec.rb index 001d1af1..cbdb5120 100644 --- a/spec/cucumber/core/gherkin/location_query_spec.rb +++ b/spec/cucumber/core/gherkin/location_query_spec.rb @@ -98,6 +98,51 @@ module Gherkin end end + describe 'pickle_step_argument_location' do + let(:pickle_step) { pickle.steps.first } + + context 'when there is a docstring argument' do + let(:content) { + <<-FEATURE + Feature: my simple feature + + Scenario: A scenario + Given a passed step + """ + This is my DocString + """ + FEATURE + } + + it 'returns the location of the doc string' do + expect(subject.pickle_step_argument_location(pickle_step).line).to eq(5) + end + end + + context 'when there is a datatable argument' do + let(:content) { + <<-FEATURE + Feature: my simple feature + + Scenario: A scenario + Given a passed step + | name | value | + | plic | ploc | + FEATURE + } + + it 'returns the location of the datatable' do + expect(subject.pickle_step_argument_location(pickle_step).line).to eq(5) + end + end + + context 'when there is no argument' do + it 'returns nil' do + expect(subject.pickle_step_argument_location(pickle_step)).to be_nil + end + end + end + describe 'pickle_tag_location' do let(:content) { <<-FEATURE diff --git a/spec/cucumber/core/gherkin/parser_spec.rb b/spec/cucumber/core/gherkin/parser_spec.rb index f5b3ae7d..46d1186c 100644 --- a/spec/cucumber/core/gherkin/parser_spec.rb +++ b/spec/cucumber/core/gherkin/parser_spec.rb @@ -69,7 +69,9 @@ def self.source(&block) end it "the pickles have the correct language" do - expect( receiver ).to receive(:pickle).with(pickle_with_language('ja')) + expect( receiver ) + .to receive(:pickle) + .with(pickle_with_language('ja'), kind_of(LocationQuery)) parse end end