square-cucumber 0.3.12.2 → 0.3.93.1

Sign up to get free protection for your applications and to get access to all the features.
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