cucumber 1.1.9 → 1.2.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 (53) hide show
  1. data/.travis.yml +9 -0
  2. data/History.md +20 -3
  3. data/README.md +1 -2
  4. data/cucumber.gemspec +10 -13
  5. data/cucumber.yml +2 -2
  6. data/features/.cucumber/stepdefs.json +13 -391
  7. data/features/backtraces.feature +36 -0
  8. data/features/{issue_117.feature → drb_server_integration.feature} +3 -3
  9. data/features/formatter_step_file_colon_line.feature +46 -0
  10. data/features/{issue_57.feature → rerun_formatter.feature} +2 -2
  11. data/features/run_specific_scenarios.feature +47 -0
  12. data/gem_tasks/cucumber.rake +15 -8
  13. data/legacy_features/cucumber_cli.feature +0 -7
  14. data/legacy_features/junit_formatter.feature +60 -10
  15. data/legacy_features/language_help.feature +1 -0
  16. data/lib/cucumber.rb +2 -1
  17. data/lib/cucumber/ast/step.rb +1 -1
  18. data/lib/cucumber/ast/step_invocation.rb +2 -15
  19. data/lib/cucumber/ast/table.rb +16 -6
  20. data/lib/cucumber/ast/tree_walker.rb +5 -5
  21. data/lib/cucumber/cli/options.rb +5 -8
  22. data/lib/cucumber/formatter/ansicolor.rb +7 -12
  23. data/lib/cucumber/formatter/cucumber.css +7 -1
  24. data/lib/cucumber/formatter/gherkin_formatter_adapter.rb +1 -1
  25. data/lib/cucumber/formatter/html.rb +5 -5
  26. data/lib/cucumber/formatter/interceptor.rb +62 -0
  27. data/lib/cucumber/formatter/junit.rb +30 -14
  28. data/lib/cucumber/formatter/pretty.rb +3 -3
  29. data/lib/cucumber/formatter/progress.rb +1 -1
  30. data/lib/cucumber/formatter/rerun.rb +1 -1
  31. data/lib/cucumber/formatter/usage.rb +1 -1
  32. data/lib/cucumber/js_support/js_snippets.rb +1 -1
  33. data/lib/cucumber/platform.rb +1 -1
  34. data/lib/cucumber/rb_support/rb_dsl.rb +15 -8
  35. data/lib/cucumber/rb_support/rb_language.rb +3 -3
  36. data/lib/cucumber/rb_support/rb_step_definition.rb +17 -5
  37. data/lib/cucumber/term/ansicolor.rb +118 -0
  38. data/spec/cucumber/ast/table_spec.rb +9 -0
  39. data/spec/cucumber/cli/configuration_spec.rb +12 -6
  40. data/spec/cucumber/cli/options_spec.rb +9 -3
  41. data/spec/cucumber/constantize_spec.rb +5 -1
  42. data/spec/cucumber/formatter/ansicolor_spec.rb +1 -1
  43. data/spec/cucumber/formatter/interceptor_spec.rb +111 -0
  44. data/spec/cucumber/formatter/junit_spec.rb +36 -20
  45. data/spec/cucumber/formatter/progress_spec.rb +2 -2
  46. data/spec/cucumber/rb_support/rb_language_spec.rb +5 -5
  47. data/spec/cucumber/rb_support/rb_step_definition_spec.rb +17 -1
  48. data/spec/cucumber/rb_support/regexp_argument_matcher_spec.rb +6 -2
  49. data/spec/cucumber/step_match_spec.rb +8 -4
  50. data/spec/spec_helper.rb +15 -1
  51. metadata +215 -82
  52. data/.gitmodules +0 -3
  53. data/lib/cucumber/formatter/pdf.rb +0 -244
@@ -100,16 +100,16 @@ module Cucumber
100
100
  end
101
101
  end
102
102
 
103
- def visit_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background)
104
- broadcast(keyword, step_match, multiline_arg, status, exception, source_indent, background) do
105
- visit_step_name(keyword, step_match, status, source_indent, background)
103
+ def visit_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background, file_colon_line)
104
+ broadcast(keyword, step_match, multiline_arg, status, exception, source_indent, background, file_colon_line) do
105
+ visit_step_name(keyword, step_match, status, source_indent, background, file_colon_line)
106
106
  visit_multiline_arg(multiline_arg) if multiline_arg
107
107
  visit_exception(exception, status) if exception
108
108
  end
109
109
  end
110
110
 
