cucumber 0.3.11 → 0.3.90

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 (164) hide show
  1. data/History.txt +101 -0
  2. data/Manifest.txt +14 -5
  3. data/config/hoe.rb +1 -2
  4. data/cucumber.yml +1 -0
  5. data/examples/i18n/ar/Rakefile +1 -1
  6. data/examples/i18n/ar/features/addition.feature +1 -0
  7. data/examples/i18n/bg/Rakefile +1 -1
  8. data/examples/i18n/bg/features/addition.feature +1 -0
  9. data/examples/i18n/bg/features/consecutive_calculations.feature +1 -0
  10. data/examples/i18n/bg/features/division.feature +1 -0
  11. data/examples/i18n/cat/Rakefile +1 -1
  12. data/examples/i18n/cat/features/suma.feature +1 -0
  13. data/examples/i18n/da/Rakefile +1 -1
  14. data/examples/i18n/da/features/summering.feature +1 -0
  15. data/examples/i18n/de/Rakefile +1 -1
  16. data/examples/i18n/de/features/addition.feature +1 -0
  17. data/examples/i18n/de/features/division.feature +1 -0
  18. data/examples/i18n/en-lol/features/stuffing.feature +1 -1
  19. data/examples/i18n/en/Rakefile +1 -1
  20. data/examples/i18n/en/features/addition.feature +1 -0
  21. data/examples/i18n/en/features/division.feature +1 -0
  22. data/examples/i18n/es/Rakefile +1 -1
  23. data/examples/i18n/es/features/adicion.feature +1 -0
  24. data/examples/i18n/et/Rakefile +1 -1
  25. data/examples/i18n/et/features/jagamine.feature +1 -0
  26. data/examples/i18n/et/features/liitmine.feature +1 -0
  27. data/examples/i18n/fi/Rakefile +1 -1
  28. data/examples/i18n/fi/features/jakolasku.feature +1 -0
  29. data/examples/i18n/fr/Rakefile +1 -1
  30. data/examples/i18n/fr/features/addition.feature +2 -1
  31. data/examples/i18n/he/Rakefile +1 -1
  32. data/examples/i18n/he/features/addition.feature +1 -0
  33. data/examples/i18n/he/features/division.feature +1 -0
  34. data/examples/i18n/hu/Rakefile +1 -1
  35. data/examples/i18n/hu/features/addition.feature +1 -0
  36. data/examples/i18n/hu/features/division.feature +1 -0
  37. data/examples/i18n/id/Rakefile +1 -1
  38. data/examples/i18n/id/features/addition.feature +1 -0
  39. data/examples/i18n/id/features/division.feature +1 -0
  40. data/examples/i18n/it/Rakefile +1 -1
  41. data/examples/i18n/it/features/somma.feature +1 -0
  42. data/examples/i18n/ja/Rakefile +1 -1
  43. data/examples/i18n/ja/features/addition.feature +1 -0
  44. data/examples/i18n/ja/features/division.feature +1 -0
  45. data/examples/i18n/ko/Rakefile +1 -1
  46. data/examples/i18n/ko/features/addition.feature +6 -5
  47. data/examples/i18n/ko/features/division.feature +1 -0
  48. data/examples/i18n/ko/features/step_definitons/calculator_steps.rb +1 -1
  49. data/examples/i18n/lt/Rakefile +1 -1
  50. data/examples/i18n/lt/features/addition.feature +1 -0
  51. data/examples/i18n/lt/features/division.feature +1 -0
  52. data/examples/i18n/lv/Rakefile +1 -1
  53. data/examples/i18n/lv/features/addition.feature +1 -0
  54. data/examples/i18n/lv/features/division.feature +1 -0
  55. data/examples/i18n/no/Rakefile +1 -1
  56. data/examples/i18n/no/features/step_definitons/kalkulator_steps.rb +1 -1
  57. data/examples/i18n/no/features/summering.feature +1 -0
  58. data/examples/i18n/pl/Rakefile +1 -1
  59. data/examples/i18n/pl/features/addition.feature +1 -0
  60. data/examples/i18n/pl/features/division.feature +1 -0
  61. data/examples/i18n/pt/Rakefile +1 -1
  62. data/examples/i18n/pt/features/adicao.feature +1 -0
  63. data/examples/i18n/ro/Rakefile +1 -1
  64. data/examples/i18n/ro/features/suma.feature +1 -0
  65. data/examples/i18n/ru/Rakefile +1 -1
  66. data/examples/i18n/ru/features/addition.feature +1 -0
  67. data/examples/i18n/ru/features/consecutive_calculations.feature +1 -0
  68. data/examples/i18n/ru/features/division.feature +1 -0
  69. data/examples/i18n/se/Rakefile +1 -1
  70. data/examples/i18n/se/features/summering.feature +1 -0
  71. data/examples/i18n/sk/Rakefile +1 -1
  72. data/examples/i18n/sk/features/addition.feature +1 -0
  73. data/examples/i18n/sk/features/division.feature +1 -0
  74. data/examples/i18n/zh-CN/features/addition.feature +1 -0
  75. data/examples/i18n/zh-TW/features/addition.feature +1 -0
  76. data/examples/i18n/zh-TW/features/division.feature +1 -0
  77. data/examples/self_test/features/support/env.rb +2 -1
  78. data/examples/sinatra/features/step_definitions/add_steps.rb +1 -1
  79. data/examples/sinatra/features/support/env.rb +13 -5
  80. data/examples/steps_library/features/step_definitions/steps_lib1.rb +8 -0
  81. data/examples/steps_library/features/step_definitions/steps_lib2.rb +8 -0
  82. data/examples/tickets/features/step_definitons/tickets_steps.rb +15 -0
  83. data/examples/tickets/features/table_diffing.feature +13 -0
  84. data/features/after_block_exceptions.feature +4 -1
  85. data/features/after_step_block_exceptions.feature +4 -1
  86. data/features/background.feature +6 -0
  87. data/features/bug_371.feature +32 -0
  88. data/features/cucumber_cli.feature +11 -1
  89. data/features/cucumber_cli_diff_disabled.feature +9 -2
  90. data/features/drb_server_integration.feature +28 -5
  91. data/features/expand.feature +2 -1
  92. data/features/html_formatter/a.html +129 -1614
  93. data/features/junit_formatter.feature +4 -4
  94. data/features/language_from_header.feature +30 -0
  95. data/features/rake_task.feature +28 -0
  96. data/features/step_definitions/cucumber_steps.rb +2 -2
  97. data/features/steps_formatter.feature +25 -0
  98. data/features/support/env.rb +13 -5
  99. data/features/table_diffing.feature +45 -0
  100. data/features/unicode_table.feature +35 -0
  101. data/features/work_in_progress.feature +3 -0
  102. data/gem_tasks/sass.rake +4 -0
  103. data/lib/cucumber.rb +0 -57
  104. data/lib/cucumber/ast/comment.rb +1 -1
  105. data/lib/cucumber/ast/feature.rb +2 -2
  106. data/lib/cucumber/ast/feature_element.rb +4 -0
  107. data/lib/cucumber/ast/outline_table.rb +2 -1
  108. data/lib/cucumber/ast/py_string.rb +0 -1
  109. data/lib/cucumber/ast/scenario.rb +5 -3
  110. data/lib/cucumber/ast/scenario_outline.rb +6 -1
  111. data/lib/cucumber/ast/step.rb +8 -1
  112. data/lib/cucumber/ast/step_invocation.rb +6 -1
  113. data/lib/cucumber/ast/table.rb +287 -49
  114. data/lib/cucumber/ast/visitor.rb +2 -1
  115. data/lib/cucumber/cli/configuration.rb +45 -28
  116. data/lib/cucumber/cli/drb_client.rb +8 -9
  117. data/lib/cucumber/cli/language_help_formatter.rb +9 -7
  118. data/lib/cucumber/cli/main.rb +8 -9
  119. data/lib/cucumber/feature_file.rb +53 -0
  120. data/lib/cucumber/filter.rb +50 -0
  121. data/lib/cucumber/formatter/console.rb +12 -0
  122. data/lib/cucumber/formatter/cucumber.css +106 -48
  123. data/lib/cucumber/formatter/cucumber.sass +121 -31
  124. data/lib/cucumber/formatter/html.rb +6 -5
  125. data/lib/cucumber/formatter/junit.rb +3 -6
  126. data/lib/cucumber/formatter/pretty.rb +22 -9
  127. data/lib/cucumber/formatter/profile.rb +1 -1
  128. data/lib/cucumber/formatter/progress.rb +1 -1
  129. data/lib/cucumber/formatter/steps.rb +49 -0
  130. data/lib/cucumber/languages.yml +3 -3
  131. data/lib/cucumber/parser.rb +1 -33
  132. data/lib/cucumber/parser/feature.rb +39 -16
  133. data/lib/cucumber/parser/feature.tt +1 -3
  134. data/lib/cucumber/parser/i18n.tt +30 -23
  135. data/lib/cucumber/parser/i18n/language.rb +83 -0
  136. data/lib/cucumber/parser/treetop_ext.rb +12 -83
  137. data/lib/cucumber/platform.rb +6 -0
  138. data/lib/cucumber/rake/task.rb +6 -0
  139. data/lib/cucumber/step_definition.rb +6 -0
  140. data/lib/cucumber/step_match.rb +1 -1
  141. data/lib/cucumber/step_mother.rb +3 -3
  142. data/lib/cucumber/version.rb +1 -1
  143. data/lib/cucumber/webrat/table_locator.rb +66 -0
  144. data/rails_generators/cucumber/templates/cucumber.rake +4 -0
  145. data/rails_generators/cucumber/templates/env.rb +1 -0
  146. data/rails_generators/cucumber/templates/spork_env.rb +1 -1
  147. data/rails_generators/cucumber/templates/webrat_steps.rb +17 -0
  148. data/rails_generators/feature/templates/feature.erb +1 -1
  149. data/rails_generators/feature/templates/steps.erb +2 -8
  150. data/spec/cucumber/ast/step_collection_spec.rb +5 -4
  151. data/spec/cucumber/ast/table_spec.rb +145 -0
  152. data/spec/cucumber/cli/configuration_spec.rb +55 -9
  153. data/spec/cucumber/cli/drb_client_spec.rb +5 -4
  154. data/spec/cucumber/cli/main_spec.rb +9 -12
  155. data/spec/cucumber/formatter/progress_spec.rb +2 -2
  156. data/spec/cucumber/parser/feature_parser_spec.rb +11 -9
  157. data/spec/cucumber/parser/table_parser_spec.rb +1 -1
  158. data/spec/spec_helper.rb +2 -1
  159. metadata +21 -20
  160. data/spec/cucumber/formatter/html/cucumber.css +0 -37
  161. data/spec/cucumber/formatter/html/cucumber.js +0 -13
  162. data/spec/cucumber/formatter/html/index.html +0 -45
  163. data/spec/cucumber/formatter/html/jquery-1.3.min.js +0 -19
  164. data/spec/cucumber/formatter/html/jquery.uitableedit.js +0 -100
