cucumber 2.0.0.beta.2 → 2.0.0.beta.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +25 -7
  3. data/cucumber.gemspec +1 -1
  4. data/features/docs/defining_steps/nested_steps.feature +0 -1
  5. data/features/docs/defining_steps/printing_messages.feature +1 -0
  6. data/features/docs/defining_steps/table_diffing.feature +9 -4
  7. data/features/docs/exception_in_after_step_hook.feature +1 -0
  8. data/features/docs/formatters/json_formatter.feature +51 -4
  9. data/features/docs/formatters/junit_formatter.feature +1 -0
  10. data/features/docs/gherkin/outlines.feature +4 -0
  11. data/features/docs/output_from_hooks.feature +128 -0
  12. data/features/docs/wire_protocol_table_diffing.feature +6 -2
  13. data/features/docs/writing_support_code/after_hooks.feature +56 -0
  14. data/lib/cucumber/cli/configuration.rb +0 -4
  15. data/lib/cucumber/cli/main.rb +0 -1
  16. data/lib/cucumber/cli/options.rb +0 -3
  17. data/lib/cucumber/formatter/console.rb +3 -1
  18. data/lib/cucumber/formatter/debug.rb +4 -0
  19. data/lib/cucumber/formatter/gherkin_formatter_adapter.rb +26 -3
  20. data/lib/cucumber/formatter/html.rb +6 -2
  21. data/lib/cucumber/formatter/usage.rb +1 -58
  22. data/lib/cucumber/mappings.rb +25 -7
  23. data/lib/cucumber/multiline_argument.rb +40 -82
  24. data/lib/cucumber/multiline_argument/data_table.rb +719 -0
  25. data/lib/cucumber/multiline_argument/doc_string.rb +10 -0
  26. data/lib/cucumber/platform.rb +1 -1
  27. data/lib/cucumber/rb_support/rb_world.rb +2 -4
  28. data/lib/cucumber/reports/legacy_formatter.rb +69 -22
  29. data/lib/cucumber/runtime.rb +0 -39
  30. data/lib/cucumber/runtime/for_programming_languages.rb +12 -10
  31. data/lib/cucumber/runtime/support_code.rb +11 -4
  32. data/lib/cucumber/wire_support/wire_protocol/requests.rb +2 -2
  33. data/spec/cucumber/formatter/pretty_spec.rb +5 -5
  34. data/spec/cucumber/mappings_spec.rb +137 -8
  35. data/spec/cucumber/multiline_argument/data_table_spec.rb +508 -0
  36. data/spec/cucumber/rb_support/rb_step_definition_spec.rb +3 -3
  37. data/spec/cucumber/rb_support/snippet_spec.rb +1 -1
  38. data/spec/cucumber/runtime/for_programming_languages_spec.rb +16 -12
  39. metadata +13 -6
  40. data/lib/cucumber/runtime/features_loader.rb +0 -62
@@ -62,10 +62,6 @@ module Cucumber
62
62
  @options[:expand]
63
63
  end
64
64
 
65
- def dotcucumber
66
- @options[:dotcucumber]
67
- end
68
-
69
65
  def snippet_type
70
66
  @options[:snippet_type] || :regexp
71
67
  end
@@ -36,7 +36,6 @@ module Cucumber
36
36
  end
37
37
 
38
38
  runtime.run!
39
- runtime.write_stepdefs_json
40
39
  failure = runtime.results.failure? || Cucumber.wants_to_quit
41
40
  @kernel.exit(failure ? 1 : 0)
42
41
  rescue FileNotFoundException => e
@@ -223,9 +223,6 @@ module Cucumber
223
223
  opts.on("-x", "--expand", "Expand Scenario Outline Tables in output.") do
224
224
  @options[:expand] = true
225
225
  end
226
- opts.on("--dotcucumber DIR", "Write metadata to DIR") do |dir|
227
- @options[:dotcucumber] = dir
228
- end
229
226
  opts.on("--order TYPE[:SEED]", "Run examples in the specified order. Available types:",
230
227
  *<<-TEXT.split("\n")) do |order|
231
228
  [defined] Run scenarios in the order they were defined (default).
@@ -139,7 +139,9 @@ module Cucumber
139
139
 
140
140
  unknown_programming_language = runtime.unknown_programming_language?
141
141
  snippets = undefined.map do |step|
142
- step_name = Undefined === step.exception ? step.exception.step_name : step.name
142
+ # step_name = Undefined === step.exception ? step.exception.step_name : step.name
143
+ # TODO: This probably won't work for nested steps :( See above for old code.
144
+ step_name = step.name
143
145
  @runtime.snippet_text(step.actual_keyword, step_name, step.multiline_arg)
144
146
  end.compact.uniq
145
147
 
