cucumber 1.2.5 → 1.3.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 (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