cucumber-core 4.0.0 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
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