111
- def visit_step_name(keyword, step_match, status, source_indent, background) #:nodoc:
112
- broadcast(keyword, step_match, status, source_indent, background)
111
+ def visit_step_name(keyword, step_match, status, source_indent, background, file_colon_line) #:nodoc:
112
+ broadcast(keyword, step_match, status, source_indent, background, file_colon_line)
113
113
  end
114
114
 
115
115
  def visit_multiline_arg(multiline_arg) #:nodoc:
@@ -9,10 +9,6 @@ module Cucumber
9
9
  BUILTIN_FORMATS = {
10
10
  'html' => ['Cucumber::Formatter::Html', 'Generates a nice looking HTML report.'],
11
11
  'pretty' => ['Cucumber::Formatter::Pretty', 'Prints the feature as is - in colours.'],
12
- 'pdf' => ['Cucumber::Formatter::Pdf', "Generates a PDF report. You need to have the\n" +
13
- "#{INDENT}prawn gem installed. Will pick up logo from\n" +
14
- "#{INDENT}features/support/logo.png or\n" +
15
- "#{INDENT}features/support/logo.jpg if present."],
16
12
  'progress' => ['Cucumber::Formatter::Progress', 'Prints one character per scenario.'],
17
13
  'rerun' => ['Cucumber::Formatter::Rerun', 'Prints failing files with line numbers.'],
18
14
  'usage' => ['Cucumber::Formatter::Usage', "Prints where step definitions are used.\n" +
@@ -42,6 +38,7 @@ module Cucumber
42
38
  "on Ruby's LOAD_PATH, for example in a Ruby gem."
43
39
  ]
44
40
  DRB_FLAG = '--drb'
41
+ DRB_OPTIONAL_FLAG = '--[no-]drb'
45
42
  PROFILE_SHORT_FLAG = '-p'
46
43
  NO_PROFILE_SHORT_FLAG = '-P'
47
44
  PROFILE_LONG_FLAG = '--profile'
@@ -214,7 +211,7 @@ module Cucumber
214
211
  opts.on("-c", "--[no-]color",
215
212
  "Whether or not to use ANSI color in the output. Cucumber decides",
216
213
  "based on your platform and the output destination if not specified.") do |v|
217
- Term::ANSIColor.coloring = v
214
+ Cucumber::Term::ANSIColor.coloring = v
218
215
  end
219
216
  opts.on("-d", "--dry-run", "Invokes formatters without executing the steps.",
220
217
  "This also omits the loading of your support/env.rb file if it exists.") do
@@ -225,7 +222,7 @@ module Cucumber
225
222
  "Be careful if you choose to overwrite the originals.",
226
223
  "Implies --dry-run --format pretty.") do |directory|
227
224
  @options[:autoformat] = directory
228
- Term::ANSIColor.coloring = false
225
+ Cucumber::Term::ANSIColor.coloring = false
229
226
  @options[:dry_run] = true
230
227
  @quiet = true
231
228
  end
@@ -265,8 +262,8 @@ module Cucumber
265
262
  opts.on("-x", "--expand", "Expand Scenario Outline Tables in output.") do
266
263
  @options[:expand] = true
267
264
  end
268
- opts.on(DRB_FLAG, "Run features against a DRb server. (i.e. with the spork gem)") do
269
- @options[:drb] = true
265
+ opts.on(DRB_OPTIONAL_FLAG, "Run features against a DRb server. (i.e. with the spork gem)") do |drb|
266
+ @options[:drb] = drb
270
267
  end
271
268
  opts.on("--port PORT", "Specify DRb port. Ignored without --drb") do |port|
272
269
  @options[:drb_port] = port
@@ -1,10 +1,5 @@
1
- begin
2
- require 'term/ansicolor'
3
- rescue LoadError
4
- require 'rubygems'
5
- require 'term/ansicolor'
6
- end
7
1
  require 'cucumber/platform'
2
+ require 'cucumber/term/ansicolor'
8
3
 
9
4
  if Cucumber::IRONRUBY
10
5
  begin
@@ -17,11 +12,11 @@ end
17
12
  if Cucumber::WINDOWS_MRI
18
13
  unless ENV['ANSICON']
