rspec-core 3.5.4 → 3.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/Changelog.md +165 -2
- data/README.md +16 -16
- data/lib/rspec/core.rb +2 -1
- data/lib/rspec/core/bisect/coordinator.rb +26 -30
- data/lib/rspec/core/bisect/example_minimizer.rb +12 -8
- data/lib/rspec/core/bisect/fork_runner.rb +134 -0
- data/lib/rspec/core/bisect/server.rb +10 -14
- data/lib/rspec/core/bisect/{runner.rb → shell_command.rb} +27 -70
- data/lib/rspec/core/bisect/shell_runner.rb +73 -0
- data/lib/rspec/core/bisect/utilities.rb +58 -0
- data/lib/rspec/core/configuration.rb +315 -79
- data/lib/rspec/core/configuration_options.rb +43 -4
- data/lib/rspec/core/did_you_mean.rb +46 -0
- data/lib/rspec/core/drb.rb +3 -1
- data/lib/rspec/core/example.rb +19 -12
- data/lib/rspec/core/example_group.rb +17 -7
- data/lib/rspec/core/formatters.rb +28 -11
- data/lib/rspec/core/formatters/base_bisect_formatter.rb +45 -0
- data/lib/rspec/core/formatters/base_formatter.rb +1 -1
- data/lib/rspec/core/formatters/base_text_formatter.rb +3 -5
- data/lib/rspec/core/formatters/bisect_drb_formatter.rb +29 -0
- data/lib/rspec/core/formatters/bisect_progress_formatter.rb +29 -16
- data/lib/rspec/core/formatters/console_codes.rb +7 -4
- data/lib/rspec/core/formatters/deprecation_formatter.rb +9 -9
- data/lib/rspec/core/formatters/documentation_formatter.rb +37 -4
- data/lib/rspec/core/formatters/exception_presenter.rb +21 -4
- data/lib/rspec/core/formatters/failure_list_formatter.rb +23 -0
- data/lib/rspec/core/formatters/html_formatter.rb +4 -2
- data/lib/rspec/core/formatters/html_printer.rb +3 -3
- data/lib/rspec/core/formatters/html_snippet_extractor.rb +4 -0
- data/lib/rspec/core/formatters/json_formatter.rb +9 -3
- data/lib/rspec/core/formatters/progress_formatter.rb +1 -0
- data/lib/rspec/core/formatters/protocol.rb +43 -42
- data/lib/rspec/core/formatters/snippet_extractor.rb +1 -3
- data/lib/rspec/core/{source → formatters}/syntax_highlighter.rb +21 -1
- data/lib/rspec/core/hooks.rb +18 -10
- data/lib/rspec/core/invocations.rb +30 -10
- data/lib/rspec/core/memoized_helpers.rb +36 -14
- data/lib/rspec/core/metadata.rb +2 -3
- data/lib/rspec/core/metadata_filter.rb +29 -17
- data/lib/rspec/core/notifications.rb +34 -11
- data/lib/rspec/core/option_parser.rb +32 -4
- data/lib/rspec/core/output_wrapper.rb +29 -0
- data/lib/rspec/core/profiler.rb +3 -1
- data/lib/rspec/core/project_initializer/.rspec +0 -1
- data/lib/rspec/core/project_initializer/spec/spec_helper.rb +1 -4
- data/lib/rspec/core/rake_task.rb +21 -1
- data/lib/rspec/core/reporter.rb +33 -16
- data/lib/rspec/core/runner.rb +31 -15
- data/lib/rspec/core/set.rb +5 -0
- data/lib/rspec/core/shared_example_group.rb +41 -19
- data/lib/rspec/core/shell_escape.rb +2 -2
- data/lib/rspec/core/version.rb +1 -1
- data/lib/rspec/core/world.rb +24 -5
- metadata +26 -20
- metadata.gz.sig +0 -0
- data/lib/rspec/core/formatters/bisect_formatter.rb +0 -69
- data/lib/rspec/core/source.rb +0 -86
- data/lib/rspec/core/source/location.rb +0 -13
- data/lib/rspec/core/source/node.rb +0 -93
- data/lib/rspec/core/source/token.rb +0 -87
data/lib/rspec/core/profiler.rb
CHANGED
@@ -20,7 +20,9 @@ module RSpec
|
|
20
20
|
def example_group_finished(notification)
|
21
21
|
return unless notification.group.top_level?
|
22
22
|
|
23
|
-
|
23
|
+
group = @example_groups[notification.group]
|
24
|
+
return unless group.key?(:start)
|
25
|
+
group[:total_time] = Time.now - group[:start]
|
24
26
|
end
|
25
27
|
|
26
28
|
def example_started(notification)
|
@@ -12,9 +12,6 @@
|
|
12
12
|
# the additional setup, and require it from the spec files that actually need
|
13
13
|
# it.
|
14
14
|
#
|
15
|
-
# The `.rspec` file also contains a few flags that are not defaults but that
|
16
|
-
# users commonly want.
|
17
|
-
#
|
18
15
|
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
19
16
|
RSpec.configure do |config|
|
20
17
|
# rspec-expectations config goes here. You can use an alternate
|
@@ -80,7 +77,7 @@ RSpec.configure do |config|
|
|
80
77
|
# Use the documentation formatter for detailed output,
|
81
78
|
# unless a formatter has already been configured
|
82
79
|
# (e.g. via a command-line flag).
|
83
|
-
config.default_formatter =
|
80
|
+
config.default_formatter = "doc"
|
84
81
|
end
|
85
82
|
|
86
83
|
# Print the 10 slowest examples and example groups at the
|
data/lib/rspec/core/rake_task.rb
CHANGED
@@ -45,6 +45,21 @@ module RSpec
|
|
45
45
|
# A message to print to stderr when there are failures.
|
46
46
|
attr_accessor :failure_message
|
47
47
|
|
48
|
+
if RUBY_VERSION < "1.9.0" || Support::Ruby.jruby?
|
49
|
+
# Run RSpec with a clean (empty) environment is not supported
|
50
|
+
def with_clean_environment=(_value)
|
51
|
+
raise ArgumentError, "Running in a clean environment is not supported on Ruby versions before 1.9.0"
|
52
|
+
end
|
53
|
+
|
54
|
+
# Run RSpec with a clean (empty) environment is not supported
|
55
|
+
def with_clean_environment
|
56
|
+
false
|
57
|
+
end
|
58
|
+
else
|
59
|
+
# Run RSpec with a clean (empty) environment.
|
60
|
+
attr_accessor :with_clean_environment
|
61
|
+
end
|
62
|
+
|
48
63
|
# Use verbose output. If this is set to true, the task will print the
|
49
64
|
# executed spec command to stdout. Defaults to `true`.
|
50
65
|
attr_accessor :verbose
|
@@ -76,7 +91,12 @@ module RSpec
|
|
76
91
|
command = spec_command
|
77
92
|
puts command if verbose
|
78
93
|
|
79
|
-
|
94
|
+
if with_clean_environment
|
95
|
+
return if system({}, command, :unsetenv_others => true)
|
96
|
+
else
|
97
|
+
return if system(command)
|
98
|
+
end
|
99
|
+
|
80
100
|
puts failure_message if failure_message
|
81
101
|
|
82
102
|
return unless fail_on_error
|
data/lib/rspec/core/reporter.rb
CHANGED
@@ -18,25 +18,15 @@ module RSpec::Core
|
|
18
18
|
@failed_examples = []
|
19
19
|
@pending_examples = []
|
20
20
|
@duration = @start = @load_time = nil
|
21
|
+
@non_example_exception_count = 0
|
22
|
+
@setup_default = lambda {}
|
23
|
+
@setup = false
|
24
|
+
@profiler = nil
|
21
25
|
end
|
22
26
|
|
23
27
|
# @private
|
24
28
|
attr_reader :examples, :failed_examples, :pending_examples
|
25
29
|
|
26
|
-
# @private
|
27
|
-
def reset
|
28
|
-
@examples = []
|
29
|
-
@failed_examples = []
|
30
|
-
@pending_examples = []
|
31
|
-
@profiler = Profiler.new if defined?(@profiler)
|
32
|
-
end
|
33
|
-
|
34
|
-
# @private
|
35
|
-
def setup_profiler
|
36
|
-
@profiler = Profiler.new
|
37
|
-
register_listener @profiler, *Profiler::NOTIFICATIONS
|
38
|
-
end
|
39
|
-
|
40
30
|
# Registers a listener to a list of notifications. The reporter will send
|
41
31
|
# notification of events to all registered listeners.
|
42
32
|
#
|
@@ -51,6 +41,13 @@ module RSpec::Core
|
|
51
41
|
true
|
52
42
|
end
|
53
43
|
|
44
|
+
# @private
|
45
|
+
def prepare_default(loader, output_stream, deprecation_stream)
|
46
|
+
@setup_default = lambda do
|
47
|
+
loader.setup_default output_stream, deprecation_stream
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
54
51
|
# @private
|
55
52
|
def registered_listeners(notification)
|
56
53
|
@listeners[notification].to_a
|
@@ -80,6 +77,14 @@ module RSpec::Core
|
|
80
77
|
end
|
81
78
|
end
|
82
79
|
|
80
|
+
# @param exit_code [Integer] the exit_code to be return by the reporter
|
81
|
+
#
|
82
|
+
# Reports a run that exited early without having run any examples.
|
83
|
+
#
|
84
|
+
def exit_early(exit_code)
|
85
|
+
report(0) { exit_code }
|
86
|
+
end
|
87
|
+
|
83
88
|
# @private
|
84
89
|
def start(expected_example_count, time=RSpec::Core::Time.now)
|
85
90
|
@start = time
|
@@ -153,10 +158,11 @@ module RSpec::Core
|
|
153
158
|
|
154
159
|
# @private
|
155
160
|
# Provides a way to notify of an exception that is not tied to any
|
156
|
-
# particular
|
161
|
+
# particular example (such as an exception encountered in a :suite hook).
|
157
162
|
# Exceptions will be formatted the same way they normally are.
|
158
163
|
def notify_non_example_exception(exception, context_description)
|
159
164
|
@configuration.world.non_example_failure = true
|
165
|
+
@non_example_exception_count += 1
|
160
166
|
|
161
167
|
example = Example.new(AnonymousExampleGroup, context_description, {})
|
162
168
|
presenter = Formatters::ExceptionPresenter.new(exception, example, :indentation => 0)
|
@@ -177,7 +183,8 @@ module RSpec::Core
|
|
177
183
|
@profiler.example_groups)
|
178
184
|
end
|
179
185
|
notify :dump_summary, Notifications::SummaryNotification.new(@duration, @examples, @failed_examples,
|
180
|
-
@pending_examples, @load_time
|
186
|
+
@pending_examples, @load_time,
|
187
|
+
@non_example_exception_count)
|
181
188
|
notify :seed, Notifications::SeedNotification.new(@configuration.seed, seed_used?)
|
182
189
|
end
|
183
190
|
end
|
@@ -197,6 +204,7 @@ module RSpec::Core
|
|
197
204
|
|
198
205
|
# @private
|
199
206
|
def notify(event, notification)
|
207
|
+
ensure_listeners_ready
|
200
208
|
registered_listeners(event).each do |formatter|
|
201
209
|
formatter.__send__(event, notification)
|
202
210
|
end
|
@@ -222,6 +230,15 @@ module RSpec::Core
|
|
222
230
|
|
223
231
|
private
|
224
232
|
|
233
|
+
def ensure_listeners_ready
|
234
|
+
return if @setup
|
235
|
+
|
236
|
+
@setup_default.call
|
237
|
+
@profiler = Profiler.new
|
238
|
+
register_listener @profiler, *Profiler::NOTIFICATIONS
|
239
|
+
@setup = true
|
240
|
+
end
|
241
|
+
|
225
242
|
def close
|
226
243
|
notify :close, Notifications::NullNotification
|
227
244
|
end
|
data/lib/rspec/core/runner.rb
CHANGED
@@ -84,6 +84,8 @@ module RSpec
|
|
84
84
|
# @param out [IO] output stream
|
85
85
|
def run(err, out)
|
86
86
|
setup(err, out)
|
87
|
+
return @configuration.reporter.exit_early(@configuration.failure_exit_code) if RSpec.world.wants_to_quit
|
88
|
+
|
87
89
|
run_specs(@world.ordered_example_groups).tap do
|
88
90
|
persist_example_statuses
|
89
91
|
end
|
@@ -94,10 +96,11 @@ module RSpec
|
|
94
96
|
# @param err [IO] error stream
|
95
97
|
# @param out [IO] output stream
|
96
98
|
def setup(err, out)
|
97
|
-
|
98
|
-
|
99
|
-
|
99
|
+
configure(err, out)
|
100
|
+
return if RSpec.world.wants_to_quit
|
101
|
+
|
100
102
|
@configuration.load_spec_files
|
103
|
+
ensure
|
101
104
|
@world.announce_filters
|
102
105
|
end
|
103
106
|
|
@@ -108,8 +111,13 @@ module RSpec
|
|
108
111
|
# or the configured failure exit code (1 by default) if specs
|
109
112
|
# failed.
|
110
113
|
def run_specs(example_groups)
|
111
|
-
|
114
|
+
examples_count = @world.example_count(example_groups)
|
115
|
+
success = @configuration.reporter.report(examples_count) do |reporter|
|
112
116
|
@configuration.with_suite_hooks do
|
117
|
+
if examples_count == 0 && @configuration.fail_if_no_examples
|
118
|
+
return @configuration.failure_exit_code
|
119
|
+
end
|
120
|
+
|
113
121
|
example_groups.map { |g| g.run(reporter) }.all?
|
114
122
|
end
|
115
123
|
end && !@world.non_example_failure
|
@@ -117,17 +125,11 @@ module RSpec
|
|
117
125
|
success ? 0 : @configuration.failure_exit_code
|
118
126
|
end
|
119
127
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
ExampleStatusPersister.persist(@world.all_examples, path)
|
126
|
-
rescue SystemCallError => e
|
127
|
-
RSpec.warning "Could not write example statuses to #{path} (configured as " \
|
128
|
-
"`config.example_status_persistence_file_path`) due to a " \
|
129
|
-
"system error: #{e.inspect}. Please check that the config " \
|
130
|
-
"option is set to an accessible, valid file path", :call_site => nil
|
128
|
+
# @private
|
129
|
+
def configure(err, out)
|
130
|
+
@configuration.error_stream = err
|
131
|
+
@configuration.output_stream = out if @configuration.output_stream == $stdout
|
132
|
+
@options.configure(@configuration)
|
131
133
|
end
|
132
134
|
|
133
135
|
# @private
|
@@ -183,6 +185,20 @@ module RSpec
|
|
183
185
|
$stderr.puts "\nRSpec is shutting down and will print the summary report... Interrupt again to force quit."
|
184
186
|
end
|
185
187
|
end
|
188
|
+
|
189
|
+
private
|
190
|
+
|
191
|
+
def persist_example_statuses
|
192
|
+
return if @configuration.dry_run
|
193
|
+
return unless (path = @configuration.example_status_persistence_file_path)
|
194
|
+
|
195
|
+
ExampleStatusPersister.persist(@world.all_examples, path)
|
196
|
+
rescue SystemCallError => e
|
197
|
+
RSpec.warning "Could not write example statuses to #{path} (configured as " \
|
198
|
+
"`config.example_status_persistence_file_path`) due to a " \
|
199
|
+
"system error: #{e.inspect}. Please check that the config " \
|
200
|
+
"option is set to an accessible, valid file path", :call_site => nil
|
201
|
+
end
|
186
202
|
end
|
187
203
|
end
|
188
204
|
end
|
data/lib/rspec/core/set.rb
CHANGED
@@ -64,11 +64,6 @@ module RSpec
|
|
64
64
|
# group; any example group or example with matching metadata will
|
65
65
|
# automatically include this shared example group.
|
66
66
|
# @param block The block to be eval'd
|
67
|
-
# @overload shared_examples(metadata, &block)
|
68
|
-
# @param metadata [Array<Symbol>, Hash] metadata to attach to this
|
69
|
-
# group; any example group or example with matching metadata will
|
70
|
-
# automatically include this shared example group.
|
71
|
-
# @param block The block to be eval'd
|
72
67
|
#
|
73
68
|
# Stores the block for later use. The block will be evaluated
|
74
69
|
# in the context of an example group via `include_examples`,
|
@@ -81,7 +76,7 @@ module RSpec
|
|
81
76
|
# end
|
82
77
|
# end
|
83
78
|
#
|
84
|
-
# describe Account do
|
79
|
+
# RSpec.describe Account do
|
85
80
|
# it_behaves_like "auditable" do
|
86
81
|
# let(:auditable) { Account.new }
|
87
82
|
# end
|
@@ -108,7 +103,6 @@ module RSpec
|
|
108
103
|
# Shared examples top level DSL.
|
109
104
|
module TopLevelDSL
|
110
105
|
# @private
|
111
|
-
# rubocop:disable Lint/NestedMethodDefinition
|
112
106
|
def self.definitions
|
113
107
|
proc do
|
114
108
|
def shared_examples(name, *args, &block)
|
@@ -118,7 +112,6 @@ module RSpec
|
|
118
112
|
alias shared_examples_for shared_examples
|
119
113
|
end
|
120
114
|
end
|
121
|
-
# rubocop:enable Lint/NestedMethodDefinition
|
122
115
|
|
123
116
|
# @private
|
124
117
|
def self.exposed_globally?
|
@@ -153,6 +146,12 @@ module RSpec
|
|
153
146
|
# @private
|
154
147
|
class Registry
|
155
148
|
def add(context, name, *metadata_args, &block)
|
149
|
+
unless block
|
150
|
+
RSpec.warning "Shared example group #{name} was defined without a "\
|
151
|
+
"block and will have no effect. Please define a "\
|
152
|
+
"block or remove the definition."
|
153
|
+
end
|
154
|
+
|
156
155
|
if RSpec.configuration.shared_context_metadata_behavior == :trigger_inclusion
|
157
156
|
return legacy_add(context, name, *metadata_args, &block)
|
158
157
|
end
|
@@ -213,20 +212,43 @@ module RSpec
|
|
213
212
|
|
214
213
|
def warn_if_key_taken(context, key, new_block)
|
215
214
|
existing_module = shared_example_groups[context][key]
|
216
|
-
|
217
215
|
return unless existing_module
|
218
216
|
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
217
|
+
old_definition_location = formatted_location existing_module.definition
|
218
|
+
new_definition_location = formatted_location new_block
|
219
|
+
loaded_spec_files = RSpec.configuration.loaded_spec_files
|
220
|
+
|
221
|
+
if loaded_spec_files.include?(new_definition_location) && old_definition_location == new_definition_location
|
222
|
+
RSpec.warn_with <<-WARNING.gsub(/^ +\|/, ''), :call_site => nil
|
223
|
+
|WARNING: Your shared example group, '#{key}', defined at:
|
224
|
+
| #{old_definition_location}
|
225
|
+
|was automatically loaded by RSpec because the file name
|
226
|
+
|matches the configured autoloading pattern (#{RSpec.configuration.pattern}),
|
227
|
+
|and is also being required from somewhere else. To fix this
|
228
|
+
|warning, either rename the file to not match the pattern, or
|
229
|
+
|do not explicitly require the file.
|
230
|
+
WARNING
|
231
|
+
else
|
232
|
+
RSpec.warn_with <<-WARNING.gsub(/^ +\|/, ''), :call_site => nil
|
233
|
+
|WARNING: Shared example group '#{key}' has been previously defined at:
|
234
|
+
| #{old_definition_location}
|
235
|
+
|...and you are now defining it at:
|
236
|
+
| #{new_definition_location}
|
237
|
+
|The new definition will overwrite the original one.
|
238
|
+
WARNING
|
239
|
+
end
|
226
240
|
end
|
227
241
|
|
228
|
-
|
229
|
-
block
|
242
|
+
if RUBY_VERSION.to_f >= 1.9
|
243
|
+
def formatted_location(block)
|
244
|
+
block.source_location.join(":")
|
245
|
+
end
|
246
|
+
else # 1.8.7
|
247
|
+
# :nocov:
|
248
|
+
def formatted_location(block)
|
249
|
+
block.source_location.join(":").gsub(/:in.*$/, '')
|
250
|
+
end
|
251
|
+
# :nocov:
|
230
252
|
end
|
231
253
|
|
232
254
|
if Proc.method_defined?(:source_location)
|
@@ -235,7 +257,7 @@ module RSpec
|
|
235
257
|
# :nocov:
|
236
258
|
def ensure_block_has_source_location(block)
|
237
259
|
source_location = yield.split(':')
|
238
|
-
block.extend
|
260
|
+
block.extend(Module.new { define_method(:source_location) { source_location } })
|
239
261
|
end
|
240
262
|
# :nocov:
|
241
263
|
end
|
@@ -6,7 +6,7 @@ module RSpec
|
|
6
6
|
module_function
|
7
7
|
|
8
8
|
def quote(argument)
|
9
|
-
"'#{argument.gsub("'", "\\\\'")}'"
|
9
|
+
"'#{argument.to_s.gsub("'", "\\\\'")}'"
|
10
10
|
end
|
11
11
|
|
12
12
|
if RSpec::Support::OS.windows?
|
@@ -17,7 +17,7 @@ module RSpec
|
|
17
17
|
require 'shellwords'
|
18
18
|
|
19
19
|
def escape(shell_command)
|
20
|
-
shell_command.
|
20
|
+
Shellwords.escape(shell_command.to_s)
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
data/lib/rspec/core/version.rb
CHANGED
data/lib/rspec/core/world.rb
CHANGED
@@ -21,6 +21,17 @@ module RSpec
|
|
21
21
|
configuration.world = self
|
22
22
|
@example_groups = []
|
23
23
|
@example_group_counts_by_spec_file = Hash.new(0)
|
24
|
+
prepare_example_filtering
|
25
|
+
end
|
26
|
+
|
27
|
+
# @api public
|
28
|
+
#
|
29
|
+
# Prepares filters so that they apply to example groups when they run.
|
30
|
+
#
|
31
|
+
# This is a separate method so that filters can be modified/replaced and
|
32
|
+
# examples refiltered during a process's lifetime, which can be useful for
|
33
|
+
# a custom runner.
|
34
|
+
def prepare_example_filtering
|
24
35
|
@filtered_examples = Hash.new do |hash, group|
|
25
36
|
hash[group] = filter_manager.prune(group.examples)
|
26
37
|
end
|
@@ -40,7 +51,8 @@ module RSpec
|
|
40
51
|
def reset
|
41
52
|
RSpec::ExampleGroups.remove_all_constants
|
42
53
|
example_groups.clear
|
43
|
-
@
|
54
|
+
@sources_by_path.clear if defined?(@sources_by_path)
|
55
|
+
@syntax_highlighter = nil
|
44
56
|
end
|
45
57
|
|
46
58
|
# @private
|
@@ -129,11 +141,18 @@ module RSpec
|
|
129
141
|
end
|
130
142
|
|
131
143
|
# @private
|
132
|
-
def
|
133
|
-
@
|
134
|
-
RSpec::Support.
|
135
|
-
|
144
|
+
def source_from_file(path)
|
145
|
+
unless defined?(@sources_by_path)
|
146
|
+
RSpec::Support.require_rspec_support 'source'
|
147
|
+
@sources_by_path = {}
|
136
148
|
end
|
149
|
+
|
150
|
+
@sources_by_path[path] ||= Support::Source.from_file(path)
|
151
|
+
end
|
152
|
+
|
153
|
+
# @private
|
154
|
+
def syntax_highlighter
|
155
|
+
@syntax_highlighter ||= Formatters::SyntaxHighlighter.new(@configuration)
|
137
156
|
end
|
138
157
|
|
139
158
|
# @api private
|