aslakhellesoy-cucumber 0.1.99.15 → 0.1.99.17

Sign up to get free protection for your applications and to get access to all the features.
@@ -41,7 +41,7 @@ module Cucumber
41
41
  # * <tt>skipped</tt> - defaults to <tt>cyan</tt>
42
42
  # * <tt>skipped_param</tt> - defaults to <tt>cyan,bold</tt>
43
43
  # * <tt>comment</tt> - defaults to <tt>grey</tt>
44
- # * <tt>tag</tt> - defaults to <tt>blue</tt>
44
+ # * <tt>tag</tt> - defaults to <tt>cyan</tt>
45
45
  #
46
46
  # For instance, if your shell has a black background and a green font (like the
47
47
  # "Homebrew" settings for OS X' Terminal.app), you may want to override passed
@@ -81,7 +81,7 @@ module Cucumber
81
81
  'outline' => 'cyan',
82
82
  'skipped' => 'cyan',
83
83
  'comment' => 'grey',
84
- 'tag' => 'blue'
84
+ 'tag' => 'cyan'
85
85
  })
86
86
 
87
87
  if ENV['CUCUMBER_COLORS'] # Example: export CUCUMBER_COLORS="passed=red:failed=yellow"
@@ -82,7 +82,7 @@ module Cucumber
82
82
  undefined = features.steps[:undefined]
83
83
  return if undefined.empty?
84
84
  snippets = undefined.map do |step|
85
- step_name = StepMother::Undefined === step.exception ? step.exception.step_name : step.name
85
+ step_name = Undefined === step.exception ? step.exception.step_name : step.name
86
86
  snippet = @step_mother.snippet_text(step.actual_keyword, step_name)
87
87
  snippet
88
88
  end.compact.uniq
@@ -1,6 +1,9 @@
1
1
  module Cucumber
2
2
  module Parser
3
3
  # TIP: When you hack on the grammar, just delete feature.rb in this directory.
4
+ # Also make sure you have uninstalled all cucumber gems (don't forget xxx-cucumber
5
+ # github gems).
6
+ #
4
7
  # Treetop will then generate the parser in-memory. When you're happy, just generate
5
8
  # the rb file with tt feature.tt
6
9
  module Feature
@@ -49,6 +52,7 @@ module Cucumber
49
52
  def feature_elements
50
53
  elements[7]
51
54
  end
55
+
52
56
  end
53
57
 
54
58
  module Feature2
@@ -150,6 +154,15 @@ module Cucumber
150
154
  if r14
151
155
  r16 = _nt_feature_elements
152
156
  s0 << r16
157
+ if r16
158
+ r18 = _nt_comment
159
+ if r18
160
+ r17 = r18
161
+ else
162
+ r17 = SyntaxNode.new(input, index...index)
163
+ end
164
+ s0 << r17
165
+ end
153
166
  end
154
167
  end
155
168
  end
@@ -336,6 +349,9 @@ module Cucumber
336
349
  elements[0]
337
350
  end
338
351
 
352
+ def white
353
+ elements[1]
354
+ end
339
355
  end
340
356
 
341
357
  module Comment1
@@ -358,21 +374,7 @@ module Cucumber
358
374
  r2 = _nt_comment_line
359
375
  s1 << r2
360
376
  if r2
361
- s3, i3 = [], index
362
- loop do
363
- r4 = _nt_eol
364
- if r4
365
- s3 << r4
366
- else
367
- break
368
- end
369
- end
370
- if s3.empty?
371
- self.index = i3
372
- r3 = nil
373
- else
374
- r3 = SyntaxNode.new(input, i3...index, s3)
375
- end
377
+ r3 = _nt_white
376
378
  s1 << r3
377
379
  end
378
380
  if s1.last
@@ -612,6 +614,10 @@ module Cucumber
612
614
  def steps
613
615
  elements[7]
614
616
  end
617
+
618
+ def white
619
+ elements[8]
620
+ end
615
621
  end
616
622
 
617
623
  module Scenario1
@@ -694,6 +700,10 @@ module Cucumber
694
700
  if r8
695
701
  r12 = _nt_steps
696
702
  s0 << r12
