cucumber 0.3.93 → 0.3.94

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 (42) hide show
  1. data/History.txt +67 -38
  2. data/Manifest.txt +8 -0
  3. data/Rakefile +1 -1
  4. data/cucumber.yml +2 -2
  5. data/examples/python/features/fibonacci.feature +19 -0
  6. data/examples/python/features/step_definitions/fib_steps.rb +7 -0
  7. data/examples/python/features/support/env.rb +21 -0
  8. data/examples/python/lib/fib.py +7 -0
  9. data/examples/self_test/features/tags_sample.feature +17 -0
  10. data/examples/sinatra/README.textile +13 -0
  11. data/features/cucumber_cli.feature +85 -3
  12. data/features/custom_formatter.feature +2 -2
  13. data/features/html_formatter/a.html +1 -1
  14. data/features/junit_formatter.feature +19 -12
  15. data/features/step_definitions/cucumber_steps.rb +8 -15
  16. data/features/support/env.rb +4 -5
  17. data/gem_tasks/contributors.rake +4 -0
  18. data/lib/cucumber/ast/feature.rb +13 -0
  19. data/lib/cucumber/ast/feature_element.rb +8 -4
  20. data/lib/cucumber/ast/features.rb +6 -1
  21. data/lib/cucumber/ast/table.rb +13 -6
  22. data/lib/cucumber/ast/tags.rb +9 -1
  23. data/lib/cucumber/cli/configuration.rb +3 -15
  24. data/lib/cucumber/cli/main.rb +25 -8
  25. data/lib/cucumber/cli/options.rb +53 -31
  26. data/lib/cucumber/filter.rb +4 -3
  27. data/lib/cucumber/formatter/ansicolor.rb +42 -9
  28. data/lib/cucumber/formatter/console.rb +38 -6
  29. data/lib/cucumber/formatter/html.rb +2 -8
  30. data/lib/cucumber/formatter/junit.rb +65 -24
  31. data/lib/cucumber/formatter/ordered_xml_markup.rb +24 -0
  32. data/lib/cucumber/formatter/pretty.rb +9 -4
  33. data/lib/cucumber/formatter/progress.rb +7 -1
  34. data/lib/cucumber/rake/task.rb +3 -3
  35. data/lib/cucumber/step_mother.rb +3 -1
  36. data/lib/cucumber/version.rb +1 -1
  37. data/rails_generators/cucumber/templates/cucumber.rake +18 -6
  38. data/spec/cucumber/ast/scenario_outline_spec.rb +2 -2
  39. data/spec/cucumber/ast/table_spec.rb +5 -0
  40. data/spec/cucumber/cli/configuration_spec.rb +2 -1
  41. data/spec/cucumber/cli/options_spec.rb +11 -6
  42. metadata +10 -2
@@ -2,8 +2,9 @@ module Cucumber
2
2
  class Filter
3
3
  def initialize(lines, options)
4
4
  @lines = lines
5
- @include_tags = options[:include_tags] || []
6
- @exclude_tags = options[:exclude_tags] || []
5
+
6
+ @include_tags = options[:include_tags] ? options[:include_tags].keys : []
7
+ @exclude_tags = options[:exclude_tags] ? options[:exclude_tags].keys : []
7
8
  @name_regexps = options[:name_regexps] || []
8
9
  end
9
10
 
@@ -14,7 +15,7 @@ module Cucumber
14
15
  end
15
16
 
16
17
  def accept_example?(syntax_node, outline)
17
- (at_line?(syntax_node) || outline_at_line?(outline)) &&
18
+ (at_line?(syntax_node) || outline_at_line?(outline)) &&
18
19
  (matches_names?(syntax_node) || outline_matches_names?(outline))
19
20
  end
20
21
 
@@ -60,15 +60,6 @@ module Cucumber
60
60
  module ANSIColor
61
61
  include Term::ANSIColor
62
62
 
