square-cucumber 0.3.12.2 → 0.3.93.1

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 (91) hide show
  1. data/History.txt +117 -4
  2. data/Manifest.txt +11 -0
  3. data/Rakefile +1 -1
  4. data/config/hoe.rb +3 -2
  5. data/cucumber.yml +2 -2
  6. data/examples/i18n/ko/features/addition.feature +5 -5
  7. data/examples/i18n/ko/features/step_definitons/calculator_steps.rb +1 -1
  8. data/examples/i18n/no/features/step_definitons/kalkulator_steps.rb +1 -1
  9. data/examples/i18n/pt/features/adicao.feature +4 -4
  10. data/examples/self_test/features/support/env.rb +2 -1
  11. data/examples/sinatra/features/support/env.rb +7 -1
  12. data/examples/steps_library/features/step_definitions/steps_lib1.rb +8 -0
  13. data/examples/steps_library/features/step_definitions/steps_lib2.rb +8 -0
  14. data/examples/tickets/features/step_definitons/tickets_steps.rb +15 -0
  15. data/examples/tickets/features/table_diffing.feature +13 -0
  16. data/examples/watir/features/step_definitons/search_steps.rb +5 -1
  17. data/features/cucumber_cli_diff_disabled.feature +2 -1
  18. data/features/html_formatter/a.html +5 -7
  19. data/features/junit_formatter.feature +21 -14
  20. data/features/profiles.feature +99 -0
  21. data/features/rake_task.feature +28 -0
  22. data/features/step_definitions/cucumber_steps.rb +28 -15
  23. data/features/steps_formatter.feature +25 -0
  24. data/features/support/env.rb +9 -5
  25. data/features/table_diffing.feature +45 -0
  26. data/features/unicode_table.feature +35 -0
  27. data/features/work_in_progress.feature +1 -0
  28. data/gem_tasks/contributors.rake +4 -0
  29. data/lib/cucumber/ast/background.rb +1 -0
  30. data/lib/cucumber/ast/comment.rb +1 -0
  31. data/lib/cucumber/ast/examples.rb +1 -0
  32. data/lib/cucumber/ast/feature.rb +10 -0
  33. data/lib/cucumber/ast/features.rb +6 -1
  34. data/lib/cucumber/ast/outline_table.rb +4 -1
  35. data/lib/cucumber/ast/py_string.rb +1 -1
  36. data/lib/cucumber/ast/scenario.rb +1 -0
  37. data/lib/cucumber/ast/scenario_outline.rb +2 -0
  38. data/lib/cucumber/ast/step.rb +5 -1
  39. data/lib/cucumber/ast/step_collection.rb +1 -0
  40. data/lib/cucumber/ast/step_invocation.rb +1 -0
  41. data/lib/cucumber/ast/table.rb +306 -52
  42. data/lib/cucumber/ast/tags.rb +1 -0
  43. data/lib/cucumber/ast/visitor.rb +2 -1
  44. data/lib/cucumber/cli/configuration.rb +28 -278
  45. data/lib/cucumber/cli/drb_client.rb +3 -1
  46. data/lib/cucumber/cli/language_help_formatter.rb +9 -7
  47. data/lib/cucumber/cli/main.rb +16 -2
  48. data/lib/cucumber/cli/options.rb +370 -0
  49. data/lib/cucumber/cli/profile_loader.rb +65 -0
  50. data/lib/cucumber/core_ext/instance_exec.rb +8 -5
  51. data/lib/cucumber/feature_file.rb +7 -1
  52. data/lib/cucumber/filter.rb +2 -2
  53. data/lib/cucumber/formatter/ansicolor.rb +42 -9
  54. data/lib/cucumber/formatter/console.rb +1 -1
  55. data/lib/cucumber/formatter/html.rb +12 -10
  56. data/lib/cucumber/formatter/junit.rb +63 -26
  57. data/lib/cucumber/formatter/pretty.rb +20 -5
  58. data/lib/cucumber/formatter/progress.rb +1 -1
  59. data/lib/cucumber/formatter/steps.rb +49 -0
  60. data/lib/cucumber/languages.yml +6 -6
  61. data/lib/cucumber/parser/feature.rb +90 -63
  62. data/lib/cucumber/parser/feature.tt +28 -1
  63. data/lib/cucumber/parser/i18n/language.rb +12 -5
  64. data/lib/cucumber/parser/table.rb +25 -25
  65. data/lib/cucumber/rake/task.rb +9 -3
  66. data/lib/cucumber/step_definition.rb +1 -1
  67. data/lib/cucumber/step_match.rb +1 -1
  68. data/lib/cucumber/step_mother.rb +3 -1
  69. data/lib/cucumber/version.rb +2 -2
  70. data/lib/cucumber/webrat/table_locator.rb +66 -0
  71. data/rails_generators/cucumber/cucumber_generator.rb +5 -1
  72. data/rails_generators/cucumber/templates/cucumber +3 -2
  73. data/rails_generators/cucumber/templates/cucumber.rake +18 -6
  74. data/rails_generators/cucumber/templates/cucumber_environment.rb +7 -4
  75. data/rails_generators/cucumber/templates/env.rb +1 -0
  76. data/rails_generators/cucumber/templates/spork_env.rb +1 -0
  77. data/rails_generators/cucumber/templates/webrat_steps.rb +22 -0
  78. data/rails_generators/feature/templates/feature.erb +1 -1
  79. data/rails_generators/feature/templates/steps.erb +2 -8
  80. data/spec/cucumber/ast/table_spec.rb +169 -0
  81. data/spec/cucumber/cli/configuration_spec.rb +144 -101
  82. data/spec/cucumber/cli/main_spec.rb +14 -5
  83. data/spec/cucumber/cli/options_spec.rb +311 -0
  84. data/spec/cucumber/cli/profile_loader_spec.rb +10 -0
  85. data/spec/cucumber/core_ext/proc_spec.rb +16 -2
  86. data/spec/cucumber/formatter/html_spec.rb +18 -0
  87. data/spec/cucumber/formatter/progress_spec.rb +2 -2
  88. data/spec/cucumber/parser/table_parser_spec.rb +1 -1
  89. data/spec/spec.opts +3 -1
  90. metadata +18 -4
  91. data/lib/cucumber/webrat/mechanize_world.rb +0 -82
