cucumber 0.3.7 → 0.3.8

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.
@@ -79,13 +79,21 @@ Then /^"(.*)" should contain XML$/ do |file, xml|
79
79
  end
80
80
 
81
81
  Then /^"(.*)" should contain$/ do |file, text|
82
- IO.read(file).should == text
82
+ strip_duration(IO.read(file)).should == text
83
83
  end
84
84
 
85
85
  Then /^"(.*)" should match$/ do |file, text|
86
86
  IO.read(file).should =~ Regexp.new(text)
87
87
  end
88
88
 
89
+ Then /^"([^\"]*)" should have the same contents as "([^\"]*)"$/ do |actual_file, expected_file|
90
+ actual = IO.read(actual_file)
91
+ # Comment out to replace expected file. Use with care! Remember to update duration afterwards.
92
+ # File.open(expected_file, "w"){|io| io.write(actual)}
93
+ actual = replace_duration(actual, '0m30.005s')
94
+ actual.should == IO.read(expected_file)
95
+ end
96
+
89
97
  Then /^STDERR should match$/ do |text|
90
98
  last_stderr.should =~ /#{text}/
91
99
  end
@@ -30,7 +30,20 @@ class CucumberWorld
30
30
  end
31
31
 
32
32
  private
33
- attr_reader :last_exit_status, :last_stdout, :last_stderr
33
+ attr_reader :last_exit_status, :last_stderr
34
+
35
+ # The last standard out, with the duration line taken out (unpredictable)
36
+ def last_stdout
37
+ strip_duration(@last_stdout)
38
+ end
39
+
40
+ def strip_duration(s)
41
+ s.gsub(/^\d+m\d+\.\d+s\n/m, "")
42
+ end
43
+
44
+ def replace_duration(s, replacement)
45
+ s.gsub(/\d+m\d+\.\d+s/m, replacement)
46
+ end
34
47
 
35
48
  def create_file(file_name, file_content)
36
49
  file_content.gsub!("CUCUMBER_LIB", "'#{cucumber_lib_dir}'") # Some files, such as Rakefiles need to use the lib dir
@@ -3,6 +3,8 @@ module Cucumber
3
3
  class Features
4
4
  include Enumerable
5
5
 
6
+ attr_reader :duration
7
+
6
8
  def initialize
7
9
  @features = []
8
10
  end
@@ -17,9 +19,11 @@ module Cucumber
17
19
  end
18
20
 
19
21
  def accept(visitor)
22
+ start = Time.now
20
23
  @features.each do |feature|
21
24
  visitor.visit_feature(feature)
22
25
  end
26
+ @duration = Time.now - start
23
27
  end
24
28
  end
25
29
  end
@@ -4,7 +4,7 @@ module Cucumber
4
4
  def initialize(raw, scenario_outline)
5
5
  super(raw)
6
6
  @scenario_outline = scenario_outline
7
- @cells_class = ExampleCells
7
+ @cells_class = ExampleRow
8
8
  create_step_invocations_for_example_rows!(scenario_outline)
9
9
  end
10
10
 
@@ -43,7 +43,7 @@ module Cucumber
43
43
  @scenario_outline.visit_scenario_name(visitor, row)
44
44
  end
45
45
 
46
- class ExampleCells < Cells
46
+ class ExampleRow < Cells
47
47
 
48
48
  def create_step_invocations!(scenario_outline)
49
49
  @scenario_outline = scenario_outline
@@ -5,6 +5,8 @@ module Cucumber
5
5
  class Scenario
6
6
  include FeatureElement
7
7
 
8
+ attr_reader :name, :line
9
+
8
10
  def initialize(background, comment, tags, line, keyword, name, steps)
9
11
  @background, @comment, @tags, @line, @keyword, @name = background, comment, tags, line, keyword, name
10
12
  attach_steps(steps)
@@ -257,6 +257,7 @@ module Cucumber
257
257
  requires = @options[:require] || feature_dirs
258
258
  files = requires.map do |path|
259
259
  path = path.gsub(/\\/, '/') # In case we're on windows. Globs don't work with backslashes.
260
+ path = path.gsub(/\/$/, '') # Strip trailing slash.
260
261
  File.directory?(path) ? Dir["#{path}/**/*.rb"] : path