63
- # Not supported in Term::ANSIColor
64
- def grey(m)
65
- if ::Term::ANSIColor.coloring?
66
- "\e[90m#{m}\e[0m"
67
- else
68
- m
69
- end
70
- end
71
-
72
63
  ALIASES = Hash.new do |h,k|
73
64
  if k.to_s =~ /(.*)_param/
74
65
  h[$1] + ',bold'
@@ -105,6 +96,48 @@ module Cucumber
105
96
  eval(code)
106
97
  end
107
98
  end
99
+
100
+ def self.define_grey
101
+ begin
102
+ gem 'genki-ruby-terminfo'
103
+ require 'terminfo'
104
+ puts TermInfo.default_object.tigetnum("colors")
105
+ case TermInfo.default_object.tigetnum("colors")
106
+ when 0
107
+ raise "Your terminal doesn't support colours"
108
+ when 1
109
+ ::Term::ANSIColor.coloring = false
110
+ alias grey white
111
+ when 2..8
112
+ alias grey white
113
+ else
114
+ define_real_grey
115
+ end
116
+ rescue Exception => e
117
+ if e.class.name == 'TermInfo::TermInfoError'
118
+ STDERR.puts "*** WARNING ***"
119
+ STDERR.puts "You have the genki-ruby-terminfo gem installed, but you haven't set your TERM variable."
120
+ STDERR.puts "Try setting it to TERM=xterm-256color to get grey colour in output"
121
+ STDERR.puts "\n"
122
+ alias grey white
123
+ else
124
+ define_real_grey
125
+ end
126
+ end
127
+ end
128
+
129
+ def self.define_real_grey
130
+ def grey(m)
131
+ if ::Term::ANSIColor.coloring?
132
+ "\e[90m#{m}\e[0m"
133
+ else
134
+ m
135
+ end
136
+ end
137
+ end
138
+
139
+ define_grey
140
+
108
141
  end
109
142
  end
110
143
  end
@@ -6,7 +6,7 @@ module Cucumber
6
6
  module Console
7
7
  extend ANSIColor
8
8
  include Duration
9
-
9
+
10
10
  FORMATS = Hash.new{|hash, format| hash[format] = method(format).to_proc}
11
11
 
12
12
  def format_step(keyword, step_match, status, source_indent)
@@ -59,9 +59,9 @@ module Cucumber
59
59
  end
60
60
 
61
61
  def print_stats(features)
62
-
62
+
63
63
  @failures = step_mother.scenarios(:failed).select { |s| s.is_a?(Cucumber::Ast::Scenario) }
64
-
64
+
65
65
  if !@failures.empty?
66
66
  @io.puts format_string("Failing Scenarios:", :failed)
67
67
  @failures.each do |failure|
@@ -70,7 +70,7 @@ module Cucumber
70
70
  end
71
71
  @io.puts
72
72
  end
73
-
73
+
74
74
  @io.print dump_count(step_mother.scenarios.length, "scenario")
75
75
  print_status_counts{|status| step_mother.scenarios(status)}
76
76
 
@@ -81,7 +81,7 @@ module Cucumber
81
81
 
82
82
  @io.flush
83
83
  end
84
-
84
+
85
85
  def print_exception(e, status, indent)
86
86
  @io.puts(format_string("#{e.message} (#{e.class})\n#{e.backtrace.join("\n")}".indent(indent), status))
87
87
  end
@@ -114,6 +114,29 @@ module Cucumber
114
114
  end
115
115
  end
116
116
 
