rspec-core 3.5.4 → 3.9.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 +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
|