Skip to content

Commit

Permalink
Merge eeab7e1 into cdc8d33
Browse files Browse the repository at this point in the history
  • Loading branch information
Sigill committed Aug 25, 2019
2 parents cdc8d33 + eeab7e1 commit 6327047
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 21 deletions.
18 changes: 12 additions & 6 deletions lib/cucumber/core/test/action.rb
Expand Up @@ -3,6 +3,7 @@
require 'cucumber/core/test/timer'
require 'cucumber/core/test/result'
require 'cucumber/core/test/location'
require 'cucumber/core/test/invoke_result'

module Cucumber
module Core
Expand All @@ -21,8 +22,13 @@ def skip(*)

def execute(*args)
@timer.start
@block.call(*args)
passed
invoke_result = @block.call(*args)

case invoke_result
when PassedInvokeResult; then passed(invoke_result.embeddings)
when FailedInvokeResult; then failed(invoke_result.exception, invoke_result.embeddings)
else passed
end
rescue Result::Raisable => exception
exception.with_duration(@timer.duration)
rescue Exception => exception
Expand All @@ -39,12 +45,12 @@ def inspect

private

def passed
Result::Passed.new(@timer.duration)
def passed(embeddings = [])
Result::Passed.new(@timer.duration, embeddings)
end

def failed(exception)
Result::Failed.new(@timer.duration, exception)
def failed(exception, embeddings = [])
Result::Failed.new(@timer.duration, exception, embeddings)
end

def skipped
Expand Down
23 changes: 23 additions & 0 deletions lib/cucumber/core/test/invoke_result.rb
@@ -0,0 +1,23 @@
module Cucumber
module Core
module Test
class InvokeResult
attr_reader :embeddings
def initialize(embeddings = [])
@embeddings = embeddings
end
end

class PassedInvokeResult < InvokeResult
end

class FailedInvokeResult < InvokeResult
attr_reader :exception
def initialize(exception, embeddings = [])
super(embeddings)
@exception = exception
end
end
end
end
end
18 changes: 14 additions & 4 deletions lib/cucumber/core/test/result.rb
Expand Up @@ -48,19 +48,22 @@ def with_filtered_backtrace(filter)
class Passed
include Result.query_methods :passed
attr_accessor :duration
attr_reader :embeddings

def self.ok?(be_strict = false)
true
end

def initialize(duration)
def initialize(duration, embeddings = [])
raise ArgumentError unless duration
@duration = duration
@embeddings = embeddings
end

def describe_to(visitor, *args)
visitor.passed(*args)
visitor.duration(duration, *args)
@embeddings.each { |e| visitor.embed(e['src'], e['mime_type'], e['label']) }
self
end

Expand All @@ -84,22 +87,25 @@ def with_filtered_backtrace(filter)
class Failed
include Result.query_methods :failed
attr_reader :duration, :exception
attr_reader :embeddings

def self.ok?(be_strict = false)
false
end

def initialize(duration, exception)
def initialize(duration, exception, embeddings = [])
raise ArgumentError unless duration
raise ArgumentError unless exception
@duration = duration
@exception = exception
@embeddings = embeddings
end

def describe_to(visitor, *args)
visitor.failed(*args)
visitor.duration(duration, *args)
visitor.exception(exception, *args) if exception
@embeddings.each { |e| visitor.embed(e['src'], e['mime_type'], e['label']) }
self
end

Expand All @@ -112,7 +118,7 @@ def ok?(be_strict = nil)
end

def with_duration(new_duration)
self.class.new(new_duration, exception)
self.class.new(new_duration, exception, embeddings)
end

def with_appended_backtrace(step)
Expand All @@ -121,7 +127,7 @@ def with_appended_backtrace(step)
end

def with_filtered_backtrace(filter)
self.class.new(duration, filter.new(exception.dup).exception)
self.class.new(duration, filter.new(exception.dup).exception, embeddings)
end
end

Expand Down Expand Up @@ -318,6 +324,10 @@ def duration(duration)
self
end

def embed(*)
self
end

def total(for_status = nil)
if for_status
@totals.fetch(for_status) { 0 }
Expand Down
4 changes: 4 additions & 0 deletions lib/cucumber/core/test/runner.rb
Expand Up @@ -90,6 +90,10 @@ def duration(step_duration, step_result)
self
end

def embed(*)
self
end

attr_reader :status
private :status

Expand Down
28 changes: 25 additions & 3 deletions spec/cucumber/core/test/action_spec.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
require 'cucumber/core/test/action'
require 'cucumber/core/test/duration_matcher'
require 'cucumber/core/test/invoke_result'

module Cucumber
module Core
Expand Down Expand Up @@ -46,15 +47,18 @@ module Test

it "returns a passed result if the block doesn't fail" do
action = Action.new {}
expect( action.execute ).to be_passed
result = action.execute
expect( result ).to be_passed
expect( result.embeddings ).to be_empty
end

it "returns a failed result when the block raises an error" do
exception = StandardError.new
action = Action.new { raise exception }
result = action.execute
expect( result ).to be_failed
expect( result.exception ).to eq exception
expect( result ).to be_failed
expect( result.exception ).to eq exception
expect( result.embeddings ).to be_empty
end

it "yields the args passed to #execute to the block" do
Expand Down Expand Up @@ -89,6 +93,24 @@ module Test
expect( result.message ).to eq "new step"
end