19
14
  STDERR.puts %{*** WARNING: You must use ANSICON 1.31 or higher (http://adoxa.110mb.com/ansicon) to get coloured output on Windows}
20
- Term::ANSIColor.coloring = false
15
+ Cucumber::Term::ANSIColor.coloring = false
21
16
  end
22
17
  end
23
18
 
24
- Term::ANSIColor.coloring = false if !STDOUT.tty? && !ENV.has_key?('AUTOTEST')
19
+ Cucumber::Term::ANSIColor.coloring = false if !STDOUT.tty? && !ENV.has_key?("AUTOTEST")
25
20
 
26
21
  module Cucumber
27
22
  module Formatter
@@ -57,11 +52,11 @@ module Cucumber
57
52
  # (If you're on Windows, use SET instead of export).
58
53
  # To see what colours and effects are available, just run this in your shell:
59
54
  #
60
- # ruby -e "require 'rubygems'; require 'term/ansicolor'; puts Term::ANSIColor.attributes"
55
+ # ruby -e "require 'rubygems'; require 'term/ansicolor'; puts Cucumber::Term::ANSIColor.attributes"
61
56
  #
62
57
  # Although not listed, you can also use <tt>grey</tt>
63
58
  module ANSIColor
64
- include Term::ANSIColor
59
+ include Cucumber::Term::ANSIColor
65
60
 
66
61
  ALIASES = Hash.new do |h,k|
67
62
  if k.to_s =~ /(.*)_param/
@@ -108,7 +103,7 @@ module Cucumber
108
103
  when 0
109
104
  raise "Your terminal doesn't support colours"
110
105
  when 1
111
- ::Term::ANSIColor.coloring = false
106
+ ::Cucumber::Term::ANSIColor.coloring = false
112
107
  alias grey white
113
108
  when 2..8
114
109
  alias grey white
@@ -130,7 +125,7 @@ module Cucumber
130
125
 
131
126
  def self.define_real_grey #:nodoc:
132
127
  def grey(m) #:nodoc:
133
- if ::Term::ANSIColor.coloring?
128
+ if ::Cucumber::Term::ANSIColor.coloring?
134
129
  "\e[90m#{m}\e[0m"
135
130
  else
136
131
  m
@@ -21,7 +21,7 @@ body {
21
21
  float: right;
22
22
  margin: 0 0 0 10px;
23
23
  }
24
- .cucumber .scenario h3, td .scenario h3, th .scenario h3 {
24
+ .cucumber .scenario h3, td .scenario h3, th .scenario h3, .background h3 {
25
25
  font-size: 11px;
26
26
  padding: 3px;
27
27
  margin: 0;
@@ -29,6 +29,12 @@ body {
29
29
  color: white;
30
30
  font-weight: bold;
31
31
  }
32
+
33
+ .background h3 {
34
+ font-size: 1.2em;
35
+ background: #666;
36
+ }
37
+
32
38
  .cucumber h1, td h1, th h1 {
33
39
  margin: 0px 10px 0px 10px;
34
40
  padding: 10px;
@@ -46,7 +46,7 @@ module Cucumber
46
46
  end
47
47
  end
48
48
 
49
- def before_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background)
49
+ def before_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background, file_colon_line)
50
50
  arguments = step_match.step_arguments.map{|a| Gherkin::Formatter::Argument.new(a.offset, a.val)}
51
51
  location = step_match.file_colon_line
52
52
  match = Gherkin::Formatter::Model::Match.new(arguments, location)
@@ -143,7 +143,7 @@ module Cucumber
143
143
 
144
144
  def background_name(keyword, name, file_colon_line, source_indent)
145
145
  @listing_background = true
146
- @builder.h3 do |h3|
146
+ @builder.h3(:id => "background_#{@scenario_number}") do |h3|
147
147
  @builder.span(keyword, :class => 'keyword')
148
148
  @builder.text!(' ')
149
149
  @builder.span(name, :class => 'val')
@@ -221,7 +221,7 @@ module Cucumber
221
221
  move_progress
222
222
  end
223
223
 
224
- def before_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background)
224
+ def before_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background, file_colon_line)
225
225
  @step_match = step_match
226
226
  @hide_this_step = false
227
227
  if exception
@@ -241,7 +241,7 @@ module Cucumber
241
241
  @builder << "<li id='#{@step_id}' class='step #{status}'>"
242
242
  end
243
243
 
244
- def after_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background)
244
+ def after_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background, file_colon_line)
245
245
  return if @hide_this_step
246
246
  # print snippet for undefined steps
247
247
  if status == :undefined
@@ -254,7 +254,7 @@ module Cucumber
254
254
  print_messages
255
255
  end
256
256
 
257
- def step_name(keyword, step_match, status, source_indent, background)
257
+ def step_name(keyword, step_match, status, source_indent, background, file_colon_line)
258
258
  @step_matches ||= []
259
259
  background_in_scenario = background && !@listing_background
260
260
  @skip_step = @step_matches.index(step_match) || background_in_scenario
@@ -513,7 +513,7 @@ module Cucumber
513
513
  def inline_js_content
514
514
  <<-EOF
515
515
 
