cucumber 0.8.7 → 0.9.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.
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