@@ -10,10 +10,12 @@ class Object
10
10
  cucumber_run_with_backtrace_filtering(pseudo_method) do
11
11
  if check_arity && !cucumber_compatible_arity?(args, block)
12
12
  instance_exec do
13
- s1 = cucumber_arity(block) == 1 ? "" : "s"
13
+ ari = cucumber_arity(block)
14
+ ari = ari < 0 ? (ari.abs-1).to_s+"+" : ari
15
+ s1 = ari == 1 ? "" : "s"
14
16
  s2 = args.length == 1 ? "" : "s"
15
17
  raise Cucumber::ArityMismatchError.new(
16
- "Your block takes #{cucumber_arity(block)} argument#{s1}, but the Regexp matched #{args.length} argument#{s2}."
18
+ "Your block takes #{ari} argument#{s1}, but the Regexp matched #{args.length} argument#{s2}."
17
19
  )
18
20
  end
19
21
  else
@@ -28,9 +30,10 @@ class Object
28
30
  end
29
31
 
30
32
  def cucumber_compatible_arity?(args, block)
31
- a = cucumber_arity(block)
32
- return true if (a == -1) && Cucumber::RUBY_1_9
33
- a == args.length
33
+ ari = cucumber_arity(block)
34
+ len = args.length
35
+ return true if ari == len or ari < 0 && len >= ari.abs-1
36
+ false
34
37
  end
35
38
 
36
39
  def cucumber_run_with_backtrace_filtering(pseudo_method)
@@ -31,7 +31,13 @@ module Cucumber
31
31
  require 'open-uri'
32
32
  open(@path).read
33
33
  else
34
- File.open(@path, Cucumber.file_mode('r')).read
34
+ begin
35
+ File.open(@path, Cucumber.file_mode('r')).read
36
+ rescue Errno::EACCES => e
37
+ p = File.expand_path(@path)
38
+ e.message << "\nCouldn't open #{p}"
39
+ raise e
40
+ end
35
41
  end
36
42
  end
37
43
 
@@ -32,7 +32,7 @@ module Cucumber
32
32
  end
33
33
 
34
34
  def included_by_tags?(syntax_node)
35
- @include_tags.empty? || syntax_node.has_tags?(@include_tags)
35
+ @include_tags.empty? || syntax_node.has_all_tags?(@include_tags)
36
36
  end
37
37
 
38
38
  def excluded_by_tags?(syntax_node)
