public
Fork of aslakhellesoy/cucumber
Description: A reimplementation of RSpec's story framework, based on Treetop.
Homepage: http://github.com/aslakhellesoy/cucumber/wikis
Clone URL: git://github.com/josephwilk/cucumber.git
Add support for calling 'pending' from step defintions.
Joseph Wilk (author)
Sun Dec 07 11:09:52 -0800 2008
commit  ad48ddf031f0cf1d1776c8baed03ffef3b507775
tree    bc642c5cf4c248d11cea0c94ecd1bbcb7e04b704
parent  db4696e3240a79a2634d5ca0ebe9aa52f7022017
...
15
16
17
 
18
19
20
...
15
16
17
18
19
20
21
0
@@ -15,6 +15,7 @@ require 'cucumber/formatters'
0
 require 'cucumber/treetop_parser/feature_parser'
0
 require 'cucumber/cli'
0
 require 'cucumber/broadcaster'
0
+require 'cucumber/world'
0
 
0
 module Cucumber
0
   LANGUAGE_FILE = File.expand_path(File.dirname(__FILE__) + '/cucumber/languages.yml')
...
112
113
114
 
 
 
115
116
117
...
124
125
126
 
 
 
127
128
129
...
179
180
181
 
182
183
184
...
112
113
114
115
116
117
118
119
120
...
127
128
129
130
131
132
133
134
135
...
185
186
187
188
189
190
191
0
@@ -112,6 +112,9 @@ module Cucumber
0
           step.execute_in(@world, regexp, args, proc)
0
           @after_step_procs.each{|p| p.call_in(@world, *[])}
0
           formatters.step_passed(step, regexp, args)
0
+        rescue ForcedPending => e
0
+          step.error = e
0
+          record_pending_step(step, regexp, args)
0
         rescue Pending
0
           record_pending_step(step, regexp, args)
0
         rescue => e
0
@@ -124,6 +127,9 @@ module Cucumber
0
           regexp, args, proc = step.regexp_args_proc(@step_mother)
0
           step.execute_in(@world, regexp, args, proc)
0
           formatters.step_skipped(step, regexp, args)
0
+        rescue ForcedPending => e
0
+          step.error = e
0
+          record_pending_step(step, regexp, args)
0
         rescue Pending
0
           record_pending_step(step, regexp, args)
0
         rescue Exception
0
@@ -179,6 +185,7 @@ module Cucumber
0
     
0
     def create_world
0
       world = Object.new
0
+      world.extend(World::Pending)
0
       @world_procs.each do |world_proc|
0
         world = world_proc.call(world)
0
       end
...
18
19
20
 
 
21
22
23
...
136
137
138
 
 
 
 
139
140
141
...
150
151
152
 
 
153
154
155
156
157
158
 
 
 
 
 
159
160
161
162
163
164
 
 
 
 
 
 
 
 
165
166
167
168
169
170
 
171
172
173
...
184
185
186
 
 
 
 
187
188
189
...
18
19
20
21
22
23
24
25
...
138
139
140
141
142
143
144
145
146
147
...
156
157
158
159
160
161
162
163
164
165
 
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
 
190
191
192
193
...
204
205
206
207
208
209
210
211
212
213
0
@@ -18,6 +18,8 @@ module Cucumber
0
         @pending_steps      = []
0
         @skipped            = []
0
         @last_executed_was_row = false
0
+        @pending_messages = {}
0
+        @forced_pending_step_count = 0
0
       end
0
 
0
       def feature_executing(feature)
0
@@ -136,6 +138,10 @@ module Cucumber
0
           end
0
           @io.puts
0
         end
0
+        if step.forced_to_pending?
0
+          @pending_messages[regexp.inspect] ||= "#{step.keyword} #{regexp.inspect} (#{step.error.message}) #{source_comment(step)}" 
0
+          @forced_pending_step_count += 1
0
+        end
0
       end
0
 
0
       def output_failing_step(step)
0
@@ -150,24 +156,38 @@ module Cucumber
0
       def dump
0
         @io.puts
0
 
0
+        print_pending_messages if @pending_messages.any?
0
+
0
         @io.puts pending("#{@pending_scenarios.length} scenarios pending") if @pending_scenarios.any?
0
 
0
         @io.puts passed("#{@passed.length} steps passed")           if @passed.any?
0
         @io.puts failed("#{@failed.length} steps failed")           if @failed.any?
0
         @io.puts skipped("#{@skipped.length} steps skipped")        if @skipped.any?
0
-        @io.puts pending("#{@pending_steps.length} steps pending")  if @pending_steps.any?
0
+        if @pending_steps.any?
0
+          @io.print pending("#{@pending_steps.length} steps pending") 
0
+          @io.print pending(" (#{number_of_unimplemented_steps} with no step definition)") if number_of_unimplemented_steps > 0
0
+          @io.puts
0
+        end
0
 