@@ -64,6 +64,7 @@ module Cucumber
64
64
  end
65
65
 
66
66
  def visit_outline_table(outline_table)
67
+ @table = outline_table
67
68
  outline_table.accept(self)
68
69
  end
69
70
 
@@ -105,7 +106,7 @@ module Cucumber
105
106
  table_cell.accept(self)
106
107
  end
107
108
 
108
- def visit_table_cell_value(value, width, status)
109
+ def visit_table_cell_value(value, status)
109
110
  end
110
111
 
111
112
  def announce(announcement)
@@ -4,15 +4,16 @@ module Cucumber
4
4
 
5
5
  class Configuration
6
6
  BUILTIN_FORMATS = {
7
- 'html' => 'Cucumber::Formatter::Html',
8
- 'pretty' => 'Cucumber::Formatter::Pretty',
9
- 'profile' => 'Cucumber::Formatter::Profile',
10
- 'progress' => 'Cucumber::Formatter::Progress',
11
- 'rerun' => 'Cucumber::Formatter::Rerun',
12
- 'usage' => 'Cucumber::Formatter::Usage',
13
- 'junit' => 'Cucumber::Formatter::Junit'
7
+ 'html' => 'Cucumber::Formatter::Html',
8
+ 'pretty' => 'Cucumber::Formatter::Pretty',
9
+ 'profile' => 'Cucumber::Formatter::Profile',
10
+ 'progress' => 'Cucumber::Formatter::Progress',
11
+ 'rerun' => 'Cucumber::Formatter::Rerun',
12
+ 'usage' => 'Cucumber::Formatter::Usage',
13
+ 'junit' => 'Cucumber::Formatter::Junit',
14
+ 'tag_cloud' => 'Cucumber::Formatter::TagCloud',
15
+ 'steps' => 'Cucumber::Formatter::Steps'
14
16
  }
