cucumber 3.2.0 → 5.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +280 -19
- data/CONTRIBUTING.md +11 -25
- data/README.md +4 -5
- data/bin/cucumber +1 -1
- data/lib/autotest/cucumber_mixin.rb +46 -53
- data/lib/cucumber/cli/configuration.rb +5 -5
- data/lib/cucumber/cli/main.rb +12 -12
- data/lib/cucumber/cli/options.rb +90 -73
- data/lib/cucumber/cli/profile_loader.rb +49 -26
- data/lib/cucumber/configuration.rb +44 -29
- data/lib/cucumber/constantize.rb +2 -5
- data/lib/cucumber/deprecate.rb +31 -7
- data/lib/cucumber/errors.rb +5 -7
- data/lib/cucumber/events/envelope.rb +9 -0
- data/lib/cucumber/events/gherkin_source_parsed.rb +11 -0
- data/lib/cucumber/events/hook_test_step_created.rb +13 -0
- data/lib/cucumber/events/step_activated.rb +2 -1
- data/lib/cucumber/events/test_case_created.rb +13 -0
- data/lib/cucumber/events/test_case_ready.rb +12 -0
- data/lib/cucumber/events/test_step_created.rb +13 -0
- data/lib/cucumber/events/undefined_parameter_type.rb +10 -0
- data/lib/cucumber/events.rb +13 -6
- data/lib/cucumber/file_specs.rb +6 -6
- data/lib/cucumber/filters/activate_steps.rb +5 -3
- data/lib/cucumber/filters/broadcast_test_case_ready_event.rb +12 -0
- data/lib/cucumber/filters/prepare_world.rb +5 -9
- data/lib/cucumber/filters/quit.rb +1 -3
- data/lib/cucumber/filters/tag_limits/verifier.rb +2 -4
- data/lib/cucumber/filters.rb +1 -0
- data/lib/cucumber/formatter/ansicolor.rb +40 -45
- data/lib/cucumber/formatter/ast_lookup.rb +163 -0
- data/lib/cucumber/formatter/backtrace_filter.rb +9 -8
- data/lib/cucumber/formatter/console.rb +58 -66
- data/lib/cucumber/formatter/console_counts.rb +4 -9
- data/lib/cucumber/formatter/console_issues.rb +6 -3
- data/lib/cucumber/formatter/duration.rb +1 -1
- data/lib/cucumber/formatter/duration_extractor.rb +3 -1
- data/lib/cucumber/formatter/errors.rb +6 -0
- data/lib/cucumber/formatter/fanout.rb +2 -0
- data/lib/cucumber/formatter/html.rb +11 -598
- data/lib/cucumber/formatter/http_io.rb +43 -42
- data/lib/cucumber/formatter/ignore_missing_messages.rb +1 -1
- data/lib/cucumber/formatter/interceptor.rb +11 -30
- data/lib/cucumber/formatter/io.rb +46 -10
- data/lib/cucumber/formatter/json.rb +102 -116
- data/lib/cucumber/formatter/junit.rb +55 -55
- data/lib/cucumber/formatter/message.rb +22 -0
- data/lib/cucumber/formatter/message_builder.rb +255 -0
- data/lib/cucumber/formatter/pretty.rb +359 -153
- data/lib/cucumber/formatter/progress.rb +30 -32
- data/lib/cucumber/formatter/publish_banner_printer.rb +77 -0
- data/lib/cucumber/formatter/query/hook_by_test_step.rb +31 -0
- data/lib/cucumber/formatter/query/pickle_by_test.rb +26 -0
- data/lib/cucumber/formatter/query/pickle_step_by_test_step.rb +26 -0
- data/lib/cucumber/formatter/query/step_definitions_by_test_step.rb +40 -0
- data/lib/cucumber/formatter/query/test_case_started_by_test_case.rb +40 -0
- data/lib/cucumber/formatter/rerun.rb +22 -4
- data/lib/cucumber/formatter/stepdefs.rb +1 -2
- data/lib/cucumber/formatter/steps.rb +3 -4
- data/lib/cucumber/formatter/summary.rb +16 -8
- data/lib/cucumber/formatter/unicode.rb +15 -17
- data/lib/cucumber/formatter/url_reporter.rb +17 -0
- data/lib/cucumber/formatter/usage.rb +11 -10
- data/lib/cucumber/gherkin/data_table_parser.rb +17 -6
- data/lib/cucumber/gherkin/formatter/ansi_escapes.rb +13 -17
- data/lib/cucumber/gherkin/formatter/escaping.rb +2 -2
- data/lib/cucumber/gherkin/steps_parser.rb +17 -8
- data/lib/cucumber/glue/hook.rb +34 -11
- data/lib/cucumber/glue/invoke_in_world.rb +13 -18
- data/lib/cucumber/glue/proto_world.rb +42 -33
- data/lib/cucumber/glue/registry_and_more.rb +42 -12
- data/lib/cucumber/glue/snippet.rb +23 -22
- data/lib/cucumber/glue/step_definition.rb +42 -19
- data/lib/cucumber/glue/world_factory.rb +1 -1
- data/lib/cucumber/hooks.rb +11 -11
- data/lib/cucumber/multiline_argument/data_table/diff_matrices.rb +2 -2
- data/lib/cucumber/multiline_argument/data_table.rb +97 -64
- data/lib/cucumber/multiline_argument/doc_string.rb +1 -1
- data/lib/cucumber/multiline_argument.rb +4 -6
- data/lib/cucumber/platform.rb +3 -3
- data/lib/cucumber/rake/task.rb +16 -18
- data/lib/cucumber/rspec/disable_option_parser.rb +9 -8
- data/lib/cucumber/rspec/doubles.rb +3 -5
- data/lib/cucumber/running_test_case.rb +2 -53
- data/lib/cucumber/runtime/after_hooks.rb +8 -4
- data/lib/cucumber/runtime/before_hooks.rb +8 -4
- data/lib/cucumber/runtime/for_programming_languages.rb +4 -2
- data/lib/cucumber/runtime/step_hooks.rb +6 -2
- data/lib/cucumber/runtime/support_code.rb +13 -15
- data/lib/cucumber/runtime/user_interface.rb +6 -16
- data/lib/cucumber/runtime.rb +41 -58
- data/lib/cucumber/step_definition_light.rb +4 -3
- data/lib/cucumber/step_definitions.rb +2 -2
- data/lib/cucumber/step_match.rb +12 -11
- data/lib/cucumber/step_match_search.rb +2 -1
- data/lib/cucumber/term/ansicolor.rb +9 -9
- data/lib/cucumber/term/banner.rb +56 -0
- data/lib/cucumber/version +1 -1
- data/lib/cucumber.rb +1 -1
- metadata +253 -80
- data/lib/cucumber/formatter/cucumber.css +0 -286
- data/lib/cucumber/formatter/cucumber.sass +0 -247
- data/lib/cucumber/formatter/hook_query_visitor.rb +0 -42
- data/lib/cucumber/formatter/html_builder.rb +0 -121
- data/lib/cucumber/formatter/inline-js.js +0 -30
- data/lib/cucumber/formatter/jquery-min.js +0 -154
- data/lib/cucumber/formatter/json_pretty.rb +0 -11
- data/lib/cucumber/formatter/legacy_api/adapter.rb +0 -1028
- data/lib/cucumber/formatter/legacy_api/ast.rb +0 -394
- data/lib/cucumber/formatter/legacy_api/results.rb +0 -50
- data/lib/cucumber/formatter/legacy_api/runtime_facade.rb +0 -32
- data/lib/cucumber/step_argument.rb +0 -25
@@ -1,80 +1,82 @@
|
|
1
1
|
require 'net/http'
|
2
2
|
require 'tempfile'
|
3
|
+
require 'shellwords'
|
3
4
|
|
4
5
|
module Cucumber
|
5
6
|
module Formatter
|
6
7
|
class HTTPIO
|
7
8
|
class << self
|
8
9
|
# Returns an IO that will write to a HTTP request's body
|
9
|
-
|
10
|
+
# https_verify_mode can be set to OpenSSL::SSL::VERIFY_NONE
|
11
|
+
# to ignore unsigned certificate - setting to nil will verify the certificate
|
12
|
+
def open(url, https_verify_mode = nil, reporter = nil)
|
10
13
|
@https_verify_mode = https_verify_mode
|
11
14
|
uri, method, headers = CurlOptionParser.parse(url)
|
12
|
-
IOHTTPBuffer.new(uri, method, headers, https_verify_mode)
|
15
|
+
IOHTTPBuffer.new(uri, method, headers, https_verify_mode, reporter)
|
13
16
|
end
|
14
17
|
end
|
15
18
|
end
|
16
19
|
|
17
20
|
class CurlOptionParser
|
18
21
|
def self.parse(options)
|
19
|
-
|
20
|
-
http_method = 'PUT'
|
21
|
-
url = chunks[0]
|
22
|
-
headers = ''
|
23
|
-
|
24
|
-
last_flag = nil
|
25
|
-
chunks.each do |chunk|
|
26
|
-
if ['-X', '--request'].include?(chunk)
|
27
|
-
last_flag = '-X'
|
28
|
-
next
|
29
|
-
end
|
22
|
+
args = Shellwords.split(options)
|
30
23
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
24
|
+
url = nil
|
25
|
+
http_method = 'PUT'
|
26
|
+
headers = {}
|
27
|
+
|
28
|
+
until args.empty?
|
29
|
+
arg = args.shift
|
30
|
+
case arg
|
31
|
+
when '-X', '--request'
|
32
|
+
http_method = remove_arg_for(args, arg)
|
33
|
+
when '-H'
|
34
|
+
header_arg = remove_arg_for(args, arg)
|
35
|
+
headers = headers.merge(parse_header(header_arg))
|
36
|
+
else
|
37
|
+
raise StandardError, "#{options} was not a valid curl command. Can't set url to #{arg} it is already set to #{url}" if url
|
38
|
+
url = arg
|
39
39
|
end
|
40
|
-
|
41
|
-
headers += chunk if last_flag == '-H'
|
42
40
|
end
|
41
|
+
raise StandardError, "#{options} was not a valid curl command" unless url
|
43
42
|
|
44
43
|
[
|
45
44
|
url,
|
46
45
|
http_method,
|
47
|
-
|
46
|
+
headers
|
48
47
|
]
|
49
48
|
end
|
50
49
|
|
51
|
-
def self.
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
headers.scan(str_scanner) do |header|
|
56
|
-
header = header.compact!
|
57
|
-
hash_headers[header[0]] = header[1] ? header[1].strip : header[1]
|
58
|
-
end
|
50
|
+
def self.remove_arg_for(args, arg)
|
51
|
+
return args.shift unless args.empty?
|
52
|
+
raise StandardError, "Missing argument for #{arg}"
|
53
|
+
end
|
59
54
|
|
60
|
-
|
55
|
+
def self.parse_header(header_arg)
|
56
|
+
parts = header_arg.split(':', 2)
|
57
|
+
raise StandardError, "#{header_arg} was not a valid header" unless parts.length == 2
|
58
|
+
{ parts[0].strip => parts[1].strip }
|
61
59
|
end
|
62
60
|
end
|
63
61
|
|
64
62
|
class IOHTTPBuffer
|
65
63
|
attr_reader :uri, :method, :headers
|
66
64
|
|
67
|
-
def initialize(uri, method, headers = {}, https_verify_mode = nil)
|
65
|
+
def initialize(uri, method, headers = {}, https_verify_mode = nil, reporter = nil)
|
68
66
|
@uri = URI(uri)
|
69
67
|
@method = method
|
70
68
|
@headers = headers
|
71
69
|
@write_io = Tempfile.new('cucumber', encoding: 'UTF-8')
|
72
70
|
@https_verify_mode = https_verify_mode
|
71
|
+
@reporter = reporter || NoReporter.new
|
73
72
|
end
|
74
73
|
|
75
74
|
def close
|
76
|
-
|
75
|
+
response = send_content(@uri, @method, @headers)
|
76
|
+
@reporter.report(response.body)
|
77
77
|
@write_io.close
|
78
|
+
return if response.is_a?(Net::HTTPSuccess) || response.is_a?(Net::HTTPRedirection)
|
79
|
+
raise StandardError, "request to #{uri} failed with status #{response.code}"
|
78
80
|
end
|
79
81
|
|
80
82
|
def write(data)
|
@@ -91,8 +93,8 @@ module Cucumber
|
|
91
93
|
|
92
94
|
private
|
93
95
|
|
94
|
-
def
|
95
|
-
content = @write_io
|
96
|
+
def send_content(uri, method, headers, attempt = 10)
|
97
|
+
content = (method == 'GET' ? StringIO.new : @write_io)
|
96
98
|
http = build_client(uri, @https_verify_mode)
|
97
99
|
|
98
100
|
raise StandardError, "request to #{uri} failed (too many redirections)" if attempt <= 0
|
@@ -115,13 +117,12 @@ module Cucumber
|
|
115
117
|
end
|
116
118
|
|
117
119
|
case response
|
118
|
-
when Net::
|
119
|
-
response
|
120
|
+
when Net::HTTPAccepted
|
121
|
+
send_content(URI(response['Location']), 'PUT', {}, attempt - 1) if response['Location']
|
120
122
|
when Net::HTTPRedirection
|
121
|
-
|
122
|
-
else
|
123
|
-
raise StandardError, "request to #{uri} failed with status #{response.code}"
|
123
|
+
send_content(URI(response['Location']), method, headers, attempt - 1)
|
124
124
|
end
|
125
|
+
response
|
125
126
|
end
|
126
127
|
|
127
128
|
def build_request(uri, method, headers)
|
@@ -8,7 +8,7 @@ module Cucumber
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def method_missing(message, *args)
|
11
|
-
@receiver.
|
11
|
+
@receiver.respond_to?(message) ? @receiver.send(message, *args) : super
|
12
12
|
end
|
13
13
|
|
14
14
|
def respond_to_missing?(name, include_private = false)
|
@@ -5,34 +5,23 @@ module Cucumber
|
|
5
5
|
module Interceptor
|
6
6
|
class Pipe
|
7
7
|
attr_reader :pipe
|
8
|
+
|
8
9
|
def initialize(pipe)
|
9
10
|
@pipe = pipe
|
10
11
|
@buffer = StringIO.new
|
11
12
|
@wrapped = true
|
13
|
+
@lock = Mutex.new
|
12
14
|
end
|
13
15
|
|
14
16
|
def write(str)
|
15
|
-
lock.synchronize do
|
17
|
+
@lock.synchronize do
|
16
18
|
@buffer << str if @wrapped
|
17
19
|
return @pipe.write(str)
|
18
20
|
end
|
19
21
|
end
|
20
22
|
|
21
|
-
# @deprecated use #buffer_string
|
22
|
-
def buffer
|
23
|
-
require 'cucumber/deprecate.rb'
|
24
|
-
Cucumber.deprecate(
|
25
|
-
'Use Cucumber::Formatter::Interceptor::Pipe#buffer_string instead',
|
26
|
-
'Cucumber::Formatter::Interceptor::Pipe#buffer',
|
27
|
-
'3.99'
|
28
|
-
)
|
29
|
-
lock.synchronize do
|
30
|
-
return @buffer.string.lines
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
23
|
def buffer_string
|
35
|
-
lock.synchronize do
|
24
|
+
@lock.synchronize do
|
36
25
|
return @buffer.string.dup
|
37
26
|
end
|
38
27
|
end
|
@@ -43,17 +32,15 @@ module Cucumber
|
|
43
32
|
end
|
44
33
|
|
45
34
|
def method_missing(method, *args, &blk)
|
46
|
-
@pipe.send(method, *args, &blk)
|
35
|
+
@pipe.respond_to?(method) ? @pipe.send(method, *args, &blk) : super
|
47
36
|
end
|
48
37
|
|
49
|
-
def
|
38
|
+
def respond_to_missing?(method, include_private = false)
|
50
39
|
super || @pipe.respond_to?(method, include_private)
|
51
40
|
end
|
52
41
|
|
53
42
|
def self.validate_pipe(pipe)
|
54
|
-
unless [
|
55
|
-
raise ArgumentError, '#wrap only accepts :stderr or :stdout'
|
56
|
-
end
|
43
|
+
raise ArgumentError, '#wrap only accepts :stderr or :stdout' unless %i[stdout stderr].include? pipe
|
57
44
|
end
|
58
45
|
|
59
46
|
def self.unwrap!(pipe)
|
@@ -75,19 +62,13 @@ module Cucumber
|
|
75
62
|
|
76
63
|
case pipe
|
77
64
|
when :stderr
|
78
|
-
$stderr =
|
79
|
-
|
65
|
+
$stderr = new($stderr)
|
66
|
+
$stderr
|
80
67
|
when :stdout
|
81
|
-
$stdout =
|
82
|
-
|
68
|
+
$stdout = new($stdout)
|
69
|
+
$stdout
|
83
70
|
end
|
84
71
|
end
|
85
|
-
|
86
|
-
private
|
87
|
-
|
88
|
-
def lock
|
89
|
-
@lock ||= Mutex.new
|
90
|
-
end
|
91
72
|
end
|
92
73
|
end
|
93
74
|
end
|
@@ -1,34 +1,70 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'cucumber/formatter/http_io'
|
4
|
+
require 'cucumber/formatter/url_reporter'
|
5
|
+
require 'cucumber/cli/options'
|
4
6
|
|
5
7
|
module Cucumber
|
6
8
|
module Formatter
|
7
9
|
module Io
|
8
10
|
module_function
|
9
11
|
|
10
|
-
def ensure_io(path_or_url_or_io)
|
12
|
+
def ensure_io(path_or_url_or_io, error_stream)
|
11
13
|
return nil if path_or_url_or_io.nil?
|
12
|
-
return path_or_url_or_io if
|
13
|
-
|
14
|
-
|
14
|
+
return path_or_url_or_io if io?(path_or_url_or_io)
|
15
|
+
|
16
|
+
io = if url?(path_or_url_or_io)
|
17
|
+
url = path_or_url_or_io
|
18
|
+
reporter = url.start_with?(Cucumber::Cli::Options::CUCUMBER_PUBLISH_URL) ? URLReporter.new(error_stream) : NoReporter.new
|
19
|
+
HTTPIO.open(url, nil, reporter)
|
15
20
|
else
|
16
21
|
File.open(path_or_url_or_io, Cucumber.file_mode('w'))
|
17
22
|
end
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
23
|
+
@io_objects_to_close ||= []
|
24
|
+
@io_objects_to_close.push(io)
|
25
|
+
io
|
26
|
+
end
|
27
|
+
|
28
|
+
module ClassMethods
|
29
|
+
def new(*args, &block)
|
30
|
+
instance = super
|
31
|
+
|
32
|
+
config = args[0]
|
33
|
+
if config.respond_to? :on_event
|
34
|
+
config.on_event :test_run_finished do
|
35
|
+
ios = instance.instance_variable_get(:@io_objects_to_close) || []
|
36
|
+
ios.each do |io|
|
37
|
+
at_exit do
|
38
|
+
unless io.closed?
|
39
|
+
io.flush
|
40
|
+
io.close
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
22
45
|
end
|
46
|
+
|
47
|
+
instance
|
23
48
|
end
|
24
|
-
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.included(formatter_class)
|
52
|
+
formatter_class.extend(ClassMethods)
|
53
|
+
end
|
54
|
+
|
55
|
+
def io?(path_or_url_or_io)
|
56
|
+
path_or_url_or_io.respond_to?(:write)
|
57
|
+
end
|
58
|
+
|
59
|
+
def url?(path_or_url_or_io)
|
60
|
+
path_or_url_or_io.match(%r{^https?://})
|
25
61
|
end
|
26
62
|
|
27
63
|
def ensure_file(path, name)
|
28
64
|
raise "You *must* specify --out FILE for the #{name} formatter" unless String == path.class
|
29
65
|
raise "I can't write #{name} to a directory - it has to be a file" if File.directory?(path)
|
30
66
|
raise "I can't write #{name} to a file in the non-existing directory #{File.dirname(path)}" unless File.directory?(File.dirname(path))
|
31
|
-
ensure_io(path)
|
67
|
+
ensure_io(path, nil)
|
32
68
|
end
|
33
69
|
|
34
70
|
def ensure_dir(path, name)
|