cucumber 0.3.11 → 0.3.90
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +101 -0
- data/Manifest.txt +14 -5
- data/config/hoe.rb +1 -2
- data/cucumber.yml +1 -0
- data/examples/i18n/ar/Rakefile +1 -1
- data/examples/i18n/ar/features/addition.feature +1 -0
- data/examples/i18n/bg/Rakefile +1 -1
- data/examples/i18n/bg/features/addition.feature +1 -0
- data/examples/i18n/bg/features/consecutive_calculations.feature +1 -0
- data/examples/i18n/bg/features/division.feature +1 -0
- data/examples/i18n/cat/Rakefile +1 -1
- data/examples/i18n/cat/features/suma.feature +1 -0
- data/examples/i18n/da/Rakefile +1 -1
- data/examples/i18n/da/features/summering.feature +1 -0
- data/examples/i18n/de/Rakefile +1 -1
- data/examples/i18n/de/features/addition.feature +1 -0
- data/examples/i18n/de/features/division.feature +1 -0
- data/examples/i18n/en-lol/features/stuffing.feature +1 -1
- data/examples/i18n/en/Rakefile +1 -1
- data/examples/i18n/en/features/addition.feature +1 -0
- data/examples/i18n/en/features/division.feature +1 -0
- data/examples/i18n/es/Rakefile +1 -1
- data/examples/i18n/es/features/adicion.feature +1 -0
- data/examples/i18n/et/Rakefile +1 -1
- data/examples/i18n/et/features/jagamine.feature +1 -0
- data/examples/i18n/et/features/liitmine.feature +1 -0
- data/examples/i18n/fi/Rakefile +1 -1
- data/examples/i18n/fi/features/jakolasku.feature +1 -0
- data/examples/i18n/fr/Rakefile +1 -1
- data/examples/i18n/fr/features/addition.feature +2 -1
- data/examples/i18n/he/Rakefile +1 -1
- data/examples/i18n/he/features/addition.feature +1 -0
- data/examples/i18n/he/features/division.feature +1 -0
- data/examples/i18n/hu/Rakefile +1 -1
- data/examples/i18n/hu/features/addition.feature +1 -0
- data/examples/i18n/hu/features/division.feature +1 -0
- data/examples/i18n/id/Rakefile +1 -1
- data/examples/i18n/id/features/addition.feature +1 -0
- data/examples/i18n/id/features/division.feature +1 -0
- data/examples/i18n/it/Rakefile +1 -1
- data/examples/i18n/it/features/somma.feature +1 -0
- data/examples/i18n/ja/Rakefile +1 -1
- data/examples/i18n/ja/features/addition.feature +1 -0
- data/examples/i18n/ja/features/division.feature +1 -0
- data/examples/i18n/ko/Rakefile +1 -1
- data/examples/i18n/ko/features/addition.feature +6 -5
- data/examples/i18n/ko/features/division.feature +1 -0
- data/examples/i18n/ko/features/step_definitons/calculator_steps.rb +1 -1
- data/examples/i18n/lt/Rakefile +1 -1
- data/examples/i18n/lt/features/addition.feature +1 -0
- data/examples/i18n/lt/features/division.feature +1 -0
- data/examples/i18n/lv/Rakefile +1 -1
- data/examples/i18n/lv/features/addition.feature +1 -0
- data/examples/i18n/lv/features/division.feature +1 -0
- data/examples/i18n/no/Rakefile +1 -1
- data/examples/i18n/no/features/step_definitons/kalkulator_steps.rb +1 -1
- data/examples/i18n/no/features/summering.feature +1 -0
- data/examples/i18n/pl/Rakefile +1 -1
- data/examples/i18n/pl/features/addition.feature +1 -0
- data/examples/i18n/pl/features/division.feature +1 -0
- data/examples/i18n/pt/Rakefile +1 -1
- data/examples/i18n/pt/features/adicao.feature +1 -0
- data/examples/i18n/ro/Rakefile +1 -1
- data/examples/i18n/ro/features/suma.feature +1 -0
- data/examples/i18n/ru/Rakefile +1 -1
- data/examples/i18n/ru/features/addition.feature +1 -0
- data/examples/i18n/ru/features/consecutive_calculations.feature +1 -0
- data/examples/i18n/ru/features/division.feature +1 -0
- data/examples/i18n/se/Rakefile +1 -1
- data/examples/i18n/se/features/summering.feature +1 -0
- data/examples/i18n/sk/Rakefile +1 -1
- data/examples/i18n/sk/features/addition.feature +1 -0
- data/examples/i18n/sk/features/division.feature +1 -0
- data/examples/i18n/zh-CN/features/addition.feature +1 -0
- data/examples/i18n/zh-TW/features/addition.feature +1 -0
- data/examples/i18n/zh-TW/features/division.feature +1 -0
- data/examples/self_test/features/support/env.rb +2 -1
- data/examples/sinatra/features/step_definitions/add_steps.rb +1 -1
- data/examples/sinatra/features/support/env.rb +13 -5
- data/examples/steps_library/features/step_definitions/steps_lib1.rb +8 -0
- data/examples/steps_library/features/step_definitions/steps_lib2.rb +8 -0
- data/examples/tickets/features/step_definitons/tickets_steps.rb +15 -0
- data/examples/tickets/features/table_diffing.feature +13 -0
- data/features/after_block_exceptions.feature +4 -1
- data/features/after_step_block_exceptions.feature +4 -1
- data/features/background.feature +6 -0
- data/features/bug_371.feature +32 -0
- data/features/cucumber_cli.feature +11 -1
- data/features/cucumber_cli_diff_disabled.feature +9 -2
- data/features/drb_server_integration.feature +28 -5
- data/features/expand.feature +2 -1
- data/features/html_formatter/a.html +129 -1614
- data/features/junit_formatter.feature +4 -4
- data/features/language_from_header.feature +30 -0
- data/features/rake_task.feature +28 -0
- data/features/step_definitions/cucumber_steps.rb +2 -2
- data/features/steps_formatter.feature +25 -0
- data/features/support/env.rb +13 -5
- data/features/table_diffing.feature +45 -0
- data/features/unicode_table.feature +35 -0
- data/features/work_in_progress.feature +3 -0
- data/gem_tasks/sass.rake +4 -0
- data/lib/cucumber.rb +0 -57
- data/lib/cucumber/ast/comment.rb +1 -1
- data/lib/cucumber/ast/feature.rb +2 -2
- data/lib/cucumber/ast/feature_element.rb +4 -0
- data/lib/cucumber/ast/outline_table.rb +2 -1
- data/lib/cucumber/ast/py_string.rb +0 -1
- data/lib/cucumber/ast/scenario.rb +5 -3
- data/lib/cucumber/ast/scenario_outline.rb +6 -1
- data/lib/cucumber/ast/step.rb +8 -1
- data/lib/cucumber/ast/step_invocation.rb +6 -1
- data/lib/cucumber/ast/table.rb +287 -49
- data/lib/cucumber/ast/visitor.rb +2 -1
- data/lib/cucumber/cli/configuration.rb +45 -28
- data/lib/cucumber/cli/drb_client.rb +8 -9
- data/lib/cucumber/cli/language_help_formatter.rb +9 -7
- data/lib/cucumber/cli/main.rb +8 -9
- data/lib/cucumber/feature_file.rb +53 -0
- data/lib/cucumber/filter.rb +50 -0
- data/lib/cucumber/formatter/console.rb +12 -0
- data/lib/cucumber/formatter/cucumber.css +106 -48
- data/lib/cucumber/formatter/cucumber.sass +121 -31
- data/lib/cucumber/formatter/html.rb +6 -5
- data/lib/cucumber/formatter/junit.rb +3 -6
- data/lib/cucumber/formatter/pretty.rb +22 -9
- data/lib/cucumber/formatter/profile.rb +1 -1
- data/lib/cucumber/formatter/progress.rb +1 -1
- data/lib/cucumber/formatter/steps.rb +49 -0
- data/lib/cucumber/languages.yml +3 -3
- data/lib/cucumber/parser.rb +1 -33
- data/lib/cucumber/parser/feature.rb +39 -16
- data/lib/cucumber/parser/feature.tt +1 -3
- data/lib/cucumber/parser/i18n.tt +30 -23
- data/lib/cucumber/parser/i18n/language.rb +83 -0
- data/lib/cucumber/parser/treetop_ext.rb +12 -83
- data/lib/cucumber/platform.rb +6 -0
- data/lib/cucumber/rake/task.rb +6 -0
- data/lib/cucumber/step_definition.rb +6 -0
- data/lib/cucumber/step_match.rb +1 -1
- data/lib/cucumber/step_mother.rb +3 -3
- data/lib/cucumber/version.rb +1 -1
- data/lib/cucumber/webrat/table_locator.rb +66 -0
- data/rails_generators/cucumber/templates/cucumber.rake +4 -0
- data/rails_generators/cucumber/templates/env.rb +1 -0
- data/rails_generators/cucumber/templates/spork_env.rb +1 -1
- data/rails_generators/cucumber/templates/webrat_steps.rb +17 -0
- data/rails_generators/feature/templates/feature.erb +1 -1
- data/rails_generators/feature/templates/steps.erb +2 -8
- data/spec/cucumber/ast/step_collection_spec.rb +5 -4
- data/spec/cucumber/ast/table_spec.rb +145 -0
- data/spec/cucumber/cli/configuration_spec.rb +55 -9
- data/spec/cucumber/cli/drb_client_spec.rb +5 -4
- data/spec/cucumber/cli/main_spec.rb +9 -12
- data/spec/cucumber/formatter/progress_spec.rb +2 -2
- data/spec/cucumber/parser/feature_parser_spec.rb +11 -9
- data/spec/cucumber/parser/table_parser_spec.rb +1 -1
- data/spec/spec_helper.rb +2 -1
- metadata +21 -20
- data/spec/cucumber/formatter/html/cucumber.css +0 -37
- data/spec/cucumber/formatter/html/cucumber.js +0 -13
- data/spec/cucumber/formatter/html/index.html +0 -45
- data/spec/cucumber/formatter/html/jquery-1.3.min.js +0 -19
- data/spec/cucumber/formatter/html/jquery.uitableedit.js +0 -100
data/lib/cucumber/ast/visitor.rb
CHANGED
@@ -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,
|
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'
|
8
|
-
'pretty'
|
9
|
-
'profile'
|
10
|
-
'progress'
|
11
|
-
'rerun'
|
12
|
-
'usage'
|
13
|
-
'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
|
-
|
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:
|
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
|
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][
|
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
|
-
|
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
|
-
|
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 |
|
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] ||
|
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 =>
|
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
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
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}
|
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
|
-
|
26
|
-
|
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 =>
|
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,
|
46
|
+
def visit_table_cell_value(value, status)
|
45
47
|
if @col == 1
|
46
48
|
if(@options[:check_lang])
|
47
|
-
@incomplete =
|
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,
|
57
|
+
super(value, status)
|
56
58
|
end
|
57
59
|
end
|
58
60
|
end
|
data/lib/cucumber/cli/main.rb
CHANGED
@@ -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
|
-
|
38
|
-
return
|
39
|
-
|
40
|
-
@error_stream.puts "WARNING:
|
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
|
-
|
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
|
-
|
3
|
-
|
4
|
+
font-family: "Lucida Grande", Helvetica, sans-serif;
|
5
|
+
font-size: 0.7em;
|
6
|
+
background: white;
|
4
7
|
padding: 1em;
|
5
8
|
}
|
6
|
-
.cucumber .
|
7
|
-
|
8
|
-
|
9
|
-
|
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 .
|
13
|
-
|
14
|
+
.cucumber div.feature {
|
15
|
+
border: 1px solid;
|
16
|
+
padding: 2px;
|
17
|
+
margin: 4px;
|
14
18
|
}
|
15
|
-
.cucumber .
|
16
|
-
|
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 .
|
19
|
-
|
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 .
|
38
|
-
|
39
|
-
font-weight: bold;
|
40
|
-
color: #ff0000;
|
25
|
+
.cucumber .stats {
|
26
|
+
margin: 2em;
|
41
27
|
}
|
42
|
-
.cucumber .
|
43
|
-
|
44
|
-
color: #00ffff;
|
28
|
+
.cucumber .summary ul.features li {
|
29
|
+
display: inline;
|
45
30
|
}
|
46
|
-
.cucumber .
|
47
|
-
|
48
|
-
|
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
|
65
|
-
margin:
|
81
|
+
.cucumber ol li {
|
82
|
+
margin: 0em 0em 0em 1em;
|
83
|
+
padding: 0em 0em 0em 0.2em;
|
66
84
|
}
|
67
|
-
.cucumber
|
68
|
-
|
85
|
+
.cucumber ol li span.param {
|
86
|
+
font-weight: bold;
|
69
87
|
}
|
70
|
-
.cucumber .
|
71
|
-
|
72
|
-
|
73
|
-
|
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
|
}
|