@@ -47,4 +47,4 @@ module Cucumber
47
47
  @name_regexps.nil? || @name_regexps.empty? || @name_regexps.detect{|name_regexp| syntax_node.matches_name?(name_regexp)}
48
48
  end
49
49
  end
50
- end
50
+ end
@@ -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
@@ -77,7 +77,7 @@ module Cucumber
77
77
  @io.print dump_count(step_mother.steps.length, "step")
78
78
  print_status_counts{|status| step_mother.steps(status)}
79
79
 
80
- @io.puts(format_duration(features.duration)) if features
80
+ @io.puts(format_duration(features.duration)) if features && features.duration
81
81
 
82
82
  @io.flush
83
83
  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)
@@ -65,12 +59,20 @@ module Cucumber
65
59
  end
66
60
  end
67
61
 
62
+ def visit_tags(tags)
63
+ super
64
+ @tag_spacer = nil
65
+ end
66
+
68
67
  def visit_tag_name(tag_name)
68
+ @builder.text!(@tag_spacer) if @tag_spacer
69
+ @tag_spacer = ' '
69
70
  @builder.span("@#{tag_name}", :class => 'tag')
70
71
  end
71
72
 
72
73
  def visit_feature_name(name)
73
74
  lines = name.split(/\r?\n/)
75
+ return if lines.empty?
74
76
  @builder.h2 do |h2|
75
77
  @builder.span(lines[0], :class => 'val')
76
78
  end
@@ -192,7 +194,7 @@ module Cucumber
192
194
 
193
195
  def visit_py_string(string)
194
196
  @builder.pre(:class => 'val') do |pre|
195
- @builder.text!(' ' + string)
197
+ @builder << string.gsub("\n", '&#x000A;')
196
198
  end
197
199
  end
198
200
 
@@ -214,7 +216,7 @@ module Cucumber
214
216
  @outline_row += 1 if @outline_row
215
217
  end
216
218
 
217
- def visit_table_cell_value(value, width, status)
219
+ def visit_table_cell_value(value, status)
218
220
  cell_type = @outline_row == 0 ? :th : :td
219
221
  attributes = {:id => "#{@row_id}_#{@col_index}", :class => 'val'}
220
222
  attributes[:class] += " #{status}" if status
@@ -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 => @time,
27
+ :name => @feature_name ) do
31
28
  @testsuite << @builder.target!
32
29
  end
33
30
 
@@ -36,40 +33,80 @@ 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
- def visit_scenario_name(keyword, name, file_colon_line, source_indent)
45
- @scenario = name
47
+ def visit_scenario_name(keyword, name, file_colon_line, source_indent)
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
53
67
  end
54
68
 
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
61
- end
62
- @steps_failed = true
69
+ def visit_outline_table(outline_table)
70
+ @header_row = true
71
+ super(outline_table)
72
+ end
73
+
74
+ def visit_table_row(table_row)
75
+ start = Time.now
76
+ super(table_row)
77
+ duration = Time.now - start
78
+ unless @header_row
79
+ name_suffix = " (outline example : #{table_row.name})"
80
+ if table_row.failed?
81
+ @output += "Example row: #{table_row.name}\n"
82
+ @output += "\nMessage:\n"
63
83
  end
84
+ build_testcase(duration, table_row.status, table_row.exception, name_suffix)
64
85
  end
86
+ @header_row = false
65
87
  end
66
88
 
67
89
  private
68
90
 
69
- def format_exception(exception)
70
- (["#{exception.message} (#{exception.class})"] + exception.backtrace).join("\n")
71
- end
72
- end
91
+ def build_testcase(duration, status, exception = nil, suffix = "")
92
+ @time += duration
93
+ classname = "#{@feature_name}.#{@scenario}"
94
+ name = "#{@scenario}#{suffix}"
95
+ @builder.testcase(:classname => classname, :name => name, :time => duration) do
96
+ if status != :passed
97
+ @builder.failure(:message => "#{status.to_s} #{name}", :type => status.to_s) do
98
+ @builder.text! @output
99
+ @builder.text!(format_exception(exception)) if exception
100
+ end
101
+ @failures += 1
102
+ end
103
+ end
104
+ @tests += 1
105
+ end
73
106
 
107
+ def format_exception(exception)
108
+ (["#{exception.message} (#{exception.class})"] + exception.backtrace).join("\n")
109
+ end
110
+ end
74
111
  end
