cucumber-core 1.0.0.beta.3 → 1.0.0.beta.4
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/.yardopts +6 -0
- data/HISTORY.md +20 -0
- data/README.md +121 -3
- data/cucumber-core.gemspec +1 -0
- data/lib/cucumber/core.rb +19 -13
- data/lib/cucumber/core/ast/data_table.rb +1 -1
- data/lib/cucumber/core/ast/examples_table.rb +5 -4
- data/lib/cucumber/core/ast/feature.rb +7 -1
- data/lib/cucumber/core/ast/scenario.rb +1 -1
- data/lib/cucumber/core/ast/step.rb +2 -2
- data/lib/cucumber/core/compiler.rb +7 -0
- data/lib/cucumber/core/gherkin/ast_builder.rb +15 -10
- data/lib/cucumber/core/platform.rb +0 -15
- data/lib/cucumber/core/report/summary.rb +26 -0
- data/lib/cucumber/core/test/case.rb +1 -1
- data/lib/cucumber/core/test/filters.rb +2 -47
- data/lib/cucumber/core/test/filters/locations_filter.rb +21 -0
- data/lib/cucumber/core/test/filters/name_filter.rb +27 -0
- data/lib/cucumber/core/test/hooks.rb +17 -0
- data/lib/cucumber/core/test/mapper.rb +14 -2
- data/lib/cucumber/core/test/result.rb +40 -30
- data/lib/cucumber/core/test/timer.rb +3 -1
- data/lib/cucumber/core/version.rb +1 -1
- data/spec/cucumber/core/ast/examples_table_spec.rb +19 -12
- data/spec/cucumber/core/ast/outline_step_spec.rb +3 -3
- data/spec/cucumber/core/gherkin/parser_spec.rb +18 -0
- data/spec/cucumber/core/test/action_spec.rb +3 -2
- data/spec/cucumber/core/test/duration_matcher.rb +19 -0
- data/spec/cucumber/core/test/mapper_spec.rb +30 -10
- data/spec/cucumber/core/test/result_spec.rb +47 -5
- data/spec/cucumber/core/test/runner_spec.rb +3 -2
- data/spec/cucumber/core/test/timer_spec.rb +13 -0
- data/spec/cucumber/core_spec.rb +33 -49
- data/spec/readme_spec.rb +36 -0
- metadata +26 -3
@@ -4,27 +4,12 @@ require 'rbconfig'
|
|
4
4
|
|
5
5
|
module Cucumber
|
6
6
|
unless defined?(Cucumber::VERSION)
|
7
|
-
VERSION = '2.0'
|
8
|
-
BINARY = File.expand_path(File.dirname(__FILE__) + '/../../bin/cucumber')
|
9
|
-
LIBDIR = File.expand_path(File.dirname(__FILE__) + '/../../lib')
|
10
7
|
JRUBY = defined?(JRUBY_VERSION)
|
11
8
|
IRONRUBY = defined?(RUBY_ENGINE) && RUBY_ENGINE == "ironruby"
|
12
9
|
WINDOWS = RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
|
13
10
|
OS_X = RbConfig::CONFIG['host_os'] =~ /darwin/
|
14
11
|
WINDOWS_MRI = WINDOWS && !JRUBY && !IRONRUBY
|
15
|
-
RAILS = defined?(Rails)
|
16
|
-
RUBY_BINARY = File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name'])
|
17
12
|
RUBY_2_0 = RUBY_VERSION =~ /^2\.0/
|
18
13
|
RUBY_1_9 = RUBY_VERSION =~ /^1\.9/
|
19
|
-
|
20
|
-
class << self
|
21
|
-
attr_accessor :use_full_backtrace
|
22
|
-
|
23
|
-
# @private
|
24
|
-
def file_mode(m, encoding="UTF-8")
|
25
|
-
"#{m}:#{encoding}"
|
26
|
-
end
|
27
|
-
end
|
28
|
-
self.use_full_backtrace = false
|
29
14
|
end
|
30
15
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Cucumber
|
2
|
+
module Core
|
3
|
+
module Report
|
4
|
+
class Summary
|
5
|
+
attr_reader :test_cases, :test_steps
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@test_cases = Test::Result::Summary.new
|
9
|
+
@test_steps = Test::Result::Summary.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def after_test_case(test_case, result)
|
13
|
+
result.describe_to test_cases
|
14
|
+
end
|
15
|
+
|
16
|
+
def after_test_step(test_step, result)
|
17
|
+
result.describe_to test_steps
|
18
|
+
end
|
19
|
+
|
20
|
+
def method_missing(*)
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -6,7 +6,7 @@ module Cucumber
|
|
6
6
|
module Test
|
7
7
|
class Case
|
8
8
|
include Cucumber.initializer(:test_steps, :source, :around_hooks)
|
9
|
-
attr_reader :source
|
9
|
+
attr_reader :source, :test_steps
|
10
10
|
|
11
11
|
def initialize(test_steps, source, around_hooks = [])
|
12
12
|
super(test_steps, source, around_hooks)
|
@@ -1,48 +1,3 @@
|
|
1
|
+
require 'cucumber/core/test/filters/locations_filter'
|
2
|
+
require 'cucumber/core/test/filters/name_filter'
|
1
3
|
require 'cucumber/core/test/filters/tag_filter'
|
2
|
-
module Cucumber
|
3
|
-
module Core
|
4
|
-
module Test
|
5
|
-
|
6
|
-
class LocationsFilter
|
7
|
-
def initialize(locations, receiver)
|
8
|
-
@receiver = receiver
|
9
|
-
@locations = locations
|
10
|
-
end
|
11
|
-
|
12
|
-
def test_case(test_case)
|
13
|
-
if test_case.match_locations?(@locations)
|
14
|
-
test_case.describe_to @receiver
|
15
|
-
end
|
16
|
-
self
|
17
|
-
end
|
18
|
-
|
19
|
-
def done
|
20
|
-
@receiver.done
|
21
|
-
self
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
class NameFilter
|
26
|
-
include Cucumber.initializer(:name_regexps, :receiver)
|
27
|
-
|
28
|
-
def test_case(test_case)
|
29
|
-
if accept?(test_case)
|
30
|
-
test_case.describe_to(receiver)
|
31
|
-
end
|
32
|
-
self
|
33
|
-
end
|
34
|
-
|
35
|
-
def done
|
36
|
-
@receiver.done
|
37
|
-
self
|
38
|
-
end
|
39
|
-
|
40
|
-
private
|
41
|
-
|
42
|
-
def accept?(test_case)
|
43
|
-
name_regexps.empty? || name_regexps.any? { |name_regexp| test_case.match_name?(name_regexp) }
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Cucumber
|
2
|
+
module Core
|
3
|
+
module Test
|
4
|
+
class LocationsFilter
|
5
|
+
include Cucumber.initializer(:locations, :receiver)
|
6
|
+
|
7
|
+
def test_case(test_case)
|
8
|
+
if test_case.match_locations?(@locations)
|
9
|
+
test_case.describe_to @receiver
|
10
|
+
end
|
11
|
+
self
|
12
|
+
end
|
13
|
+
|
14
|
+
def done
|
15
|
+
@receiver.done
|
16
|
+
self
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Cucumber
|
2
|
+
module Core
|
3
|
+
module Test
|
4
|
+
class NameFilter
|
5
|
+
include Cucumber.initializer(:name_regexps, :receiver)
|
6
|
+
|
7
|
+
def test_case(test_case)
|
8
|
+
if accept?(test_case)
|
9
|
+
test_case.describe_to(receiver)
|
10
|
+
end
|
11
|
+
self
|
12
|
+
end
|
13
|
+
|
14
|
+
def done
|
15
|
+
@receiver.done
|
16
|
+
self
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def accept?(test_case)
|
22
|
+
name_regexps.empty? || name_regexps.any? { |name_regexp| test_case.match_name?(name_regexp) }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -53,6 +53,23 @@ module Cucumber
|
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
56
|
+
class BeforeStepHook
|
57
|
+
include Cucumber.initializer(:location)
|
58
|
+
public :location
|
59
|
+
|
60
|
+
def name
|
61
|
+
"BeforeStep hook"
|
62
|
+
end
|
63
|
+
|
64
|
+
def match_locations?(queried_locations)
|
65
|
+
queried_locations.any? { |other_location| other_location.match?(location) }
|
66
|
+
end
|
67
|
+
|
68
|
+
def describe_to(visitor, *args)
|
69
|
+
visitor.before_step_hook(self, *args)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
56
73
|
class AfterStepHook
|
57
74
|
include Cucumber.initializer(:location)
|
58
75
|
public :location
|
@@ -33,7 +33,7 @@ module Cucumber
|
|
33
33
|
hook_factory = HookFactory.new(test_step.source)
|
34
34
|
mapper = StepMapper.new(test_step)
|
35
35
|
test_step.describe_to mapping_definition, StepMapper::DSL.new(mapper, hook_factory)
|
36
|
-
test_steps.push(*[mapper.test_step] + mapper.after_step_hooks)
|
36
|
+
test_steps.push(*(mapper.before_step_hooks + [mapper.test_step] + mapper.after_step_hooks))
|
37
37
|
self
|
38
38
|
end
|
39
39
|
|
@@ -65,7 +65,7 @@ module Cucumber
|
|
65
65
|
|
66
66
|
# Run this block of code after the scenario
|
67
67
|
def after(&block)
|
68
|
-
mapper.after_hooks
|
68
|
+
mapper.after_hooks.unshift(hook_factory.after(block))
|
69
69
|
self
|
70
70
|
end
|
71
71
|
|
@@ -83,6 +83,10 @@ module Cucumber
|
|
83
83
|
|
84
84
|
attr_accessor :test_step
|
85
85
|
|
86
|
+
def before_step_hooks
|
87
|
+
@before_step_hooks ||= []
|
88
|
+
end
|
89
|
+
|
86
90
|
def after_step_hooks
|
87
91
|
@after_step_hooks ||= []
|
88
92
|
end
|
@@ -91,6 +95,10 @@ module Cucumber
|
|
91
95
|
class DSL
|
92
96
|
include Cucumber.initializer(:mapper, :hook_factory)
|
93
97
|
|
98
|
+
def before(&block)
|
99
|
+
mapper.before_step_hooks << hook_factory.before_step(block)
|
100
|
+
end
|
101
|
+
|
94
102
|
# Define the step with a block of code to be executed
|
95
103
|
def map(&block)
|
96
104
|
mapper.test_step = mapper.test_step.with_mapping(&block)
|
@@ -117,6 +125,10 @@ module Cucumber
|
|
117
125
|
build_hook_step(block, Hooks::BeforeHook, Test::UnskippableAction)
|
118
126
|
end
|
119
127
|
|
128
|
+
def before_step(block)
|
129
|
+
build_hook_step(block, Hooks::BeforeStepHook, Test::UnskippableAction)
|
130
|
+
end
|
131
|
+
|
120
132
|
def after_step(block)
|
121
133
|
build_hook_step(block, Hooks::AfterStepHook, Test::Action)
|
122
134
|
end
|
@@ -81,7 +81,7 @@ module Cucumber
|
|
81
81
|
class Raisable < StandardError
|
82
82
|
attr_reader :message, :duration
|
83
83
|
|
84
|
-
def initialize(message = "", duration =
|
84
|
+
def initialize(message = "", duration = UnknownDuration.new, backtrace = nil)
|
85
85
|
@message, @duration = message, duration
|
86
86
|
super(message)
|
87
87
|
set_backtrace(backtrace) if backtrace
|
@@ -101,7 +101,7 @@ module Cucumber
|
|
101
101
|
|
102
102
|
def describe_to(visitor, *args)
|
103
103
|
visitor.undefined(*args)
|
104
|
-
visitor.duration(duration, *args)
|
104
|
+
visitor.duration(duration, *args)
|
105
105
|
self
|
106
106
|
end
|
107
107
|
|
@@ -116,7 +116,7 @@ module Cucumber
|
|
116
116
|
|
117
117
|
def describe_to(visitor, *args)
|
118
118
|
visitor.skipped(*args)
|
119
|
-
visitor.duration(duration, *args)
|
119
|
+
visitor.duration(duration, *args)
|
120
120
|
self
|
121
121
|
end
|
122
122
|
|
@@ -131,7 +131,7 @@ module Cucumber
|
|
131
131
|
|
132
132
|
def describe_to(visitor, *args)
|
133
133
|
visitor.pending(self, *args)
|
134
|
-
visitor.duration(duration, *args)
|
134
|
+
visitor.duration(duration, *args)
|
135
135
|
self
|
136
136
|
end
|
137
137
|
|
@@ -151,54 +151,64 @@ module Cucumber
|
|
151
151
|
# => 1
|
152
152
|
#
|
153
153
|
class Summary
|
154
|
-
attr_reader :
|
155
|
-
:total_passed,
|
156
|
-
:total_skipped,
|
157
|
-
:total_undefined,
|
158
|
-
:exceptions,
|
159
|
-
:durations
|
154
|
+
attr_reader :exceptions, :durations
|
160
155
|
|
161
156
|
def initialize
|
162
|
-
@
|
163
|
-
@total_passed =
|
164
|
-
@total_skipped =
|
165
|
-
@total_undefined = 0
|
157
|
+
@totals = Hash.new { 0 }
|
166
158
|
@exceptions = []
|
167
159
|
@durations = []
|
168
160
|
end
|
169
161
|
|
170
|
-
def
|
171
|
-
|
172
|
-
|
162
|
+
def method_missing(name, *args)
|
163
|
+
if name =~ /^total_/
|
164
|
+
get_total(name)
|
165
|
+
else
|
166
|
+
increment_total(name)
|
167
|
+
end
|
173
168
|
end
|
174
169
|
|
175
|
-
def
|
176
|
-
@
|
170
|
+
def exception(exception)
|
171
|
+
@exceptions << exception
|
177
172
|
self
|
178
173
|
end
|
179
174
|
|
180
|
-
def
|
181
|
-
@
|
175
|
+
def duration(duration)
|
176
|
+
@durations << duration
|
182
177
|
self
|
183
178
|
end
|
184
179
|
|
185
|
-
def
|
186
|
-
@
|
187
|
-
self
|
180
|
+
def total
|
181
|
+
@totals.reduce(0) { |total, status| total += status[1] }
|
188
182
|
end
|
189
183
|
|
190
|
-
|
191
|
-
|
184
|
+
private
|
185
|
+
|
186
|
+
def get_total(method_name)
|
187
|
+
status = method_name.to_s.gsub('total_', '').to_sym
|
188
|
+
return @totals.fetch(status) { 0 }
|
189
|
+
end
|
190
|
+
|
191
|
+
def increment_total(status)
|
192
|
+
@totals[status] += 1
|
192
193
|
self
|
193
194
|
end
|
195
|
+
end
|
194
196
|
|
195
|
-
|
196
|
-
|
197
|
+
class Duration
|
198
|
+
attr_reader :nanoseconds
|
199
|
+
|
200
|
+
def initialize(nanoseconds)
|
201
|
+
@nanoseconds = nanoseconds
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
class UnknownDuration
|
206
|
+
def tap(&block)
|
197
207
|
self
|
198
208
|
end
|
199
209
|
|
200
|
-
def
|
201
|
-
|
210
|
+
def nanoseconds
|
211
|
+
raise "#nanoseconds only allowed to be used in #tap block"
|
202
212
|
end
|
203
213
|
end
|
204
214
|
end
|
@@ -3,6 +3,7 @@ require 'cucumber/core/ast/examples_table'
|
|
3
3
|
module Cucumber::Core::Ast
|
4
4
|
describe ExamplesTable do
|
5
5
|
let(:location) { double(:to_s => 'file.feature:8') }
|
6
|
+
let(:language) { double }
|
6
7
|
|
7
8
|
describe ExamplesTable::Header do
|
8
9
|
let(:header) { ExamplesTable::Header.new(%w{foo bar baz}, location) }
|
@@ -15,7 +16,7 @@ module Cucumber::Core::Ast
|
|
15
16
|
|
16
17
|
context 'building a row' do
|
17
18
|
it 'includes the header values as keys' do
|
18
|
-
expect( header.build_row(%w{1 2 3}, 1, location) ).to eq ExamplesTable::Row.new({'foo' => '1', 'bar' => '2', 'baz' => '3'}, 1, location)
|
19
|
+
expect( header.build_row(%w{1 2 3}, 1, location, language) ).to eq ExamplesTable::Row.new({'foo' => '1', 'bar' => '2', 'baz' => '3'}, 1, location, language)
|
19
20
|
end
|
20
21
|
end
|
21
22
|
end
|
@@ -23,15 +24,21 @@ module Cucumber::Core::Ast
|
|
23
24
|
|
24
25
|
describe 'location' do
|
25
26
|
it 'knows the file and line number' do
|
26
|
-
row = ExamplesTable::Row.new({}, 1, location)
|
27
|
+
row = ExamplesTable::Row.new({}, 1, location, language)
|
27
28
|
expect( row.file_colon_line ).to eq 'file.feature:8'
|
28
29
|
end
|
29
30
|
end
|
30
31
|
|
32
|
+
describe 'language' do
|
33
|
+
it "has a language" do
|
34
|
+
expect( ExamplesTable::Row.new({}, 1, location, language) ).to respond_to(:language)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
31
38
|
describe "expanding a string" do
|
32
39
|
context "when an argument matches" do
|
33
40
|
it "replaces the argument with the value from the row" do
|
34
|
-
row = ExamplesTable::Row.new({'arg' => 'replacement'}, 1, location)
|
41
|
+
row = ExamplesTable::Row.new({'arg' => 'replacement'}, 1, location, language)
|
35
42
|
text = 'this <arg> a test'
|
36
43
|
expect( row.expand(text) ).to eq 'this replacement a test'
|
37
44
|
end
|
@@ -39,7 +46,7 @@ module Cucumber::Core::Ast
|
|
39
46
|
|
40
47
|
context "when the replacement value is nil" do
|
41
48
|
it "uses an empty string for the replacement" do
|
42
|
-
row = ExamplesTable::Row.new({'color' => nil}, 1, location)
|
49
|
+
row = ExamplesTable::Row.new({'color' => nil}, 1, location, language)
|
43
50
|
text = 'a <color> cucumber'
|
44
51
|
expect( row.expand(text) ).to eq 'a cucumber'
|
45
52
|
end
|
@@ -47,7 +54,7 @@ module Cucumber::Core::Ast
|
|
47
54
|
|
48
55
|
context "when an argument does not match" do
|
49
56
|
it "ignores the arguments that do not match" do
|
50
|
-
row = ExamplesTable::Row.new({'x' => '1', 'y' => '2'}, 1, location)
|
57
|
+
row = ExamplesTable::Row.new({'x' => '1', 'y' => '2'}, 1, location, language)
|
51
58
|
text = 'foo <x> bar <z>'
|
52
59
|
expect( row.expand(text) ).to eq 'foo 1 bar <z>'
|
53
60
|
end
|
@@ -56,7 +63,7 @@ module Cucumber::Core::Ast
|
|
56
63
|
|
57
64
|
describe 'accesing the values' do
|
58
65
|
it 'returns the actual row values' do
|
59
|
-
row = ExamplesTable::Row.new({'x' => '1', 'y' => '2'}, 1, location)
|
66
|
+
row = ExamplesTable::Row.new({'x' => '1', 'y' => '2'}, 1, location, language)
|
60
67
|
expect( row.values ).to eq ['1', '2']
|
61
68
|
end
|
62
69
|
end
|
@@ -65,20 +72,20 @@ module Cucumber::Core::Ast
|
|
65
72
|
let(:data) { {} }
|
66
73
|
let(:number) { double }
|
67
74
|
let(:location) { double }
|
68
|
-
let(:original) { ExamplesTable::Row.new(data, number, location) }
|
75
|
+
let(:original) { ExamplesTable::Row.new(data, number, location, language) }
|
69
76
|
|
70
77
|
it 'is equal to another instance with the same data, number and location' do
|
71
|
-
expect( original ).to eq ExamplesTable::Row.new(data, number, location)
|
78
|
+
expect( original ).to eq ExamplesTable::Row.new(data, number, location, language)
|
72
79
|
end
|
73
80
|
|
74
81
|
it 'is not equal to another instance with different data, number or location' do
|
75
|
-
expect( original ).not_to eq ExamplesTable::Row.new({'x' => 'y'}, number, location)
|
76
|
-
expect( original ).not_to eq ExamplesTable::Row.new(data, double, location)
|
77
|
-
expect( original ).not_to eq ExamplesTable::Row.new(data, number, double)
|
82
|
+
expect( original ).not_to eq ExamplesTable::Row.new({'x' => 'y'}, number, location, language)
|
83
|
+
expect( original ).not_to eq ExamplesTable::Row.new(data, double, location, language)
|
84
|
+
expect( original ).not_to eq ExamplesTable::Row.new(data, number, double, double)
|
78
85
|
end
|
79
86
|
|
80
87
|
it 'is not equal to another type of object' do
|
81
|
-
expect( original ).not_to eq double(data: data, number: number, location: location)
|
88
|
+
expect( original ).not_to eq double(data: data, number: number, location: location, language: language)
|
82
89
|
end
|
83
90
|
|
84
91
|
end
|