Skip to content

Commit

Permalink
Merge 352bfb3 into 320b6fc
Browse files Browse the repository at this point in the history
  • Loading branch information
vincent-psarga authored Jan 13, 2020
2 parents 320b6fc + 352bfb3 commit 5b26b75
Show file tree
Hide file tree
Showing 9 changed files with 74 additions and 48 deletions.
3 changes: 2 additions & 1 deletion lib/cucumber/core.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
require 'cucumber/core/gherkin/document'
require 'cucumber/core/compiler'
require 'cucumber/core/test/runner'
require 'cucumber/core/id_generator'

module Cucumber
module Core
Expand All @@ -17,7 +18,7 @@ def execute(gherkin_documents, filters = [], event_bus = EventBus.new)

def compile(gherkin_documents, last_receiver, filters = [], event_bus = EventBus.new)
first_receiver = compose(filters, last_receiver)
compiler = Compiler.new(first_receiver)
compiler = Compiler.new(first_receiver, IdGenerator::Incrementing.new)
parse gherkin_documents, compiler, event_bus
self
end
Expand Down
11 changes: 6 additions & 5 deletions lib/cucumber/core/compiler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ module Cucumber
module Core
# Compiles the Pickles into test cases
class Compiler
attr_reader :receiver
private :receiver
attr_reader :receiver, :id_generator
private :receiver, :id_generator

def initialize(receiver)
def initialize(receiver, id_generator)
@receiver = receiver
@id_generator = id_generator
end

def pickle(pickle)
Expand All @@ -35,13 +36,13 @@ def create_test_case(pickle)
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::Case.new(pickle.name, test_steps, Test::Location.new(uri, lines), tags, pickle.language)
Test::Case.new(id_generator.new_id, 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)
Test::Step.new(pickle_step.text, Test::Location.new(uri, lines), multiline_arg)
Test::Step.new(id_generator.new_id, pickle_step.text, Test::Location.new(uri, lines), multiline_arg)
end

def create_multiline_arg(pickle_step, uri)
Expand Down
18 changes: 18 additions & 0 deletions lib/cucumber/core/id_generator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# This is temporary - we'll use the IDGenerator that built-in cucumber-messages

module Cucumber
module Core
module IdGenerator
class Incrementing
def initialize
@index = -1
end

def new_id
@index += 1
@index.to_s
end
end
end
end
end
9 changes: 5 additions & 4 deletions lib/cucumber/core/test/case.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ module Cucumber
module Core
module Test
class Case
attr_reader :name, :test_steps, :location, :tags, :language, :around_hooks
attr_reader :id, :name, :test_steps, :location, :tags, :language, :around_hooks

def initialize(name, test_steps, location, tags, language, around_hooks = [])
def initialize(id, name, test_steps, location, tags, language, around_hooks = [])
raise ArgumentError.new("test_steps should be an Array but is a #{test_steps.class}") unless test_steps.is_a?(Array)
@id = id
@name = name
@test_steps = test_steps
@location = location
Expand All @@ -35,11 +36,11 @@ def describe_to(visitor, *args)
end

def with_steps(test_steps)
self.class.new(name, test_steps, location, tags, language, around_hooks)
self.class.new(id, name, test_steps, location, tags, language, around_hooks)
end

def with_around_hooks(around_hooks)
self.class.new(name, test_steps, location, tags, language, around_hooks)
self.class.new(id, name, test_steps, location, tags, language, around_hooks)
end

def match_tags?(*expressions)
Expand Down
11 changes: 6 additions & 5 deletions lib/cucumber/core/test/step.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ module Cucumber
module Core
module Test
class Step
attr_reader :text, :location, :multiline_arg
attr_reader :id, :text, :location, :multiline_arg

def initialize(text, location, multiline_arg = Test::EmptyMultilineArgument.new, action = Test::UndefinedAction.new(location))
def initialize(id, text, location, multiline_arg = Test::EmptyMultilineArgument.new, action = Test::UndefinedAction.new(location))
raise ArgumentError if text.nil? || text.empty?
@id = id
@text = text
@location = location
@multiline_arg = multiline_arg
Expand All @@ -35,7 +36,7 @@ def execute(*args)
end

def with_action(action_location = nil, &block)
self.class.new(text, location, multiline_arg, Test::Action.new(action_location, &block))
self.class.new(id, text, location, multiline_arg, Test::Action.new(action_location, &block))
end

def backtrace_line
Expand All @@ -56,8 +57,8 @@ def inspect
end

class HookStep < Step
def initialize(text, location, action)
super(text, location, Test::EmptyMultilineArgument.new, action)
def initialize(id, text, location, action)
super(id, text, location, Test::EmptyMultilineArgument.new, action)
end

def hook?
Expand Down
5 changes: 3 additions & 2 deletions spec/cucumber/core/test/case_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ module Test
include Core
include Core::Gherkin::Writer