516
- SCENARIOS = "h3[id^='scenario_']";
516
+ SCENARIOS = "h3[id^='scenario_'],h3[id^=background_]";
517
517
 
518
518
  $(document).ready(function() {
519
519
  $(SCENARIOS).css('cursor', 'pointer');
@@ -0,0 +1,62 @@
1
+
2
+ module Cucumber
3
+ module Formatter
4
+ module Interceptor
5
+ class Pipe
6
+ attr_reader :pipe, :buffer
7
+ def initialize(pipe)
8
+ @pipe = pipe
9
+ @buffer = []
10
+ @wrapped = true
11
+ end
12
+
13
+ def write(str)
14
+ @buffer << str if @wrapped
15
+ return @pipe.write(str)
16
+ end
17
+
18
+ def unwrap!
19
+ @wrapped = false
20
+ @pipe
21
+ end
22
+
23
+ def method_missing(method, *args, &blk)
24
+ @pipe.send(method, *args, &blk)
25
+ end
26
+
27
+ def self.validate_pipe(pipe)
28
+ unless [:stdout, :stderr].include? pipe
29
+ raise ArgumentError, '#wrap only accepts :stderr or :stdout'
30
+ end
31
+ end
32
+
33
+ def self.unwrap!(pipe)
34
+ validate_pipe pipe
35
+ wrapped = nil
36
+ case pipe
37
+ when :stdout
38
+ wrapped = $stdout
39
+ $stdout = wrapped.unwrap!
40
+ when :stderr
41
+ wrapped = $stderr
42
+ $stderr = wrapped.unwrap!
43
+ end
44
+ wrapped
45
+ end
46
+
47
+ def self.wrap(pipe)
48
+ validate_pipe pipe
49
+
50
+ case pipe
51
+ when :stderr
52
+ $stderr = self.new($stderr)
53
+ return $stderr
54
+ when :stdout
55
+ $stdout = self.new($stdout)
56
+ return $stdout
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -1,5 +1,6 @@
1
1
  require 'cucumber/formatter/ordered_xml_markup'
2
2
  require 'cucumber/formatter/io'
3
+ require 'cucumber/formatter/interceptor'
3
4
  require 'fileutils'
4
5
 
5
6
  module Cucumber
@@ -7,13 +8,13 @@ module Cucumber
7
8
  # The formatter used for <tt>--format junit</tt>
8
9
  class Junit
9
10
  include Io
10
-
11
+
11
12
  class UnNamedFeatureError < StandardError
12
13
  def initialize(feature_file)
13
14
  super("The feature in '#{feature_file}' does not have a name. The JUnit XML format requires a name for the testsuite element.")
14
15
  end
15
16
  end
16
-
17
+
17
18
  def initialize(step_mother, io, options)
18
19
  @reportdir = ensure_dir(io, "junit")
19
20
  @options = options
@@ -24,13 +25,17 @@ module Cucumber
24
25
  @failures = @errors = @tests = @skipped = 0
25
26
  @builder = OrderedXmlMarkup.new( :indent => 2 )
26
27
  @time = 0
28
+ # In order to fill out <system-err/> and <system-out/>, we need to
29
+ # intercept the $stderr and $stdout
30
+ @interceptedout = Interceptor::Pipe.wrap(:stdout)
31
+ @interceptederr = Interceptor::Pipe.wrap(:stderr)
27
32
  end
28
-
33
+
29
34
  def before_feature_element(feature_element)
30
35
  @in_examples = Ast::ScenarioOutline === feature_element
31
36
  @steps_start = Time.now
32
37
  end
33
-
38
+
34
39
  def after_feature(feature)
35
40
  @testsuite = OrderedXmlMarkup.new( :indent => 2 )
36
41
  @testsuite.instruct!
@@ -42,15 +47,24 @@ module Cucumber
42
47
  :time => "%.6f" % @time,
43
48
  :name => @feature_name ) do
44
49
  @testsuite << @builder.target!
50
+ @testsuite.tag!('system-out') do
51
+ @testsuite.cdata! @interceptedout.buffer.join
52
+ end
53
+ @testsuite.tag!('system-err') do
54
+ @testsuite.cdata! @interceptederr.buffer.join
55
+ end
45
56
  end
46
57
 
47
58
  write_file(feature_result_filename(feature.file), @testsuite.target!)
59
+
60
+ Interceptor::Pipe.unwrap! :stdout
61
+ Interceptor::Pipe.unwrap! :stderr
48
62
  end
49
63
 
50
64
  def before_background(*args)
51
65
  @in_background = true
52
66
  end
53
-
67
+
54
68
  def after_background(*args)
55
69
  @in_background = false
56
70
  end
@@ -68,10 +82,10 @@ module Cucumber
68
82
 
69
83
  def before_steps(steps)
70
84
  end
71
-
85
+
72
86
  def after_steps(steps)
73
87
  return if @in_background || @in_examples
74
-
88
+
75
89
  duration = Time.now - @steps_start
76
90
  if steps.failed?
77
91
  steps.each { |step| @output += "#{step.keyword}#{step.name}\n" }
@@ -79,12 +93,12 @@ module Cucumber
79
93
  end
80
94
  build_testcase(duration, steps.status, steps.exception)
81
95
  end
82
-
96
+
83
97
  def before_examples(*args)
84
98
  @header_row = true
85
99
  @in_examples = true
86
100
  end
87
-
101
+
88
102
  def after_examples(*args)
89
103
  @in_examples = false
90
104
  end
@@ -106,7 +120,7 @@ module Cucumber
106
120
  end
107
121
  build_testcase(duration, table_row.status, table_row.exception, name_suffix)
108
122
  end
109
-
123
+
110
124
  @header_row = false if @header_row
111
125
  end
112
126
 
@@ -114,7 +128,7 @@ module Cucumber
114
128
 
115
129
  def build_testcase(duration, status, exception = nil, suffix = "")
116
130
  @time += duration
117
- classname = "#{@feature_name}.#{@scenario}"
131
+ classname = @feature_name
118
132
  name = "#{@scenario}#{suffix}"
119
133
  pending = [:pending, :undefined].include?(status)
120
134
  passed = (status == :passed || (pending && !@options[:strict]))
@@ -131,6 +145,8 @@ module Cucumber
131
145
  @builder.skipped
132
146
  @skipped += 1
133
147
  end
148
+ @builder.tag!('system-out')
149
+ @builder.tag!('system-err')
134
150
  end
135
151
  @tests += 1
136
152
  end
@@ -138,15 +154,15 @@ module Cucumber
138
154
  def format_exception(exception)
139
155
  (["#{exception.message} (#{exception.class})"] + exception.backtrace).join("\n")
140
156
  end
141
-
157
+
142
158
  def feature_result_filename(feature_file)
143
159
  File.join(@reportdir, "TEST-#{basename(feature_file)}.xml")
144
160
  end
145
-
161
+
146
162
  def basename(feature_file)
147
163
  File.basename(feature_file.gsub(/[\\\/]/, '-'), '.feature')
148
164
  end
149
-
165
+
150
166
  def write_file(feature_filename, data)
151
167
  File.open(feature_filename, 'w') { |file| file.write(data) }
152
168
  end
@@ -129,7 +129,7 @@ module Cucumber
129
129
  @indent = 6
130
130
  end
131
131
 
132
- def before_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background)
132
+ def before_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background, file_colon_line)
133
133
  @hide_this_step = false
