Skip to content

Commit

Permalink
Update to use gherkin version 6.
Browse files Browse the repository at this point in the history
The feature file oriented formatters (like the pretty formatter) does
not include the rule keyword in its output, but they will find and handle
the scenarios within the rules.
  • Loading branch information
brasmusson committed Sep 25, 2018
1 parent a948ad7 commit 9d9998b
Show file tree
Hide file tree
Showing 13 changed files with 176 additions and 94 deletions.
4 changes: 4 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,7 @@ elsif !ENV['CUCUMBER_USE_RELEASED_GEMS']
end

gem 'cucumber-expressions', path: ENV['CUCUMBER_EXPRESSIONS_RUBY'] if ENV['CUCUMBER_EXPRESSIONS_RUBY']

gem 'gherkin', path: ENV['GHERKIN_RUBY'] if ENV['GHERKIN_RUBY']

gem 'cucumber-messages', path: ENV['CUCUMBER_MESSAGES_RUBY'] if ENV['CUCUMBER_MESSAGES_RUBY']
2 changes: 1 addition & 1 deletion cucumber.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Gem::Specification.new do |s|
s.add_dependency 'cucumber-expressions', '~> 6.0.1'
s.add_dependency 'cucumber-wire', '~> 0.0.1'
s.add_dependency 'diff-lcs', '~> 1.3'
s.add_dependency 'gherkin', '~> 5.1.0'
s.add_dependency 'gherkin', '~> 6.0'
s.add_dependency 'multi_json', '>= 1.7.5', '< 2.0'
s.add_dependency 'multi_test', '>= 0.1.2'

