rspec-expectations 3.2.1 → 3.3.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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/Changelog.md +55 -4
- data/README.md +1 -1
- data/lib/rspec/expectations.rb +13 -1
- data/lib/rspec/expectations/configuration.rb +17 -0
- data/lib/rspec/expectations/expectation_target.rb +3 -9
- data/lib/rspec/expectations/fail_with.rb +1 -3
- data/lib/rspec/expectations/failure_aggregator.rb +194 -0
- data/lib/rspec/expectations/minitest_integration.rb +13 -0
- data/lib/rspec/expectations/version.rb +1 -1
- data/lib/rspec/matchers.rb +59 -5
- data/lib/rspec/matchers/built_in/base_matcher.rb +56 -7
- data/lib/rspec/matchers/built_in/be.rb +25 -15
- data/lib/rspec/matchers/built_in/be_between.rb +1 -1
- data/lib/rspec/matchers/built_in/be_within.rb +2 -2
- data/lib/rspec/matchers/built_in/contain_exactly.rb +12 -8
- data/lib/rspec/matchers/built_in/eq.rb +3 -38
- data/lib/rspec/matchers/built_in/eql.rb +2 -2
- data/lib/rspec/matchers/built_in/equal.rb +3 -3
- data/lib/rspec/matchers/built_in/exist.rb +2 -2
- data/lib/rspec/matchers/built_in/has.rb +3 -1
- data/lib/rspec/matchers/built_in/have_attributes.rb +5 -4
- data/lib/rspec/matchers/built_in/include.rb +44 -19
- data/lib/rspec/matchers/built_in/match.rb +9 -1
- data/lib/rspec/matchers/built_in/operators.rb +14 -5
- data/lib/rspec/matchers/built_in/output.rb +9 -2
- data/lib/rspec/matchers/built_in/raise_error.rb +64 -22
- data/lib/rspec/matchers/built_in/respond_to.rb +2 -3
- data/lib/rspec/matchers/built_in/satisfy.rb +7 -9
- data/lib/rspec/matchers/built_in/start_or_end_with.rb +3 -1
- data/lib/rspec/matchers/built_in/throw_symbol.rb +1 -1
- data/lib/rspec/matchers/built_in/yield.rb +7 -5
- data/lib/rspec/matchers/composable.rb +5 -4
- data/lib/rspec/matchers/dsl.rb +19 -6
- data/lib/rspec/matchers/english_phrasing.rb +42 -0
- data/lib/rspec/matchers/expecteds_for_multiple_diffs.rb +2 -8
- data/lib/rspec/matchers/fail_matchers.rb +42 -0
- data/lib/rspec/matchers/matcher_delegator.rb +2 -0
- metadata +9 -7
- metadata.gz.sig +0 -0
- data/lib/rspec/matchers/pretty.rb +0 -77
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 050cebd3fe559b7cd5391cba39333fc9815e7650
|
4
|
+
data.tar.gz: 0034049cdc0f2fd7ab5210ba606b72a267b3abbc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: afee08bfc1eedff07267817c53989802b649cab426c15f55aa869e71bac7db27eadb679b854d5c9da3bbdb7ac39bedcc7c448e8fd7ae8eec311b1a19a694ff07
|
7
|
+
data.tar.gz: 1215a16c5ec70686dba0fd02d4ae14c4238352a995850a4c437eda0d7a4279597e1866f7426c623afc31ba32db5215517102576a2442caeddfdc44da308e5123
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
data/Changelog.md
CHANGED
@@ -1,3 +1,54 @@
|
|
1
|
+
### 3.3.0 / 2015-06-12
|
2
|
+
[Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.2.1...v3.3.0)
|
3
|
+
|
4
|
+
Enhancements:
|
5
|
+
|
6
|
+
* Expose `RSpec::Matchers::EnglishPhrasing` to make it easier to write
|
7
|
+
nice failure messages in custom matchers. (Jared Beck, #736)
|
8
|
+
* Add `RSpec::Matchers::FailMatchers`, a mixin which provides
|
9
|
+
`fail`, `fail_with` and `fail_including` matchers for use in
|
10
|
+
specifying that an expectation fails for use by
|
11
|
+
extension/plugin authors. (Charlie Rudolph, #729)
|
12
|
+
* Avoid loading `tempfile` (and its dependencies) unless
|
13
|
+
it is absolutely needed. (Myron Marston, #735)
|
14
|
+
* Improve failure output when attempting to use `be_true` or `be_false`.
|
15
|
+
(Tim Wade, #744)
|
16
|
+
* Define `RSpec::Matchers#respond_to_missing?` so that
|
17
|
+
`RSpec::Matchers#respond_to?` and `RSpec::Matchers#method` handle
|
18
|
+
dynamic predicate matchers. (Andrei Botalov, #751)
|
19
|
+
* Use custom Time/DateTime/BigDecimal formatting for all matchers
|
20
|
+
so they are consistently represented in failure messages.
|
21
|
+
(Gavin Miller, #740)
|
22
|
+
* Add configuration to turn off warnings about matcher combinations that
|
23
|
+
may cause false positives. (Jon Rowe, #768)
|
24
|
+
* Warn when using a bare `raise_error` matcher that you may be subject to
|
25
|
+
false positives. (Jon Rowe, #768)
|
26
|
+
* Warn rather than raise when using the`raise_error` matcher in negative
|
27
|
+
expectations that may be subject to false positives. (Jon Rowe, #775)
|
28
|
+
* Improve failure message for `include(a, b, c)` so that if `a` and `b`
|
29
|
+
are included the failure message only mentions `c`. (Chris Arcand, #780)
|
30
|
+
* Allow `satisfy` matcher to take an optional description argument
|
31
|
+
that will be used in the `description`, `failure_message` and
|
32
|
+
`failure_message_when_negated` in place of the undescriptive
|
33
|
+
"sastify block". (Chris Arcand, #783)
|
34
|
+
* Add new `aggregate_failures` API that allows multiple independent
|
35
|
+
expectations to all fail and be listed in the failure output, rather
|
36
|
+
than the example aborting on the first failure. (Myron Marston, #776)
|
37
|
+
* Improve `raise_error` matcher so that it can accept a matcher as a single argument
|
38
|
+
that matches the message. (Time Wade, #782)
|
39
|
+
|
40
|
+
Bug Fixes:
|
41
|
+
|
42
|
+
* Make `contain_exactly` / `match_array` work with strict test doubles
|
43
|
+
that have not defined `<=>`. (Myron Marston, #758)
|
44
|
+
* Fix `include` matcher so that it omits the diff when it would
|
45
|
+
confusingly highlight items that are actually included but are not
|
46
|
+
an exact match in a line-by-line diff. (Tim Wade, #763)
|
47
|
+
* Fix `match` matcher so that it does not blow up when matching a string
|
48
|
+
or regex against another matcher (rather than a string or regex).
|
49
|
+
(Myron Marston, #772)
|
50
|
+
* Silence whitespace-only diffs. (Myron Marston, #801)
|
51
|
+
|
1
52
|
### 3.2.1 / 2015-04-06
|
2
53
|
[Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.2.0...v3.2.1)
|
3
54
|
|
@@ -321,7 +372,7 @@ Breaking Changes for 3.0.0:
|
|
321
372
|
(Sam Phippen)
|
322
373
|
* Remove the deprecated `have`, `have_at_least` and `have_at_most` matchers.
|
323
374
|
You can continue using those matchers through https://github.com/rspec/rspec-collection_matchers,
|
324
|
-
or you can rewrite your expectations with something like
|
375
|
+
or you can rewrite your expectations with something like
|
325
376
|
`expect(your_object.size).to eq(num)`. (Hugo Baraúna)
|
326
377
|
* Rename `be_true` and `be_false` to `be_truthy` and `be_falsey`. (Sam Phippen)
|
327
378
|
* Make `expect { }.to_not raise_error(SomeSpecificClass, message)`,
|
@@ -442,9 +493,9 @@ Deprecations:
|
|
442
493
|
Deprecations
|
443
494
|
|
444
495
|
* Deprecate `have`, `have_at_least` and `have_at_most`. You can continue using those
|
445
|
-
|
446
|
-
|
447
|
-
|
496
|
+
matchers through https://github.com/rspec/rspec-collection_matchers, or
|
497
|
+
you can rewrite your expectations with something like
|
498
|
+
`expect(your_object.size).to eq(num)`. (Hugo Baraúna)
|
448
499
|
* Deprecate `be_xyz` predicate matcher when `xyz?` is a private method.
|
449
500
|
(Jon Rowe)
|
450
501
|
* Deprecate `be_true`/`be_false` in favour of `be_truthy`/`be_falsey`
|
data/README.md
CHANGED
@@ -95,7 +95,7 @@ Note: The new `expect` syntax no longer supports the `=~` matcher.
|
|
95
95
|
|
96
96
|
```ruby
|
97
97
|
expect(actual).to be_an_instance_of(expected) # passes if actual.class == expected
|
98
|
-
expect(actual).to be_a(expected) # passes if actual.
|
98
|
+
expect(actual).to be_a(expected) # passes if actual.kind_of?(expected)
|
99
99
|
expect(actual).to be_an(expected) # an alias for be_a
|
100
100
|
expect(actual).to be_a_kind_of(expected) # another alias
|
101
101
|
```
|
data/lib/rspec/expectations.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'rspec/support'
|
2
2
|
RSpec::Support.require_rspec_support "caller_filter"
|
3
3
|
RSpec::Support.require_rspec_support "warnings"
|
4
|
+
RSpec::Support.require_rspec_support "object_formatter"
|
4
5
|
|
5
6
|
require 'rspec/matchers'
|
6
7
|
|
@@ -63,7 +64,18 @@ module RSpec
|
|
63
64
|
# the user sets an expectation, it can't be caught in their
|
64
65
|
# code by a bare `rescue`.
|
65
66
|
# @api public
|
66
|
-
class ExpectationNotMetError <
|
67
|
+
class ExpectationNotMetError < Exception
|
67
68
|
end
|
69
|
+
|
70
|
+
# Exception raised from `aggregate_failures` when multiple expectations fail.
|
71
|
+
#
|
72
|
+
# @note The constant is defined here but the extensive logic of this class
|
73
|
+
# is lazily defined when `FailureAggregator` is autoloaded, since we do
|
74
|
+
# not need to waste time defining that functionality unless
|
75
|
+
# `aggregate_failures` is used.
|
76
|
+
class MultipleExpectationsNotMetError < ExpectationNotMetError
|
77
|
+
end
|
78
|
+
|
79
|
+
autoload :FailureAggregator, "rspec/expectations/failure_aggregator"
|
68
80
|
end
|
69
81
|
end
|
@@ -18,6 +18,10 @@ module RSpec
|
|
18
18
|
#
|
19
19
|
# RSpec::Expectations.configuration
|
20
20
|
class Configuration
|
21
|
+
def initialize
|
22
|
+
@warn_about_potential_false_positives = true
|
23
|
+
end
|
24
|
+
|
21
25
|
# Configures the supported syntax.
|
22
26
|
# @param [Array<Symbol>, Symbol] values the syntaxes to enable
|
23
27
|
# @example
|
@@ -133,6 +137,19 @@ module RSpec
|
|
133
137
|
backtrace
|
134
138
|
end
|
135
139
|
end
|
140
|
+
|
141
|
+
# Configures whether RSpec will warn about matcher use which will
|
142
|
+
# potentially cause false positives in tests.
|
143
|
+
#
|
144
|
+
# @param value [Boolean]
|
145
|
+
attr_writer :warn_about_potential_false_positives
|
146
|
+
|
147
|
+
# Indicates whether RSpec will warn about matcher use which will
|
148
|
+
# potentially cause false positives in tests, generally you want to
|
149
|
+
# avoid such scenarios so this defaults to `true`.
|
150
|
+
def warn_about_potential_false_positives?
|
151
|
+
@warn_about_potential_false_positives
|
152
|
+
end
|
136
153
|
end
|
137
154
|
|
138
155
|
# The configuration object.
|
@@ -98,9 +98,9 @@ module RSpec
|
|
98
98
|
def enforce_block_expectation(matcher)
|
99
99
|
return if supports_block_expectations?(matcher)
|
100
100
|
|
101
|
-
raise ExpectationNotMetError, "You must pass an argument rather than " \
|
102
|
-
"
|
103
|
-
"
|
101
|
+
raise ExpectationNotMetError, "You must pass an argument rather than a block to use the provided " \
|
102
|
+
"matcher (#{RSpec::Support::ObjectFormatter.format(matcher)}), or the matcher must implement " \
|
103
|
+
"`supports_block_expectations?`."
|
104
104
|
end
|
105
105
|
|
106
106
|
def supports_block_expectations?(matcher)
|
@@ -108,12 +108,6 @@ module RSpec
|
|
108
108
|
rescue NoMethodError
|
109
109
|
false
|
110
110
|
end
|
111
|
-
|
112
|
-
def description_of(matcher)
|
113
|
-
matcher.description
|
114
|
-
rescue NoMethodError
|
115
|
-
matcher.inspect
|
116
|
-
end
|
117
111
|
end
|
118
112
|
end
|
119
113
|
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
RSpec::Support.require_rspec_support 'differ'
|
2
|
-
|
3
1
|
module RSpec
|
4
2
|
module Expectations
|
5
3
|
class << self
|
@@ -26,7 +24,7 @@ module RSpec
|
|
26
24
|
|
27
25
|
message = ::RSpec::Matchers::ExpectedsForMultipleDiffs.from(expected).message_with_diff(message, differ, actual)
|
28
26
|
|
29
|
-
|
27
|
+
RSpec::Support.notify_failure(RSpec::Expectations::ExpectationNotMetError.new message)
|
30
28
|
end
|
31
29
|
end
|
32
30
|
end
|
@@ -0,0 +1,194 @@
|
|
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 Exception => 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?
|
56
|
+
# On JRuby, `caller` and `raise` produce different backtraces with regards to `.java`
|
57
|
+
# stack frames. It's important that we use `raise` for JRuby to produce a backtrace
|
58
|
+
# 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 nil
|
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
|
154
|
+
"#{index_label index}#{indented formatted_message, index}"
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def enumerated_failures
|
159
|
+
enumerated(failures, 0, &:message)
|
160
|
+
end
|
161
|
+
|
162
|
+
def enumerated_errors
|
163
|
+
enumerated(other_errors, failures.size) do |error|
|
164
|
+
"#{error.class}: #{error.message}"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def indented(failure_message, index)
|
169
|
+
line_1, *rest = failure_message.strip.lines.to_a
|
170
|
+
first_line_indentation = ' ' * (longest_index_label_width - width_of_label(index))
|
171
|
+
|
172
|
+
first_line_indentation + line_1 + rest.map do |line|
|
173
|
+
line =~ /\S/ ? indentation + line : line
|
174
|
+
end.join
|
175
|
+
end
|
176
|
+
|
177
|
+
def indentation
|
178
|
+
@indentation ||= ' ' * longest_index_label_width
|
179
|
+
end
|
180
|
+
|
181
|
+
def longest_index_label_width
|
182
|
+
@longest_index_label_width ||= width_of_label(failures.size)
|
183
|
+
end
|
184
|
+
|
185
|
+
def width_of_label(index)
|
186
|
+
index_label(index).chars.count
|
187
|
+
end
|
188
|
+
|
189
|
+
def index_label(index)
|
190
|
+
" #{index + 1}) "
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
@@ -7,6 +7,19 @@ Minitest::Test.class_eval do
|
|
7
7
|
assert(true) # so each expectation gets counted in minitest's assertion stats
|
8
8
|
super
|
9
9
|
end
|
10
|
+
|
11
|
+
# Convert a `MultipleExpectationsNotMetError` to a `Minitest::Assertion` error so
|
12
|
+
# it gets counted in minitest's summary stats as a failure rather than an error.
|
13
|
+
# It would be nice to make `MultipleExpectationsNotMetError` subclass
|
14
|
+
# `Minitest::Assertion`, but Minitest's implementation does not treat subclasses
|
15
|
+
# the same, so this is the best we can do.
|
16
|
+
def aggregate_failures(*args, &block)
|
17
|
+
super
|
18
|
+
rescue RSpec::Expectations::MultipleExpectationsNotMetError => e
|
19
|
+
assertion_failed = Minitest::Assertion.new(e.message)
|
20
|
+
assertion_failed.set_backtrace e.backtrace
|
21
|
+
raise assertion_failed
|
22
|
+
end
|
10
23
|
end
|
11
24
|
|
12
25
|
module RSpec
|
data/lib/rspec/matchers.rb
CHANGED
@@ -3,7 +3,7 @@ RSpec::Support.require_rspec_support 'matcher_definition'
|
|
3
3
|
RSpec::Support.define_optimized_require_for_rspec(:matchers) { |f| require_relative(f) }
|
4
4
|
|
5
5
|
%w[
|
6
|
-
|
6
|
+
english_phrasing
|
7
7
|
composable
|
8
8
|
built_in
|
9
9
|
generated_descriptions
|
@@ -243,7 +243,7 @@ module RSpec
|
|
243
243
|
# alias $1 $2
|
244
244
|
def self.alias_matcher(new_name, old_name, options={}, &description_override)
|
245
245
|
description_override ||= lambda do |old_desc|
|
246
|
-
old_desc.gsub(
|
246
|
+
old_desc.gsub(EnglishPhrasing.split_words(old_name), EnglishPhrasing.split_words(new_name))
|
247
247
|
end
|
248
248
|
klass = options.fetch(:klass) { AliasedMatcher }
|
249
249
|
|
@@ -277,6 +277,42 @@ module RSpec
|
|
277
277
|
alias_matcher(negated_name, base_name, :klass => AliasedNegatedMatcher, &description_override)
|
278
278
|
end
|
279
279
|
|
280
|
+
# Allows multiple expectations in the provided block to fail, and then
|
281
|
+
# aggregates them into a single exception, rather than aborting on the
|
282
|
+
# first expectation failure like normal. This allows you to see all
|
283
|
+
# failures from an entire set of expectations without splitting each
|
284
|
+
# off into its own example (which may slow things down if the example
|
285
|
+
# setup is expensive).
|
286
|
+
#
|
287
|
+
# @param label [String] label for this aggregation block, which will be
|
288
|
+
# included in the aggregated exception message.
|
289
|
+
# @param metadata [Hash] additional metadata about this failure aggregation
|
290
|
+
# block. If multiple expectations fail, it will be exposed from the
|
291
|
+
# {Expectations::MultipleExpectationsNotMetError} exception. Mostly
|
292
|
+
# intended for internal RSpec use but you can use it as well.
|
293
|
+
# @yield Block containing as many expectation as you want. The block is
|
294
|
+
# simply yielded to, so you can trust that anything that works outside
|
295
|
+
# the block should work within it.
|
296
|
+
# @raise [Expectations::MultipleExpectationsNotMetError] raised when
|
297
|
+
# multiple expectations fail.
|
298
|
+
# @raise [Expectations::ExpectationNotMetError] raised when a single
|
299
|
+
# expectation fails.
|
300
|
+
# @raise [Exception] other sorts of exceptions will be raised as normal.
|
301
|
+
#
|
302
|
+
# @example
|
303
|
+
# aggregate_failures("verifying response") do
|
304
|
+
# expect(response.status).to eq(200)
|
305
|
+
# expect(response.headers).to include("Content-Type" => "text/plain")
|
306
|
+
# expect(response.body).to include("Success")
|
307
|
+
# end
|
308
|
+
#
|
309
|
+
# @note The implementation of this feature uses a thread-local variable,
|
310
|
+
# which means that if you have an expectation failure in another thread,
|
311
|
+
# it'll abort like normal.
|
312
|
+
def aggregate_failures(label=nil, metadata={}, &block)
|
313
|
+
Expectations::FailureAggregator.new(label, metadata).aggregate(&block)
|
314
|
+
end
|
315
|
+
|
280
316
|
# Passes if actual is truthy (anything but false or nil)
|
281
317
|
def be_truthy
|
282
318
|
BuiltIn::BeTruthy.new
|
@@ -732,7 +768,7 @@ module RSpec
|
|
732
768
|
# expect { do_something_risky }.to raise_error(PoorRiskDecisionError, /oo ri/)
|
733
769
|
#
|
734
770
|
# expect { do_something_risky }.not_to raise_error
|
735
|
-
def raise_error(error=
|
771
|
+
def raise_error(error=nil, message=nil, &block)
|
736
772
|
BuiltIn::RaiseError.new(error, message, &block)
|
737
773
|
end
|
738
774
|
alias_method :raise_exception, :raise_error
|
@@ -767,10 +803,13 @@ module RSpec
|
|
767
803
|
# If you do find yourself in such a situation, you could always write
|
768
804
|
# a custom matcher, which would likely make your specs more expressive.
|
769
805
|
#
|
806
|
+
# @param description [String] optional description to be used for this matcher.
|
807
|
+
#
|
770
808
|
# @example
|
771
809
|
# expect(5).to satisfy { |n| n > 3 }
|
772
|
-
|
773
|
-
|
810
|
+
# expect(5).to satisfy("be greater than 3") { |n| n > 3 }
|
811
|
+
def satisfy(description="satisfy block", &block)
|
812
|
+
BuiltIn::Satisfy.new(description, &block)
|
774
813
|
end
|
775
814
|
alias_matcher :an_object_satisfying, :satisfy
|
776
815
|
alias_matcher :satisfying, :satisfy
|
@@ -915,6 +954,7 @@ module RSpec
|
|
915
954
|
|
916
955
|
BE_PREDICATE_REGEX = /^(be_(?:an?_)?)(.*)/
|
917
956
|
HAS_REGEX = /^(?:have_)(.*)/
|
957
|
+
DYNAMIC_MATCHER_REGEX = Regexp.union(BE_PREDICATE_REGEX, HAS_REGEX)
|
918
958
|
|
919
959
|
def method_missing(method, *args, &block)
|
920
960
|
case method.to_s
|
@@ -927,6 +967,20 @@ module RSpec
|
|
927
967
|
end
|
928
968
|
end
|
929
969
|
|
970
|
+
if RUBY_VERSION.to_f >= 1.9
|
971
|
+
def respond_to_missing?(method, *)
|
972
|
+
method =~ DYNAMIC_MATCHER_REGEX || super
|
973
|
+
end
|
974
|
+
else # for 1.8.7
|
975
|
+
# :nocov:
|
976
|
+
def respond_to?(method, *)
|
977
|
+
method = method.to_s
|
978
|
+
method =~ DYNAMIC_MATCHER_REGEX || super
|
979
|
+
end
|
980
|
+
public :respond_to?
|
981
|
+
# :nocov:
|
982
|
+
end
|
983
|
+
|
930
984
|
# @api private
|
931
985
|
def self.is_a_matcher?(obj)
|
932
986
|
return true if ::RSpec::Matchers::BuiltIn::BaseMatcher === obj
|