rspec-expectations 2.11.3 → 3.11.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 +7 -0
- checksums.yaml.gz.sig +0 -0
- data/.document +1 -1
- data/.yardopts +1 -1
- data/Changelog.md +1026 -21
- data/{License.txt → LICENSE.md} +5 -3
- data/README.md +174 -78
- data/lib/rspec/expectations/block_snippet_extractor.rb +253 -0
- data/lib/rspec/expectations/configuration.rb +230 -0
- data/lib/rspec/expectations/expectation_target.rb +130 -55
- data/lib/rspec/expectations/fail_with.rb +17 -33
- data/lib/rspec/expectations/failure_aggregator.rb +212 -0
- data/lib/rspec/expectations/handler.rb +163 -29
- data/lib/rspec/expectations/minitest_integration.rb +58 -0
- data/lib/rspec/expectations/syntax.rb +68 -54
- data/lib/rspec/expectations/version.rb +1 -1
- data/lib/rspec/expectations.rb +59 -24
- data/lib/rspec/matchers/aliased_matcher.rb +116 -0
- data/lib/rspec/matchers/built_in/all.rb +86 -0
- data/lib/rspec/matchers/built_in/base_matcher.rb +150 -20
- data/lib/rspec/matchers/built_in/be.rb +115 -109
- data/lib/rspec/matchers/built_in/be_between.rb +77 -0
- data/lib/rspec/matchers/built_in/be_instance_of.rb +16 -1
- data/lib/rspec/matchers/built_in/be_kind_of.rb +10 -1
- data/lib/rspec/matchers/built_in/be_within.rb +43 -17
- data/lib/rspec/matchers/built_in/change.rb +392 -75
- data/lib/rspec/matchers/built_in/compound.rb +290 -0
- data/lib/rspec/matchers/built_in/contain_exactly.rb +302 -0
- data/lib/rspec/matchers/built_in/count_expectation.rb +169 -0
- data/lib/rspec/matchers/built_in/cover.rb +3 -0
- data/lib/rspec/matchers/built_in/eq.rb +26 -8
- data/lib/rspec/matchers/built_in/eql.rb +19 -8
- data/lib/rspec/matchers/built_in/equal.rb +56 -19
- data/lib/rspec/matchers/built_in/exist.rb +74 -10
- data/lib/rspec/matchers/built_in/has.rb +141 -22
- data/lib/rspec/matchers/built_in/have_attributes.rb +114 -0
- data/lib/rspec/matchers/built_in/include.rb +175 -20
- data/lib/rspec/matchers/built_in/match.rb +95 -1
- data/lib/rspec/matchers/built_in/operators.rb +128 -0
- data/lib/rspec/matchers/built_in/output.rb +207 -0
- data/lib/rspec/matchers/built_in/raise_error.rb +212 -38
- data/lib/rspec/matchers/built_in/respond_to.rb +155 -29
- data/lib/rspec/matchers/built_in/satisfy.rb +39 -9
- data/lib/rspec/matchers/built_in/start_or_end_with.rb +94 -0
- data/lib/rspec/matchers/built_in/throw_symbol.rb +58 -14
- data/lib/rspec/matchers/built_in/yield.rb +252 -98
- data/lib/rspec/matchers/built_in.rb +47 -33
- data/lib/rspec/matchers/composable.rb +171 -0
- data/lib/rspec/matchers/dsl.rb +530 -10
- data/lib/rspec/matchers/english_phrasing.rb +58 -0
- data/lib/rspec/matchers/expecteds_for_multiple_diffs.rb +82 -0
- data/lib/rspec/matchers/fail_matchers.rb +42 -0
- data/lib/rspec/matchers/generated_descriptions.rb +15 -10
- data/lib/rspec/matchers/matcher_delegator.rb +35 -0
- data/lib/rspec/matchers/matcher_protocol.rb +105 -0
- data/lib/rspec/matchers.rb +604 -252
- data.tar.gz.sig +0 -0
- metadata +178 -278
- metadata.gz.sig +0 -0
- data/features/README.md +0 -49
- data/features/Upgrade.md +0 -53
- data/features/built_in_matchers/README.md +0 -90
- data/features/built_in_matchers/be.feature +0 -173
- data/features/built_in_matchers/be_within.feature +0 -46
- data/features/built_in_matchers/cover.feature +0 -45
- data/features/built_in_matchers/end_with.feature +0 -46
- data/features/built_in_matchers/equality.feature +0 -145
- data/features/built_in_matchers/exist.feature +0 -43
- data/features/built_in_matchers/expect_change.feature +0 -59
- data/features/built_in_matchers/expect_error.feature +0 -138
- data/features/built_in_matchers/have.feature +0 -103
- data/features/built_in_matchers/include.feature +0 -121
- data/features/built_in_matchers/match.feature +0 -50
- data/features/built_in_matchers/operators.feature +0 -221
- data/features/built_in_matchers/predicates.feature +0 -128
- data/features/built_in_matchers/respond_to.feature +0 -78
- data/features/built_in_matchers/satisfy.feature +0 -31
- data/features/built_in_matchers/start_with.feature +0 -46
- data/features/built_in_matchers/throw_symbol.feature +0 -85
- data/features/built_in_matchers/types.feature +0 -114
- data/features/built_in_matchers/yield.feature +0 -146
- data/features/custom_matchers/access_running_example.feature +0 -53
- data/features/custom_matchers/define_diffable_matcher.feature +0 -27
- data/features/custom_matchers/define_matcher.feature +0 -340
- data/features/custom_matchers/define_matcher_outside_rspec.feature +0 -38
- data/features/custom_matchers/define_matcher_with_fluent_interface.feature +0 -24
- data/features/customized_message.feature +0 -22
- data/features/diffing.feature +0 -85
- data/features/implicit_docstrings.feature +0 -52
- data/features/step_definitions/additional_cli_steps.rb +0 -22
- data/features/support/env.rb +0 -5
- data/features/syntax_configuration.feature +0 -68
- data/features/test_frameworks/test_unit.feature +0 -46
- data/lib/rspec/expectations/deprecation.rb +0 -38
- data/lib/rspec/expectations/differ.rb +0 -81
- data/lib/rspec/expectations/errors.rb +0 -9
- data/lib/rspec/expectations/extensions/array.rb +0 -9
- data/lib/rspec/expectations/extensions/object.rb +0 -39
- data/lib/rspec/expectations/extensions.rb +0 -2
- data/lib/rspec/matchers/be_close.rb +0 -9
- data/lib/rspec/matchers/built_in/have.rb +0 -108
- data/lib/rspec/matchers/built_in/match_array.rb +0 -45
- data/lib/rspec/matchers/built_in/start_and_end_with.rb +0 -48
- data/lib/rspec/matchers/compatibility.rb +0 -14
- data/lib/rspec/matchers/configuration.rb +0 -66
- data/lib/rspec/matchers/extensions/instance_eval_with_args.rb +0 -39
- data/lib/rspec/matchers/matcher.rb +0 -299
- data/lib/rspec/matchers/method_missing.rb +0 -12
- data/lib/rspec/matchers/operator_matcher.rb +0 -84
- data/lib/rspec/matchers/pretty.rb +0 -60
- data/lib/rspec-expectations.rb +0 -1
- data/spec/rspec/expectations/differ_spec.rb +0 -153
- data/spec/rspec/expectations/expectation_target_spec.rb +0 -65
- data/spec/rspec/expectations/extensions/kernel_spec.rb +0 -67
- data/spec/rspec/expectations/fail_with_spec.rb +0 -70
- data/spec/rspec/expectations/handler_spec.rb +0 -206
- data/spec/rspec/matchers/base_matcher_spec.rb +0 -60
- data/spec/rspec/matchers/be_close_spec.rb +0 -22
- data/spec/rspec/matchers/be_instance_of_spec.rb +0 -40
- data/spec/rspec/matchers/be_kind_of_spec.rb +0 -37
- data/spec/rspec/matchers/be_spec.rb +0 -452
- data/spec/rspec/matchers/be_within_spec.rb +0 -80
- data/spec/rspec/matchers/change_spec.rb +0 -528
- data/spec/rspec/matchers/configuration_spec.rb +0 -202
- data/spec/rspec/matchers/cover_spec.rb +0 -69
- data/spec/rspec/matchers/description_generation_spec.rb +0 -176
- data/spec/rspec/matchers/dsl_spec.rb +0 -57
- data/spec/rspec/matchers/eq_spec.rb +0 -54
- data/spec/rspec/matchers/eql_spec.rb +0 -41
- data/spec/rspec/matchers/equal_spec.rb +0 -60
- data/spec/rspec/matchers/exist_spec.rb +0 -110
- data/spec/rspec/matchers/has_spec.rb +0 -118
- data/spec/rspec/matchers/have_spec.rb +0 -461
- data/spec/rspec/matchers/include_spec.rb +0 -367
- data/spec/rspec/matchers/match_array_spec.rb +0 -124
- data/spec/rspec/matchers/match_spec.rb +0 -61
- data/spec/rspec/matchers/matcher_spec.rb +0 -434
- data/spec/rspec/matchers/matchers_spec.rb +0 -31
- data/spec/rspec/matchers/method_missing_spec.rb +0 -24
- data/spec/rspec/matchers/operator_matcher_spec.rb +0 -221
- data/spec/rspec/matchers/raise_error_spec.rb +0 -344
- data/spec/rspec/matchers/respond_to_spec.rb +0 -295
- data/spec/rspec/matchers/satisfy_spec.rb +0 -44
- data/spec/rspec/matchers/start_with_end_with_spec.rb +0 -182
- data/spec/rspec/matchers/throw_symbol_spec.rb +0 -116
- data/spec/rspec/matchers/yield_spec.rb +0 -402
- data/spec/spec_helper.rb +0 -27
- data/spec/support/classes.rb +0 -56
- data/spec/support/in_sub_process.rb +0 -31
- data/spec/support/matchers.rb +0 -22
- data/spec/support/ruby_version.rb +0 -10
- data/spec/support/shared_examples.rb +0 -13
@@ -0,0 +1,212 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Expectations
|
3
|
+
# @private
|
4
|
+
class FailureAggregator
|
5
|
+
attr_reader :block_label, :metadata
|
6
|
+
|
7
|
+
def aggregate
|
8
|
+
RSpec::Support.with_failure_notifier(self) do
|
9
|
+
begin
|
10
|
+
yield
|
11
|
+
rescue ExpectationNotMetError => e
|
12
|
+
# Normally, expectation failures will be notified via the `call` method, below,
|
13
|
+
# but since the failure notifier uses a thread local variable, failing expectations
|
14
|
+
# in another thread will still raise. We handle that here and categorize it as part
|
15
|
+
# of `failures` rather than letting it fall through and be categorized as part of
|
16
|
+
# `other_errors`.
|
17
|
+
failures << e
|
18
|
+
rescue Support::AllExceptionsExceptOnesWeMustNotRescue => e
|
19
|
+
# While it is normally a bad practice to rescue `Exception`, it's important we do
|
20
|
+
# so here. It's low risk (`notify_aggregated_failures` below will re-raise the exception,
|
21
|
+
# or raise a `MultipleExpectationsNotMetError` that includes the exception), and it's
|
22
|
+
# essential that the user is notified of expectation failures that may have already
|
23
|
+
# occurred in the `aggregate_failures` block. Those expectation failures may provide
|
24
|
+
# important diagnostics for understanding why this exception occurred, and if we simply
|
25
|
+
# allowed this exception to be raised as-is, it would (wrongly) suggest to the user
|
26
|
+
# that the expectation passed when it did not, which would be quite confusing.
|
27
|
+
other_errors << e
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
notify_aggregated_failures
|
32
|
+
end
|
33
|
+
|
34
|
+
def failures
|
35
|
+
@failures ||= []
|
36
|
+
end
|
37
|
+
|
38
|
+
def other_errors
|
39
|
+
@other_errors ||= []
|
40
|
+
end
|
41
|
+
|
42
|
+
# This method is defined to satisfy the callable interface
|
43
|
+
# expected by `RSpec::Support.with_failure_notifier`.
|
44
|
+
def call(failure, options)
|
45
|
+
source_id = options[:source_id]
|
46
|
+
return if source_id && @seen_source_ids.key?(source_id)
|
47
|
+
|
48
|
+
@seen_source_ids[source_id] = true
|
49
|
+
assign_backtrace(failure) unless failure.backtrace
|
50
|
+
failures << failure
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
if RSpec::Support::Ruby.jruby? && RSpec::Support::Ruby.jruby_version < '9.2.0.0'
|
56
|
+
# On JRuby 9.1.x.x and before, `caller` and `raise` produce different backtraces with
|
57
|
+
# regards to `.java` stack frames. It's important that we use `raise` for JRuby to produce
|
58
|
+
# a backtrace that has a continuous common section with the raised `MultipleExpectationsNotMetError`,
|
59
|
+
# so that rspec-core's truncation logic can work properly on it to list the backtrace
|
60
|
+
# relative to the `aggregate_failures` block.
|
61
|
+
def assign_backtrace(failure)
|
62
|
+
raise failure
|
63
|
+
rescue failure.class => e
|
64
|
+
failure.set_backtrace(e.backtrace)
|
65
|
+
end
|
66
|
+
else
|
67
|
+
# Using `caller` performs better (and is simpler) than `raise` on most Rubies.
|
68
|
+
def assign_backtrace(failure)
|
69
|
+
failure.set_backtrace(caller)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def initialize(block_label, metadata)
|
74
|
+
@block_label = block_label
|
75
|
+
@metadata = metadata
|
76
|
+
@seen_source_ids = {} # don't want to load stdlib set
|
77
|
+
end
|
78
|
+
|
79
|
+
def notify_aggregated_failures
|
80
|
+
all_errors = failures + other_errors
|
81
|
+
|
82
|
+
case all_errors.size
|
83
|
+
when 0 then return true
|
84
|
+
when 1 then RSpec::Support.notify_failure all_errors.first
|
85
|
+
else RSpec::Support.notify_failure MultipleExpectationsNotMetError.new(self)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Exception raised from `aggregate_failures` when multiple expectations fail.
|
91
|
+
class MultipleExpectationsNotMetError
|
92
|
+
# @return [String] The fully formatted exception message.
|
93
|
+
def message
|
94
|
+
@message ||= (["#{summary}:"] + enumerated_failures + enumerated_errors).join("\n\n")
|
95
|
+
end
|
96
|
+
|
97
|
+
# @return [Array<RSpec::Expectations::ExpectationNotMetError>] The list of expectation failures.
|
98
|
+
def failures
|
99
|
+
@failure_aggregator.failures
|
100
|
+
end
|
101
|
+
|
102
|
+
# @return [Array<Exception>] The list of other exceptions.
|
103
|
+
def other_errors
|
104
|
+
@failure_aggregator.other_errors
|
105
|
+
end
|
106
|
+
|
107
|
+
# @return [Array<Exception>] The list of expectation failures and other exceptions, combined.
|
108
|
+
attr_reader :all_exceptions
|
109
|
+
|
110
|
+
# @return [String] The user-assigned label for the aggregation block.
|
111
|
+
def aggregation_block_label
|
112
|
+
@failure_aggregator.block_label
|
113
|
+
end
|
114
|
+
|
115
|
+
# @return [Hash] The metadata hash passed to `aggregate_failures`.
|
116
|
+
def aggregation_metadata
|
117
|
+
@failure_aggregator.metadata
|
118
|
+
end
|
119
|
+
|
120
|
+
# @return [String] A summary of the failure, including the block label and a count of failures.
|
121
|
+
def summary
|
122
|
+
"Got #{exception_count_description} from failure aggregation " \
|
123
|
+
"block#{block_description}"
|
124
|
+
end
|
125
|
+
|
126
|
+
# return [String] A description of the failure/error counts.
|
127
|
+
def exception_count_description
|
128
|
+
failure_count = pluralize("failure", failures.size)
|
129
|
+
return failure_count if other_errors.empty?
|
130
|
+
error_count = pluralize("other error", other_errors.size)
|
131
|
+
"#{failure_count} and #{error_count}"
|
132
|
+
end
|
133
|
+
|
134
|
+
private
|
135
|
+
|
136
|
+
def initialize(failure_aggregator)
|
137
|
+
@failure_aggregator = failure_aggregator
|
138
|
+
@all_exceptions = failures + other_errors
|
139
|
+
end
|
140
|
+
|
141
|
+
def block_description
|
142
|
+
return "" unless aggregation_block_label
|
143
|
+
" #{aggregation_block_label.inspect}"
|
144
|
+
end
|
145
|
+
|
146
|
+
def pluralize(noun, count)
|
147
|
+
"#{count} #{noun}#{'s' unless count == 1}"
|
148
|
+
end
|
149
|
+
|
150
|
+
def enumerated(exceptions, index_offset)
|
151
|
+
exceptions.each_with_index.map do |exception, index|
|
152
|
+
index += index_offset
|
153
|
+
formatted_message = "#{yield exception}\n#{format_backtrace(exception.backtrace).first}"
|
154
|
+
"#{index_label index}#{indented formatted_message, index}"
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def exclusion_patterns
|
159
|
+
patterns = %w[/lib\d*/ruby/ bin/ exe/rspec /lib/bundler/ /exe/bundle:]
|
160
|
+
patterns << "org/jruby/" if RSpec::Support::Ruby.jruby?
|
161
|
+
patterns.map! { |s| Regexp.new(s.gsub('/', File::SEPARATOR)) }
|
162
|
+
end
|
163
|
+
|
164
|
+
def format_backtrace(backtrace)
|
165
|
+
backtrace.map { |l| backtrace_line(l) }.compact.tap { |filtered| filtered.concat backtrace if filtered.empty? }
|
166
|
+
end
|
167
|
+
|
168
|
+
def backtrace_line(line)
|
169
|
+
return if [Regexp.union(RSpec::CallerFilter::IGNORE_REGEX, *exclusion_patterns)].any? { |p| line =~ p }
|
170
|
+
|
171
|
+
# It changes the current path that is relative to
|
172
|
+
# system root to be relative to the project root.
|
173
|
+
line.sub(/(\A|\s)#{File.expand_path('.')}(#{File::SEPARATOR}|\s|\Z)/, '\\1.\\2'.freeze).sub(/\A([^:]+:\d+)$/, '\\1'.freeze)
|
174
|
+
end
|
175
|
+
|
176
|
+
def enumerated_failures
|
177
|
+
enumerated(failures, 0, &:message)
|
178
|
+
end
|
179
|
+
|
180
|
+
def enumerated_errors
|
181
|
+
enumerated(other_errors, failures.size) do |error|
|
182
|
+
"#{error.class}: #{error.message}"
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def indented(failure_message, index)
|
187
|
+
line_1, *rest = failure_message.strip.lines.to_a
|
188
|
+
first_line_indentation = ' ' * (longest_index_label_width - width_of_label(index))
|
189
|
+
|
190
|
+
first_line_indentation + line_1 + rest.map do |line|
|
191
|
+
line =~ /\S/ ? indentation + line : line
|
192
|
+
end.join
|
193
|
+
end
|
194
|
+
|
195
|
+
def indentation
|
196
|
+
@indentation ||= ' ' * longest_index_label_width
|
197
|
+
end
|
198
|
+
|
199
|
+
def longest_index_label_width
|
200
|
+
@longest_index_label_width ||= width_of_label(failures.size)
|
201
|
+
end
|
202
|
+
|
203
|
+
def width_of_label(index)
|
204
|
+
index_label(index).chars.count
|
205
|
+
end
|
206
|
+
|
207
|
+
def index_label(index)
|
208
|
+
" #{index + 1}) "
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
@@ -1,18 +1,39 @@
|
|
1
1
|
module RSpec
|
2
2
|
module Expectations
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
# @private
|
4
|
+
module ExpectationHelper
|
5
|
+
def self.check_message(msg)
|
6
|
+
unless msg.nil? || msg.respond_to?(:to_str) || msg.respond_to?(:call)
|
7
|
+
::Kernel.warn [
|
8
|
+
"WARNING: ignoring the provided expectation message argument (",
|
9
|
+
msg.inspect,
|
10
|
+
") since it is not a string or a proc."
|
11
|
+
].join
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns an RSpec-3+ compatible matcher, wrapping a legacy one
|
16
|
+
# in an adapter if necessary.
|
17
|
+
#
|
18
|
+
# @private
|
19
|
+
def self.modern_matcher_from(matcher)
|
20
|
+
LegacyMatcherAdapter::RSpec2.wrap(matcher) ||
|
21
|
+
LegacyMatcherAdapter::RSpec1.wrap(matcher) || matcher
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.with_matcher(handler, matcher, message)
|
25
|
+
check_message(message)
|
26
|
+
matcher = modern_matcher_from(matcher)
|
27
|
+
yield matcher
|
28
|
+
ensure
|
29
|
+
::RSpec::Matchers.last_expectation_handler = handler
|
6
30
|
::RSpec::Matchers.last_matcher = matcher
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
matcher.failure_message_for_should :
|
14
|
-
matcher.failure_message
|
15
|
-
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.handle_failure(matcher, message, failure_message_method)
|
34
|
+
message = message.call if message.respond_to?(:call)
|
35
|
+
message ||= matcher.__send__(failure_message_method)
|
36
|
+
|
16
37
|
if matcher.respond_to?(:diffable?) && matcher.diffable?
|
17
38
|
::RSpec::Expectations.fail_with message, matcher.expected, matcher.actual
|
18
39
|
else
|
@@ -21,28 +42,141 @@ module RSpec
|
|
21
42
|
end
|
22
43
|
end
|
23
44
|
|
45
|
+
# @private
|
46
|
+
class PositiveExpectationHandler
|
47
|
+
def self.handle_matcher(actual, initial_matcher, custom_message=nil, &block)
|
48
|
+
ExpectationHelper.with_matcher(self, initial_matcher, custom_message) do |matcher|
|
49
|
+
return ::RSpec::Matchers::BuiltIn::PositiveOperatorMatcher.new(actual) unless initial_matcher
|
50
|
+
|
51
|
+
match_result = matcher.matches?(actual, &block)
|
52
|
+
if custom_message && match_result.respond_to?(:error_generator)
|
53
|
+
match_result.error_generator.opts[:message] = custom_message
|
54
|
+
end
|
55
|
+
|
56
|
+
match_result || ExpectationHelper.handle_failure(matcher, custom_message, :failure_message)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.verb
|
61
|
+
'is expected to'
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.should_method
|
65
|
+
:should
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.opposite_should_method
|
69
|
+
:should_not
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# @private
|
24
74
|
class NegativeExpectationHandler
|
25
|
-
def self.handle_matcher(actual,
|
26
|
-
|
27
|
-
|
28
|
-
return ::RSpec::Matchers::BuiltIn::NegativeOperatorMatcher.new(actual) if matcher.nil?
|
29
|
-
|
30
|
-
match = matcher.respond_to?(:does_not_match?) ?
|
31
|
-
!matcher.does_not_match?(actual, &block) :
|
32
|
-
matcher.matches?(actual, &block)
|
33
|
-
return match unless match
|
34
|
-
|
35
|
-
message ||= matcher.respond_to?(:failure_message_for_should_not) ?
|
36
|
-
matcher.failure_message_for_should_not :
|
37
|
-
matcher.negative_failure_message
|
75
|
+
def self.handle_matcher(actual, initial_matcher, custom_message=nil, &block)
|
76
|
+
ExpectationHelper.with_matcher(self, initial_matcher, custom_message) do |matcher|
|
77
|
+
return ::RSpec::Matchers::BuiltIn::NegativeOperatorMatcher.new(actual) unless initial_matcher
|
38
78
|
|
39
|
-
|
40
|
-
|
79
|
+
negated_match_result = does_not_match?(matcher, actual, &block)
|
80
|
+
if custom_message && negated_match_result.respond_to?(:error_generator)
|
81
|
+
negated_match_result.error_generator.opts[:message] = custom_message
|
82
|
+
end
|
83
|
+
|
84
|
+
negated_match_result || ExpectationHelper.handle_failure(matcher, custom_message, :failure_message_when_negated)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.does_not_match?(matcher, actual, &block)
|
89
|
+
if matcher.respond_to?(:does_not_match?)
|
90
|
+
matcher.does_not_match?(actual, &block)
|
41
91
|
else
|
42
|
-
|
92
|
+
!matcher.matches?(actual, &block)
|
43
93
|
end
|
44
94
|
end
|
95
|
+
|
96
|
+
def self.verb
|
97
|
+
'is expected not to'
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.should_method
|
101
|
+
:should_not
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.opposite_should_method
|
105
|
+
:should
|
106
|
+
end
|
45
107
|
end
|
108
|
+
|
109
|
+
# Wraps a matcher written against one of the legacy protocols in
|
110
|
+
# order to present the current protocol.
|
111
|
+
#
|
112
|
+
# @private
|
113
|
+
class LegacyMatcherAdapter < Matchers::MatcherDelegator
|
114
|
+
def initialize(matcher)
|
115
|
+
super
|
116
|
+
::RSpec.warn_deprecation(<<-EOS.gsub(/^\s+\|/, ''), :type => "legacy_matcher")
|
117
|
+
|#{matcher.class.name || matcher.inspect} implements a legacy RSpec matcher
|
118
|
+
|protocol. For the current protocol you should expose the failure messages
|
119
|
+
|via the `failure_message` and `failure_message_when_negated` methods.
|
120
|
+
|(Used from #{CallerFilter.first_non_rspec_line})
|
121
|
+
EOS
|
122
|
+
end
|
123
|
+
|
124
|
+
def self.wrap(matcher)
|
125
|
+
new(matcher) if interface_matches?(matcher)
|
126
|
+
end
|
127
|
+
|
128
|
+
# Starting in RSpec 1.2 (and continuing through all 2.x releases),
|
129
|
+
# the failure message protocol was:
|
130
|
+
# * `failure_message_for_should`
|
131
|
+
# * `failure_message_for_should_not`
|
132
|
+
# @private
|
133
|
+
class RSpec2 < self
|
134
|
+
def failure_message
|
135
|
+
base_matcher.failure_message_for_should
|
136
|
+
end
|
137
|
+
|
138
|
+
def failure_message_when_negated
|
139
|
+
base_matcher.failure_message_for_should_not
|
140
|
+
end
|
141
|
+
|
142
|
+
def self.interface_matches?(matcher)
|
143
|
+
(
|
144
|
+
!matcher.respond_to?(:failure_message) &&
|
145
|
+
matcher.respond_to?(:failure_message_for_should)
|
146
|
+
) || (
|
147
|
+
!matcher.respond_to?(:failure_message_when_negated) &&
|
148
|
+
matcher.respond_to?(:failure_message_for_should_not)
|
149
|
+
)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
# Before RSpec 1.2, the failure message protocol was:
|
154
|
+
# * `failure_message`
|
155
|
+
# * `negative_failure_message`
|
156
|
+
# @private
|
157
|
+
class RSpec1 < self
|
158
|
+
def failure_message
|
159
|
+
base_matcher.failure_message
|
160
|
+
end
|
161
|
+
|
162
|
+
def failure_message_when_negated
|
163
|
+
base_matcher.negative_failure_message
|
164
|
+
end
|
165
|
+
|
166
|
+
# Note: `failure_message` is part of the RSpec 3 protocol
|
167
|
+
# (paired with `failure_message_when_negated`), so we don't check
|
168
|
+
# for `failure_message` here.
|
169
|
+
def self.interface_matches?(matcher)
|
170
|
+
!matcher.respond_to?(:failure_message_when_negated) &&
|
171
|
+
matcher.respond_to?(:negative_failure_message)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# RSpec 3.0 was released with the class name misspelled. For SemVer compatibility,
|
177
|
+
# we will provide this misspelled alias until 4.0.
|
178
|
+
# @deprecated Use LegacyMatcherAdapter instead.
|
179
|
+
# @private
|
180
|
+
LegacyMacherAdapter = LegacyMatcherAdapter
|
46
181
|
end
|
47
182
|
end
|
48
|
-
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'rspec/expectations'
|
2
|
+
|
3
|
+
Minitest::Test.class_eval do
|
4
|
+
include ::RSpec::Matchers
|
5
|
+
|
6
|
+
# This `expect` will only be called if the user is using Minitest < 5.6
|
7
|
+
# or if they are _not_ using Minitest::Spec on 5.6+. Minitest::Spec on 5.6+
|
8
|
+
# defines its own `expect` and will have the assertions incremented via our
|
9
|
+
# definitions of `to`/`not_to`/`to_not` below.
|
10
|
+
def expect(*a, &b)
|
11
|
+
self.assertions += 1
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
# Convert a `MultipleExpectationsNotMetError` to a `Minitest::Assertion` error so
|
16
|
+
# it gets counted in minitest's summary stats as a failure rather than an error.
|
17
|
+
# It would be nice to make `MultipleExpectationsNotMetError` subclass
|
18
|
+
# `Minitest::Assertion`, but Minitest's implementation does not treat subclasses
|
19
|
+
# the same, so this is the best we can do.
|
20
|
+
def aggregate_failures(*args, &block)
|
21
|
+
super
|
22
|
+
rescue RSpec::Expectations::MultipleExpectationsNotMetError => e
|
23
|
+
assertion_failed = Minitest::Assertion.new(e.message)
|
24
|
+
assertion_failed.set_backtrace e.backtrace
|
25
|
+
raise assertion_failed
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Older versions of Minitest (e.g. before 5.6) do not define
|
30
|
+
# `Minitest::Expectation`.
|
31
|
+
if defined?(::Minitest::Expectation)
|
32
|
+
Minitest::Expectation.class_eval do
|
33
|
+
include RSpec::Expectations::ExpectationTarget::InstanceMethods
|
34
|
+
|
35
|
+
def to(*args)
|
36
|
+
ctx.assertions += 1
|
37
|
+
super
|
38
|
+
end
|
39
|
+
|
40
|
+
def not_to(*args)
|
41
|
+
ctx.assertions += 1
|
42
|
+
super
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_not(*args)
|
46
|
+
ctx.assertions += 1
|
47
|
+
super
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
module RSpec
|
53
|
+
module Expectations
|
54
|
+
remove_const :ExpectationNotMetError
|
55
|
+
# Exception raised when an expectation fails.
|
56
|
+
const_set :ExpectationNotMetError, ::Minitest::Assertion
|
57
|
+
end
|
58
|
+
end
|
@@ -4,38 +4,7 @@ module RSpec
|
|
4
4
|
# Provides methods for enabling and disabling the available
|
5
5
|
# syntaxes provided by rspec-expectations.
|
6
6
|
module Syntax
|
7
|
-
|
8
|
-
|
9
|
-
# @method should
|
10
|
-
# Passes if `matcher` returns true. Available on every `Object`.
|
11
|
-
# @example
|
12
|
-
# actual.should eq expected
|
13
|
-
# actual.should match /expression/
|
14
|
-
# @param [Matcher]
|
15
|
-
# matcher
|
16
|
-
# @param [String] message optional message to display when the expectation fails
|
17
|
-
# @return [Boolean] true if the expectation succeeds (else raises)
|
18
|
-
# @see RSpec::Matchers
|
19
|
-
|
20
|
-
# @method should_not
|
21
|
-
# Passes if `matcher` returns false. Available on every `Object`.
|
22
|
-
# @example
|
23
|
-
# actual.should_not eq expected
|
24
|
-
# @param [Matcher]
|
25
|
-
# matcher
|
26
|
-
# @param [String] message optional message to display when the expectation fails
|
27
|
-
# @return [Boolean] false if the negative expectation succeeds (else raises)
|
28
|
-
# @see RSpec::Matchers
|
29
|
-
|
30
|
-
# @method expect
|
31
|
-
# Supports `expect(actual).to matcher` syntax by wrapping `actual` in an
|
32
|
-
# `ExpectationTarget`.
|
33
|
-
# @example
|
34
|
-
# expect(actual).to eq(expected)
|
35
|
-
# expect(actual).to_not eq(expected)
|
36
|
-
# @return [ExpectationTarget]
|
37
|
-
# @see ExpectationTarget#to
|
38
|
-
# @see ExpectationTarget#to_not
|
7
|
+
module_function
|
39
8
|
|
40
9
|
# @api private
|
41
10
|
# Determines where we add `should` and `should_not`.
|
@@ -43,76 +12,121 @@ module RSpec
|
|
43
12
|
@default_should_host ||= ::Object.ancestors.last
|
44
13
|
end
|
45
14
|
|
15
|
+
# @api private
|
16
|
+
# Instructs rspec-expectations to warn on first usage of `should` or `should_not`.
|
17
|
+
# Enabled by default. This is largely here to facilitate testing.
|
18
|
+
def warn_about_should!
|
19
|
+
@warn_about_should = true
|
20
|
+
end
|
21
|
+
|
22
|
+
# @api private
|
23
|
+
# Generates a deprecation warning for the given method if no warning
|
24
|
+
# has already been issued.
|
25
|
+
def warn_about_should_unless_configured(method_name)
|
26
|
+
return unless @warn_about_should
|
27
|
+
|
28
|
+
RSpec.deprecate(
|
29
|
+
"Using `#{method_name}` from rspec-expectations' old `:should` syntax without explicitly enabling the syntax",
|
30
|
+
:replacement => "the new `:expect` syntax or explicitly enable `:should` with `config.expect_with(:rspec) { |c| c.syntax = :should }`"
|
31
|
+
)
|
32
|
+
|
33
|
+
@warn_about_should = false
|
34
|
+
end
|
35
|
+
|
46
36
|
# @api private
|
47
37
|
# Enables the `should` syntax.
|
48
|
-
def enable_should(syntax_host
|
38
|
+
def enable_should(syntax_host=default_should_host)
|
39
|
+
@warn_about_should = false if syntax_host == default_should_host
|
49
40
|
return if should_enabled?(syntax_host)
|
50
41
|
|
51
|
-
syntax_host.
|
42
|
+
syntax_host.module_exec do
|
52
43
|
def should(matcher=nil, message=nil, &block)
|
44
|
+
::RSpec::Expectations::Syntax.warn_about_should_unless_configured(::Kernel.__method__)
|
53
45
|
::RSpec::Expectations::PositiveExpectationHandler.handle_matcher(self, matcher, message, &block)
|
54
46
|
end
|
55
47
|
|
56
48
|
def should_not(matcher=nil, message=nil, &block)
|
49
|
+
::RSpec::Expectations::Syntax.warn_about_should_unless_configured(::Kernel.__method__)
|
57
50
|
::RSpec::Expectations::NegativeExpectationHandler.handle_matcher(self, matcher, message, &block)
|
58
51
|
end
|
59
52
|
end
|
60
|
-
|
61
|
-
::RSpec::Expectations::ExpectationTarget.enable_deprecated_should if expect_enabled?
|
62
53
|
end
|
63
54
|
|
64
55
|
# @api private
|
65
56
|
# Disables the `should` syntax.
|
66
|
-
def disable_should(syntax_host
|
57
|
+
def disable_should(syntax_host=default_should_host)
|
67
58
|
return unless should_enabled?(syntax_host)
|
68
59
|
|
69
|
-
syntax_host.
|
60
|
+
syntax_host.module_exec do
|
70
61
|
undef should
|
71
62
|
undef should_not
|
72
63
|
end
|
73
|
-
|
74
|
-
::RSpec::Expectations::ExpectationTarget.disable_deprecated_should
|
75
64
|
end
|
76
65
|
|
77
66
|
# @api private
|
78
67
|
# Enables the `expect` syntax.
|
79
|
-
def enable_expect(syntax_host
|
68
|
+
def enable_expect(syntax_host=::RSpec::Matchers)
|
80
69
|
return if expect_enabled?(syntax_host)
|
81
70
|
|
82
|
-
syntax_host.
|
83
|
-
def expect(
|
84
|
-
|
85
|
-
raise ArgumentError.new("You must pass an argument or a block to #expect but not both.") unless target.size == 1
|
86
|
-
::RSpec::Expectations::ExpectationTarget.new(target.first)
|
71
|
+
syntax_host.module_exec do
|
72
|
+
def expect(value=::RSpec::Expectations::ExpectationTarget::UndefinedValue, &block)
|
73
|
+
::RSpec::Expectations::ExpectationTarget.for(value, block)
|
87
74
|
end
|
88
75
|
end
|
89
|
-
|
90
|
-
::RSpec::Expectations::ExpectationTarget.enable_deprecated_should if should_enabled?
|
91
76
|
end
|
92
77
|
|
93
78
|
# @api private
|
94
79
|
# Disables the `expect` syntax.
|
95
|
-
def disable_expect(syntax_host
|
80
|
+
def disable_expect(syntax_host=::RSpec::Matchers)
|
96
81
|
return unless expect_enabled?(syntax_host)
|
97
82
|
|
98
|
-
syntax_host.
|
83
|
+
syntax_host.module_exec do
|
99
84
|
undef expect
|
100
85
|
end
|
101
|
-
|
102
|
-
::RSpec::Expectations::ExpectationTarget.disable_deprecated_should
|
103
86
|
end
|
104
87
|
|
105
88
|
# @api private
|
106
89
|
# Indicates whether or not the `should` syntax is enabled.
|
107
|
-
def should_enabled?(syntax_host
|
90
|
+
def should_enabled?(syntax_host=default_should_host)
|
108
91
|
syntax_host.method_defined?(:should)
|
109
92
|
end
|
110
93
|
|
111
94
|
# @api private
|
112
95
|
# Indicates whether or not the `expect` syntax is enabled.
|
113
|
-
def expect_enabled?(syntax_host
|
96
|
+
def expect_enabled?(syntax_host=::RSpec::Matchers)
|
114
97
|
syntax_host.method_defined?(:expect)
|
115
98
|
end
|
116
99
|
end
|
117
100
|
end
|
118
101
|
end
|
102
|
+
|
103
|
+
if defined?(BasicObject)
|
104
|
+
# The legacy `:should` syntax adds the following methods directly to
|
105
|
+
# `BasicObject` so that they are available off of any object. Note, however,
|
106
|
+
# that this syntax does not always play nice with delegate/proxy objects.
|
107
|
+
# We recommend you use the non-monkeypatching `:expect` syntax instead.
|
108
|
+
class BasicObject
|
109
|
+
# @method should(matcher, message)
|
110
|
+
# Passes if `matcher` returns true. Available on every `Object`.
|
111
|
+
# @example
|
112
|
+
# actual.should eq expected
|
113
|
+
# actual.should match /expression/
|
114
|
+
# @param [Matcher]
|
115
|
+
# matcher
|
116
|
+
# @param [String] message optional message to display when the expectation fails
|
117
|
+
# @return [Boolean] true if the expectation succeeds (else raises)
|
118
|
+
# @note This is only available when you have enabled the `:should` syntax.
|
119
|
+
# @see RSpec::Matchers
|
120
|
+
|
121
|
+
# @method should_not(matcher, message)
|
122
|
+
# Passes if `matcher` returns false. Available on every `Object`.
|
123
|
+
# @example
|
124
|
+
# actual.should_not eq expected
|
125
|
+
# @param [Matcher]
|
126
|
+
# matcher
|
127
|
+
# @param [String] message optional message to display when the expectation fails
|
128
|
+
# @return [Boolean] false if the negative expectation succeeds (else raises)
|
129
|
+
# @note This is only available when you have enabled the `:should` syntax.
|
130
|
+
# @see RSpec::Matchers
|
131
|
+
end
|
132
|
+
end
|