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.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE.md +48 -0
  3. data/.github/PULL_REQUEST_TEMPLATE.md +39 -0
  4. data/.travis.yml +2 -3
  5. data/HISTORY.md +12 -1
  6. data/README.md +37 -43
  7. data/cucumber-core.gemspec +2 -0
  8. data/lib/cucumber/core.rb +5 -2
  9. data/lib/cucumber/core/ast.rb +1 -0
  10. data/lib/cucumber/core/ast/background.rb +1 -0
  11. data/lib/cucumber/core/ast/comment.rb +1 -0
  12. data/lib/cucumber/core/ast/data_table.rb +1 -0
  13. data/lib/cucumber/core/ast/describes_itself.rb +1 -0
  14. data/lib/cucumber/core/ast/doc_string.rb +1 -0
  15. data/lib/cucumber/core/ast/empty_background.rb +1 -0
  16. data/lib/cucumber/core/ast/empty_multiline_argument.rb +1 -0
  17. data/lib/cucumber/core/ast/examples_table.rb +1 -0
  18. data/lib/cucumber/core/ast/feature.rb +1 -0
  19. data/lib/cucumber/core/ast/location.rb +1 -0
  20. data/lib/cucumber/core/ast/names.rb +1 -0
  21. data/lib/cucumber/core/ast/outline_step.rb +1 -0
  22. data/lib/cucumber/core/ast/scenario.rb +1 -0
  23. data/lib/cucumber/core/ast/scenario_outline.rb +1 -0
  24. data/lib/cucumber/core/ast/step.rb +1 -0
  25. data/lib/cucumber/core/ast/tag.rb +1 -0
  26. data/lib/cucumber/core/compiler.rb +1 -0
  27. data/lib/cucumber/core/event.rb +63 -0
  28. data/lib/cucumber/core/event_bus.rb +64 -0
  29. data/lib/cucumber/core/events.rb +69 -0
  30. data/lib/cucumber/core/filter.rb +1 -0
  31. data/lib/cucumber/core/gherkin/ast_builder.rb +14 -5
  32. data/lib/cucumber/core/gherkin/document.rb +6 -4
  33. data/lib/cucumber/core/gherkin/parser.rb +6 -4
  34. data/lib/cucumber/core/gherkin/tag_expression.rb +1 -0
  35. data/lib/cucumber/core/gherkin/writer.rb +1 -0
  36. data/lib/cucumber/core/gherkin/writer/helpers.rb +1 -0
  37. data/lib/cucumber/core/platform.rb +1 -0
  38. data/lib/cucumber/core/report/summary.rb +30 -6
  39. data/lib/cucumber/core/test/action.rb +1 -0
  40. data/lib/cucumber/core/test/around_hook.rb +1 -0
  41. data/lib/cucumber/core/test/case.rb +13 -0
  42. data/lib/cucumber/core/test/filters.rb +1 -0
  43. data/lib/cucumber/core/test/filters/locations_filter.rb +1 -0
  44. data/lib/cucumber/core/test/filters/name_filter.rb +1 -0
  45. data/lib/cucumber/core/test/filters/tag_filter.rb +1 -0
  46. data/lib/cucumber/core/test/result.rb +5 -0
  47. data/lib/cucumber/core/test/runner.rb +10 -10
  48. data/lib/cucumber/core/test/step.rb +1 -0
  49. data/lib/cucumber/core/test/timer.rb +1 -0
  50. data/lib/cucumber/core/version.rb +2 -1
  51. data/spec/capture_warnings.rb +3 -2
  52. data/spec/coverage.rb +1 -0
  53. data/spec/cucumber/core/ast/background_spec.rb +1 -0
  54. data/spec/cucumber/core/ast/data_table_spec.rb +1 -0
  55. data/spec/cucumber/core/ast/doc_string_spec.rb +2 -1
  56. data/spec/cucumber/core/ast/empty_multiline_argument_spec.rb +1 -0
  57. data/spec/cucumber/core/ast/examples_table_spec.rb +1 -0
  58. data/spec/cucumber/core/ast/location_spec.rb +1 -0
  59. data/spec/cucumber/core/ast/outline_step_spec.rb +1 -0
  60. data/spec/cucumber/core/ast/step_spec.rb +1 -0
  61. data/spec/cucumber/core/compiler_spec.rb +1 -0
  62. data/spec/cucumber/core/event_bus_spec.rb +151 -0
  63. data/spec/cucumber/core/event_spec.rb +40 -0
  64. data/spec/cucumber/core/filter_spec.rb +1 -0
  65. data/spec/cucumber/core/gherkin/parser_spec.rb +24 -0
  66. data/spec/cucumber/core/gherkin/writer_spec.rb +1 -0
  67. data/spec/cucumber/core/report/summary_spec.rb +127 -0
  68. data/spec/cucumber/core/test/action_spec.rb +1 -0
  69. data/spec/cucumber/core/test/case_spec.rb +26 -2
  70. data/spec/cucumber/core/test/duration_matcher.rb +2 -1
  71. data/spec/cucumber/core/test/filters/locations_filter_spec.rb +2 -0
  72. data/spec/cucumber/core/test/result_spec.rb +5 -0
  73. data/spec/cucumber/core/test/runner_spec.rb +44 -50
  74. data/spec/cucumber/core/test/step_spec.rb +1 -0
  75. data/spec/cucumber/core/test/timer_spec.rb +1 -0
  76. data/spec/cucumber/core_spec.rb +68 -8
  77. data/spec/readme_spec.rb +1 -0
  78. data/spec/report_api_spy.rb +1 -0
  79. metadata +42 -3