117
+ def print_tag_limit_warnings(options)
118
+ return unless tag_limit_breached?(options, @tag_occurences)
119
+ @io.puts
120
+ @io.puts format_string("Failed due to exceeding the tag limit", :failed)
121
+ options[:include_tags].each do |tag_name, limit|
122
+ tag_frequnecy = @tag_occurences[tag_name].size
123
+ if limit && tag_frequnecy > limit
124
+ @io.puts format_string("@#{tag_name} occurred:#{tag_frequnecy} limit:#{limit}", :failed)
125
+ @tag_occurences[tag_name].each {|location| @io.puts format_string(" #{location}", :failed)}
126
+ @io.flush
127
+ end
128
+ end
129
+ end
130
+
131
+ def record_tag_occurrences(feature_element, options)
132
+ @tag_occurences ||= Hash.new{|k,v| k[v] = []}
133
+ options[:include_tags].each do |tag_name, limit|
134
+ if feature_element.tag_count(tag_name) > 0
135
+ @tag_occurences[tag_name] << feature_element.file_colon_line
136
+ end
137
+ end
138
+ end
139
+
117
140
  def announce(announcement)
118
141
  @io.puts
119
142
  @io.puts(format_string(announcement, :tag))
@@ -144,6 +167,15 @@ module Cucumber
144
167
  raise "No format for #{key.inspect}: #{FORMATS.inspect}" if fmt.nil?
145
168
  fmt
146
169
  end
170
+
171
+ def tag_limit_breached?(options, tag_occurences)
172
+ return if tag_occurences.nil?
173
+ tag_limit_breached = false
174
+ options[:include_tags].each do |tag_name, limit|
175
+ tag_limit_breached ||= limit && (tag_occurences[tag_name].size > limit)
176
+ end
177
+ tag_limit_breached
178
+ end
147
179
  end
148
180
  end
149
- end
181
+ end
@@ -1,10 +1,4 @@
1
- require 'erb'
2
- begin
3
- require 'builder'
4
- rescue LoadError
5
- gem 'builder'
6
- require 'builder'
7
- end
1
+ require 'cucumber/formatter/ordered_xml_markup'
8
2
  require 'cucumber/formatter/duration'
9
3
 
10
4
  module Cucumber
@@ -20,7 +14,7 @@ module Cucumber
20
14
  end
21
15
 
22
16
  def create_builder(io)
23
- Builder::XmlMarkup.new(:target => io, :indent => 0)
17
+ OrderedXmlMarkup.new(:target => io, :indent => 0)
24
18
  end
25
19
 
26
20
  def visit_features(features)
@@ -1,9 +1,4 @@
1
- begin
2
- require 'builder'
3
- rescue LoadError
4
- gem 'builder'
5
- require 'builder'
6
- end
1
+ require 'cucumber/formatter/ordered_xml_markup'
7
2
 
8
3
  module Cucumber
9
4
  module Formatter
@@ -18,16 +13,18 @@ module Cucumber
18
13
 
19
14
  def visit_feature(feature)
20
15
  @failures = @errors = @tests = 0
21
- @builder = Builder::XmlMarkup.new( :indent => 2 )
16
+ @builder = OrderedXmlMarkup.new( :indent => 2 )
17
+ @time = 0
22
18
  super
23
19
 
24
- @testsuite = Builder::XmlMarkup.new( :indent => 2 )
20
+ @testsuite = OrderedXmlMarkup.new( :indent => 2 )
25
21
  @testsuite.instruct!
26
22
  @testsuite.testsuite(
27
23
  :failures => @failures,
28
24
  :errors => @errors,
29
25
  :tests => @tests,
30
- :name => @feature_name ) do
26
+ :time => "%.6f" % @time,
27
+ :name => @feature_name ) do
31
28
  @testsuite << @builder.target!
32
29
  end
33
30
 
@@ -36,40 +33,84 @@ module Cucumber
36
33
  File.open(feature_filename, 'w') { |file| file.write(@testsuite.target!) }
37
34
  end
38
35
 
36
+ def visit_background(name)
37
+ @in_background = true
38
+ super
39
+ @in_background = false
40
+ end
41
+
39
42
  def visit_feature_name(name)
40
43
  lines = name.split(/\r?\n/)
41
44
  @feature_name = lines[0].sub(/Feature\:/, '').strip
