cucumber 1.2.5 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. checksums.yaml +14 -6
  2. data/.ruby-gemset +1 -0
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +1 -0
  5. data/.yardopts +1 -0
  6. data/CONTRIBUTING.md +2 -2
  7. data/History.md +38 -2
  8. data/bin/cucumber +2 -11
  9. data/cucumber.gemspec +3 -3
  10. data/cucumber.yml +5 -1
  11. data/examples/test_unit/Gemfile +4 -0
  12. data/examples/test_unit/features/step_definitions/test_unit_steps.rb +1 -4
  13. data/examples/watir/README.textile +2 -2
  14. data/examples/watir/features/support/env.rb +10 -7
  15. data/features/.cucumber/stepdefs.json +747 -1354
  16. data/features/assertions.feature +6 -2
  17. data/features/background.feature +3 -0
  18. data/features/backtraces.feature +3 -3
  19. data/features/before_hook.feature +43 -0
  20. data/features/bootstrap.feature +14 -2
  21. data/features/custom_formatter.feature +1 -1
  22. data/features/drb_server_integration.feature +3 -3
  23. data/features/formatter_callbacks.feature +2 -2
  24. data/features/formatter_step_file_colon_line.feature +1 -1
  25. data/features/html_formatter.feature +52 -1
  26. data/features/json_formatter.feature +93 -7
  27. data/features/load_path.feature +14 -0
  28. data/features/nested_steps.feature +75 -3
  29. data/features/nested_steps_i18n.feature +36 -0
  30. data/features/pretty_formatter.feature +31 -0
  31. data/features/progress_formatter.feature +31 -0
  32. data/features/raketask.feature +51 -0
  33. data/features/rerun_formatter.feature +1 -1
  34. data/features/stats_formatters.feature +17 -14
  35. data/features/step_definitions/cucumber_steps.rb +6 -4
  36. data/features/support/env.rb +31 -4
  37. data/features/support/feature_factory.rb +17 -0
  38. data/features/tagged_hooks.feature +37 -195
  39. data/features/transforms.feature +15 -15
  40. data/gem_tasks/cucumber.rake +2 -0
  41. data/gem_tasks/yard.rake +10 -6
  42. data/legacy_features/README.md +14 -0
  43. data/legacy_features/language_help.feature +3 -1
  44. data/legacy_features/report_called_undefined_steps.feature +1 -0
  45. data/legacy_features/snippets_when_using_star_keyword.feature +1 -0
  46. data/legacy_features/support/env.rb +4 -0
  47. data/lib/cucumber/ast/background.rb +35 -35
  48. data/lib/cucumber/ast/empty_background.rb +33 -0
  49. data/lib/cucumber/ast/examples.rb +5 -2
  50. data/lib/cucumber/ast/feature.rb +24 -35
  51. data/lib/cucumber/ast/features.rb +4 -1
  52. data/lib/cucumber/ast/has_steps.rb +9 -17
  53. data/lib/cucumber/ast/location.rb +41 -0
  54. data/lib/cucumber/ast/scenario.rb +37 -50
  55. data/lib/cucumber/ast/scenario_outline.rb +62 -49
  56. data/lib/cucumber/ast/step.rb +23 -27
  57. data/lib/cucumber/ast/step_collection.rb +16 -0
  58. data/lib/cucumber/ast/step_invocation.rb +4 -1
  59. data/lib/cucumber/ast/tree_walker.rb +7 -0
  60. data/lib/cucumber/cli/configuration.rb +15 -3
  61. data/lib/cucumber/cli/main.rb +24 -11
  62. data/lib/cucumber/cli/options.rb +24 -16
  63. data/lib/cucumber/configuration.rb +4 -0
  64. data/lib/cucumber/core_ext/disable_mini_and_test_unit_autorun.rb +10 -34
  65. data/lib/cucumber/core_ext/instance_exec.rb +4 -1
  66. data/lib/cucumber/core_ext/proc.rb +2 -0
  67. data/lib/cucumber/feature_file.rb +5 -12
  68. data/lib/cucumber/formatter/console.rb +10 -0
  69. data/lib/cucumber/formatter/gherkin_formatter_adapter.rb +4 -4
  70. data/lib/cucumber/formatter/html.rb +7 -42
  71. data/lib/cucumber/formatter/interceptor.rb +4 -0
  72. data/lib/cucumber/formatter/json_pretty.rb +0 -4
  73. data/lib/cucumber/formatter/junit.rb +8 -2
  74. data/lib/cucumber/formatter/pretty.rb +5 -1
  75. data/lib/cucumber/formatter/progress.rb +4 -0
  76. data/lib/cucumber/formatter/unicode.rb +12 -25
  77. data/lib/cucumber/formatter/usage.rb +7 -2
  78. data/lib/cucumber/js_support/js_snippets.rb +1 -1
  79. data/lib/cucumber/load_path.rb +13 -0
  80. data/lib/cucumber/parser/gherkin_builder.rb +237 -81
  81. data/lib/cucumber/platform.rb +1 -1
  82. data/lib/cucumber/py_support/py_language.rb +1 -1
  83. data/lib/cucumber/rake/task.rb +5 -1
  84. data/lib/cucumber/rb_support/rb_language.rb +20 -19
  85. data/lib/cucumber/rb_support/rb_world.rb +63 -21
  86. data/lib/cucumber/rb_support/snippet.rb +108 -0
  87. data/lib/cucumber/runtime.rb +1 -0
  88. data/lib/cucumber/runtime/support_code.rb +2 -2
  89. data/lib/cucumber/unit.rb +11 -0
  90. data/lib/cucumber/wire_support/wire_language.rb +1 -1
  91. data/spec/cucumber/ast/background_spec.rb +13 -6
  92. data/spec/cucumber/ast/feature_factory.rb +20 -10
  93. data/spec/cucumber/ast/features_spec.rb +51 -0
  94. data/spec/cucumber/ast/scenario_outline_spec.rb +13 -7
  95. data/spec/cucumber/ast/step_spec.rb +6 -4
  96. data/spec/cucumber/cli/configuration_spec.rb +34 -1
  97. data/spec/cucumber/cli/main_spec.rb +36 -26
  98. data/spec/cucumber/cli/options_spec.rb +28 -19
  99. data/spec/cucumber/core_ext/proc_spec.rb +13 -1
  100. data/spec/cucumber/formatter/interceptor_spec.rb +8 -0
  101. data/spec/cucumber/formatter/junit_spec.rb +33 -0
  102. data/spec/cucumber/formatter/pretty_spec.rb +391 -0
  103. data/spec/cucumber/rb_support/rb_language_spec.rb +21 -50
  104. data/spec/cucumber/rb_support/regexp_argument_matcher_spec.rb +2 -4
  105. data/spec/cucumber/rb_support/snippet_spec.rb +128 -0
  106. data/spec/cucumber/step_match_spec.rb +2 -6
  107. metadata +62 -113
  108. data/.rvmrc +0 -1
  109. data/features/hooks.feature +0 -59
  110. data/legacy_features/call_steps_from_stepdefs.feature +0 -154