75
112
  end
@@ -13,13 +13,13 @@ module Cucumber
13
13
  include Console
14
14
  attr_writer :indent
15
15
 
16
- def initialize(step_mother, io, options, delim='|')
16
+ def initialize(step_mother, io, options)
17
17
  super(step_mother)
18
18
  @io = io
19
19
  @options = options
20
- @delim = delim
21
20
  @exceptions = []
22
21
  @indent = 0
22
+ @prefixes = options[:prefixes] || {}
23
23
  end
24
24
 
25
25
  def visit_features(features)
@@ -145,6 +145,7 @@ module Cucumber
145
145
 
146
146
  def visit_multiline_arg(multiline_arg)
147
147
  return if @options[:no_multiline]
148
+ @table = multiline_arg
148
149
  super
149
150
  end
150
151
 
@@ -154,7 +155,8 @@ module Cucumber
154
155
  end
155
156
 
156
157
  def visit_table_row(table_row)
157
- @io.print @delim.indent(@indent)
158
+ @col_index = 0
159
+ @io.print ' |'.indent(@indent-2)
158
160
  super
159
161
  @io.puts
160
162
  if table_row.exception && !@exceptions.index(table_row.exception)
@@ -169,13 +171,26 @@ module Cucumber
169
171
  @io.flush
170
172
  end
171
173
 
172
- def visit_table_cell_value(value, width, status)
174
+ def visit_table_cell(cell)
175
+ super
176
+ @col_index += 1
177
+ end
178
+
179
+ def visit_table_cell_value(value, status)
173
180
  status ||= @status || :passed
174
- @io.print(' ' + format_string((value.to_s || '').ljust(width), status) + ::Term::ANSIColor.reset(" #{@delim}"))
181
+ width = @table.col_width(@col_index)
182
+ cell_text = value.to_s || ''
183
+ padded = cell_text + (' ' * (width - cell_text.jlength))
184
+ prefix = cell_prefix(status)
185
+ @io.print(' ' + format_string("#{prefix}#{padded}", status) + ::Term::ANSIColor.reset(" |"))
175
186
  @io.flush
176
187
  end
177
188
 
178
189
  private
190
+
191
+ def cell_prefix(status)
192
+ @prefixes[status]
193
+ end
179
194
 
180
195
  def print_summary(features)
181
196
  print_stats(features)
@@ -23,7 +23,7 @@ module Cucumber
23
23
  @status = status
24
24
  end
25
25
 
26
- def visit_table_cell_value(value, width, status)
26
+ def visit_table_cell_value(value, status)
27
27
  status ||= @status
28
28
  progress(status) unless table_header_cell?(status)
29
29
  end
@@ -0,0 +1,49 @@
1
+ module Cucumber
2
+ module Formatter
3
+ class Steps < Ast::Visitor
4
+
5
+ def initialize(step_mother, io, options)
6
+ super(step_mother)
7
+ @io = io
8
+ @options = options
9
+ @step_definition_files = collect_steps(step_mother)
10
+ end
11
+
12
+ def visit_features(features)
13
+ print_summary
14
+ end
15
+
16
+ private
17
+
18
+ def print_summary
19
+ count = 0
20
+ @step_definition_files.keys.sort.each do |step_definition_file|
21
+ @io.puts step_definition_file
22
+
23
+ sources = @step_definition_files[step_definition_file]
24
+ source_indent = source_indent(sources)
25
+ sources.sort.each do |file_colon_line, regexp|
26
+ @io.print "#{regexp}".indent(2)
27
+ @io.print " # #{file_colon_line}".indent(source_indent - regexp.size)
28
+ @io.puts
29
+ end
30
+ @io.puts
31
+ count += sources.size
32
+ end
33
+ @io.puts "#{count} step definition(s) in #{@step_definition_files.size} source file(s)."
34
+ end
35
+
36
+ def collect_steps(step_mother)
37
+ step_mother.step_definitions.inject({}) do |step_definitions, step_definition|
38
+ step_definitions[step_definition.file] ||= []
39
+ step_definitions[step_definition.file] << [ step_definition.file_colon_line, step_definition.regexp.inspect ]
40
+ step_definitions
41
+ end
42
+ end
43
+
44
+ def source_indent(sources)
45
+ sources.map { |file_colon_line, regexp| regexp.size }.max + 1
46
+ end
47
+ end
48
+ end
49
+ end