cucumber 0.8.7 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. data/.gitignore +24 -0
  2. data/Gemfile +5 -0
  3. data/History.txt +16 -3
  4. data/Rakefile +4 -50
  5. data/cucumber.gemspec +36 -600
  6. data/features/cucumber_cli.feature +1 -1
  7. data/features/json_formatter.feature +1 -1
  8. data/features/junit_formatter.feature +10 -6
  9. data/features/post_configuration_hook.feature +15 -2
  10. data/features/step_definitions/cucumber_steps.rb +5 -1
  11. data/features/step_definitions/wire_steps.rb +1 -0
  12. data/features/support/env.rb +2 -5
  13. data/features/wire_protocol.feature +1 -1
  14. data/lib/cucumber.rb +8 -0
  15. data/lib/cucumber/ast/outline_table.rb +4 -4
  16. data/lib/cucumber/ast/step_invocation.rb +14 -13
  17. data/lib/cucumber/ast/table.rb +2 -1
  18. data/lib/cucumber/ast/tree_walker.rb +3 -3
  19. data/lib/cucumber/cli/configuration.rb +32 -7
  20. data/lib/cucumber/cli/main.rb +26 -30
  21. data/lib/cucumber/cli/options.rb +1 -3
  22. data/lib/cucumber/cli/profile_loader.rb +2 -0
  23. data/lib/cucumber/configuration.rb +37 -0
  24. data/lib/cucumber/errors.rb +40 -0
  25. data/lib/cucumber/feature_file.rb +5 -12
  26. data/lib/cucumber/formatter/junit.rb +2 -2
  27. data/lib/cucumber/formatter/tag_cloud.rb +1 -1
  28. data/lib/cucumber/js_support/js_dsl.js +4 -4
  29. data/lib/cucumber/js_support/js_language.rb +9 -5
  30. data/lib/cucumber/language_support.rb +2 -2
  31. data/lib/cucumber/parser/gherkin_builder.rb +19 -19
  32. data/lib/cucumber/platform.rb +3 -4
  33. data/lib/cucumber/rake/task.rb +1 -7
  34. data/lib/cucumber/rb_support/rb_dsl.rb +1 -0
  35. data/lib/cucumber/rb_support/rb_language.rb +1 -0
  36. data/lib/cucumber/rspec/doubles.rb +3 -3
  37. data/lib/cucumber/runtime.rb +192 -0
  38. data/lib/cucumber/runtime/features_loader.rb +62 -0
  39. data/lib/cucumber/runtime/results.rb +46 -0
  40. data/lib/cucumber/runtime/support_code.rb +174 -0
  41. data/lib/cucumber/runtime/user_interface.rb +80 -0
  42. data/lib/cucumber/step_mother.rb +6 -427
  43. data/lib/cucumber/wire_support/configuration.rb +2 -0
  44. data/lib/cucumber/wire_support/wire_language.rb +1 -8
  45. data/spec/cucumber/ast/background_spec.rb +3 -3
  46. data/spec/cucumber/ast/feature_spec.rb +2 -2
  47. data/spec/cucumber/ast/scenario_outline_spec.rb +1 -1
  48. data/spec/cucumber/ast/scenario_spec.rb +1 -2
  49. data/spec/cucumber/ast/tree_walker_spec.rb +1 -1
  50. data/spec/cucumber/cli/configuration_spec.rb +31 -5
  51. data/spec/cucumber/cli/drb_client_spec.rb +1 -1
  52. data/spec/cucumber/cli/main_spec.rb +8 -37
  53. data/spec/cucumber/cli/options_spec.rb +20 -0
  54. data/spec/cucumber/formatter/spec_helper.rb +5 -7
  55. data/spec/cucumber/rb_support/rb_language_spec.rb +2 -2
  56. data/spec/cucumber/rb_support/rb_step_definition_spec.rb +1 -1
  57. data/spec/cucumber/runtime_spec.rb +294 -0
  58. data/spec/cucumber/step_match_spec.rb +10 -8
  59. data/spec/cucumber/world/pending_spec.rb +1 -1
  60. data/spec/spec_helper.rb +2 -21
  61. metadata +215 -84
  62. data/Caliper.yml +0 -4
  63. data/VERSION.yml +0 -5
  64. data/spec/cucumber/step_mother_spec.rb +0 -302