261
262
  end.flatten.uniq
262
263
  sorted_files = files.sort { |a,b| (b =~ %r{/support/} || -1) <=> (a =~ %r{/support/} || -1) }.reject{|f| f =~ /^http/}
@@ -75,11 +75,12 @@ module Cucumber
75
75
  private
76
76
 
77
77
  def require_files
78
+ requires = configuration.files_to_require
78
79
  verbose_log("Ruby files required:")
79
- configuration.files_to_require.each do |lib|
80
+ verbose_log(requires.map{|lib| " * #{lib}"}.join("\n"))
81
+ requires.each do |lib|
80
82
  begin
81
83
  require lib
82
- verbose_log(" * #{lib}")
83
84
  rescue LoadError => e
84
85
  e.message << "\nFailed to load #{lib}"
85
86
  raise e
@@ -93,14 +94,18 @@ module Cucumber
93
94
  end
94
95
 
95
96
  def enable_diffing
96
- if configuration.diff_enabled? && defined?(::Spec)
97
+ if configuration.diff_enabled?
97
98
  begin
98
- require 'spec/runner/differs/default' # RSpec >=1.2.4
99
- rescue ::LoadError
100
- require 'spec/expectations/differs/default' # RSpec <=1.2.3
99
+ require 'spec/expectations'
100
+ begin
101
+ require 'spec/runner/differs/default' # RSpec >=1.2.4
102
+ rescue ::LoadError
103
+ require 'spec/expectations/differs/default' # RSpec <=1.2.3
104
+ end
105
+ options = OpenStruct.new(:diff_format => :unified, :context_lines => 3)
106
+ ::Spec::Expectations.differ = ::Spec::Expectations::Differs::Default.new(options)
107
+ rescue ::LoadError => ignore
101
108
  end
102
- options = OpenStruct.new(:diff_format => :unified, :context_lines => 3)
103
- ::Spec::Expectations.differ = ::Spec::Expectations::Differs::Default.new(options)
104
109
  end
105
110
  end
106
111
 
@@ -1,9 +1,12 @@
1
1
  require 'cucumber/formatter/ansicolor'
2
+ require 'cucumber/formatter/duration'
2
3
 
3
4
  module Cucumber
4
5
  module Formatter
5
6
  module Console
6
7
  extend ANSIColor
8
+ include Duration
9
+
7
10
  FORMATS = Hash.new{|hash, format| hash[format] = method(format).to_proc}
8
11
 
9
12
  def format_step(keyword, step_match, status, source_indent)
@@ -50,13 +53,15 @@ module Cucumber
50
53
  end
51
54
  end
52
55
 
53
- def print_counts
56
+ def print_stats(features)
54
57
  @io.print dump_count(step_mother.scenarios.length, "scenario")
55
58
  print_status_counts{|status| step_mother.scenarios(status)}
56
59
 
57
60
  @io.print dump_count(step_mother.steps.length, "step")
58
61
  print_status_counts{|status| step_mother.steps(status)}
59
62
 
63
+ @io.puts(format_duration(features.duration))
64
+
60
65
  @io.flush
61
66
  end
62
67
 
@@ -1,34 +1,53 @@
1
-
2
-
3
-
4
-
5
-
6
1
  .cucumber {
7
2
  background: black;
8
3
  color: white;
9
4
  padding: 1em;
10
5
  }
11
6
  .cucumber .passed {
12
- color: green;
7
+ color: #008800;
13
8
  }
14
9
  .cucumber .undefined {
15
- color: yellow;
10
+ color: #888800;
16
11
  }
17
12
  .cucumber .pending {
18
- color: yellow;
13
+ color: #888800;
19
14
  }
20
15
  .cucumber .failed {
21
- color: red;
16
+ color: #880000;
22
17
  }
23
18
  .cucumber .skipped {
24
- color: cyan;
19
+ color: #008888;
25
20
  }
26
21
  .cucumber .outline {
27
- color: cyan;
22
+ color: #008888;
23
+ }
24
+
25
+ .cucumber .passed_param {
26
+ font-weight: bold;
27
+ color: #00ff00;
28
+ }
29
+ .cucumber .undefined_param {
30
+ font-weight: bold;
31
+ color: #ffff00;
28
32
  }
