cucumber-core 4.0.0 → 5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA256:
3
- metadata.gz: 82c21261d3bd32b6f07c066ffc1fc87559b54c80adedacb1b219dc5a6fa607dc
4
- data.tar.gz: 2b11fd0ed43ca9b8aa3b5fc0041c5c341bd2ba2f16324319bde2e0c010fdc308
2
+ SHA1:
3
+ metadata.gz: a5ba16d6f3fc1772d232afd8159f009c8464e586
4
+ data.tar.gz: 69531a546edaa1bd2d51cb66510451043f32e87a
5
5
  SHA512:
6
- metadata.gz: b39751c63f5fda3cbaa4d66fe634e86eadbdbb9efb92b6c4f8bf5bde36259a374c9a41c313a10db9ebc849564e97374c9af715f71a74ec64820b4630c789d256
7
- data.tar.gz: 06c3dc949a7a213e661ac021a793d4177dde521887a538ed291a4031200562ddb8f96ab70c2598ac78cbbcb68b6eee8c0fe67a61f72a894fc396b887b3150e7a
6
+ metadata.gz: ee28cc3b48def98ad79cae99e5b8eb4ded00dd08e550235d2289a89ad2d4a46a2ef58709294089289adb4aed9a69b60093f655879aa1a9e66164e23dba0942f2
7
+ data.tar.gz: 1809cd9af683812a02b68fd82ef97a858bc5529dd9951718cfff8dd940fe8eef2a43eb6d5f78d62148588fe5c2698db031888b382928a64fdc1acbc351ca5685
@@ -1,6 +1,6 @@
1
1
  Please see [CONTRIBUTING.md](https://github.com/cucumber/cucumber/blob/master/CONTRIBUTING.md) on how to contribute to Cucumber.
2
2
 
3
- ## [In Git](https://github.com/cucumber/cucumber-ruby-core/compare/v4.0.0...master)
3
+ ## [In Git](https://github.com/cucumber/cucumber-ruby-core/compare/v5.0.0...master)
4
4
 
5
5
  ### Changed
6
6
 
@@ -22,6 +22,12 @@ Please see [CONTRIBUTING.md](https://github.com/cucumber/cucumber/blob/master/CO
22
22
 
23
23
  * N/A
24
24
 
25
+ ## [5.0.0](https://github.com/cucumber/cucumber-ruby-core/compare/v4.0.0...v5.0.0)
26
+
27
+ ### Changed
28
+
29
+ * Update to use Gherkin v7
30
+
25
31
  ## [4.0.0](https://github.com/cucumber/cucumber-ruby-core/compare/v3.2.0...v4.0.0)
26
32
 
27
33
  ### Changed
data/README.md CHANGED
@@ -1,10 +1,9 @@
1
1
  # cucumber-core
2
2
 
3
3
  [![Chat with us](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/cucumber/cucumber-ruby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
4
- [![Build Status](https://secure.travis-ci.org/cucumber/cucumber-ruby-core.svg)](http://travis-ci.org/cucumber/cucumber-ruby-core)
4
+ [![Build Status](https://travis-ci.org/cucumber/cucumber-ruby-core.svg?branch=master)](https://travis-ci.org/cucumber/cucumber-ruby-core)
5
5
  [![Code Climate](https://codeclimate.com/github/cucumber/cucumber-ruby-core.svg)](https://codeclimate.com/github/cucumber/cucumber-ruby-core)
6
6
  [![Coverage Status](https://coveralls.io/repos/cucumber/cucumber-ruby-core/badge.svg?branch=master)](https://coveralls.io/r/cucumber/cucumber-ruby-core?branch=master)
7
- [![Dependency Status](https://gemnasium.com/cucumber/cucumber-ruby-core.svg)](https://gemnasium.com/cucumber/cucumber-ruby-core)
8
7
 
9
8
  Cucumber Core is the [inner hexagon](http://alistair.cockburn.us/Hexagonal+architecture) for the [Ruby flavour of Cucumber](https://github.com/cucumber/cucumber-ruby).
10
9
 
@@ -31,34 +31,36 @@ module Cucumber
31
31
  private
32
32
 
33
33
  def create_test_case(pickle)
34
- uri = pickle[:uri]
35
- test_steps = pickle[:steps].map { |step| create_test_step(step, uri) }
36
- lines = pickle[:locations].map { |location| location[:line] }.sort.reverse
37
- tags = pickle[:tags].map { |tag| Test::Tag.new(Test::Location.new(uri, tag[:location][:line]), tag[:name]) }
38
- Test::Case.new(pickle[:name], test_steps, Test::Location.new(uri, lines), tags, pickle[:language])
34
+ uri = pickle.uri
35
+ test_steps = pickle.steps.map { |step| create_test_step(step, uri) }
36
+ lines = pickle.locations.map { |location| location.line }.sort.reverse
37
+ tags = pickle.tags.map { |tag| Test::Tag.new(Test::Location.new(uri, tag.location.line), tag.name) }
38
+ Test::Case.new(pickle.name, test_steps, Test::Location.new(uri, lines), tags, pickle.language)
39
39
  end
40
40
 
41
41
  def create_test_step(pickle_step, uri)
42
- lines = pickle_step[:locations].map { |location| location[:line] }.sort.reverse
42
+ lines = pickle_step.locations.map { |location| location.line }.sort.reverse
43
43
  multiline_arg = create_multiline_arg(pickle_step, uri)
44
- Test::Step.new(pickle_step[:text], Test::Location.new(uri, lines), multiline_arg)
44
+ Test::Step.new(pickle_step.text, Test::Location.new(uri, lines), multiline_arg)
45
45
  end
46
46
 
47
47
  def create_multiline_arg(pickle_step, uri)
48
- if !pickle_step[:doc_string].nil?
49
- argument = pickle_step[:doc_string]
50
- Test::DocString.new(
51
- argument[:content],
52
- argument[:content_type],
53
- Test::Location.new(uri, argument[:location][:line])
54
- )
55
- elsif !pickle_step[:data_table].nil?
56
- argument = pickle_step[:data_table]
57
- first_cell = argument[:rows].first[:cells].first
58
- Test::DataTable.new(
59
- argument[:rows].map { |row| row[:cells].map { |cell| cell[:value] } },
60
- Test::Location.new(uri, first_cell[:location][:line])
61
- )
48
+ if pickle_step.argument
49
+ if pickle_step.argument.doc_string
50
+ doc_string = pickle_step.argument.doc_string
51
+ Test::DocString.new(
52
+ doc_string.content,
53
+ doc_string.contentType,
54
+ Test::Location.new(uri, doc_string.location.line)
55
+ )
56
+ elsif pickle_step.argument.data_table
57
+ data_table = pickle_step.argument.data_table
58
+ first_cell = data_table.rows.first.cells.first
59
+ Test::DataTable.new(
60
+ data_table.rows.map { |row| row.cells.map { |cell| cell.value } },
61
+ Test::Location.new(uri, first_cell.location.line)
62
+ )
63
+ end
62
64
  else
63
65
  Test::EmptyMultilineArgument.new
64
66
  end
@@ -11,7 +11,7 @@ module Cucumber
11
11
  class EventBus
12
12
  attr_reader :event_types
13
13
 
14
- # @param [Hash{Symbol => Class}] a hash of event types to use on the bus
14
+ # @param registry [Hash{Symbol => Class}] a hash of event types to use on the bus
15
15
  def initialize(registry = Events.registry)
16
16
  @event_types = registry.freeze
17
17
  @handlers = {}
@@ -19,17 +19,16 @@ module Cucumber
19
19
  messages = ::Gherkin::Gherkin.from_source(document.uri, document.body, {default_dialect: document.language, include_source: false})
20
20
  messages.each do |message|
21
21
  if !message.gherkinDocument.nil?
22
- event_bus.gherkin_source_parsed(message.gherkinDocument.to_hash)
22
+ event_bus.gherkin_source_parsed(message.gherkinDocument)
23
23
  elsif !message.pickle.nil?
24
- receiver.pickle(message.pickle.to_hash)
24
+ receiver.pickle(message.pickle)
25
25
  elsif !message.attachment.nil?
26
- raise message.attachment.data
26
+ # Parse error
27
+ raise Core::Gherkin::ParseError.new("#{document.uri}: #{message.attachment.data}")
27
28
  else
28
29
  raise "Unknown message: #{message.to_hash}"
29
30
  end
30
31
  end
31
- rescue RuntimeError => e
32
- raise Core::Gherkin::ParseError.new("#{document.uri}: #{e.message}")
33
32
  end
34
33
 
35
34
  def done
@@ -3,7 +3,7 @@ module Cucumber
3
3
  module Core
4
4
  class Version
5
5
  def self.to_s
6
- "4.0.0"
6
+ "5.0.0"
7
7
  end
8
8
  end
9
9
  end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+ # With thanks to @myronmarston
3
+ # https://github.com/vcr/vcr/blob/master/spec/capture_warnings.rb
4
+
5
+ module CaptureWarnings
6
+ def report_warnings(&block)
7
+ current_dir = Dir.pwd
8
+ warnings, errors = capture_error(&block).partition { |line| line.include?('warning') }
9
+ project_warnings, other_warnings = warnings.uniq.partition { |line| line.include?(current_dir) }
10
+
11
+ if errors.any?
12
+ puts errors.join("\n")
13
+ end
14
+
15
+ if other_warnings.any?
16
+ puts "#{ other_warnings.count } non-cucumber-core warnings detected, set VIEW_OTHER_WARNINGS=true to see them."
17
+ print_warnings('other', other_warnings) if ENV['VIEW_OTHER_WARNINGS']
18
+ end
19
+
20
+ # Until they fix https://bugs.ruby-lang.org/issues/10661
21
+ if RUBY_VERSION == "2.2.0"
22
+ project_warnings = project_warnings.reject { |w| w =~ /warning: possible reference to past scope/ }
23
+ end
24
+
25
+ if project_warnings.any?
26
+ puts "#{ project_warnings.count } cucumber-core warnings detected"
27
+ print_warnings('cucumber-core', project_warnings)
28
+ fail "Please remove all cucumber-core warnings."
29
+ end
30
+
31
+ ensure_system_exit_if_required
32
+ end
33
+
34
+ def capture_error(&block)
35
+ old_stderr = STDERR.clone
36
+ pipe_r, pipe_w = IO.pipe
37
+ pipe_r.sync = true
38
+ error = String.new
39
+ reader = Thread.new do
40
+ begin
41
+ loop do
42
+ error << pipe_r.readpartial(1024)
43
+ end
44
+ rescue EOFError
45
+ end
46
+ end
47
+ STDERR.reopen(pipe_w)
48
+ block.call
49
+ ensure
50
+ capture_system_exit
51
+ STDERR.reopen(old_stderr)
52
+ pipe_w.close
53
+ reader.join
54
+ return error.split("\n")
55
+ end
56
+
57
+ def print_warnings(type, warnings)
58
+ puts
59
+ puts "-" * 30 + " #{type} warnings: " + "-" * 30
60
+ puts
61
+ puts warnings.join("\n")
62
+ puts
63
+ puts "-" * 75
64
+ puts
65
+ end
66
+
67
+ def ensure_system_exit_if_required
68
+ raise @system_exit if @system_exit
69
+ end
70
+
71
+ def capture_system_exit
72
+ @system_exit = $!
73
+ end
74
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+ require 'simplecov'
3
+ formatters = [ SimpleCov::Formatter::HTMLFormatter ]
4
+
5
+ if ENV['TRAVIS']
6
+ require 'coveralls'
7
+ formatters << Coveralls::SimpleCov::Formatter
8
+ end
9
+
10
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(formatters)
11
+ SimpleCov.start
@@ -0,0 +1,178 @@
1
+ # frozen_string_literal: true
2
+ require 'cucumber/core'
3
+ require 'cucumber/core/compiler'
4
+ require 'cucumber/core/gherkin/writer'
5
+
6
+ module Cucumber::Core
7
+ describe Compiler do
8
+ include Gherkin::Writer
9
+ include Cucumber::Core
10
+
11
+ def self.stubs(*names)
12
+ names.each do |name|
13
+ let(name) { double(name.to_s) }
14
+ end
15
+ end
16
+
17
+ it "compiles a feature with a single scenario" do
18
+ gherkin_documents = [
19
+ gherkin do
20
+ feature do
21
+ scenario do
22
+ step 'passing'
23
+ end
24
+ end
25
+ end
26
+ ]
27
+ compile(gherkin_documents) do |visitor|
28
+ expect( visitor ).to receive(:test_case).once.ordered.and_yield(visitor)
29
+ expect( visitor ).to receive(:test_step).once.ordered
30
+ expect( visitor ).to receive(:done).once.ordered
31
+ end
32
+ end
33
+
34
+ it "compiles a feature with a background" do
35
+ gherkin_documents = [
36
+ gherkin do
37
+ feature do
38
+ background do
39
+ step 'passing'
40
+ end
41
+
42
+ scenario do
43
+ step 'passing'
44
+ end
45
+ end
46
+ end
47
+ ]
48
+ compile(gherkin_documents) do |visitor|
49
+ expect( visitor ).to receive(:test_case).once.ordered.and_yield(visitor)
50
+ expect( visitor ).to receive(:test_step).exactly(2).times.ordered
51
+ expect( visitor ).to receive(:done).once.ordered
52
+ end
53
+ end
54
+
55
+ it "compiles multiple features" do
56
+ gherkin_documents = [
57
+ gherkin do
58
+ feature do
59
+ background do
60
+ step 'passing'
61
+ end
62
+ scenario do
63
+ step 'passing'
64
+ end
65
+ end
66
+ end,
67
+ gherkin do
68
+ feature do
69
+ background do
70
+ step 'passing'
71
+ end
72
+ scenario do
73
+ step 'passing'
74
+ end
75
+ end
76
+ end
77
+ ]
78
+ compile(gherkin_documents) do |visitor|
79
+ expect( visitor ).to receive(:test_case).once.ordered
80
+ expect( visitor ).to receive(:test_step).twice.ordered
81
+ expect( visitor ).to receive(:test_case).once.ordered
82
+ expect( visitor ).to receive(:test_step).twice.ordered
83
+ expect( visitor ).to receive(:done).once
84
+ end
85
+ end
86
+
87
+ context "compiling scenario outlines" do
88
+ it "compiles a scenario outline to test cases" do
89
+ gherkin_documents = [
90
+ gherkin do
91
+ feature do
92
+ background do
93
+ step 'passing'
94
+ end
95
+
96
+ scenario_outline do
97
+ step 'passing <arg>'
98
+ step 'passing'
99
+
100
+ examples 'examples 1' do
101
+ row 'arg'
102
+ row '1'
103
+ row '2'
104
+ end
105
+
106
+ examples 'examples 2' do
107
+ row 'arg'
108
+ row 'a'
109
+ end
110
+ end
111
+ end
112
+ end
113
+ ]
114
+ compile(gherkin_documents) do |visitor|
115
+ expect( visitor ).to receive(:test_case).exactly(3).times.and_yield(visitor)
116
+ expect( visitor ).to receive(:test_step).exactly(9).times
117
+ expect( visitor ).to receive(:done).once
118
+ end
119
+ end
120
+
121
+ it 'replaces arguments correctly when generating test steps' do
122
+ gherkin_documents = [
123
+ gherkin do
124
+ feature do
125
+ scenario_outline do
126
+ step 'passing <arg1> with <arg2>'
127
+ step 'as well as <arg3>'
128
+
129
+ examples do
130
+ row 'arg1', 'arg2', 'arg3'
131
+ row '1', '2', '3'
132
+ end
133
+ end
134
+ end
135
+ end
136
+ ]
137
+
138
+ compile(gherkin_documents) do |visitor|
139
+ expect( visitor ).to receive(:test_step) do |test_step|
140
+ expect(test_step.text).to eq 'passing 1 with 2'
141
+ end.once.ordered
142
+
143
+ expect( visitor ).to receive(:test_step) do |test_step|
144
+ expect(test_step.text).to eq 'as well as 3'
145
+ end.once.ordered
146
+
147
+ expect( visitor ).to receive(:done).once.ordered
148
+ end
149
+ end
150
+ end
151
+
152
+ context 'empty scenarios' do
153
+ it 'does create test cases for them' do
154
+ gherkin_documents = [
155
+ gherkin do
156
+ feature do
157
+ scenario do
158
+ end
159
+ end
160
+ end
161
+ ]
162
+ compile(gherkin_documents) do |visitor|
163
+ expect( visitor ).to receive(:test_case).once.ordered
164
+ expect( visitor ).to receive(:done).once.ordered
165
+ end
166
+ end
167
+ end
168
+
169
+ def compile(gherkin_documents)
170
+ visitor = double
171
+ allow( visitor ).to receive(:test_suite).and_yield(visitor)
172
+ allow( visitor ).to receive(:test_case).and_yield(visitor)
173
+ yield visitor
174
+ super(gherkin_documents, visitor)
175
+ end
176
+
177
+ end
178
+ end
@@ -0,0 +1,163 @@
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
+ it "sends events that were broadcast before you subscribed" do
140
+ event_bus.test_event :some_attribute
141
+ event_bus.another_test_event
142
+
143
+ received_payload = nil
144
+ event_bus.on(:test_event) do |event|
145
+ received_payload = event
146
+ end
147
+
148
+ expect(received_payload.some_attribute).to eq(:some_attribute)
149
+ end
150
+
151
+ end
152
+
153
+ it "will let you inspect the registry" do
154
+ expect(event_bus.event_types[:test_event]).to eq Events::TestEvent
155
+ end
156
+
157
+ it "won't let you modify the registry" do
158
+ expect { event_bus.event_types[:foo] = :bar }.to raise_error(RuntimeError)
159
+ end
160
+
161
+ end
162
+ end
163
+ end