Skip to content

Commit

Permalink
Implement the --expand option in legacy_formatter
Browse files Browse the repository at this point in the history
Remove @wip-new-core from scenarios passed by this.
The change from #700 is merged and working in both the v1.3.x branch and
in the master branch, so now it is time to close cucumber/gherkin#165.
  • Loading branch information
brasmusson committed Aug 12, 2014
1 parent f02823b commit 84eb09c
Show file tree
Hide file tree
Showing 6 changed files with 280 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ Feature: Formatter Callback
"""


@wip-new-core
Scenario: callback if expanded
Given a file named "features/f.feature" with:
"""
Expand Down
2 changes: 1 addition & 1 deletion features/docs/formatters/json_formatter.feature
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ Feature: JSON output formatter
]
"""
@wip-new-core

@spawn
Scenario: scenario outline expanded
When I run `cucumber --expand --format json features/outline.feature`
Expand Down
1 change: 0 additions & 1 deletion features/docs/gherkin/expand_option_for_outlines.feature
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
@wip-new-core
Feature: Scenario outlines --expand option

In order to make it easier to write certain editor plugins and also
Expand Down
126 changes: 88 additions & 38 deletions lib/cucumber/reports/legacy_formatter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -597,15 +597,21 @@ def before
formatter.before_examples(node)
formatter.examples_name(node.keyword, node.legacy_conflated_name_and_description)
formatter.before_outline_table(legacy_table)
TableRowPrinter.new(formatter, runtime, ExampleTableRow.new(node.header)).before.after
if !runtime.configuration.expand?
TableRowPrinter.new(formatter, runtime, ExampleTableRow.new(node.header)).before.after
end
self
end

def examples_table_row(examples_table_row, before_hook_result)
return if examples_table_row == @current
@child.after if @child
row = ExampleTableRow.new(examples_table_row)
@child = TableRowPrinter.new(formatter, runtime, row, nil, before_hook_result).before
if !runtime.configuration.expand?
@child = TableRowPrinter.new(formatter, runtime, row, nil, before_hook_result).before
else
@child = ExpandTableRowPrinter.new(formatter, runtime, row, nil, before_hook_result).before
end
@current = examples_table_row
end

Expand Down Expand Up @@ -665,17 +671,42 @@ def char_length_of(cell)
end
end

TableRowPrinter = Struct.new(:formatter, :runtime, :node, :background, :before_hook_result) do
class TableRowPrinterBase < Struct.new(:formatter, :runtime, :node, :background, :before_hook_result)
def after_hook(result)
@after_hook_result = result
end

def after_step_hook(result)
@after_step_hook_result = result
end

def after_test_case(*args)
after
end

private

def indent
:not_needed
end

def legacy_table_row
LegacyExampleTableRow.new(exception, @status, node.values, node.location)
end

def exception
return nil unless @failed_step
@failed_step.exception
end
end

class TableRowPrinter < TableRowPrinterBase
def before
before_hook_result.describe_exception_to(formatter) if before_hook_result
formatter.before_table_row(node)
self
end

def after_hook(result)
@after_hook_result = result
end

def step_invocation(step_invocation, source)
result = source.step_result
step_invocation.messages.each { |message| formatter.puts(message) }
Expand All @@ -684,14 +715,6 @@ def step_invocation(step_invocation, source)
@status = step_invocation.status unless @status == :failed
end

def after_step_hook(result)
@after_step_hook_result = result
end

def after_test_case(*args)
after
end

def after
return if @done
@child.after if @child
Expand All @@ -706,36 +729,61 @@ def after
@done = true
self
end
end

private
class ExpandTableRowPrinter < TableRowPrinterBase
def before
before_hook_result.describe_exception_to(formatter) if before_hook_result
self
end

def indent
:not_needed
def step_invocation(step_invocation, source)
result = source.step_result
@table_row ||= legacy_table_row
step_invocation.indent.record_width_of(@table_row)
if !@scenario_name_printed
print_scenario_name(step_invocation, @table_row)
@scenario_name_printed = true
end
step_invocation.accept(formatter)
@failed_step = step_invocation if result.status == :failed
@status = step_invocation.status unless @status == :failed
end

def legacy_table_row
LegacyExampleTableRow.new(exception, @status, node.values, node.location)
def after
return if @done
@child.after if @child
@after_step_hook_result.describe_exception_to formatter if @after_step_hook_result
@after_hook_result.describe_exception_to(formatter) if @after_hook_result
@done = true
self
end

LegacyExampleTableRow = Struct.new(:exception, :status, :cells, :location) do
def name
'| ' + cells.join(' | ') + ' |'
end
private

def failed?
status == :failed
end
def print_scenario_name(step_invocation, table_row)
formatter.scenario_name table_row.keyword, table_row.name, node.location.to_s, step_invocation.indent.of(table_row)
end
end

def line
location.line
end
LegacyExampleTableRow = Struct.new(:exception, :status, :cells, :location) do
def name
'| ' + cells.join(' | ') + ' |'
end

def exception
return nil unless @failed_step
@failed_step.exception
def failed?
status == :failed
end

def line
location.line
end

def keyword
# This method is only called when used for the scenario name line with
# the expand option, and on that line the keyword is "Scenario"
"Scenario"
end
end

class Indent
Expand All @@ -761,18 +809,20 @@ def examples_table(*); end
def examples_table_row(*); end

def of(node)
max - node.name.length - node.keyword.length
# The length of the instantiated steps in --expand mode are currently
# not included in the calculation of max => make sure to return >= 1
[1, max - node.name.length - node.keyword.length].max
end

def record_width_of(node)
@widths << node.keyword.length + node.name.length + 1
end

private

def max
@widths.max
end

def record_width_of(node)
@widths << node.keyword.length + node.name.length + 1
end
end

class LegacyResultBuilder
Expand Down
131 changes: 131 additions & 0 deletions spec/cucumber/formatter/pretty_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,137 @@ module Formatter
end
end
end

context "In --expand mode" do
let(:runtime) { Runtime.new({:expand => true})}
let(:mappings) { Mappings.new(runtime) }
before(:each) do
Cucumber::Term::ANSIColor.coloring = false
@out = StringIO.new
@formatter = Pretty.new(runtime, @out, {})
end

describe "given a single feature" do
before(:each) do
run_defined_feature
end

describe "with a scenario outline" do
define_feature <<-FEATURE
Feature: Fud Pyramid
Scenario Outline: Monkey eats a balanced diet
Given there are <Things>
Examples: Fruit
| Things |
| apples |
| bananas |
Examples: Vegetables
| Things |
| broccoli |
| carrots |
FEATURE

it "outputs the instantiated scenarios" do
lines = <<-OUTPUT
Examples: Fruit
Scenario: | apples |
Given there are apples
Scenario: | bananas |
Given there are bananas
Examples: Vegetables
Scenario: | broccoli |
Given there are broccoli
Scenario: | carrots |
Given there are carrots
OUTPUT
lines.split("\n").each do |line|
expect(@out.string).to include line.strip
end
end
end
end
end

context "In --expand mode with --source as an option" do
let(:runtime) { Runtime.new({:expand => true})}
let(:mappings) { Mappings.new(runtime) }
before(:each) do
Cucumber::Term::ANSIColor.coloring = false
@out = StringIO.new
@formatter = Pretty.new(runtime, @out, {:source => true})
end

describe "given a single feature" do
before(:each) do
run_defined_feature
end

describe "with a scenario outline" do
define_feature <<-FEATURE
Feature: Fud Pyramid
Scenario Outline: Monkey eats a balanced diet
Given there are <Things>
Examples: Fruit
| Things |
| apples |
| bananas |
Examples: Vegetables
| Things |
| broccoli |
| carrots |
FEATURE

it "includes the source in the output" do
lines = <<-OUTPUT
Scenario Outline: Monkey eats a balanced diet # spec.feature:3
Given there are <Things> # spec.feature:4
Examples: Fruit
Scenario: | apples | # spec.feature:8
Given there are apples # spec.feature:4
Scenario: | bananas | # spec.feature:9
Given there are bananas # spec.feature:4
Examples: Vegetables
Scenario: | broccoli | # spec.feature:12
Given there are broccoli # spec.feature:4
Scenario: | carrots | # spec.feature:13
Given there are carrots # spec.feature:4
OUTPUT
lines.split("\n").each do |line|
expect(@out.string).to include line.strip
end
end

context "With very wide cells" do
define_feature <<-FEATURE
Feature: Monkey Business
Scenario Outline: Types of monkey
Given there are <Types of monkey>
Examples:
| Types of monkey | Extra |
| Hominidae | Very long cell content |
FEATURE

it "the scenario line controls the source indentation" do
lines = <<-OUTPUT
Examples:
Scenario: | Hominidae | Very long cell content | # spec.feature:8
Given there are Hominidae # spec.feature:4
OUTPUT
lines.split("\n").each do |line|
expect(@out.string).to include line.strip
end
end
end
end
end
end
end
end
end
Loading

2 comments on commit 84eb09c

@brasmusson
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The handling of indentation of the source designations does not work perfectly in together with the --expand option.

First the source hash for instantiated scenario and steps are indented four steps further to the left compared to the scenario outline itself - since the left most character of the instantiated scenarios and steps is indented four steps further to the left compared to the left most character scenario outline and steps (rspec spec).

Then, the instantiated steps are not considered in the calculation of max width, so if an instantiated step becomes very, very long it will push its source hash out of alignment. Instantiated scenario names that becomes very, very long is handled, so the following step sources will be aligned with source of the very, very long scenario name.

@mattwynne
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see what you mean. I don't think we need to worry about this for now.

Thanks @brasmusson!

Please sign in to comment.