cucumber 1.1.9 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. data/.travis.yml +9 -0
  2. data/History.md +20 -3
  3. data/README.md +1 -2
  4. data/cucumber.gemspec +10 -13
  5. data/cucumber.yml +2 -2
  6. data/features/.cucumber/stepdefs.json +13 -391
  7. data/features/backtraces.feature +36 -0
  8. data/features/{issue_117.feature → drb_server_integration.feature} +3 -3
  9. data/features/formatter_step_file_colon_line.feature +46 -0
  10. data/features/{issue_57.feature → rerun_formatter.feature} +2 -2
  11. data/features/run_specific_scenarios.feature +47 -0
  12. data/gem_tasks/cucumber.rake +15 -8
  13. data/legacy_features/cucumber_cli.feature +0 -7
  14. data/legacy_features/junit_formatter.feature +60 -10
  15. data/legacy_features/language_help.feature +1 -0
  16. data/lib/cucumber.rb +2 -1
  17. data/lib/cucumber/ast/step.rb +1 -1
  18. data/lib/cucumber/ast/step_invocation.rb +2 -15
  19. data/lib/cucumber/ast/table.rb +16 -6
  20. data/lib/cucumber/ast/tree_walker.rb +5 -5
  21. data/lib/cucumber/cli/options.rb +5 -8
  22. data/lib/cucumber/formatter/ansicolor.rb +7 -12
  23. data/lib/cucumber/formatter/cucumber.css +7 -1
  24. data/lib/cucumber/formatter/gherkin_formatter_adapter.rb +1 -1
  25. data/lib/cucumber/formatter/html.rb +5 -5
  26. data/lib/cucumber/formatter/interceptor.rb +62 -0
  27. data/lib/cucumber/formatter/junit.rb +30 -14
  28. data/lib/cucumber/formatter/pretty.rb +3 -3
  29. data/lib/cucumber/formatter/progress.rb +1 -1
  30. data/lib/cucumber/formatter/rerun.rb +1 -1
  31. data/lib/cucumber/formatter/usage.rb +1 -1
  32. data/lib/cucumber/js_support/js_snippets.rb +1 -1
  33. data/lib/cucumber/platform.rb +1 -1
  34. data/lib/cucumber/rb_support/rb_dsl.rb +15 -8
  35. data/lib/cucumber/rb_support/rb_language.rb +3 -3
  36. data/lib/cucumber/rb_support/rb_step_definition.rb +17 -5
  37. data/lib/cucumber/term/ansicolor.rb +118 -0
  38. data/spec/cucumber/ast/table_spec.rb +9 -0
  39. data/spec/cucumber/cli/configuration_spec.rb +12 -6
  40. data/spec/cucumber/cli/options_spec.rb +9 -3
  41. data/spec/cucumber/constantize_spec.rb +5 -1
  42. data/spec/cucumber/formatter/ansicolor_spec.rb +1 -1
  43. data/spec/cucumber/formatter/interceptor_spec.rb +111 -0
  44. data/spec/cucumber/formatter/junit_spec.rb +36 -20
  45. data/spec/cucumber/formatter/progress_spec.rb +2 -2
  46. data/spec/cucumber/rb_support/rb_language_spec.rb +5 -5
  47. data/spec/cucumber/rb_support/rb_step_definition_spec.rb +17 -1
  48. data/spec/cucumber/rb_support/regexp_argument_matcher_spec.rb +6 -2
  49. data/spec/cucumber/step_match_spec.rb +8 -4
  50. data/spec/spec_helper.rb +15 -1
  51. metadata +215 -82
  52. data/.gitmodules +0 -3
  53. 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
 
@@ -1,7 +1,7 @@
1
1
  module Cucumber
2
2
  module JsSupport
3
3
  module JsSnippets
4
- PARAM_PATTERN = /"([^"]*)"/
4
+ PARAM_PATTERN = /"(.*?)"/
5
5
  ESCAPED_PARAM_PATTERN = '"([^\\"]*)"'
6
6
 
7
7
  def snippet_text(code_keyword, step_name, multiline_arg_class)
@@ -4,7 +4,7 @@ require 'rbconfig'
4
4
 
5
5
  module Cucumber
6
6
  unless defined?(Cucumber::VERSION)
7
- VERSION = '1.1.9'
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, proc)
27
- @rb_language.register_rb_step_definition(regexp, proc)
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
- # The +&proc+ gets executed in the context of a <tt>World</tt>
102
- # object, which is defined by #World. A new <tt>World</tt>
103
- # object is created for each scenario and is shared across
104
- # step definitions within that scenario.
105
- def register_rb_step_definition(regexp, &proc)
106
- RbDsl.register_rb_step_definition(regexp, proc)
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 = ['"([^"]*)"', '(\d+)']
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, proc)
114
- step_definition = RbStepDefinition.new(self, regexp, proc)
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, proc)
27
- raise MissingProc if proc.nil?
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, proc
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.file_colon_line
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
- config.parse!([])
409
- config.tag_expression.should be_empty
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
- config.parse!(['--tags','@foo'])
414
- config.tag_expression.should_not be_empty
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
- when_parsing '--i18n help' do
60
- Kernel.should_receive(:exit)
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
- when_parsing('--i18n help') { Kernel.should_receive(:exit) }
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
@@ -23,7 +23,7 @@ module Cucumber
23
23
  end
24
24
 
25
25
  it "should not generate ansi codes when colors are disabled" do
26
- ::Term::ANSIColor.coloring = false
26
+ ::Cucumber::Term::ANSIColor.coloring = false
27
27
  passed("foo").should == "foo"
28
28
  end
29
29
  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