703
+ if r12
704
+ r13 = _nt_white
705
+ s0 << r13
706
+ end
697
707
  end
698
708
  end
699
709
  end
@@ -747,6 +757,10 @@ module Cucumber
747
757
  def examples_sections
748
758
  elements[8]
749
759
  end
760
+
761
+ def white
762
+ elements[9]
763
+ end
750
764
  end
751
765
 
752
766
  module ScenarioOutline1
@@ -807,6 +821,10 @@ module Cucumber
807
821
  if r9
808
822
  r10 = _nt_examples_sections
809
823
  s0 << r10
824
+ if r10
825
+ r11 = _nt_white
826
+ s0 << r11
827
+ end
810
828
  end
811
829
  end
812
830
  end
@@ -1190,12 +1208,7 @@ module Cucumber
1190
1208
  break
1191
1209
  end
1192
1210
  end
1193
- if s0.empty?
1194
- self.index = i0
1195
- r0 = nil
1196
- else
1197
- r0 = SyntaxNode.new(input, i0...index, s0)
1198
- end
1211
+ r0 = SyntaxNode.new(input, i0...index, s0)
1199
1212
 
1200
1213
  node_cache[:line_to_eol][start_index] = r0
1201
1214
 
@@ -1,6 +1,9 @@
1
1
  module Cucumber
2
2
  module Parser
3
3
  # TIP: When you hack on the grammar, just delete feature.rb in this directory.
4
+ # Also make sure you have uninstalled all cucumber gems (don't forget xxx-cucumber
5
+ # github gems).
6
+ #
4
7
  # Treetop will then generate the parser in-memory. When you're happy, just generate
5
8
  # the rb file with tt feature.tt
6
9
  grammar Feature
@@ -8,7 +11,15 @@ module Cucumber
8
11
  include Table
9
12
 
10
13
  rule feature