0
         @io.print reset
0
 
0
         print_snippets if @options[:snippets]
0
       end
0
 
0
+      def print_pending_messages
0
+        @io.puts "Pending Notes:"
0
+        @pending_messages.each_value do |message|
0
+          @io.puts message
0
+        end
0
+        @io.puts
0
+      end
0
+
0
       def print_snippets
0
         snippets = @pending_steps
0
         snippets.delete_if {|snippet| snippet.row? || @step_mother.has_step_definition?(snippet.name)}
0
 
0
         unless snippets.empty?
0
-          @io.puts "\nYou can use these snippets to implement pending steps:\n\n"
0
+          @io.puts "\nYou can use these snippets to implement pending steps which have no step definition:\n\n"
0
 
0
           prev_keyword = nil
0
           snippets = snippets.map do |step|
0
@@ -184,6 +204,10 @@ module Cucumber
0
 
0
       private
0
 
0
+      def number_of_unimplemented_steps
0
+        @pending_steps.length - @forced_pending_step_count
0
+      end
0
+
0
       def escape_regexp_characters(string)
0
         Regexp.escape(string).gsub('\ ', ' ').gsub('/', '\/') unless string.nil?
0
       end
...
4
5
6
 
 
 
7
8
9
...
4
5
6
7
8
9
10
11
12
0
@@ -4,6 +4,9 @@ module Cucumber
0
   class Pending < StandardError
0
   end
0
 
0
+  class ForcedPending < Pending
0
+  end
0
+
0
   class Duplicate < StandardError
0
   end
0
 
...
90
91
92
 
 
 
 
 
93
94
95
...
90
91
92
93
94
95
96
97
98
99
100
0
@@ -90,6 +90,11 @@ module Cucumber
0
       def padding_length
0
         @scenario.step_padding_length(self)
0
       end
0
+
0
+      def forced_to_pending?
0
+        @error.kind_of?(ForcedPending)
0
+      end
0
+            
0
     end
0
     
0
     class Step < BaseStep
...
75
76
77
 
 
 
 
 
 
 
78
79
80
...
162
163
164
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
166
167
...
293
294
295
296
 
297
298
...
75
76
77
78
79
80
81
82
83
84
85
86
87
...
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
...
334
335
336
 
337
338
339
0
@@ -75,6 +75,13 @@ dang
0
         world.doit.should == "dunit"
0
         world.beatit.should == "beatenit"
0
       end
0
+      
0
+      it "should add support for calling 'pending' from world" do
0
+        world = @executor.create_world
0
+      
0
+        world.should respond_to(:pending)
0
+      end
0
+      
0
     end
0
 
0
     describe "visiting feature" do
0
@@ -162,6 +169,40 @@ dang
0
       end
0
       
0
     end
0
+    
0
+    describe "visit forced pending step" do
0
+
0
+      before(:each) do
0
+        @executor.formatters = mock('formatter', :null_object => true)          
0
+      end
0
+
0
+      it "should store the pending exception with the step" do
0
+        mock_step = mock("mock step", :regexp_args_proc => nil)
0
+        pending_exception = ForcedPending.new("implement me")
0
+        mock_step.stub!(:execute_in).and_raise(pending_exception)
0
+
0
+        mock_step.should_receive(:'error=').with(pending_exception)
0
+        
0
+        @executor.visit_step(mock_step)
0
+      end
0
+      
0
+      describe "after failed/pending step" do
0
+        
0
+        it "should store the pending exception with the step" do
0
+          mock_step_1 = mock("mock step", :null_object => true)
0
+          mock_step_2 = mock("mock step", :regexp_args_proc => nil)
0
+          pending_exception = ForcedPending.new("implement me")
0
+          mock_step_1.stub!(:execute_in).and_raise(StandardError)
0
+          mock_step_2.stub!(:execute_in).and_raise(pending_exception)
0
+
0
+          mock_step_2.should_receive(:'error=').with(pending_exception)
0
+
0
+          @executor.visit_step(mock_step_1)
0
+          @executor.visit_step(mock_step_2)
0
+        end
0
+        
0
+      end
0
+    end
0
               
0
     describe "visiting row scenarios" do
0
       
0
@@ -293,6 +334,6 @@ dang
0
         @executor.visit_features(@features)
0
       end
0
     end
0
-        
0
+
0
   end
0
 end
...
13
14
15
16
 
 
 
17
18
 
19
20
21
...
36
37
38
39
40
 
 
41
42
43
...
199
200
201
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
202
203
204
...
13
14
15
 