let(:id) { double }
let(:name) { double }
let(:location) { double }
let(:tags) { double }
let(:language) { double }
let(:test_case) { Test::Case.new(name, test_steps, location, tags, language) }
let(:test_case) { Test::Case.new(id, name, test_steps, location, tags, language) }
let(:test_steps) { [double, double] }

context 'describing itself' do
Expand Down Expand Up @@ -45,7 +46,7 @@ module Test
expect( first_hook ).to receive(:describe_to).ordered.and_yield
expect( second_hook ).to receive(:describe_to).ordered.and_yield
around_hooks = [first_hook, second_hook]
Test::Case.new(name, [], location, tags, language, around_hooks).describe_to(visitor, double)
Test::Case.new(id, name, [], location, tags, language, around_hooks).describe_to(visitor, double)
end

end
Expand Down
44 changes: 23 additions & 21 deletions spec/cucumber/core/test/runner_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,21 @@
module Cucumber::Core::Test
describe Runner do

let(:step_id) { double }
let(:test_id) { double }
let(:name) { double }
let(:location) { double }
let(:tags) { double }
let(:language) { double }
let(:test_case) { Case.new(name, test_steps, location, tags, language) }
let(:test_case) { Case.new(test_id, name, test_steps, location, tags, language) }
let(:text) { double }
let(:runner) { Runner.new(event_bus) }
let(:event_bus) { double.as_null_object }
let(:passing) { Step.new(text, location, location).with_action {} }
let(:failing) { Step.new(text, location, location).with_action { raise exception } }
let(:pending) { Step.new(text, location, location).with_action { raise Result::Pending.new("TODO") } }
let(:skipping) { Step.new(text, location, location).with_action { raise Result::Skipped.new } }
let(:undefined) { Step.new(text, location, location) }
let(:passing) { Step.new(step_id, text, location, location).with_action {} }
let(:failing) { Step.new(step_id, text, location, location).with_action { raise exception } }
let(:pending) { Step.new(step_id, text, location, location).with_action { raise Result::Pending.new("TODO") } }
let(:skipping) { Step.new(step_id, text, location, location).with_action { raise Result::Skipped.new } }
let(:undefined) { Step.new(step_id, text, location, location) }
let(:exception) { StandardError.new('test error') }

before do
Expand Down Expand Up @@ -223,8 +225,8 @@ module Cucumber::Core::Test

context 'with multiple test cases' do
context 'when the first test case fails' do
let(:first_test_case) { Case.new(name, [failing], location, tags, language) }
let(:last_test_case) { Case.new(name, [passing], location, tags, language) }
let(:first_test_case) { Case.new(test_id, name, [failing], location, tags, language) }
let(:last_test_case) { Case.new(test_id, name, [passing], location, tags, language) }
let(:test_cases) { [first_test_case, last_test_case] }

it 'reports the results correctly for the following test case' do
Expand All @@ -244,9 +246,9 @@ module Cucumber::Core::Test
hook_mapping = UnskippableAction.new do |last_result|
result_spy = last_result
end
after_hook = HookStep.new(text, location, hook_mapping)
failing_step = Step.new(text, location).with_action { fail }
test_case = Case.new(name, [failing_step, after_hook], location, tags, language)
after_hook = HookStep.new(step_id, text, location, hook_mapping)
failing_step = Step.new(step_id, text, location).with_action { fail }
test_case = Case.new(test_id, name, [failing_step, after_hook], location, tags, language)
test_case.describe_to runner
expect(result_spy).to be_failed
end
Expand All @@ -256,8 +258,8 @@ module Cucumber::Core::Test
context "with around hooks" do
it "passes normally when around hooks don't fail" do
around_hook = AroundHook.new { |block| block.call }
passing_step = Step.new(text, location, location).with_action {}
test_case = Case.new(name, [passing_step], location, tags, language, [around_hook])
passing_step = Step.new(step_id, text, location, location).with_action {}
test_case = Case.new(test_id, name, [passing_step], location, tags, language, [around_hook])
expect(event_bus).to receive(:test_case_finished).with(test_case, anything) do |reported_test_case, result|
expect(result).to be_passed
end
Expand All @@ -266,8 +268,8 @@ module Cucumber::Core::Test

it "gets a failed result if the Around hook fails before the test case is run" do
around_hook = AroundHook.new { |block| raise exception }
passing_step = Step.new(text, location, location).with_action {}
test_case = Case.new(name, [passing_step], location, tags, language, [around_hook])
passing_step = Step.new(step_id, text, location, location).with_action {}
test_case = Case.new(test_id, name, [passing_step], location, tags, language, [around_hook])
expect(event_bus).to receive(:test_case_finished).with(test_case, anything) do |reported_test_case, result|
expect(result).to be_failed
expect(result.exception).to eq exception
Expand All @@ -277,8 +279,8 @@ module Cucumber::Core::Test

