cucumber 0.1.12 → 0.1.13

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. data/History.txt +38 -3
  2. data/Manifest.txt +17 -1
  3. data/README.txt +2 -39
  4. data/bin/cucumber +1 -1
  5. data/examples/calculator_ruby_features/features/addition.rb +16 -0
  6. data/examples/i18n/ar/features/step_definitons/calculator_steps.rb +1 -1
  7. data/examples/i18n/da/features/step_definitons/kalkulator_steps.rb +1 -0
  8. data/examples/i18n/de/features/step_definitons/calculator_steps.rb +1 -0
  9. data/examples/i18n/en/features/step_definitons/calculator_steps.rb +1 -0
  10. data/examples/i18n/es/features/step_definitons/calculador_steps.rb +1 -0
  11. data/examples/i18n/et/features/step_definitions/kalkulaator_steps.rb +1 -0
  12. data/examples/i18n/fr/features/addition.feature +13 -11
  13. data/examples/i18n/fr/features/step_definitions/calculatrice_steps.rb +6 -2
  14. data/examples/i18n/id/features/step_definitons/calculator_steps.rb +1 -0
  15. data/examples/i18n/it/features/step_definitons/calcolatrice_steps.rb +1 -0
  16. data/examples/i18n/ja/features/step_definitons/calculator_steps.rb +2 -0
  17. data/examples/i18n/lt/features/step_definitons/calculator_steps.rb +1 -0
  18. data/examples/i18n/no/features/step_definitons/kalkulator_steps.rb +1 -0
  19. data/examples/i18n/pt/features/step_definitions/calculadora_steps.rb +1 -0
  20. data/examples/i18n/ro/features/step_definitons/calculator_steps.rb +1 -0
  21. data/examples/i18n/se/features/step_definitons/kalkulator_steps.rb +1 -0
  22. data/examples/i18n/zh-CN/features/step_definitons/calculator_steps.rb +1 -0
  23. data/examples/selenium/features/search.feature +1 -1
  24. data/examples/selenium/features/step_definitons/stories_steps.rb +2 -3
  25. data/examples/tickets/features/lib/eatting_machine.rb +18 -0
  26. data/examples/tickets/features/lib/pantry.rb +20 -0
  27. data/examples/tickets/features/scenario_outline.feature +64 -0
  28. data/examples/tickets/features/step_definitons/scenario_outline_steps.rb +34 -0
  29. data/examples/tickets/features/step_definitons/tickets_steps.rb +4 -0
  30. data/gem_tasks/fix_cr_lf.rake +1 -1
  31. data/gem_tasks/yard.rake +8 -0
  32. data/lib/autotest/cucumber_mixin.rb +3 -3
  33. data/lib/cucumber.rb +2 -0
  34. data/lib/cucumber/broadcaster.rb +1 -1
  35. data/lib/cucumber/cli.rb +87 -42
  36. data/lib/cucumber/core_ext/exception.rb +20 -0
  37. data/lib/cucumber/core_ext/string.rb +1 -1
  38. data/lib/cucumber/executor.rb +35 -18
  39. data/lib/cucumber/formatters/ansicolor.rb +65 -74
  40. data/lib/cucumber/formatters/html_formatter.rb +33 -10
  41. data/lib/cucumber/formatters/pretty_formatter.rb +58 -16
  42. data/lib/cucumber/formatters/progress_formatter.rb +3 -0
  43. data/lib/cucumber/formatters/unicode.rb +27 -0
  44. data/lib/cucumber/languages.yml +6 -4
  45. data/lib/cucumber/platform.rb +1 -0
  46. data/lib/cucumber/rails/world.rb +6 -6
  47. data/lib/cucumber/step_mother.rb +3 -0
  48. data/lib/cucumber/tree/feature.rb +28 -2
  49. data/lib/cucumber/tree/scenario.rb +62 -1
  50. data/lib/cucumber/tree/step.rb +32 -1
  51. data/lib/cucumber/treetop_parser/feature.treetop.erb +54 -7
  52. data/lib/cucumber/treetop_parser/feature_ar.rb +377 -18
  53. data/lib/cucumber/treetop_parser/feature_cy.rb +377 -18
  54. data/lib/cucumber/treetop_parser/feature_da.rb +377 -18
  55. data/lib/cucumber/treetop_parser/feature_de.rb +377 -18
  56. data/lib/cucumber/treetop_parser/feature_en-lol.rb +377 -18
  57. data/lib/cucumber/treetop_parser/feature_en-tx.rb +377 -18
  58. data/lib/cucumber/treetop_parser/feature_en.rb +377 -18
  59. data/lib/cucumber/treetop_parser/feature_es.rb +377 -18
  60. data/lib/cucumber/treetop_parser/feature_et.rb +377 -18
  61. data/lib/cucumber/treetop_parser/feature_fr.rb +389 -30
  62. data/lib/cucumber/treetop_parser/feature_id.rb +377 -18
  63. data/lib/cucumber/treetop_parser/feature_it.rb +377 -18
  64. data/lib/cucumber/treetop_parser/feature_ja.rb +377 -18
  65. data/lib/cucumber/treetop_parser/feature_lt.rb +377 -18
  66. data/lib/cucumber/treetop_parser/feature_nl.rb +377 -18
  67. data/lib/cucumber/treetop_parser/feature_no.rb +377 -18
  68. data/lib/cucumber/treetop_parser/feature_pl.rb +377 -18
  69. data/lib/cucumber/treetop_parser/feature_pt.rb +377 -18
  70. data/lib/cucumber/treetop_parser/feature_ro.rb +377 -18
  71. data/lib/cucumber/treetop_parser/feature_ro2.rb +377 -18
  72. data/lib/cucumber/treetop_parser/feature_ru.rb +377 -18
  73. data/lib/cucumber/treetop_parser/feature_se.rb +377 -18
  74. data/lib/cucumber/treetop_parser/feature_zh-CN.rb +377 -18
  75. data/lib/cucumber/version.rb +1 -1
  76. data/lib/cucumber/world.rb +1 -0
  77. data/lib/cucumber/world/pending.rb +22 -0
  78. data/rails_generators/cucumber/templates/env.rb +1 -0
  79. data/rails_generators/feature/feature_generator.rb +22 -2
  80. data/rails_generators/feature/templates/feature.erb +15 -12
  81. data/rails_generators/feature/templates/steps.erb +16 -14
  82. data/spec/cucumber/cli_spec.rb +87 -6
  83. data/spec/cucumber/executor_spec.rb +102 -30
  84. data/spec/cucumber/formatters/ansicolor_spec.rb +10 -10
  85. data/spec/cucumber/formatters/html_formatter_spec.rb +30 -0
  86. data/spec/cucumber/formatters/pretty_formatter_spec.rb +139 -4
  87. data/spec/cucumber/formatters/progress_formatter_spec.rb +16 -0
  88. data/spec/cucumber/tree/feature_spec.rb +84 -5
  89. data/spec/cucumber/tree/row_scenario_outline_spec.rb +73 -0
  90. data/spec/cucumber/tree/row_step_outline_spec.rb +38 -0
  91. data/spec/cucumber/tree/scenario_outline_spec.rb +50 -0
  92. data/spec/cucumber/tree/step_outline_spec.rb +17 -0
  93. data/spec/cucumber/tree/step_spec.rb +9 -0
  94. data/spec/cucumber/treetop_parser/empty_scenario_outline.feature +3 -0
  95. data/spec/cucumber/treetop_parser/feature_parser_spec.rb +22 -0
  96. data/spec/cucumber/treetop_parser/invalid_scenario_outlines.feature +7 -0
  97. data/spec/cucumber/treetop_parser/scenario_outline.feature +16 -0
  98. data/spec/cucumber/world/pending_spec.rb +46 -0
  99. data/spec/spec_helper.rb +2 -1
  100. metadata +19 -4
  101. data/TODO.txt +0 -26