@@ -1,8 +1,9 @@
1
+ # frozen_string_literal: true
1
2
  module Cucumber
2
3
  module Core
3
4
  class Version
4
5
  def self.to_s
5
- "1.5.0"
6
+ "2.0.0"
6
7
  end
7
8
  end
8
9
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  # With thanks to @myronmarston
2
3
  # https://github.com/vcr/vcr/blob/master/spec/capture_warnings.rb
3
4
 
@@ -22,7 +23,7 @@ module CaptureWarnings
22
23
  end
23
24
 
24
25
  if project_warnings.any?
25
- puts "#{ project_warnings.count } cucumber-core warnings detected"
26
+ puts "#{ project_warnings.count } cucumber-core warnings detected"
26
27
  print_warnings('cucumber-core', project_warnings)
27
28
  fail "Please remove all cucumber-core warnings."
28
29
  end
@@ -34,7 +35,7 @@ module CaptureWarnings
34
35
  old_stderr = STDERR.clone
35
36
  pipe_r, pipe_w = IO.pipe
36
37
  pipe_r.sync = true
37
- error = ""
38
+ error = String.new
38
39
  reader = Thread.new do
39
40
  begin
40
41
  loop do
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'simplecov'
2
3
  formatters = [ SimpleCov::Formatter::HTMLFormatter ]
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'cucumber/core/ast/background'
2
3
  module Cucumber::Core::Ast
3
4
  describe Background do
@@ -1,4 +1,5 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
2
3
  require 'cucumber/core/ast/data_table'
3
4
 
4
5
  module Cucumber
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'cucumber/core/ast/location'
2
3
  require 'cucumber/core/ast/doc_string'
3
4
  require 'unindent'
@@ -68,7 +69,7 @@ module Cucumber
68
69
  end
69
70
 
70
71
  context 'quacking like a String' do
71
- let(:content) { 'content' }
72
+ let(:content) { String.new('content') }
72
73
  let(:content_type) { 'text/plain' }
73
74
 
74
75
  it 'delegates #encoding to the content string' do
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'cucumber/core/ast/location'
2
3
  require 'cucumber/core/ast/empty_multiline_argument'
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'cucumber/core/ast/examples_table'
2
3
 
3
4
  module Cucumber::Core::Ast
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'cucumber/core/ast/location'
2
3
 
3
4
  module Cucumber::Core::Ast
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'cucumber/core/ast/outline_step'
2
3
  require 'cucumber/core/ast/examples_table'
3
4
  require 'cucumber/core/ast/data_table'
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'cucumber/core/ast/step'
2
3
  require 'cucumber/core/ast/outline_step'
3
4
  require 'cucumber/core/ast/empty_multiline_argument'
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'cucumber/core'
2
3
  require 'cucumber/core/compiler'
3
4
  require 'cucumber/core/gherkin/writer'
