cucumber 1.1.9 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|