cucumber 0.3.93 → 0.3.94
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +67 -38
- data/Manifest.txt +8 -0
- data/Rakefile +1 -1
- data/cucumber.yml +2 -2
- data/examples/python/features/fibonacci.feature +19 -0
- data/examples/python/features/step_definitions/fib_steps.rb +7 -0
- data/examples/python/features/support/env.rb +21 -0
- data/examples/python/lib/fib.py +7 -0
- data/examples/self_test/features/tags_sample.feature +17 -0
- data/examples/sinatra/README.textile +13 -0
- data/features/cucumber_cli.feature +85 -3
- data/features/custom_formatter.feature +2 -2
- data/features/html_formatter/a.html +1 -1
- data/features/junit_formatter.feature +19 -12
- data/features/step_definitions/cucumber_steps.rb +8 -15
- data/features/support/env.rb +4 -5
- data/gem_tasks/contributors.rake +4 -0
- data/lib/cucumber/ast/feature.rb +13 -0
- data/lib/cucumber/ast/feature_element.rb +8 -4
- data/lib/cucumber/ast/features.rb +6 -1
- data/lib/cucumber/ast/table.rb +13 -6
- data/lib/cucumber/ast/tags.rb +9 -1
- data/lib/cucumber/cli/configuration.rb +3 -15
- data/lib/cucumber/cli/main.rb +25 -8
- data/lib/cucumber/cli/options.rb +53 -31
- data/lib/cucumber/filter.rb +4 -3
- data/lib/cucumber/formatter/ansicolor.rb +42 -9
- data/lib/cucumber/formatter/console.rb +38 -6
- data/lib/cucumber/formatter/html.rb +2 -8
- data/lib/cucumber/formatter/junit.rb +65 -24
- data/lib/cucumber/formatter/ordered_xml_markup.rb +24 -0
- data/lib/cucumber/formatter/pretty.rb +9 -4
- data/lib/cucumber/formatter/progress.rb +7 -1
- data/lib/cucumber/rake/task.rb +3 -3
- data/lib/cucumber/step_mother.rb +3 -1
- data/lib/cucumber/version.rb +1 -1
- data/rails_generators/cucumber/templates/cucumber.rake +18 -6
- data/spec/cucumber/ast/scenario_outline_spec.rb +2 -2
- data/spec/cucumber/ast/table_spec.rb +5 -0
- data/spec/cucumber/cli/configuration_spec.rb +2 -1
- data/spec/cucumber/cli/options_spec.rb +11 -6
- metadata +10 -2
@@ -4,8 +4,8 @@ Feature: Custom Formatter
|
|
4
4
|
When I run cucumber --format Cucumber::Formatter::TagCloud features
|
5
5
|
Then it should fail with
|
6
6
|
"""
|
7
|
-
| after_file | background_tagged_before_on_outline | four | lots | one | three | two |
|
8
|
-
| 1 | 1 | 1 | 1 | 1 | 2 | 1 |
|
7
|
+
| after_file | background_tagged_before_on_outline | four | lots | one | sample_four | sample_one | sample_three | sample_two | three | two |
|
8
|
+
| 1 | 1 | 1 | 1 | 1 | 2 | 1 | 2 | 1 | 2 | 1 |
|
9
9
|
|
10
10
|
"""
|
11
11
|
|
@@ -178,6 +178,6 @@ features/search_sample.feature:10:in `Given failing without a table'</pre></li><
|
|
178
178
|
features/search_sample.feature:13:in `Given <state> without a table'</pre></td></tr></table></div></div><div class="scenario outline"><h3><span class="keyword">Scenario Outline:</span> <span class="val">Hantu Pisang match</span></h3><ol><li class="step skipped" id="features_search_sample_feature_19"><div><span class="keyword">Given</span> <span class="step val"><state> without a table</span></div></li></ol><div class="examples"><h4><span class="keyword">Examples:</span> <span class="val"></span></h4><table><tr id="row_21"><th class="val skipped_param" id="row_21_0">state</th></tr><tr id="row_22"><td class="val passed" id="row_22_0">passing</td></tr></table></div></div><div class="scenario outline"><h3><span class="keyword">Scenario Outline:</span> <span class="val">no match in name but in examples</span></h3><ol><li class="step skipped" id="features_search_sample_feature_25"><div><span class="keyword">Given</span> <span class="step val"><state> without a table</span></div></li></ol><div class="examples"><h4><span class="keyword">Examples:</span> <span class="val">Hantu Pisang</span></h4><table><tr id="row_27"><th class="val skipped_param" id="row_27_0">state</th></tr><tr id="row_28"><td class="val passed" id="row_28_0">passing</td></tr></table></div><div class="examples"><h4><span class="keyword">Examples:</span> <span class="val">Ignore me</span></h4><table><tr id="row_31"><th class="val skipped_param" id="row_31_0">state</th></tr><tr id="row_32"><td class="val failed" id="row_32_0">failing</td></tr><tr><td class="failed" colspan="1"><pre>FAIL (RuntimeError)
|
179
179
|
./features/step_definitions/sample_steps.rb:2:in `flunker'
|
180
180
|
./features/step_definitions/sample_steps.rb:16:in `/^failing without a table$/'
|
181
|
-
features/search_sample.feature:25:in `Given <state> without a table'</pre></td></tr></table></div></div></div><div class="feature"><span class="tag">@lots</span><h2><span class="val">Feature: Tons of cukes</span></h2><p class="narrative"></p><div class="scenario"><h3><span class="keyword">Scenario:</span> <span class="val">Lots and lots</span></h3><ol><li class="step passed" id="features_tons_of_cukes_feature_4"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step failed" id="features_tons_of_cukes_feature_5"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div><pre class="failed">We already have 2 cukes! (RuntimeError)
|
181
|
+
features/search_sample.feature:25:in `Given <state> without a table'</pre></td></tr></table></div></div></div><div class="feature"><span class="tag">@sample_one</span><h2><span class="val">Feature: Tag samples</span></h2><p class="narrative"></p><div class="scenario"><span class="tag">@sample_two</span> <span class="tag">@sample_four</span><h3><span class="keyword">Scenario:</span> <span class="val">Passing</span></h3><ol><li class="step undefined" id="features_tags_sample_feature_6"><div><span class="keyword">Given</span> <span class="step val">missing</span></div></li></ol></div><div class="scenario outline"><span class="tag">@sample_three</span><h3><span class="keyword">Scenario Outline:</span> <span class="val"></span></h3><ol><li class="step skipped" id="features_tags_sample_feature_10"><div><span class="keyword">Given</span> <span class="step val"><state></span></div></li></ol><div class="examples"><h4><span class="keyword">Examples:</span> <span class="val"></span></h4><table><tr id="row_12"><th class="val skipped_param" id="row_12_0">state</th></tr><tr id="row_13"><td class="val undefined" id="row_13_0">missing</td></tr></table></div></div><div class="scenario"><span class="tag">@sample_three</span> <span class="tag">@sample_four</span><h3><span class="keyword">Scenario:</span> <span class="val">Skipped</span></h3><ol><li class="step undefined" id="features_tags_sample_feature_17"><div><span class="keyword">Given</span> <span class="step val">missing</span></div></li></ol></div></div><div class="feature"><span class="tag">@lots</span><h2><span class="val">Feature: Tons of cukes</span></h2><p class="narrative"></p><div class="scenario"><h3><span class="keyword">Scenario:</span> <span class="val">Lots and lots</span></h3><ol><li class="step passed" id="features_tons_of_cukes_feature_4"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step failed" id="features_tons_of_cukes_feature_5"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div><pre class="failed">We already have 2 cukes! (RuntimeError)
|
182
182
|
./features/step_definitions/sample_steps.rb:28:in `/^'(.+)' cukes$/'
|
183
183
|
features/tons_of_cukes.feature:5:in `Given '2' cukes'</pre></li><li class="step skipped" id="features_tons_of_cukes_feature_6"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_7"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_8"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_9"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_10"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_11"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_12"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_13"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_14"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_15"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_16"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_17"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_18"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_19"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_20"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_21"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_22"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_23"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_24"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_25"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_26"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_27"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_28"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_29"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_30"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_31"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_32"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_33"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_34"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_35"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_36"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_37"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_38"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_39"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_40"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_41"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_42"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_43"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_44"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_45"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_46"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_47"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_48"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_49"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_50"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_51"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li><li class="step skipped" id="features_tons_of_cukes_feature_52"><div><span class="keyword">Given</span> <span class="step val">'<span class="param">2</span>' cukes</span></div></li></ol></div></div><div class="feature"><h2><span class="val">Feature: undefined multiline args</span></h2><p class="narrative"></p><div class="scenario"><h3><span class="keyword">Scenario:</span> <span class="val">pystring</span></h3><ol><li class="step undefined" id="features_undefined_multiline_args_feature_4"><div><span class="keyword">Given</span> <span class="step val">a pystring</span></div><pre class="val"> example</pre></li></ol></div><div class="scenario"><h3><span class="keyword">Scenario:</span> <span class="val">table</span></h3><ol><li class="step undefined" id="features_undefined_multiline_args_feature_10"><div><span class="keyword">Given</span> <span class="step val">a table</span></div><table><tr id="row_11"><td class="val" id="row_11_0">table</td></tr><tr id="row_12"><td class="val" id="row_12_0">example</td></tr></table></li></ol></div></div><div class="duration">0m30.005s</div></div></body></html>
|
@@ -6,42 +6,49 @@ Feature: JUnit output formatter
|
|
6
6
|
Given I am in junit
|
7
7
|
And the tmp directory is empty
|
8
8
|
|
9
|
-
@mri186
|
9
|
+
@mri186
|
10
10
|
Scenario: one feature, one passing scenario, one failing scenario
|
11
11
|
When I run cucumber --format junit --out tmp/ features/one_passing_one_failing.feature
|
12
12
|
Then it should fail with
|
13
13
|
"""
|
14
14
|
|
15
15
|
"""
|
16
|
-
And "examples/junit/tmp/TEST-one_passing_one_failing.xml" should contain
|
16
|
+
And "examples/junit/tmp/TEST-one_passing_one_failing.xml" with junit duration "0.005" should contain
|
17
17
|
"""
|
18
18
|
<?xml version="1.0" encoding="UTF-8"?>
|
19
|
-
<testsuite errors="0"
|
20
|
-
<testcase
|
19
|
+
<testsuite errors="0" failures="1" name="One passing scenario, one failing scenario" tests="2" time="0.005">
|
20
|
+
<testcase classname="One passing scenario, one failing scenario.Passing" name="Passing" time="0.005">
|
21
21
|
</testcase>
|
22
|
-
<testcase
|
23
|
-
<failure message="
|
22
|
+
<testcase classname="One passing scenario, one failing scenario.Failing" name="Failing" time="0.005">
|
23
|
+
<failure message="failed Failing" type="failed">
|
24
|
+
Scenario: Failing
|
25
|
+
|
26
|
+
Given a failing scenario
|
27
|
+
|
28
|
+
Message:
|
24
29
|
(RuntimeError)
|
25
30
|
./features/step_definitions/steps.rb:6:in `/a failing scenario/'
|
26
31
|
features/one_passing_one_failing.feature:7:in `Given a failing scenario' </failure>
|
27
32
|
</testcase>
|
28
33
|
</testsuite>
|
29
|
-
|
34
|
+
|
30
35
|
"""
|
31
36
|
|
32
|
-
@mri186
|
37
|
+
@mri186
|
33
38
|
Scenario: pending step
|
34
39
|
When I run cucumber --format junit --out tmp/ features/pending.feature
|
35
40
|
Then it should pass with
|
36
41
|
"""
|
37
42
|
|
38
43
|
"""
|
39
|
-
And "examples/junit/tmp/TEST-pending.xml" should contain
|
44
|
+
And "examples/junit/tmp/TEST-pending.xml" with junit duration "0.009" should contain
|
40
45
|
"""
|
41
46
|
<?xml version="1.0" encoding="UTF-8"?>
|
42
|
-
<testsuite errors="0"
|
43
|
-
<testcase
|
44
|
-
<failure message="
|
47
|
+
<testsuite errors="0" failures="1" name="Pending step" tests="1" time="0.009">
|
48
|
+
<testcase classname="Pending step.Pending" name="Pending" time="0.009">
|
49
|
+
<failure message="pending Pending" type="pending">
|
50
|
+
Scenario: Pending
|
51
|
+
|
45
52
|
TODO (Cucumber::Pending)
|
46
53
|
./features/step_definitions/steps.rb:10:in `/a pending step/'
|
47
54
|
features/pending.feature:4:in `Given a pending step' </failure>
|
@@ -39,7 +39,6 @@ Given /^I am not running (?:.*) in the background$/ do
|
|
39
39
|
# no-op
|
40
40
|
end
|
41
41
|
|
42
|
-
|
43
42
|
When /^I run cucumber (.*)$/ do |cucumber_opts|
|
44
43
|
run "#{Cucumber::RUBY_BINARY} #{Cucumber::BINARY} --no-color #{cucumber_opts}"
|
45
44
|
end
|
@@ -75,23 +74,17 @@ Then /^the output should be$/ do |text|
|
|
75
74
|
last_stdout.should == text
|
76
75
|
end
|
77
76
|
|
78
|
-
Then /^"(
|
79
|
-
|
80
|
-
t.write(xml)
|
81
|
-
t.flush
|
82
|
-
t.close
|
83
|
-
cmd = "diffxml #{t.path} #{file}"
|
84
|
-
diff = `#{cmd}`
|
85
|
-
if diff =~ /<delta>/m
|
86
|
-
raise diff + "\nXML WAS:\n" + IO.read(file)
|
87
|
-
end
|
77
|
+
Then /^"([^\"]*)" should contain$/ do |file, text|
|
78
|
+
strip_duration(IO.read(file)).should == text
|
88
79
|
end
|
89
80
|
|
90
|
-
Then /^"(
|
91
|
-
|
81
|
+
Then /^"([^\"]*)" with junit duration "([^\"]*)" should contain$/ do |actual_file, duration_replacement, text|
|
82
|
+
actual = IO.read(actual_file)
|
83
|
+
actual = replace_junit_duration(actual, duration_replacement)
|
84
|
+
actual.should == text
|
92
85
|
end
|
93
86
|
|
94
|
-
Then /^"(
|
87
|
+
Then /^"([^\"]*)" should match$/ do |file, text|
|
95
88
|
IO.read(file).should =~ Regexp.new(text)
|
96
89
|
end
|
97
90
|
|
@@ -119,7 +112,7 @@ Then /^STDERR should be empty$/ do
|
|
119
112
|
last_stderr.should == ""
|
120
113
|
end
|
121
114
|
|
122
|
-
Then /^"(
|
115
|
+
Then /^"([^\"]*)" should exist$/ do |file|
|
123
116
|
File.exists?(file).should be_true
|
124
117
|
FileUtils.rm(file)
|
125
118
|
end
|
data/features/support/env.rb
CHANGED
@@ -50,6 +50,10 @@ class CucumberWorld
|
|
50
50
|
s.gsub(/\d+m\d+\.\d+s/m, replacement)
|
51
51
|
end
|
52
52
|
|
53
|
+
def replace_junit_duration(s, replacement)
|
54
|
+
s.gsub(/\d+\.\d\d+/m, replacement)
|
55
|
+
end
|
56
|
+
|
53
57
|
def create_file(file_name, file_content)
|
54
58
|
file_content.gsub!("CUCUMBER_LIB", "'#{cucumber_lib_dir}'") # Some files, such as Rakefiles need to use the lib dir
|
55
59
|
in_current_dir do
|
@@ -118,8 +122,3 @@ end
|
|
118
122
|
After do
|
119
123
|
terminate_background_jobs
|
120
124
|
end
|
121
|
-
|
122
|
-
Before('@diffxml') do
|
123
|
-
`diffxml --version`
|
124
|
-
raise "Please install diffxml from http://diffxml.sourceforge.net/" if $? != 0
|
125
|
-
end
|
data/lib/cucumber/ast/feature.rb
CHANGED
@@ -44,6 +44,19 @@ module Cucumber
|
|
44
44
|
"#{@file}:#{line}"
|
45
45
|
end
|
46
46
|
|
47
|
+
def tag_count(tag)
|
48
|
+
if @tags.respond_to?(:count)
|
49
|
+
@tags.count(tag) # 1.9
|
50
|
+
else
|
51
|
+
@tags.select{|t| t == tag}.length # 1.8
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def feature_and_children_tag_count(tag)
|
56
|
+
children_tag_count = @feature_elements.inject(0){|count, feature_element| count += feature_element.tag_count(tag)}
|
57
|
+
children_tag_count + tag_count(tag)
|
58
|
+
end
|
59
|
+
|
47
60
|
def short_name
|
48
61
|
first_line = name.split(/\n/)[0]
|
49
62
|
if first_line =~ /#{language.keywords('feature', true)}:(.*)/
|
@@ -24,7 +24,7 @@ module Cucumber
|
|
24
24
|
if @name.empty?
|
25
25
|
[@keyword.jlength]
|
26
26
|
else
|
27
|
-
@name.split("\n").enum_for(:each_with_index).map do |line, line_number|
|
27
|
+
@name.split("\n").enum_for(:each_with_index).map do |line, line_number|
|
28
28
|
line_number == 0 ? @keyword.jlength + line.jlength : line.jlength + Ast::Step::INDENT - 1 # We -1 as names which are not keyword lines are missing a space between keyword and name
|
29
29
|
end
|
30
30
|
end
|
@@ -32,7 +32,7 @@ module Cucumber
|
|
32
32
|
|
33
33
|
def matches_scenario_names?(scenario_name_regexps)
|
34
34
|
scenario_name_regexps.detect{|name| name =~ @name}
|
35
|
-
end
|
35
|
+
end
|
36
36
|
|
37
37
|
def backtrace_line(name = "#{@keyword} #{@name}", line = @line)
|
38
38
|
@feature.backtrace_line(name, line) if @feature
|
@@ -49,9 +49,13 @@ module Cucumber
|
|
49
49
|
def accept_hook?(hook)
|
50
50
|
@tags.accept_hook?(hook) || @feature.accept_hook?(hook)
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
|
+
def tag_count(tag)
|
54
|
+
@feature.tag_count(tag) == 0 ? @tags.count(tag) : @feature.tag_count(tag)
|
55
|
+
end
|
56
|
+
|
53
57
|
def language
|
54
58
|
@feature.language
|
55
59
|
end
|
56
|
-
|
60
|
+
end
|
57
61
|
end
|
data/lib/cucumber/ast/table.rb
CHANGED
@@ -126,23 +126,30 @@ module Cucumber
|
|
126
126
|
[:table, *cells_rows.map{|row| row.to_sexp}]
|
127
127
|
end
|
128
128
|
|
129
|
-
# Redefines the table headers. This makes it
|
130
|
-
#
|
129
|
+
# Redefines the table headers. This makes it possible to use
|
130
|
+
# prettier and more flexible header names in the features. The
|
131
|
+
# keys of +mappings+ are Strings or regular expressions
|
132
|
+
# (anything that responds to #=== will work) that may match
|
133
|
+
# column headings in the table. The values of +mappings+ are
|
134
|
+
# desired names for the columns.
|
135
|
+
#
|
136
|
+
# Example:
|
131
137
|
#
|
132
138
|
# | Phone Number | Address |
|
133
139
|
# | 123456 | xyz |
|
134
140
|
# | 345678 | abc |
|
135
141
|
#
|
136
|
-
# A StepDefinition receiving this table can then map the columns
|
142
|
+
# A StepDefinition receiving this table can then map the columns
|
143
|
+
# with both Regexp and String:
|
137
144
|
#
|
138
|
-
#
|
139
|
-
#
|
145
|
+
# table.map_headers!(/phone( number)?/i => :phone, 'Address' => :address)
|
146
|
+
# table.hashes
|
140
147
|
# # => [{:phone => '123456', :address => 'xyz'}, {:phone => '345678', :address => 'abc'}]
|
141
148
|
#
|
142
149
|
def map_headers!(mappings)
|
143
150
|
header_cells = cell_matrix[0]
|
144
151
|
mappings.each_pair do |pre, post|
|
145
|
-
header_cell = header_cells.detect{|cell| cell.value
|
152
|
+
header_cell = header_cells.detect{|cell| pre === cell.value}
|
146
153
|
header_cell.value = post
|
147
154
|
if @conversion_procs.has_key?(pre)
|
148
155
|
@conversion_procs[post] = @conversion_procs.delete(pre)
|
data/lib/cucumber/ast/tags.rb
CHANGED
@@ -10,7 +10,7 @@ module Cucumber
|
|
10
10
|
def self.strip_prefix(tag_name)
|
11
11
|
tag_name =~ /^@(.*)/ ? $1 : tag_name
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
def initialize(line, tag_names)
|
15
15
|
@line, @tag_names = line, tag_names
|
16
16
|
end
|
@@ -26,6 +26,14 @@ module Cucumber
|
|
26
26
|
hook.matches_tag_names?(@tag_names)
|
27
27
|
end
|
28
28
|
|
29
|
+
def count(tag)
|
30
|
+
if @tag_names.respond_to?(:count)
|
31
|
+
@tag_names.count(tag) # 1.9
|
32
|
+
else
|
33
|
+
@tag_names.select{|t| t == tag}.length # 1.8
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
29
37
|
def to_sexp
|
30
38
|
@tag_names.map{|tag_name| [:tag, tag_name]}
|
31
39
|
end
|
@@ -7,18 +7,6 @@ module Cucumber
|
|
7
7
|
class ProfileNotFound < StandardError; end
|
8
8
|
|
9
9
|
class Configuration
|
10
|
-
BUILTIN_FORMATS = {
|
11
|
-
'html' => 'Cucumber::Formatter::Html',
|
12
|
-
'pretty' => 'Cucumber::Formatter::Pretty',
|
13
|
-
'profile' => 'Cucumber::Formatter::Profile',
|
14
|
-
'progress' => 'Cucumber::Formatter::Progress',
|
15
|
-
'rerun' => 'Cucumber::Formatter::Rerun',
|
16
|
-
'usage' => 'Cucumber::Formatter::Usage',
|
17
|
-
'junit' => 'Cucumber::Formatter::Junit',
|
18
|
-
'tag_cloud' => 'Cucumber::Formatter::TagCloud',
|
19
|
-
'steps' => 'Cucumber::Formatter::Steps'
|
20
|
-
}
|
21
|
-
|
22
10
|
attr_reader :options
|
23
11
|
|
24
12
|
def initialize(out_stream = STDOUT, error_stream = STDERR)
|
@@ -96,8 +84,8 @@ module Cucumber
|
|
96
84
|
end
|
97
85
|
|
98
86
|
def formatter_class(format)
|
99
|
-
if(builtin = BUILTIN_FORMATS[format])
|
100
|
-
constantize(builtin)
|
87
|
+
if(builtin = Options::BUILTIN_FORMATS[format])
|
88
|
+
constantize(builtin[0])
|
101
89
|
else
|
102
90
|
constantize(format)
|
103
91
|
end
|
@@ -180,7 +168,7 @@ module Cucumber
|
|
180
168
|
tr("-", "_").
|
181
169
|
downcase
|
182
170
|
end
|
183
|
-
|
171
|
+
|
184
172
|
end
|
185
173
|
|
186
174
|
end
|
data/lib/cucumber/cli/main.rb
CHANGED
@@ -11,6 +11,8 @@ require 'cucumber/cli/drb_client'
|
|
11
11
|
module Cucumber
|
12
12
|
module Cli
|
13
13
|
class Main
|
14
|
+
FAILURE = 1
|
15
|
+
|
14
16
|
class << self
|
15
17
|
def step_mother
|
16
18
|
@step_mother
|
@@ -32,7 +34,7 @@ module Cucumber
|
|
32
34
|
@out_stream = out_stream == STDOUT ? Formatter::ColorIO.new : out_stream
|
33
35
|
@error_stream = error_stream
|
34
36
|
end
|
35
|
-
|
37
|
+
|
36
38
|
def execute!(step_mother)
|
37
39
|
trap_interrupt
|
38
40
|
if configuration.drb?
|
@@ -56,17 +58,32 @@ module Cucumber
|
|
56
58
|
step_mother.visitor = visitor # Needed to support World#announce
|
57
59
|
visitor.visit_features(features)
|
58
60
|
|
59
|
-
failure = if
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
61
|
+
failure = if exceeded_tag_limts?(features)
|
62
|
+
FAILURE
|
63
|
+
elsif configuration.wip?
|
64
|
+
step_mother.scenarios(:passed).any?
|
65
|
+
else
|
66
|
+
step_mother.scenarios(:failed).any? ||
|
67
|
+
(configuration.strict? && step_mother.steps(:undefined).any?)
|
68
|
+
end
|
65
69
|
rescue ProfilesNotDefinedError, YmlLoadError, ProfileNotFound => e
|
66
70
|
@error_stream.puts e.message
|
67
71
|
true
|
68
72
|
end
|
69
73
|
|
74
|
+
def exceeded_tag_limts?(features)
|
75
|
+
exceeded = false
|
76
|
+
configuration.options[:include_tags].each do |tag, limit|
|
77
|
+
unless limit.nil?
|
78
|
+
tag_count = features.tag_count(tag)
|
79
|
+
if tag_count > limit.to_i
|
80
|
+
exceeded = true
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
exceeded
|
85
|
+
end
|
86
|
+
|
70
87
|
def load_plain_text_features
|
71
88
|
features = Ast::Features.new
|
72
89
|
|
@@ -85,7 +102,7 @@ module Cucumber
|
|
85
102
|
|
86
103
|
def configuration
|
87
104
|
return @configuration if @configuration
|
88
|
-
|
105
|
+
|
89
106
|
@configuration = Configuration.new(@out_stream, @error_stream)
|
90
107
|
@configuration.parse!(@args)
|
91
108
|
@configuration
|
data/lib/cucumber/cli/options.rb
CHANGED
@@ -4,16 +4,28 @@ module Cucumber
|
|
4
4
|
|
5
5
|
class Options
|
6
6
|
BUILTIN_FORMATS = {
|
7
|
-
'html' => 'Cucumber::Formatter::Html',
|
8
|
-
'pretty' => 'Cucumber::Formatter::Pretty',
|
9
|
-
'profile' => 'Cucumber::Formatter::Profile',
|
10
|
-
'progress' => 'Cucumber::Formatter::Progress',
|
11
|
-
'rerun' => 'Cucumber::Formatter::Rerun',
|
12
|
-
'usage' => 'Cucumber::Formatter::Usage',
|
13
|
-
'junit' => 'Cucumber::Formatter::Junit',
|
14
|
-
'tag_cloud' => 'Cucumber::Formatter::TagCloud',
|
15
|
-
'steps' => 'Cucumber::Formatter::Steps'
|
7
|
+
'html' => ['Cucumber::Formatter::Html', 'Generates a nice looking HTML report.'],
|
8
|
+
'pretty' => ['Cucumber::Formatter::Pretty', 'Prints the feature as is - in colours.'],
|
9
|
+
'profile' => ['Cucumber::Formatter::Profile', 'Prints the 10 slowest steps at the end.'],
|
10
|
+
'progress' => ['Cucumber::Formatter::Progress', 'Prints one character per scenario.'],
|
11
|
+
'rerun' => ['Cucumber::Formatter::Rerun', 'Prints failing files with line numbers.'],
|
12
|
+
'usage' => ['Cucumber::Formatter::Usage', 'Prints where step definitions are used.'],
|
13
|
+
'junit' => ['Cucumber::Formatter::Junit', 'Generates a report similar to Ant+JUnit.'],
|
14
|
+
'tag_cloud' => ['Cucumber::Formatter::TagCloud', 'Prints a tag cloud of tag usage.'],
|
15
|
+
'steps' => ['Cucumber::Formatter::Steps', 'Prints location of step definitions.']
|
16
16
|
}
|
17
|
+
max = BUILTIN_FORMATS.keys.map{|s| s.length}.max
|
18
|
+
FORMAT_HELP = (BUILTIN_FORMATS.keys.sort.map do |key|
|
19
|
+
" #{key}#{' ' * (max - key.length)} : #{BUILTIN_FORMATS[key][1]}"
|
20
|
+
end) + ["FORMAT can also be the fully qualified class name of",
|
21
|
+
"your own custom formatter. If the class isn't loaded,",
|
22
|
+
"Cucumber will attempt to require a file with a relative",
|
23
|
+
"file name that is the underscore name of the class name.",
|
24
|
+
"Example: --format Foo::BarZap -> Cucumber will look for",
|
25
|
+
"foo/bar_zap.rb. You can place the file with this relative",
|
26
|
+
"path underneath your features/support directory or anywhere",
|
27
|
+
"on Ruby's LOAD_PATH, for example in a Ruby gem."
|
28
|
+
]
|
17
29
|
DRB_FLAG = '--drb'
|
18
30
|
PROFILE_SHORT_FLAG = '-p'
|
19
31
|
PROFILE_LONG_FLAG = '--profile'
|
@@ -31,6 +43,7 @@ module Cucumber
|
|
31
43
|
@default_profile = options[:default_profile]
|
32
44
|
@skip_profile_information = options[:skip_profile_information]
|
33
45
|
@profiles = []
|
46
|
+
@overridden_paths = []
|
34
47
|
@options = default_options
|
35
48
|
end
|
36
49
|
|
@@ -54,7 +67,7 @@ module Cucumber
|
|
54
67
|
previous_flag_was_profile = true
|
55
68
|
next true
|
56
69
|
end
|
57
|
-
arg == DRB_FLAG
|
70
|
+
arg == DRB_FLAG || @overridden_paths.include?(arg)
|
58
71
|
end
|
59
72
|
)
|
60
73
|
end
|
@@ -96,16 +109,8 @@ module Cucumber
|
|
96
109
|
end
|
97
110
|
end
|
98
111
|
opts.on("-f FORMAT", "--format FORMAT",
|
99
|
-
"How to format features (Default: pretty)",
|
100
|
-
|
101
|
-
"FORMAT can also be the fully qualified class name of",
|
102
|
-
"your own custom formatter. If the class isn't loaded,",
|
103
|
-
"Cucumber will attempt to require a file with a relative",
|
104
|
-
"file name that is the underscore name of the class name.",
|
105
|
-
"Example: --format Foo::BarZap -> Cucumber will look for",
|
106
|
-
"foo/bar_zap.rb. You can place the file with this relative",
|
107
|
-
"path underneath your features/support directory or anywhere",
|
108
|
-
"on Ruby's LOAD_PATH, for example in a Ruby gem.") do |v|
|
112
|
+
"How to format features (Default: pretty). Available formats:",
|
113
|
+
*FORMAT_HELP) do |v|
|
109
114
|
@options[:formats] << [v, @out_stream]
|
110
115
|
end
|
111
116
|
opts.on("-o", "--out [FILE|DIR]",
|
@@ -118,12 +123,16 @@ module Cucumber
|
|
118
123
|
end
|
119
124
|
opts.on("-t TAGS", "--tags TAGS",
|
120
125
|
"Only execute the features or scenarios with the specified tags.",
|
121
|
-
"TAGS must be comma-separated without spaces.
|
122
|
-
"
|
123
|
-
"with
|
126
|
+
"TAGS must be comma-separated without spaces. They can be",
|
127
|
+
"specified with or without the @ prefix. Example: --tags dev\n",
|
128
|
+
"Negative tags: Prefix tags with ~ to exclude features or scenarios",
|
129
|
+
"having that tag.\n",
|
130
|
+
"Limit WIP: Positive tags can be given a threshold to limit the",
|
131
|
+
"number of occurrences. Example: --tags qa:3 will fail if there",
|
132
|
+
"are more than 3 occurrences of the @qa tag.") do |v|
|
124
133
|
include_tags, exclude_tags = *parse_tags(v)
|
125
|
-
@options[:include_tags]
|
126
|
-
@options[:exclude_tags]
|
134
|
+
@options[:include_tags].merge!(include_tags)
|
135
|
+
@options[:exclude_tags].merge!(exclude_tags)
|
127
136
|
end
|
128
137
|
opts.on("-n NAME", "--name NAME",
|
129
138
|
"Only execute the feature elements which match part of the given name.",
|
@@ -261,7 +270,16 @@ module Cucumber
|
|
261
270
|
# Strip @
|
262
271
|
includes = includes.map{|tag| Ast::Tags.strip_prefix(tag)}
|
263
272
|
excludes = excludes.map{|tag| Ast::Tags.strip_prefix(tag)}
|
264
|
-
[includes, excludes]
|
273
|
+
[parse_tag_limits(includes), parse_tag_limits(excludes)]
|
274
|
+
end
|
275
|
+
|
276
|
+
def parse_tag_limits(includes)
|
277
|
+
dict = {}
|
278
|
+
includes.each do |tag|
|
279
|
+
tag, limit = tag.split(':')
|
280
|
+
dict[tag] = limit.nil? ? limit : limit.to_i
|
281
|
+
end
|
282
|
+
dict
|
265
283
|
end
|
266
284
|
|
267
285
|
def disable_profile_loading?
|
@@ -298,10 +316,14 @@ module Cucumber
|
|
298
316
|
def reverse_merge(other_options)
|
299
317
|
@options = other_options.options.merge(@options)
|
300
318
|
@options[:require] += other_options[:require]
|
301
|
-
@options[:include_tags]
|
302
|
-
@options[:exclude_tags]
|
319
|
+
@options[:include_tags].merge! other_options[:include_tags]
|
320
|
+
@options[:exclude_tags].merge! other_options[:exclude_tags]
|
303
321
|
@options[:env_vars] = other_options[:env_vars].merge(@options[:env_vars])
|
304
|
-
|
322
|
+
if @options[:paths].empty?
|
323
|
+
@options[:paths] = other_options[:paths]
|
324
|
+
else
|
325
|
+
@overridden_paths += (other_options[:paths] - @options[:paths])
|
326
|
+
end
|
305
327
|
@options[:source] &= other_options[:source]
|
306
328
|
@options[:snippets] &= other_options[:snippets]
|
307
329
|
|
@@ -348,8 +370,8 @@ module Cucumber
|
|
348
370
|
:dry_run => false,
|
349
371
|
:formats => [],
|
350
372
|
:excludes => [],
|
351
|
-
:include_tags =>
|
352
|
-
:exclude_tags =>
|
373
|
+
:include_tags => {},
|
374
|
+
:exclude_tags => {},
|
353
375
|
:name_regexps => [],
|
354
376
|
:env_vars => {},
|
355
377
|
:diff_enabled => true
|