cucumber 0.3.11 → 0.3.90

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