16
17
18
19
 
20
21
22
23
...
38
39
40
 
 
41
42
43
44
45
...
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
0
@@ -13,9 +13,11 @@ module Cucumber
0
           :padding_length => 2,
0
           :file => 'test',
0
           :line => 1,
0
-          :row? => false}.merge(stubs))
0
+          :row? => false,
0
+          :forced_to_pending? => false,
0
+          :regexp_args_proc => [nil, nil, mock_proc]}.merge(stubs))
0
       end
0
-
0
+   
0
       def mock_scenario(stubs={})
0
         stub('scenario', {
0
           :name => 'test',
0
@@ -36,8 +38,8 @@ module Cucumber
0
           :backtrace => 'example backtrace'}.merge(stubs))
0
       end
0
 
0
-      def mock_proc
0
-        stub(Proc, :to_comment_line => '# steps/example_steps.rb:11')
0
+      def mock_proc(stubs={})
0
+        stub(Proc, {:to_comment_line => '# steps/example_steps.rb:11'}.merge(stubs))
0
       end
0
 
0
       it "should print step file and line when passed" do
0
@@ -199,6 +201,74 @@ module Cucumber
0
         }.should_not raise_error(TypeError)
0
       end
0
 
0
+      describe "pending messages" do
0
+
0
+        before(:each) do
0
+          @io = StringIO.new
0
+          @formatter = PrettyFormatter.new @io, mock('step_mother')
0
+        end
0
+
0
+        it "should show pending message for step" do
0
+          @formatter.step_pending(mock_step(:keyword => 'Given', :forced_to_pending? => true, :error => ForcedPending.new("please implement me")), /yatta/, nil)
0
+
0
+          @formatter.dump
0
+        
0
+          @io.string.should include("Given /yatta/ (please implement me)")
0
+        end
0
+        
0
+        it "should show pending step's file and line" do
0
+          @formatter.step_pending(mock_step(:forced_to_pending? => true, :error => ForcedPending.new("please implement me"), 
0
+                                            :regexp_args_proc => [nil, nil, mock_proc(:to_comment_line => "steps/example_steps.rb:11")]), nil, nil)
0
+
0
+          @formatter.dump
0
+        
0
+          @io.string.should include("steps/example_steps.rb:11")
0
+        end
0
+        
0
+        it "should not show duplicates" do
0
+          @formatter.step_pending(mock_step(:keyword => 'Given', :forced_to_pending? => true, :error => ForcedPending.new("please implement me")), /yatta/, [])
0
+          @formatter.step_pending(mock_step(:forced_to_pending? => true, :error => ForcedPending.new("please implement me"), :row? => true), /yatta/, [])
0
+
0
+          @formatter.dump
0
+
0
+          @io.string.scan(/please implement me/).length.should_not == 2
0
+        end
0
+        
0
+        it "should ignore messages from steps that where not forced to pending" do
0
+          @formatter.step_pending(mock_step(:keyword => 'Given', :forced_to_pending? => false, :error => Pending.new("do not show me")), nil, [])
0
+          
0
+          @formatter.dump
0
+          
0
+          @io.string.should_not include("do not show me")
0
+        end
0
+        
0
+      end
0
+
0
+      describe "no pending messages" do
0
+        
0
+        it "should not show any pending message information" do
0
+          io = StringIO.new
0
+          formatter = PrettyFormatter.new io, mock('step_mother')
0
+
0
+          formatter.dump
0
+        
0
+          io.string.should_not include("Pending Notes:\n")
0
+        end
0
+
0
+      end
0
+      
0
+      it "should show number of pending steps that have no step definition" do
0
+        io = StringIO.new
0
+        formatter = PrettyFormatter.new io, mock('step_mother')
0
+        
0
+        formatter.step_pending(mock_step(:error => ForcedPending.new, :forced_to_pending? => true), nil, [])
0
+        formatter.step_pending(mock_step(:error => Pending.new, :forced_to_pending? => false), nil, [])
0
+        
0
+        formatter.dump
0
+        
0
+        io.string.should include("1 with no step definition")
0
+      end
0
+
0
     end
0
   end
0
 end
...
43
44
45
 
 
 
 
 
 
 
 
 
46
47
48
...
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
0
@@ -43,6 +43,15 @@ module Cucumber
0
         end
0
 
0
       end
0
+
0
+      it "should indicate if a forced pending exception occured" do
0
+        scenario = Scenario.new(nil, '9', 1)
0
+        step = scenario.create_step('Given', '666666', 98)
0
+        
0
+        step.instance_variable_set("@error", ForcedPending.new)
0
+        
0
+        step.should be_forced_to_pending
0
+      end
0
       
0
     end
0
   end

Comments