jeffrafter-cucumber 0.1.10
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 +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
|