@@ -0,0 +1,151 @@
1
+ require "cucumber/core/event_bus"
2
+
3
+ module Cucumber
4
+ module Core
5
+ module Events
6
+
7
+ class TestEvent < Core::Event.new(:some_attribute)
8
+ end
9
+
10
+ AnotherTestEvent = Core::Event.new
11
+
12
+ UnregisteredEvent = Core::Event.new
13
+ end
14
+
15
+ describe EventBus do
16
+ let(:event_bus) { EventBus.new(registry) }
17
+ let(:registry) { { test_event: Events::TestEvent, another_test_event: Events::AnotherTestEvent } }
18
+
19
+ context "broadcasting events" do
20
+
21
+ it "can broadcast by calling a method named after the event ID" do
22
+ called = false
23
+ event_bus.on(:test_event) {called = true }
24
+ event_bus.test_event
25
+ expect(called).to be true
26
+ end
27
+
28
+ it "can broadcast by calling the `broadcast` method with an instance of the event type" do
29
+ called = false
30
+ event_bus.on(:test_event) {called = true }
31
+ event_bus.broadcast(Events::TestEvent.new(:some_attribute))
32
+ expect(called).to be true
33
+ end
34
+
35
+ it "calls a subscriber for an event, passing details of the event" do
36
+ received_payload = nil
37
+ event_bus.on :test_event do |event|
38
+ received_payload = event
39
+ end
40
+
41
+ event_bus.test_event :some_attribute
42
+
43
+ expect(received_payload.some_attribute).to eq(:some_attribute)
44
+ end
45
+
46
+ it "does not call subscribers for other events" do
47
+ handler_called = false
48
+ event_bus.on :test_event do
49
+ handler_called = true
50
+ end
51
+
52
+ event_bus.another_test_event
53
+
54
+ expect(handler_called).to eq(false)
55
+ end
56
+
57
+ it "broadcasts to multiple subscribers" do
58
+ received_events = []
59
+ event_bus.on :test_event do
60
+ received_events << :event
61
+ end
62
+ event_bus.on :test_event do
63
+ received_events << :event
64
+ end
65
+
66
+ event_bus.test_event(:some_attribute)
67
+
68
+ expect(received_events.length).to eq 2
69
+ end
70
+
71
+ it "raises an error when given an event to broadcast that it doesn't recognise" do
72
+ expect { event_bus.some_unknown_event }.to raise_error(NameError)
73
+ end
74
+
75
+ context "#broadcast method" do
76
+ it "must be passed an instance of a registered event type" do
77
+ expect {
78
+ event_bus.broadcast Events::UnregisteredEvent
79
+ }.to raise_error(ArgumentError)
80
+ end
81
+ end
82
+
83
+ end
84
+
85
+ context "subscribing to events" do
86
+ it "allows subscription by symbol (Event ID)" do
87
+ received_payload = nil
88
+ event_bus.on(:test_event) do |event|
89
+ received_payload = event
90
+ end
91
+
92
+ event_bus.test_event :some_attribute
93
+
94
+ expect(received_payload.some_attribute).to eq(:some_attribute)
95
+ end
96
+
97
+ it "raises an error if you use an unknown Event ID" do
98
+ expect {
99
+ event_bus.on(:some_unknown_event) { :whatever }
100
+ }.to raise_error(ArgumentError)
101
+ end
102
+
103
+ it "allows handlers that are objects with a `call` method" do
104
+ class MyHandler
105
+ attr_reader :received_payload
106
+
107
+ def call(event)
108
+ @received_payload = event
109
+ end
110
+ end
111
+
112
+ handler = MyHandler.new
113
+ event_bus.on(:test_event, handler)
114
+
115
+ event_bus.test_event :some_attribute
116
+
117
+ expect(handler.received_payload.some_attribute).to eq :some_attribute
118
+ end
119
+
120
+ it "allows handlers that are procs" do
121
+ class MyProccyHandler
122
+ attr_reader :received_payload
123
+
124
+ def initialize(event_bus)
125
+ event_bus.on :test_event, &method(:on_test_event)
126
+ end
127
+
128
+ def on_test_event(event)
129
+ @received_payload = event
130
+ end
131
+ end
132
+
133
+ handler = MyProccyHandler.new(event_bus)
134
+
135
+ event_bus.test_event :some_attribute
136
+ expect(handler.received_payload.some_attribute).to eq :some_attribute
137
+ end
138
+
139
+ end
140
+
141
+ it "will let you inspect the registry" do
142
+ expect(event_bus.event_types[:test_event]).to eq Events::TestEvent
143
+ end
144
+
145
+ it "won't let you modify the registry" do
146
+ expect { event_bus.event_types[:foo] = :bar }.to raise_error(RuntimeError)
147
+ end
148
+
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,40 @@
1
+ require 'cucumber/core/event'
2
+
3
+ module Cucumber
4
+ module Core
5
+ describe Event do
6
+
7
+ describe ".new" do
8
+ it "generates new types of events" do
9
+ my_event_type = Event.new
10
+ my_event = my_event_type.new
11
+ expect(my_event).to be_kind_of(Core::Event)
12
+ end
13
+
14
+ it "generates events with attributes" do
15
+ my_event_type = Event.new(:foo, :bar)
16
+ my_event = my_event_type.new(1,2)
17
+ expect(my_event.attributes).to eq [1, 2]
18
+ expect(my_event.foo).to eq 1
19
+ expect(my_event.bar).to eq 2
20
+ end
21
+ end
22
+
23
+ describe "a generated event" do
24
+ class MyEventType < Event.new(:foo, :bar)
25
+ end
26
+
27
+ it "can be converted to a hash" do
28
+ my_event = MyEventType.new(1,2)
29
+ expect(my_event.to_h).to eq foo: 1, bar: 2
30
+ end
31
+
32
+ it "has an event_id" do
33
+ expect(MyEventType.event_id).to eq :my_event_type
34
+ expect(MyEventType.new(1,2).event_id).to eq :my_event_type
35
+ end
36
+ end
37
+ end
38
+
39
+ end
40
+ end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'cucumber/core/gherkin/writer'
2
3
  require 'cucumber/core'