@@ -42,7 +42,7 @@ module Cucumber
42
42
 
43
43
 
44
44
  def before_features(features)
45
- @step_count = get_step_count(features)
45
+ @step_count = features.step_count
46
46
 
47
47
  # <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
48
48
  @builder.declare!(
@@ -314,7 +314,11 @@ module Cucumber
314
314
  end
315
315
  end
316
316
  end
317
- set_scenario_color_failed
317
+ if table_row.exception.is_a? ::Cucumber::Pending
318
+ set_scenario_color_pending
319
+ else
320
+ set_scenario_color_failed
321
+ end
318
322
  end
319
323
  if @outline_row
320
324
  @outline_row += 1
@@ -398,7 +402,7 @@ module Cucumber
398
402
  end
399
403
 
400
404
  def set_scenario_color(status)
401
- if status == :undefined or status == :pending
405
+ if status.nil? or status == :undefined or status == :pending
402
406
  set_scenario_color_pending
403
407
  end
404
408
  if status == :failed
@@ -422,45 +426,6 @@ module Cucumber
422
426
  end
423
427
  end
424
428
 
425
- def get_step_count(features)
426
- count = 0
427
- features = features.instance_variable_get("@features")
428
- features.each do |feature|
429
- #get background steps
430
- if feature.instance_variable_get("@background")
431
- background = feature.instance_variable_get("@background")
432
- background.init
433
- background_steps = background.instance_variable_get("@steps").instance_variable_get("@steps")
434
- count += background_steps.size
435
- end
436
- #get scenarios
437
- feature.instance_variable_get("@feature_elements").each do |scenario|
438
- scenario.init
439
- #get steps
440
- steps = scenario.instance_variable_get("@steps").instance_variable_get("@steps")
441
- count += steps.size
442
-
443
- #get example table
444
- examples = scenario.instance_variable_get("@examples_array")
445
- unless examples.nil?
446
- examples.each do |example|
447
- example_matrix = example.instance_variable_get("@outline_table").instance_variable_get("@cell_matrix")
448
- count += example_matrix.size
449
- end
450
- end
451
-
452
- #get multiline step tables
453
- steps.each do |step|
454
- multi_arg = step.instance_variable_get("@multiline_arg")
455
- next if multi_arg.nil?
456
- matrix = multi_arg.instance_variable_get("@cell_matrix")
457
- count += matrix.size unless matrix.nil?
458
- end
459
- end
460
- end
461
- return count
462
- end
463
-
464
429
  def build_step(keyword, step_match, status)
465
430
  step_name = step_match.format_args(lambda{|param| %{<span class="param">#{param}</span>}})
466
431
  @builder.div(:class => 'step_name') do |div|
@@ -24,6 +24,10 @@ module Cucumber
24
24
  @pipe.send(method, *args, &blk)
25
25
  end
26
26
 
27
+ def respond_to?(method, include_private=false)
28
+ super || @pipe.respond_to?(method, include_private)
29
+ end
30
+
27
31
  def self.validate_pipe(pipe)
28
32
  unless [:stdout, :stderr].include? pipe
29
33
  raise ArgumentError, '#wrap only accepts :stderr or :stdout'
@@ -1,13 +1,9 @@
1
- require 'multi_json'
2
1
  require 'cucumber/formatter/json'
3
2
 
4
3
  module Cucumber
5
4
  module Formatter
6
5
  # The formatter used for <tt>--format json_pretty</tt>
7
6
  class JsonPretty < Json
8
- def after_features(features)
9
- @io.write(MultiJson.dump(@obj, :pretty => true))
10
- end
11
7
  end
12
8
  end
13
9
  end
@@ -48,10 +48,10 @@ module Cucumber
48
48
  :name => @feature_name ) do
49
49
  @testsuite << @builder.target!
50
50
  @testsuite.tag!('system-out') do
51
- @testsuite.cdata! @interceptedout.buffer.join
51
+ @testsuite.cdata! strip_control_chars(@interceptedout.buffer.join)
52
52
  end
53
53
  @testsuite.tag!('system-err') do
54
- @testsuite.cdata! @interceptederr.buffer.join
54
+ @testsuite.cdata! strip_control_chars(@interceptederr.buffer.join)
55
55
  end
56
56
  end
57
57
 
@@ -166,6 +166,12 @@ module Cucumber
166
166
  def write_file(feature_filename, data)
167
167
  File.open(feature_filename, 'w') { |file| file.write(data) }
168
168
  end
169
+
170
+ # strip control chars from cdata, to make it safe for external parsers
171
+ def strip_control_chars(cdata)
172
+ cdata.scan(/[[:print:]\t\n\r]/).join
173
+ end
174
+
169
175
  end
170
176
  end
171
177
  end
@@ -28,6 +28,10 @@ module Cucumber
28
28
  @delayed_messages = []
29
29
  end
30
30
 
31
+ def before_features(features)
32
+ print_profile_information
33
+ end
34
+
31
35
  def after_features(features)
32
36
  print_summary(features) unless @options[:autoformat]
33
37
  end
@@ -154,7 +158,7 @@ module Cucumber
154
158
  end
155
159
 
156
160
  def doc_string(string)
157
- return if @hide_this_step
161
+ return if @options[:no_multiline] || @hide_this_step
158
162
  s = %{"""\n#{string}\n"""}.indent(@indent)
159
163
  s = s.split("\n").map{|l| l =~ /^\s+$/ ? '' : l}.join("\n")
160
164
  @io.puts(format_string(s, @current_step.status))
@@ -13,6 +13,10 @@ module Cucumber
13
13
  @runtime, @io, @options = runtime, ensure_io(path_or_io, "progress"), options
14
14
  end
15
15
 
16
+ def before_features(features)
17
+ print_profile_information
18
+ end
19
+
16
20
  def after_features(features)
17
21
  @io.puts
18
22
  @io.puts
@@ -25,48 +25,35 @@ if Cucumber::WINDOWS
25
25
  module WindowsOutput #:nodoc:
26
26
  def self.extended(o)
27
27
  o.instance_eval do
28
- alias cucumber_print print
29
- def print(*a)
28
+ def cucumber_preprocess_output(*a)
30
29
  if Cucumber::RUBY_1_8_7
31
30
  begin
32
- cucumber_print(*Iconv.iconv(Cucumber::CODEPAGE, "UTF-8", *a.map{|a|a.to_s}))
31
+ *Iconv.iconv(Cucumber::CODEPAGE, "UTF-8", *a.map{|a|a.to_s})
33
32
  rescue Iconv::InvalidEncoding => e
34
33
  STDERR.cucumber_puts("WARNING: #{e.message}")
35
- cucumber_print(*a)
34
+ *a
36
35
  rescue Iconv::IllegalSequence => e
37
36
  STDERR.cucumber_puts("WARNING: #{e.message}")
38
- cucumber_print(*a)
37
+ *a
39
38
  end
40
39
  else
41
40
  begin
42
- cucumber_print(*a.map{|arg| arg.to_s.encode(Encoding.default_external)})
41
+ *a.map{|arg| arg.to_s.encode(Encoding.default_external)}
43
42
  rescue Encoding::UndefinedConversionError => e
44
43
  STDERR.cucumber_puts("WARNING: #{e.message}")
45
- cucumber_print(*a)
44
+ *a
46
45
  end
47
46
  end
48
47
  end
49
48
 
49
+ alias cucumber_print print
50
+ def print(*a)
51
+ cucumber_print(cucumber_preprocess_output(*a))
52
+ end
53
+
50
54
  alias cucumber_puts puts
51
55
  def puts(*a)
52
- if Cucumber::RUBY_1_8_7
53
- begin
54
- cucumber_puts(*Iconv.iconv(Cucumber::CODEPAGE, "UTF-8", *a.map{|a|a.to_s}))
55
- rescue Iconv::InvalidEncoding => e
56
- STDERR.cucumber_print("WARNING: #{e.message}")
57
- cucumber_print(*a)
58
- rescue Iconv::IllegalSequence => e
59
- STDERR.cucumber_puts("WARNING: #{e.message}")
60
- cucumber_puts(*a)
61
- end
62
- else
63
- begin
64
- cucumber_puts(*a.map{|arg| arg.to_s.encode(Encoding.default_external)})
65
- rescue Encoding::UndefinedConversionError => e
66
- STDERR.cucumber_puts("WARNING: #{e.message}")
67
- cucumber_puts(*a)
68
- end
69
- end
56
+ cucumber_puts(cucumber_preprocess_output(*a))
70
57
  end
71
58
  end
72
59
  end
@@ -17,6 +17,10 @@ module Cucumber
17
17
  @stepdef_to_match = Hash.new{|h,stepdef_key| h[stepdef_key] = []}
18
18
  end
19
19
 
20
+ def before_features(features)
21
+ print_profile_information
22
+ end
23
+
20
24
  def before_step(step)
21
25
  @step = step
22
26
  @start_time = Time.now
@@ -27,8 +31,9 @@ module Cucumber
27
31
  end
28
32
 
29
33
  def after_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background, file_colon_line)
30
- if step_match.name.nil? # nil if it's from a scenario outline
31
- stepdef_key = StepDefKey.new(step_match.step_definition.regexp_source, step_match.step_definition.file_colon_line)
34
+ step_definition = step_match.step_definition
35
+ unless step_definition.nil? # nil if it's from a scenario outline
36
+ stepdef_key = StepDefKey.new(step_definition.regexp_source, step_definition.file_colon_line)
32
37
 
33
38
  @stepdef_to_match[stepdef_key] << {
34
39
  :keyword => keyword,
@@ -4,7 +4,7 @@ module Cucumber
4
4
  PARAM_PATTERN = /"(.*?)"/
5
5
  ESCAPED_PARAM_PATTERN = '"([^\\"]*)"'
6
6
 
7
- def snippet_text(code_keyword, step_name, multiline_arg_class)
7
+ def snippet_text(code_keyword, step_name, multiline_arg_class, snippet_type)
8
8
  escaped = Regexp.escape(step_name).gsub('\ ', ' ').gsub('/', '\/')
9
9
  escaped = escaped.gsub(PARAM_PATTERN, ESCAPED_PARAM_PATTERN)
10
10
 
@@ -0,0 +1,13 @@
1
+ module Cucumber
2
+ module LoadPath
3
+ def add_dirs(*dirs)
4
+ dirs.each do |dir|
5
+ $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir)
6
+ end
7
+ end
8
+
9
+ module_function :add_dirs
10
+ end
11
+ end
12
+
13
+ Cucumber::LoadPath.add_dirs('lib')
@@ -1,6 +1,7 @@
1
1
  require 'cucumber/ast'
2
2
  require 'gherkin/rubify'
3
3
  require 'cucumber/ast/multiline_argument'
4
+ require 'cucumber/ast/empty_background'
4
5
 
5
6
  module Cucumber
6
7
  module Parser
@@ -10,98 +11,60 @@ module Cucumber
10
11
  class GherkinBuilder
11
12
  include Gherkin::Rubify
12
13
 
13
- def ast
14
- @feature || @multiline_arg
15
- end
16
-
17
- def feature(feature)
18
- @feature = Ast::Feature.new(
19
- nil,
20
- Ast::Comment.new(feature.comments.map{|comment| comment.value}.join("\n")),
21
- Ast::Tags.new(nil, feature.tags),
22
- feature.keyword,
23
- feature.name.lstrip,
24
- feature.description.rstrip,
25
- []
26
- )
27
- @feature.gherkin_statement(feature)
28
- @feature
29
- end
30
-
31
- def background(background)
32
- @background = Ast::Background.new(
33
- Ast::Comment.new(background.comments.map{|comment| comment.value}.join("\n")),
34
- background.line,
35
- background.keyword,
36
- background.name,
37
- background.description,
38
- []
39
- )
40
- @feature.background = @background
41
- @background.feature = @feature
42
- @step_container = @background
43
- @background.gherkin_statement(background)
44
- end
45
-
46
- def scenario(statement)
47
- scenario = Ast::Scenario.new(
48
- @background,
49
- Ast::Comment.new(statement.comments.map{|comment| comment.value}.join("\n")),
50
- Ast::Tags.new(nil, statement.tags),
51
- statement.line,
52
- statement.keyword,
53
- statement.name,
54
- statement.description,
55
- []
56
- )
57
- @feature.add_feature_element(scenario)
58
- @background.feature_elements << scenario if @background
59
- @step_container = scenario
60
- scenario.gherkin_statement(statement)
61
- end
62
-
63
- def scenario_outline(statement)
64
- scenario_outline = Ast::ScenarioOutline.new(
65
- @background,
66
- Ast::Comment.new(statement.comments.map{|comment| comment.value}.join("\n")),
67
- Ast::Tags.new(nil, statement.tags),
68
- statement.line,
69
- statement.keyword,
70
- statement.name,
71
- statement.description,
72
- [],
73
- []
74
- )
75
- @feature.add_feature_element(scenario_outline)
76
- if @background
77
- @background = @background.dup
78
- @background.feature_elements << scenario_outline
79
- end
80
- @step_container = scenario_outline
81
- scenario_outline.gherkin_statement(statement)
14
+ def initialize(path = 'UNKNOWN-FILE')
15
+ @path = path
16
+ end
17
+
18
+ def result
19
+ return nil unless @feature_builder
20
+ @feature_builder.result(language)
21
+ end
22
+
23
+ def language=(language)
24
+ @language = language
25
+ end
26
+
27
+ def uri(uri)
28
+ @path = uri
29
+ end
30
+
31
+ def feature(node)
32
+ @feature_builder = FeatureBuilder.new(file, node)
33
+ end
34
+
35
+ def background(node)
36
+ builder = BackgroundBuilder.new(file, node)
37
+ @feature_builder.background_builder = builder
38
+ @current = builder
39
+ end
40
+
41
+ def scenario(node)
42
+ builder = ScenarioBuilder.new(file, node)
43
+ @feature_builder.add_child builder
44
+ @current = builder
45
+ end
46
+
47
+ def scenario_outline(node)
48
+ builder = ScenarioOutlineBuilder.new(file, node)
49
+ @feature_builder.add_child builder
50
+ @current = builder
82
51
  end
83
52
 
84
53
  def examples(examples)
85
54
  examples_fields = [
55
+ Ast::Location.new(file, examples.line),
86
56
  Ast::Comment.new(examples.comments.map{|comment| comment.value}.join("\n")),
87
- examples.line,
88
57
  examples.keyword,
89
58
  examples.name,
90
59
  examples.description,
91
60
  matrix(examples.rows)
92
61
  ]
93
- @step_container.add_examples(examples_fields, examples)
62
+ @current.add_examples examples_fields, examples
94
63
  end
95
64
 
96
- def step(gherkin_step)
97
- step = Ast::Step.new(
98
- gherkin_step.line,
99
- gherkin_step.keyword,
100
- gherkin_step.name,
101
- Ast::MultilineArgument.from(gherkin_step.doc_string || gherkin_step.rows)
102
- )
103
- step.gherkin_statement(gherkin_step)
104
- @step_container.add_step(step)
65
+ def step(node)
66
+ builder = StepBuilder.new(file, node)
67
+ @current.add_child builder
105
68
  end
106
69
 
107
70
  def eof
@@ -111,7 +74,12 @@ module Cucumber
111
74
  # raise "SYNTAX ERROR"
112
75
  end
113
76
 
114
- private
77
+ private
78
+
79
+ if defined?(JRUBY_VERSION)
80
+ java_import java.util.ArrayList
81
+ ArrayList.__persistent__ = true
82
+ end
115
83
 
116
84
  def matrix(gherkin_table)
117
85
  gherkin_table.map do |gherkin_row|
@@ -123,6 +91,194 @@ module Cucumber
123
91
  row
124
92
  end
125
93
  end
94
+
95
+ def language
96
+ @language || raise("Language has not been set")
97
+ end
98
+
99
+ def file
100
+ if Cucumber::WINDOWS && !ENV['CUCUMBER_FORWARD_SLASH_PATHS']
101
+ @path.gsub(/\//, '\\')
102
+ else
103
+ @path
104
+ end
105
+ end
106
+
107
+ class Builder
108
+ def initialize(file, node)
109
+ @file, @node = file, node
110
+ end
111
+
112
+ private
113
+
114
+ def tags
115
+ Ast::Tags.new(nil, node.tags)
116
+ end
117
+
118
+ def location
119
+ Ast::Location.new(file, node.line)
120
+ end
121
+
122
+ def comment
123
+ Ast::Comment.new(node.comments.map{ |comment| comment.value }.join("\n"))
124
+ end
125
+
126
+ attr_reader :file, :node
127
+ end
128
+
129
+ class FeatureBuilder < Builder
130
+ def result(language)
131
+ background = background(language)
132
+ feature = Ast::Feature.new(
133
+ location,
134
+ background,
135
+ comment,
136
+ tags,
137
+ node.keyword,
138
+ node.name.lstrip,
139
+ node.description.rstrip,
140
+ children.map { |builder| builder.result(background, language, tags) }
141
+ )
142
+ feature.gherkin_statement(node)
143
+ feature.language = language
144
+ feature
145
+ end
146
+
147
+ def background_builder=(builder)
148
+ @background_builder = builder
149
+ end
150
+
151
+ def add_child(child)
152
+ children << child
153
+ end
154
+
155
+ def children
156
+ @children ||= []
157
+ end
158
+
159
+ private
160
+
161
+ def background(language)
162
+ return Ast::EmptyBackground.new unless @background_builder
163
+ @background ||= @background_builder.result(language)
164
+ end
165
+ end
166
+
167
+ class BackgroundBuilder < Builder
168
+ def result(language)
169
+ background = Ast::Background.new(
170
+ language,
171
+ location,
172
+ comment,
173
+ node.keyword,
174
+ node.name,
175
+ node.description,
176
+ steps(language)
177
+ )
178
+ background.gherkin_statement(node)
179
+ background
180
+ end
181
+
182
+ def steps(language)
183
+ children.map { |child| child.result(language) }
184
+ end
185
+
186
+ def add_child(child)
187
+ children << child
188
+ end
189
+
190
+ def children
191
+ @children ||= []
192
+ end
193
+
194
+ end
195
+
196
+ class ScenarioBuilder < Builder
197
+ def result(background, language, feature_tags)
198
+ scenario = Ast::Scenario.new(
199
+ language,
200
+ location,
201
+ background,
202
+ comment,
203
+ tags,
204
+ feature_tags,
205
+ node.keyword,
206
+ node.name,
207
+ node.description,
208
+ steps(language)
209
+ )
210
+ scenario.gherkin_statement(node)
211
+ scenario
212
+ end
213
+
214
+ def steps(language)
215
+ children.map { |child| child.result(language) }
216
+ end
217
+
218
+ def add_child(child)
219
+ children << child
220
+ end
221
+
222
+ def children
223
+ @children ||= []
224
+ end
225
+ end
226
+
227
+ class ScenarioOutlineBuilder < Builder
228
+ def result(background, language, feature_tags)
229
+ scenario_outline = Ast::ScenarioOutline.new(
230
+ language,
231
+ location,
232
+ background,
233
+ comment,
234
+ tags,
235
+ feature_tags,
236
+ node.keyword,
237
+ node.name,
238
+ node.description,
239
+ steps(language),
240
+ examples_sections
241
+ )
242
+ scenario_outline.gherkin_statement(node)
243
+ scenario_outline
244
+ end
245
+
246
+ def add_examples(examples_section, node)
247
+ @examples_sections ||= []
248
+ @examples_sections << [examples_section, node]
249
+ end
250
+
251
+ def steps(language)
252
+ children.map { |child| child.result(language) }
253
+ end
254
+
255
+ def add_child(child)
256
+ children << child
257
+ end
258
+
259
+ def children
260
+ @children ||= []
261
+ end
262
+
263
+ private
264
+
265
+ attr_reader :examples_sections
266
+ end
267
+
268
+ class StepBuilder < Builder
269
+ def result(language)
270
+ step = Ast::Step.new(
271
+ language,
272
+ location,
273
+ node.keyword,
274
+ node.name,
275
+ Ast::MultilineArgument.from(node.doc_string || node.rows)
276
+ )
277
+ step.gherkin_statement(node)
278
+ step
279
+ end
280
+ end
281
+
126
282
  end
127
283
  end
128
284
  end