@@ -24,6 +24,10 @@ module Cucumber
24
24
  @indent += 2 if name.to_s =~ /^before/
25
25
  end
26
26
 
27
+ def puts(*args)
28
+ print("puts")
29
+ end
30
+
27
31
  private
28
32
 
29
33
  def print(text)
@@ -10,6 +10,8 @@ module Cucumber
10
10
  @gf = gherkin_formatter
11
11
  @print_empty_match = print_empty_match
12
12
  @options = options
13
+ @delayed_messages = []
14
+ @delayed_embeddings = []
13
15
  end
14
16
 
15
17
  def before_feature(feature)
@@ -19,10 +21,12 @@ module Cucumber
19
21
 
20
22
  def before_background(background)
21
23
  @outline = false
24
+ @before_steps = true
22
25
  @gf.background(background.gherkin_statement)
23
26
  end
24
27
 
25
28
  def before_feature_element(feature_element)
29
+ @before_steps = true
26
30
  case(feature_element)
27
31
  when Core::Ast::Scenario
28
32
  @outline = false
@@ -65,6 +69,8 @@ module Cucumber
65
69
  def before_step(step)
66
70
  unless @outline and @options[:expand]
67
71
  @gf.step(step.gherkin_statement)
72
+ pass_delayed_output
73
+ @before_steps = false
68
74
  else
69
75
  if @in_instantiated_scenario
70
76
  @current_step_hash = to_hash(step.gherkin_statement)
@@ -111,9 +117,11 @@ module Cucumber
111
117
  @current_step_hash['comments'],
112
118
  @current_step_hash['keyword'],
113
119
  step_match.format_args(),
114
- @current_step_hash['line'],
120
+ file_colon_line.split(':')[1].to_i,
115
121
  @current_step_hash['rows'],
116
122
  @current_step_hash['doc_string']))
123
+ pass_delayed_output
124
+ @before_steps = false
117
125
  @gf.match(@current_match)
118
126
  @gf.result(@current_result)
119
127
  end
@@ -159,11 +167,19 @@ module Cucumber
159
167
  if defined?(JRUBY_VERSION)
160
168
  data = data.to_java_bytes
161
169
  end
162
- @gf.embedding(mime_type, data)
170
+ unless @before_steps
171
+ @gf.embedding(mime_type, data)
172
+ else
173
+ @delayed_embeddings.push [mime_type, data]
174
+ end
163
175
  end
164
176
 
165
177
  def puts(message)
166
- @gf.write(message)
178
+ unless @before_steps
179
+ @gf.write(message)
180
+ else
181
+ @delayed_messages.push message
182
+ end
167
183
  end
168
184
 
169
185
  private
@@ -175,6 +191,13 @@ module Cucumber
175
191
  gherkin_statement.to_hash
176
192
  end
177
193
  end
194
+
195
+ def pass_delayed_output
196
+ @delayed_messages.each { |message| @gf.write(message) }
197
+ @delayed_embeddings.each { |embed_data| @gf.embedding(embed_data[0], embed_data[1]) }
198
+ @delayed_messages = []
199
+ @delayed_embeddings = []
200
+ end
178
201
  end
179
202
  end
180
203
  end
@@ -12,7 +12,7 @@ module Cucumber
12
12
  Cucumber::Core::Ast::Scenario => 'scenario',
13
13
  Cucumber::Core::Ast::ScenarioOutline => 'scenario outline'
14
14
  }
15
- AST_DATA_TABLE = Cucumber::Core::Ast::DataTable
15
+ AST_DATA_TABLE = Cucumber::Reports::Legacy::Ast::MultilineArg::DataTable
16
16
 
17
17
  include ERB::Util # for the #h method
18
18
  include Duration
@@ -618,8 +618,12 @@ module Cucumber
618
618
 
619
619
  def lines_around(file, line)
620
620
  if File.file?(file)
621
+ begin
621
622
  lines = File.open(file).read.split("\n")
622
- min = [0, line-3].max
623
+ rescue ArgumentError
624
+ return "# Couldn't get snippet for #{file}"
625
+ end
626
+ min = [0, line-3].max
623
627
  max = [line+1, lines.length-1].min
624
628
  selected_lines = []
625
629
  selected_lines.join("\n")
@@ -21,36 +21,6 @@ module Cucumber
21
21
  print_profile_information
22
22
  end
23
23
 
24
- def before_background(background)
25
- @outline = false
26
- end
27
-
28
- def before_feature_element(feature_element)
29
- case(feature_element)
30
- when Core::Ast::Scenario
31
- @outline = false
32
- when Core::Ast::ScenarioOutline
33
- @outline = true
34
- if @options[:expand]
35
- @in_instantiated_scenario = false
36
- end
37
- else
38
- raise "Bad type: #{feature_element.class}"
39
- end
40
- end
41
-
42
- def scenario_name(keyword, name, file_colon_line, source_indent)
43
- if @outline and @in_instantiated_scenario
44
- if @new_example_table
45
- @example_row = 1
46
- @new_example_table = false
47
- else
48
- @example_row += 1
49
- end
50
- @example_line = @current_example_rows[@example_row].to_hash['line']
51
- end
52
- end
53
-
54
24
  def before_step(step)