134
134
  if exception
135
135
  if @exceptions.include?(exception)
@@ -145,7 +145,7 @@ module Cucumber
145
145
  @status = status
146
146
  end
147
147
 
148
- def step_name(keyword, step_match, status, source_indent, background)
148
+ def step_name(keyword, step_match, status, source_indent, background, file_colon_line)
149
149
  return if @hide_this_step
150
150
  source_indent = nil unless @options[:source]
151
151
  name_to_report = format_step(keyword, step_match, status, source_indent)
@@ -203,7 +203,7 @@ module Cucumber
203
203
  cell_text = escape_cell(value.to_s || '')
204
204
  padded = cell_text + (' ' * (width - cell_text.unpack('U*').length))
205
205
  prefix = cell_prefix(status)
206
- @io.print(' ' + format_string("#{prefix}#{padded}", status) + ::Term::ANSIColor.reset(" |"))
206
+ @io.print(' ' + format_string("#{prefix}#{padded}", status) + ::Cucumber::Term::ANSIColor.reset(" |"))
207
207
  @io.flush
208
208
  end
209
209
 
@@ -37,7 +37,7 @@ module Cucumber
37
37
  @exception_raised = false
38
38
  end
39
39
 
40
- def after_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background)
40
+ def after_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background, file_colon_line)
41
41
  progress(status)
42
42
  @status = status
43
43
  end
@@ -76,7 +76,7 @@ module Cucumber
76
76
  return unless @in_examples
77
77
  end
78
78
 
79
- def step_name(keyword, step_match, status, source_indent, background)
79
+ def step_name(keyword, step_match, status, source_indent, background, file_colon_line)
80
80
  @rerun = true if [:failed, :pending, :undefined].index(status)
81
81
  end
82
82