@@ -1,3 +1,5 @@
1
+ require 'yaml'
2
+
1
3
  module Cucumber
2
4
  module WireSupport
3
5
  class Configuration
@@ -1,12 +1,5 @@
1
1
  require 'socket'
2
- begin
3
- require 'json'
4
- rescue LoadError
5
- STDERR.puts <<-EOM
6
- You must gem install #{defined?(JRUBY_VERSION) ? 'json_pure' : 'json'} before you can use the wire support.
7
- EOM
8
- exit(1)
9
- end
2
+ require 'json'
10
3
  require 'cucumber/wire_support/connection'
11
4
  require 'cucumber/wire_support/configuration'
12
5
  require 'cucumber/wire_support/wire_packet'
@@ -8,8 +8,8 @@ module Cucumber
8
8
 
9
9
  before do
10
10
  extend(Cucumber::RbSupport::RbDsl)
11
- @step_mother = Cucumber::StepMother.new
12
- @rb = @step_mother.load_programming_language('rb')
11
+ @runtime = Cucumber::Runtime.new
12
+ @rb = @runtime.load_programming_language('rb')
13
13
 
14
14
  $x = $y = nil
15
15
  Before do
@@ -19,7 +19,7 @@ module Cucumber
19
19
  $y = $x * n.to_i
20
20
  end
21
21
 
22
- @visitor = TreeWalker.new(@step_mother)
22
+ @visitor = TreeWalker.new(@runtime)
23
23
 
24
24
  @feature = mock('feature', :visit? => true).as_null_object
25
25
  end
@@ -7,7 +7,7 @@ module Cucumber
7
7
  include FeatureFactory
8
8
 
9
9
  it "should convert to sexp" do
10
- step_mother = Cucumber::StepMother.new
10
+ step_mother = Cucumber::Runtime.new
11
11
  step_mother.load_programming_language('rb')
12
12
  dsl = Object.new
13
13
  dsl.extend Cucumber::RbSupport::RbDsl
@@ -45,7 +45,7 @@ module Cucumber
45
45
  end
46
46
 
47
47
  it "should store OS specific file paths" do
48
- step_mother = Cucumber::StepMother.new
48
+ step_mother = Cucumber::Runtime.new
49
49
  step_mother.load_programming_language('rb')
50
50
  dsl = Object.new
51
51
  dsl.extend Cucumber::RbSupport::RbDsl
@@ -8,7 +8,7 @@ module Cucumber
8
8
  module Ast
9
9
  describe ScenarioOutline do
10
10
  before do
11
- @step_mother = Cucumber::StepMother.new
11
+ @step_mother = Cucumber::Runtime.new
12
12
  @step_mother.load_programming_language('rb')
13
13
  @dsl = Object.new
14
14
  @dsl.extend(Cucumber::RbSupport::RbDsl)
@@ -7,7 +7,7 @@ module Cucumber
7
7
  module Ast
8
8
  describe Scenario do
9
9
  before do
10
- @step_mother = Cucumber::StepMother.new
10
+ @step_mother = Cucumber::Runtime.new
11
11
  @step_mother.load_programming_language('rb')
12
12
  @dsl = Object.new
13
13
  @dsl.extend(Cucumber::RbSupport::RbDsl)
@@ -17,7 +17,6 @@ module Cucumber
17
17
  $y = n.to_i
18
18
  end
19
19
  @visitor = TreeWalker.new(@step_mother)
20
- @visitor.options = {}
21
20
  end
22
21
 
23
22
  it "should skip steps when previous is not passed" do
@@ -3,7 +3,7 @@ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
3
3
  module Cucumber::Ast
4
4
  describe TreeWalker do
5
5
  it "should visit features" do
6
- tw = TreeWalker.new(nil, [mock('listener', :before_visit_features => nil)], {})
6
+ tw = TreeWalker.new(nil, [mock('listener', :before_visit_features => nil)])
7
7
  tw.should_not_receive(:warn)
