cucumber 1.1.9 → 1.2.0
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/.travis.yml +9 -0
- data/History.md +20 -3
- data/README.md +1 -2
- data/cucumber.gemspec +10 -13
- data/cucumber.yml +2 -2
- data/features/.cucumber/stepdefs.json +13 -391
- data/features/backtraces.feature +36 -0
- data/features/{issue_117.feature → drb_server_integration.feature} +3 -3
- data/features/formatter_step_file_colon_line.feature +46 -0
- data/features/{issue_57.feature → rerun_formatter.feature} +2 -2
- data/features/run_specific_scenarios.feature +47 -0
- data/gem_tasks/cucumber.rake +15 -8
- data/legacy_features/cucumber_cli.feature +0 -7
- data/legacy_features/junit_formatter.feature +60 -10
- data/legacy_features/language_help.feature +1 -0
- data/lib/cucumber.rb +2 -1
- data/lib/cucumber/ast/step.rb +1 -1
- data/lib/cucumber/ast/step_invocation.rb +2 -15
- data/lib/cucumber/ast/table.rb +16 -6
- data/lib/cucumber/ast/tree_walker.rb +5 -5
- data/lib/cucumber/cli/options.rb +5 -8
- data/lib/cucumber/formatter/ansicolor.rb +7 -12
- data/lib/cucumber/formatter/cucumber.css +7 -1
- data/lib/cucumber/formatter/gherkin_formatter_adapter.rb +1 -1
- data/lib/cucumber/formatter/html.rb +5 -5
- data/lib/cucumber/formatter/interceptor.rb +62 -0
- data/lib/cucumber/formatter/junit.rb +30 -14
- data/lib/cucumber/formatter/pretty.rb +3 -3
- data/lib/cucumber/formatter/progress.rb +1 -1
- data/lib/cucumber/formatter/rerun.rb +1 -1
- data/lib/cucumber/formatter/usage.rb +1 -1
- data/lib/cucumber/js_support/js_snippets.rb +1 -1
- data/lib/cucumber/platform.rb +1 -1
- data/lib/cucumber/rb_support/rb_dsl.rb +15 -8
- data/lib/cucumber/rb_support/rb_language.rb +3 -3
- data/lib/cucumber/rb_support/rb_step_definition.rb +17 -5
- data/lib/cucumber/term/ansicolor.rb +118 -0
- data/spec/cucumber/ast/table_spec.rb +9 -0
- data/spec/cucumber/cli/configuration_spec.rb +12 -6
- data/spec/cucumber/cli/options_spec.rb +9 -3
- data/spec/cucumber/constantize_spec.rb +5 -1
- data/spec/cucumber/formatter/ansicolor_spec.rb +1 -1
- data/spec/cucumber/formatter/interceptor_spec.rb +111 -0
- data/spec/cucumber/formatter/junit_spec.rb +36 -20
- data/spec/cucumber/formatter/progress_spec.rb +2 -2
- data/spec/cucumber/rb_support/rb_language_spec.rb +5 -5
- data/spec/cucumber/rb_support/rb_step_definition_spec.rb +17 -1
- data/spec/cucumber/rb_support/regexp_argument_matcher_spec.rb +6 -2
- data/spec/cucumber/step_match_spec.rb +8 -4
- data/spec/spec_helper.rb +15 -1
- metadata +215 -82
- data/.gitmodules +0 -3
- data/lib/cucumber/formatter/pdf.rb +0 -244
@@ -26,7 +26,7 @@ module Cucumber
|
|
26
26
|
@duration = Time.now - @start_time
|
27
27
|
end
|
28
28
|
|
29
|
-
def after_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background)
|
29
|
+
def after_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background, file_colon_line)
|
30
30
|
if step_match.name.nil? # nil if it's from a scenario outline
|
31
31
|
stepdef_key = StepDefKey.new(step_match.step_definition.regexp_source, step_match.step_definition.file_colon_line)
|
32
32
|
|
data/lib/cucumber/platform.rb
CHANGED
@@ -4,7 +4,7 @@ require 'rbconfig'
|
|
4
4
|
|
5
5
|
module Cucumber
|
6
6
|
unless defined?(Cucumber::VERSION)
|
7
|
-
VERSION = '1.
|
7
|
+
VERSION = '1.2.0'
|
8
8
|
BINARY = File.expand_path(File.dirname(__FILE__) + '/../../bin/cucumber')
|
9
9
|
LIBDIR = File.expand_path(File.dirname(__FILE__) + '/../../lib')
|
10
10
|
JRUBY = defined?(JRUBY_VERSION)
|
@@ -23,8 +23,8 @@ module Cucumber
|
|
23
23
|
@rb_language.register_rb_transform(regexp, proc)
|
24
24
|
end
|
25
25
|
|
26
|
-
def register_rb_step_definition(regexp,
|
27
|
-
@rb_language.register_rb_step_definition(regexp,
|
26
|
+
def register_rb_step_definition(regexp, proc_or_sym, options = {})
|
27
|
+
@rb_language.register_rb_step_definition(regexp, proc_or_sym, options)
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
@@ -98,12 +98,19 @@ module Cucumber
|
|
98
98
|
# also to the i18n translations whenever a feature of a
|
99
99
|
# new language is loaded.
|
100
100
|
#
|
101
|
-
#
|
102
|
-
#
|
103
|
-
#
|
104
|
-
#
|
105
|
-
|
106
|
-
|
101
|
+
# If provided, the +symbol+ is sent to the <tt>World</tt> object
|
102
|
+
# as defined by #World. A new <tt>World</tt> object is created
|
103
|
+
# for each scenario and is shared across step definitions within
|
104
|
+
# that scenario. If the +options+ hash contains an <tt>:on</tt>
|
105
|
+
# key, the value for this is assumed to be a proc. This proc
|
106
|
+
# will be executed in the context of the <tt>World</tt> object
|
107
|
+
# and then sent the +symbol+.
|
108
|
+
#
|
109
|
+
# If no +symbol+ if provided then the +&proc+ gets executed in
|
110
|
+
# the context of the <tt>World</tt> object.
|
111
|
+
def register_rb_step_definition(regexp, symbol = nil, options = {}, &proc)
|
112
|
+
proc_or_sym = symbol || proc
|
113
|
+
RbDsl.register_rb_step_definition(regexp, proc_or_sym, options)
|
107
114
|
end
|
108
115
|
end
|
109
116
|
end
|
@@ -75,7 +75,7 @@ module Cucumber
|
|
75
75
|
end.compact
|
76
76
|
end
|
77
77
|
|
78
|
-
ARGUMENT_PATTERNS = ['"(
|
78
|
+
ARGUMENT_PATTERNS = ['"(.*?)"', '(\d+)']
|
79
79
|
|
80
80
|
def snippet_text(code_keyword, step_name, multiline_arg_class)
|
81
81
|
snippet_pattern = Regexp.escape(step_name).gsub('\ ', ' ').gsub('/', '\/')
|
@@ -110,8 +110,8 @@ module Cucumber
|
|
110
110
|
add_transform(RbTransform.new(self, regexp, proc))
|
111
111
|
end
|
112
112
|
|
113
|
-
def register_rb_step_definition(regexp,
|
114
|
-
step_definition = RbStepDefinition.new(self, regexp,
|
113
|
+
def register_rb_step_definition(regexp, proc_or_sym, options)
|
114
|
+
step_definition = RbStepDefinition.new(self, regexp, proc_or_sym, options)
|
115
115
|
@step_definitions << step_definition
|
116
116
|
step_definition
|
117
117
|
end
|
@@ -19,18 +19,25 @@ module Cucumber
|
|
19
19
|
|
20
20
|
class MissingProc < StandardError
|
21
21
|
def message
|
22
|
-
"Step definitions must always have a proc"
|
22
|
+
"Step definitions must always have a proc or symbol"
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
def initialize(rb_language, regexp,
|
27
|
-
raise MissingProc if
|
26
|
+
def initialize(rb_language, regexp, proc_or_sym, options)
|
27
|
+
raise MissingProc if proc_or_sym.nil?
|
28
28
|
if String === regexp
|
29
29
|
p = Regexp.escape(regexp)
|
30
30
|
p = p.gsub(/\\\$\w+/, '(.*)') # Replace $var with (.*)
|
31
31
|
regexp = Regexp.new("^#{p}$")
|
32
32
|
end
|
33
|
-
@rb_language, @regexp, @proc = rb_language, regexp,
|
33
|
+
@rb_language, @regexp, @proc = rb_language, regexp, proc_or_sym
|
34
|
+
if @proc.kind_of? Symbol
|
35
|
+
@proc = lambda do |*args|
|
36
|
+
target = options[:on] ? instance_exec(&options[:on]) : self
|
37
|
+
target.send(proc_or_sym, *args)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
34
41
|
@rb_language.available_step_definition(regexp_source, file_colon_line)
|
35
42
|
end
|
36
43
|
|
@@ -71,7 +78,12 @@ module Cucumber
|
|
71
78
|
end
|
72
79
|
|
73
80
|
def file_colon_line
|
74
|
-
@proc
|
81
|
+
case @proc
|
82
|
+
when Proc
|
83
|
+
@proc.file_colon_line
|
84
|
+
when Symbol
|
85
|
+
":#{@proc}"
|
86
|
+
end
|
75
87
|
end
|
76
88
|
|
77
89
|
def file
|
@@ -0,0 +1,118 @@
|
|
1
|
+
module Cucumber
|
2
|
+
module Term
|
3
|
+
# The ANSIColor module can be used for namespacing and mixed into your own
|
4
|
+
# classes.
|
5
|
+
module ANSIColor
|
6
|
+
# :stopdoc:
|
7
|
+
ATTRIBUTES = [
|
8
|
+
[ :clear , 0 ],
|
9
|
+
[ :reset , 0 ], # synonym for :clear
|
10
|
+
[ :bold , 1 ],
|
11
|
+
[ :dark , 2 ],
|
12
|
+
[ :italic , 3 ], # not widely implemented
|
13
|
+
[ :underline , 4 ],
|
14
|
+
[ :underscore , 4 ], # synonym for :underline
|
15
|
+
[ :blink , 5 ],
|
16
|
+
[ :rapid_blink , 6 ], # not widely implemented
|
17
|
+
[ :negative , 7 ], # no reverse because of String#reverse
|
18
|
+
[ :concealed , 8 ],
|
19
|
+
[ :strikethrough, 9 ], # not widely implemented
|
20
|
+
[ :black , 30 ],
|
21
|
+
[ :red , 31 ],
|
22
|
+
[ :green , 32 ],
|
23
|
+
[ :yellow , 33 ],
|
24
|
+
[ :blue , 34 ],
|
25
|
+
[ :magenta , 35 ],
|
26
|
+
[ :cyan , 36 ],
|
27
|
+
[ :white , 37 ],
|
28
|
+
[ :on_black , 40 ],
|
29
|
+
[ :on_red , 41 ],
|
30
|
+
[ :on_green , 42 ],
|
31
|
+
[ :on_yellow , 43 ],
|
32
|
+
[ :on_blue , 44 ],
|
33
|
+
[ :on_magenta , 45 ],
|
34
|
+
[ :on_cyan , 46 ],
|
35
|
+
[ :on_white , 47 ],
|
36
|
+
]
|
37
|
+
|
38
|
+
ATTRIBUTE_NAMES = ATTRIBUTES.transpose.first
|
39
|
+
# :startdoc:
|
40
|
+
|
41
|
+
# Returns true, if the coloring function of this module
|
42
|
+
# is switched on, false otherwise.
|
43
|
+
def self.coloring?
|
44
|
+
@coloring
|
45
|
+
end
|
46
|
+
|
47
|
+
# Turns the coloring on or off globally, so you can easily do
|
48
|
+
# this for example:
|
49
|
+
# Cucumber::Term::ANSIColor::coloring = STDOUT.isatty
|
50
|
+
def self.coloring=(val)
|
51
|
+
@coloring = val
|
52
|
+
end
|
53
|
+
self.coloring = true
|
54
|
+
|
55
|
+
ATTRIBUTES.each do |c, v|
|
56
|
+
eval %Q{
|
57
|
+
def #{c}(string = nil)
|
58
|
+
result = ''
|
59
|
+
result << "\e[#{v}m" if Cucumber::Term::ANSIColor.coloring?
|
60
|
+
if block_given?
|
61
|
+
result << yield
|
62
|
+
elsif string
|
63
|
+
result << string
|
64
|
+
elsif respond_to?(:to_str)
|
65
|
+
result << to_str
|
66
|
+
else
|
67
|
+
return result #only switch on
|
68
|
+
end
|
69
|
+
result << "\e[0m" if Cucumber::Term::ANSIColor.coloring?
|
70
|
+
result
|
71
|
+
end
|
72
|
+
}
|
73
|
+
end
|
74
|
+
|
75
|
+
# Regular expression that is used to scan for ANSI-sequences while
|
76
|
+
# uncoloring strings.
|
77
|
+
COLORED_REGEXP = /\e\[(?:[34][0-7]|[0-9])?m/
|
78
|
+
|
79
|
+
|
80
|
+
def self.included(klass)
|
81
|
+
if version_is_greater_than_18? and klass == String
|
82
|
+
ATTRIBUTES.delete(:clear)
|
83
|
+
ATTRIBUTE_NAMES.delete(:clear)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Returns an uncolored version of the string, that is all
|
88
|
+
# ANSI-sequences are stripped from the string.
|
89
|
+
def uncolored(string = nil) # :yields:
|
90
|
+
if block_given?
|
91
|
+
yield.gsub(COLORED_REGEXP, '')
|
92
|
+
elsif string
|
93
|
+
string.gsub(COLORED_REGEXP, '')
|
94
|
+
elsif respond_to?(:to_str)
|
95
|
+
to_str.gsub(COLORED_REGEXP, '')
|
96
|
+
else
|
97
|
+
''
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
module_function
|
102
|
+
|
103
|
+
# Returns an array of all Cucumber::Term::ANSIColor attributes as symbols.
|
104
|
+
def attributes
|
105
|
+
ATTRIBUTE_NAMES
|
106
|
+
end
|
107
|
+
extend self
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
def version_is_greater_than_18?
|
112
|
+
version = RUBY_VERSION.split('.')
|
113
|
+
version.map! &:to_i
|
114
|
+
version[0] >= 1 && version[1] > 8
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -474,6 +474,15 @@ module Cucumber
|
|
474
474
|
lambda { @t.dup.diff!(t) }.should_not raise_error
|
475
475
|
lambda { @t.dup.diff!(t, :surplus_col => true) }.should raise_error
|
476
476
|
end
|
477
|
+
|
478
|
+
it "should not raise on misplaced columns" do
|
479
|
+
t = table(%{
|
480
|
+
| b | a |
|
481
|
+
| d | c |
|
482
|
+
}, __FILE__, __LINE__)
|
483
|
+
lambda { @t.dup.diff!(t) }.should_not raise_error
|
484
|
+
lambda { @t.dup.diff!(t, :misplaced_col => true) }.should raise_error
|
485
|
+
end
|
477
486
|
end
|
478
487
|
|
479
488
|
def table(text, file, offset)
|
@@ -321,12 +321,12 @@ END_OF_MESSAGE
|
|
321
321
|
end
|
322
322
|
|
323
323
|
it "should accept --color option" do
|
324
|
-
Term::ANSIColor.should_receive(:coloring=).with(true)
|
324
|
+
Cucumber::Term::ANSIColor.should_receive(:coloring=).with(true)
|
325
325
|
config.parse!(['--color'])
|
326
326
|
end
|
327
327
|
|
328
328
|
it "should accept --no-color option" do
|
329
|
-
Term::ANSIColor.should_receive(:coloring=).with(false)
|
329
|
+
Cucumber::Term::ANSIColor.should_receive(:coloring=).with(false)
|
330
330
|
config = Configuration.new(StringIO.new)
|
331
331
|
config.parse!(['--no-color'])
|
332
332
|
end
|
@@ -404,14 +404,20 @@ END_OF_MESSAGE
|
|
404
404
|
end
|
405
405
|
|
406
406
|
describe "#tag_expression" do
|
407
|
+
include RSpec::WorkInProgress
|
408
|
+
|
407
409
|
it "returns an empty expression when no tags are specified" do
|
408
|
-
|
409
|
-
|
410
|
+
pending_under :java, 'the java class Gherkin::TagExpression has no isEmpty method' do
|
411
|
+
config.parse!([])
|
412
|
+
config.tag_expression.should be_empty
|
413
|
+
end
|
410
414
|
end
|
411
415
|
|
412
416
|
it "returns an expression when tags are specified" do
|
413
|
-
|
414
|
-
|
417
|
+
pending_under :java, 'the java class Gherkin::TagExpression has no isEmpty method' do
|
418
|
+
config.parse!(['--tags','@foo'])
|
419
|
+
config.tag_expression.should_not be_empty
|
420
|
+
end
|
415
421
|
end
|
416
422
|
end
|
417
423
|
|
@@ -55,14 +55,20 @@ module Cli
|
|
55
55
|
|
56
56
|
context '--i18n' do
|
57
57
|
context "with LANG specified as 'help'" do
|
58
|
+
include RSpec::WorkInProgress
|
59
|
+
|
58
60
|
it "lists all known langues" do
|
59
|
-
|
60
|
-
|
61
|
+
pending_under :java, "require gherkin >= b5e96f13" do
|
62
|
+
when_parsing '--i18n help' do
|
63
|
+
Kernel.should_receive(:exit)
|
64
|
+
end
|
61
65
|
end
|
62
66
|
end
|
63
67
|
|
64
68
|
it "exits the program" do
|
65
|
-
|
69
|
+
pending_under :java, "require gherkin >= b5e96f13" do
|
70
|
+
when_parsing('--i18n help') { Kernel.should_receive(:exit) }
|
71
|
+
end
|
66
72
|
end
|
67
73
|
end
|
68
74
|
end
|
@@ -8,5 +8,9 @@ module Cucumber
|
|
8
8
|
clazz = constantize('Cucumber::Formatter::Html')
|
9
9
|
clazz.name.should == 'Cucumber::Formatter::Html'
|
10
10
|
end
|
11
|
+
|
12
|
+
it "fails to load a made up class" do
|
13
|
+
expect { constantize('My::MadeUp::ClassName') }.to raise_error(LoadError)
|
14
|
+
end
|
11
15
|
end
|
12
|
-
end
|
16
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'cucumber/formatter/interceptor'
|
3
|
+
|
4
|
+
module Cucumber::Formatter
|
5
|
+
describe Interceptor::Pipe do
|
6
|
+
let(:pipe) do
|
7
|
+
pipe = double('original pipe')
|
8
|
+
pipe.stub(:instance_of?).and_return(true)
|
9
|
+
pipe
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#wrap!' do
|
13
|
+
it 'should raise an ArgumentError if its not passed :stderr/:stdout' do
|
14
|
+
expect {
|
15
|
+
Interceptor::Pipe.wrap(:nonsense)
|
16
|
+
}.to raise_error(ArgumentError)
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'when passed :stderr' do
|
21
|
+
before :each do
|
22
|
+
@stderr = $stdout
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should wrap $stderr' do
|
26
|
+
wrapped = Interceptor::Pipe.wrap(:stderr)
|
27
|
+
$stderr.should be_instance_of Interceptor::Pipe
|
28
|
+
$stderr.should be wrapped
|
29
|
+
end
|
30
|
+
|
31
|
+
after :each do
|
32
|
+
$stderr = @stderr
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'when passed :stdout' do
|
37
|
+
before :each do
|
38
|
+
@stdout = $stdout
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should wrap $stdout' do
|
42
|
+
wrapped = Interceptor::Pipe.wrap(:stdout)
|
43
|
+
$stdout.should be_instance_of Interceptor::Pipe
|
44
|
+
$stdout.should be wrapped
|
45
|
+
end
|
46
|
+
|
47
|
+
after :each do
|
48
|
+
$stdout = @stdout
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe '#unwrap!' do
|
54
|
+
before :each do
|
55
|
+
@stdout = $stdout
|
56
|
+
@wrapped = Interceptor::Pipe.wrap(:stdout)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should raise an ArgumentError if it wasn\'t passed :stderr/:stdout' do
|
60
|
+
expect {
|
61
|
+
Interceptor::Pipe.unwrap!(:nonsense)
|
62
|
+
}.to raise_error(ArgumentError)
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'should reset $stdout when #unwrap! is called' do
|
66
|
+
interceptor = Interceptor::Pipe.unwrap! :stdout
|
67
|
+
interceptor.should be_instance_of Interceptor::Pipe
|
68
|
+
$stdout.should_not be interceptor
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should disable the pipe bypass' do
|
72
|
+
buffer = '(::)'
|
73
|
+
Interceptor::Pipe.unwrap! :stdout
|
74
|
+
|
75
|
+
@wrapped.should_receive(:write).with(buffer)
|
76
|
+
@wrapped.buffer.should_not_receive(:<<)
|
77
|
+
@wrapped.write(buffer)
|
78
|
+
end
|
79
|
+
|
80
|
+
after :each do
|
81
|
+
$stdout = @stdout
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe '#write' do
|
86
|
+
let(:buffer) { 'Some stupid buffer' }
|
87
|
+
let(:pi) { Interceptor::Pipe.new(pipe) }
|
88
|
+
|
89
|
+
it 'should write arguments to the original pipe' do
|
90
|
+
pipe.should_receive(:write).with(buffer).and_return(buffer.size)
|
91
|
+
pi.write(buffer).should == buffer.size
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'should add the buffer to its stored output' do
|
95
|
+
pipe.stub(:write)
|
96
|
+
pi.write(buffer)
|
97
|
+
pi.buffer.should_not be_empty
|
98
|
+
pi.buffer.first.should == buffer
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe '#method_missing' do
|
103
|
+
let(:pi) { Interceptor::Pipe.new(pipe) }
|
104
|
+
|
105
|
+
it 'should pass #tty? to the original pipe' do
|
106
|
+
pipe.should_receive(:tty?).and_return(true)
|
107
|
+
pi.tty?.should be true
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|