42
45
  end
43
46
 
44
47
  def visit_scenario_name(keyword, name, file_colon_line, source_indent)
45
- @scenario = name
48
+ scenario_name = name.strip
49
+ scenario_name = "Unnamed scenario" if name == ""
50
+ @scenario = scenario_name
51
+ @outline = keyword.include?('Scenario Outline')
52
+ @output = "Scenario#{ " outline" if @outline}: #{@scenario}\n\n"
46
53
  end
47
54
 
48
55
  def visit_steps(steps)
49
- @steps_failed = false
56
+ return if @in_background
57
+ start = Time.now
50
58
  super
51
- @failures += 1 if @steps_failed
52
- @tests += 1
59
+ duration = Time.now - start
60
+ unless @outline
61
+ if steps.failed?
62
+ steps.each { |step| @output += "#{step.keyword} #{step.name}\n" }
63
+ @output += "\nMessage:\n"
64
+ end
65
+ build_testcase(duration, steps.status, steps.exception)
66
+ end
67
+ end
68
+
69
+ def visit_outline_table(outline_table)
70
+ @header_row = true
71
+ super(outline_table)
53
72
  end
54
73
 
55
- def visit_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background)
56
- step_name = keyword + " " + step_match.format_args(lambda{|param| "*#{param}*"})
57
- @builder.testcase(:classname => "#{@feature_name}.#{@scenario}", :name => step_name) do
58
- if status != :passed
59
- @builder.failure(:message => step_name) do
60
- @builder.text!(format_exception(exception)) if exception
74
+ def visit_table_row(table_row)
75
+ if @outline
76
+ start = Time.now
77
+ super(table_row)
78
+ duration = Time.now - start
79
+ unless @header_row
80
+ name_suffix = " (outline example : #{table_row.name})"
81
+ if table_row.failed?
82
+ @output += "Example row: #{table_row.name}\n"
83
+ @output += "\nMessage:\n"
61
84
  end
62
- @steps_failed = true
85
+ build_testcase(duration, table_row.status, table_row.exception, name_suffix)
63
86
  end
87
+ else
88
+ super(table_row)
64
89
  end
90
+ @header_row = false
65
91
  end
66
92
 
67
93
  private
68
94
 
69
- def format_exception(exception)
70
- (["#{exception.message} (#{exception.class})"] + exception.backtrace).join("\n")
71
- end
72
- end
95
+ def build_testcase(duration, status, exception = nil, suffix = "")
96
+ @time += duration
97
+ classname = "#{@feature_name}.#{@scenario}"
98
+ name = "#{@scenario}#{suffix}"
99
+ @builder.testcase(:classname => classname, :name => name, :time => "%.6f" % duration) do
100
+ if status != :passed
101
+ @builder.failure(:message => "#{status.to_s} #{name}", :type => status.to_s) do
102
+ @builder.text! @output
103
+ @builder.text!(format_exception(exception)) if exception
104
+ end
105
+ @failures += 1
106
+ end
107
+ end
108
+ @tests += 1
109
+ end
73
110
 
111
+ def format_exception(exception)
112
+ (["#{exception.message} (#{exception.class})"] + exception.backtrace).join("\n")
113
+ end
114
+ end
74
115
  end
75
116
  end