8
8
  tw.visit_features(mock('features', :accept => nil))
9
9
  end
@@ -4,6 +4,9 @@ require 'yaml'
4
4
  module Cucumber
5
5
  module Cli
6
6
  describe Configuration do
7
+ module ExposesOptions
8
+ attr_reader :options
9
+ end
7
10
 
8
11
  def given_cucumber_yml_defined_as(hash_or_string)
9
12
  File.stub!(:exist?).and_return(true)
@@ -23,7 +26,7 @@ module Cli
23
26
  end
24
27
 
25
28
  def config
26
- @config ||= Configuration.new(@out = StringIO.new, @error = StringIO.new)
29
+ @config ||= Configuration.new(@out = StringIO.new, @error = StringIO.new).extend(ExposesOptions)
27
30
  end
28
31
 
29
32
  def reset_config
@@ -287,17 +290,17 @@ END_OF_MESSAGE
287
290
 
288
291
  it "should accept --out option" do
289
292
  config.parse!(%w{--out jalla.txt})
290
- config.options[:formats].should == [['pretty', 'jalla.txt']]
293
+ config.formats.should == [['pretty', 'jalla.txt']]
291
294
  end
292
295
 
293
296
  it "should accept multiple --out options" do
294
297
  config.parse!(%w{--format progress --out file1 --out file2})
295
- config.options[:formats].should == [['progress', 'file2']]
298
+ config.formats.should == [['progress', 'file2']]
296
299
  end
297
300
 
298
301
  it "should accept multiple --format options and put the STDOUT one first so progress is seen" do
299
302
  config.parse!(%w{--format pretty --out pretty.txt --format progress})
300
- config.options[:formats].should == [['progress', out], ['pretty', 'pretty.txt']]
303
+ config.formats.should == [['progress', out], ['pretty', 'pretty.txt']]
301
304
  end
302
305
 
303
306
  it "should not accept multiple --format options when both use implicit STDOUT" do
@@ -314,7 +317,7 @@ END_OF_MESSAGE
314
317
 
315
318
  it "should associate --out to previous --format" do
316
319
  config.parse!(%w{--format progress --out file1 --format profile --out file2})
317
- config.options[:formats].should == [["progress", "file1"], ["profile" ,"file2"]]
320
+ config.formats.should == [["progress", "file1"], ["profile" ,"file2"]]
318
321
  end
319
322
 
320
323
  it "should accept --color option" do
@@ -399,7 +402,30 @@ END_OF_MESSAGE
399
402
  ENV["RAILS_ENV"].should == "selenium"
400
403
  config.feature_files.should_not include('RAILS_ENV=selenium')
401
404
  end
405
+
406
+ describe "#tag_expression" do
407
+ it "returns an empty expression when no tags are specified" do
408
+ config.parse!([])
409
+ config.tag_expression.should be_empty
410
+ end
402
411
 
412
+ it "returns an expression when tags are specified" do
413
+ config.parse!(['--tags','@foo'])
414
+ config.tag_expression.should_not be_empty
415
+ end
416
+ end
417
+
418
+ describe "#dry_run?" do
419
+ it "returns true when --dry-run was specified on in the arguments" do
420
+ config.parse!(['--dry-run'])
421
+ config.dry_run?.should be_true
422
+ end
423
+
424
+ it "returns false by default" do
425
+ config.parse!([])
426
+ config.dry_run?.should be_false
427
+ end
428
+ end
403
429
  end
404
430
  end
405
431
  end
@@ -30,7 +30,7 @@ module Cucumber
30
30
 
31
31
  it "returns raises an error when it can't connect to the server" do
32
32
  DRbObject.stub!(:new_with_uri).and_raise(DRb::DRbConnError)
33
- running { DRbClient.run(@args, @error_stream, @out_stream) }.should raise_error(DRbClientError, "No DRb server is running.")
33
+ lambda { DRbClient.run(@args, @error_stream, @out_stream) }.should raise_error(DRbClientError, "No DRb server is running.")
34
34
  end
35
35
 
36
36
  it "returns the result from the DRb server call" do
@@ -24,7 +24,7 @@ module Cucumber
24
24
 