Expand Down
2 changes: 1 addition & 1 deletion features/docs/cli/i18n.feature
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Feature: i18n
"""
| feature | "Funcionalidade", "Característica", "Caracteristica" |
| background | "Contexto", "Cenário de Fundo", "Cenario de Fundo", "Fundo" |
| scenario | "Cenário", "Cenario" |
| scenario | "Exemplo", "Cenário", "Cenario" |
| scenario_outline | "Esquema do Cenário", "Esquema do Cenario", "Delineação do Cenário", "Delineacao do Cenario" |
| examples | "Exemplos", "Cenários", "Cenarios" |
| given | "* ", "Dado ", "Dada ", "Dados ", "Dadas " |
Expand Down
4 changes: 2 additions & 2 deletions features/docs/gherkin/background.feature
Original file line number Diff line number Diff line change
Expand Up @@ -461,15 +461,15 @@ Feature: Background
Examples:
Scenario: | 10 |
Example: | 10 |
Then I should have '10' global cukes
Scenario Outline: failing background
Then I should have '<count>' global cukes
Examples:
Scenario: | 10 |
Example: | 10 |
And '10' global cukes
FAIL (RuntimeError)
./features/step_definitions/cuke_steps.rb:8:in `/^'(.+)' global cukes$/'
Expand Down
4 changes: 2 additions & 2 deletions features/docs/gherkin/expand_option_for_outlines.feature
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ Feature: Scenario outlines --expand option
Examples:
Scenario: | blue | blue | right |
Example: | blue | blue | right |
Given the secret code is blue
When I guess blue
Then I am right
Scenario: | red | blue | wrong |
Example: | red | blue | wrong |
Given the secret code is red
When I guess blue
Then I am wrong
Expand Down
5 changes: 1 addition & 4 deletions lib/cucumber/events/gherkin_source_parsed.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@
module Cucumber
module Events
# Fired after we've parsed the contents of a feature file
class GherkinSourceParsed < Core::Event.new(:uri, :gherkin_document)
# The uri of the file
attr_reader :uri

class GherkinSourceParsed < Core::Event.new(:gherkin_document)
# The Gherkin Ast
attr_reader :gherkin_document
end
Expand Down
113 changes: 80 additions & 33 deletions lib/cucumber/formatter/ast_lookup.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def initialize(config)
end

def on_gherkin_source_parsed(event)
@gherkin_documents[event.uri] = event.gherkin_document
@gherkin_documents[event.gherkin_document[:uri]] = event.gherkin_document
end

def gherkin_document(uri)
Expand All @@ -21,13 +21,13 @@ def gherkin_document(uri)

def scenario_source(test_case)
uri = test_case.location.file
@test_case_lookups[uri] ||= create_test_case_lookup(gherkin_document(uri))
@test_case_lookups[uri] ||= TestCaseLookupBuilder.new(gherkin_document(uri)).lookup_hash
@test_case_lookups[uri][test_case.location.lines.max]
end

def step_source(test_step)
uri = test_step.location.file
@test_step_lookups[uri] ||= create_test_step_lookup(gherkin_document(uri))
@test_step_lookups[uri] ||= TestStepLookupBuilder.new(gherkin_document(uri)).lookup_hash
@test_step_lookups[uri][test_step.location.lines.min]
end

Expand Down Expand Up @@ -61,52 +61,99 @@ def snippet_step_keyword(test_step)
private

def step_keyword_lookup(uri)
@step_keyword_lookups[uri] ||= create_keyword_lookup(gherkin_document(uri))
@step_keyword_lookups[uri] ||= KeywordLookupBuilder.new(gherkin_document(uri)).lookup_hash
end

def create_test_case_lookup(gherkin_document)
feature = gherkin_document[:feature]
lookup_hash = {}
feature[:children].each do |child|
if child[:type] == :Scenario
lookup_hash[child[:location][:line]] = ScenarioSource.new(:Scenario, child)
elsif child[:type] == :ScenarioOutline
child[:examples].each do |examples|
examples[:tableBody].each do |row|
lookup_hash[row[:location][:line]] = ScenarioOutlineSource.new(:ScenarioOutline, child, examples, row)
class TestCaseLookupBuilder
attr_reader :lookup_hash

def initialize(gherkin_document)
@lookup_hash = {}
process_scenario_container(gherkin_document[:feature])
end

private

def process_scenario_container(container)
container[:children].each do |child|
if !child[:rule].nil?
process_scenario_container(child[:rule])
elsif !child[:scenario].nil?
if child[:scenario][:examples].empty?
@lookup_hash[child[:scenario][:location][:line]] = ScenarioSource.new(:Scenario, child[:scenario])

else
child[:scenario][:examples].each do |examples|
examples[:table_body].each do |row|
@lookup_hash[row[:location][:line]] = ScenarioOutlineSource.new(:ScenarioOutline, child[:scenario], examples, row)
end
end
end
end
end
end
lookup_hash
end

def create_test_step_lookup(gherkin_document)
feature = gherkin_document[:feature]
lookup_hash = {}
feature[:children].each do |child|
child[:steps].each do |step|
lookup_hash[step[:location][:line]] = StepSource.new(:Step, step)
class TestStepLookupBuilder
attr_reader :lookup_hash

def initialize(gherkin_document)
@lookup_hash = {}
process_scenario_container(gherkin_document[:feature])
end

private

def process_scenario_container(container)
container[:children].each do |child|
if !child[:rule].nil?
process_scenario_container(child[:rule])
elsif !child[:scenario].nil?
child[:scenario][:steps].each do |step|
@lookup_hash[step[:location][:line]] = StepSource.new(:Step, step)
end
elsif !child[:background].nil?
child[:background][:steps].each do |step|
@lookup_hash[step[:location][:line]] = StepSource.new(:Step, step)
end
end
end
end
lookup_hash
end

KeywordSearchNode = Struct.new(:keyword, :previous_node)

def create_keyword_lookup(gherkin_document)
lookup = {}
original_previous_node = nil
gherkin_document[:feature][:children].each do |child|
previous_node = original_previous_node
child[:steps].each do |step|
node = KeywordSearchNode.new(step[:keyword], previous_node)
lookup[step[:location][:line]] = node
previous_node = node
class KeywordLookupBuilder
attr_reader :lookup_hash

def initialize(gherkin_document)
@lookup_hash = {}
process_scenario_container(gherkin_document[:feature], nil)
end

private

def process_scenario_container(container, original_previous_node)
container[:children].each do |child|
previous_node = original_previous_node
if !child[:rule].nil?
process_scenario_container(child[:rule], original_previous_node)
elsif !child[:scenario].nil?
child[:scenario][:steps].each do |step|
node = KeywordSearchNode.new(step[:keyword], previous_node)
@lookup_hash[step[:location][:line]] = node
previous_node = node
end
elsif !child[:background].nil?
child[:background][:steps].each do |step|
node = KeywordSearchNode.new(step[:keyword], previous_node)
@lookup_hash[step[:location][:line]] = node
previous_node = node
original_previous_node = previous_node
end
end
end
original_previous_node = previous_node if child[:type] == :Background
end
lookup
end
end
end
Expand Down
10 changes: 4 additions & 6 deletions lib/cucumber/formatter/json.rb
Original file line number Diff line number Diff line change
Expand Up @@ -167,10 +167,8 @@ def create_step_hash(test_step)
name: test_step.text,
line: test_step.location.lines.min
}
unless step_source[:argument].nil?
step_hash[:doc_string] = create_doc_string_hash(step_source[:argument]) if step_source[:argument][:type] == :DocString
step_hash[:rows] = create_data_table_value(step_source[:argument]) if step_source[:argument][:type] == :DataTable
end
step_hash[:doc_string] = create_doc_string_hash(step_source[:doc_string]) unless step_source[:doc_string].nil?
step_hash[:rows] = create_data_table_value(step_source[:data_table]) unless step_source[:data_table].nil?
step_hash
end

Expand Down Expand Up @@ -234,7 +232,7 @@ def initialize(test_case, ast_lookup)
uri = test_case.location.file
feature = ast_lookup.gherkin_document(uri)[:feature]
feature(feature, uri)
background(feature[:children].first) if feature[:children].first[:type] == :Background
background(feature[:children].first[:background]) unless feature[:children].first[:background].nil?
scenario(ast_lookup.scenario_source(test_case), test_case)
end

Expand Down Expand Up @@ -300,7 +298,7 @@ def create_id_from_scenario_source(scenario_source)
end

def calculate_row_number(scenario_source)
scenario_source.examples[:tableBody].each_with_index do |row, index|
scenario_source.examples[:table_body].each_with_index do |row, index|
return index + 2 if row == scenario_source.row
end
end
Expand Down
24 changes: 11 additions & 13 deletions lib/cucumber/formatter/pretty.rb
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ def same_feature_as_previous_test_case?(location)
def feature_has_background?
feature_children = gherkin_document[:feature][:children]
return false if feature_children.empty?
feature_children[0][:type] == :Background
!feature_children.first[:background].nil?
end

def print_step_header(test_case)
Expand Down Expand Up @@ -296,7 +296,7 @@ def print_description(description)

def print_background_data
@io.puts
background = gherkin_document[:feature][:children][0]
background = gherkin_document[:feature][:children].first[:background]
@source_indent = calculate_source_indent_for_ast_node(background) if options[:source]
print_comments(background[:location][:line], 2)
print_background_line(background)
Expand Down Expand Up @@ -355,12 +355,10 @@ def gherkin_document

def print_multiline_argument(test_step, result, indent)
step = step_source(test_step).step
multiline_arg = step[:argument]
return unless multiline_arg
if multiline_arg[:type] == :DocString
print_doc_string(multiline_arg[:content], result.to_sym, indent)
elsif multiline_arg[:type] == :DataTable
print_data_table(step[:argument], result.to_sym, indent)
if !step[:doc_string].nil?
print_doc_string(step[:doc_string][:content], result.to_sym, indent)
elsif !step[:data_table].nil?
print_data_table(step[:data_table], result.to_sym, indent)
end
end

Expand All @@ -371,7 +369,7 @@ def print_data_table(data_table, status, indent)
end
end

def print_outline_data(scenario_outline) # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity
def print_outline_data(scenario_outline) # rubocop:disable Metrics/AbcSize
print_comments(scenario_outline[:location][:line], 2)
print_tags(scenario_outline[:tags], 2)
@source_indent = calculate_source_indent_for_ast_node(scenario_outline) if options[:source]
Expand All @@ -387,8 +385,8 @@ def print_outline_data(scenario_outline) # rubocop:disable Metrics/AbcSize, Metr
end
@io.puts
next if options[:no_multiline]
print_doc_string(step[:argument][:content], :skipped, 6) if step[:argument] && step[:argument][:type] == :DocString
print_data_table(step[:argument], :skipped, 6) if step[:argument] && step[:argument][:type] == :DataTable
print_doc_string(step[:doc_string][:content], :skipped, 6) unless step[:doc_string].nil?
print_data_table(step[:data_table], :skipped, 6) unless step[:data_table].nil?
end
@io.flush
end
Expand All @@ -405,8 +403,8 @@ def print_examples_data(examples)
print_keyword_name(examples[:keyword], examples[:name], 4)
print_description(examples[:description])
unless options[:expand]
print_comments(examples[:tableHeader][:location][:line], 6)
@io.puts(gherkin_source.split("\n")[examples[:tableHeader][:location][:line] - 1].strip.indent(6))
print_comments(examples[:table_header][:location][:line], 6)
@io.puts(gherkin_source.split("\n")[examples[:table_header][:location][:line] - 1].strip.indent(6))
end
@io.flush
end
Expand Down
14 changes: 8 additions & 6 deletions lib/cucumber/gherkin/data_table_parser.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# frozen_string_literal: true

require 'gherkin/token_scanner'
require 'gherkin/parser'
require 'gherkin/gherkin'
require 'gherkin/dialect'

module Cucumber
Expand All @@ -12,11 +11,14 @@ def initialize(builder)
end

def parse(text)
token_scanner = ::Gherkin::TokenScanner.new(feature_header + text)
parser = ::Gherkin::Parser.new
gherkin_document = parser.parse(token_scanner)
gherkin_document = nil
messages = ::Gherkin::Gherkin.from_source('dummy', feature_header + text, include_source: false, include_pickles: false)
messages.each do |message|
gherkin_document = message.gherkinDocument.to_hash unless message.gherkinDocument.nil?
end

gherkin_document[:feature][:children][0][:steps][0][:argument][:rows].each do |row|
return if gherkin_document.nil?
gherkin_document[:feature][:children][0][:scenario][:steps][0][:data_table][:rows].each do |row|
@builder.row(row[:cells].map { |cell| cell[:value] })
end
end
Expand Down
15 changes: 7 additions & 8 deletions lib/cucumber/gherkin/steps_parser.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
# frozen_string_literal: true

require 'gherkin/token_scanner'
require 'gherkin/token_matcher'
require 'gherkin/parser'
require 'gherkin/gherkin'
require 'gherkin/dialect'

module Cucumber
Expand All @@ -15,12 +13,13 @@ def initialize(builder, language)

def parse(text)
dialect = ::Gherkin::Dialect.for(@language)
token_matcher = ::Gherkin::TokenMatcher.new(@language)
token_scanner = ::Gherkin::TokenScanner.new(feature_header(dialect) + text)
parser = ::Gherkin::Parser.new
gherkin_document = parser.parse(token_scanner, token_matcher)
gherkin_document = nil
messages = ::Gherkin::Gherkin.from_source('dummy', feature_header(dialect) + text, default_dialect: @language, include_source: false, include_pickles: false)
messages.each do |message|
gherkin_document = message.gherkinDocument.to_hash unless message.gherkinDocument.nil?
end

@builder.steps(gherkin_document[:feature][:children][0][:steps])
@builder.steps(gherkin_document[:feature][:children][0][:scenario][:steps])
end

def feature_header(dialect)
Expand Down
13 changes: 5 additions & 8 deletions lib/cucumber/runtime/support_code.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,11 @@ def step(step)
end

def multiline_arg(step, location)
argument = step[:argument]

if argument
if argument[:type] == :DocString
MultilineArgument.from(argument[:content], location, argument[:content_type])
else
MultilineArgument::DataTable.from(argument[:rows].map { |row| row[:cells].map { |cell| cell[:value] } })
end
if !step[:doc_string].nil?

MultilineArgument.from(step[:doc_string][:content], location, step[:doc_string][:content_type])
elsif !step[:data_table].nil?
MultilineArgument::DataTable.from(step[:data_table][:rows].map { |row| row[:cells].map { |cell| cell[:value] } })
else
MultilineArgument.from(nil)
end
Expand Down
Loading

0 comments on commit 9d9998b

Please sign in to comment.