55
25
  @step = step
56
26
  @start_time = Time.now
@@ -65,30 +35,17 @@ module Cucumber
65
35
  unless step_definition.nil? # nil if it's from a scenario outline
66
36
  stepdef_key = StepDefKey.new(step_definition.regexp_source, step_definition.file_colon_line)
67
37
 
68
- file_colon_line = @step.file_colon_line
69
- if @outline and @in_instantiated_scenario
70
- file_colon_line = replace_line_number(@step.file_colon_line, @example_line)
71
- end
72
-
73
38
  @stepdef_to_match[stepdef_key] << {
74
39
  :keyword => keyword,
75
40
  :step_match => step_match,
76
41
  :status => status,
77
- :file_colon_line => file_colon_line,
42
+ :file_colon_line => @step.file_colon_line,
78
43
  :duration => @duration
79
44
  }
80
45
  end
81
46
  super
82
47
  end
83
48
 
84
- def before_examples(examples)
85
- if @options[:expand]
86
- @in_instantiated_scenario = true
87
- @new_example_table = true
88
- @current_example_rows = to_hash(examples.gherkin_statement)['rows']
89
- end
90
- end
91
-
92
49
  def print_summary(features)
93
50
  add_unused_stepdefs
94
51
  aggregate_info
@@ -176,20 +133,6 @@ module Cucumber
176
133
  @stepdef_to_match[stepdef_key] = []
177
134
  end
178
135
  end
179
-
180
- private
181
-
182
- def replace_line_number(file_colon_line, line)
183
- file_colon_line.split(':')[0] + ':' + line.to_s
184
- end
185
-
186
- def to_hash(gherkin_statement)
187
- if defined?(JRUBY_VERSION)
188
- gherkin_statement.toMap()
189
- else
190
- gherkin_statement.to_hash
191
- end
192
- end
193
136
  end
194
137
  end
195
138
  end
@@ -68,13 +68,13 @@ module Cucumber
68
68
 
69
69
  def map_test_case_hooks(mapper)
70
70
  ruby.hooks_for(:before, scenario).each do |hook|
71
- mapper.before do
72
- hook.invoke('Before', scenario)
71
+ mapper.before do |result|
72
+ hook.invoke('Before', scenario.with_result(result))
73
73
  end
74
74
  end
75
75
  ruby.hooks_for(:after, scenario).each do |hook|
76
- mapper.after do
77
- hook.invoke('After', scenario)
76
+ mapper.after do |result|
77
+ hook.invoke('After', scenario.with_result(result))
78
78
  end
79
79
  end
80
80
  ruby.hooks_for(:around, scenario).each do |hook|
@@ -86,9 +86,10 @@ module Cucumber
86
86
 
87
87
  # adapts our test_case to look like the Cucumber Runtime's old Scenario
88
88
  class TestCase
89
- def initialize(test_case, feature)
89
+ def initialize(test_case, feature, result = Core::Test::Result::Unknown.new)
90
90
  @test_case = test_case
91
91
  @feature = feature
92
+ @result = result
92
93
  end
93
94
 
94
95
  def accept_hook?(hook)
@@ -96,7 +97,7 @@ module Cucumber
96
97
  end
97
98
 
98
99
  def failed?
99
- warn("Calling failed? on a scenario is not currently supported in Cucumber 2.0. Please see https://github.com/cucumber/cucumber/issues/726")
100
+ @result.failed?
100
101
  end
101
102
 
102
103
  def language
@@ -111,6 +112,11 @@ module Cucumber
111
112
  @test_case.name
112
113
  end
113
114
 
115
+ def title
116
+ warn("deprecated: call #name instead")
117
+ name
118
+ end
119
+
114
120
  def source_tags
115
121
  #warn('deprecated: call #tags instead')
116
122
  tags
@@ -123,12 +129,24 @@ module Cucumber
123
129
  def tags
124
130
  @test_case.tags
125
131
  end
132
+
133
+ def outline?
134
+ false
135
+ end
136
+
137
+ def with_result(result)
138
+ self.class.new(@test_case, @feature, result)
139
+ end
126
140
  end
127
141
 
128
142
  class Scenario < TestCase
129
143
  end
130
144
 
131
145
  class ScenarioOutlineExample < TestCase
146
+ def outline?
147
+ true
148
+ end
149
+
132
150
  def scenario_outline
133
151
  self
134
152
  end
@@ -204,7 +222,7 @@ module Cucumber
204
222
 