25
25
  Cucumber::FeatureFile.stub!(:new).and_return(mock("feature file", :parse => @empty_feature))
26
26
 
27
- @cli.execute!(Cucumber::StepMother.new)
27
+ @cli.execute!
28
28
 
29
29
  @out.string.should include('example.feature')
30
30
  end
@@ -46,42 +46,12 @@ module Cucumber
46
46
  Object.should_receive(:const_get).with('ZooModule').and_return(mock_module)
47
47
  mock_module.should_receive(:const_get).with('MonkeyFormatterClass').and_return(mock('formatter class', :new => f))
48
48
 
49
- cli.execute!(Cucumber::StepMother.new)
49
+ cli.execute!
50
50
  end
51
51
 
52
52
  end
53
53
  end
54
54
 
55
- describe "setup step sequence" do
56
-
57
- it "should load files and execute hooks in order" do
58
- Configuration.stub!(:new).and_return(configuration = mock('configuration').as_null_object)
59
- step_mother = mock('step mother').as_null_object
60
- configuration.stub!(:drb?).and_return false
61
- cli = Main.new(%w{--verbose example.feature}, @out)
62
- cli.stub!(:require)
63
-
64
- configuration.stub!(:support_to_load).and_return(['support'])
65
- configuration.stub!(:step_defs_to_load).and_return(['step defs'])
66
-
67
- # Support must be loaded first to ensure post configuration hook can
68
- # run before anything else.
69
- step_mother.should_receive(:load_code_files).with(['support']).ordered
70
- # The post configuration hook/s (if any) need to be run next to enable
71
- # extensions to do their thing before features are loaded
72
- step_mother.should_receive(:after_configuration).with(configuration).ordered
73
- # Feature files must be loaded before step definitions are required.
74
- # This is because i18n step methods are only aliased when
75
- # features are loaded. If we swap the order, the requires
76
- # will fail.
77
- step_mother.should_receive(:load_plain_text_features).ordered
78
- step_mother.should_receive(:load_code_files).with(['step defs']).ordered
79
-
80
- cli.execute!(step_mother)
81
- end
82
-
83
- end
84
-
85
55
  [ProfilesNotDefinedError, YmlLoadError, ProfileNotFound].each do |exception_klass|
86
56
 
87
57
  it "rescues #{exception_klass}, prints the message to the error stream and returns true" do
@@ -89,7 +59,7 @@ module Cucumber
89
59
  configuration.stub!(:parse!).and_raise(exception_klass.new("error message"))
90
60
 
91
61
  main = Main.new('', out = StringIO.new, error = StringIO.new)
92
- main.execute!(Cucumber::StepMother.new).should be_true
62
+ main.execute!.should be_true
93
63
  error.string.should == "error message\n"
94
64
  end
95
65
  end
@@ -103,30 +73,31 @@ module Cucumber
103
73
 
104
74
  @cli = Main.new(@args, @out, @err)
105
75
  @step_mother = mock('StepMother').as_null_object
76
+ StepMother.stub!(:new).and_return(@step_mother)
106
77
  end
107
78
 
108
79
  it "delegates the execution to the DRB client passing the args and streams" do
109
80
  @configuration.stub :drb_port => 1450
110
81
  DRbClient.should_receive(:run).with(@args, @err, @out, 1450).and_return(true)
111
- @cli.execute!(@step_mother)
82
+ @cli.execute!
112
83
  end
113
84
 
114
85
  it "returns the result from the DRbClient" do
115
86
  DRbClient.stub!(:run).and_return('foo')
116
- @cli.execute!(@step_mother).should == 'foo'
87
+ @cli.execute!.should == 'foo'
117
88
  end
118
89
 
119
90
  it "ceases execution if the DrbClient is able to perform the execution" do
120
91
  DRbClient.stub!(:run).and_return(true)
121
92
  @configuration.should_not_receive(:build_formatter_broadcaster)
122
- @cli.execute!(@step_mother)
93
+ @cli.execute!
123
94
  end
124
95
 
125
96
  context "when the DrbClient is unable to perfrom the execution" do
126
97
  before { DRbClient.stub!(:run).and_raise(DRbClientError.new('error message.')) }