@@ -0,0 +1,24 @@
1
+ begin
2
+ require 'builder'
3
+ rescue LoadError
4
+ gem 'builder'
5
+ require 'builder'
6
+ end
7
+
8
+ module Cucumber
9
+ module Formatter
10
+ # Emits attributes ordered alphabetically, so that we can predicatbly test output.
11
+ class OrderedXmlMarkup < Builder::XmlMarkup
12
+ def _insert_attributes(attrs, order=[])
13
+ return if attrs.nil?
14
+ keys = attrs.keys.map{|k| k.to_s}
15
+ keys.sort!
16
+ keys.reverse! if (attrs.keys - [:version, :encoding] == []) #HACK to ensure the 'version' attribute is first in xml declaration.
17
+ keys.each do |k|
18
+ v = attrs[k.to_sym] || attrs[k]
19
+ @target << %{ #{k}="#{_attr_value(v)}"} if v
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -48,14 +48,14 @@ module Cucumber
48
48
  end
49
49
 
50
50
  def visit_comment_line(comment_line)
51
- @io.puts(comment_line.indent(@indent))
51
+ @io.puts(comment_line.indent(@indent))
52
52
  @io.flush
53
53
  end
54
54
 
55
55
  def visit_tags(tags)
56
56
  tags.accept(self)
57
57
  if @indent == 1
58
- @io.puts
58
+ @io.puts
59
59
  @io.flush
60
60
  end
61
61
  end
@@ -74,6 +74,7 @@ module Cucumber
74
74
  end
75
75
 
76
76
  def visit_feature_element(feature_element)
77
+ record_tag_occurrences(feature_element, @options)
77
78
  @indent = 2
78
79
  @scenario_indent = 2
79
80
  super
@@ -160,7 +161,7 @@ module Cucumber
160
161
  super
161
162
  @io.puts
162
163
  if table_row.exception && !@exceptions.index(table_row.exception)
163
- print_exception(table_row.exception, :failed, @indent)
164
+ print_exception(table_row.exception, :failed, @indent)
164
165
  end
165
166
  end
166
167
 
@@ -187,7 +188,10 @@ module Cucumber
187
188
  end
188
189
 
189
190
  private
190
-
191
+ def cell_prefix(status)
192
+ @prefixes[status]
193
+ end
194
+
191
195
  def cell_prefix(status)
192
196
  @prefixes[status]
193
197
  end
@@ -196,6 +200,7 @@ module Cucumber
196
200
  print_stats(features)
197
201
  print_snippets(@options)
198
202
  print_passing_wip(@options)
203
+ print_tag_limit_warnings(@options)
199
204
  end
200
205
 
201
206
  end
@@ -18,6 +18,11 @@ module Cucumber
18
18
  print_summary(features)
19
19
  end
20
20
 
21
+ def visit_feature_element(feature_element)
22
+ record_tag_occurrences(feature_element, @options)
23
+ super
24
+ end
25
+
21
26
  def visit_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background)
22
27
  progress(status)
23
28
  @status = status
@@ -36,6 +41,7 @@ module Cucumber
36
41
  print_stats(features)
37
42
  print_snippets(@options)
38
43
  print_passing_wip(@options)
44
+ print_tag_limit_warnings(@options)
39
45
  end
40
46
 
41
47
  CHARS = {
@@ -51,7 +57,7 @@ module Cucumber
51
57
  @io.print(format_string(char, status))
52
58
  @io.flush
53
59
  end
54
-
60
+
55
61
  def table_header_cell?(status)
56
62
  status == :skipped_param
57
63
  end
@@ -8,8 +8,8 @@ module Cucumber
8
8
  #
9
9
  # Cucumber::Rake::Task.new
10
10
  #
11
- # This will create a task named 'features' described as 'Run Features with
12
- # Cucumber'. It will use steps from 'features/**/*.rb' and features in 'features/**/*.feature'.
11
+ # This will create a task named 'cucumber' described as 'Run Cucumber features'.
12
+ # It will use steps from 'features/**/*.rb' and features in 'features/**/*.feature'.
13
13
  #
14
14
  # To further configure the task, you can pass a block:
15
15
  #
@@ -148,7 +148,7 @@ module Cucumber
148
148
  end
149
149
 
150
150
  # Define Cucumber Rake task
151
- def initialize(task_name = "features", desc = "Run Features with Cucumber")
151
+ def initialize(task_name = "cucumber", desc = "Run Cucumber features")
152
152
  @task_name, @desc = task_name, desc
153
153
  @fork = true
154
154
  @libs = ['lib']