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.
- 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
|
}
|