127
98
 
128
99
  it "alerts the user that execution will be performed locally" do
129
- @cli.execute!(@step_mother)
100
+ @cli.execute!
130
101
  @err.string.should include("WARNING: error message. Running features locally:")
131
102
  end
132
103
 
@@ -1,5 +1,6 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
2
  require 'yaml'
3
+ require 'cucumber/cli/options'
3
4
 
4
5
  module Cucumber
5
6
  module Cli
@@ -324,6 +325,25 @@ module Cli
324
325
 
325
326
  end
326
327
 
328
+ describe "dry-run" do
329
+ it "should have the default value for snippets" do
330
+ given_cucumber_yml_defined_as({'foo' => %w[--dry-run]})
331
+ options.parse!(%w{--dry-run})
332
+ options[:snippets].should == true
333
+ end
334
+
335
+ it "should set snippets to false when no-snippets provided after dry-run" do
336
+ given_cucumber_yml_defined_as({'foo' => %w[--dry-run --no-snippets]})
337
+ options.parse!(%w{--dry-run --no-snippets})
338
+ options[:snippets].should == false
339
+ end
340
+
341
+ it "should set snippets to false when no-snippets provided before dry-run" do
342
+ given_cucumber_yml_defined_as({'foo' => %w[--no-snippet --dry-run]})
343
+ options.parse!(%w{--no-snippets --dry-run})
344
+ options[:snippets].should == false
345
+ end
346
+ end
327
347
  end
328
348
 
329
349
  end
@@ -21,19 +21,21 @@ module Cucumber
21
21
  end
22
22
 
23
23
  def step_mother
24
- @step_mother ||= StepMother.new
24
+ @step_mother ||= Runtime.new
25
25
  end
26
26
 
27
27
  def load_features(content)
28
28
  feature_file = FeatureFile.new('spec.feature', content)
29
29
  features = Ast::Features.new
30
- feature = feature_file.parse(options, {})
30
+ filters = []
31
+ feature = feature_file.parse(filters, {})
31
32
  features.add_feature(feature) if feature
32
33
  features
33
34
  end
34
35
 
35
36
  def run(features)
36
- tree_walker = Cucumber::Ast::TreeWalker.new(@step_mother, [@formatter], options, STDOUT)
37
+ configuration = Cucumber::Configuration.default
38
+ tree_walker = Cucumber::Ast::TreeWalker.new(@step_mother, [@formatter], configuration)
37
39
  tree_walker.visit_features(features)
38
40
  end
39
41
 
@@ -44,10 +46,6 @@ module Cucumber
44
46
  dsl.extend RbSupport::RbDsl
45
47
  dsl.instance_exec &step_defs
46
48
  end
47
-
48
- def options
49
- @options ||= mock(Cucumber::Cli::Options, :filters => [], :[] => nil)
50
- end
51
49
  end
52
50
  end
53
51
  end
@@ -6,9 +6,9 @@ require 'cucumber/rb_support/rb_language'
6
6
  module Cucumber
7
7
  module RbSupport
8
8
  describe RbStepDefinition do
9
+ let(:runtime) { Cucumber::Runtime.new }
9
10
  before do
10
- @step_mother = Cucumber::StepMother.new
11
- @rb = @step_mother.load_programming_language('rb')
11
+ @rb = runtime.load_programming_language('rb')
12
12
  end
13
13
 
14
14
  def unindented(s)
@@ -8,7 +8,7 @@ module Cucumber
8
8
  module RbSupport
9
9
  describe RbStepDefinition do
10
10
  before do
11
- @step_mother = Cucumber::StepMother.new
11
+ @step_mother = Cucumber::Runtime.new
12
12
  @rb = @step_mother.load_programming_language('rb')
13
13
  @dsl = Object.new
14
14
  @dsl.extend Cucumber::RbSupport::RbDsl