it "returns a passed result if the block returns a PassedInvokeResult" do
embeddings = [double]
action = Action.new { PassedInvokeResult.new(embeddings) }
result = action.execute
expect( result ).to be_passed
expect( result.embeddings ).to eq embeddings
end

it "returns a failed result when the block returns a FailedInvokeResult" do
exception = StandardError.new
embeddings = [double]
action = Action.new { FailedInvokeResult.new(exception, embeddings) }
result = action.execute
expect( result ).to be_failed
expect( result.exception ).to eq exception
expect( result.embeddings ).to eq embeddings
end

context "recording the duration" do
before do
allow( Timer::MonotonicTime ).to receive(:time_in_nanoseconds).and_return(525702744080000, 525702744080001)
Expand Down
26 changes: 22 additions & 4 deletions spec/cucumber/core/test/result_spec.rb
Expand Up @@ -10,12 +10,17 @@ module Cucumber::Core::Test
let(:args) { double('args') }

describe Result::Passed do
subject(:result) { Result::Passed.new(duration) }
subject(:result) { Result::Passed.new(duration, embeddings) }
let(:duration) { Result::Duration.new(1 * 1000 * 1000) }
let(:embedding1) { {'src' => 'src1', 'mime_type' => 'mime_type1', 'label' => 'label1'} }
let(:embedding2) { {'src' => 'src2', 'mime_type' => 'mime_type2', 'label' => 'label2'} }
let(:embeddings) { [embedding1, embedding2] }

it "describes itself to a visitor" do
expect( visitor ).to receive(:passed).with(args)
expect( visitor ).to receive(:duration).with(duration, args)
expect( visitor ).to receive(:embed).with(embedding1['src'], embedding1['mime_type'], embedding1['label']).ordered
expect( visitor ).to receive(:embed).with(embedding2['src'], embedding2['mime_type'], embedding2['label']).ordered
result.describe_to(visitor, args)
end

Expand All @@ -27,7 +32,11 @@ module Cucumber::Core::Test
expect( result.duration ).to eq duration
end

it "requires the constructor argument" do
it "has embeddings" do
expect( result.embeddings ).to eq embeddings
end

it "requires the first constructor argument" do
expect { Result::Passed.new }.to raise_error(ArgumentError)
end

Expand All @@ -53,22 +62,31 @@ module Cucumber::Core::Test
end

describe Result::Failed do
subject(:result) { Result::Failed.new(duration, exception) }
subject(:result) { Result::Failed.new(duration, exception, embeddings) }
let(:duration) { Result::Duration.new(1 * 1000 * 1000) }
let(:exception) { StandardError.new("error message") }
let(:embedding1) { {'src' => 'src1', 'mime_type' => 'mime_type1', 'label' => 'label1'} }
let(:embedding2) { {'src' => 'src2', 'mime_type' => 'mime_type2', 'label' => 'label2'} }
let(:embeddings) { [embedding1, embedding2] }

it "describes itself to a visitor" do
expect( visitor ).to receive(:failed).with(args)
expect( visitor ).to receive(:duration).with(duration, args)
expect( visitor ).to receive(:exception).with(exception, args)
expect( visitor ).to receive(:embed).with(embedding1['src'], embedding1['mime_type'], embedding1['label']).ordered
expect( visitor ).to receive(:embed).with(embedding2['src'], embedding2['mime_type'], embedding2['label']).ordered
result.describe_to(visitor, args)
end

it "has a duration" do
expect( result.duration ).to eq duration
end

it "requires both constructor arguments" do
it "has embeddings" do
expect( result.embeddings ).to eq embeddings
end

it "requires the first two constructor arguments" do
expect { Result::Failed.new }.to raise_error(ArgumentError)
expect { Result::Failed.new(duration) }.to raise_error(ArgumentError)
end
Expand Down
21 changes: 17 additions & 4 deletions spec/cucumber/core/test/step_spec.rb
@@ -1,5 +1,6 @@
# frozen_string_literal: true
require 'cucumber/core/test/step'
require 'cucumber/core/test/invoke_result'

module Cucumber::Core::Test
describe Step do
Expand Down Expand Up @@ -37,22 +38,34 @@ module Cucumber::Core::Test
expect(args_spy).to eq expected_args
end

context "when a passing action exists" do
it "returns a passing result" do
context "passing action" do
it "returns a passing result when the step invocation doesn't fail" do
test_step = Step.new(text, location).with_action {}
expect( test_step.execute ).to be_passed
end

it "returns a passing result when the step invocation returns a PassedInvokeResult" do
test_step = Step.new(text, location).with_action { PassedInvokeResult.new }
expect( test_step.execute ).to be_passed
end
end

context "when a failing action exists" do
context "failing action" do
let(:exception) { StandardError.new('oops') }

it "returns a failing result" do
it "returns a failing result when the step invocation raises an error" do
test_step = Step.new(text, location).with_action { raise exception }
result = test_step.execute
expect( result ).to be_failed
expect( result.exception ).to eq exception
end

it "returns a failing result when the step invocation returns a FailedInvokeResult" do
test_step = Step.new(text, location).with_action { FailedInvokeResult.new(exception) }
result = test_step.execute
expect( result ).to be_failed
expect( result.exception ).to eq exception
end
end

context "with no action" do
Expand Down

0 comments on commit 6327047

Please sign in to comment.