15
- DEFAULT_FORMAT = 'pretty'
16
17
  DRB_FLAG = '--drb'
17
18
  PROFILE_SHORT_FLAG = '-p'
18
19
  PROFILE_LONG_FLAG = '--profile'
@@ -26,15 +27,21 @@ module Cucumber
26
27
 
27
28
  @paths = []
28
29
  @options = default_options
29
-
30
- @active_format = DEFAULT_FORMAT
31
30
  end
32
31
 
33
32
  def parse!(args)
34
- @args = args.empty? ? args_from_profile('default') : args
33
+ args.concat(%w{--profile default}) if args.empty?
34
+ @args = args
35
35
  expand_profiles_into_args
36
36
  return if parse_drb
37
37
 
38
+ @args.each do |arg|
39
+ if arg =~ /^(\w+)=(.*)$/
40
+ ENV[$1] = $2
41
+ @args.delete(arg)
42
+ end
43
+ end
44
+
38
45
  @args.extend(::OptionParser::Arguable)
39
46
 
40
47
  @args.options do |opts|
@@ -69,7 +76,7 @@ module Cucumber
69
76
  end
70
77
  end
71
78
  opts.on("-f FORMAT", "--format FORMAT",
72
- "How to format features (Default: #{DEFAULT_FORMAT})",
79
+ "How to format features (Default: pretty)",
73
80
  "Available formats: #{BUILTIN_FORMATS.keys.sort.join(", ")}",
74
81
  "FORMAT can also be the fully qualified class name of",
75
82
  "your own custom formatter. If the class isn't loaded,",
@@ -79,7 +86,7 @@ module Cucumber
79
86
  "foo/bar_zap.rb. You can place the file with this relative",
80
87
  "path underneath your features/support directory or anywhere",
81
88
  "on Ruby's LOAD_PATH, for example in a Ruby gem.") do |v|
