jeffrafter-cucumber 0.1.10
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +262 -0
- data/License.txt +20 -0
- data/Manifest.txt +241 -0
- data/README.txt +41 -0
- data/Rakefile +8 -0
- data/TODO.txt +26 -0
- data/bin/cucumber +6 -0
- data/config/hoe.rb +69 -0
- data/config/requirements.rb +15 -0
- data/cucumber.yml +1 -0
- data/examples/calculator_ruby_features/Rakefile +6 -0
- data/examples/calculator_ruby_features/features/addition.rb +23 -0
- data/examples/calculator_ruby_features/features/step_definitons/calculator_steps.rb +43 -0
- data/examples/cs/README.textile +22 -0
- data/examples/cs/Rakefile +12 -0
- data/examples/cs/features/hello.feature +11 -0
- data/examples/cs/features/step_definitons/hello_steps.rb +25 -0
- data/examples/cs/features/step_definitons/tree_steps.rb +14 -0
- data/examples/cs/features/tree.feature +9 -0
- data/examples/cs/src/Hello.cs +18 -0
- data/examples/dos_line_endings/Rakefile +6 -0
- data/examples/dos_line_endings/features/dos_line_endings.feature +9 -0
- data/examples/i18n/README.textile +18 -0
- data/examples/i18n/Rakefile +16 -0
- data/examples/i18n/ar/Rakefile +6 -0
- data/examples/i18n/ar/features/addition.feature +17 -0
- data/examples/i18n/ar/features/step_definitons/calculator_steps.rb +32 -0
- data/examples/i18n/ar/lib/calculator.rb +10 -0
- data/examples/i18n/da/Rakefile +6 -0
- data/examples/i18n/da/features/step_definitons/kalkulator_steps.rb +22 -0
- data/examples/i18n/da/features/summering.feature +17 -0
- data/examples/i18n/da/lib/kalkulator.rb +11 -0
- data/examples/i18n/de/Rakefile +6 -0
- data/examples/i18n/de/features/addition.feature +17 -0
- data/examples/i18n/de/features/division.feature +10 -0
- data/examples/i18n/de/features/step_definitons/calculator_steps.rb +30 -0
- data/examples/i18n/de/lib/calculator.rb +14 -0
- data/examples/i18n/en/Rakefile +6 -0
- data/examples/i18n/en/features/addition.feature +17 -0
- data/examples/i18n/en/features/division.feature +10 -0
- data/examples/i18n/en/features/step_definitons/calculator_steps.rb +31 -0
- data/examples/i18n/en/lib/calculator.rb +14 -0
- data/examples/i18n/es/Rakefile +6 -0
- data/examples/i18n/es/features/adicion.feature +17 -0
- data/examples/i18n/es/features/step_definitons/calculador_steps.rb +22 -0
- data/examples/i18n/es/lib/calculador.rb +11 -0
- data/examples/i18n/et/Rakefile +6 -0
- data/examples/i18n/et/features/liitmine.feature +17 -0
- data/examples/i18n/et/features/step_definitions/kalkulaator_steps.rb +26 -0
- data/examples/i18n/et/lib/kalkulaator.rb +10 -0
- data/examples/i18n/fr/Rakefile +6 -0
- data/examples/i18n/fr/features/addition.feature +13 -0
- data/examples/i18n/fr/features/step_definitions/calculatrice_steps.rb +22 -0
- data/examples/i18n/fr/lib/calculatrice.rb +10 -0
- data/examples/i18n/id/Rakefile +6 -0
- data/examples/i18n/id/features/addition.feature +17 -0
- data/examples/i18n/id/features/division.feature +10 -0
- data/examples/i18n/id/features/step_definitons/calculator_steps.rb +31 -0
- data/examples/i18n/id/lib/calculator.rb +14 -0
- data/examples/i18n/it/Rakefile +6 -0
- data/examples/i18n/it/features/somma.feature +10 -0
- data/examples/i18n/it/features/step_definitons/calcolatrice_steps.rb +22 -0
- data/examples/i18n/it/lib/calcolatrice.rb +11 -0
- data/examples/i18n/ja/README.txt +5 -0
- data/examples/i18n/ja/Rakefile +6 -0
- data/examples/i18n/ja/features/addition.feature +17 -0
- data/examples/i18n/ja/features/division.feature +10 -0
- data/examples/i18n/ja/features/step_definitons/calculator_steps.rb +30 -0
- data/examples/i18n/ja/lib/calculator.rb +14 -0
- data/examples/i18n/lt/Rakefile +6 -0
- data/examples/i18n/lt/features/addition.feature +17 -0
- data/examples/i18n/lt/features/division.feature +10 -0
- data/examples/i18n/lt/features/step_definitons/calculator_steps.rb +31 -0
- data/examples/i18n/lt/lib/calculator.rb +14 -0
- data/examples/i18n/no/Rakefile +6 -0
- data/examples/i18n/no/features/step_definitons/kalkulator_steps.rb +22 -0
- data/examples/i18n/no/features/summering.feature +17 -0
- data/examples/i18n/no/lib/kalkulator.rb +11 -0
- data/examples/i18n/pt/Rakefile +6 -0
- data/examples/i18n/pt/features/adicao.feature +10 -0
- data/examples/i18n/pt/features/step_definitions/calculadora_steps.rb +22 -0
- data/examples/i18n/pt/lib/calculadora.rb +10 -0
- data/examples/i18n/ro/Rakefile +6 -0
- data/examples/i18n/ro/features/step_definitons/calculator_steps.rb +22 -0
- data/examples/i18n/ro/features/suma.feature +10 -0
- data/examples/i18n/ro/lib/calculator.rb +11 -0
- data/examples/i18n/se/Rakefile +6 -0
- data/examples/i18n/se/features/step_definitons/kalkulator_steps.rb +22 -0
- data/examples/i18n/se/features/summering.feature +17 -0
- data/examples/i18n/se/lib/kalkulator.rb +11 -0
- data/examples/i18n/zh-CN/Rakefile +6 -0
- data/examples/i18n/zh-CN/features/addition.feature +17 -0
- data/examples/i18n/zh-CN/features/step_definitons/calculator_steps.rb +24 -0
- data/examples/i18n/zh-CN/lib/calculator.rb +10 -0
- data/examples/java/README.textile +22 -0
- data/examples/java/Rakefile +12 -0
- data/examples/java/features/hello.feature +11 -0
- data/examples/java/features/step_definitons/hello_steps.rb +25 -0
- data/examples/java/features/step_definitons/tree_steps.rb +14 -0
- data/examples/java/features/tree.feature +9 -0
- data/examples/java/src/cucumber/demo/Hello.java +16 -0
- data/examples/selenium/Rakefile +6 -0
- data/examples/selenium/features/search.feature +9 -0
- data/examples/selenium/features/step_definitons/stories_steps.rb +41 -0
- data/examples/test_unit/Rakefile +6 -0
- data/examples/test_unit/features/step_definitions/test_unit_steps.rb +26 -0
- data/examples/test_unit/features/test_unit.feature +9 -0
- data/examples/tickets/Rakefile +11 -0
- data/examples/tickets/cucumber.yml +2 -0
- data/examples/tickets/features/step_definitons/tickets_steps.rb +32 -0
- data/examples/tickets/features/tickets.feature +24 -0
- data/examples/watir/Rakefile +6 -0
- data/examples/watir/features/search.feature +9 -0
- data/examples/watir/features/step_definitons/stories_steps.rb +51 -0
- data/features/see_features.feature +8 -0
- data/features/steps/features_steps.rb +9 -0
- data/gem_tasks/deployment.rake +34 -0
- data/gem_tasks/environment.rake +7 -0
- data/gem_tasks/features.rake +6 -0
- data/gem_tasks/fix_cr_lf.rake +10 -0
- data/gem_tasks/flog.rake +4 -0
- data/gem_tasks/gemspec.rake +6 -0
- data/gem_tasks/rspec.rake +35 -0
- data/gem_tasks/treetop.rake +41 -0
- data/lib/autotest/cucumber.rb +6 -0
- data/lib/autotest/cucumber_mixin.rb +109 -0
- data/lib/autotest/cucumber_rails.rb +6 -0
- data/lib/autotest/cucumber_rails_rspec.rb +6 -0
- data/lib/autotest/cucumber_rspec.rb +6 -0
- data/lib/autotest/discover.rb +9 -0
- data/lib/cucumber/broadcaster.rb +20 -0
- data/lib/cucumber/cli.rb +303 -0
- data/lib/cucumber/core_ext/proc.rb +69 -0
- data/lib/cucumber/core_ext/string.rb +28 -0
- data/lib/cucumber/executor.rb +190 -0
- data/lib/cucumber/formatters/ansicolor.rb +109 -0
- data/lib/cucumber/formatters/autotest_formatter.rb +23 -0
- data/lib/cucumber/formatters/cucumber.css +132 -0
- data/lib/cucumber/formatters/cucumber.js +11 -0
- data/lib/cucumber/formatters/html_formatter.rb +128 -0
- data/lib/cucumber/formatters/jquery.js +32 -0
- data/lib/cucumber/formatters/pretty_formatter.rb +234 -0
- data/lib/cucumber/formatters/profile_formatter.rb +92 -0
- data/lib/cucumber/formatters/progress_formatter.rb +58 -0
- data/lib/cucumber/formatters.rb +1 -0
- data/lib/cucumber/languages.yml +258 -0
- data/lib/cucumber/model/table.rb +28 -0
- data/lib/cucumber/model.rb +1 -0
- data/lib/cucumber/platform.rb +12 -0
- data/lib/cucumber/rails/rspec.rb +12 -0
- data/lib/cucumber/rails/world.rb +73 -0
- data/lib/cucumber/rake/task.rb +101 -0
- data/lib/cucumber/step_methods.rb +49 -0
- data/lib/cucumber/step_mother.rb +95 -0
- data/lib/cucumber/tree/feature.rb +63 -0
- data/lib/cucumber/tree/features.rb +21 -0
- data/lib/cucumber/tree/given_scenario.rb +13 -0
- data/lib/cucumber/tree/scenario.rb +174 -0
- data/lib/cucumber/tree/step.rb +134 -0
- data/lib/cucumber/tree/table.rb +26 -0
- data/lib/cucumber/tree/top_down_visitor.rb +23 -0
- data/lib/cucumber/tree.rb +18 -0
- data/lib/cucumber/treetop_parser/feature.treetop.erb +206 -0
- data/lib/cucumber/treetop_parser/feature_ar.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_cy.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_da.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_de.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_en-tx.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_en.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_es.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_et.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_fr.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_id.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_it.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_ja.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_lt.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_nl.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_no.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_parser.rb +34 -0
- data/lib/cucumber/treetop_parser/feature_pl.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_pt.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_ro.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_ro2.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_ru.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_se.rb +1591 -0
- data/lib/cucumber/treetop_parser/feature_zh-CN.rb +1591 -0
- data/lib/cucumber/version.rb +9 -0
- data/lib/cucumber.rb +38 -0
- data/rails_generators/cucumber/USAGE +11 -0
- data/rails_generators/cucumber/cucumber_generator.rb +30 -0
- data/rails_generators/cucumber/templates/cucumber +7 -0
- data/rails_generators/cucumber/templates/cucumber.rake +7 -0
- data/rails_generators/cucumber/templates/env.rb +8 -0
- data/rails_generators/cucumber/templates/webrat_steps.rb +95 -0
- data/rails_generators/feature/USAGE +12 -0
- data/rails_generators/feature/feature_generator.rb +16 -0
- data/rails_generators/feature/templates/feature.erb +28 -0
- data/rails_generators/feature/templates/steps.erb +22 -0
- data/script/console +10 -0
- data/script/console.cmd +1 -0
- data/script/destroy +14 -0
- data/script/destroy.cmd +1 -0
- data/script/generate +14 -0
- data/script/generate.cmd +1 -0
- data/script/txt2html +74 -0
- data/script/txt2html.cmd +1 -0
- data/setup.rb +1585 -0
- data/spec/cucumber/broadcaster_spec.rb +27 -0
- data/spec/cucumber/cli_spec.rb +412 -0
- data/spec/cucumber/core_ext/proc_spec.rb +45 -0
- data/spec/cucumber/core_ext/string_spec.rb +34 -0
- data/spec/cucumber/executor_spec.rb +298 -0
- data/spec/cucumber/formatters/ansicolor_spec.rb +35 -0
- data/spec/cucumber/formatters/autotest_formatter_spec.rb +26 -0
- data/spec/cucumber/formatters/features.html +269 -0
- data/spec/cucumber/formatters/html_formatter_spec.rb +74 -0
- data/spec/cucumber/formatters/pretty_formatter_spec.rb +204 -0
- data/spec/cucumber/formatters/profile_formatter_spec.rb +192 -0
- data/spec/cucumber/formatters/progress_formatter_spec.rb +65 -0
- data/spec/cucumber/model/table_spec.rb +20 -0
- data/spec/cucumber/rails/stubs/mini_rails.rb +17 -0
- data/spec/cucumber/rails/stubs/test_help.rb +1 -0
- data/spec/cucumber/rails/world_spec.rb +11 -0
- data/spec/cucumber/sell_cucumbers.feature +19 -0
- data/spec/cucumber/step_mother_spec.rb +74 -0
- data/spec/cucumber/tree/feature_spec.rb +43 -0
- data/spec/cucumber/tree/row_scenario_spec.rb +55 -0
- data/spec/cucumber/tree/scenario_spec.rb +76 -0
- data/spec/cucumber/tree/step_spec.rb +50 -0
- data/spec/cucumber/treetop_parser/empty_feature.feature +4 -0
- data/spec/cucumber/treetop_parser/empty_scenario.feature +9 -0
- data/spec/cucumber/treetop_parser/feature_parser_spec.rb +98 -0
- data/spec/cucumber/treetop_parser/fit_scenario.feature +8 -0
- data/spec/cucumber/treetop_parser/given_scenario.feature +9 -0
- data/spec/cucumber/treetop_parser/multiline_steps.feature +17 -0
- data/spec/cucumber/treetop_parser/multiple_tables.feature +29 -0
- data/spec/cucumber/treetop_parser/spaces.feature +10 -0
- data/spec/cucumber/treetop_parser/test_dos.feature +25 -0
- data/spec/cucumber/treetop_parser/with_comments.feature +10 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +20 -0
- metadata +335 -0
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'autotest'
|
2
|
+
require 'tempfile'
|
3
|
+
|
4
|
+
module Autotest::CucumberMixin
|
5
|
+
def self.included(receiver)
|
6
|
+
receiver::ALL_HOOKS << [:run_features, :ran_features]
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_accessor :scenarios_to_run
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
super
|
13
|
+
reset_features
|
14
|
+
end
|
15
|
+
|
16
|
+
def run
|
17
|
+
hook :initialize
|
18
|
+
reset
|
19
|
+
reset_features
|
20
|
+
add_sigint_handler
|
21
|
+
|
22
|
+
self.last_mtime = Time.now if $f
|
23
|
+
|
24
|
+
loop do # ^c handler
|
25
|
+
begin
|
26
|
+
get_to_green
|
27
|
+
if self.tainted then
|
28
|
+
rerun_all_tests
|
29
|
+
rerun_all_features if all_good
|
30
|
+
else
|
31
|
+
hook :all_good
|
32
|
+
end
|
33
|
+
wait_for_changes
|
34
|
+
# Once tests and features are green, reset features every
|
35
|
+
# time a file is changed to see if anything breaks.
|
36
|
+
reset_features
|
37
|
+
rescue Interrupt
|
38
|
+
break if self.wants_to_quit
|
39
|
+
reset
|
40
|
+
reset_features
|
41
|
+
end
|
42
|
+
end
|
43
|
+
hook :quit
|
44
|
+
end
|
45
|
+
|
46
|
+
def all_features_good
|
47
|
+
scenarios_to_run == []
|
48
|
+
end
|
49
|
+
|
50
|
+
def get_to_green
|
51
|
+
begin
|
52
|
+
super
|
53
|
+
run_features
|
54
|
+
wait_for_changes unless all_features_good
|
55
|
+
end until all_features_good
|
56
|
+
end
|
57
|
+
|
58
|
+
def rerun_all_features
|
59
|
+
reset_features
|
60
|
+
run_features
|
61
|
+
end
|
62
|
+
|
63
|
+
def reset_features
|
64
|
+
self.scenarios_to_run = :all
|
65
|
+
end
|
66
|
+
|
67
|
+
def run_features
|
68
|
+
hook :run_features
|
69
|
+
Tempfile.open('autotest-cucumber') do |dirty_scenarios_file|
|
70
|
+
cmd = self.make_cucumber_cmd self.scenarios_to_run, dirty_scenarios_file.path
|
71
|
+
return if cmd.empty?
|
72
|
+
puts cmd unless $q
|
73
|
+
system cmd
|
74
|
+
self.scenarios_to_run = dirty_scenarios_file.readlines.map { |l| l.chomp }
|
75
|
+
self.tainted = true unless self.scenarios_to_run == []
|
76
|
+
end
|
77
|
+
hook :ran_features
|
78
|
+
end
|
79
|
+
|
80
|
+
def make_cucumber_cmd(scenarios_to_run, dirty_scenarios_filename)
|
81
|
+
return '' if scenarios_to_run == []
|
82
|
+
|
83
|
+
profiles = YAML.load_file("cucumber.yml").keys rescue []
|
84
|
+
|
85
|
+
profile ||= "autotest-all" if profiles.include?("autotest-all") and scenarios_to_run == :all
|
86
|
+
profile ||= "autotest" if profiles.include?("autotest")
|
87
|
+
profile ||= nil
|
88
|
+
|
89
|
+
if profile
|
90
|
+
args = ["--profile", profile]
|
91
|
+
else
|
92
|
+
args = %w{features --format} << (scenarios_to_run == :all ? "progress" : "pretty")
|
93
|
+
end
|
94
|
+
args += %w{--format autotest --out} << dirty_scenarios_filename
|
95
|
+
args = args.join(' ')
|
96
|
+
|
97
|
+
if scenarios_to_run == :all
|
98
|
+
scenario_args = nil
|
99
|
+
else
|
100
|
+
scenario_args = scenarios_to_run.map { |s| "-s '#{s}'" }.join(' ')
|
101
|
+
end
|
102
|
+
|
103
|
+
return "#{cucumber} #{args} #{scenario_args}"
|
104
|
+
end
|
105
|
+
|
106
|
+
def cucumber
|
107
|
+
File.exist?("script/cucumber") ? "script/cucumber" : "cucumber"
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Cucumber
|
2
|
+
class Broadcaster
|
3
|
+
|
4
|
+
def initialize(receivers = [])
|
5
|
+
@receivers = receivers
|
6
|
+
end
|
7
|
+
|
8
|
+
def register(receiver)
|
9
|
+
@receivers << receiver
|
10
|
+
end
|
11
|
+
|
12
|
+
def method_missing(method_name, *args)
|
13
|
+
@receivers.each do |receiver|
|
14
|
+
r = (receiver == STDOUT) ? Kernel: receiver # Needed to make colors work on Windows
|
15
|
+
r.__send__(method_name, *args) if receiver.respond_to?(method_name)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
data/lib/cucumber/cli.rb
ADDED
@@ -0,0 +1,303 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'cucumber'
|
3
|
+
|
4
|
+
module Cucumber
|
5
|
+
class CLI
|
6
|
+
class << self
|
7
|
+
attr_writer :step_mother, :executor, :features
|
8
|
+
|
9
|
+
def execute
|
10
|
+
@execute_called = true
|
11
|
+
parse(ARGV).execute!(@step_mother, @executor, @features)
|
12
|
+
end
|
13
|
+
|
14
|
+
def execute_called?
|
15
|
+
@execute_called
|
16
|
+
end
|
17
|
+
|
18
|
+
def parse(args)
|
19
|
+
cli = new
|
20
|
+
cli.parse_options!(args)
|
21
|
+
cli
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
attr_reader :options, :paths
|
26
|
+
FORMATS = %w{pretty profile progress html autotest}
|
27
|
+
DEFAULT_FORMAT = 'pretty'
|
28
|
+
|
29
|
+
def initialize(out_stream = STDOUT, error_stream = STDERR)
|
30
|
+
@out_stream = out_stream
|
31
|
+
@error_stream = error_stream
|
32
|
+
@paths = []
|
33
|
+
@options = {
|
34
|
+
:require => nil,
|
35
|
+
:lang => 'en',
|
36
|
+
:dry_run => false,
|
37
|
+
:source => true,
|
38
|
+
:snippets => true,
|
39
|
+
:formats => {},
|
40
|
+
:excludes => [],
|
41
|
+
:scenario_names => nil
|
42
|
+
}
|
43
|
+
@active_format = DEFAULT_FORMAT
|
44
|
+
end
|
45
|
+
|
46
|
+
def parse_options!(args)
|
47
|
+
return parse_args_from_profile('default') if args.empty?
|
48
|
+
args.extend(OptionParser::Arguable)
|
49
|
+
|
50
|
+
args.options do |opts|
|
51
|
+
opts.banner = "Usage: cucumber [options] FILES|DIRS"
|
52
|
+
opts.on("-r LIBRARY|DIR", "--require LIBRARY|DIR", "Require files before executing the features.",
|
53
|
+
"If this option is not specified, all *.rb files that",
|
54
|
+
"are siblings or below the features will be autorequired",
|
55
|
+
"This option can be specified multiple times.") do |v|
|
56
|
+
@options[:require] ||= []
|
57
|
+
@options[:require] << v
|
58
|
+
end
|
59
|
+
opts.on("-s SCENARIO", "--scenario SCENARIO", "Only execute the scenario with the given name.",
|
60
|
+
"If this option is given more than once, run all",
|
61
|
+
"the specified scenarios.") do |v|
|
62
|
+
@options[:scenario_names] ||= []
|
63
|
+
@options[:scenario_names] << v
|
64
|
+
end
|
65
|
+
opts.on("-a LANG", "--language LANG", "Specify language for features (Default: #{@options[:lang]})",
|
66
|
+
"Available languages: #{Cucumber.languages.join(", ")}",
|
67
|
+
"Look at #{Cucumber::LANGUAGE_FILE} for keywords") do |v|
|
68
|
+
@options[:lang] = v
|
69
|
+
end
|
70
|
+
opts.on("-f FORMAT", "--format FORMAT", "How to format features (Default: #{DEFAULT_FORMAT})",
|
71
|
+
"Available formats: #{FORMATS.join(", ")}",
|
72
|
+
"You can also provide your own formatter classes as long as they have been",
|
73
|
+
"previously required using --require or if they are in the folder",
|
74
|
+
"structure such that cucumber will require them automatically.",
|
75
|
+
"This option can be specified multiple times.") do |v|
|
76
|
+
|
77
|
+
@options[:formats][v] ||= []
|
78
|
+
@options[:formats][v] << @out_stream
|
79
|
+
@active_format = v
|
80
|
+
end
|
81
|
+
opts.on("-o", "--out FILE", "Write output to a file instead of @out_stream.",
|
82
|
+
"This option can be specified multiple times, and applies to the previously",
|
83
|
+
"specified --format.") do |v|
|
84
|
+
@options[:formats][@active_format] ||= []
|
85
|
+
if @options[:formats][@active_format].last == @out_stream
|
86
|
+
@options[:formats][@active_format][-1] = File.open(v, 'w')
|
87
|
+
else
|
88
|
+
@options[:formats][@active_format] << File.open(v, 'w')
|
89
|
+
end
|
90
|
+
end
|
91
|
+
opts.on("-c", "--[no-]color", "Use ANSI color in the output, if formatters use it. If",
|
92
|
+
"these options are given multiple times, the last one is",
|
93
|
+
"used. If neither --color or --no-color is given cucumber",
|
94
|
+
"decides based on your platform and the output destination") do |v|
|
95
|
+
@options[:color] = v
|
96
|
+
end
|
97
|
+
opts.on("-e", "--exclude PATTERN", "Don't run features matching a pattern") do |v|
|
98
|
+
@options[:excludes] << v
|
99
|
+
end
|
100
|
+
opts.on("-p", "--profile PROFILE", "Pull commandline arguments from cucumber.yml.") do |v|
|
101
|
+
parse_args_from_profile(v)
|
102
|
+
end
|
103
|
+
opts.on("-d", "--dry-run", "Invokes formatters without executing the steps.") do
|
104
|
+
@options[:dry_run] = true
|
105
|
+
end
|
106
|
+
opts.on("-n", "--no-source", "Don't show the file and line of the step definition with the steps.") do
|
107
|
+
@options[:source] = false
|
108
|
+
end
|
109
|
+
opts.on("-i", "--no-snippets", "Don't show the snippets for pending steps") do
|
110
|
+
@options[:snippets] = false
|
111
|
+
end
|
112
|
+
opts.on("-q", "--quiet", "Don't show any development aid information") do
|
113
|
+
@options[:snippets] = false
|
114
|
+
@options[:source] = false
|
115
|
+
end
|
116
|
+
opts.on("-v", "--verbose", "Show the files and features loaded") do
|
117
|
+
@options[:verbose] = true
|
118
|
+
end
|
119
|
+
opts.on_tail("--version", "Show version") do
|
120
|
+
@out_stream.puts VERSION::STRING
|
121
|
+
Kernel.exit
|
122
|
+
end
|
123
|
+
opts.on_tail("--help", "You're looking at it") do
|
124
|
+
@out_stream.puts opts.help
|
125
|
+
Kernel.exit
|
126
|
+
end
|
127
|
+
end.parse!
|
128
|
+
|
129
|
+
if @options[:formats].empty?
|
130
|
+
@options[:formats][DEFAULT_FORMAT] = [@out_stream]
|
131
|
+
end
|
132
|
+
|
133
|
+
# Whatever is left after option parsing is the FILE arguments
|
134
|
+
args = extract_and_store_line_numbers(args)
|
135
|
+
@paths += args
|
136
|
+
end
|
137
|
+
|
138
|
+
def parse_args_from_profile(profile)
|
139
|
+
unless File.exist?('cucumber.yml')
|
140
|
+
return exit_with_error("cucumber.yml was not found. Please define your '#{profile}' and other profiles in cucumber.yml.\n"+
|
141
|
+
"Type 'cucumber --help' for usage.\n")
|
142
|
+
end
|
143
|
+
|
144
|
+
require 'yaml'
|
145
|
+
cucumber_yml = YAML::load(IO.read('cucumber.yml'))
|
146
|
+
args_from_yml = cucumber_yml[profile]
|
147
|
+
if args_from_yml.nil?
|
148
|
+
exit_with_error <<-END_OF_ERROR
|
149
|
+
Could not find profile: '#{profile}'
|
150
|
+
|
151
|
+
Defined profiles in cucumber.yml:
|
152
|
+
* #{cucumber_yml.keys.join("\n * ")}
|
153
|
+
END_OF_ERROR
|
154
|
+
elsif !args_from_yml.is_a?(String)
|
155
|
+
exit_with_error "Profiles must be defined as a String. The '#{profile}' profile was #{args_from_yml.inspect} (#{args_from_yml.class}).\n"
|
156
|
+
else
|
157
|
+
parse_options!(args_from_yml.split(' '))
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def execute!(step_mother, executor, features)
|
162
|
+
Term::ANSIColor.coloring = @options[:color] unless @options[:color].nil?
|
163
|
+
Cucumber.load_language(@options[:lang])
|
164
|
+
require_files
|
165
|
+
executor.formatters = build_formatter_broadcaster(step_mother)
|
166
|
+
load_plain_text_features(features)
|
167
|
+
executor.lines_for_features = @options[:lines_for_features]
|
168
|
+
executor.scenario_names = @options[:scenario_names] if @options[:scenario_names]
|
169
|
+
executor.visit_features(features)
|
170
|
+
exit 1 if executor.failed
|
171
|
+
end
|
172
|
+
|
173
|
+
private
|
174
|
+
|
175
|
+
def extract_and_store_line_numbers(file_arguments)
|
176
|
+
@options[:lines_for_features] = Hash.new{|k,v| k[v] = []}
|
177
|
+
file_arguments.map do |arg|
|
178
|
+
_, file, lines = */^([\w\W]*?):([\d:]+)$/.match(arg)
|
179
|
+
unless file.nil?
|
180
|
+
@options[:lines_for_features][file] += lines.split(':').map { |line| line.to_i }
|
181
|
+
arg = file
|
182
|
+
end
|
183
|
+
arg
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
# Requires files - typically step files and ruby feature files.
|
188
|
+
def require_files
|
189
|
+
ARGV.clear # Shut up RSpec
|
190
|
+
require "cucumber/treetop_parser/feature_#{@options[:lang]}"
|
191
|
+
require "cucumber/treetop_parser/feature_parser"
|
192
|
+
|
193
|
+
verbose_log("Ruby files required:")
|
194
|
+
requires = @options[:require] || feature_dirs
|
195
|
+
libs = requires.map do |path|
|
196
|
+
path = path.gsub(/\\/, '/') # In case we're on windows. Globs don't work with backslashes.
|
197
|
+
File.directory?(path) ? Dir["#{path}/**/*.rb"] : path
|
198
|
+
end.flatten.uniq
|
199
|
+
libs.each do |lib|
|
200
|
+
begin
|
201
|
+
require lib
|
202
|
+
verbose_log(" * #{lib}")
|
203
|
+
rescue LoadError => e
|
204
|
+
e.message << "\nFailed to load #{lib}"
|
205
|
+
raise e
|
206
|
+
end
|
207
|
+
end
|
208
|
+
verbose_log("\n")
|
209
|
+
end
|
210
|
+
|
211
|
+
def feature_files
|
212
|
+
potential_feature_files = @paths.map do |path|
|
213
|
+
path = path.gsub(/\\/, '/') # In case we're on windows. Globs don't work with backslashes.
|
214
|
+
path = path.chomp('/')
|
215
|
+
File.directory?(path) ? Dir["#{path}/**/*.feature"] : path
|
216
|
+
end.flatten.uniq
|
217
|
+
|
218
|
+
@options[:excludes].each do |exclude|
|
219
|
+
potential_feature_files.reject! do |path|
|
220
|
+
path =~ /#{Regexp.escape(exclude)}/
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
potential_feature_files
|
225
|
+
end
|
226
|
+
|
227
|
+
def feature_dirs
|
228
|
+
feature_files.map{|f| File.directory?(f) ? f : File.dirname(f)}.uniq
|
229
|
+
end
|
230
|
+
|
231
|
+
def load_plain_text_features(features)
|
232
|
+
parser = TreetopParser::FeatureParser.new
|
233
|
+
|
234
|
+
verbose_log("Features:")
|
235
|
+
feature_files.each do |f|
|
236
|
+
features << parser.parse_feature(f)
|
237
|
+
verbose_log(" * #{f}")
|
238
|
+
end
|
239
|
+
verbose_log("\n"*2)
|
240
|
+
end
|
241
|
+
|
242
|
+
def build_formatter_broadcaster(step_mother)
|
243
|
+
formatter_broadcaster = Broadcaster.new
|
244
|
+
@options[:formats].each do |format, output_list|
|
245
|
+
output_broadcaster = build_output_broadcaster(output_list)
|
246
|
+
case format
|
247
|
+
when 'pretty'
|
248
|
+
formatter_broadcaster.register(Formatters::PrettyFormatter.new(output_broadcaster, step_mother, @options))
|
249
|
+
when 'progress'
|
250
|
+
formatter_broadcaster.register(Formatters::ProgressFormatter.new(output_broadcaster))
|
251
|
+
when 'profile'
|
252
|
+
formatter_broadcaster.register(Formatters::ProfileFormatter.new(output_broadcaster, step_mother))
|
253
|
+
when 'html'
|
254
|
+
formatter_broadcaster.register(Formatters::HtmlFormatter.new(output_broadcaster, step_mother))
|
255
|
+
when 'autotest'
|
256
|
+
formatter_broadcaster.register(Formatters::AutotestFormatter.new(output_broadcaster))
|
257
|
+
else
|
258
|
+
begin
|
259
|
+
formatter_class = Kernel.const_get(format)
|
260
|
+
formatter_broadcaster.register(formatter_class.new(output_broadcaster, step_mother, @options))
|
261
|
+
rescue NameError => e
|
262
|
+
@error_stream.puts "Invalid format: #{format}\n"
|
263
|
+
exit_with_help
|
264
|
+
rescue Exception => e
|
265
|
+
exit_with_error("Error creating formatter: #{format}\n#{e}")
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
formatter_broadcaster
|
270
|
+
end
|
271
|
+
|
272
|
+
def build_output_broadcaster(output_list)
|
273
|
+
output_broadcaster = Broadcaster.new
|
274
|
+
output_list.each do |output|
|
275
|
+
output_broadcaster.register(output)
|
276
|
+
end
|
277
|
+
output_broadcaster
|
278
|
+
end
|
279
|
+
|
280
|
+
private
|
281
|
+
|
282
|
+
def verbose_log(string)
|
283
|
+
@out_stream.puts(string) if @options[:verbose]
|
284
|
+
end
|
285
|
+
|
286
|
+
def exit_with_help
|
287
|
+
parse_options!(%w{--help})
|
288
|
+
end
|
289
|
+
|
290
|
+
def exit_with_error(error_message)
|
291
|
+
@error_stream << error_message
|
292
|
+
Kernel.exit 1
|
293
|
+
end
|
294
|
+
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
extend Cucumber::StepMethods
|
299
|
+
Cucumber::CLI.step_mother = step_mother
|
300
|
+
Cucumber::CLI.executor = executor
|
301
|
+
|
302
|
+
extend Cucumber::Tree
|
303
|
+
Cucumber::CLI.features = features
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Cucumber
|
2
|
+
class ArityMismatchError < StandardError
|
3
|
+
end
|
4
|
+
|
5
|
+
module CoreExt
|
6
|
+
# Proc extension that allows a proc to be called in the context of any object.
|
7
|
+
# Also makes it possible to tack a name onto a Proc.
|
8
|
+
module CallIn
|
9
|
+
PROC_PATTERN = /[\d\w]+@(.*):(.*)>/
|
10
|
+
|
11
|
+
if Proc.new{}.to_s =~ PROC_PATTERN
|
12
|
+
def to_backtrace_line
|
13
|
+
"#{file_colon_line}:in `#{name}'"
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_comment_line
|
17
|
+
"# #{file_colon_line}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def file_colon_line
|
21
|
+
path, line = *to_s.match(PROC_PATTERN)[1..2]
|
22
|
+
path = File.expand_path(path)
|
23
|
+
pwd = Dir.pwd
|
24
|
+
path = path[pwd.length+1..-1]
|
25
|
+
"#{path}:#{line}"
|
26
|
+
end
|
27
|
+
else
|
28
|
+
# This Ruby implementation doesn't implement Proc#to_s correctly
|
29
|
+
STDERR.puts "*** THIS RUBY IMPLEMENTATION DOESN'T REPORT FILE AND LINE FOR PROCS ***"
|
30
|
+
|
31
|
+
def to_backtrace_line
|
32
|
+
nil
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_comment_line
|
36
|
+
""
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
attr_accessor :name
|
41
|
+
|
42
|
+
def call_in(obj, *args)
|
43
|
+
obj.extend(mod)
|
44
|
+
if self != StepMother::PENDING && args.length != arity2
|
45
|
+
# We have to manually raise when the block has arity -1 (no pipes)
|
46
|
+
raise ArityMismatchError.new("expected #{arity2} block argument(s), got #{args.length}")
|
47
|
+
else
|
48
|
+
obj.__send__(meth, *args)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def arity2
|
53
|
+
arity == -1 ? 0 : arity
|
54
|
+
end
|
55
|
+
|
56
|
+
def meth
|
57
|
+
@meth ||= "__cucumber_#{object_id}"
|
58
|
+
end
|
59
|
+
|
60
|
+
def mod
|
61
|
+
p = self
|
62
|
+
m = meth
|
63
|
+
@mod ||= Module.new do
|
64
|
+
define_method(m, &p)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class String
|
2
|
+
def gzub(regexp, format=nil, &proc)
|
3
|
+
md = match(regexp)
|
4
|
+
raise "#{self.inspect} doesn't match #{regexp.inspect}" if md.nil?
|
5
|
+
|
6
|
+
s = dup
|
7
|
+
pos = 0
|
8
|
+
md.captures.each_with_index do |m, n|
|
9
|
+
replacement = if block_given?
|
10
|
+
proc.call(m)
|
11
|
+
else
|
12
|
+
format % m
|
13
|
+
end
|
14
|
+
|
15
|
+
if md.offset(n+1)[0]
|
16
|
+
s[md.offset(n+1)[0] + pos, m.length] = replacement
|
17
|
+
pos += replacement.length - m.length
|
18
|
+
end
|
19
|
+
end
|
20
|
+
s
|
21
|
+
end
|
22
|
+
|
23
|
+
if ENV['CUCUMBER_NO_JCODE']
|
24
|
+
alias jlength length
|
25
|
+
else
|
26
|
+
require 'jcode'
|
27
|
+
end
|
28
|
+
end
|