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.
Files changed (155) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data/.document +1 -1
  4. data/.yardopts +1 -1
  5. data/Changelog.md +976 -25
  6. data/{License.txt → LICENSE.md} +5 -3
  7. data/README.md +162 -26
  8. data/lib/rspec/expectations/block_snippet_extractor.rb +253 -0
  9. data/lib/rspec/expectations/configuration.rb +230 -0
  10. data/lib/rspec/expectations/expectation_target.rb +127 -51
  11. data/lib/rspec/expectations/fail_with.rb +17 -57
  12. data/lib/rspec/expectations/failure_aggregator.rb +229 -0
  13. data/lib/rspec/expectations/handler.rb +146 -32
  14. data/lib/rspec/expectations/minitest_integration.rb +58 -0
  15. data/lib/rspec/expectations/syntax.rb +68 -100
  16. data/lib/rspec/expectations/version.rb +1 -1
  17. data/lib/rspec/expectations.rb +58 -23
  18. data/lib/rspec/matchers/aliased_matcher.rb +116 -0
  19. data/lib/rspec/matchers/built_in/all.rb +86 -0
  20. data/lib/rspec/matchers/built_in/base_matcher.rb +191 -20
  21. data/lib/rspec/matchers/built_in/be.rb +114 -114
  22. data/lib/rspec/matchers/built_in/be_between.rb +77 -0
  23. data/lib/rspec/matchers/built_in/be_instance_of.rb +15 -4
  24. data/lib/rspec/matchers/built_in/be_kind_of.rb +10 -1
  25. data/lib/rspec/matchers/built_in/be_within.rb +35 -18
  26. data/lib/rspec/matchers/built_in/change.rb +389 -80
  27. data/lib/rspec/matchers/built_in/compound.rb +290 -0
  28. data/lib/rspec/matchers/built_in/contain_exactly.rb +310 -0
  29. data/lib/rspec/matchers/built_in/count_expectation.rb +169 -0
  30. data/lib/rspec/matchers/built_in/cover.rb +3 -0
  31. data/lib/rspec/matchers/built_in/eq.rb +30 -8
  32. data/lib/rspec/matchers/built_in/eql.rb +23 -8
  33. data/lib/rspec/matchers/built_in/equal.rb +55 -22
  34. data/lib/rspec/matchers/built_in/exist.rb +74 -10
  35. data/lib/rspec/matchers/built_in/has.rb +141 -22
  36. data/lib/rspec/matchers/built_in/have_attributes.rb +114 -0
  37. data/lib/rspec/matchers/built_in/include.rb +184 -32
  38. data/lib/rspec/matchers/built_in/match.rb +95 -1
  39. data/lib/rspec/matchers/built_in/operators.rb +128 -0
  40. data/lib/rspec/matchers/built_in/output.rb +207 -0
  41. data/lib/rspec/matchers/built_in/raise_error.rb +192 -44
  42. data/lib/rspec/matchers/built_in/respond_to.rb +154 -28
  43. data/lib/rspec/matchers/built_in/satisfy.rb +39 -9
  44. data/lib/rspec/matchers/built_in/start_or_end_with.rb +94 -0
  45. data/lib/rspec/matchers/built_in/throw_symbol.rb +58 -14
  46. data/lib/rspec/matchers/built_in/yield.rb +240 -161
  47. data/lib/rspec/matchers/built_in.rb +47 -33
  48. data/lib/rspec/matchers/composable.rb +171 -0
  49. data/lib/rspec/matchers/dsl.rb +531 -10
  50. data/lib/rspec/matchers/english_phrasing.rb +58 -0
  51. data/lib/rspec/matchers/fail_matchers.rb +42 -0
  52. data/lib/rspec/matchers/generated_descriptions.rb +14 -8
  53. data/lib/rspec/matchers/matcher_delegator.rb +61 -0
  54. data/lib/rspec/matchers/matcher_protocol.rb +105 -0
  55. data/lib/rspec/matchers/multi_matcher_diff.rb +82 -0
  56. data/lib/rspec/matchers.rb +520 -173
  57. data.tar.gz.sig +0 -0
  58. metadata +141 -242
  59. metadata.gz.sig +2 -0
  60. data/features/README.md +0 -48
  61. data/features/Upgrade.md +0 -53
  62. data/features/built_in_matchers/README.md +0 -90
  63. data/features/built_in_matchers/be.feature +0 -175
  64. data/features/built_in_matchers/be_within.feature +0 -48
  65. data/features/built_in_matchers/cover.feature +0 -47
  66. data/features/built_in_matchers/end_with.feature +0 -48
  67. data/features/built_in_matchers/equality.feature +0 -139
  68. data/features/built_in_matchers/exist.feature +0 -45
  69. data/features/built_in_matchers/expect_change.feature +0 -59
  70. data/features/built_in_matchers/expect_error.feature +0 -144
  71. data/features/built_in_matchers/have.feature +0 -109
  72. data/features/built_in_matchers/include.feature +0 -174
  73. data/features/built_in_matchers/match.feature +0 -52
  74. data/features/built_in_matchers/operators.feature +0 -227
  75. data/features/built_in_matchers/predicates.feature +0 -137
  76. data/features/built_in_matchers/respond_to.feature +0 -84
  77. data/features/built_in_matchers/satisfy.feature +0 -33
  78. data/features/built_in_matchers/start_with.feature +0 -48
  79. data/features/built_in_matchers/throw_symbol.feature +0 -91
  80. data/features/built_in_matchers/types.feature +0 -116
  81. data/features/built_in_matchers/yield.feature +0 -161
  82. data/features/custom_matchers/access_running_example.feature +0 -53
  83. data/features/custom_matchers/define_diffable_matcher.feature +0 -27
  84. data/features/custom_matchers/define_matcher.feature +0 -368
  85. data/features/custom_matchers/define_matcher_outside_rspec.feature +0 -38
  86. data/features/custom_matchers/define_matcher_with_fluent_interface.feature +0 -24
  87. data/features/customized_message.feature +0 -22
  88. data/features/diffing.feature +0 -85
  89. data/features/implicit_docstrings.feature +0 -52
  90. data/features/step_definitions/additional_cli_steps.rb +0 -22
  91. data/features/support/env.rb +0 -14
  92. data/features/syntax_configuration.feature +0 -71
  93. data/features/test_frameworks/test_unit.feature +0 -44
  94. data/lib/rspec/expectations/deprecation.rb +0 -17
  95. data/lib/rspec/expectations/differ.rb +0 -133
  96. data/lib/rspec/expectations/errors.rb +0 -9
  97. data/lib/rspec/expectations/extensions/array.rb +0 -9
  98. data/lib/rspec/expectations/extensions/object.rb +0 -29
  99. data/lib/rspec/expectations/extensions.rb +0 -2
  100. data/lib/rspec/matchers/be_close.rb +0 -9
  101. data/lib/rspec/matchers/built_in/have.rb +0 -124
  102. data/lib/rspec/matchers/built_in/match_array.rb +0 -51
  103. data/lib/rspec/matchers/built_in/start_and_end_with.rb +0 -48
  104. data/lib/rspec/matchers/compatibility.rb +0 -14
  105. data/lib/rspec/matchers/configuration.rb +0 -108
  106. data/lib/rspec/matchers/extensions/instance_eval_with_args.rb +0 -39
  107. data/lib/rspec/matchers/matcher.rb +0 -300
  108. data/lib/rspec/matchers/method_missing.rb +0 -12
  109. data/lib/rspec/matchers/operator_matcher.rb +0 -109
  110. data/lib/rspec/matchers/pretty.rb +0 -70
  111. data/lib/rspec/matchers/test_unit_integration.rb +0 -11
  112. data/lib/rspec-expectations.rb +0 -1
  113. data/spec/rspec/expectations/differ_spec.rb +0 -192
  114. data/spec/rspec/expectations/expectation_target_spec.rb +0 -82
  115. data/spec/rspec/expectations/extensions/kernel_spec.rb +0 -67
  116. data/spec/rspec/expectations/fail_with_spec.rb +0 -114
  117. data/spec/rspec/expectations/handler_spec.rb +0 -227
  118. data/spec/rspec/expectations/syntax_spec.rb +0 -139
  119. data/spec/rspec/matchers/base_matcher_spec.rb +0 -62
  120. data/spec/rspec/matchers/be_close_spec.rb +0 -22
  121. data/spec/rspec/matchers/be_instance_of_spec.rb +0 -63
  122. data/spec/rspec/matchers/be_kind_of_spec.rb +0 -41
  123. data/spec/rspec/matchers/be_spec.rb +0 -516
  124. data/spec/rspec/matchers/be_within_spec.rb +0 -137
  125. data/spec/rspec/matchers/change_spec.rb +0 -553
  126. data/spec/rspec/matchers/configuration_spec.rb +0 -206
  127. data/spec/rspec/matchers/cover_spec.rb +0 -69
  128. data/spec/rspec/matchers/description_generation_spec.rb +0 -190
  129. data/spec/rspec/matchers/dsl_spec.rb +0 -57
  130. data/spec/rspec/matchers/eq_spec.rb +0 -60
  131. data/spec/rspec/matchers/eql_spec.rb +0 -41
  132. data/spec/rspec/matchers/equal_spec.rb +0 -78
  133. data/spec/rspec/matchers/exist_spec.rb +0 -124
  134. data/spec/rspec/matchers/has_spec.rb +0 -122
  135. data/spec/rspec/matchers/have_spec.rb +0 -455
  136. data/spec/rspec/matchers/include_matcher_integration_spec.rb +0 -30
  137. data/spec/rspec/matchers/include_spec.rb +0 -531
  138. data/spec/rspec/matchers/match_array_spec.rb +0 -194
  139. data/spec/rspec/matchers/match_spec.rb +0 -61
  140. data/spec/rspec/matchers/matcher_spec.rb +0 -471
  141. data/spec/rspec/matchers/matchers_spec.rb +0 -37
  142. data/spec/rspec/matchers/method_missing_spec.rb +0 -28
  143. data/spec/rspec/matchers/operator_matcher_spec.rb +0 -223
  144. data/spec/rspec/matchers/raise_error_spec.rb +0 -485
  145. data/spec/rspec/matchers/respond_to_spec.rb +0 -292
  146. data/spec/rspec/matchers/satisfy_spec.rb +0 -44
  147. data/spec/rspec/matchers/start_with_end_with_spec.rb +0 -186
  148. data/spec/rspec/matchers/throw_symbol_spec.rb +0 -116
  149. data/spec/rspec/matchers/yield_spec.rb +0 -514
  150. data/spec/spec_helper.rb +0 -54
  151. data/spec/support/classes.rb +0 -56
  152. data/spec/support/in_sub_process.rb +0 -38
  153. data/spec/support/matchers.rb +0 -22
  154. data/spec/support/ruby_version.rb +0 -10
  155. 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