11
- white comment white tags white header:(!(scenario_outline / scenario / background) .)* background:(background)? feature_elements {
14
+ white
15
+ comment
16
+ white
17
+ tags
18
+ white
19
+ header:(!(scenario_outline / scenario / background) .)*
20
+ background:(background)?
21
+ feature_elements
22
+ comment? {
12
23
  def build
13
24
  if background.respond_to?(:build)
14
25
  Ast::Feature.new(comment.build, tags.build, header.text_value, feature_elements.build, background.build)
@@ -33,7 +44,7 @@ module Cucumber
33
44
  end
34
45
 
35
46
  rule comment
36
- (comment_line eol+)* {
47
+ (comment_line white)* {
37
48
  def build
38
49
  Ast::Comment.new(text_value)
39
50
  end
@@ -66,7 +77,7 @@ module Cucumber
66
77
  end
67
78
 
68
79
  rule scenario
69
- comment tags white scenario_keyword space* name:line_to_eol (eol+ / eof) steps {
80
+ comment tags white scenario_keyword space* name:line_to_eol (eol+ / eof) steps white {
70
81
  def build
71
82
  Ast::Scenario.new(
72
83
  comment.build,
@@ -81,7 +92,7 @@ module Cucumber
81
92
  end
82
93
 
83
94
  rule scenario_outline
84
- comment tags white scenario_outline_keyword space* name:line_to_eol white steps examples_sections {
95
+ comment tags white scenario_outline_keyword space* name:line_to_eol white steps examples_sections white {
85
96
  def build
86
97
  Ast::ScenarioOutline.new(
87
98
  comment.build,
@@ -137,7 +148,7 @@ module Cucumber
137
148
  end
138
149
 
139
150
  rule line_to_eol
140
- (!eol .)+
151
+ (!eol .)*
141
152
  end
142
153
 
143
154
  rule py_string
@@ -1,5 +1,11 @@
1
1
  module Cucumber
2
2
  module Parser
3
+ # TIP: When you hack on the grammar, just delete feature.rb in this directory.
4
+ # Also make sure you have uninstalled all cucumber gems (don't forget xxx-cucumber
5
+ # github gems).
6
+ #
7
+ # Treetop will then generate the parser in-memory. When you're happy, just generate
8
+ # the rb file with tt feature.tt
3
9
  module Table
4
10
  include Treetop::Runtime
5
11
 
@@ -1,5 +1,11 @@
1
1
  module Cucumber
2
2
  module Parser
3
+ # TIP: When you hack on the grammar, just delete feature.rb in this directory.
4
+ # Also make sure you have uninstalled all cucumber gems (don't forget xxx-cucumber
5
+ # github gems).
6
+ #
7
+ # Treetop will then generate the parser in-memory. When you're happy, just generate
8
+ # the rb file with tt feature.tt
3
9
  grammar Table
4
10
 
5
11
  rule table
@@ -1,6 +1,14 @@
1
- require 'treetop'
2
- require 'treetop/runtime'
3
- require 'treetop/ruby_extensions'
1
+ begin
2
+ require 'treetop'
3
+ require 'treetop/runtime'
4
+ require 'treetop/ruby_extensions'
5
+ rescue LoadError
6
+ require "rubygems"
7
+ gem "treetop"
8
+ require 'treetop'
9
+ require 'treetop/runtime'
10
+ require 'treetop/ruby_extensions'
11
+ end
4
12
 
5
13
  module Cucumber
6
14
  module Parser
@@ -32,7 +40,7 @@ module Cucumber
32
40
  class SyntaxError < StandardError
33
41
  def initialize(parser, file, line_offset)
34
42
  tf = parser.terminal_failures
35
- expected = tf.size == 1 ? tf[0].expected_string.inspect : "one of #{tf.map{|f| f.expected_string}.uniq*', '}"
43
+ expected = tf.size == 1 ? tf[0].expected_string.inspect : "one of #{tf.map{|f| f.expected_string.inspect}.uniq*', '}"
36
44
  line = parser.failure_line + line_offset
37
45
  message = "#{file}:#{line}:#{parser.failure_column}: Parse error, expected #{expected}."
38
46
  super(message)
@@ -2,47 +2,48 @@ require 'cucumber/step_definition'
2
2
  require 'cucumber/core_ext/instance_exec'
3
3
 
4
4
  module Cucumber
5
- # This is the main interface for registering step definitions, which is done
6
- # from <tt>*_steps.rb</tt> files. This module is included right at the top-level
7
- # so #register_step_definition (and more interestingly - its aliases) are
8
- # available from the top-level.
9
- module StepMother
10
- attr_writer :snippet_generator
11
-
12
- class Undefined < StandardError
13
- attr_reader :step_name
5
+ class Undefined < StandardError
6
+ attr_reader :step_name
14
7
 
15
- def initialize(step_name)
16
- super %{Undefined step: "#{step_name}"}
17
- @step_name = step_name
18
- end
19
- Cucumber::EXCEPTION_STATUS[self] = :undefined
8
+ def initialize(step_name)
9
+ super %{Undefined step: "#{step_name}"}
10
+ @step_name = step_name
20
11
  end
12
+ Cucumber::EXCEPTION_STATUS[self] = :undefined
13
+ end
21
14
 
22
- class Pending < StandardError
23
- Cucumber::EXCEPTION_STATUS[self] = :pending
24
- end
15
+ class Pending < StandardError
16
+ Cucumber::EXCEPTION_STATUS[self] = :pending
17
+ end
25
18
 
26
- # Raised when a step matches 2 or more StepDefinition
27
- class Ambiguous < StandardError
28
- def initialize(step_name, step_definitions)
29
- message = "Ambiguous match of \"#{step_name}\":\n\n"
30
- message << step_definitions.map{|sd| sd.to_backtrace_line}.join("\n")
31
- message << "\n\n"
32
- super(message)
33
- end
19
+ # Raised when a step matches 2 or more StepDefinition
20
+ class Ambiguous < StandardError
21
+ def initialize(step_name, step_definitions)
22
+ message = "Ambiguous match of \"#{step_name}\":\n\n"
23
+ message << step_definitions.map{|sd| sd.to_backtrace_line}.join("\n")
24
+ message << "\n\n"
25
+ super(message)
34
26
  end
27
+ end
35
28
 
36
- # Raised when 2 or more StepDefinition have the same Regexp
37
- class Redundant < StandardError
38
- def initialize(step_def_1, step_def_2)
39
- message = "Multiple step definitions have the same Regexp:\n\n"
40
- message << step_def_1.to_backtrace_line << "\n"
41
- message << step_def_2.to_backtrace_line << "\n\n"
42
- super(message)
43
- end
29
+ # Raised when 2 or more StepDefinition have the same Regexp
30
+ class Redundant < StandardError
31
+ def initialize(step_def_1, step_def_2)
32
+ message = "Multiple step definitions have the same Regexp:\n\n"
33
+ message << step_def_1.to_backtrace_line << "\n"
34
+ message << step_def_2.to_backtrace_line << "\n\n"
35
+ super(message)
44
36
  end
37
+ end
45
38
 
39
+ # This is the main interface for registering step definitions, which is done
40
+ # from <tt>*_steps.rb</tt> files. This module is included right at the top-level
41
+ # so #register_step_definition (and more interestingly - its aliases) are
42
+ # available from the top-level.
43
+ module StepMother
44
+ attr_writer :snippet_generator
45
+ attr_writer :options
46
+
46
47
  # Registers a new StepDefinition. This method is aliased
47
48
  # to <tt>Given</tt>, <tt>When</tt> and <tt>Then</tt>.
48
49
  #
@@ -112,10 +113,22 @@ module Cucumber
112
113
  step_definition.match(step_name)
113
114
  end
114
115
  raise Undefined.new(step_name) if found.empty?
116
+ found = best_matches(step_name, found) if found.size > 1 && options[:guess]
115
117
  raise Ambiguous.new(step_name, found) if found.size > 1
116
118
  found[0]
117
119
  end
118
120
 
121
+ def best_matches(step_name, step_definitions)
122
+ top_group_score = step_definitions.map {|s| s.match(step_name).captures.length }.sort.last
123
+ top_groups = step_definitions.select {|s| s.match(step_name).captures.length == top_group_score }
124
+ if top_groups.size > 1
125
+ shortest_capture_length = top_groups.map {|s| s.match(step_name).captures.inject(0) {|sum, c| sum + c.length } }.sort.first
126
+ top_groups.select {|s| s.match(step_name).captures.inject(0) {|sum, c| sum + c.length } == shortest_capture_length }
127
+ else
128
+ top_groups
129
+ end
130
+ end
131
+
119
132
  def step_definitions
120
133
  @step_definitions ||= []
121
134
  end
@@ -124,6 +137,12 @@ module Cucumber
124
137
  @snippet_generator.snippet_text(step_keyword, step_name)
125
138
  end
126
139
 
140
+ private
141
+
142
+ def options
143
+ @options || {}
144
+ end
145
+
127
146
  module WorldMethods #:nodoc:
128
147
  attr_writer :__cucumber_step_mother, :__cucumber_current_step
129
148
 
@@ -3,7 +3,7 @@ module Cucumber #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 1
5
5
  TINY = 99
6
- PATCH = 15 # Set to nil for official release
6
+ PATCH = 17 # Set to nil for official release
7
7
 
8
8
  STRING = [MAJOR, MINOR, TINY, PATCH].compact.join('.')
9
9
  end
@@ -0,0 +1,239 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+ require 'yaml'
3
+
4
+ module Cucumber
5
+ module Cli
6
+ describe Configuration do
7
+
8
+ def given_cucumber_yml_defined_as(hash_or_string)
9
+ File.stub!(:exist?).and_return(true)
10
+ cucumber_yml = hash_or_string.is_a?(Hash) ? hash_or_string.to_yaml : hash_or_string
11
+ IO.stub!(:read).with('cucumber.yml').and_return(cucumber_yml)
12
+ end
13
+
14
+ before(:each) do
15
+ Kernel.stub!(:exit).and_return(nil)
16
+ end
17
+
18
+ it "should require files in support paths first" do
19
+ File.stub!(:directory?).and_return(true)
20
+ Dir.stub!(:[]).and_return(["/features/step_definitions/foo.rb","/features/support/env.rb"])
21
+
22
+ config = Configuration.new(StringIO.new)
23
+ config.parse!(%w{--require /features})
24
+
25
+ config.files_to_require.should == [
26
+ "/features/support/env.rb",
27
+ "/features/step_definitions/foo.rb"
28
+ ]
29
+ end
30
+
31
+ it "should expand args from YAML file" do
32
+ given_cucumber_yml_defined_as({'bongo' => '--require from/yml'})
33
+
34
+ config = Configuration.new
35
+ config.parse!(%w{--format progress --profile bongo})
36
+ config.options[:formats].should == {'progress' => STDOUT}
37
+ config.options[:require].should == ['from/yml']
38
+ end
39
+
40
+ it "should expand args from YAML file's default if there are no args" do
41
+ given_cucumber_yml_defined_as({'default' => '--require from/yml'})
42
+
43
+ config = Configuration.new
44
+ config.parse!([])
45
+ config.options[:require].should == ['from/yml']
46
+ end
47
+
48
+ it "should provide a helpful error message when a specified profile does not exists in YAML file" do
49
+ given_cucumber_yml_defined_as({'default' => '--require from/yml', 'html_report' => '--format html'})
50
+
51
+ config = Configuration.new(StringIO.new, error = StringIO.new)
52
+ config.parse!(%w{--profile i_do_not_exist})
53
+
54
+ expected_message = <<-END_OF_MESSAGE
55
+ Could not find profile: 'i_do_not_exist'
56
+
57
+ Defined profiles in cucumber.yml:
58
+ * default
59
+ * html_report
60
+ END_OF_MESSAGE
61
+
62
+ error.string.should == expected_message
63
+ end
64
+
65
+ it "should provide a helpful error message when a specified profile is not a String" do
66
+ given_cucumber_yml_defined_as({'foo' => [1,2,3]})
67
+
68
+ config = Configuration.new(StringIO.new, error = StringIO.new)
69
+ config.parse!(%w{--profile foo})
70
+
71
+ error.string.should == "Profiles must be defined as a String. The 'foo' profile was [1, 2, 3] (Array).\n"
72
+ end
73
+
74
+ it "should provide a helpful error message when a specified profile exists but is nil or blank" do
75
+ [nil, ' '].each do |bad_input|
76
+ given_cucumber_yml_defined_as({'foo' => bad_input})
77
+
78
+ config = Configuration.new(StringIO.new, error = StringIO.new)
79
+ config.parse!(%w{--profile foo})
80
+
81
+ error.string.should match(/The 'foo' profile in cucumber.yml was blank. Please define the command line arguments for the 'foo' profile in cucumber.yml./)
82
+ end
83
+ end
84
+
85
+ it "should provide a helpful error message when no YAML file exists and a profile is specified" do
86
+ File.should_receive(:exist?).with('cucumber.yml').and_return(false)
87
+
88
+ config = Configuration.new(StringIO.new, error = StringIO.new)
89
+ config.parse!(%w{--profile i_do_not_exist})
90
+
91
+ error.string.should match(/cucumber.yml was not found. Please refer to cucumber's documentaion on defining profiles in cucumber.yml./)
92
+ end
93
+
94
+ it "should provide a helpful error message when cucumber.yml is blank or malformed" do
95
+ expected_error_message = /cucumber.yml was found, but was blank or malformed. Please refer to cucumber's documentaion on correct profile usage./
96
+
97
+ ['', 'sfsadfs', "--- \n- an\n- array\n", "---dddfd"].each do |bad_input|
98
+ given_cucumber_yml_defined_as(bad_input)
99
+
100
+ config = Configuration.new(StringIO.new, error = StringIO.new)
101
+ config.parse!([])
102
+
103
+ error.string.should match(expected_error_message)
104
+ end
105
+ end
106
+
107
+ it "should procide a helpful error message when the YAML can not be parsed" do
108
+ expected_error_message = /cucumber.yml was found, but could not be parsed. Please refer to cucumber's documentaion on correct profile usage./
109
+
110
+ given_cucumber_yml_defined_as("input that causes an exception in YAML loading")
111
+ YAML.should_receive(:load).and_raise Exception
112
+
113
+ config = Configuration.new(StringIO.new, error = StringIO.new)
114
+ config.parse!([])
115
+
116
+ error.string.should match(expected_error_message)
117
+ end
118
+
119
+ it "should accept --dry-run option" do
120
+ config = Configuration.new(StringIO.new)
121
+ config.parse!(%w{--dry-run})
122
+ config.options[:dry_run].should be_true
123
+ end
124
+
125
+ it "should accept --no-source option" do
126
+ config = Configuration.new
127
+ config.parse!(%w{--no-source})
128
+
129
+ config.options[:source].should be_false
130
+ end
131
+
132
+ it "should accept --no-snippets option" do
133
+ config = Configuration.new
134
+ config.parse!(%w{--no-snippets})
135
+
136
+ config.options[:snippets].should be_false
137
+ end
138
+
139
+ it "should set snippets and source to false with --quiet option" do
140
+ config = Configuration.new
141
+ config.parse!(%w{--quiet})
142
+
143
+ config.options[:snippets].should be_nil
144
+ config.options[:source].should be_nil
145
+ end
146
+
147
+ it "should accept --verbose option" do
148
+ config = Configuration.new
149
+ config.parse!(%w{--verbose})
150
+
151
+ config.options[:verbose].should be_true
152
+ end
153
+
154
+ it "should accept --out option" do
155
+ config = Configuration.new(StringIO.new)
156
+ config.parse!(%w{--out jalla.txt})
157
+ config.options[:formats]['pretty'].should == 'jalla.txt'
158
+ end
159
+
160
+ it "should accept multiple --out options" do
161
+ config = Configuration.new(StringIO.new)
162
+ config.parse!(%w{--format progress --out file1 --out file2})
163
+ config.options[:formats].should == {'progress' => 'file2'}
164
+ end
165
+
166
+ it "should accept multiple --format options" do
167
+ config = Configuration.new(StringIO.new)
168
+ config.parse!(%w{--format pretty --format progress})
169
+ config.options[:formats].should have_key('pretty')
170
+ config.options[:formats].should have_key('progress')
171
+ end
172
+
173
+ it "should associate --out to previous --format" do
174
+ config = Configuration.new(StringIO.new)
175
+ config.parse!(%w{--format progress --out file1 --format profile --out file2})
176
+ config.options[:formats].should == {"profile"=>"file2", "progress"=>"file1"}
177
+ end
178
+
179
+ it "should accept --color option" do
180
+ Term::ANSIColor.should_receive(:coloring=).with(true)
181
+ config = Configuration.new(StringIO.new)
182
+ config.parse!(['--color'])
183
+ end
184
+
185
+ it "should accept --no-color option" do
186
+ Term::ANSIColor.should_receive(:coloring=).with(false)
187
+ config = Configuration.new(StringIO.new)
188
+ config.parse!(['--no-color'])
189
+ end
190
+
191
+ describe "--backtrace" do
192
+ before do
193
+ Exception.cucumber_full_backtrace = false
194
+ end
195
+
196
+ it "should show full backtrace when --backtrace is present" do
197
+ config = Main.new(['--backtrace'])
198
+ begin
199
+ "x".should == "y"
200
+ rescue => e
201
+ e.backtrace[0].should_not == "#{__FILE__}:#{__LINE__ - 2}"
202
+ end
203
+ end
204
+
205
+ xit "should strip gems when --backtrace is absent" do
206
+ config = Main.new(['--'])
207
+ begin
208
+ "x".should == "y"
209
+ rescue => e
210
+ e.backtrace[0].should == "#{__FILE__}:#{__LINE__ - 2}"
211
+ end
212
+ end
213
+
214
+ after do
215
+ Exception.cucumber_full_backtrace = false
216
+ end
217
+ end
218
+
219
+ it "should accept multiple --scenario options" do
220
+ config = Configuration.new
221
+ config.parse!(['--scenario', "User logs in", '--scenario', "User signs up"])
222
+
223
+ config.options[:scenario_names].should include("User logs in")
224
+ config.options[:scenario_names].should include("User signs up")
225
+ end
226
+
227
+ it "should search for all features in the specified directory" do
228
+ File.stub!(:directory?).and_return(true)
229
+ Dir.should_receive(:[]).with("feature_directory/**/*.feature").any_number_of_times.and_return(["cucumber.feature"])
230
+
231
+ config = Configuration.new(StringIO)
232
+ config.parse!(%w{feature_directory/})
233
+
234
+ config.feature_files.should == ["cucumber.feature"]
235
+ end
236
+
237
+ end
238
+ end
239
+ end