cucumber 0.4.5.rc2 → 0.5.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/.gitignore +1 -0
- data/History.txt +11 -2
- data/Rakefile +12 -11
- data/VERSION.yml +2 -3
- data/cucumber.gemspec +39 -31
- data/cucumber.yml +1 -1
- data/features/language_help.feature +2 -2
- data/features/wire_protocol.feature +167 -48
- data/features/wire_protocol_table_diffing.feature +95 -0
- data/lib/cucumber/cli/configuration.rb +7 -1
- data/lib/cucumber/cli/main.rb +6 -2
- data/lib/cucumber/cli/options.rb +9 -9
- data/lib/cucumber/feature_file.rb +1 -1
- data/lib/cucumber/formatter/color_io.rb +4 -4
- data/lib/cucumber/formatter/html.rb +4 -3
- data/lib/cucumber/formatter/tag_cloud.rb +1 -0
- data/lib/cucumber/formatter/unicode.rb +28 -23
- data/lib/cucumber/languages.yml +1 -1
- data/lib/cucumber/step_argument.rb +3 -3
- data/lib/cucumber/step_match.rb +2 -2
- data/lib/cucumber/wire_support/connection.rb +4 -0
- data/lib/cucumber/wire_support/request_handler.rb +1 -1
- data/lib/cucumber/wire_support/wire_exception.rb +23 -1
- data/lib/cucumber/wire_support/wire_language.rb +4 -1
- data/lib/cucumber/wire_support/wire_packet.rb +0 -4
- data/lib/cucumber/wire_support/wire_protocol.rb +51 -7
- data/lib/cucumber/wire_support/wire_step_definition.rb +14 -9
- data/spec/cucumber/cli/options_spec.rb +4 -8
- data/spec/cucumber/formatter/color_io_spec.rb +7 -5
- data/spec/cucumber/rb_support/regexp_argument_matcher_spec.rb +2 -2
- data/spec/cucumber/step_match_spec.rb +6 -1
- data/spec/cucumber/wire_support/wire_exception_spec.rb +44 -0
- data/spec/cucumber/wire_support/wire_step_definition_spec.rb +20 -0
- metadata +30 -15
@@ -0,0 +1,95 @@
|
|
1
|
+
@wire
|
2
|
+
Feature: Wire protocol table diffing
|
3
|
+
In order to use the amazing functionality in the Cucumber table object
|
4
|
+
As a wire server
|
5
|
+
I want to be able to ask for a table diff during a step definition invocation
|
6
|
+
|
7
|
+
Background:
|
8
|
+
Given a standard Cucumber project directory structure
|
9
|
+
And a file named "features/wired.feature" with:
|
10
|
+
"""
|
11
|
+
Scenario: Wired
|
12
|
+
Given we're all wired
|
13
|
+
|
14
|
+
"""
|
15
|
+
And a file named "features/step_definitions/some_remote_place.wire" with:
|
16
|
+
"""
|
17
|
+
host: localhost
|
18
|
+
port: 54321
|
19
|
+
|
20
|
+
"""
|
21
|
+
|
22
|
+
Scenario: Invoke a step definition tries to diff the table and fails
|
23
|
+
Given there is a wire server running on port 54321 which understands the following protocol:
|
24
|
+
| request | response |
|
25
|
+
| ["step_matches",{"name_to_match":"we're all wired"}] | ["step_matches",[{"id":"1", "args":[]}]] |
|
26
|
+
| ["begin_scenario",null] | ["success",null] |
|
27
|
+
| ["invoke",{"id":"1","args":[]}] | ["diff",[[["a","b"],["c","d"]],[["x","y"],["z","z"]]]] |
|
28
|
+
| ["diff_failed",null] | ["step_failed",{"message":"Not same", "exception":"DifferentException", "backtrace":["a.cs:12","b.cs:34"]}] |
|
29
|
+
| ["end_scenario",null] | ["success",null] |
|
30
|
+
When I run cucumber -f progress --backtrace
|
31
|
+
And it should fail with
|
32
|
+
"""
|
33
|
+
F
|
34
|
+
|
35
|
+
(::) failed steps (::)
|
36
|
+
|
37
|
+
Not same (DifferentException from localhost:54321)
|
38
|
+
a.cs:12
|
39
|
+
b.cs:34
|
40
|
+
features/wired.feature:2:in `Given we're all wired'
|
41
|
+
|
42
|
+
Failing Scenarios:
|
43
|
+
cucumber features/wired.feature:1 # Scenario: Wired
|
44
|
+
|
45
|
+
1 scenario (1 failed)
|
46
|
+
1 step (1 failed)
|
47
|
+
|
48
|
+
"""
|
49
|
+
|
50
|
+
Scenario: Invoke a step definition tries to diff the table and passes
|
51
|
+
Given there is a wire server running on port 54321 which understands the following protocol:
|
52
|
+
| request | response |
|
53
|
+
| ["step_matches",{"name_to_match":"we're all wired"}] | ["step_matches",[{"id":"1", "args":[]}]] |
|
54
|
+
| ["begin_scenario",null] | ["success",null] |
|
55
|
+
| ["invoke",{"id":"1","args":[]}] | ["diff",[[["a"],["b"]],[["a"],["b"]]]] |
|
56
|
+
| ["diff_ok",null] | ["success",null] |
|
57
|
+
| ["end_scenario",null] | ["success",null] |
|
58
|
+
When I run cucumber -f progress
|
59
|
+
And it should pass with
|
60
|
+
"""
|
61
|
+
.
|
62
|
+
|
63
|
+
1 scenario (1 passed)
|
64
|
+
1 step (1 passed)
|
65
|
+
|
66
|
+
"""
|
67
|
+
|
68
|
+
Scenario: Invoke a step definition which successfully diffs a table but then fails
|
69
|
+
Given there is a wire server running on port 54321 which understands the following protocol:
|
70
|
+
| request | response |
|
71
|
+
| ["step_matches",{"name_to_match":"we're all wired"}] | ["step_matches",[{"id":"1", "args":[]}]] |
|
72
|
+
| ["begin_scenario",null] | ["success",null] |
|
73
|
+
| ["invoke",{"id":"1","args":[]}] | ["diff",[[["a"],["b"]],[["a"],["b"]]]] |
|
74
|
+
| ["diff_ok",null] | ["step_failed",{"message":"I wanted things to be different for us"}] |
|
75
|
+
| ["end_scenario",null] | ["success",null] |
|
76
|
+
When I run cucumber -f progress
|
77
|
+
And it should fail with
|
78
|
+
"""
|
79
|
+
F
|
80
|
+
|
81
|
+
(::) failed steps (::)
|
82
|
+
|
83
|
+
I wanted things to be different for us (Cucumber::WireSupport::WireException)
|
84
|
+
features/wired.feature:2:in `Given we're all wired'
|
85
|
+
|
86
|
+
Failing Scenarios:
|
87
|
+
cucumber features/wired.feature:1 # Scenario: Wired
|
88
|
+
|
89
|
+
1 scenario (1 failed)
|
90
|
+
1 step (1 failed)
|
91
|
+
|
92
|
+
"""
|
93
|
+
|
94
|
+
|
95
|
+
|
@@ -127,7 +127,13 @@ module Cucumber
|
|
127
127
|
private
|
128
128
|
|
129
129
|
def formatters(step_mother)
|
130
|
-
|
130
|
+
# TODO: We should remove the autoformat functionality. That
|
131
|
+
# can be done with the gherkin CLI.
|
132
|
+
if @options[:autoformat]
|
133
|
+
require 'cucumber/formatter/pretty'
|
134
|
+
return [Formatter::Pretty.new(step_mother, nil, @options)]
|
135
|
+
end
|
136
|
+
|
131
137
|
@options[:formats].map do |format_and_out|
|
132
138
|
format = format_and_out[0]
|
133
139
|
path_or_io = format_and_out[1]
|
data/lib/cucumber/cli/main.rb
CHANGED
@@ -5,7 +5,6 @@ require 'logger'
|
|
5
5
|
require 'cucumber/parser'
|
6
6
|
require 'cucumber/feature_file'
|
7
7
|
require 'cucumber/formatter/color_io'
|
8
|
-
require 'cucumber/cli/language_help_formatter'
|
9
8
|
require 'cucumber/cli/configuration'
|
10
9
|
require 'cucumber/cli/drb_client'
|
11
10
|
require 'cucumber/ast/tags'
|
@@ -27,7 +26,12 @@ module Cucumber
|
|
27
26
|
|
28
27
|
def initialize(args, out_stream = STDOUT, error_stream = STDERR)
|
29
28
|
@args = args
|
30
|
-
|
29
|
+
if Cucumber::WINDOWS_MRI
|
30
|
+
@out_stream = out_stream == STDOUT ? Formatter::ColorIO.new(Kernel, STDOUT) : out_stream
|
31
|
+
else
|
32
|
+
@out_stream = out_stream
|
33
|
+
end
|
34
|
+
|
31
35
|
@error_stream = error_stream
|
32
36
|
@configuration = nil
|
33
37
|
end
|
data/lib/cucumber/cli/options.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
require 'cucumber/cli/profile_loader'
|
2
|
+
require 'cucumber/formatter/ansicolor'
|
3
|
+
|
2
4
|
module Cucumber
|
3
5
|
module Cli
|
4
6
|
|
@@ -115,17 +117,13 @@ module Cucumber
|
|
115
117
|
"This option can be specified multiple times.") do |v|
|
116
118
|
@options[:require] << v
|
117
119
|
end
|
118
|
-
opts.on("
|
119
|
-
"
|
120
|
-
%{Run with "--
|
121
|
-
|
122
|
-
if v == 'help'
|
120
|
+
opts.on("--i18n LANG",
|
121
|
+
"List keywords for in a particular language",
|
122
|
+
%{Run with "--i18n help" to see all languages}) do |lang|
|
123
|
+
if lang == 'help'
|
123
124
|
list_languages_and_exit
|
124
|
-
elsif args==['help']
|
125
|
-
list_keywords_and_exit(v)
|
126
125
|
else
|
127
|
-
|
128
|
-
@options[:lang] = v
|
126
|
+
list_keywords_and_exit(lang)
|
129
127
|
end
|
130
128
|
end
|
131
129
|
opts.on("-f FORMAT", "--format FORMAT",
|
@@ -367,11 +365,13 @@ module Cucumber
|
|
367
365
|
unless Cucumber::LANGUAGES[lang]
|
368
366
|
raise("No language with key #{lang}")
|
369
367
|
end
|
368
|
+
require 'cucumber/cli/language_help_formatter'
|
370
369
|
LanguageHelpFormatter.list_keywords(@out_stream, lang)
|
371
370
|
Kernel.exit(0)
|
372
371
|
end
|
373
372
|
|
374
373
|
def list_languages_and_exit
|
374
|
+
require 'cucumber/cli/language_help_formatter'
|
375
375
|
LanguageHelpFormatter.list_languages(@out_stream)
|
376
376
|
Kernel.exit(0)
|
377
377
|
end
|
@@ -23,7 +23,7 @@ module Cucumber
|
|
23
23
|
# be filtered.
|
24
24
|
def parse(step_mother, options)
|
25
25
|
filter = Filter.new(@lines, options)
|
26
|
-
language = Parser::NaturalLanguage.get(step_mother, (lang ||
|
26
|
+
language = Parser::NaturalLanguage.get(step_mother, (lang || 'en'))
|
27
27
|
language.parse(source, @path, filter)
|
28
28
|
end
|
29
29
|
|
@@ -2,15 +2,15 @@ require 'forwardable'
|
|
2
2
|
|
3
3
|
module Cucumber
|
4
4
|
module Formatter
|
5
|
-
# Adapter to make #puts/#print/#flush work with
|
5
|
+
# Adapter to make #puts/#print/#flush work with win32console
|
6
6
|
class ColorIO #:nodoc:
|
7
7
|
extend Forwardable
|
8
8
|
def_delegators :@kernel, :puts, :print # win32console colours only work when sent to Kernel
|
9
9
|
def_delegators :@stdout, :flush, :tty?, :write, :close
|
10
10
|
|
11
|
-
def initialize
|
12
|
-
@kernel =
|
13
|
-
@stdout =
|
11
|
+
def initialize(kernel, stdout)
|
12
|
+
@kernel = kernel
|
13
|
+
@stdout = stdout
|
14
14
|
end
|
15
15
|
|
16
16
|
# Ensure using << still gets colours in win32console
|
@@ -315,16 +315,17 @@ module Cucumber
|
|
315
315
|
backtrace = Array.new
|
316
316
|
@builder.div(:class => 'message') do
|
317
317
|
message = exception.message
|
318
|
-
if message.include?('Exception caught')
|
318
|
+
if defined?(RAILS_ROOT) && message.include?('Exception caught')
|
319
319
|
matches = message.match(/Showing <i>(.+)<\/i>(?:.+)#(\d+)/)
|
320
320
|
backtrace += ["#{RAILS_ROOT}/#{matches[1]}:#{matches[2]}"]
|
321
321
|
message = message.match(/<code>([^(\/)]+)<\//m)[1]
|
322
322
|
end
|
323
|
-
@builder
|
323
|
+
@builder.pre do
|
324
|
+
@builder.text!(message)
|
325
|
+
end
|
324
326
|
end
|
325
327
|
@builder.div(:class => 'backtrace') do
|
326
328
|
@builder.pre do
|
327
|
-
# backtrace += (exception.backtrace.size == 1 || exception.backtrace[0].include?('(eval):')) ? ["#{RAILS_ROOT}/#{@step_match.file_colon_line}"] + exception.backtrace : exception.backtrace
|
328
329
|
backtrace = exception.backtrace
|
329
330
|
backtrace.delete_if { |x| x =~ /\/gems\/(cucumber|rspec)/ }
|
330
331
|
@builder << backtrace_line(backtrace.join("\n"))
|
@@ -1,35 +1,40 @@
|
|
1
1
|
# Require this file if you need Unicode support.
|
2
2
|
require 'cucumber/platform'
|
3
3
|
require 'cucumber/formatter/ansicolor'
|
4
|
-
|
5
4
|
$KCODE='u' unless Cucumber::RUBY_1_9
|
6
5
|
|
7
|
-
if Cucumber::
|
6
|
+
if Cucumber::WINDOWS && `cmd /c chcp` =~ /(\d+)/
|
7
|
+
require 'iconv'
|
8
8
|
codepage = $1.to_i
|
9
|
-
|
9
|
+
Cucumber::CODEPAGE = "cp#{codepage}"
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
end
|
11
|
+
module Cucumber
|
12
|
+
module WindowsOutput #:nodoc:
|
13
|
+
def self.extended(o)
|
14
|
+
o.instance_eval do
|
15
|
+
alias cucumber_print print
|
16
|
+
def print(*a)
|
17
|
+
begin
|
18
|
+
cucumber_print(*Iconv.iconv(Cucumber::CODEPAGE, "UTF-8", *a.map{|a|a.to_s}))
|
19
|
+
rescue Iconv::IllegalSequence
|
20
|
+
cucumber_print(*a)
|
21
|
+
end
|
22
|
+
end
|
24
23
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
24
|
+
alias cucumber_puts puts
|
25
|
+
def puts(*a)
|
26
|
+
begin
|
27
|
+
cucumber_puts(*Iconv.iconv(Cucumber::CODEPAGE, "UTF-8", *a.map{|a|a.to_s}))
|
28
|
+
rescue Iconv::IllegalSequence
|
29
|
+
cucumber_puts(*a)
|
30
|
+
end
|
31
|
+
end
|
31
32
|
end
|
32
33
|
end
|
34
|
+
|
35
|
+
Kernel.extend(self)
|
36
|
+
STDOUT.extend(self)
|
37
|
+
STDERR.extend(self)
|
33
38
|
end
|
34
39
|
end
|
35
|
-
end
|
40
|
+
end
|
data/lib/cucumber/languages.yml
CHANGED
data/lib/cucumber/step_match.rb
CHANGED
@@ -59,7 +59,7 @@ module Cucumber
|
|
59
59
|
s = string.dup
|
60
60
|
offset = 0
|
61
61
|
step_arguments.each do |step_argument|
|
62
|
-
next if step_argument.
|
62
|
+
next if step_argument.byte_offset.nil?
|
63
63
|
replacement = if block_given?
|
64
64
|
proc.call(step_argument.val)
|
65
65
|
elsif Proc === format
|
@@ -68,7 +68,7 @@ module Cucumber
|
|
68
68
|
format % step_argument.val
|
69
69
|
end
|
70
70
|
|
71
|
-
s[step_argument.
|
71
|
+
s[step_argument.byte_offset + offset, step_argument.val.length] = replacement
|
72
72
|
offset += replacement.jlength - step_argument.val.jlength
|
73
73
|
end
|
74
74
|
s
|
@@ -2,8 +2,30 @@ module Cucumber
|
|
2
2
|
module WireSupport
|
3
3
|
# Proxy for an exception that occured at the remote end of the wire
|
4
4
|
class WireException < StandardError
|
5
|
-
|
5
|
+
module CanSetName
|
6
|
+
attr_writer :exception_name
|
7
|
+
def to_s
|
8
|
+
@exception_name
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(args, host, port)
|
6
13
|
super args['message']
|
14
|
+
if args['exception']
|
15
|
+
self.class.extend(CanSetName)
|
16
|
+
self.class.exception_name = "#{args['exception']} from #{host}:#{port}"
|
17
|
+
end
|
18
|
+
if args['backtrace']
|
19
|
+
@backtrace = if args['backtrace'].is_a?(String)
|
20
|
+
args['backtrace'].split("\n") # TODO: change cuke4nuke to pass an array instead of a big string
|
21
|
+
else
|
22
|
+
args['backtrace']
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def backtrace
|
28
|
+
@backtrace || super
|
7
29
|
end
|
8
30
|
end
|
9
31
|
end
|
@@ -29,7 +29,10 @@ module Cucumber
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def snippet_text(step_keyword, step_name, multiline_arg_class)
|
32
|
-
|
32
|
+
snippets = @connections.map do |remote|
|
33
|
+
remote.snippet_text(step_keyword, step_name, multiline_arg_class.to_s)
|
34
|
+
end
|
35
|
+
snippets.flatten.join("\n")
|
33
36
|
end
|
34
37
|
|
35
38
|
protected
|
@@ -22,10 +22,6 @@ module Cucumber
|
|
22
22
|
[@message, @params].to_json
|
23
23
|
end
|
24
24
|
|
25
|
-
def raise_if_bad
|
26
|
-
raise WireException.new(@params) if @message == 'fail' || @message == 'step_failed'
|
27
|
-
end
|
28
|
-
|
29
25
|
def handle_with(handler)
|
30
26
|
handler.send("handle_#{@message}", @params)
|
31
27
|
end
|
@@ -9,7 +9,7 @@ module Cucumber
|
|
9
9
|
make_request(:step_matches, :name_to_match => name_to_match) do
|
10
10
|
def handle_step_matches(params)
|
11
11
|
params.map do |raw_step_match|
|
12
|
-
step_definition = WireStepDefinition.new(
|
12
|
+
step_definition = WireStepDefinition.new(@connection, raw_step_match)
|
13
13
|
step_args = raw_step_match['args'].map do |raw_arg|
|
14
14
|
StepArgument.new(raw_arg['val'], raw_arg['pos'])
|
15
15
|
end
|
@@ -23,12 +23,37 @@ module Cucumber
|
|
23
23
|
StepMatch.new(step_definition, @name_to_match, @name_to_report, step_args)
|
24
24
|
end
|
25
25
|
|
26
|
+
def snippet_text(step_keyword, step_name, multiline_arg_class_name)
|
27
|
+
request_params = { :step_keyword => step_keyword, :step_name => step_name, :multiline_arg_class => multiline_arg_class_name }
|
28
|
+
|
29
|
+
make_request(:snippet_text, request_params) do
|
30
|
+
def handle_snippet_text(text)
|
31
|
+
text
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
26
36
|
def invoke(step_definition_id, args)
|
27
37
|
request_params = { :id => step_definition_id, :args => args }
|
28
|
-
|
38
|
+
|
29
39
|
make_request(:invoke, request_params) do
|
30
40
|
def handle_success(params)
|
31
41
|
end
|
42
|
+
|
43
|
+
def handle_pending(message)
|
44
|
+
raise Pending, message || "TODO"
|
45
|
+
end
|
46
|
+
|
47
|
+
def handle_diff(tables)
|
48
|
+
table1 = Ast::Table.new(tables[0])
|
49
|
+
table2 = Ast::Table.new(tables[1])
|
50
|
+
begin
|
51
|
+
table1.diff!(table2)
|
52
|
+
rescue Cucumber::Ast::Table::Different
|
53
|
+
@connection.diff_failed
|
54
|
+
end
|
55
|
+
@connection.diff_ok
|
56
|
+
end
|
32
57
|
|
33
58
|
def handle_step_failed(params)
|
34
59
|
handle_fail(params)
|
@@ -36,6 +61,28 @@ module Cucumber
|
|
36
61
|
end
|
37
62
|
end
|
38
63
|
|
64
|
+
def diff_failed
|
65
|
+
make_request(:diff_failed) do
|
66
|
+
def handle_success(params)
|
67
|
+
end
|
68
|
+
|
69
|
+
def handle_step_failed(params)
|
70
|
+
handle_fail(params)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def diff_ok
|
76
|
+
make_request(:diff_ok) do
|
77
|
+
def handle_success(params)
|
78
|
+
end
|
79
|
+
|
80
|
+
def handle_step_failed(params)
|
81
|
+
handle_fail(params)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
39
86
|
def begin_scenario(scenario)
|
40
87
|
make_request(:begin_scenario) do
|
41
88
|
def handle_success(params)
|
@@ -52,12 +99,9 @@ module Cucumber
|
|
52
99
|
|
53
100
|
private
|
54
101
|
|
55
|
-
def handler(request_message, &block)
|
56
|
-
RequestHandler.new(self, request_message, &block)
|
57
|
-
end
|
58
|
-
|
59
102
|
def make_request(request_message, params = nil, &block)
|
60
|
-
handler(request_message, &block)
|
103
|
+
handler = RequestHandler.new(self, request_message, &block)
|
104
|
+
handler.execute(params)
|
61
105
|
end
|
62
106
|
end
|
63
107
|
end
|