rspec-expectations 2.14.0 → 3.13.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 +976 -25
- data/{License.txt → LICENSE.md} +5 -3
- data/README.md +162 -26
- 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 +127 -51
- data/lib/rspec/expectations/fail_with.rb +17 -57
- data/lib/rspec/expectations/failure_aggregator.rb +229 -0
- data/lib/rspec/expectations/handler.rb +146 -32
- data/lib/rspec/expectations/minitest_integration.rb +58 -0
- data/lib/rspec/expectations/syntax.rb +68 -100
- data/lib/rspec/expectations/version.rb +1 -1
- data/lib/rspec/expectations.rb +58 -23
- 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 +191 -20
- data/lib/rspec/matchers/built_in/be.rb +114 -114
- data/lib/rspec/matchers/built_in/be_between.rb +77 -0
- data/lib/rspec/matchers/built_in/be_instance_of.rb +15 -4
- data/lib/rspec/matchers/built_in/be_kind_of.rb +10 -1
- data/lib/rspec/matchers/built_in/be_within.rb +35 -18
- data/lib/rspec/matchers/built_in/change.rb +389 -80
- data/lib/rspec/matchers/built_in/compound.rb +290 -0
- data/lib/rspec/matchers/built_in/contain_exactly.rb +310 -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 +30 -8
- data/lib/rspec/matchers/built_in/eql.rb +23 -8
- data/lib/rspec/matchers/built_in/equal.rb +55 -22
- 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 +184 -32
- 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 +192 -44
- data/lib/rspec/matchers/built_in/respond_to.rb +154 -28
- 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 +240 -161
- data/lib/rspec/matchers/built_in.rb +47 -33
- data/lib/rspec/matchers/composable.rb +171 -0
- data/lib/rspec/matchers/dsl.rb +531 -10
- data/lib/rspec/matchers/english_phrasing.rb +58 -0
- data/lib/rspec/matchers/fail_matchers.rb +42 -0
- data/lib/rspec/matchers/generated_descriptions.rb +14 -8
- data/lib/rspec/matchers/matcher_delegator.rb +61 -0
- data/lib/rspec/matchers/matcher_protocol.rb +105 -0
- data/lib/rspec/matchers/multi_matcher_diff.rb +82 -0
- data/lib/rspec/matchers.rb +520 -173
- data.tar.gz.sig +0 -0
- metadata +141 -242
- metadata.gz.sig +2 -0
- data/features/README.md +0 -48
- data/features/Upgrade.md +0 -53
- data/features/built_in_matchers/README.md +0 -90
- data/features/built_in_matchers/be.feature +0 -175
- data/features/built_in_matchers/be_within.feature +0 -48
- data/features/built_in_matchers/cover.feature +0 -47
- data/features/built_in_matchers/end_with.feature +0 -48
- data/features/built_in_matchers/equality.feature +0 -139
- data/features/built_in_matchers/exist.feature +0 -45
- data/features/built_in_matchers/expect_change.feature +0 -59
- data/features/built_in_matchers/expect_error.feature +0 -144
- data/features/built_in_matchers/have.feature +0 -109
- data/features/built_in_matchers/include.feature +0 -174
- data/features/built_in_matchers/match.feature +0 -52
- data/features/built_in_matchers/operators.feature +0 -227
- data/features/built_in_matchers/predicates.feature +0 -137
- data/features/built_in_matchers/respond_to.feature +0 -84
- data/features/built_in_matchers/satisfy.feature +0 -33
- data/features/built_in_matchers/start_with.feature +0 -48
- data/features/built_in_matchers/throw_symbol.feature +0 -91
- data/features/built_in_matchers/types.feature +0 -116
- data/features/built_in_matchers/yield.feature +0 -161
- 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 -368
- 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 -14
- data/features/syntax_configuration.feature +0 -71
- data/features/test_frameworks/test_unit.feature +0 -44
- data/lib/rspec/expectations/deprecation.rb +0 -17
- data/lib/rspec/expectations/differ.rb +0 -133
- 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 -29
- 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 -124
- data/lib/rspec/matchers/built_in/match_array.rb +0 -51
- 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 -108
- data/lib/rspec/matchers/extensions/instance_eval_with_args.rb +0 -39
- data/lib/rspec/matchers/matcher.rb +0 -300
- data/lib/rspec/matchers/method_missing.rb +0 -12
- data/lib/rspec/matchers/operator_matcher.rb +0 -109
- data/lib/rspec/matchers/pretty.rb +0 -70
- data/lib/rspec/matchers/test_unit_integration.rb +0 -11
- data/lib/rspec-expectations.rb +0 -1
- data/spec/rspec/expectations/differ_spec.rb +0 -192
- data/spec/rspec/expectations/expectation_target_spec.rb +0 -82
- data/spec/rspec/expectations/extensions/kernel_spec.rb +0 -67
- data/spec/rspec/expectations/fail_with_spec.rb +0 -114
- data/spec/rspec/expectations/handler_spec.rb +0 -227
- data/spec/rspec/expectations/syntax_spec.rb +0 -139
- data/spec/rspec/matchers/base_matcher_spec.rb +0 -62
- data/spec/rspec/matchers/be_close_spec.rb +0 -22
- data/spec/rspec/matchers/be_instance_of_spec.rb +0 -63
- data/spec/rspec/matchers/be_kind_of_spec.rb +0 -41
- data/spec/rspec/matchers/be_spec.rb +0 -516
- data/spec/rspec/matchers/be_within_spec.rb +0 -137
- data/spec/rspec/matchers/change_spec.rb +0 -553
- data/spec/rspec/matchers/configuration_spec.rb +0 -206
- data/spec/rspec/matchers/cover_spec.rb +0 -69
- data/spec/rspec/matchers/description_generation_spec.rb +0 -190
- data/spec/rspec/matchers/dsl_spec.rb +0 -57
- data/spec/rspec/matchers/eq_spec.rb +0 -60
- data/spec/rspec/matchers/eql_spec.rb +0 -41
- data/spec/rspec/matchers/equal_spec.rb +0 -78
- data/spec/rspec/matchers/exist_spec.rb +0 -124
- data/spec/rspec/matchers/has_spec.rb +0 -122
- data/spec/rspec/matchers/have_spec.rb +0 -455
- data/spec/rspec/matchers/include_matcher_integration_spec.rb +0 -30
- data/spec/rspec/matchers/include_spec.rb +0 -531
- data/spec/rspec/matchers/match_array_spec.rb +0 -194
- data/spec/rspec/matchers/match_spec.rb +0 -61
- data/spec/rspec/matchers/matcher_spec.rb +0 -471
- data/spec/rspec/matchers/matchers_spec.rb +0 -37
- data/spec/rspec/matchers/method_missing_spec.rb +0 -28
- data/spec/rspec/matchers/operator_matcher_spec.rb +0 -223
- data/spec/rspec/matchers/raise_error_spec.rb +0 -485
- data/spec/rspec/matchers/respond_to_spec.rb +0 -292
- data/spec/rspec/matchers/satisfy_spec.rb +0 -44
- data/spec/rspec/matchers/start_with_end_with_spec.rb +0 -186
- data/spec/rspec/matchers/throw_symbol_spec.rb +0 -116
- data/spec/rspec/matchers/yield_spec.rb +0 -514
- data/spec/spec_helper.rb +0 -54
- data/spec/support/classes.rb +0 -56
- data/spec/support/in_sub_process.rb +0 -38
- 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,229 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Expectations
|
3
|
+
# @private
|
4
|
+
class FailureAggregator
|
5
|
+
attr_reader :block_label, :metadata
|
6
|
+
|
7
|
+
# @private
|
8
|
+
class AggregatedFailure
|
9
|
+
# @private
|
10
|
+
MESSAGE =
|
11
|
+
'AggregatedFailure: This method caused a failure which has been ' \
|
12
|
+
'suppressed to be aggregated into our failure report by returning ' \
|
13
|
+
'this value, further errors can be ignored.'
|
14
|
+
|
15
|
+
def inspect
|
16
|
+
MESSAGE
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
AGGREGATED_FAILURE = AggregatedFailure.new
|
21
|
+
|
22
|
+
def aggregate
|
23
|
+
RSpec::Support.with_failure_notifier(self) do
|
24
|
+
begin
|
25
|
+
yield
|
26
|
+
rescue ExpectationNotMetError => e
|
27
|
+
# Normally, expectation failures will be notified via the `call` method, below,
|
28
|
+
# but since the failure notifier uses a thread local variable, failing expectations
|
29
|
+
# in another thread will still raise. We handle that here and categorize it as part
|
30
|
+
# of `failures` rather than letting it fall through and be categorized as part of
|
31
|
+
# `other_errors`.
|
32
|
+
failures << e
|
33
|
+
rescue Support::AllExceptionsExceptOnesWeMustNotRescue => e
|
34
|
+
# While it is normally a bad practice to rescue `Exception`, it's important we do
|
35
|
+
# so here. It's low risk (`notify_aggregated_failures` below will re-raise the exception,
|
36
|
+
# or raise a `MultipleExpectationsNotMetError` that includes the exception), and it's
|
37
|
+
# essential that the user is notified of expectation failures that may have already
|
38
|
+
# occurred in the `aggregate_failures` block. Those expectation failures may provide
|
39
|
+
# important diagnostics for understanding why this exception occurred, and if we simply
|
40
|
+
# allowed this exception to be raised as-is, it would (wrongly) suggest to the user
|
41
|
+
# that the expectation passed when it did not, which would be quite confusing.
|
42
|
+
other_errors << e
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
notify_aggregated_failures
|
47
|
+
end
|
48
|
+
|
49
|
+
def failures
|
50
|
+
@failures ||= []
|
51
|
+
end
|
52
|
+
|
53
|
+
def other_errors
|
54
|
+
@other_errors ||= []
|
55
|
+
end
|
56
|
+
|
57
|
+
# This method is defined to satisfy the callable interface
|
58
|
+
# expected by `RSpec::Support.with_failure_notifier`.
|
59
|
+
def call(failure, options)
|
60
|
+
source_id = options[:source_id]
|
61
|
+
return if source_id && @seen_source_ids.key?(source_id)
|
62
|
+
|
63
|
+
@seen_source_ids[source_id] = true
|
64
|
+
assign_backtrace(failure) unless failure.backtrace
|
65
|
+
failures << failure
|
66
|
+
|
67
|
+
AGGREGATED_FAILURE
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
if RSpec::Support::Ruby.jruby? && RSpec::Support::Ruby.jruby_version < '9.2.0.0'
|
73
|
+
# On JRuby 9.1.x.x and before, `caller` and `raise` produce different backtraces with
|
74
|
+
# regards to `.java` stack frames. It's important that we use `raise` for JRuby to produce
|
75
|
+
# a backtrace that has a continuous common section with the raised `MultipleExpectationsNotMetError`,
|
76
|
+
# so that rspec-core's truncation logic can work properly on it to list the backtrace
|
77
|
+
# relative to the `aggregate_failures` block.
|
78
|
+
def assign_backtrace(failure)
|
79
|
+
raise failure
|
80
|
+
rescue failure.class => e
|
81
|
+
failure.set_backtrace(e.backtrace)
|
82
|
+
end
|
83
|
+
else
|
84
|
+
# Using `caller` performs better (and is simpler) than `raise` on most Rubies.
|
85
|
+
def assign_backtrace(failure)
|
86
|
+
failure.set_backtrace(caller)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def initialize(block_label, metadata)
|
91
|
+
@block_label = block_label
|
92
|
+
@metadata = metadata
|
93
|
+
@seen_source_ids = {} # don't want to load stdlib set
|
94
|
+
end
|
95
|
+
|
96
|
+
def notify_aggregated_failures
|
97
|
+
all_errors = failures + other_errors
|
98
|
+
|
99
|
+
case all_errors.size
|
100
|
+
when 0 then return true
|
101
|
+
when 1 then RSpec::Support.notify_failure all_errors.first
|
102
|
+
else RSpec::Support.notify_failure MultipleExpectationsNotMetError.new(self)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Exception raised from `aggregate_failures` when multiple expectations fail.
|
108
|
+
class MultipleExpectationsNotMetError
|
109
|
+
# @return [String] The fully formatted exception message.
|
110
|
+
def message
|
111
|
+
@message ||= (["#{summary}:"] + enumerated_failures + enumerated_errors).join("\n\n")
|
112
|
+
end
|
113
|
+
|
114
|
+
# @return [Array<RSpec::Expectations::ExpectationNotMetError>] The list of expectation failures.
|
115
|
+
def failures
|
116
|
+
@failure_aggregator.failures
|
117
|
+
end
|
118
|
+
|
119
|
+
# @return [Array<Exception>] The list of other exceptions.
|
120
|
+
def other_errors
|
121
|
+
@failure_aggregator.other_errors
|
122
|
+
end
|
123
|
+
|
124
|
+
# @return [Array<Exception>] The list of expectation failures and other exceptions, combined.
|
125
|
+
attr_reader :all_exceptions
|
126
|
+
|
127
|
+
# @return [String] The user-assigned label for the aggregation block.
|
128
|
+
def aggregation_block_label
|
129
|
+
@failure_aggregator.block_label
|
130
|
+
end
|
131
|
+
|
132
|
+
# @return [Hash] The metadata hash passed to `aggregate_failures`.
|
133
|
+
def aggregation_metadata
|
134
|
+
@failure_aggregator.metadata
|
135
|
+
end
|
136
|
+
|
137
|
+
# @return [String] A summary of the failure, including the block label and a count of failures.
|
138
|
+
def summary
|
139
|
+
"Got #{exception_count_description} from failure aggregation " \
|
140
|
+
"block#{block_description}"
|
141
|
+
end
|
142
|
+
|
143
|
+
# return [String] A description of the failure/error counts.
|
144
|
+
def exception_count_description
|
145
|
+
failure_count = pluralize("failure", failures.size)
|
146
|
+
return failure_count if other_errors.empty?
|
147
|
+
error_count = pluralize("other error", other_errors.size)
|
148
|
+
"#{failure_count} and #{error_count}"
|
149
|
+
end
|
150
|
+
|
151
|
+
private
|
152
|
+
|
153
|
+
def initialize(failure_aggregator)
|
154
|
+
@failure_aggregator = failure_aggregator
|
155
|
+
@all_exceptions = failures + other_errors
|
156
|
+
end
|
157
|
+
|
158
|
+
def block_description
|
159
|
+
return "" unless aggregation_block_label
|
160
|
+
" #{aggregation_block_label.inspect}"
|
161
|
+
end
|
162
|
+
|
163
|
+
def pluralize(noun, count)
|
164
|
+
"#{count} #{noun}#{'s' unless count == 1}"
|
165
|
+
end
|
166
|
+
|
167
|
+
def enumerated(exceptions, index_offset)
|
168
|
+
exceptions.each_with_index.map do |exception, index|
|
169
|
+
index += index_offset
|
170
|
+
formatted_message = "#{yield exception}\n#{format_backtrace(exception.backtrace).first}"
|
171
|
+
"#{index_label index}#{indented formatted_message, index}"
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def exclusion_patterns
|
176
|
+
patterns = %w[/lib\d*/ruby/ bin/ exe/rspec /lib/bundler/ /exe/bundle:]
|
177
|
+
patterns << "org/jruby/" if RSpec::Support::Ruby.jruby?
|
178
|
+
patterns.map! { |s| Regexp.new(s.gsub('/', File::SEPARATOR)) }
|
179
|
+
end
|
180
|
+
|
181
|
+
def format_backtrace(backtrace)
|
182
|
+
backtrace.map { |l| backtrace_line(l) }.compact.tap { |filtered| filtered.concat backtrace if filtered.empty? }
|
183
|
+
end
|
184
|
+
|
185
|
+
def backtrace_line(line)
|
186
|
+
return if [Regexp.union(RSpec::CallerFilter::IGNORE_REGEX, *exclusion_patterns)].any? { |p| line =~ p }
|
187
|
+
|
188
|
+
# It changes the current path that is relative to
|
189
|
+
# system root to be relative to the project root.
|
190
|
+
line.sub(/(\A|\s)#{File.expand_path('.')}(#{File::SEPARATOR}|\s|\Z)/, '\\1.\\2'.freeze).sub(/\A([^:]+:\d+)$/, '\\1'.freeze)
|
191
|
+
end
|
192
|
+
|
193
|
+
def enumerated_failures
|
194
|
+
enumerated(failures, 0, &:message)
|
195
|
+
end
|
196
|
+
|
197
|
+
def enumerated_errors
|
198
|
+
enumerated(other_errors, failures.size) do |error|
|
199
|
+
"#{error.class}: #{error.message}"
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def indented(failure_message, index)
|
204
|
+
line_1, *rest = failure_message.strip.lines.to_a
|
205
|
+
first_line_indentation = ' ' * (longest_index_label_width - width_of_label(index))
|
206
|
+
|
207
|
+
first_line_indentation + line_1 + rest.map do |line|
|
208
|
+
line =~ /\S/ ? indentation + line : line
|
209
|
+
end.join
|
210
|
+
end
|
211
|
+
|
212
|
+
def indentation
|
213
|
+
@indentation ||= ' ' * longest_index_label_width
|
214
|
+
end
|
215
|
+
|
216
|
+
def longest_index_label_width
|
217
|
+
@longest_index_label_width ||= width_of_label(failures.size)
|
218
|
+
end
|
219
|
+
|
220
|
+
def width_of_label(index)
|
221
|
+
index_label(index).chars.count
|
222
|
+
end
|
223
|
+
|
224
|
+
def index_label(index)
|
225
|
+
" #{index + 1}) "
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module RSpec
|
2
2
|
module Expectations
|
3
|
-
|
4
|
-
|
3
|
+
# @private
|
4
|
+
module ExpectationHelper
|
5
5
|
def self.check_message(msg)
|
6
6
|
unless msg.nil? || msg.respond_to?(:to_str) || msg.respond_to?(:call)
|
7
7
|
::Kernel.warn [
|
@@ -11,24 +11,28 @@ module RSpec
|
|
11
11
|
].join
|
12
12
|
end
|
13
13
|
end
|
14
|
-
end
|
15
14
|
|
16
|
-
|
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
|
17
23
|
|
18
|
-
def self.
|
24
|
+
def self.with_matcher(handler, matcher, message)
|
19
25
|
check_message(message)
|
20
|
-
|
26
|
+
matcher = modern_matcher_from(matcher)
|
27
|
+
yield matcher
|
28
|
+
ensure
|
29
|
+
::RSpec::Matchers.last_expectation_handler = handler
|
21
30
|
::RSpec::Matchers.last_matcher = matcher
|
22
|
-
|
23
|
-
|
24
|
-
match = matcher.matches?(actual, &block)
|
25
|
-
return match if match
|
31
|
+
end
|
26
32
|
|
33
|
+
def self.handle_failure(matcher, message, failure_message_method)
|
27
34
|
message = message.call if message.respond_to?(:call)
|
28
|
-
|
29
|
-
message ||= matcher.respond_to?(:failure_message_for_should) ?
|
30
|
-
matcher.failure_message_for_should :
|
31
|
-
matcher.failure_message
|
35
|
+
message ||= matcher.__send__(failure_message_method)
|
32
36
|
|
33
37
|
if matcher.respond_to?(:diffable?) && matcher.diffable?
|
34
38
|
::RSpec::Expectations.fail_with message, matcher.expected, matcher.actual
|
@@ -38,31 +42,141 @@ module RSpec
|
|
38
42
|
end
|
39
43
|
end
|
40
44
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
return ::RSpec::Matchers::BuiltIn::NegativeOperatorMatcher.new(actual) if matcher.nil?
|
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
|
47
50
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
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
|
52
55
|
|
53
|
-
|
56
|
+
match_result || ExpectationHelper.handle_failure(matcher, custom_message, :failure_message)
|
57
|
+
end
|
58
|
+
end
|
54
59
|
|
55
|
-
|
56
|
-
|
57
|
-
|
60
|
+
def self.verb
|
61
|
+
'is expected to'
|
62
|
+
end
|
58
63
|
|
59
|
-
|
60
|
-
|
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
|
74
|
+
class NegativeExpectationHandler
|
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
|
78
|
+
|
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)
|
61
91
|
else
|
62
|
-
|
92
|
+
!matcher.matches?(actual, &block)
|
93
|
+
end
|
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
|
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)
|
63
172
|
end
|
64
173
|
end
|
65
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
|
66
181
|
end
|
67
182
|
end
|
68
|
-
|
@@ -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
|