@@ -1,3 +1,5 @@
1
+ require 'cgi'
2
+
1
3
  module Cucumber
2
4
  module Formatters
3
5
  class HtmlFormatter
@@ -53,15 +55,11 @@ HTML
53
55
  end
54
56
 
55
57
  def visit_regular_scenario(scenario)
56
- @scenario_table_header = scenario.table_header
57
- @io.puts %{ <dl class="new">}
58
- @io.puts %{ <dt>#{Cucumber.language['scenario']}: #{scenario.name}</dt>}
59
- @io.puts %{ <dd>}
60
- @io.puts %{ <ul>}
61
- scenario.accept(self)
62
- @io.puts %{ </ul>}
63
- @io.puts %{ </dd>}
64
- @io.puts %{ </dl>}
58
+ visit_scenario(scenario, Cucumber.language['scenario'])
59
+ end
60
+
61
+ def visit_scenario_outline(scenario)
62
+ visit_scenario(scenario, Cucumber.language['scenario_outline'])
65
63
  end
66
64
 
67
65
  def visit_row_scenario(scenario)
@@ -86,6 +84,7 @@ HTML
86
84
 
87
85
  def visit_row_step(step)
88
86
  _, args, _ = step.regexp_args_proc(@step_mother)
87
+ args = step.visible_args if step.outline?
89
88
  args.each do |arg|
90
89
  @io.puts %{ <td id="#{step.id}"><span>#{arg}</span></td>}
91
90
  end
@@ -95,6 +94,11 @@ HTML
95
94
  regexp, _, _ = step.regexp_args_proc(@step_mother)
96
95
  @io.puts %{ <li class="new" id="#{step.id}">#{step.keyword} #{step.format(regexp, '<span>%s</span>')}</li>}
97
96
  end
97
+
98
+ def visit_step_outline(step)
99
+ regexp, _, _ = step.regexp_args_proc(@step_mother)
100
+ @io.puts %{ <li class="new" id="#{step.id}">#{step.keyword} #{CGI.escapeHTML(step.format(nil))}</li>}
101
+ end
98
102
 
99
103
  def step_passed(step, regexp, args)
100
104
  print_javascript_tag("stepPassed(#{step.id})")
@@ -112,7 +116,11 @@ HTML
112
116
  def step_skipped(step, regexp, args)
113
117
  # noop
114
118
  end
115
-
119
+
120
+ def step_traced(step, regexp, args)
121
+ # noop
122
+ end
123
+
116
124
  def print_javascript_tag(js)
117
125
  @io.puts %{ <script type="text/javascript">#{js}</script>}
118
126
  end
@@ -123,6 +131,21 @@ HTML
123
131
  </html>
124
132
  HTML
125
133
  end
134
+
135
+ private
136
+
137
+ def visit_scenario(scenario, scenario_or_scenario_outline_keyword)
138
+ @scenario_table_header = scenario.table_header
139
+ @io.puts %{ <dl class="new">}
140
+ @io.puts %{ <dt>#{scenario_or_scenario_outline_keyword}: #{scenario.name}</dt>}
141
+ @io.puts %{ <dd>}
142
+ @io.puts %{ <ul>}
143
+ scenario.accept(self)
144
+ @io.puts %{ </ul>}
145
+ @io.puts %{ </dd>}
146
+ @io.puts %{ </dl>}
147
+ end
148
+
126
149
  end
127
150
  end
128
151
  end
@@ -6,7 +6,6 @@ module Cucumber
6
6
  include ANSIColor
7
7
 
8
8
  INDENT = "\n "
9
- BACKTRACE_FILTER_PATTERNS = [/vendor\/rails/, /vendor\/plugins\/cucumber/, /spec\/expectations/, /spec\/matchers/]
10
9
 
11
10
  def initialize(io, step_mother, options={})
12
11
  @io = (io == STDOUT) ? Kernel : io
@@ -18,6 +17,8 @@ module Cucumber
18
17
  @pending_steps = []
19
18
  @skipped = []
20
19
  @last_executed_was_row = false
20
+ @pending_messages = {}
21
+ @forced_pending_step_count = 0
21
22
  end
22
23
 
23
24
  def feature_executing(feature)
@@ -40,17 +41,23 @@ module Cucumber
40
41
  end
41
42
 
42
43
  def scenario_executing(scenario)
44
+ scenario_or_scenario_outline_keyword = scenario.outline? ? Cucumber.language['scenario_outline'] : Cucumber.language['scenario']
45
+
43
46
  @scenario_failed = false
44
47
  @io.puts if @last_executed_was_row && !scenario.row?
45
48
  if scenario.row?
46
49
  @last_executed_was_row = true
47
50
  @io.print " |"
48
51
  else
52
+ scenario_text = "#{scenario_or_scenario_outline_keyword}: #{scenario.name}"
53
+
49
54
  if scenario.pending?
50
55
  @pending_scenarios << scenario
51
- @io.print pending(" #{Cucumber.language['scenario']}: #{scenario.name}")
56
+ @io.print pending(" #{scenario_text}")
57
+ elsif scenario.outline?
58
+ @io.print skipped(" #{scenario_text}")
52
59
  else
53
- @io.print passed(" #{Cucumber.language['scenario']}: #{scenario.name}")
60
+ @io.print passed(" #{scenario_text}")
54
61
  end
55
62
  @last_executed_was_row = false
56
63
 
@@ -78,6 +85,7 @@ module Cucumber
78
85
 
79
86
  def step_passed(step, regexp, args)
80
87
  if step.row?
88
+ args = step.visible_args if step.outline?
81
89
  @passed << step
82
90
  print_passed_args(args)
83
91
  else
@@ -93,6 +101,7 @@ module Cucumber
93
101
 
94
102
  def step_failed(step, regexp, args)
95
103
  if step.row?
104
+ args = step.visible_args if step.outline?
96
105
  @failed << step
97
106
  @scenario_failed = true
98
107
  print_failed_args(args)
@@ -112,12 +121,17 @@ module Cucumber
112
121
  def step_skipped(step, regexp, args)
113
122
  @skipped << step
114
123
  if step.row?
124
+ args = step.visible_args if step.outline?
115
125
  print_skipped_args(args)
116
126
  else
117
127
  @io.print skipped(" #{step.keyword} #{step.format(regexp){|param| skipped_param(param) << skipped}}")
118
128
  if @options[:source]
119
129
  @io.print padding_spaces(step)
120
- @io.print source_comment(step)
130
+ if step.outline?
131
+ @io.print comment("# #{step.file}:#{step.line}")
132
+ else
133
+ @io.print source_comment(step)
134
+ end
121
135
  end
122
136
  @io.puts
123
137
  end
@@ -125,6 +139,7 @@ module Cucumber
125
139
 
126
140
  def step_pending(step, regexp, args)
127
141
  if step.row?
142
+ args = step.visible_args if step.outline?
128
143
  @pending_steps << step
129
144
  print_pending_args(args)
130
145
  else
@@ -136,38 +151,61 @@ module Cucumber
136
151
  end
137
152
  @io.puts
138
153
  end
154
+ if step.forced_to_pending?
155
+ @pending_messages[regexp.inspect] ||= "#{step.keyword} #{regexp.inspect} (#{step.error.message}) #{source_comment(step)}"
156
+ @forced_pending_step_count += 1
157
+ end
158
+ end
159
+
160
+ def step_traced(step, regexp, args)
161
+ @io.print skipped(" #{step.keyword} #{step.format(regexp){|param| skipped_param(param) << skipped}}")
162
+ if @options[:source]
163
+ @io.print padding_spaces(step)
164
+ @io.print comment("# #{step.file}:#{step.line}")
165
+ end
166
+ @io.puts
139
167
  end
140
168
 
141
169
  def output_failing_step(step)
142
- backtrace = step.error.backtrace || []
143
- clean_backtrace = backtrace.map {|b| b.split("\n") }.flatten.reject do |line|
144
- BACKTRACE_FILTER_PATTERNS.detect{|p| line =~ p}
145
- end.map { |line| line.strip }
146
170
  @io.puts failed(" #{step.error.message.split("\n").join(INDENT)} (#{step.error.class})")
147
- @io.puts failed(" #{clean_backtrace.join(INDENT)}")
171
+ @io.puts failed(" #{step.error.cucumber_backtrace.join(INDENT)}")
148
172
  end
149
173
 
150
174
  def dump
151
175
  @io.puts
152
176
 
177
+ print_pending_messages if @pending_messages.any?
178
+
153
179
  @io.puts pending("#{@pending_scenarios.length} scenarios pending") if @pending_scenarios.any?
154
180
 
155
181
  @io.puts passed("#{@passed.length} steps passed") if @passed.any?
156
182
  @io.puts failed("#{@failed.length} steps failed") if @failed.any?
157
183
  @io.puts skipped("#{@skipped.length} steps skipped") if @skipped.any?
158
- @io.puts pending("#{@pending_steps.length} steps pending") if @pending_steps.any?
184
+ if @pending_steps.any?
185
+ @io.print pending("#{@pending_steps.length} steps pending")
186
+ @io.print pending(" (#{number_of_unimplemented_steps} with no step definition)") if number_of_unimplemented_steps > 0
187
+ @io.puts
188
+ end
159
189
 
160
190
  @io.print reset
161
191
 
162
192
  print_snippets if @options[:snippets]
163
193
  end
164
194
 
195
+ def print_pending_messages
196
+ @io.puts "Pending Notes:"
197
+ @pending_messages.each_value do |message|
198
+ @io.puts message
199
+ end
200
+ @io.puts
201
+ end
202
+
165
203
  def print_snippets
166
204
  snippets = @pending_steps
167
205
  snippets.delete_if {|snippet| snippet.row? || @step_mother.has_step_definition?(snippet.name)}
168
206
 
169
207
  unless snippets.empty?
170
- @io.puts "\nYou can use these snippets to implement pending steps:\n\n"
208
+ @io.puts "\nYou can use these snippets to implement pending steps which have no step definition:\n\n"
171
209
 
172
210
  prev_keyword = nil
173
211
  snippets = snippets.map do |step|
@@ -184,6 +222,10 @@ module Cucumber
184
222
 
185
223
  private
186
224
 
225
+ def number_of_unimplemented_steps
226
+ @pending_steps.length - @forced_pending_step_count
227
+ end
228
+
187
229
  def escape_regexp_characters(string)
188
230
  Regexp.escape(string).gsub('\ ', ' ').gsub('/', '\/') unless string.nil?
189
231
  end
@@ -204,7 +246,7 @@ module Cucumber
204
246
  @current_column
205
247
  end
206
248
 
207
- def print_row row_args, &colorize_proc
249
+ def print_row(row_args, &colorize_proc)
208
250
  colorize_proc = Proc.new{|row_element| row_element} unless colorize_proc
209
251
 
210
252
  row_args.each do |row_arg|
@@ -214,19 +256,19 @@ module Cucumber
214
256
  end
215
257
  end
216
258
 
217
- def print_passed_args args
259
+ def print_passed_args(args)
218
260
  print_row(args) {|arg| passed(arg)}
219
261
  end
220
262
 
221
- def print_skipped_args args
263
+ def print_skipped_args(args)
222
264
  print_row(args) {|arg| skipped(arg)}
223
265
  end
224
266
 
225
- def print_failed_args args
267
+ def print_failed_args(args)
226
268
  print_row(args) {|arg| failed(arg)}
227
269
  end
228
270
 
229
- def print_pending_args args
271
+ def print_pending_args(args)
230
272
  print_row(args) {|arg| pending(arg)}
231
273
  end
232
274
  end
@@ -36,6 +36,9 @@ module Cucumber
36
36
  @io.print skipped('_')
37
37
  end
38
38
 
39
+ def step_traced(step, regexp, args)
40
+ end
41
+
39
42
  def dump
40
43
  @io.puts pending
41
44
  @io.puts "\nPending Scenarios:\n\n" if @pending_scenarios.any?
@@ -0,0 +1,27 @@
1
+ # Require this file if you need Unicode support.
2
+ require 'cucumber/platform'
3
+ require 'cucumber/formatters/ansicolor'
4
+
5
+ $KCODE='u'
6
+
7
+ if $CUCUMBER_WINDOWS_MRI && `chcp` =~ /Active code page: (\d+)/
8
+ codepage = $1.to_i
9
+ codepages = (1251..1252)
10
+
11
+ if codepages.include?(codepage)
12
+ $CUCUMBER_CODEPAGE = "cp#{codepage}"
13
+
14
+ require 'iconv'
15
+ module Kernel
16
+ alias cucumber_print print
17
+ def print(*a)
18
+ cucumber_print *Iconv.iconv($CUCUMBER_CODEPAGE, "UTF-8", *a)
19
+ end
20
+
21
+ alias cucumber_puts puts
22
+ def puts(*a)
23
+ cucumber_puts *Iconv.iconv($CUCUMBER_CODEPAGE, "UTF-8", *a)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -7,6 +7,8 @@
7
7
  "en":
8
8
  feature: Feature
9
9
  scenario: Scenario
10
+ scenario_outline: Scenario Outline
11
+ examples: Examples
10
12
  more_examples: More Examples
11
13
  given_scenario: GivenScenario
12
14
  given: Given
@@ -108,11 +110,11 @@
108
110
  but: Kuid
109
111
  # French
110
112
  "fr":
111
- feature: Fonction
112
- scenario: Scenario
113
+ feature: Fonctionnalité
114
+ scenario: Scénario
113
115
  more_examples: Plus d'exemples
114
- given_scenario: SoitScenario
115
- given: Soit
116
+ given_scenario: Soit le Scénario
117
+ given: Etant donné
116
118
  when: Lorsque
117
119
  then: Alors
118
120
  and: Et
@@ -7,3 +7,4 @@ $CUCUMBER_IRONRUBY = Config::CONFIG['sitedir'] =~ /IronRuby/
7
7
  $CUCUMBER_WINDOWS = Config::CONFIG['host_os'] =~ /mswin|mingw/
8
8
  $CUCUMBER_WINDOWS_MRI = $CUCUMBER_WINDOWS && !$CUCUMBER_JRUBY && !$CUCUMBER_IRONRUBY
9
9
  $CUCUMBER_RAILS = defined?(Rails)
10
+ $CUCUMBER_RUBY = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])
@@ -11,7 +11,7 @@ require 'test/unit/testresult'
11
11
 
12
12
  # These allow exceptions to come through as opposed to being caught and having non-helpful responses returned.
13
13
  ActionController::Base.class_eval do
14
- def perform_action
14
+ def perform_action_with_rescue
15
15
  perform_action_without_rescue
16
16
  end
17
17
  end
@@ -24,7 +24,7 @@ end
24
24
  # So that Test::Unit doesn't launch at the end - makes it think it has already been run.
25
25
  Test::Unit.run = true if Test::Unit.respond_to?(:run=)
26
26
 
27
- $main = self
27
+ $cucumber_toplevel = self
28
28
 
29
29
  module Cucumber #:nodoc:
30
30
  module Rails
@@ -44,22 +44,22 @@ module Cucumber #:nodoc:
44
44
  def self.use_transactional_fixtures
45
45
  World.use_transactional_fixtures = true
46
46
  if defined?(ActiveRecord::Base)
47
- $main.Before do
47
+ $cucumber_toplevel.Before do
48
48
  if ActiveRecord::Base.connection.respond_to?(:increment_open_transactions)
49
49
  ActiveRecord::Base.connection.increment_open_transactions
50
50
  else
51
- ActiveRecord::Base.send :increment_open_transactions
51
+ ActiveRecord::Base.__send__(:increment_open_transactions)
52
52
  end
53
53
  ActiveRecord::Base.connection.begin_db_transaction
54
54
  ActionMailer::Base.deliveries = [] if defined?(ActionMailer::Base)
55
55
  end
56
56
 
57
- $main.After do
57
+ $cucumber_toplevel.After do
58
58
  ActiveRecord::Base.connection.rollback_db_transaction
59
59
  if ActiveRecord::Base.connection.respond_to?(:decrement_open_transactions)
60
60
  ActiveRecord::Base.connection.decrement_open_transactions
61
61
  else
62
- ActiveRecord::Base.send :decrement_open_transactions
62
+ ActiveRecord::Base.__send__(:decrement_open_transactions)
63
63
  end
64
64
  end
65
65
  end
@@ -4,6 +4,9 @@ module Cucumber
4
4
  class Pending < StandardError
5
5
  end
6
6
 
7
+ class ForcedPending < Pending
8
+ end
9
+
7
10
  class Duplicate < StandardError
8
11
  end
9
12
 
@@ -19,11 +19,23 @@ module Cucumber
19
19
  scenario
20
20
  end
21
21
 
22
+ def add_scenario_outline(name, line, &proc)
23
+ scenario = ScenarioOutline.new(self, name, line, &proc)
24
+ @scenarios << scenario
25
+ scenario
26
+ end
27
+
22
28
  def add_row_scenario(template_scenario, values, line)
23
29
  scenario = RowScenario.new(self, template_scenario, values, line)
24
30
  @scenarios << scenario
25
31
  scenario
26
32
  end
33
+
34
+ def add_row_scenario_outline(template_scenario, values, line)
35
+ scenario = RowScenarioOutline.new(self, template_scenario, values, line)
36
+ @scenarios << scenario
37
+ scenario
38
+ end
27
39
 
28
40
  def scenario_named(name)
29
41
  @scenarios.find {|s| s.name == name}
@@ -38,26 +50,40 @@ module Cucumber
38
50
  add_scenario(name, line, &proc)
39
51
  end
40
52
 
53
+ def ScenarioOutline(name, &proc)
54
+ line = caller[0] =~ /:(\d+)$/ ? $1 : nil
55
+ add_scenario_outline(name, line, &proc)
56
+ end
57
+
41
58
  def Table(matrix = [], &proc)
42
59
  table = Table.new(matrix)
43
60
  proc.call(table)
61
+
44
62
  template_scenario = @scenarios.last
45
63
  template_scenario.table_header = matrix[0]
64
+
46
65
  matrix[1..-1].each do |row|
47
- add_row_scenario(template_scenario, row, row.line)
66
+ if template_scenario.outline?
67
+ add_row_scenario_outline(template_scenario, row, row.line)
68
+ else
69
+ add_row_scenario(template_scenario, row, row.line)
70
+ end
48
71
  end
49
72
  end
50
73
 
51
74
  def accept(visitor)
52
75
  visitor.visit_header(@header)
53
76
  @scenarios.each do |scenario|
54
- if scenario.row?
77
+ if scenario.outline? && !scenario.row?
78
+ visitor.visit_scenario_outline(scenario)
79
+ elsif scenario.row?
55
80
  visitor.visit_row_scenario(scenario)
56
81
  else
57
82
  visitor.visit_regular_scenario(scenario)
58
83
  end
59
84
  end
60
85
  end
86
+
61
87
  end
62
88
  end
63
89
  end