29
- .cucumber .param {
33
+ .cucumber .pending_param {
30
34
  font-weight: bold;
35
+ color: #ffff00;
31
36
  }
37
+ .cucumber .failed_param {
38
+ font-weight: bold;
39
+ font-weight: bold;
40
+ color: #ff0000;
41
+ }
42
+ .cucumber .skipped_param {
43
+ font-weight: bold;
44
+ color: #00ffff;
45
+ }
46
+ .cucumber .outline_param {
47
+ font-weight: bold;
48
+ color: #00ffff;
49
+ }
50
+
32
51
  .cucumber a {
33
52
  text-decoration: none;
34
53
  color: inherit;
@@ -0,0 +1,10 @@
1
+ module Cucumber
2
+ module Formatter
3
+ module Duration
4
+ def format_duration(seconds)
5
+ m, s = seconds.divmod(60)
6
+ "#{m}m#{'%.3f' % s}s"
7
+ end
8
+ end
9
+ end
10
+ end
@@ -5,11 +5,13 @@ rescue LoadError
5
5
  gem 'builder'
6
6
  require 'builder'
7
7
  end
8
+ require 'cucumber/formatter/duration'
8
9
 
9
10
  module Cucumber
10
11
  module Formatter
11
12
  class Html < Ast::Visitor
12
13
  include ERB::Util # for the #h method
14
+ include Duration
13
15
 
14
16
  def initialize(step_mother, io, options)
15
17
  super(step_mother)
@@ -34,6 +36,7 @@ module Cucumber
34
36
  @builder.body do
35
37
  @builder.div(:class => 'cucumber') do
36
38
  super
39
+ @builder.div(format_duration(features.duration), :class => 'duration')
37
40
  end
38
41
  end
39
42
  end
@@ -45,6 +48,10 @@ module Cucumber
45
48
  end
46
49
  end
47
50
 
51
+ def visit_tag_name(tag_name)
52
+ @builder.span("@#{tag_name}", :class => 'tag')
53
+ end
54
+
48
55
  def visit_feature_name(name)
49
56
  lines = name.split(/\r?\n/)
50
57
  @builder.h2(lines[0])
@@ -63,6 +70,7 @@ module Cucumber
63
70
  end
64
71
 
65
72
  def visit_background_name(keyword, name, file_colon_line, source_indent)
73
+ @listing_background = true
66
74
  @builder.h3("#{keyword} #{name}")
67
75
  end
68
76
 
@@ -74,6 +82,7 @@ module Cucumber
74
82
  end
75
83
 
76
84
  def visit_scenario_name(keyword, name, file_colon_line, source_indent)
85
+ @listing_background = false
77
86
  @builder.h3("#{keyword} #{name}")
78
87
  end
79
88
 
@@ -102,21 +111,19 @@ module Cucumber
102
111
 
103
112
  def visit_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background)
104
113
  @status = status
105
- @builder.li(:id => @step_id, :class => status) do
114
+ @builder.li(:id => @step_id, :class => "step #{status}") do
106
115
  super(keyword, step_match, multiline_arg, status, exception, source_indent, background)
107
116
  end
108
117
  end
109
118
 
110
119
  def visit_step_name(keyword, step_match, status, source_indent, background)
111
120
  @step_matches ||= []
112
- @skip_step = @step_matches.index(step_match)
121
+ background_in_scenario = background && !@listing_background
122
+ @skip_step = @step_matches.index(step_match) || background_in_scenario
113
123
  @step_matches << step_match
114
124
 
115
125
  unless @skip_step
116
- step_name = step_match.format_args(lambda{|param| "<span>#{param}</span>"})
117
- @builder.div do |div|
118
- div << h("#{keyword} #{step_name}").gsub(/&lt;span&gt;/, '<span>').gsub(/&lt;\/span&gt;/, '</span>')
119
- end
126
+ build_step(keyword, step_match, status)
120
127
  end
121
128
  end
122
129
 
@@ -163,15 +170,26 @@ module Cucumber
163
170
  cell_type = @outline_row == 0 ? :th : :td
164
171
  attributes = {:id => "#{@row_id}_#{@col_index}"}
165
172
  attributes[:class] = status if status
166
- @builder.__send__(cell_type, value, attributes)
173
+ build_cell(cell_type, value, attributes)
167
174
  @col_index += 1
168
175
  end
169
-
176
+
170
177
  def announce(announcement)
171
178
  @builder.pre(announcement, :class => 'announcement')
172
179
  end
173
180
 
174
- private
181
+ protected
182
+
183
+ def build_step(keyword, step_match, status)
184
+ step_name = step_match.format_args(lambda{|param| %{<span class="#{status}_param">#{param}</span>}})
185
+ @builder.div do |div|
186
+ div << h("#{keyword} #{step_name}").gsub(/&lt;span class=&quot;(.*?)&quot;&gt;/, '<span class="\1">').gsub(/&lt;\/span&gt;/, '</span>')
187
+ end
188
+ end
189
+
190
+ def build_cell(cell_type, value, attributes)
191
+ @builder.__send__(cell_type, value, attributes)
192
+ end
175
193
 
176
194
  def inline_css
177
195
  @builder.style(:type => 'text/css') do
@@ -182,6 +200,7 @@ module Cucumber
182
200
  def format_exception(exception)
183
201
  (["#{exception.message} (#{exception.class})"] + exception.backtrace).join("\n")
184
202
  end
203
+
185
204
  end
186
205
  end
187
206
  end
@@ -24,7 +24,7 @@ module Cucumber
24
24
 
25
25
  def visit_features(features)
26
26
  super
27
- print_summary unless @options[:autoformat]
27
+ print_summary(features) unless @options[:autoformat]
28
28
  end
29
29
 
30
30
  def visit_feature(feature)
@@ -178,8 +178,8 @@ module Cucumber
178
178
 
179
179
  private
180
180
 
181
- def print_summary
182
- print_counts
181
+ def print_summary(features)
182
+ print_stats(features)
183
183
  print_snippets(@options)
184
184
  print_passing_wip(@options)
185
185
  end
@@ -27,7 +27,7 @@ module Cucumber
27
27
  end
28
28
  end
29
29
 
30
- def print_summary
30
+ def print_summary(features)
31
31
  super
32
32
  @io.puts "\n\nTop #{NUMBER_OF_STEP_DEFINITONS_TO_SHOW} average slowest steps with #{NUMBER_OF_STEP_INVOCATIONS_TO_SHOW} slowest matches:\n"
33
33
 
@@ -15,7 +15,7 @@ module Cucumber
15
15
  super
16
16
  @io.puts
17
17
  @io.puts
18
- print_summary
18
+ print_summary(features)
19
19
  end
20
20
 
21
21
  def visit_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background)
@@ -30,10 +30,10 @@ module Cucumber
30
30
 
31
31
  private
32
32
 
33
- def print_summary
33
+ def print_summary(features)
34
34
  print_steps(:pending)
35
35
  print_steps(:failed)
36
- print_counts
36
+ print_stats(features)
37
37
  print_snippets(@options)
38
38
  print_passing_wip(@options)
39
39
  end
@@ -10,14 +10,14 @@ module Cucumber
10
10
 
11
11
  def visit_features(features)
12
12
  super
13
- print_summary
13
+ print_summary(features)
14
14
  end
15
15
 
16
16
  def visit_tag_name(tag_name)
17
17
  @counts[tag_name] += 1
18
18
  end
19
19
 
20
- def print_summary
20
+ def print_summary(features)
21
21
  matrix = @counts.to_a.sort{|paira, pairb| paira[0] <=> pairb[0]}.transpose
22
22
  table = Cucumber::Ast::Table.new(matrix)
23
23
  Cucumber::Formatter::Pretty.new(@step_mother, @io, {}).visit_multiline_arg(table)
@@ -16,7 +16,7 @@ module Cucumber
16
16
 
17
17
  def visit_features(features)
18
18
  super
19
- print_summary
19
+ print_summary(features)
20
20
  end
21
21
 
22
22
  def visit_step(step)
@@ -37,7 +37,7 @@ module Cucumber
37
37
  end
38
38
  end
39
39
 
40
- def print_summary
40
+ def print_summary(features)
41
41
  sorted_defs = @step_definitions.keys.sort_by{|step_definition| step_definition.backtrace_line}
42
42
 
43
43
  sorted_defs.each do |step_definition|