- class ExpectationHandler
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
- class PositiveExpectationHandler < ExpectationHandler
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.handle_matcher(actual, matcher, message=nil, &block)
24
+ def self.with_matcher(handler, matcher, message)
19
25
  check_message(message)
20
- ::RSpec::Matchers.last_should = :should
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
- return ::RSpec::Matchers::BuiltIn::PositiveOperatorMatcher.new(actual) if matcher.nil?
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
- class NegativeExpectationHandler < ExpectationHandler
42
- def self.handle_matcher(actual, matcher, message=nil, &block)
43
- check_message(message)
44
- ::RSpec::Matchers.last_should = :should_not
45
- ::RSpec::Matchers.last_matcher = matcher
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
- match = matcher.respond_to?(:does_not_match?) ?
49
- !matcher.does_not_match?(actual, &block) :
50
- matcher.matches?(actual, &block)
51
- return match unless match
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
- message = message.call if message.respond_to?(:call)
56
+ match_result || ExpectationHelper.handle_failure(matcher, custom_message, :failure_message)
57
+ end
58
+ end
54
59
 
55
- message ||= matcher.respond_to?(:failure_message_for_should_not) ?
56
- matcher.failure_message_for_should_not :
57
- matcher.negative_failure_message
60
+ def self.verb
61
+ 'is expected to'
62
+ end
58
63
 
59
- if matcher.respond_to?(:diffable?) && matcher.diffable?
60
- ::RSpec::Expectations.fail_with message, matcher.expected, matcher.actual
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
- ::RSpec::Expectations.fail_with message
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