it "gets a failed result if the Around hook fails after the test case is run" do
around_hook = AroundHook.new { |block| block.call; raise exception }
passing_step = Step.new(text, location, location).with_action {}
test_case = Case.new(name, [passing_step], location, tags, language, [around_hook])
passing_step = Step.new(step_id, text, location, location).with_action {}
test_case = Case.new(test_id, name, [passing_step], location, tags, language, [around_hook])
expect(event_bus).to receive(:test_case_finished).with(test_case, anything) do |reported_test_case, result|
expect(result).to be_failed
expect(result.exception).to eq exception
Expand All @@ -288,8 +290,8 @@ module Cucumber::Core::Test

it "fails when a step fails if the around hook works" do
around_hook = AroundHook.new { |block| block.call }
failing_step = Step.new(text, location, location).with_action { raise exception }
test_case = Case.new(name, [failing_step], location, tags, language, [around_hook])
failing_step = Step.new(step_id, text, location, location).with_action { raise exception }
test_case = Case.new(test_id, name, [failing_step], location, tags, language, [around_hook])
expect(event_bus).to receive(:test_case_finished).with(test_case, anything) do |reported_test_case, result|
expect(result).to be_failed
expect(result.exception).to eq exception
Expand All @@ -299,8 +301,8 @@ module Cucumber::Core::Test

it "sends after_test_step for a step interrupted by (a timeout in) the around hook" do
around_hook = AroundHook.new { |block| block.call; raise exception }
passing_step = Step.new(text, location, location).with_action {}
test_case = Case.new(name, [], location, tags, language, [around_hook])
passing_step = Step.new(step_id, text, location, location).with_action {}
test_case = Case.new(test_id, name, [], location, tags, language, [around_hook])
allow(runner).to receive(:running_test_step).and_return(passing_step)
expect(event_bus).to receive(:test_step_finished).with(passing_step, anything) do |reported_test_case, result|
expect(result).to be_failed
Expand Down
19 changes: 10 additions & 9 deletions spec/cucumber/core/test/step_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@

module Cucumber::Core::Test
describe Step do
let(:id) { 'some-random-uid' }
let(:text) { 'step text' }
let(:location) { double }

describe "describing itself" do
it "describes itself to a visitor" do
visitor = double
args = double
test_step = Step.new(text, location)
test_step = Step.new(id, text, location)
expect( visitor ).to receive(:test_step).with(test_step, args)
test_step.describe_to(visitor, args)
end
Expand All @@ -19,7 +20,7 @@ module Cucumber::Core::Test
describe "backtrace line" do
let(:text) { 'this step passes' }
let(:location) { Location.new('path/file.feature', 10) }
let(:test_step) { Step.new(text, location) }
let(:test_step) { Step.new(id, text, location) }

it "knows how to form the backtrace line" do
expect( test_step.backtrace_line ).to eq("path/file.feature:10:in `this step passes'")
Expand All @@ -30,7 +31,7 @@ module Cucumber::Core::Test
it "passes arbitrary arguments to the action's block" do
args_spy = nil
expected_args = [double, double]
test_step = Step.new(text, location).with_action do |*actual_args|
test_step = Step.new(id, text, location).with_action do |*actual_args|
args_spy = actual_args
end
test_step.execute(*expected_args)
Expand All @@ -39,7 +40,7 @@ module Cucumber::Core::Test

context "when a passing action exists" do
it "returns a passing result" do
test_step = Step.new(text, location).with_action {}
test_step = Step.new(id, text, location).with_action {}
expect( test_step.execute ).to be_passed
end
end
Expand All @@ -48,7 +49,7 @@ module Cucumber::Core::Test
let(:exception) { StandardError.new('oops') }

it "returns a failing result" do
test_step = Step.new(text, location).with_action { raise exception }
test_step = Step.new(id, text, location).with_action { raise exception }
result = test_step.execute
expect( result ).to be_failed
expect( result.exception ).to eq exception
Expand All @@ -57,29 +58,29 @@ module Cucumber::Core::Test

context "with no action" do
it "returns an Undefined result" do
test_step = Step.new(text, location)
test_step = Step.new(id, text, location)
result = test_step.execute
expect( result ).to be_undefined
end
end
end

it "exposes the text and location of as attributes" do
test_step = Step.new(text, location)
test_step = Step.new(id, text, location)
expect( test_step.text ).to eq text
expect( test_step.location ).to eq location
end

it "exposes the location of the action as attribute" do
location = double
action = double(location: location)
test_step = Step.new(text, location, action)
test_step = Step.new(id, text, location, action)
expect( test_step.action_location ).to eq location
end

it "returns the text when converted to a string" do
text = 'a passing step'
test_step = Step.new(text, location)
test_step = Step.new(id, text, location)
expect( test_step.to_s ).to eq 'a passing step'
end

Expand Down
2 changes: 1 addition & 1 deletion spec/cucumber/core_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ module Cucumber
context "with around hooks" do
class WithAroundHooks < Core::Filter.new(:logger)
def test_case(test_case)
base_step = Core::Test::Step.new('text', nil, nil, nil)
base_step = Core::Test::Step.new('some-random-uid', 'text', nil, nil, nil)
test_steps = [
base_step.with_action { logger << :step },
]
Expand Down

0 comments on commit 5b26b75

Please sign in to comment.