205
223
  private
206
224
  def map_step(node, step_match)
207
- multiline_arg = MultilineArgument.from(node.multiline_arg)
225
+ multiline_arg = MultilineArgument.from_core(node.multiline_arg)
208
226
  mapper.map { step_match.invoke(multiline_arg) }
209
227
  end
210
228
 
@@ -1,104 +1,62 @@
1
1
  require 'delegate'
2
+ require 'cucumber/multiline_argument/data_table'
3
+ require 'cucumber/multiline_argument/doc_string'
4
+ require 'gherkin/rubify'
5
+
2
6
  module Cucumber
3
7
  module MultilineArgument
4
- def self.from(core_multiline_arg)
5
- Builder.new(core_multiline_arg).result
6
- end
7
-
8
- class Builder
9
- def initialize(multiline_arg)
10
- multiline_arg.describe_to self
11
- end
8
+ extend Gherkin::Rubify
12
9
 
13
- def doc_string(string, *args)
14
- @result = DocString.new(string)
10
+ class << self
11
+ def from_core(node)
12
+ builder.wrap(node)
15
13
  end
16
14
 
17
- def data_table(table, *args)
18
- @result = DataTable.new(table)
15
+ def from(argument, location=nil)
16
+ location ||= Core::Ast::Location.of_caller
17
+ argument = rubify(argument)
18
+ case argument
19
+ when String
20
+ doc_string(argument, 'text/plain', location)
21
+ when Array
22
+ location = location.on_line(argument.first.line..argument.last.line)
23
+ data_table(argument.map{ |row| row.cells }, location)
24
+ when DataTable, DocString, None
25
+ argument
26
+ when nil
27
+ None.new
28
+ else
29
+ raise ArgumentError, "Don't know how to convert #{argument.class} #{argument.inspect} into a MultilineArgument"
30
+ end
19
31
  end
20
32
 
21
- def result
22
- @result || None.new
33
+ def doc_string(argument, content_type, location)
34
+ builder.doc_string(Core::Ast::DocString.new(argument, content_type, location))
23
35
  end
24
- end
25
36
 
26
- class DocString < SimpleDelegator
27
- def append_to(array)
28
- array << self
37
+ def data_table(data, location)
38
+ builder.data_table(Core::Ast::DataTable.new(data, location))
29
39
  end
30
- end
31
40
 
32
- class DataTable < SimpleDelegator
33
- def append_to(array)
34
- array << self
35
- end
41
+ private
36
42
 
37
- def to_json(options)
38
- raw.to_json(options)
43
+ def builder
44
+ @builder ||= Builder.new
39
45
  end
40
46
 
41
- def diff!(other_table)
42
- other_table = ensure_table(other_table)
43
- other_table_cell_matrix = other_table.cell_matrix
44
-
45
- ensure_green!
46
-
47
- require_diff_lcs
48
- cell_matrix.extend(Diff::LCS)
49
-
50
- changes = cell_matrix.diff(other_table_cell_matrix).flatten
51
-
52
- return if changes.empty?
53
-
54
- inserted = 0
55
- missing = 0
56
-
57
- changes.each do |change|
58
- if(change.action == '-')
59
- missing_row_pos = change.position + inserted
60
- cell_matrix[missing_row_pos].each{|cell| cell.status = :undefined}
61
-
62
- missing += 1
63
- else # '+'
64
- inserted_row = change.element
65
- inserted_row.each{|cell| cell.status = :comment}
66
-
67
- insert_row_pos = change.position + missing
68
- cell_matrix.insert(insert_row_pos, inserted_row)
69
-
70
- inserted += 1
71
- end
47
+ class Builder
48
+ def wrap(node)
49
+ @result = None.new
50
+ node.describe_to(self)
51
+ @result
72
52
  end
73
53
 
74
- raise Different.new(self)
75
- end
76
-
77
- def ensure_green! #:nodoc:
78
- each_cell{|cell| cell.status = :passed}
79
- end
80
-
81
- private
82
-
83
- def ensure_table(table_or_array) #:nodoc:
84
- return table_or_array if DataTable === table_or_array
85
- DataTable.new(table_or_array)
86
- end
87
-
88
- def require_diff_lcs #:nodoc:
89
- begin
90
- require 'diff/lcs'
91
- rescue LoadError => e
92
- e.message << "\n Please gem install diff-lcs\n"
93
- raise e
54
+ def doc_string(node, *args)
55
+ @result = DocString.new(node)
94
56
  end
95
- end
96
57
 
97
- class Different < StandardError
98
- attr_reader :table
99
- def initialize(table)
100
- @table = table
101
- super("Tables were not identical")
58
+ def data_table(node, *args)
59
+ @result = DataTable.new(node)
102
60
  end
103
61
  end
104
62
  end