3
4
  require 'cucumber/core/filter'
@@ -1,4 +1,5 @@
1
1
  # -*- encoding: utf-8 -*-
2
+ # frozen_string_literal: true
2
3
  require 'cucumber/core/gherkin/parser'
3
4
  require 'cucumber/core/gherkin/writer'
4
5
 
@@ -223,6 +224,29 @@ module Cucumber
223
224
 
224
225
  end
225
226
 
227
+ context "a Scenario Outline with an empty examples table" do
228
+ source do
229
+ feature do
230
+ scenario_outline 'outline name' do
231
+ step 'passing <arg>'
232
+
233
+ examples do
234
+ end
235
+ end
236
+ end
237
+ end
238
+
239
+ it "creates an examples table node but no example table rows" do
240
+ allow( visitor ).to receive(:feature).and_yield(visitor)
241
+ allow( visitor ).to receive(:scenario_outline).and_yield(visitor)
242
+ allow( visitor ).to receive(:outline_step)
243
+ expect( visitor ).to receive(:examples_table).and_yield(visitor)
244
+ expect( visitor ).to receive(:examples_table_row).exactly(0).times
245
+ feature.describe_to(visitor)
246
+ end
247
+
248
+ end
249
+
226
250
  context "a Scenario Outline with no Examples" do
227
251
  source do
228
252
  feature(language: 'not-a-language')
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'cucumber/core/gherkin/writer'
2
3
  require 'unindent'
3
4
 