82
- @options[:formats][v] = @out_stream
89
+ @options[:formats] << [v, @out_stream]
83
90
  @active_format = v
84
91
  end
85
92
  opts.on("-o", "--out [FILE|DIR]",
@@ -87,14 +94,17 @@ module Cucumber
87
94
  "applies to the previously specified --format, or the",
88
95
  "default format if no format is specified. Check the specific",
89
96
  "formatter's docs to see whether to pass a file or a dir.") do |v|
90
- @options[:formats][@active_format] = v
97
+ @options[:formats] << ['pretty', nil] if @options[:formats].empty?
98
+ @options[:formats][-1][1] = v
91
99
  end
92
100
  opts.on("-t TAGS", "--tags TAGS",
93
101
  "Only execute the features or scenarios with the specified tags.",
94
102
  "TAGS must be comma-separated without spaces. Prefix tags with ~ to",
95
103
  "exclude features or scenarios having that tag. Tags can be specified",
96
104
  "with or without the @ prefix.") do |v|
97
- @options[:include_tags], @options[:exclude_tags] = *parse_tags(v)
105
+ include_tags, exclude_tags = *parse_tags(v)
106
+ @options[:include_tags] += include_tags
107
+ @options[:exclude_tags] += exclude_tags
98
108
  end
99
109
  opts.on("-n NAME", "--name NAME",
100
110
  "Only execute the feature elements which match part of the given name.",
@@ -176,7 +186,7 @@ module Cucumber
176
186
  end
177
187
  end.parse!
178
188
 
179
- @options[:formats]['pretty'] = @out_stream if @options[:formats].empty?
189
+ arrange_formats
180
190
 
181
191
  @options[:snippets] = true if !@quiet && @options[:snippets].nil?
182
192
  @options[:source] = true if !@quiet && @options[:source].nil?
@@ -211,14 +221,6 @@ module Cucumber
211
221
  @drb
212
222
  end
213
223
 
214
- def load_language
215
- if Cucumber.language_incomplete?(@options[:lang])
216
- list_keywords_and_exit(@options[:lang])
217
- else
218
- Cucumber.load_language(@options[:lang])
219
- end
220
- end
221
-
222
224
  def parse_tags(tag_string)
223
225
  tag_names = tag_string.split(",")
224
226
  excludes, includes = tag_names.partition{|tag| tag =~ /^~/}
@@ -232,7 +234,9 @@ module Cucumber
232
234
 
233
235
  def build_formatter_broadcaster(step_mother)
234
236
  return Formatter::Pretty.new(step_mother, nil, @options) if @options[:autoformat]
235
- formatters = @options[:formats].map do |format, out|
237
+ formatters = @options[:formats].map do |format_and_out|
238
+ format = format_and_out[0]
239
+ out = format_and_out[1]
236
240
  if String === out # file name
237
241
  unless File.directory?(out)
238
242
  out = File.open(out, Cucumber.file_mode('w'))
@@ -266,7 +270,7 @@ module Cucumber
266
270
  end
267
271
 
268
272
  def files_to_require
269
- requires = @options[:require] || feature_dirs
273
+ requires = @options[:require] || require_dirs
270
274
  files = requires.map do |path|
271
275
  path = path.gsub(/\\/, '/') # In case we're on windows. Globs don't work with backslashes.
272
276
  path = path.gsub(/\/$/, '') # Strip trailing slash.
@@ -292,6 +296,14 @@ module Cucumber
292
296
 
293
297
  protected
294
298
 
299
+ def arrange_formats
300
+ @options[:formats] << ['pretty', @out_stream] if @options[:formats].empty?
301
+ @options[:formats] = @options[:formats].sort_by{|f| f[1] == @out_stream ? -1 : 1}
302
+ if @options[:formats].length > 1 && @options[:formats][1][1] == @out_stream
303
+ raise "All but one formatter must use --out, only one can print to STDOUT"
304
+ end
305
+ end
306
+
295
307
  def remove_excluded_files_from(files)
296
308
  files.reject! {|path| @options[:excludes].detect {|pattern| path =~ pattern } }
297
309
  end
@@ -300,6 +312,10 @@ module Cucumber
300
312
  @paths.map { |f| File.directory?(f) ? f : File.dirname(f) }.uniq
301
313
  end
302
314
 
315
+ def require_dirs
316
+ feature_dirs+Dir['vendor/{gems,plugins}/*/cucumber']
317
+ end
318
+
303
319
  def constantize(camel_cased_word)
304
320
  begin
305
321
  names = camel_cased_word.split('::')
@@ -377,6 +393,7 @@ Defined profiles in cucumber.yml:
377
393
  return @cucumber_yml
378
394
  end
379
395
 
396
+ # TODO: Move to Language
380
397
  def list_keywords_and_exit(lang)
381
398
  unless Cucumber::LANGUAGES[lang]
382
399
  raise("No language with key #{lang}")
@@ -398,9 +415,9 @@ Defined profiles in cucumber.yml:
398
415
  {
399
416
  :strict => false,
400
417
  :require => nil,
401
- :lang => 'en',
418
+ :lang => nil,
402
419
  :dry_run => false,
403
- :formats => {},
420
+ :formats => [],
404
421
  :excludes => [],
405
422
  :include_tags => [],
406
423
  :exclude_tags => [],
@@ -3,18 +3,17 @@ require "drb/drb"
3
3
 
4
4
  module Cucumber
5
5
  module Cli
6
+ class DRbClientError < StandardError
7
+ end
6
8
  # Runs features on a DRB server, originally created with Spork compatibility in mind.
7
9
  class DRbClient
8
10
  def self.run(args, error_stream, out_stream)
9
- begin
10
- # See http://redmine.ruby-lang.org/issues/show/496 as to why we specify localhost:0
11
- DRb.start_service("druby://localhost:0")
12
- feature_server = DRbObject.new_with_uri("druby://127.0.0.1:8990")
13
- feature_server.run(args, error_stream, out_stream)
14
- true
15
- rescue DRb::DRbConnError
16
- false
17
- end
11
+ # See http://redmine.ruby-lang.org/issues/show/496 as to why we specify localhost:0
12
+ DRb.start_service("druby://localhost:0")
13
+ feature_server = DRbObject.new_with_uri("druby://127.0.0.1:8990")
14
+ feature_server.run(args, error_stream, out_stream)
15
+ rescue DRb::DRbConnError
16
+ raise DRbClientError, "No DRb server is running."
18
17
  end
19
18
  end
20
19
  end
@@ -1,4 +1,5 @@
1
1
  require 'cucumber/formatter/pretty'
2
+ require 'cucumber/parser/i18n/language'
2
3
 
3
4
  module Cucumber
4
5
  module Cli
@@ -18,15 +19,16 @@ http://wiki.github.com/aslakhellesoy/cucumber/spoken-languages
18
19
  [lang, Cucumber::LANGUAGES[lang]['name'], Cucumber::LANGUAGES[lang]['native']]
19
20
  end
20
21
  table = Ast::Table.new(raw)
21
- new(nil, io, {:check_lang=>true}, '').visit_multiline_arg(table)
22
+ new(nil, io, {:check_lang=>true}).visit_multiline_arg(table)
22
23
  end
23
24
 
24
25
  def self.list_keywords(io, lang)
25
- raw = Cucumber::KEYWORD_KEYS.map do |key|
26
- [key, Cucumber::LANGUAGES[lang][key]]
26
+ language = Parser::I18n::Language[lang]
27
+ raw = Parser::I18n::Language::KEYWORD_KEYS.map do |key|
28
+ [key, language.keywords(key)]
27
29
  end
28
30
  table = Ast::Table.new(raw)
29
- new(nil, io, {:incomplete => Cucumber.language_incomplete?(lang)}, '').visit_multiline_arg(table)
31
+ new(nil, io, {:incomplete => language.incomplete?}).visit_multiline_arg(table)
30
32
  end
31
33
 
32
34
  def visit_multiline_arg(table)
@@ -41,10 +43,10 @@ http://wiki.github.com/aslakhellesoy/cucumber/spoken-languages
41
43
  super
42
44
  end
43
45
 
44
- def visit_table_cell_value(value, width, status)
46
+ def visit_table_cell_value(value, status)
45
47
  if @col == 1
46
48
  if(@options[:check_lang])
47
- @incomplete = Cucumber.language_incomplete?(value)
49
+ @incomplete = Parser::I18n::Language[value].incomplete?
48
50
  end
49
51
  status = :comment
50
52
  elsif @incomplete
@@ -52,7 +54,7 @@ http://wiki.github.com/aslakhellesoy/cucumber/spoken-languages
52
54
  end
53
55
 
54
56
  @col += 1
55
- super(value, width, status)
57
+ super(value, status)
56
58
  end
57
59
  end
58
60
  end
@@ -2,6 +2,7 @@ require 'optparse'
2
2
  require 'cucumber'
3
3
  require 'ostruct'
4
4
  require 'cucumber/parser'
5
+ require 'cucumber/feature_file'
5
6
  require 'cucumber/formatter/color_io'
6
7
  require 'cucumber/cli/language_help_formatter'
7
8
  require 'cucumber/cli/configuration'
@@ -34,20 +35,18 @@ module Cucumber
34
35
 
35
36
  def execute!(step_mother)
36
37
  if configuration.drb?
37
- if DRbClient.run(@args, @error_stream, @out_stream)
38
- return false
39
- else
40
- @error_stream.puts "WARNING: No DRb server is running. Running features locally:"
38
+ begin
39
+ return DRbClient.run(@args, @error_stream, @out_stream)
40
+ rescue DRbClientError => e
41
+ @error_stream.puts "WARNING: #{e.message} Running features locally:"
41
42
  configuration.parse!(@args)
42
43
  end
43
44
  end
44
- configuration.load_language
45
45
  step_mother.options = configuration.options
46
46
 
47
+ features = load_plain_text_features
47
48
  require_files
48
49
  enable_diffing
49
-
50
- features = load_plain_text_features
51
50
 
52
51
  visitor = configuration.build_formatter_broadcaster(step_mother)
53
52
  step_mother.visitor = visitor # Needed to support World#announce
@@ -63,11 +62,11 @@ module Cucumber
63
62
 
64
63
  def load_plain_text_features
65
64
  features = Ast::Features.new
66
- parser = Parser::FeatureParser.new
67
65
 
68
66
  verbose_log("Features:")
69
67
  configuration.feature_files.each do |f|
70
- feature = parser.parse_file(f, configuration.options)
68
+ feature_file = FeatureFile.new(f)
69
+ feature = feature_file.parse(configuration.options)
71
70
  if feature
72
71
  features.add_feature(feature)
73
72
  verbose_log(" * #{f}")
@@ -0,0 +1,53 @@
1
+ require 'cucumber/parser/i18n/language'
2
+ require 'cucumber/filter'
3
+
4
+ module Cucumber
5
+ class FeatureFile
6
+ FILE_COLON_LINE_PATTERN = /^([\w\W]*?):([\d:]+)$/
7
+ LANGUAGE_PATTERN = /language:\s*(.*)/
8
+
9
+ # The +uri+ argument can ba a path or a path:line1:line2 etc.
10
+ def initialize(uri, source=nil)
11
+ @source = source
12
+ _, @path, @lines = *FILE_COLON_LINE_PATTERN.match(uri)
13
+ if @path
14
+ @lines = @lines.split(':').map { |line| line.to_i }
15
+ else
16
+ @path = uri
17
+ end
18
+ end
19
+
20
+ # Parses a file and returns a Cucumber::Ast
21
+ # If +options+ contains tags, the result will
22
+ # be filtered.
23
+ def parse(options={})
24
+ filter = Filter.new(@lines, options)
25
+ language = Parser::I18n::Language[lang || options[:lang] || 'en']
26
+ language.parse(source, @path, filter)
27
+ end
28
+
29
+ def source
30
+ @source ||= if @path =~ /^http/
31
+ require 'open-uri'
32
+ open(@path).read
33
+ else
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
41
+ end
42
+ end
43
+
44
+ def lang
45
+ line_one = source.split(/\n/)[0]
46
+ if line_one =~ LANGUAGE_PATTERN
47
+ $1.strip
48
+ else
49
+ nil
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,50 @@
1
+ module Cucumber
2
+ class Filter
3
+ def initialize(lines, options)
4
+ @lines = lines
5
+ @include_tags = options[:include_tags] || []
6
+ @exclude_tags = options[:exclude_tags] || []
7
+ @name_regexps = options[:name_regexps] || []
8
+ end
9
+
10
+ def accept?(syntax_node)
11
+ at_line?(syntax_node) &&
12
+ matches_tags?(syntax_node) &&
13
+ matches_names?(syntax_node)
14
+ end
15
+
16
+ def accept_example?(syntax_node, outline)
17
+ (at_line?(syntax_node) || outline_at_line?(outline)) &&
18
+ (matches_names?(syntax_node) || outline_matches_names?(outline))
19
+ end
20
+
21
+ def at_line?(syntax_node)
22
+ @lines.nil? || @lines.empty? || @lines.detect{|line| syntax_node.at_line?(line)}
23
+ end
24
+
25
+ def outline_at_line?(syntax_node)
26
+ @lines.nil? || @lines.empty? || @lines.detect{|line| syntax_node.outline_at_line?(line)}
27
+ end
28
+
29
+ def matches_tags?(syntax_node)
30
+ !excluded_by_tags?(syntax_node) &&
31
+ included_by_tags?(syntax_node)
32
+ end
33
+
34
+ def included_by_tags?(syntax_node)
35
+ @include_tags.empty? || syntax_node.has_all_tags?(@include_tags)
36
+ end
37
+
38
+ def excluded_by_tags?(syntax_node)
39
+ @exclude_tags.any? && syntax_node.has_tags?(@exclude_tags)
40
+ end
41
+
42
+ def outline_matches_names?(syntax_node)
43
+ @name_regexps.nil? || @name_regexps.empty? || @name_regexps.detect{|name_regexp| syntax_node.outline_matches_name?(name_regexp)}
44
+ end
45
+
46
+ def matches_names?(syntax_node)
47
+ @name_regexps.nil? || @name_regexps.empty? || @name_regexps.detect{|name_regexp| syntax_node.matches_name?(name_regexp)}
48
+ end
49
+ end
50
+ end
@@ -59,6 +59,18 @@ module Cucumber
59
59
  end
60
60
 
61
61
  def print_stats(features)
62
+
63
+ @failures = step_mother.scenarios(:failed).select { |s| s.is_a?(Cucumber::Ast::Scenario) }
64
+
65
+ if !@failures.empty?
66
+ @io.puts format_string("Failing Scenarios:", :failed)
67
+ @failures.each do |failure|
68
+ @io.puts format_string("cucumber " + failure.file_colon_line, :failed) +
69
+ format_string(" # Scenario: " + failure.name, :comment)
70
+ end
71
+ @io.puts
72
+ end
73
+
62
74
  @io.print dump_count(step_mother.scenarios.length, "scenario")
63
75
  print_status_counts{|status| step_mother.scenarios(status)}
64
76
 
@@ -1,53 +1,38 @@
1
+
2
+
1
3
  .cucumber {
2
- background: black;
3
- color: white;
4
+ font-family: "Lucida Grande", Helvetica, sans-serif;
5
+ font-size: 0.7em;
6
+ background: white;
4
7
  padding: 1em;
5
8
  }
6
- .cucumber .passed {
7
- color: #008800;
8
- }
9
- .cucumber .undefined {
10
- color: #888800;
9
+ .cucumber h1, .cucumber h2, .cucumber h3, .cucumber h4, .cucumber ol, .cucumber li, .cucumber pre, .cucumber p {
10
+ font-size: 1em;
11
+ padding: 0px;
12
+ margin: 0px;
11
13
  }
12
- .cucumber .pending {
13
- color: #888800;
14
+ .cucumber div.feature {
15
+ border: 1px solid;
16
+ padding: 2px;
17
+ margin: 4px;
14
18
  }
15
- .cucumber .failed {
16
- color: #880000;
19
+ .cucumber div.feature div.background, .cucumber div.feature div.scenario, .cucumber div.feature p {
20
+ padding: 0em 0em 0em 1em;
17
21
  }
18
- .cucumber .skipped {
19
- color: #008888;
20
- }
21
- .cucumber .outline {
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;
32
- }
33
- .cucumber .pending_param {
34
- font-weight: bold;
35
- color: #ffff00;
22
+ .cucumber div.feature div.background div.examples, .cucumber div.feature div.scenario div.examples, .cucumber div.feature p div.examples {
23
+ padding: 0em 0em 0em 1em;
36
24
  }
37
- .cucumber .failed_param {
38
- font-weight: bold;
39
- font-weight: bold;
40
- color: #ff0000;
25
+ .cucumber .stats {
26
+ margin: 2em;
41
27
  }
42
- .cucumber .skipped_param {
43
- font-weight: bold;
44
- color: #00ffff;
28
+ .cucumber .summary ul.features li {
29
+ display: inline;
45
30
  }
46
- .cucumber .outline_param {
47
- font-weight: bold;
48
- color: #00ffff;
31
+ .cucumber .backtrace {
32
+ margin-top: 0;
33
+ margin-bottom: 0;
34
+ margin-left: 1em;
49
35
  }
50
-
51
36
  .cucumber a {
52
37
  text-decoration: none;
53
38
  color: inherit;
@@ -58,17 +43,90 @@
58
43
  .cucumber a:visited {
59
44
  font-weight: normal;
60
45
  }
46
+ .cucumber a div.examples {
47
+ border: 1px solid;
48
+ padding: 2px;
49
+ margin: 4px;
50
+ }
51
+ .cucumber table {
52
+ border-collapse: collapse;
53
+ }
54
+ .cucumber table td, .cucumber table th {
55
+ font-size: 0.7em;
56
+ border: 1px solid #AAAAAA;
57
+ }
58
+ .cucumber table td.failed {
59
+ background: #FFC0CB;
60
+ color: #8B0000;
61
+ }
62
+ .cucumber table td.passed {
63
+ background: #98FB98;
64
+ color: #001111;
65
+ }
66
+ .cucumber table td.skipped {
67
+ background: #e0ffff;
68
+ color: #001111;
69
+ }
70
+ .cucumber table td.pending {
71
+ background: #FFFFE0;
72
+ color: #111100;
73
+ }
74
+ .cucumber table td.undefined {
75
+ background: #FFFFE0;
76
+ color: #111100;
77
+ }
61
78
  .cucumber ol {
62
79
  list-style: none;
63
80
  }
64
- .cucumber .stats {
65
- margin: 2em;
81
+ .cucumber ol li {
82
+ margin: 0em 0em 0em 1em;
83
+ padding: 0em 0em 0em 0.2em;
66
84
  }
67
- .cucumber .summary ul.features li {
68
- display: inline;
85
+ .cucumber ol li span.param {
86
+ font-weight: bold;
69
87
  }
70
- .cucumber .backtrace {
71
- margin-top: 0;
72
- margin-bottom: 0;
73
- margin-left: 1em;
88
+ .cucumber ol li.failed {
89
+ border-left: 5px solid #ff0000;
90
+ border-bottom: 1px solid #ff0000;
91
+ background: #ffc0cb;
92
+ color: #8b0000;
93
+ }
94
+ .cucumber ol li.failed span.param {
95
+ background: !failed_dark;
96
+ }
97
+ .cucumber ol li.passed {
98
+ border-left: 5px solid #00ff00;
99
+ border-bottom: 1px solid #00ff00;
100
+ background: #98fb98;
101
+ color: #001111;
102
+ }
103
+ .cucumber ol li.passed span.param {
104
+ background: #00ff00;
105
+ }
106
+ .cucumber ol li.skipped {
107
+ border-left: 5px solid #00ffff;
108
+ border-bottom: 1px solid #00ffff;
109
+ background: #e0ffff;
110
+ color: #001111;
111
+ }
112
+ .cucumber ol li.skipped span.param {
113
+ background: #00ffff;
114
+ }
115
+ .cucumber ol li.pending {
116
+ border-left: 5px solid #ff8000;
117
+ border-bottom: 1px solid #ff8000;
118
+ background: #ffff00;
119
+ color: #2a1b0a;
120
+ }
121
+ .cucumber ol li.pending span.param {
122
+ background: #ff8000;
123
+ }
124
+ .cucumber ol li.undefined {
125
+ border-left: 5px solid #ff8000;
126
+ border-bottom: 1px solid #ff8000;
127
+ background: #ffff00;
128
+ color: #2a1b0a;
129
+ }
130
+ .cucumber ol li.undefined span.param {
131
+ background: #ff8000;
74
132
  }