cucumber 0.9.2 → 0.9.3
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +0 -8
- data/History.txt +8 -0
- data/cucumber.gemspec +1 -1
- data/features/api/list_step_defs_as_json.feature +11 -6
- data/features/api/run_cli_main_with_existing_runtime.feature +34 -0
- data/features/step_definitions/cucumber_steps.rb +1 -2
- data/lib/cucumber.rb +1 -0
- data/lib/cucumber/cli/main.rb +8 -14
- data/lib/cucumber/cli/options.rb +1 -1
- data/lib/cucumber/core_ext/disable_mini_unit_autorun.rb +10 -0
- data/lib/cucumber/platform.rb +1 -1
- data/lib/cucumber/rb_support/rb_step_definition.rb +8 -0
- data/lib/cucumber/runtime.rb +12 -62
- data/lib/cucumber/runtime/for_programming_languages.rb +65 -0
- data/lib/cucumber/runtime/results.rb +4 -0
- data/lib/cucumber/runtime/support_code.rb +29 -11
- data/lib/cucumber/step_definitions.rb +1 -3
- data/spec/cucumber/cli/main_spec.rb +30 -4
- data/spec/cucumber/formatter/spec_helper.rb +3 -3
- data/spec/cucumber/rb_support/rb_language_spec.rb +215 -29
- data/spec/cucumber/rb_support/rb_step_definition_spec.rb +30 -24
- data/spec/cucumber/runtime/support_code_spec.rb +112 -0
- data/spec/cucumber/runtime_spec.rb +21 -274
- metadata +15 -9
@@ -11,6 +11,35 @@ module Cucumber
|
|
11
11
|
File.stub!(:exist?).and_return(false) # When Configuration checks for cucumber.yml
|
12
12
|
Dir.stub!(:[]).and_return([]) # to prevent cucumber's features dir to being laoded
|
13
13
|
end
|
14
|
+
|
15
|
+
let(:args) { [] }
|
16
|
+
let(:out_stream) { nil }
|
17
|
+
let(:err_stream) { nil }
|
18
|
+
subject { Main.new(args, out_stream, err_stream)}
|
19
|
+
|
20
|
+
describe "#execute!" do
|
21
|
+
context "passed an existing runtime" do
|
22
|
+
let(:existing_runtime) { double('runtime').as_null_object }
|
23
|
+
|
24
|
+
def do_execute
|
25
|
+
subject.execute!(existing_runtime)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "configures that runtime" do
|
29
|
+
expected_configuration = double('Configuration', :drb? => false).as_null_object
|
30
|
+
Configuration.stub!(:new => expected_configuration)
|
31
|
+
existing_runtime.should_receive(:configure).with(expected_configuration)
|
32
|
+
do_execute
|
33
|
+
end
|
34
|
+
|
35
|
+
it "uses that runtime for running and reporting results" do
|
36
|
+
expected_results = double('results', :failure? => true)
|
37
|
+
existing_runtime.should_receive(:run!)
|
38
|
+
existing_runtime.stub!(:results).and_return(expected_results)
|
39
|
+
do_execute.should == expected_results.failure?
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
14
43
|
|
15
44
|
describe "verbose mode" do
|
16
45
|
|
@@ -32,9 +61,7 @@ module Cucumber
|
|
32
61
|
end
|
33
62
|
|
34
63
|
describe "--format with class" do
|
35
|
-
|
36
|
-
describe "in module" do
|
37
|
-
|
64
|
+
describe "in module" do
|
38
65
|
it "should resolve each module until it gets Formatter class" do
|
39
66
|
cli = Main.new(%w{--format ZooModule::MonkeyFormatterClass}, nil)
|
40
67
|
mock_module = mock('module')
|
@@ -48,7 +75,6 @@ module Cucumber
|
|
48
75
|
|
49
76
|
cli.execute!
|
50
77
|
end
|
51
|
-
|
52
78
|
end
|
53
79
|
end
|
54
80
|
|
@@ -35,14 +35,14 @@ module Cucumber
|
|
35
35
|
|
36
36
|
def run(features)
|
37
37
|
configuration = Cucumber::Configuration.default
|
38
|
-
tree_walker = Cucumber::Ast::TreeWalker.new(
|
38
|
+
tree_walker = Cucumber::Ast::TreeWalker.new(step_mother, [@formatter], configuration)
|
39
39
|
tree_walker.visit_features(features)
|
40
40
|
end
|
41
41
|
|
42
42
|
def define_steps
|
43
43
|
return unless step_defs = self.class.step_defs
|
44
|
-
rb =
|
45
|
-
dsl = Object.new
|
44
|
+
rb = step_mother.load_programming_language('rb')
|
45
|
+
dsl = Object.new
|
46
46
|
dsl.extend RbSupport::RbDsl
|
47
47
|
dsl.instance_exec &step_defs
|
48
48
|
end
|
@@ -6,65 +6,74 @@ require 'cucumber/rb_support/rb_language'
|
|
6
6
|
module Cucumber
|
7
7
|
module RbSupport
|
8
8
|
describe RbStepDefinition do
|
9
|
-
let(:
|
10
|
-
|
11
|
-
|
9
|
+
let(:user_interface) { double('user interface') }
|
10
|
+
let(:rb) { support_code.load_programming_language('rb')}
|
11
|
+
let(:support_code) do
|
12
|
+
Cucumber::Runtime::SupportCode.new(user_interface, {})
|
13
|
+
end
|
14
|
+
let(:dsl) do
|
15
|
+
rb
|
16
|
+
Object.new.extend(RbSupport::RbDsl)
|
12
17
|
end
|
13
18
|
|
14
19
|
def unindented(s)
|
15
20
|
s.split("\n")[1..-2].join("\n").indent(-10)
|
16
21
|
end
|
22
|
+
|
23
|
+
describe "snippets" do
|
17
24
|
|
18
|
-
|
19
|
-
|
25
|
+
it "should recognise numbers in name and make according regexp" do
|
26
|
+
rb.snippet_text('Given', 'Cloud 9 yeah', nil).should == unindented(%{
|
20
27
|
Given /^Cloud (\\d+) yeah$/ do |arg1|
|
21
28
|
pending # express the regexp above with the code you wish you had
|
22
29
|
end
|
23
|
-
|
24
|
-
|
30
|
+
})
|
31
|
+
end
|
25
32
|
|
26
|
-
|
27
|
-
|
33
|
+
it "should recognise a mix of ints, strings and why not a table too" do
|
34
|
+
rb.snippet_text('Given', 'I have 9 "awesome" cukes in 37 "boxes"', Cucumber::Ast::Table).should == unindented(%{
|
28
35
|
Given /^I have (\\d+) "([^"]*)" cukes in (\\d+) "([^"]*)"$/ do |arg1, arg2, arg3, arg4, table|
|
29
36
|
# table is a Cucumber::Ast::Table
|
30
37
|
pending # express the regexp above with the code you wish you had
|
31
38
|
end
|
32
|
-
|
33
|
-
|
39
|
+
})
|
40
|
+
end
|
34
41
|
|
35
|
-
|
36
|
-
|
42
|
+
it "should recognise quotes in name and make according regexp" do
|
43
|
+
rb.snippet_text('Given', 'A "first" arg', nil).should == unindented(%{
|
37
44
|
Given /^A "([^"]*)" arg$/ do |arg1|
|
38
45
|
pending # express the regexp above with the code you wish you had
|
39
46
|
end
|
40
|
-
|
41
|
-
|
47
|
+
})
|
48
|
+
end
|
42
49
|
|
43
|
-
|
44
|
-
|
50
|
+
it "should recognise several quoted words in name and make according regexp and args" do
|
51
|
+
rb.snippet_text('Given', 'A "first" and "second" arg', nil).should == unindented(%{
|
45
52
|
Given /^A "([^"]*)" and "([^"]*)" arg$/ do |arg1, arg2|
|
46
53
|
pending # express the regexp above with the code you wish you had
|
47
54
|
end
|
48
|
-
|
49
|
-
|
55
|
+
})
|
56
|
+
end
|
50
57
|
|
51
|
-
|
52
|
-
|
58
|
+
it "should not use quote group when there are no quotes" do
|
59
|
+
rb.snippet_text('Given', 'A first arg', nil).should == unindented(%{
|
53
60
|
Given /^A first arg$/ do
|
54
61
|
pending # express the regexp above with the code you wish you had
|
55
62
|
end
|
56
|
-
|
57
|
-
|
63
|
+
})
|
64
|
+
end
|
58
65
|
|
59
|
-
|
60
|
-
|
66
|
+
it "should be helpful with tables" do
|
67
|
+
rb.snippet_text('Given', 'A "first" arg', Cucumber::Ast::Table).should == unindented(%{
|
61
68
|
Given /^A "([^"]*)" arg$/ do |arg1, table|
|
62
69
|
# table is a Cucumber::Ast::Table
|
63
70
|
pending # express the regexp above with the code you wish you had
|
64
71
|
end
|
65
|
-
|
66
|
-
|
72
|
+
})
|
73
|
+
end
|
67
74
|
|
75
|
+
end
|
76
|
+
|
68
77
|
describe "#load_code_file" do
|
69
78
|
after do
|
70
79
|
FileUtils.rm_rf('tmp.rb')
|
@@ -81,17 +90,194 @@ module Cucumber
|
|
81
90
|
"$foo = 1"
|
82
91
|
end
|
83
92
|
|
84
|
-
|
93
|
+
rb.load_code_file('tmp.rb')
|
85
94
|
$foo.should == 1
|
86
95
|
|
87
96
|
a_file_called('tmp.rb') do
|
88
97
|
"$foo = 2"
|
89
98
|
end
|
90
99
|
|
91
|
-
|
100
|
+
rb.load_code_file('tmp.rb')
|
92
101
|
$foo.should == 2
|
93
102
|
end
|
94
103
|
end
|
104
|
+
|
105
|
+
describe "Handling the World" do
|
106
|
+
|
107
|
+
it "should raise an error if the world is nil" do
|
108
|
+
dsl.World {}
|
109
|
+
|
110
|
+
begin
|
111
|
+
rb.before(nil)
|
112
|
+
raise "Should fail"
|
113
|
+
rescue RbSupport::NilWorld => e
|
114
|
+
e.message.should == "World procs should never return nil"
|
115
|
+
e.backtrace.length.should == 1
|
116
|
+
e.backtrace[0].should =~ /spec\/cucumber\/rb_support\/rb_language_spec\.rb\:\d+\:in `World'/
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
module ModuleOne
|
121
|
+
end
|
122
|
+
|
123
|
+
module ModuleTwo
|
124
|
+
end
|
125
|
+
|
126
|
+
class ClassOne
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should implicitly extend world with modules" do
|
130
|
+
dsl.World(ModuleOne, ModuleTwo)
|
131
|
+
rb.before(mock('scenario').as_null_object)
|
132
|
+
class << rb.current_world
|
133
|
+
included_modules.inspect.should =~ /ModuleOne/ # Workaround for RSpec/Ruby 1.9 issue with namespaces
|
134
|
+
included_modules.inspect.should =~ /ModuleTwo/
|
135
|
+
end
|
136
|
+
rb.current_world.class.should == Object
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should raise error when we try to register more than one World proc" do
|
140
|
+
expected_error = %{You can only pass a proc to #World once, but it's happening
|
141
|
+
in 2 places:
|
142
|
+
|
143
|
+
spec/cucumber/rb_support/rb_language_spec.rb:\\d+:in `World'
|
144
|
+
spec/cucumber/rb_support/rb_language_spec.rb:\\d+:in `World'
|
145
|
+
|
146
|
+
Use Ruby modules instead to extend your worlds. See the Cucumber::RbSupport::RbDsl#World RDoc
|
147
|
+
or http://wiki.github.com/aslakhellesoy/cucumber/a-whole-new-world.
|
148
|
+
|
149
|
+
}
|
150
|
+
dsl.World { Hash.new }
|
151
|
+
lambda do
|
152
|
+
dsl.World { Array.new }
|
153
|
+
end.should raise_error(RbSupport::MultipleWorld, /#{expected_error}/)
|
154
|
+
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
describe "step argument transformations" do
|
159
|
+
|
160
|
+
describe "without capture groups" do
|
161
|
+
it "complains when registering with a with no transform block" do
|
162
|
+
lambda do
|
163
|
+
dsl.Transform('^abc$')
|
164
|
+
end.should raise_error(Cucumber::RbSupport::RbTransform::MissingProc)
|
165
|
+
end
|
166
|
+
|
167
|
+
it "complains when registering with a zero-arg transform block" do
|
168
|
+
lambda do
|
169
|
+
dsl.Transform('^abc$') {42}
|
170
|
+
end.should raise_error(Cucumber::RbSupport::RbTransform::MissingProc)
|
171
|
+
end
|
172
|
+
|
173
|
+
it "complains when registering with a splat-arg transform block" do
|
174
|
+
lambda do
|
175
|
+
dsl.Transform('^abc$') {|*splat| 42 }
|
176
|
+
end.should raise_error(Cucumber::RbSupport::RbTransform::MissingProc)
|
177
|
+
end
|
178
|
+
|
179
|
+
it "complains when transforming with an arity mismatch" do
|
180
|
+
lambda do
|
181
|
+
dsl.Transform('^abc$') {|one, two| 42 }
|
182
|
+
rb.execute_transforms(['abc'])
|
183
|
+
end.should raise_error(Cucumber::ArityMismatchError)
|
184
|
+
end
|
185
|
+
|
186
|
+
it "allows registering a regexp pattern that yields the step_arg matched" do
|
187
|
+
dsl.Transform(/^ab*c$/) {|arg| 42}
|
188
|
+
rb.execute_transforms(['ab']).should == ['ab']
|
189
|
+
rb.execute_transforms(['ac']).should == [42]
|
190
|
+
rb.execute_transforms(['abc']).should == [42]
|
191
|
+
rb.execute_transforms(['abbc']).should == [42]
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
describe "with capture groups" do
|
196
|
+
it "complains when registering with a with no transform block" do
|
197
|
+
lambda do
|
198
|
+
dsl.Transform('^a(.)c$')
|
199
|
+
end.should raise_error(Cucumber::RbSupport::RbTransform::MissingProc)
|
200
|
+
end
|
201
|
+
|
202
|
+
it "complains when registering with a zero-arg transform block" do
|
203
|
+
lambda do
|
204
|
+
dsl.Transform('^a(.)c$') { 42 }
|
205
|
+
end.should raise_error(Cucumber::RbSupport::RbTransform::MissingProc)
|
206
|
+
end
|
207
|
+
|
208
|
+
it "complains when registering with a splat-arg transform block" do
|
209
|
+
lambda do
|
210
|
+
dsl.Transform('^a(.)c$') {|*splat| 42 }
|
211
|
+
end.should raise_error(Cucumber::RbSupport::RbTransform::MissingProc)
|
212
|
+
end
|
213
|
+
|
214
|
+
it "complains when transforming with an arity mismatch" do
|
215
|
+
lambda do
|
216
|
+
dsl.Transform('^a(.)c$') {|one, two| 42 }
|
217
|
+
rb.execute_transforms(['abc'])
|
218
|
+
end.should raise_error(Cucumber::ArityMismatchError)
|
219
|
+
end
|
220
|
+
|
221
|
+
it "allows registering a regexp pattern that yields capture groups" do
|
222
|
+
dsl.Transform(/^shape: (.+), color: (.+)$/) do |shape, color|
|
223
|
+
{shape.to_sym => color.to_sym}
|
224
|
+
end
|
225
|
+
rb.execute_transforms(['shape: circle, color: blue']).should == [{:circle => :blue}]
|
226
|
+
rb.execute_transforms(['shape: square, color: red']).should == [{:square => :red}]
|
227
|
+
rb.execute_transforms(['not shape: square, not color: red']).should == ['not shape: square, not color: red']
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
it "allows registering a string pattern" do
|
232
|
+
dsl.Transform('^ab*c$') {|arg| 42}
|
233
|
+
rb.execute_transforms(['ab']).should == ['ab']
|
234
|
+
rb.execute_transforms(['ac']).should == [42]
|
235
|
+
rb.execute_transforms(['abc']).should == [42]
|
236
|
+
rb.execute_transforms(['abbc']).should == [42]
|
237
|
+
end
|
238
|
+
|
239
|
+
it "gives match priority to transforms defined last" do
|
240
|
+
dsl.Transform(/^transform_me$/) {|arg| :foo }
|
241
|
+
dsl.Transform(/^transform_me$/) {|arg| :bar }
|
242
|
+
dsl.Transform(/^transform_me$/) {|arg| :baz }
|
243
|
+
rb.execute_transforms(['transform_me']).should == [:baz]
|
244
|
+
end
|
245
|
+
|
246
|
+
it "allows registering a transform which returns nil" do
|
247
|
+
dsl.Transform('^ac$') {|arg| nil}
|
248
|
+
rb.execute_transforms(['ab']).should == ['ab']
|
249
|
+
rb.execute_transforms(['ac']).should == [nil]
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
describe "hooks" do
|
254
|
+
|
255
|
+
it "should find before hooks" do
|
256
|
+
fish = dsl.Before('@fish'){}
|
257
|
+
meat = dsl.Before('@meat'){}
|
258
|
+
|
259
|
+
scenario = mock('Scenario')
|
260
|
+
scenario.should_receive(:accept_hook?).with(fish).and_return(true)
|
261
|
+
scenario.should_receive(:accept_hook?).with(meat).and_return(false)
|
262
|
+
|
263
|
+
rb.hooks_for(:before, scenario).should == [fish]
|
264
|
+
end
|
265
|
+
|
266
|
+
it "should find around hooks" do
|
267
|
+
a = dsl.Around do |scenario, block|
|
268
|
+
end
|
269
|
+
|
270
|
+
b = dsl.Around('@tag') do |scenario, block|
|
271
|
+
end
|
272
|
+
|
273
|
+
scenario = mock('Scenario')
|
274
|
+
scenario.should_receive(:accept_hook?).with(a).and_return(true)
|
275
|
+
scenario.should_receive(:accept_hook?).with(b).and_return(false)
|
276
|
+
|
277
|
+
rb.hooks_for(:around, scenario).should == [a]
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
95
281
|
end
|
96
282
|
end
|
97
283
|
end
|
@@ -7,86 +7,92 @@ require 'cucumber/rb_support/rb_language'
|
|
7
7
|
module Cucumber
|
8
8
|
module RbSupport
|
9
9
|
describe RbStepDefinition do
|
10
|
+
let(:user_interface) { double('user interface') }
|
11
|
+
let(:support_code) { Cucumber::Runtime::SupportCode.new(user_interface) }
|
12
|
+
let(:rb) { support_code.load_programming_language('rb')}
|
13
|
+
let(:dsl) do
|
14
|
+
rb
|
15
|
+
Object.new.extend(Cucumber::RbSupport::RbDsl)
|
16
|
+
end
|
17
|
+
|
10
18
|
before do
|
11
|
-
|
12
|
-
@rb = @step_mother.load_programming_language('rb')
|
13
|
-
@dsl = Object.new
|
14
|
-
@dsl.extend Cucumber::RbSupport::RbDsl
|
15
|
-
@step_mother.before(mock('scenario').as_null_object)
|
19
|
+
rb.before(mock('scenario').as_null_object)
|
16
20
|
|
17
21
|
$inside = nil
|
18
22
|
end
|
19
23
|
|
20
24
|
it "should allow calling of other steps" do
|
21
|
-
|
25
|
+
dsl.Given /Outside/ do
|
22
26
|
Given "Inside"
|
23
27
|
end
|
24
|
-
|
28
|
+
dsl.Given /Inside/ do
|
25
29
|
$inside = true
|
26
30
|
end
|
27
31
|
|
28
|
-
|
32
|
+
support_code.step_match("Outside").invoke(nil)
|
29
33
|
$inside.should == true
|
30
34
|
end
|
31
35
|
|
32
36
|
it "should allow calling of other steps with inline arg" do
|
33
|
-
|
37
|
+
dsl.Given /Outside/ do
|
34
38
|
Given "Inside", Cucumber::Ast::Table.new([['inside']])
|
35
39
|
end
|
36
|
-
|
40
|
+
dsl.Given /Inside/ do |table|
|
37
41
|
$inside = table.raw[0][0]
|
38
42
|
end
|
39
43
|
|
40
|
-
|
44
|
+
support_code.step_match("Outside").invoke(nil)
|
41
45
|
$inside.should == 'inside'
|
42
46
|
end
|
43
47
|
|
44
48
|
it "should raise Undefined when inside step is not defined" do
|
45
|
-
|
49
|
+
dsl.Given /Outside/ do
|
46
50
|
Given 'Inside'
|
47
51
|
end
|
48
52
|
|
49
53
|
lambda do
|
50
|
-
|
54
|
+
support_code.step_match('Outside').invoke(nil)
|
51
55
|
end.should raise_error(Cucumber::Undefined, 'Undefined step: "Inside"')
|
52
56
|
end
|
53
57
|
|
54
58
|
it "should allow forced pending" do
|
55
|
-
|
59
|
+
dsl.Given /Outside/ do
|
56
60
|
pending("Do me!")
|
57
61
|
end
|
58
62
|
|
59
63
|
lambda do
|
60
|
-
|
64
|
+
support_code.step_match("Outside").invoke(nil)
|
61
65
|
end.should raise_error(Cucumber::Pending, "Do me!")
|
62
66
|
end
|
63
67
|
|
64
68
|
it "should raise ArityMismatchError when the number of capture groups differs from the number of step arguments" do
|
65
|
-
|
69
|
+
dsl.Given /No group: \w+/ do |arg|
|
66
70
|
end
|
67
71
|
|
68
72
|
lambda do
|
69
|
-
|
73
|
+
support_code.step_match("No group: arg").invoke(nil)
|
70
74
|
end.should raise_error(Cucumber::ArityMismatchError)
|
71
75
|
end
|
72
76
|
|
73
77
|
it "should allow announce" do
|
74
|
-
|
75
|
-
|
76
|
-
@step_mother.visitor = v
|
77
|
-
@dsl.Given /Loud/ do
|
78
|
+
user_interface.should_receive(:announce).with('wasup')
|
79
|
+
dsl.Given /Loud/ do
|
78
80
|
announce 'wasup'
|
79
81
|
end
|
80
82
|
|
81
|
-
|
83
|
+
support_code.step_match("Loud").invoke(nil)
|
82
84
|
end
|
83
85
|
|
84
86
|
it "should recognize $arg style captures" do
|
85
|
-
|
87
|
+
dsl.Given "capture this: $arg" do |arg|
|
86
88
|
arg.should == 'this'
|
87
89
|
end
|
88
90
|
|
89
|
-
|
91
|
+
support_code.step_match('capture this: this').invoke(nil)
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should have a JSON representation of the signature" do
|
95
|
+
RbStepDefinition.new(rb, /I CAN HAZ (\d+) CUKES/i, lambda{}).to_hash.should == {'source' => "I CAN HAZ (\\d+) CUKES", 'flags' => 'i'}
|
90
96
|
end
|
91
97
|
end
|
92
98
|
end
|