@@ -0,0 +1,127 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require 'cucumber/core/event_bus'
3
+ require 'cucumber/core/events'
4
+ require 'cucumber/core/report/summary'
5
+ require 'cucumber/core/test/result'
6
+
7
+ module Cucumber::Core::Report
8
+ describe Summary do
9
+ let(:event_bus) { ::Cucumber::Core::EventBus.new(registry) }
10
+ let(:registry) { ::Cucumber::Core::Events.registry }
11
+ let(:passed_result) { ::Cucumber::Core::Test::Result::Passed.new(duration) }
12
+ let(:failed_result) { ::Cucumber::Core::Test::Result::Failed.new(duration, exception) }
13
+ let(:pending_result) { ::Cucumber::Core::Test::Result::Pending.new(duration) }
14
+ let(:skipped_result) { ::Cucumber::Core::Test::Result::Skipped.new(duration) }
15
+ let(:undefined_result) { ::Cucumber::Core::Test::Result::Undefined.new(duration) }
16
+ let(:duration) { double }
17
+ let(:exception) { double }
18
+
19
+ before(:each) { @summary = Summary.new(event_bus) }
20
+
21
+ context "test case summary" do
22
+ let(:test_case) { double }
23
+
24
+ it "counts passed test cases" do
25
+ event_bus.send(:test_case_finished, test_case, passed_result)
26
+
27
+ expect( @summary.test_cases.total(:passed) ).to eq(1)
28
+ expect( @summary.test_cases.total ).to eq(1)
29
+ end
30
+
31
+ it "counts failed test cases" do
32
+ event_bus.send(:test_case_finished, test_case, failed_result)
33
+
34
+ expect( @summary.test_cases.total(:failed) ).to eq(1)
35
+ expect( @summary.test_cases.total ).to eq(1)
36
+ end
37
+
38
+ it "counts pending test cases" do
39
+ event_bus.send(:test_case_finished, test_case, pending_result)
40
+
41
+ expect( @summary.test_cases.total(:pending) ).to eq(1)
42
+ expect( @summary.test_cases.total ).to eq(1)
43
+ end
44
+
45
+ it "counts skipped test cases" do
46
+ event_bus.send(:test_case_finished, test_case, skipped_result)
47
+
48
+ expect( @summary.test_cases.total(:skipped) ).to eq(1)
49
+ expect( @summary.test_cases.total ).to eq(1)
50
+ end
51
+
52
+ it "counts undefined test cases" do
53
+ event_bus.send(:test_case_finished, test_case, undefined_result)
54
+
55
+ expect( @summary.test_cases.total(:undefined) ).to eq(1)
56
+ expect( @summary.test_cases.total ).to eq(1)
57
+ end
58
+ end
59
+
60
+ context "test step summary" do
61
+ context "with test steps from gherkin steps" do
62
+ let(:test_step) { double }
63
+
64
+ before(:each) do
65
+ step = double
66
+ expect( step ).to receive(:describe_to) do |visitor|
67
+ visitor.step
68
+ end
69
+ expect( test_step ).to receive(:source).and_return([step])
70
+ end
71
+
72
+ it "counts passed test steps" do
73
+ event_bus.send(:test_step_finished, test_step, passed_result)
74
+
75
+ expect( @summary.test_steps.total(:passed) ).to eq(1)
76
+ expect( @summary.test_steps.total ).to eq(1)
77
+ end
78
+
79
+ it "counts failed test cases" do
80
+ event_bus.send(:test_step_finished, test_step, failed_result)
81
+
82
+ expect( @summary.test_steps.total(:failed) ).to eq(1)
83
+ expect( @summary.test_steps.total ).to eq(1)
84
+ end
85
+
86
+ it "counts pending test cases" do
87
+ event_bus.send(:test_step_finished, test_step, pending_result)
88
+
89
+ expect( @summary.test_steps.total(:pending) ).to eq(1)
90
+ expect( @summary.test_steps.total ).to eq(1)
91
+ end
92
+
93
+ it "counts skipped test cases" do
94
+ event_bus.send(:test_step_finished, test_step, skipped_result)
95
+
96
+ expect( @summary.test_steps.total(:skipped) ).to eq(1)
97
+ expect( @summary.test_steps.total ).to eq(1)
98
+ end
99
+
100
+ it "counts undefined test cases" do
101
+ event_bus.send(:test_step_finished, test_step, undefined_result)
102
+
103
+ expect( @summary.test_steps.total(:undefined) ).to eq(1)
104
+ expect( @summary.test_steps.total ).to eq(1)
105
+ end
106
+ end
107
+
108
+ context "with test steps not from gherkin steps" do
109
+ let(:test_step) { double }
110
+
111
+ before(:each) do
112
+ step = double
113
+ expect( step ).to receive(:describe_to) do |visitor|
114
+ visitor.not_step
115
+ end
116
+ expect( test_step ).to receive(:source).and_return([step])
117
+ end
118
+
119
+ it "ignores test steps not defined by gherkin steps" do
120
+ event_bus.send(:test_step_finished, test_step, passed_result)
121
+
122
+ expect( @summary.test_steps.total ).to eq(0)
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end