cucumber-core 1.5.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE.md +48 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +39 -0
- data/.travis.yml +2 -3
- data/HISTORY.md +12 -1
- data/README.md +37 -43
- data/cucumber-core.gemspec +2 -0
- data/lib/cucumber/core.rb +5 -2
- data/lib/cucumber/core/ast.rb +1 -0
- data/lib/cucumber/core/ast/background.rb +1 -0
- data/lib/cucumber/core/ast/comment.rb +1 -0
- data/lib/cucumber/core/ast/data_table.rb +1 -0
- data/lib/cucumber/core/ast/describes_itself.rb +1 -0
- data/lib/cucumber/core/ast/doc_string.rb +1 -0
- data/lib/cucumber/core/ast/empty_background.rb +1 -0
- data/lib/cucumber/core/ast/empty_multiline_argument.rb +1 -0
- data/lib/cucumber/core/ast/examples_table.rb +1 -0
- data/lib/cucumber/core/ast/feature.rb +1 -0
- data/lib/cucumber/core/ast/location.rb +1 -0
- data/lib/cucumber/core/ast/names.rb +1 -0
- data/lib/cucumber/core/ast/outline_step.rb +1 -0
- data/lib/cucumber/core/ast/scenario.rb +1 -0
- data/lib/cucumber/core/ast/scenario_outline.rb +1 -0
- data/lib/cucumber/core/ast/step.rb +1 -0
- data/lib/cucumber/core/ast/tag.rb +1 -0
- data/lib/cucumber/core/compiler.rb +1 -0
- data/lib/cucumber/core/event.rb +63 -0
- data/lib/cucumber/core/event_bus.rb +64 -0
- data/lib/cucumber/core/events.rb +69 -0
- data/lib/cucumber/core/filter.rb +1 -0
- data/lib/cucumber/core/gherkin/ast_builder.rb +14 -5
- data/lib/cucumber/core/gherkin/document.rb +6 -4
- data/lib/cucumber/core/gherkin/parser.rb +6 -4
- data/lib/cucumber/core/gherkin/tag_expression.rb +1 -0
- data/lib/cucumber/core/gherkin/writer.rb +1 -0
- data/lib/cucumber/core/gherkin/writer/helpers.rb +1 -0
- data/lib/cucumber/core/platform.rb +1 -0
- data/lib/cucumber/core/report/summary.rb +30 -6
- data/lib/cucumber/core/test/action.rb +1 -0
- data/lib/cucumber/core/test/around_hook.rb +1 -0
- data/lib/cucumber/core/test/case.rb +13 -0
- data/lib/cucumber/core/test/filters.rb +1 -0
- data/lib/cucumber/core/test/filters/locations_filter.rb +1 -0
- data/lib/cucumber/core/test/filters/name_filter.rb +1 -0
- data/lib/cucumber/core/test/filters/tag_filter.rb +1 -0
- data/lib/cucumber/core/test/result.rb +5 -0
- data/lib/cucumber/core/test/runner.rb +10 -10
- data/lib/cucumber/core/test/step.rb +1 -0
- data/lib/cucumber/core/test/timer.rb +1 -0
- data/lib/cucumber/core/version.rb +2 -1
- data/spec/capture_warnings.rb +3 -2
- data/spec/coverage.rb +1 -0
- data/spec/cucumber/core/ast/background_spec.rb +1 -0
- data/spec/cucumber/core/ast/data_table_spec.rb +1 -0
- data/spec/cucumber/core/ast/doc_string_spec.rb +2 -1
- data/spec/cucumber/core/ast/empty_multiline_argument_spec.rb +1 -0
- data/spec/cucumber/core/ast/examples_table_spec.rb +1 -0
- data/spec/cucumber/core/ast/location_spec.rb +1 -0
- data/spec/cucumber/core/ast/outline_step_spec.rb +1 -0
- data/spec/cucumber/core/ast/step_spec.rb +1 -0
- data/spec/cucumber/core/compiler_spec.rb +1 -0
- data/spec/cucumber/core/event_bus_spec.rb +151 -0
- data/spec/cucumber/core/event_spec.rb +40 -0
- data/spec/cucumber/core/filter_spec.rb +1 -0
- data/spec/cucumber/core/gherkin/parser_spec.rb +24 -0
- data/spec/cucumber/core/gherkin/writer_spec.rb +1 -0
- data/spec/cucumber/core/report/summary_spec.rb +127 -0
- data/spec/cucumber/core/test/action_spec.rb +1 -0
- data/spec/cucumber/core/test/case_spec.rb +26 -2
- data/spec/cucumber/core/test/duration_matcher.rb +2 -1
- data/spec/cucumber/core/test/filters/locations_filter_spec.rb +2 -0
- data/spec/cucumber/core/test/result_spec.rb +5 -0
- data/spec/cucumber/core/test/runner_spec.rb +44 -50
- data/spec/cucumber/core/test/step_spec.rb +1 -0
- data/spec/cucumber/core/test/timer_spec.rb +1 -0
- data/spec/cucumber/core_spec.rb +68 -8
- data/spec/readme_spec.rb +1 -0
- data/spec/report_api_spy.rb +1 -0
- metadata +42 -3
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
require 'cucumber/core/events'
|
|
2
|
+
|
|
3
|
+
module Cucumber
|
|
4
|
+
module Core
|
|
5
|
+
|
|
6
|
+
# Event Bus
|
|
7
|
+
#
|
|
8
|
+
# Implements an in-process pub-sub event broadcaster allowing multiple observers
|
|
9
|
+
# to subscribe to events that fire as your tests are executed.
|
|
10
|
+
#
|
|
11
|
+
class EventBus
|
|
12
|
+
attr_reader :event_types
|
|
13
|
+
|
|
14
|
+
# @param [Hash{Symbol => Class}] a hash of event types to use on the bus
|
|
15
|
+
def initialize(registry = Events.registry)
|
|
16
|
+
@event_types = registry.freeze
|
|
17
|
+
@handlers = {}
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Register for an event. The handler proc will be called back with each of the attributes
|
|
21
|
+
# of the event.
|
|
22
|
+
def on(event_id, handler_object = nil, &handler_proc)
|
|
23
|
+
handler = handler_proc || handler_object
|
|
24
|
+
validate_handler_and_event_id!(handler, event_id)
|
|
25
|
+
event_class = event_types[event_id]
|
|
26
|
+
handlers_for(event_class) << handler
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Broadcast an event
|
|
30
|
+
def broadcast(event)
|
|
31
|
+
raise ArgumentError, "Event type #{event.class} is not registered. Try one of these:\n#{event_types.values.join("\n")}" unless is_registered_type?(event.class)
|
|
32
|
+
handlers_for(event.class).each { |handler| handler.call(event) }
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def method_missing(event_id, *args)
|
|
36
|
+
event_class = event_types.fetch(event_id) { super }
|
|
37
|
+
broadcast event_class.new(*args)
|
|
38
|
+
rescue NameError => error
|
|
39
|
+
raise error, error.message + "\nDid you get the ID of the event wrong? Try one of these:\n#{event_types.keys.join("\n")}", error.backtrace
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def handlers_for(event_class)
|
|
45
|
+
@handlers[event_class.to_s] ||= []
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def is_registered_id?(event_id)
|
|
49
|
+
event_types.keys.include?(event_id)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def is_registered_type?(event_type)
|
|
53
|
+
event_types.values.include?(event_type)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def validate_handler_and_event_id!(handler, event_id)
|
|
57
|
+
raise ArgumentError, "Please pass either an object or a handler block" unless handler
|
|
58
|
+
raise ArgumentError, "Please use a symbol for the event_id" unless event_id.is_a?(Symbol)
|
|
59
|
+
raise ArgumentError, "Event ID #{event_id} is not recognised. Try one of these:\n#{event_types.keys.join("\n")}" unless is_registered_id?(event_id)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
require 'cucumber/core/event'
|
|
2
|
+
|
|
3
|
+
module Cucumber
|
|
4
|
+
module Core
|
|
5
|
+
module Events
|
|
6
|
+
|
|
7
|
+
# Signals that a {Test::Case} is about to be executed
|
|
8
|
+
class TestCaseStarting < Event.new(:test_case)
|
|
9
|
+
|
|
10
|
+
# @return [Test::Case] the test case to be executed
|
|
11
|
+
attr_reader :test_case
|
|
12
|
+
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Signals that a {Test::Step} is about to be executed
|
|
16
|
+
class TestStepStarting < Event.new(:test_step)
|
|
17
|
+
|
|
18
|
+
# @return [Test::Step] the test step to be executed
|
|
19
|
+
attr_reader :test_step
|
|
20
|
+
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Signals that a {Test::Step} has finished executing
|
|
24
|
+
class TestStepFinished < Event.new(:test_step, :result)
|
|
25
|
+
|
|
26
|
+
# @return [Test::Step] the test step that was executed
|
|
27
|
+
attr_reader :test_step
|
|
28
|
+
|
|
29
|
+
# @return [Test::Result] the result of running the {Test::Step}
|
|
30
|
+
attr_reader :result
|
|
31
|
+
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
# Signals that a {Test::Case} has finished executing
|
|
36
|
+
class TestCaseFinished < Event.new(:test_case, :result)
|
|
37
|
+
|
|
38
|
+
# @return [Test::Case] that was executed
|
|
39
|
+
attr_reader :test_case
|
|
40
|
+
|
|
41
|
+
# @return [Test::Result] the result of running the {Test::Step}
|
|
42
|
+
attr_reader :result
|
|
43
|
+
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# The registry contains all the events registered in the core,
|
|
47
|
+
# that will be used by the {EventBus} by default.
|
|
48
|
+
def self.registry
|
|
49
|
+
build_registry(
|
|
50
|
+
TestCaseStarting,
|
|
51
|
+
TestStepStarting,
|
|
52
|
+
TestStepFinished,
|
|
53
|
+
TestCaseFinished,
|
|
54
|
+
)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Build an event registry to be passed to the {EventBus}
|
|
58
|
+
# constructor from a list of types.
|
|
59
|
+
#
|
|
60
|
+
# Each type must respond to `event_id` so that it can be added
|
|
61
|
+
# to the registry hash.
|
|
62
|
+
#
|
|
63
|
+
# @return [Hash{Symbol => Class}]
|
|
64
|
+
def self.build_registry(*types)
|
|
65
|
+
types.map { |type| [type.event_id, type] }.to_h
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
data/lib/cucumber/core/filter.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
require 'cucumber/core/ast'
|
|
2
3
|
require 'cucumber/core/platform'
|
|
3
4
|
|
|
@@ -271,7 +272,7 @@ module Cucumber
|
|
|
271
272
|
def initialize(*)
|
|
272
273
|
super
|
|
273
274
|
@step_builders = attributes[:steps].map { |step| OutlineStepBuilder.new(file, step) }
|
|
274
|
-
@example_builders = attributes[:examples].map { |example| ExamplesTableBuilder.new(file, example) }
|
|
275
|
+
@example_builders = attributes[:examples] ? attributes[:examples].map { |example| ExamplesTableBuilder.new(file, example) } : []
|
|
275
276
|
end
|
|
276
277
|
|
|
277
278
|
def result(language)
|
|
@@ -305,10 +306,8 @@ module Cucumber
|
|
|
305
306
|
|
|
306
307
|
def initialize(*)
|
|
307
308
|
super
|
|
308
|
-
@header_builder = HeaderBuilder.new(file, attributes[:table_header])
|
|
309
|
-
@example_rows_builders = attributes[:table_body].map
|
|
310
|
-
ExampleRowBuilder.new(file, row_attributes)
|
|
311
|
-
end
|
|
309
|
+
@header_builder = attributes[:table_header] ? HeaderBuilder.new(file, attributes[:table_header]) : NullHeaderBuilder.new
|
|
310
|
+
@example_rows_builders = attributes[:table_body] ? attributes[:table_body].map { |row_attributes| ExampleRowBuilder.new(file, row_attributes) } : []
|
|
312
311
|
end
|
|
313
312
|
|
|
314
313
|
def result(language)
|
|
@@ -341,6 +340,16 @@ module Cucumber
|
|
|
341
340
|
end
|
|
342
341
|
end
|
|
343
342
|
|
|
343
|
+
class NullHeaderBuilder < Builder
|
|
344
|
+
def initialize
|
|
345
|
+
@line = -1 # this inhibits Builder#handle_comments to put any comments in this object.
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
def result
|
|
349
|
+
nil
|
|
350
|
+
end
|
|
351
|
+
end
|
|
352
|
+
|
|
344
353
|
def children
|
|
345
354
|
[header_builder] + example_rows_builders
|
|
346
355
|
end
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
|
|
2
3
|
module Cucumber
|
|
3
4
|
module Core
|
|
4
5
|
module Gherkin
|
|
5
6
|
class Document
|
|
6
|
-
attr_reader :uri, :body
|
|
7
|
+
attr_reader :uri, :body, :language
|
|
7
8
|
|
|
8
|
-
def initialize(uri, body)
|
|
9
|
-
@uri
|
|
10
|
-
@body
|
|
9
|
+
def initialize(uri, body, language=nil)
|
|
10
|
+
@uri = uri
|
|
11
|
+
@body = body
|
|
12
|
+
@language = language || 'en'
|
|
11
13
|
end
|
|
12
14
|
|
|
13
15
|
def to_s
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
require 'gherkin/parser'
|
|
2
3
|
require 'gherkin/token_scanner'
|
|
3
4
|
require 'gherkin/errors'
|
|
@@ -18,12 +19,13 @@ module Cucumber
|
|
|
18
19
|
end
|
|
19
20
|
|
|
20
21
|
def document(document)
|
|
21
|
-
parser
|
|
22
|
-
scanner
|
|
23
|
-
|
|
22
|
+
parser = ::Gherkin::Parser.new
|
|
23
|
+
scanner = ::Gherkin::TokenScanner.new(document.body)
|
|
24
|
+
token_matcher = ::Gherkin::TokenMatcher.new(document.language)
|
|
25
|
+
core_builder = AstBuilder.new(document.uri)
|
|
24
26
|
|
|
25
27
|
begin
|
|
26
|
-
result = parser.parse(scanner)
|
|
28
|
+
result = parser.parse(scanner, token_matcher)
|
|
27
29
|
|
|
28
30
|
receiver.feature core_builder.feature(result)
|
|
29
31
|
rescue *PARSER_ERRORS => e
|
|
@@ -1,25 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module Cucumber
|
|
2
3
|
module Core
|
|
3
4
|
module Report
|
|
4
5
|
class Summary
|
|
5
6
|
attr_reader :test_cases, :test_steps
|
|
6
7
|
|
|
7
|
-
def initialize
|
|
8
|
+
def initialize(event_bus)
|
|
8
9
|
@test_cases = Test::Result::Summary.new
|
|
9
10
|
@test_steps = Test::Result::Summary.new
|
|
11
|
+
subscribe_to(event_bus)
|
|
10
12
|
end
|
|
11
13
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def subscribe_to(event_bus)
|
|
17
|
+
event_bus.on(:test_case_finished) do |event|
|
|
18
|
+
event.result.describe_to test_cases
|
|
19
|
+
end
|
|
20
|
+
event_bus.on(:test_step_finished) do |event|
|
|
21
|
+
event.result.describe_to test_steps if is_step?(event.test_step)
|
|
22
|
+
end
|
|
23
|
+
self
|
|
14
24
|
end
|
|
15
25
|
|
|
16
|
-
def
|
|
17
|
-
|
|
26
|
+
def is_step?(test_step)
|
|
27
|
+
StepQueryVisitor.new(test_step).is_step?
|
|
18
28
|
end
|
|
29
|
+
end
|
|
19
30
|
|
|
20
|
-
|
|
31
|
+
class StepQueryVisitor
|
|
32
|
+
def initialize(test_step)
|
|
33
|
+
@step = false
|
|
34
|
+
test_step.source.last.describe_to(self)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def is_step?
|
|
38
|
+
@step
|
|
21
39
|
end
|
|
22
40
|
|
|
41
|
+
def step(*)
|
|
42
|
+
@step = true
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def method_missing(*)
|
|
46
|
+
end
|
|
23
47
|
end
|
|
24
48
|
end
|
|
25
49
|
end
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
require 'cucumber/core/test/result'
|
|
2
3
|
require 'cucumber/core/gherkin/tag_expression'
|
|
3
4
|
require 'cucumber/core/ast/location'
|
|
@@ -99,6 +100,18 @@ module Cucumber
|
|
|
99
100
|
source.first
|
|
100
101
|
end
|
|
101
102
|
|
|
103
|
+
def hash
|
|
104
|
+
location.hash
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def eql?(other)
|
|
108
|
+
other.hash == hash
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def ==(other)
|
|
112
|
+
eql?(other)
|
|
113
|
+
end
|
|
114
|
+
|
|
102
115
|
private
|
|
103
116
|
|
|
104
117
|
def compose_around_hooks(visitor, *args, &block)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# encoding: UTF-8
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
module Cucumber
|
|
4
5
|
module Core
|
|
@@ -30,6 +31,10 @@ module Cucumber
|
|
|
30
31
|
def describe_to(visitor, *args)
|
|
31
32
|
self
|
|
32
33
|
end
|
|
34
|
+
|
|
35
|
+
def with_filtered_backtrace(filter)
|
|
36
|
+
self
|
|
37
|
+
end
|
|
33
38
|
end
|
|
34
39
|
|
|
35
40
|
class Passed
|
|
@@ -1,43 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
require 'cucumber/core/test/timer'
|
|
2
3
|
|
|
3
4
|
module Cucumber
|
|
4
5
|
module Core
|
|
5
6
|
module Test
|
|
6
7
|
class Runner
|
|
7
|
-
attr_reader :
|
|
8
|
-
private :
|
|
8
|
+
attr_reader :event_bus, :running_test_case, :running_test_step
|
|
9
|
+
private :event_bus, :running_test_case, :running_test_step
|
|
9
10
|
|
|
10
|
-
def initialize(
|
|
11
|
-
@
|
|
11
|
+
def initialize(event_bus)
|
|
12
|
+
@event_bus = event_bus
|
|
12
13
|
end
|
|
13
14
|
|
|
14
15
|
def test_case(test_case, &descend)
|
|
15
16
|
@running_test_case = RunningTestCase.new
|
|
16
17
|
@running_test_step = nil
|
|
17
|
-
|
|
18
|
+
event_bus.test_case_starting(test_case)
|
|
18
19
|
descend.call(self)
|
|
19
|
-
|
|
20
|
+
event_bus.test_case_finished(test_case, running_test_case.result)
|
|
20
21
|
self
|
|
21
22
|
end
|
|
22
23
|
|
|
23
24
|
def test_step(test_step)
|
|
24
25
|
@running_test_step = test_step
|
|
25
|
-
|
|
26
|
+
event_bus.test_step_starting test_step
|
|
26
27
|
step_result = running_test_case.execute(test_step)
|
|
27
|
-
|
|
28
|
+
event_bus.test_step_finished test_step, step_result
|
|
28
29
|
@running_test_step = nil
|
|
29
30
|
self
|
|
30
31
|
end
|
|
31
32
|
|
|
32
33
|
def around_hook(hook, &continue)
|
|
33
34
|
result = running_test_case.execute(hook, &continue)
|
|
34
|
-
|
|
35
|
+
event_bus.test_step_finished running_test_step, result if running_test_step
|
|
35
36
|
@running_test_step = nil
|
|
36
37
|
self
|
|
37
38
|
end
|
|
38
39
|
|
|
39
40
|
def done
|
|
40
|
-
report.done
|
|
41
41
|
self
|
|
42
42
|
end
|
|
43
43
|
|