@@ -0,0 +1,294 @@
1
+ require 'spec_helper'
2
+
3
+ module Cucumber
4
+ describe Runtime do
5
+ subject { Runtime.new(options) }
6
+ let(:options) { {} }
7
+ let(:dsl) do
8
+ @rb = subject.load_programming_language('rb')
9
+ Object.new.extend(RbSupport::RbDsl)
10
+ end
11
+
12
+ it "should format step names" do
13
+ dsl.Given(/it (.*) in (.*)/) { |what, month| }
14
+ dsl.Given(/nope something else/) { |what, month| }
15
+
16
+ format = subject.step_match("it snows in april").format_args("[%s]")
17
+ format.should == "it [snows] in [april]"
18
+ end
19
+
20
+ describe "#features_paths" do
21
+ let(:options) { {:paths => ['foo/bar/baz.feature', 'foo/bar/features/baz.feature', 'other_features'] } }
22
+ it "returns the value from configuration.paths" do
23
+ subject.features_paths.should == options[:paths]
24
+ end
25
+ end
26
+
27
+ describe "resolving step defintion matches" do
28
+
29
+ it "should raise Ambiguous error with guess hint when multiple step definitions match" do
30
+ expected_error = %{Ambiguous match of "Three blind mice":
31
+
32
+ spec/cucumber/runtime_spec.rb:\\d+:in `/Three (.*) mice/'
33
+ spec/cucumber/runtime_spec.rb:\\d+:in `/Three blind (.*)/'
34
+
35
+ You can run again with --guess to make Cucumber be more smart about it
36
+ }
37
+ dsl.Given(/Three (.*) mice/) {|disability|}
38
+ dsl.Given(/Three blind (.*)/) {|animal|}
39
+
40
+ lambda do
41
+ subject.step_match("Three blind mice")
42
+ end.should raise_error(Ambiguous, /#{expected_error}/)
43
+ end
44
+
45
+ describe "when --guess is used" do
46
+ let(:options) { {:guess => true} }
47
+
48
+ it "should not show --guess hint" do
49
+ expected_error = %{Ambiguous match of "Three cute mice":
50
+
51
+ spec/cucumber/runtime_spec.rb:\\d+:in `/Three (.*) mice/'
52
+ spec/cucumber/runtime_spec.rb:\\d+:in `/Three cute (.*)/'
53
+
54
+ }
55
+ dsl.Given(/Three (.*) mice/) {|disability|}
56
+ dsl.Given(/Three cute (.*)/) {|animal|}
57
+
58
+ lambda do
59
+ subject.step_match("Three cute mice")
60
+ end.should raise_error(Ambiguous, /#{expected_error}/)
61
+ end
62
+
63
+ it "should not raise Ambiguous error when multiple step definitions match" do
64
+ dsl.Given(/Three (.*) mice/) {|disability|}
65
+ dsl.Given(/Three (.*)/) {|animal|}
66
+
67
+ lambda do
68
+ subject.step_match("Three blind mice")
69
+ end.should_not raise_error
70
+ end
71
+
72
+ it "should not raise NoMethodError when guessing from multiple step definitions with nil fields" do
73
+ dsl.Given(/Three (.*) mice( cannot find food)?/) {|disability, is_disastrous|}
74
+ dsl.Given(/Three (.*)?/) {|animal|}
75
+
76
+ lambda do
77
+ subject.step_match("Three blind mice")
78
+ end.should_not raise_error
79
+ end
80
+
81
+ it "should pick right step definition when an equal number of capture groups" do
82
+ right = dsl.Given(/Three (.*) mice/) {|disability|}
83
+ wrong = dsl.Given(/Three (.*)/) {|animal|}
84
+
85
+ subject.step_match("Three blind mice").step_definition.should == right
86
+ end
87
+
88
+ it "should pick right step definition when an unequal number of capture groups" do
89
+ right = dsl.Given(/Three (.*) mice ran (.*)/) {|disability|}
90
+ wrong = dsl.Given(/Three (.*)/) {|animal|}
91
+
92
+ subject.step_match("Three blind mice ran far").step_definition.should == right
93
+ end
94
+
95
+ it "should pick most specific step definition when an unequal number of capture groups" do
96
+ general = dsl.Given(/Three (.*) mice ran (.*)/) {|disability|}
97
+ specific = dsl.Given(/Three blind mice ran far/) do; end
98
+ more_specific = dsl.Given(/^Three blind mice ran far$/) do; end
99
+
100
+ subject.step_match("Three blind mice ran far").step_definition.should == more_specific
101
+ end
102
+ end
103
+
104
+ it "should raise Undefined error when no step definitions match" do
105
+ lambda do
106
+ subject.step_match("Three blind mice")
107
+ end.should raise_error(Undefined)
108
+ end
109
+
110
+ # http://railsforum.com/viewtopic.php?pid=93881
111
+ it "should not raise Redundant unless it's really redundant" do
112
+ dsl.Given(/^(.*) (.*) user named '(.*)'$/) {|a,b,c|}
113
+ dsl.Given(/^there is no (.*) user named '(.*)'$/) {|a,b|}
114
+ end
115
+ end
116
+
117
+ describe "Handling the World" do
118
+
119
+ it "should raise an error if the world is nil" do
120
+ dsl.World {}
121
+
122
+ begin
123
+ subject.before_and_after(nil) do; end
124
+ raise "Should fail"
125
+ rescue RbSupport::NilWorld => e
126
+ e.message.should == "World procs should never return nil"
127
+ e.backtrace.length.should == 1
128
+ e.backtrace[0].should =~ /spec\/cucumber\/runtime_spec\.rb\:\d+\:in `World'/
129
+ end
130
+ end
131
+
132
+ module ModuleOne
133
+ end
134
+
135
+ module ModuleTwo
136
+ end
137
+
138
+ class ClassOne
139
+ end
140
+
141
+ it "should implicitly extend world with modules" do
142
+ dsl.World(ModuleOne, ModuleTwo)
143
+ subject.before(mock('scenario').as_null_object)
144
+ class << @rb.current_world
145
+ included_modules.inspect.should =~ /ModuleOne/ # Workaround for RSpec/Ruby 1.9 issue with namespaces
146
+ included_modules.inspect.should =~ /ModuleTwo/
147
+ end
148
+ @rb.current_world.class.should == Object
149
+ end
150
+
151
+ it "should raise error when we try to register more than one World proc" do
152
+ expected_error = %{You can only pass a proc to #World once, but it's happening
153
+ in 2 places:
154
+
155
+ spec/cucumber/runtime_spec.rb:\\d+:in `World'
156
+ spec/cucumber/runtime_spec.rb:\\d+:in `World'
157
+
158
+ Use Ruby modules instead to extend your worlds. See the Cucumber::RbSupport::RbDsl#World RDoc
159
+ or http://wiki.github.com/aslakhellesoy/cucumber/a-whole-new-world.
160
+
161
+ }
162
+ dsl.World { Hash.new }
163
+ lambda do
164
+ dsl.World { Array.new }
165
+ end.should raise_error(RbSupport::MultipleWorld, /#{expected_error}/)
166
+
167
+ end
168
+ end
169
+
170
+ describe "hooks" do
171
+
172
+ it "should find before hooks" do
173
+ fish = dsl.Before('@fish'){}
174
+ meat = dsl.Before('@meat'){}
175
+
176
+ scenario = mock('Scenario')
177
+ scenario.should_receive(:accept_hook?).with(fish).and_return(true)
178
+ scenario.should_receive(:accept_hook?).with(meat).and_return(false)
179
+
180
+ @rb.hooks_for(:before, scenario).should == [fish]
181
+ end
182
+
183
+ it "should find around hooks" do
184
+ a = dsl.Around do |scenario, block|
185
+ end
186
+
187
+ b = dsl.Around('@tag') do |scenario, block|
188
+ end
189
+
190
+ scenario = mock('Scenario')
191
+ scenario.should_receive(:accept_hook?).with(a).and_return(true)
192
+ scenario.should_receive(:accept_hook?).with(b).and_return(false)
193
+
194
+ @rb.hooks_for(:around, scenario).should == [a]
195
+ end
196
+ end
197
+
198
+ describe "step argument transformations" do
199
+
200
+ describe "without capture groups" do
201
+ it "complains when registering with a with no transform block" do
202
+ lambda do
203
+ dsl.Transform('^abc$')
204
+ end.should raise_error(Cucumber::RbSupport::RbTransform::MissingProc)
205
+ end
206
+
207
+ it "complains when registering with a zero-arg transform block" do
208
+ lambda do
209
+ dsl.Transform('^abc$') {42}
210
+ end.should raise_error(Cucumber::RbSupport::RbTransform::MissingProc)
211
+ end
212
+
213
+ it "complains when registering with a splat-arg transform block" do
214
+ lambda do
215
+ dsl.Transform('^abc$') {|*splat| 42 }
216
+ end.should raise_error(Cucumber::RbSupport::RbTransform::MissingProc)
217
+ end
218
+
219
+ it "complains when transforming with an arity mismatch" do
220
+ lambda do
221
+ dsl.Transform('^abc$') {|one, two| 42 }
222
+ @rb.execute_transforms(['abc'])
223
+ end.should raise_error(Cucumber::ArityMismatchError)
224
+ end
225
+
226
+ it "allows registering a regexp pattern that yields the step_arg matched" do
227
+ dsl.Transform(/^ab*c$/) {|arg| 42}
228
+ @rb.execute_transforms(['ab']).should == ['ab']
229
+ @rb.execute_transforms(['ac']).should == [42]
230
+ @rb.execute_transforms(['abc']).should == [42]
231
+ @rb.execute_transforms(['abbc']).should == [42]
232
+ end
233
+ end
234
+
235
+ describe "with capture groups" do
236
+ it "complains when registering with a with no transform block" do
237
+ lambda do
238
+ dsl.Transform('^a(.)c$')
239
+ end.should raise_error(Cucumber::RbSupport::RbTransform::MissingProc)
240
+ end
241
+
242
+ it "complains when registering with a zero-arg transform block" do
243
+ lambda do
244
+ dsl.Transform('^a(.)c$') { 42 }
245
+ end.should raise_error(Cucumber::RbSupport::RbTransform::MissingProc)
246
+ end
247
+
248
+ it "complains when registering with a splat-arg transform block" do
249
+ lambda do
250
+ dsl.Transform('^a(.)c$') {|*splat| 42 }
251
+ end.should raise_error(Cucumber::RbSupport::RbTransform::MissingProc)
252
+ end
253
+
254
+ it "complains when transforming with an arity mismatch" do
255
+ lambda do
256
+ dsl.Transform('^a(.)c$') {|one, two| 42 }
257
+ @rb.execute_transforms(['abc'])
258
+ end.should raise_error(Cucumber::ArityMismatchError)
259
+ end
260
+
261
+ it "allows registering a regexp pattern that yields capture groups" do
262
+ dsl.Transform(/^shape: (.+), color: (.+)$/) do |shape, color|
263
+ {shape.to_sym => color.to_sym}
264
+ end
265
+ @rb.execute_transforms(['shape: circle, color: blue']).should == [{:circle => :blue}]
266
+ @rb.execute_transforms(['shape: square, color: red']).should == [{:square => :red}]
267
+ @rb.execute_transforms(['not shape: square, not color: red']).should == ['not shape: square, not color: red']
268
+ end
269
+ end
270
+
271
+ it "allows registering a string pattern" do
272
+ dsl.Transform('^ab*c$') {|arg| 42}
273
+ @rb.execute_transforms(['ab']).should == ['ab']
274
+ @rb.execute_transforms(['ac']).should == [42]
275
+ @rb.execute_transforms(['abc']).should == [42]
276
+ @rb.execute_transforms(['abbc']).should == [42]
277
+ end
278
+
279
+ it "gives match priority to transforms defined last" do
280
+ dsl.Transform(/^transform_me$/) {|arg| :foo }
281
+ dsl.Transform(/^transform_me$/) {|arg| :bar }
282
+ dsl.Transform(/^transform_me$/) {|arg| :baz }
283
+ @rb.execute_transforms(['transform_me']).should == [:baz]
284
+ end
285
+
286
+ it "allows registering a transform which returns nil" do
287
+ dsl.Transform('^ac$') {|arg| nil}
288
+ @rb.execute_transforms(['ab']).should == ['ab']
289
+ @rb.execute_transforms(['ac']).should == [nil]
290
+ end
291
+ end
292
+
293
+ end
294
+ end