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
data/lib/rspec/matchers.rb
CHANGED
@@ -1,15 +1,24 @@
|
|
1
|
+
require 'rspec/support'
|
2
|
+
RSpec::Support.require_rspec_support 'matcher_definition'
|
3
|
+
RSpec::Support.define_optimized_require_for_rspec(:matchers) { |f| require_relative(f) }
|
4
|
+
|
5
|
+
%w[
|
6
|
+
english_phrasing
|
7
|
+
composable
|
8
|
+
built_in
|
9
|
+
generated_descriptions
|
10
|
+
dsl
|
11
|
+
matcher_delegator
|
12
|
+
aliased_matcher
|
13
|
+
expecteds_for_multiple_diffs
|
14
|
+
].each { |file| RSpec::Support.require_rspec_matchers(file) }
|
15
|
+
|
16
|
+
# RSpec's top level namespace. All of rspec-expectations is contained
|
17
|
+
# in the `RSpec::Expectations` and `RSpec::Matchers` namespaces.
|
1
18
|
module RSpec
|
2
|
-
# RSpec::Matchers provides a number of useful matchers we use to
|
3
|
-
# expectations.
|
4
|
-
#
|
5
|
-
# matches?(actual)
|
6
|
-
# failure_message_for_should
|
7
|
-
#
|
8
|
-
# These methods are also part of the matcher protocol, but are optional:
|
9
|
-
#
|
10
|
-
# does_not_match?(actual)
|
11
|
-
# failure_message_for_should_not
|
12
|
-
# description
|
19
|
+
# RSpec::Matchers provides a number of useful matchers we use to define
|
20
|
+
# expectations. Any object that implements the [matcher protocol](Matchers/MatcherProtocol)
|
21
|
+
# can be used as a matcher.
|
13
22
|
#
|
14
23
|
# ## Predicates
|
15
24
|
#
|
@@ -20,32 +29,59 @@ module RSpec
|
|
20
29
|
# A Ruby predicate is a method that ends with a "?" and returns true or false.
|
21
30
|
# Common examples are `empty?`, `nil?`, and `instance_of?`.
|
22
31
|
#
|
23
|
-
# All you need to do is write `
|
24
|
-
# the question mark, and RSpec will figure it out from there.
|
32
|
+
# All you need to do is write `expect(..).to be_` followed by the predicate
|
33
|
+
# without the question mark, and RSpec will figure it out from there.
|
34
|
+
# For example:
|
25
35
|
#
|
26
|
-
# [].
|
27
|
-
# [].
|
36
|
+
# expect([]).to be_empty # => [].empty?() | passes
|
37
|
+
# expect([]).not_to be_empty # => [].empty?() | fails
|
28
38
|
#
|
29
39
|
# In addtion to prefixing the predicate matchers with "be_", you can also use "be_a_"
|
30
40
|
# and "be_an_", making your specs read much more naturally:
|
31
41
|
#
|
32
|
-
# "a string".
|
42
|
+
# expect("a string").to be_an_instance_of(String) # =>"a string".instance_of?(String) # passes
|
33
43
|
#
|
34
|
-
# 3.
|
35
|
-
# 3.
|
36
|
-
# 3.
|
37
|
-
# 3.
|
44
|
+
# expect(3).to be_a_kind_of(Integer) # => 3.kind_of?(Numeric) | passes
|
45
|
+
# expect(3).to be_a_kind_of(Numeric) # => 3.kind_of?(Numeric) | passes
|
46
|
+
# expect(3).to be_an_instance_of(Integer) # => 3.instance_of?(Integer) | passes
|
47
|
+
# expect(3).not_to be_an_instance_of(Numeric) # => 3.instance_of?(Numeric) | fails
|
38
48
|
#
|
39
49
|
# RSpec will also create custom matchers for predicates like `has_key?`. To
|
40
50
|
# use this feature, just state that the object should have_key(:key) and RSpec will
|
41
51
|
# call has_key?(:key) on the target. For example:
|
42
52
|
#
|
43
|
-
#
|
44
|
-
#
|
53
|
+
# expect(:a => "A").to have_key(:a)
|
54
|
+
# expect(:a => "A").to have_key(:b) # fails
|
45
55
|
#
|
46
56
|
# You can use this feature to invoke any predicate that begins with "has_", whether it is
|
47
57
|
# part of the Ruby libraries (like `Hash#has_key?`) or a method you wrote on your own class.
|
48
58
|
#
|
59
|
+
# Note that RSpec does not provide composable aliases for these dynamic predicate
|
60
|
+
# matchers. You can easily define your own aliases, though:
|
61
|
+
#
|
62
|
+
# RSpec::Matchers.alias_matcher :a_user_who_is_an_admin, :be_an_admin
|
63
|
+
# expect(user_list).to include(a_user_who_is_an_admin)
|
64
|
+
#
|
65
|
+
# ## Alias Matchers
|
66
|
+
#
|
67
|
+
# With {RSpec::Matchers.alias_matcher}, you can easily create an
|
68
|
+
# alternate name for a given matcher.
|
69
|
+
#
|
70
|
+
# The description will also change according to the new name:
|
71
|
+
#
|
72
|
+
# RSpec::Matchers.alias_matcher :a_list_that_sums_to, :sum_to
|
73
|
+
# sum_to(3).description # => "sum to 3"
|
74
|
+
# a_list_that_sums_to(3).description # => "a list that sums to 3"
|
75
|
+
#
|
76
|
+
# or you can specify a custom description like this:
|
77
|
+
#
|
78
|
+
# RSpec::Matchers.alias_matcher :a_list_sorted_by, :be_sorted_by do |description|
|
79
|
+
# description.sub("be sorted by", "a list sorted by")
|
80
|
+
# end
|
81
|
+
#
|
82
|
+
# be_sorted_by(:age).description # => "be sorted by age"
|
83
|
+
# a_list_sorted_by(:age).description # => "a list sorted by age"
|
84
|
+
#
|
49
85
|
# ## Custom Matchers
|
50
86
|
#
|
51
87
|
# When you find that none of the stock matchers provide a natural feeling
|
@@ -58,15 +94,15 @@ module RSpec
|
|
58
94
|
# zones on a virtual board. To specify that bob should be in zone 4, you
|
59
95
|
# could say:
|
60
96
|
#
|
61
|
-
# bob.current_zone.
|
97
|
+
# expect(bob.current_zone).to eql(Zone.new("4"))
|
62
98
|
#
|
63
99
|
# But you might find it more expressive to say:
|
64
100
|
#
|
65
|
-
# bob.
|
101
|
+
# expect(bob).to be_in_zone("4")
|
66
102
|
#
|
67
103
|
# and/or
|
68
104
|
#
|
69
|
-
# bob.
|
105
|
+
# expect(bob).not_to be_in_zone("3")
|
70
106
|
#
|
71
107
|
# You can create such a matcher like so:
|
72
108
|
#
|
@@ -85,11 +121,11 @@ module RSpec
|
|
85
121
|
# player.in_zone?(zone)
|
86
122
|
# end
|
87
123
|
#
|
88
|
-
#
|
124
|
+
# failure_message do |player|
|
89
125
|
# # generate and return the appropriate string.
|
90
126
|
# end
|
91
127
|
#
|
92
|
-
#
|
128
|
+
# failure_message_when_negated do |player|
|
93
129
|
# # generate and return the appropriate string.
|
94
130
|
# end
|
95
131
|
#
|
@@ -100,9 +136,9 @@ module RSpec
|
|
100
136
|
#
|
101
137
|
# Each of the message-generation methods has access to the block arguments
|
102
138
|
# passed to the <tt>create</tt> method (in this case, <tt>zone</tt>). The
|
103
|
-
# failure message methods (<tt>
|
104
|
-
# <tt>
|
105
|
-
# receiver of <tt>
|
139
|
+
# failure message methods (<tt>failure_message</tt> and
|
140
|
+
# <tt>failure_message_when_negated</tt>) are passed the actual value (the
|
141
|
+
# receiver of <tt>expect(..)</tt> or <tt>expect(..).not_to</tt>).
|
106
142
|
#
|
107
143
|
# ### Custom Matcher from scratch
|
108
144
|
#
|
@@ -118,11 +154,11 @@ module RSpec
|
|
118
154
|
# @target.current_zone.eql?(Zone.new(@expected))
|
119
155
|
# end
|
120
156
|
#
|
121
|
-
# def
|
157
|
+
# def failure_message
|
122
158
|
# "expected #{@target.inspect} to be in Zone #{@expected}"
|
123
159
|
# end
|
124
160
|
#
|
125
|
-
# def
|
161
|
+
# def failure_message_when_negated
|
126
162
|
# "expected #{@target.inspect} not to be in Zone #{@expected}"
|
127
163
|
# end
|
128
164
|
# end
|
@@ -158,63 +194,149 @@ module RSpec
|
|
158
194
|
# RSpec::configure do |config|
|
159
195
|
# config.include(CustomGameMatchers)
|
160
196
|
# end
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
197
|
+
#
|
198
|
+
# ### Making custom matchers composable
|
199
|
+
#
|
200
|
+
# RSpec's built-in matchers are designed to be composed, in expressions like:
|
201
|
+
#
|
202
|
+
# expect(["barn", 2.45]).to contain_exactly(
|
203
|
+
# a_value_within(0.1).of(2.5),
|
204
|
+
# a_string_starting_with("bar")
|
205
|
+
# )
|
206
|
+
#
|
207
|
+
# Custom matchers can easily participate in composed matcher expressions like these.
|
208
|
+
# Include {RSpec::Matchers::Composable} in your custom matcher to make it support
|
209
|
+
# being composed (matchers defined using the DSL have this included automatically).
|
210
|
+
# Within your matcher's `matches?` method (or the `match` block, if using the DSL),
|
211
|
+
# use `values_match?(expected, actual)` rather than `expected == actual`.
|
212
|
+
# Under the covers, `values_match?` is able to match arbitrary
|
213
|
+
# nested data structures containing a mix of both matchers and non-matcher objects.
|
214
|
+
# It uses `===` and `==` to perform the matching, considering the values to
|
215
|
+
# match if either returns `true`. The `Composable` mixin also provides some helper
|
216
|
+
# methods for surfacing the matcher descriptions within your matcher's description
|
217
|
+
# or failure messages.
|
218
|
+
#
|
219
|
+
# RSpec's built-in matchers each have a number of aliases that rephrase the matcher
|
220
|
+
# from a verb phrase (such as `be_within`) to a noun phrase (such as `a_value_within`),
|
221
|
+
# which reads better when the matcher is passed as an argument in a composed matcher
|
222
|
+
# expressions, and also uses the noun-phrase wording in the matcher's `description`,
|
223
|
+
# for readable failure messages. You can alias your custom matchers in similar fashion
|
224
|
+
# using {RSpec::Matchers.alias_matcher}.
|
225
|
+
#
|
226
|
+
# ## Negated Matchers
|
227
|
+
#
|
228
|
+
# Sometimes if you want to test for the opposite using a more descriptive name
|
229
|
+
# instead of using `not_to`, you can use {RSpec::Matchers.define_negated_matcher}:
|
230
|
+
#
|
231
|
+
# RSpec::Matchers.define_negated_matcher :exclude, :include
|
232
|
+
# include(1, 2).description # => "include 1 and 2"
|
233
|
+
# exclude(1, 2).description # => "exclude 1 and 2"
|
234
|
+
#
|
235
|
+
# While the most obvious negated form may be to add a `not_` prefix,
|
236
|
+
# the failure messages you get with that form can be confusing (e.g.
|
237
|
+
# "expected [actual] to not [verb], but did not"). We've found it works
|
238
|
+
# best to find a more positive name for the negated form, such as
|
239
|
+
# `avoid_changing` rather than `not_change`.
|
240
|
+
#
|
241
|
+
module Matchers # rubocop:disable Metrics/ModuleLength
|
242
|
+
extend ::RSpec::Matchers::DSL
|
243
|
+
|
244
|
+
# @!macro [attach] alias_matcher
|
245
|
+
# @!parse
|
246
|
+
# alias $1 $2
|
247
|
+
# @!visibility private
|
248
|
+
# We define this override here so we can attach a YARD macro to it.
|
249
|
+
# It ensures that our docs list all the matcher aliases.
|
250
|
+
def self.alias_matcher(*args, &block)
|
251
|
+
super(*args, &block)
|
172
252
|
end
|
173
|
-
end
|
174
|
-
end
|
175
253
|
|
176
|
-
|
177
|
-
|
254
|
+
# @!method self.alias_matcher(new_name, old_name, options={}, &description_override)
|
255
|
+
# Extended from {RSpec::Matchers::DSL#alias_matcher}.
|
178
256
|
|
179
|
-
|
180
|
-
|
181
|
-
require 'rspec/matchers/operator_matcher'
|
182
|
-
require 'rspec/matchers/be_close'
|
257
|
+
# @!method self.define(name, &declarations)
|
258
|
+
# Extended from {RSpec::Matchers::DSL#define}.
|
183
259
|
|
184
|
-
|
185
|
-
|
186
|
-
require 'rspec/matchers/compatibility'
|
187
|
-
require 'rspec/matchers/dsl'
|
260
|
+
# @!method self.define_negated_matcher(negated_name, base_name, &description_override)
|
261
|
+
# Extended from {RSpec::Matchers::DSL#define_negated_matcher}.
|
188
262
|
|
189
|
-
|
190
|
-
|
263
|
+
# @method expect
|
264
|
+
# Supports `expect(actual).to matcher` syntax by wrapping `actual` in an
|
265
|
+
# `ExpectationTarget`.
|
266
|
+
# @example
|
267
|
+
# expect(actual).to eq(expected)
|
268
|
+
# expect(actual).not_to eq(expected)
|
269
|
+
# @return [Expectations::ExpectationTarget]
|
270
|
+
# @see Expectations::ExpectationTarget#to
|
271
|
+
# @see Expectations::ExpectationTarget#not_to
|
272
|
+
|
273
|
+
# Allows multiple expectations in the provided block to fail, and then
|
274
|
+
# aggregates them into a single exception, rather than aborting on the
|
275
|
+
# first expectation failure like normal. This allows you to see all
|
276
|
+
# failures from an entire set of expectations without splitting each
|
277
|
+
# off into its own example (which may slow things down if the example
|
278
|
+
# setup is expensive).
|
279
|
+
#
|
280
|
+
# @param label [String] label for this aggregation block, which will be
|
281
|
+
# included in the aggregated exception message.
|
282
|
+
# @param metadata [Hash] additional metadata about this failure aggregation
|
283
|
+
# block. If multiple expectations fail, it will be exposed from the
|
284
|
+
# {Expectations::MultipleExpectationsNotMetError} exception. Mostly
|
285
|
+
# intended for internal RSpec use but you can use it as well.
|
286
|
+
# @yield Block containing as many expectation as you want. The block is
|
287
|
+
# simply yielded to, so you can trust that anything that works outside
|
288
|
+
# the block should work within it.
|
289
|
+
# @raise [Expectations::MultipleExpectationsNotMetError] raised when
|
290
|
+
# multiple expectations fail.
|
291
|
+
# @raise [Expectations::ExpectationNotMetError] raised when a single
|
292
|
+
# expectation fails.
|
293
|
+
# @raise [Exception] other sorts of exceptions will be raised as normal.
|
294
|
+
#
|
295
|
+
# @example
|
296
|
+
# aggregate_failures("verifying response") do
|
297
|
+
# expect(response.status).to eq(200)
|
298
|
+
# expect(response.headers).to include("Content-Type" => "text/plain")
|
299
|
+
# expect(response.body).to include("Success")
|
300
|
+
# end
|
301
|
+
#
|
302
|
+
# @note The implementation of this feature uses a thread-local variable,
|
303
|
+
# which means that if you have an expectation failure in another thread,
|
304
|
+
# it'll abort like normal.
|
305
|
+
def aggregate_failures(label=nil, metadata={}, &block)
|
306
|
+
Expectations::FailureAggregator.new(label, metadata).aggregate(&block)
|
307
|
+
end
|
191
308
|
|
192
309
|
# Passes if actual is truthy (anything but false or nil)
|
193
|
-
def
|
194
|
-
BuiltIn::
|
310
|
+
def be_truthy
|
311
|
+
BuiltIn::BeTruthy.new
|
195
312
|
end
|
313
|
+
alias_matcher :a_truthy_value, :be_truthy
|
196
314
|
|
197
|
-
# Passes if actual is
|
198
|
-
def
|
199
|
-
BuiltIn::
|
315
|
+
# Passes if actual is falsey (false or nil)
|
316
|
+
def be_falsey
|
317
|
+
BuiltIn::BeFalsey.new
|
200
318
|
end
|
319
|
+
alias_matcher :be_falsy, :be_falsey
|
320
|
+
alias_matcher :a_falsey_value, :be_falsey
|
321
|
+
alias_matcher :a_falsy_value, :be_falsey
|
201
322
|
|
202
323
|
# Passes if actual is nil
|
203
324
|
def be_nil
|
204
325
|
BuiltIn::BeNil.new
|
205
326
|
end
|
327
|
+
alias_matcher :a_nil_value, :be_nil
|
206
328
|
|
207
329
|
# @example
|
208
|
-
# actual.
|
209
|
-
# actual.
|
210
|
-
# actual.
|
211
|
-
# actual.
|
212
|
-
# actual.
|
213
|
-
# actual.
|
330
|
+
# expect(actual).to be_truthy
|
331
|
+
# expect(actual).to be_falsey
|
332
|
+
# expect(actual).to be_nil
|
333
|
+
# expect(actual).to be_[arbitrary_predicate](*args)
|
334
|
+
# expect(actual).not_to be_nil
|
335
|
+
# expect(actual).not_to be_[arbitrary_predicate](*args)
|
214
336
|
#
|
215
337
|
# Given true, false, or nil, will pass if actual value is true, false or
|
216
338
|
# nil (respectively). Given no args means the caller should satisfy an if
|
217
|
-
# condition (to be or not to be).
|
339
|
+
# condition (to be or not to be).
|
218
340
|
#
|
219
341
|
# Predicates are any Ruby method that ends in a "?" and returns true or
|
220
342
|
# false. Given be_ followed by arbitrary_predicate (without the "?"),
|
@@ -225,52 +347,66 @@ module RSpec
|
|
225
347
|
# (e.g. be_empty), letting you choose the prefix that best suits the
|
226
348
|
# predicate.
|
227
349
|
def be(*args)
|
228
|
-
args.empty? ?
|
229
|
-
Matchers::BuiltIn::Be.new : equal(*args)
|
350
|
+
args.empty? ? Matchers::BuiltIn::Be.new : equal(*args)
|
230
351
|
end
|
352
|
+
alias_matcher :a_value, :be, :klass => AliasedMatcherWithOperatorSupport
|
231
353
|
|
232
354
|
# passes if target.kind_of?(klass)
|
233
355
|
def be_a(klass)
|
234
356
|
be_a_kind_of(klass)
|
235
357
|
end
|
236
|
-
|
237
358
|
alias_method :be_an, :be_a
|
238
359
|
|
239
360
|
# Passes if actual.instance_of?(expected)
|
240
361
|
#
|
241
362
|
# @example
|
242
|
-
#
|
243
|
-
# 5.
|
244
|
-
# 5.
|
245
|
-
# 5.should_not be_instance_of(Float)
|
363
|
+
# expect(5).to be_an_instance_of(Integer)
|
364
|
+
# expect(5).not_to be_an_instance_of(Numeric)
|
365
|
+
# expect(5).not_to be_an_instance_of(Float)
|
246
366
|
def be_an_instance_of(expected)
|
247
367
|
BuiltIn::BeAnInstanceOf.new(expected)
|
248
368
|
end
|
249
|
-
|
250
369
|
alias_method :be_instance_of, :be_an_instance_of
|
370
|
+
alias_matcher :an_instance_of, :be_an_instance_of
|
251
371
|
|
252
372
|
# Passes if actual.kind_of?(expected)
|
253
373
|
#
|
254
374
|
# @example
|
255
|
-
#
|
256
|
-
# 5.
|
257
|
-
# 5.
|
258
|
-
# 5.should_not be_kind_of(Float)
|
375
|
+
# expect(5).to be_a_kind_of(Integer)
|
376
|
+
# expect(5).to be_a_kind_of(Numeric)
|
377
|
+
# expect(5).not_to be_a_kind_of(Float)
|
259
378
|
def be_a_kind_of(expected)
|
260
379
|
BuiltIn::BeAKindOf.new(expected)
|
261
380
|
end
|
262
|
-
|
263
381
|
alias_method :be_kind_of, :be_a_kind_of
|
382
|
+
alias_matcher :a_kind_of, :be_a_kind_of
|
264
383
|
|
265
|
-
# Passes if actual
|
384
|
+
# Passes if actual.between?(min, max). Works with any Comparable object,
|
385
|
+
# including String, Symbol, Time, or Numeric (Fixnum, Bignum, Integer,
|
386
|
+
# Float, Complex, and Rational).
|
387
|
+
#
|
388
|
+
# By default, `be_between` is inclusive (i.e. passes when given either the max or min value),
|
389
|
+
# but you can make it `exclusive` by chaining that off the matcher.
|
266
390
|
#
|
267
391
|
# @example
|
392
|
+
# expect(5).to be_between(1, 10)
|
393
|
+
# expect(11).not_to be_between(1, 10)
|
394
|
+
# expect(10).not_to be_between(1, 10).exclusive
|
395
|
+
def be_between(min, max)
|
396
|
+
BuiltIn::BeBetween.new(min, max)
|
397
|
+
end
|
398
|
+
alias_matcher :a_value_between, :be_between
|
399
|
+
|
400
|
+
# Passes if actual == expected +/- delta
|
268
401
|
#
|
269
|
-
#
|
270
|
-
# result.
|
402
|
+
# @example
|
403
|
+
# expect(result).to be_within(0.5).of(3.0)
|
404
|
+
# expect(result).not_to be_within(0.5).of(3.0)
|
271
405
|
def be_within(delta)
|
272
406
|
BuiltIn::BeWithin.new(delta)
|
273
407
|
end
|
408
|
+
alias_matcher :a_value_within, :be_within
|
409
|
+
alias_matcher :within, :be_within
|
274
410
|
|
275
411
|
# Applied to a proc, specifies that its execution will cause some value to
|
276
412
|
# change.
|
@@ -281,78 +417,119 @@ module RSpec
|
|
281
417
|
# You can either pass <tt>receiver</tt> and <tt>message</tt>, or a block,
|
282
418
|
# but not both.
|
283
419
|
#
|
284
|
-
# When passing a block, it must use the
|
285
|
-
# do/end, as
|
286
|
-
# would errantly bind to the
|
420
|
+
# When passing a block, it must use the `{ ... }` format, not
|
421
|
+
# do/end, as `{ ... }` binds to the `change` method, whereas do/end
|
422
|
+
# would errantly bind to the `expect(..).to` or `expect(...).not_to` method.
|
287
423
|
#
|
288
|
-
#
|
424
|
+
# You can chain any of the following off of the end to specify details
|
425
|
+
# about the change:
|
426
|
+
#
|
427
|
+
# * `from`
|
428
|
+
# * `to`
|
289
429
|
#
|
290
|
-
#
|
291
|
-
# team.add_player(player)
|
292
|
-
# }.should change(roster, :count)
|
430
|
+
# or any one of:
|
293
431
|
#
|
294
|
-
#
|
295
|
-
#
|
296
|
-
#
|
432
|
+
# * `by`
|
433
|
+
# * `by_at_least`
|
434
|
+
# * `by_at_most`
|
297
435
|
#
|
298
|
-
#
|
299
|
-
#
|
300
|
-
#
|
436
|
+
# @example
|
437
|
+
# expect {
|
438
|
+
# team.add_player(player)
|
439
|
+
# }.to change(roster, :count)
|
301
440
|
#
|
302
|
-
#
|
441
|
+
# expect {
|
303
442
|
# team.add_player(player)
|
304
|
-
# }.
|
443
|
+
# }.to change(roster, :count).by(1)
|
444
|
+
#
|
445
|
+
# expect {
|
446
|
+
# team.add_player(player)
|
447
|
+
# }.to change(roster, :count).by_at_least(1)
|
448
|
+
#
|
449
|
+
# expect {
|
450
|
+
# team.add_player(player)
|
451
|
+
# }.to change(roster, :count).by_at_most(1)
|
305
452
|
#
|
306
453
|
# string = "string"
|
307
|
-
#
|
454
|
+
# expect {
|
308
455
|
# string.reverse!
|
309
|
-
# }.
|
456
|
+
# }.to change { string }.from("string").to("gnirts")
|
310
457
|
#
|
311
|
-
#
|
458
|
+
# string = "string"
|
459
|
+
# expect {
|
460
|
+
# string
|
461
|
+
# }.not_to change { string }.from("string")
|
462
|
+
#
|
463
|
+
# expect {
|
312
464
|
# person.happy_birthday
|
313
|
-
# }.
|
314
|
-
#
|
315
|
-
#
|
465
|
+
# }.to change(person, :birthday).from(32).to(33)
|
466
|
+
#
|
467
|
+
# expect {
|
316
468
|
# employee.develop_great_new_social_networking_app
|
317
|
-
# }.
|
469
|
+
# }.to change(employee, :title).from("Mail Clerk").to("CEO")
|
318
470
|
#
|
319
|
-
#
|
471
|
+
# expect {
|
320
472
|
# doctor.leave_office
|
321
|
-
# }.
|
473
|
+
# }.to change(doctor, :sign).from(/is in/).to(/is out/)
|
322
474
|
#
|
323
475
|
# user = User.new(:type => "admin")
|
324
|
-
#
|
476
|
+
# expect {
|
325
477
|
# user.symbolize_type
|
326
|
-
# }.
|
478
|
+
# }.to change(user, :type).from(String).to(Symbol)
|
327
479
|
#
|
328
480
|
# == Notes
|
329
481
|
#
|
330
|
-
# Evaluates
|
331
|
-
# evaluates the
|
332
|
-
#
|
482
|
+
# Evaluates `receiver.message` or `block` before and after it
|
483
|
+
# evaluates the block passed to `expect`. If the value is the same
|
484
|
+
# object, its before/after `hash` value is used to see if it has changed.
|
485
|
+
# Therefore, your object needs to properly implement `hash` to work correctly
|
486
|
+
# with this matcher.
|
333
487
|
#
|
334
|
-
#
|
335
|
-
#
|
336
|
-
#
|
488
|
+
# `expect( ... ).not_to change` supports the form that specifies `from`
|
489
|
+
# (which specifies what you expect the starting, unchanged value to be)
|
490
|
+
# but does not support forms with subsequent calls to `by`, `by_at_least`,
|
491
|
+
# `by_at_most` or `to`.
|
337
492
|
def change(receiver=nil, message=nil, &block)
|
338
493
|
BuiltIn::Change.new(receiver, message, &block)
|
339
494
|
end
|
495
|
+
alias_matcher :a_block_changing, :change
|
496
|
+
alias_matcher :changing, :change
|
497
|
+
|
498
|
+
# Passes if actual contains all of the expected regardless of order.
|
499
|
+
# This works for collections. Pass in multiple args and it will only
|
500
|
+
# pass if all args are found in collection.
|
501
|
+
#
|
502
|
+
# @note This is also available using the `=~` operator with `should`,
|
503
|
+
# but `=~` is not supported with `expect`.
|
504
|
+
#
|
505
|
+
# @example
|
506
|
+
# expect([1, 2, 3]).to contain_exactly(1, 2, 3)
|
507
|
+
# expect([1, 2, 3]).to contain_exactly(1, 3, 2)
|
508
|
+
#
|
509
|
+
# @see #match_array
|
510
|
+
def contain_exactly(*items)
|
511
|
+
BuiltIn::ContainExactly.new(items)
|
512
|
+
end
|
513
|
+
alias_matcher :a_collection_containing_exactly, :contain_exactly
|
514
|
+
alias_matcher :containing_exactly, :contain_exactly
|
340
515
|
|
341
516
|
# Passes if actual covers expected. This works for
|
342
517
|
# Ranges. You can also pass in multiple args
|
343
518
|
# and it will only pass if all args are found in Range.
|
344
519
|
#
|
345
520
|
# @example
|
346
|
-
# (1..10).
|
347
|
-
# (1..10).
|
348
|
-
# (1..10).
|
349
|
-
# (1..10).
|
350
|
-
# (1..10).
|
521
|
+
# expect(1..10).to cover(5)
|
522
|
+
# expect(1..10).to cover(4, 6)
|
523
|
+
# expect(1..10).to cover(4, 6, 11) # fails
|
524
|
+
# expect(1..10).not_to cover(11)
|
525
|
+
# expect(1..10).not_to cover(5) # fails
|
351
526
|
#
|
352
527
|
# ### Warning:: Ruby >= 1.9 only
|
353
528
|
def cover(*values)
|
354
529
|
BuiltIn::Cover.new(*values)
|
355
|
-
end
|
530
|
+
end
|
531
|
+
alias_matcher :a_range_covering, :cover
|
532
|
+
alias_matcher :covering, :cover
|
356
533
|
|
357
534
|
# Matches if the actual value ends with the expected value(s). In the case
|
358
535
|
# of a string, matches against the last `expected.length` characters of the
|
@@ -360,140 +537,219 @@ module RSpec
|
|
360
537
|
# `expected.length` elements of the actual array.
|
361
538
|
#
|
362
539
|
# @example
|
363
|
-
#
|
364
|
-
#
|
365
|
-
# [0,
|
366
|
-
# [0, 2, 3, 4, 4].should end_with 3, 4
|
540
|
+
# expect("this string").to end_with "string"
|
541
|
+
# expect([0, 1, 2, 3, 4]).to end_with 4
|
542
|
+
# expect([0, 2, 3, 4, 4]).to end_with 3, 4
|
367
543
|
def end_with(*expected)
|
368
544
|
BuiltIn::EndWith.new(*expected)
|
369
545
|
end
|
546
|
+
alias_matcher :a_collection_ending_with, :end_with
|
547
|
+
alias_matcher :a_string_ending_with, :end_with
|
548
|
+
alias_matcher :ending_with, :end_with
|
370
549
|
|
371
550
|
# Passes if <tt>actual == expected</tt>.
|
372
551
|
#
|
373
|
-
# See http://www.ruby-doc.org/core/classes/Object.html#M001057 for more
|
552
|
+
# See http://www.ruby-doc.org/core/classes/Object.html#M001057 for more
|
553
|
+
# information about equality in Ruby.
|
374
554
|
#
|
375
555
|
# @example
|
376
|
-
#
|
377
|
-
# 5.
|
378
|
-
# 5.should_not eq(3)
|
556
|
+
# expect(5).to eq(5)
|
557
|
+
# expect(5).not_to eq(3)
|
379
558
|
def eq(expected)
|
380
559
|
BuiltIn::Eq.new(expected)
|
381
560
|
end
|
561
|
+
alias_matcher :an_object_eq_to, :eq
|
562
|
+
alias_matcher :eq_to, :eq
|
382
563
|
|
383
|
-
# Passes if
|
564
|
+
# Passes if `actual.eql?(expected)`
|
384
565
|
#
|
385
|
-
# See http://www.ruby-doc.org/core/classes/Object.html#M001057 for more
|
566
|
+
# See http://www.ruby-doc.org/core/classes/Object.html#M001057 for more
|
567
|
+
# information about equality in Ruby.
|
386
568
|
#
|
387
569
|
# @example
|
388
|
-
#
|
389
|
-
# 5.
|
390
|
-
# 5.should_not eql(3)
|
570
|
+
# expect(5).to eql(5)
|
571
|
+
# expect(5).not_to eql(3)
|
391
572
|
def eql(expected)
|
392
573
|
BuiltIn::Eql.new(expected)
|
393
574
|
end
|
575
|
+
alias_matcher :an_object_eql_to, :eql
|
576
|
+
alias_matcher :eql_to, :eql
|
394
577
|
|
395
578
|
# Passes if <tt>actual.equal?(expected)</tt> (object identity).
|
396
579
|
#
|
397
|
-
# See http://www.ruby-doc.org/core/classes/Object.html#M001057 for more
|
580
|
+
# See http://www.ruby-doc.org/core/classes/Object.html#M001057 for more
|
581
|
+
# information about equality in Ruby.
|
398
582
|
#
|
399
583
|
# @example
|
400
|
-
#
|
401
|
-
# 5.
|
402
|
-
# "5".should_not equal("5") # Strings that look the same are not the same object
|
584
|
+
# expect(5).to equal(5) # Integers are equal
|
585
|
+
# expect("5").not_to equal("5") # Strings that look the same are not the same object
|
403
586
|
def equal(expected)
|
404
587
|
BuiltIn::Equal.new(expected)
|
405
588
|
end
|
589
|
+
alias_matcher :an_object_equal_to, :equal
|
590
|
+
alias_matcher :equal_to, :equal
|
406
591
|
|
407
592
|
# Passes if `actual.exist?` or `actual.exists?`
|
408
593
|
#
|
409
594
|
# @example
|
410
|
-
# File.
|
595
|
+
# expect(File).to exist("path/to/file")
|
411
596
|
def exist(*args)
|
412
597
|
BuiltIn::Exist.new(*args)
|
413
598
|
end
|
599
|
+
alias_matcher :an_object_existing, :exist
|
600
|
+
alias_matcher :existing, :exist
|
414
601
|
|
415
|
-
# Passes if
|
416
|
-
#
|
417
|
-
#
|
418
|
-
# If the receiver OWNS the collection, you must use the name of the
|
419
|
-
# collection. So if a `Team` instance has a collection named `#players`,
|
420
|
-
# you must use that name to set the expectation.
|
421
|
-
#
|
422
|
-
# If the receiver IS the collection, you can use any name you like for
|
423
|
-
# `named_collection`. We'd recommend using either "elements", "members", or
|
424
|
-
# "items" as these are all standard ways of describing the things IN a
|
425
|
-
# collection.
|
426
|
-
#
|
427
|
-
# This also works for Strings, letting you set expectations about their
|
428
|
-
# lengths.
|
602
|
+
# Passes if actual's attribute values match the expected attributes hash.
|
603
|
+
# This works no matter how you define your attribute readers.
|
429
604
|
#
|
430
605
|
# @example
|
606
|
+
# Person = Struct.new(:name, :age)
|
607
|
+
# person = Person.new("Bob", 32)
|
431
608
|
#
|
432
|
-
#
|
433
|
-
#
|
609
|
+
# expect(person).to have_attributes(:name => "Bob", :age => 32)
|
610
|
+
# expect(person).to have_attributes(:name => a_string_starting_with("B"), :age => (a_value > 30) )
|
434
611
|
#
|
435
|
-
#
|
436
|
-
# [1,2,3].should have(3).items #"items" is pure sugar
|
612
|
+
# @note It will fail if actual doesn't respond to any of the expected attributes.
|
437
613
|
#
|
438
|
-
#
|
439
|
-
#
|
614
|
+
# @example
|
615
|
+
# expect(person).to have_attributes(:color => "red")
|
616
|
+
def have_attributes(expected)
|
617
|
+
BuiltIn::HaveAttributes.new(expected)
|
618
|
+
end
|
619
|
+
alias_matcher :an_object_having_attributes, :have_attributes
|
620
|
+
alias_matcher :having_attributes, :have_attributes
|
621
|
+
|
622
|
+
# Passes if actual includes expected. This works for
|
623
|
+
# collections and Strings. You can also pass in multiple args
|
624
|
+
# and it will only pass if all args are found in collection.
|
440
625
|
#
|
441
|
-
#
|
442
|
-
#
|
443
|
-
|
444
|
-
|
626
|
+
# @example
|
627
|
+
# expect([1,2,3]).to include(3)
|
628
|
+
# expect([1,2,3]).to include(2,3)
|
629
|
+
# expect([1,2,3]).to include(2,3,4) # fails
|
630
|
+
# expect([1,2,3]).not_to include(4)
|
631
|
+
# expect("spread").to include("read")
|
632
|
+
# expect("spread").not_to include("red")
|
633
|
+
# expect(:a => 1, :b => 2).to include(:a)
|
634
|
+
# expect(:a => 1, :b => 2).to include(:a, :b)
|
635
|
+
# expect(:a => 1, :b => 2).to include(:a => 1)
|
636
|
+
# expect(:a => 1, :b => 2).to include(:b => 2, :a => 1)
|
637
|
+
# expect(:a => 1, :b => 2).to include(:c) # fails
|
638
|
+
# expect(:a => 1, :b => 2).not_to include(:a => 2)
|
639
|
+
def include(*expected)
|
640
|
+
BuiltIn::Include.new(*expected)
|
445
641
|
end
|
446
|
-
|
642
|
+
alias_matcher :a_collection_including, :include
|
643
|
+
alias_matcher :a_string_including, :include
|
644
|
+
alias_matcher :a_hash_including, :include
|
645
|
+
alias_matcher :including, :include
|
447
646
|
|
448
|
-
#
|
647
|
+
# Passes if the provided matcher passes when checked against all
|
648
|
+
# elements of the collection.
|
449
649
|
#
|
450
650
|
# @example
|
451
|
-
#
|
651
|
+
# expect([1, 3, 5]).to all be_odd
|
652
|
+
# expect([1, 3, 6]).to all be_odd # fails
|
653
|
+
#
|
654
|
+
# @note The negative form `not_to all` is not supported. Instead
|
655
|
+
# use `not_to include` or pass a negative form of a matcher
|
656
|
+
# as the argument (e.g. `all exclude(:foo)`).
|
452
657
|
#
|
453
|
-
#
|
658
|
+
# @note You can also use this with compound matchers as well.
|
454
659
|
#
|
455
|
-
#
|
456
|
-
|
457
|
-
|
660
|
+
# @example
|
661
|
+
# expect([1, 3, 5]).to all( be_odd.and be_an(Integer) )
|
662
|
+
def all(expected)
|
663
|
+
BuiltIn::All.new(expected)
|
458
664
|
end
|
459
665
|
|
460
|
-
#
|
666
|
+
# Given a `Regexp` or `String`, passes if `actual.match(pattern)`
|
667
|
+
# Given an arbitrary nested data structure (e.g. arrays and hashes),
|
668
|
+
# matches if `expected === actual` || `actual == expected` for each
|
669
|
+
# pair of elements.
|
461
670
|
#
|
462
671
|
# @example
|
463
|
-
#
|
672
|
+
# expect(email).to match(/^([^\s]+)((?:[-a-z0-9]+\.)+[a-z]{2,})$/i)
|
673
|
+
# expect(email).to match("@example.com")
|
464
674
|
#
|
465
|
-
#
|
675
|
+
# @example
|
676
|
+
# hash = {
|
677
|
+
# :a => {
|
678
|
+
# :b => ["foo", 5],
|
679
|
+
# :c => { :d => 2.05 }
|
680
|
+
# }
|
681
|
+
# }
|
466
682
|
#
|
467
|
-
#
|
468
|
-
|
469
|
-
|
683
|
+
# expect(hash).to match(
|
684
|
+
# :a => {
|
685
|
+
# :b => a_collection_containing_exactly(
|
686
|
+
# a_string_starting_with("f"),
|
687
|
+
# an_instance_of(Integer)
|
688
|
+
# ),
|
689
|
+
# :c => { :d => (a_value < 3) }
|
690
|
+
# }
|
691
|
+
# )
|
692
|
+
#
|
693
|
+
# @note The `match_regex` alias is deprecated and is not recommended for use.
|
694
|
+
# It was added in 2.12.1 to facilitate its use from within custom
|
695
|
+
# matchers (due to how the custom matcher DSL was evaluated in 2.x,
|
696
|
+
# `match` could not be used there), but is no longer needed in 3.x.
|
697
|
+
def match(expected)
|
698
|
+
BuiltIn::Match.new(expected)
|
470
699
|
end
|
700
|
+
alias_matcher :match_regex, :match
|
701
|
+
alias_matcher :an_object_matching, :match
|
702
|
+
alias_matcher :a_string_matching, :match
|
703
|
+
alias_matcher :matching, :match
|
471
704
|
|
472
|
-
#
|
473
|
-
#
|
474
|
-
#
|
705
|
+
# An alternate form of `contain_exactly` that accepts
|
706
|
+
# the expected contents as a single array arg rather
|
707
|
+
# that splatted out as individual items.
|
475
708
|
#
|
476
709
|
# @example
|
710
|
+
# expect(results).to contain_exactly(1, 2)
|
711
|
+
# # is identical to:
|
712
|
+
# expect(results).to match_array([1, 2])
|
477
713
|
#
|
478
|
-
#
|
479
|
-
|
480
|
-
|
481
|
-
# [1,2,3].should_not include(4)
|
482
|
-
# "spread".should include("read")
|
483
|
-
# "spread".should_not include("red")
|
484
|
-
def include(*expected)
|
485
|
-
BuiltIn::Include.new(*expected)
|
714
|
+
# @see #contain_exactly
|
715
|
+
def match_array(items)
|
716
|
+
contain_exactly(*items)
|
486
717
|
end
|
487
718
|
|
488
|
-
#
|
719
|
+
# With no arg, passes if the block outputs `to_stdout` or `to_stderr`.
|
720
|
+
# With a string, passes if the block outputs that specific string `to_stdout` or `to_stderr`.
|
721
|
+
# With a regexp or matcher, passes if the block outputs a string `to_stdout` or `to_stderr` that matches.
|
722
|
+
#
|
723
|
+
# To capture output from any spawned subprocess as well, use `to_stdout_from_any_process` or
|
724
|
+
# `to_stderr_from_any_process`. Output from any process that inherits the main process's corresponding
|
725
|
+
# standard stream will be captured.
|
489
726
|
#
|
490
727
|
# @example
|
728
|
+
# expect { print 'foo' }.to output.to_stdout
|
729
|
+
# expect { print 'foo' }.to output('foo').to_stdout
|
730
|
+
# expect { print 'foo' }.to output(/foo/).to_stdout
|
491
731
|
#
|
492
|
-
#
|
493
|
-
#
|
494
|
-
|
495
|
-
|
732
|
+
# expect { do_something }.to_not output.to_stdout
|
733
|
+
#
|
734
|
+
# expect { warn('foo') }.to output.to_stderr
|
735
|
+
# expect { warn('foo') }.to output('foo').to_stderr
|
736
|
+
# expect { warn('foo') }.to output(/foo/).to_stderr
|
737
|
+
#
|
738
|
+
# expect { do_something }.to_not output.to_stderr
|
739
|
+
#
|
740
|
+
# expect { system('echo foo') }.to output("foo\n").to_stdout_from_any_process
|
741
|
+
# expect { system('echo foo', out: :err) }.to output("foo\n").to_stderr_from_any_process
|
742
|
+
#
|
743
|
+
# @note `to_stdout` and `to_stderr` work by temporarily replacing `$stdout` or `$stderr`,
|
744
|
+
# so they're not able to intercept stream output that explicitly uses `STDOUT`/`STDERR`
|
745
|
+
# or that uses a reference to `$stdout`/`$stderr` that was stored before the
|
746
|
+
# matcher was used.
|
747
|
+
# @note `to_stdout_from_any_process` and `to_stderr_from_any_process` use Tempfiles, and
|
748
|
+
# are thus significantly (~30x) slower than `to_stdout` and `to_stderr`.
|
749
|
+
def output(expected=nil)
|
750
|
+
BuiltIn::Output.new(expected)
|
496
751
|
end
|
752
|
+
alias_matcher :a_block_outputting, :output
|
497
753
|
|
498
754
|
# With no args, matches if any error is raised.
|
499
755
|
# With a named error, matches only if that specific error is raised.
|
@@ -502,31 +758,39 @@ module RSpec
|
|
502
758
|
# Pass an optional block to perform extra verifications on the exception matched
|
503
759
|
#
|
504
760
|
# @example
|
505
|
-
#
|
506
|
-
#
|
507
|
-
#
|
508
|
-
#
|
509
|
-
#
|
510
|
-
#
|
511
|
-
#
|
512
|
-
#
|
513
|
-
#
|
514
|
-
|
515
|
-
# lambda { do_something_risky }.should_not raise_error(PoorRiskDecisionError, /oo ri/)
|
516
|
-
def raise_error(error=Exception, message=nil, &block)
|
761
|
+
# expect { do_something_risky }.to raise_error
|
762
|
+
# expect { do_something_risky }.to raise_error(PoorRiskDecisionError)
|
763
|
+
# expect { do_something_risky }.to raise_error(PoorRiskDecisionError) { |error| expect(error.data).to eq 42 }
|
764
|
+
# expect { do_something_risky }.to raise_error { |error| expect(error.data).to eq 42 }
|
765
|
+
# expect { do_something_risky }.to raise_error(PoorRiskDecisionError, "that was too risky")
|
766
|
+
# expect { do_something_risky }.to raise_error(PoorRiskDecisionError, /oo ri/)
|
767
|
+
# expect { do_something_risky }.to raise_error("that was too risky")
|
768
|
+
#
|
769
|
+
# expect { do_something_risky }.not_to raise_error
|
770
|
+
def raise_error(error=BuiltIn::RaiseError::UndefinedValue, message=nil, &block)
|
517
771
|
BuiltIn::RaiseError.new(error, message, &block)
|
518
772
|
end
|
519
|
-
|
520
773
|
alias_method :raise_exception, :raise_error
|
521
774
|
|
775
|
+
alias_matcher :a_block_raising, :raise_error do |desc|
|
776
|
+
desc.sub("raise", "a block raising")
|
777
|
+
end
|
778
|
+
|
779
|
+
alias_matcher :raising, :raise_error do |desc|
|
780
|
+
desc.sub("raise", "raising")
|
781
|
+
end
|
782
|
+
|
522
783
|
# Matches if the target object responds to all of the names
|
523
784
|
# provided. Names can be Strings or Symbols.
|
524
785
|
#
|
525
786
|
# @example
|
526
|
-
#
|
787
|
+
# expect("string").to respond_to(:length)
|
788
|
+
#
|
527
789
|
def respond_to(*names)
|
528
790
|
BuiltIn::RespondTo.new(*names)
|
529
791
|
end
|
792
|
+
alias_matcher :an_object_responding_to, :respond_to
|
793
|
+
alias_matcher :responding_to, :respond_to
|
530
794
|
|
531
795
|
# Passes if the submitted block returns true. Yields target to the
|
532
796
|
# block.
|
@@ -538,14 +802,16 @@ module RSpec
|
|
538
802
|
# If you do find yourself in such a situation, you could always write
|
539
803
|
# a custom matcher, which would likely make your specs more expressive.
|
540
804
|
#
|
541
|
-
# @
|
805
|
+
# @param description [String] optional description to be used for this matcher.
|
542
806
|
#
|
543
|
-
#
|
544
|
-
#
|
545
|
-
# }
|
546
|
-
def satisfy(&block)
|
547
|
-
BuiltIn::Satisfy.new(&block)
|
807
|
+
# @example
|
808
|
+
# expect(5).to satisfy { |n| n > 3 }
|
809
|
+
# expect(5).to satisfy("be greater than 3") { |n| n > 3 }
|
810
|
+
def satisfy(description=nil, &block)
|
811
|
+
BuiltIn::Satisfy.new(description, &block)
|
548
812
|
end
|
813
|
+
alias_matcher :an_object_satisfying, :satisfy
|
814
|
+
alias_matcher :satisfying, :satisfy
|
549
815
|
|
550
816
|
# Matches if the actual value starts with the expected value(s). In the
|
551
817
|
# case of a string, matches against the first `expected.length` characters
|
@@ -553,13 +819,15 @@ module RSpec
|
|
553
819
|
# `expected.length` elements of the actual array.
|
554
820
|
#
|
555
821
|
# @example
|
556
|
-
#
|
557
|
-
#
|
558
|
-
# [0,
|
559
|
-
# [0, 2, 3, 4, 4].should start_with 0, 1
|
822
|
+
# expect("this string").to start_with "this s"
|
823
|
+
# expect([0, 1, 2, 3, 4]).to start_with 0
|
824
|
+
# expect([0, 2, 3, 4, 4]).to start_with 0, 1
|
560
825
|
def start_with(*expected)
|
561
826
|
BuiltIn::StartWith.new(*expected)
|
562
827
|
end
|
828
|
+
alias_matcher :a_collection_starting_with, :start_with
|
829
|
+
alias_matcher :a_string_starting_with, :start_with
|
830
|
+
alias_matcher :starting_with, :start_with
|
563
831
|
|
564
832
|
# Given no argument, matches if a proc throws any Symbol.
|
565
833
|
#
|
@@ -569,39 +837,44 @@ module RSpec
|
|
569
837
|
# specified Symbol with the specified arg.
|
570
838
|
#
|
571
839
|
# @example
|
840
|
+
# expect { do_something_risky }.to throw_symbol
|
841
|
+
# expect { do_something_risky }.to throw_symbol(:that_was_risky)
|
842
|
+
# expect { do_something_risky }.to throw_symbol(:that_was_risky, 'culprit')
|
572
843
|
#
|
573
|
-
#
|
574
|
-
#
|
575
|
-
#
|
576
|
-
#
|
577
|
-
# lambda { do_something_risky }.should_not throw_symbol
|
578
|
-
# lambda { do_something_risky }.should_not throw_symbol(:that_was_risky)
|
579
|
-
# lambda { do_something_risky }.should_not throw_symbol(:that_was_risky, culprit)
|
844
|
+
# expect { do_something_risky }.not_to throw_symbol
|
845
|
+
# expect { do_something_risky }.not_to throw_symbol(:that_was_risky)
|
846
|
+
# expect { do_something_risky }.not_to throw_symbol(:that_was_risky, 'culprit')
|
580
847
|
def throw_symbol(expected_symbol=nil, expected_arg=nil)
|
581
848
|
BuiltIn::ThrowSymbol.new(expected_symbol, expected_arg)
|
582
849
|
end
|
583
850
|
|
851
|
+
alias_matcher :a_block_throwing, :throw_symbol do |desc|
|
852
|
+
desc.sub("throw", "a block throwing")
|
853
|
+
end
|
854
|
+
|
855
|
+
alias_matcher :throwing, :throw_symbol do |desc|
|
856
|
+
desc.sub("throw", "throwing")
|
857
|
+
end
|
858
|
+
|
584
859
|
# Passes if the method called in the expect block yields, regardless
|
585
860
|
# of whether or not arguments are yielded.
|
586
861
|
#
|
587
862
|
# @example
|
588
|
-
#
|
589
863
|
# expect { |b| 5.tap(&b) }.to yield_control
|
590
864
|
# expect { |b| "a".to_sym(&b) }.not_to yield_control
|
591
865
|
#
|
592
866
|
# @note Your expect block must accept a parameter and pass it on to
|
593
867
|
# the method-under-test as a block.
|
594
|
-
# @note This matcher is not designed for use with methods that yield
|
595
|
-
# multiple times.
|
596
868
|
def yield_control
|
597
869
|
BuiltIn::YieldControl.new
|
598
870
|
end
|
871
|
+
alias_matcher :a_block_yielding_control, :yield_control
|
872
|
+
alias_matcher :yielding_control, :yield_control
|
599
873
|
|
600
874
|
# Passes if the method called in the expect block yields with
|
601
875
|
# no arguments. Fails if it does not yield, or yields with arguments.
|
602
876
|
#
|
603
877
|
# @example
|
604
|
-
#
|
605
878
|
# expect { |b| User.transaction(&b) }.to yield_with_no_args
|
606
879
|
# expect { |b| 5.tap(&b) }.not_to yield_with_no_args # because it yields with `5`
|
607
880
|
# expect { |b| "a".to_sym(&b) }.not_to yield_with_no_args # because it does not yield
|
@@ -613,6 +886,8 @@ module RSpec
|
|
613
886
|
def yield_with_no_args
|
614
887
|
BuiltIn::YieldWithNoArgs.new
|
615
888
|
end
|
889
|
+
alias_matcher :a_block_yielding_with_no_args, :yield_with_no_args
|
890
|
+
alias_matcher :yielding_with_no_args, :yield_with_no_args
|
616
891
|
|
617
892
|
# Given no arguments, matches if the method called in the expect
|
618
893
|
# block yields with arguments (regardless of what they are or how
|
@@ -626,10 +901,9 @@ module RSpec
|
|
626
901
|
# operator, the matcher will pass.
|
627
902
|
#
|
628
903
|
# @example
|
629
|
-
#
|
630
904
|
# expect { |b| 5.tap(&b) }.to yield_with_args # because #tap yields an arg
|
631
905
|
# expect { |b| 5.tap(&b) }.to yield_with_args(5) # because 5 == 5
|
632
|
-
# expect { |b| 5.tap(&b) }.to yield_with_args(
|
906
|
+
# expect { |b| 5.tap(&b) }.to yield_with_args(Integer) # because Integer === 5
|
633
907
|
# expect { |b| File.open("f.txt", &b) }.to yield_with_args(/txt/) # because /txt/ === "f.txt"
|
634
908
|
#
|
635
909
|
# expect { |b| User.transaction(&b) }.not_to yield_with_args # because it yields no args
|
@@ -642,6 +916,8 @@ module RSpec
|
|
642
916
|
def yield_with_args(*args)
|
643
917
|
BuiltIn::YieldWithArgs.new(*args)
|
644
918
|
end
|
919
|
+
alias_matcher :a_block_yielding_with_args, :yield_with_args
|
920
|
+
alias_matcher :yielding_with_args, :yield_with_args
|
645
921
|
|
646
922
|
# Designed for use with methods that repeatedly yield (such as
|
647
923
|
# iterators). Passes if the method called in the expect block yields
|
@@ -652,7 +928,6 @@ module RSpec
|
|
652
928
|
# operator, the matcher will pass.
|
653
929
|
#
|
654
930
|
# @example
|
655
|
-
#
|
656
931
|
# expect { |b| [1, 2, 3].each(&b) }.to yield_successive_args(1, 2, 3)
|
657
932
|
# expect { |b| { :a => 1, :b => 2 }.each(&b) }.to yield_successive_args([:a, 1], [:b, 2])
|
658
933
|
# expect { |b| [1, 2, 3].each(&b) }.not_to yield_successive_args(1, 2)
|
@@ -662,28 +937,105 @@ module RSpec
|
|
662
937
|
def yield_successive_args(*args)
|
663
938
|
BuiltIn::YieldSuccessiveArgs.new(*args)
|
664
939
|
end
|
940
|
+
alias_matcher :a_block_yielding_successive_args, :yield_successive_args
|
941
|
+
alias_matcher :yielding_successive_args, :yield_successive_args
|
665
942
|
|
666
|
-
#
|
667
|
-
# This
|
668
|
-
#
|
669
|
-
#
|
670
|
-
# @
|
671
|
-
|
672
|
-
|
673
|
-
#
|
674
|
-
# @example
|
675
|
-
#
|
676
|
-
# expect([1,2,3]).to match_array([1,2,3])
|
677
|
-
# expect([1,2,3]).to match_array([1,3,2])
|
678
|
-
# [1,2,3].should =~ [1,2,3] # => would pass
|
679
|
-
# [1,2,3].should =~ [2,3,1] # => would pass
|
680
|
-
# [1,2,3,4].should =~ [1,2,3] # => would fail
|
681
|
-
# [1,2,2,3].should =~ [1,2,3] # => would fail
|
682
|
-
# [1,2,3].should =~ [1,2,3,4] # => would fail
|
683
|
-
def match_array(array)
|
684
|
-
BuiltIn::MatchArray.new(array)
|
943
|
+
# Delegates to {RSpec::Expectations.configuration}.
|
944
|
+
# This is here because rspec-core's `expect_with` option
|
945
|
+
# looks for a `configuration` method on the mixin
|
946
|
+
# (`RSpec::Matchers`) to yield to a block.
|
947
|
+
# @return [RSpec::Expectations::Configuration] the configuration object
|
948
|
+
def self.configuration
|
949
|
+
Expectations.configuration
|
685
950
|
end
|
686
951
|
|
687
|
-
|
952
|
+
private
|
953
|
+
|
954
|
+
BE_PREDICATE_REGEX = /^(?:be_(?:an?_)?)(.*)/
|
955
|
+
HAS_REGEX = /^(?:have_)(.*)/
|
956
|
+
DYNAMIC_MATCHER_REGEX = Regexp.union(BE_PREDICATE_REGEX, HAS_REGEX)
|
957
|
+
|
958
|
+
def method_missing(method, *args, &block)
|
959
|
+
case method.to_s
|
960
|
+
when BE_PREDICATE_REGEX
|
961
|
+
BuiltIn::BePredicate.new(method, *args, &block)
|
962
|
+
when HAS_REGEX
|
963
|
+
BuiltIn::Has.new(method, *args, &block)
|
964
|
+
else
|
965
|
+
super
|
966
|
+
end
|
967
|
+
end
|
968
|
+
ruby2_keywords :method_missing if respond_to?(:ruby2_keywords, true)
|
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
|
+
|
984
|
+
# @api private
|
985
|
+
def self.is_a_matcher?(obj)
|
986
|
+
return true if ::RSpec::Matchers::BuiltIn::BaseMatcher === obj
|
987
|
+
begin
|
988
|
+
return false if obj.respond_to?(:i_respond_to_everything_so_im_not_really_a_matcher)
|
989
|
+
rescue NoMethodError
|
990
|
+
# Some objects, like BasicObject, don't implemented standard
|
991
|
+
# reflection methods.
|
992
|
+
return false
|
993
|
+
end
|
994
|
+
return false unless obj.respond_to?(:matches?)
|
995
|
+
|
996
|
+
obj.respond_to?(:failure_message) ||
|
997
|
+
obj.respond_to?(:failure_message_for_should) # support legacy matchers
|
998
|
+
end
|
999
|
+
|
1000
|
+
::RSpec::Support.register_matcher_definition do |obj|
|
1001
|
+
is_a_matcher?(obj)
|
1002
|
+
end
|
1003
|
+
|
1004
|
+
# @api private
|
1005
|
+
def self.is_a_describable_matcher?(obj)
|
1006
|
+
is_a_matcher?(obj) && obj.respond_to?(:description)
|
1007
|
+
end
|
1008
|
+
|
1009
|
+
class << self
|
1010
|
+
private
|
1011
|
+
|
1012
|
+
if RSpec::Support::Ruby.mri? && RUBY_VERSION[0, 3] == '1.9'
|
1013
|
+
# Note that `included` doesn't work for this because it is triggered
|
1014
|
+
# _after_ `RSpec::Matchers` is an ancestor of the inclusion host, rather
|
1015
|
+
# than _before_, like `append_features`. It's important we check this before
|
1016
|
+
# in order to find the cases where it was already previously included.
|
1017
|
+
# @api private
|
1018
|
+
def append_features(mod)
|
1019
|
+
return super if mod < self # `mod < self` indicates a re-inclusion.
|
1020
|
+
|
1021
|
+
subclasses = ObjectSpace.each_object(Class).select { |c| c < mod && c < self }
|
1022
|
+
return super unless subclasses.any?
|
1023
|
+
|
1024
|
+
subclasses.reject! { |s| subclasses.any? { |s2| s < s2 } } # Filter to the root ancestor.
|
1025
|
+
subclasses = subclasses.map { |s| "`#{s}`" }.join(", ")
|
1026
|
+
|
1027
|
+
RSpec.warning "`#{self}` has been included in a superclass (`#{mod}`) " \
|
1028
|
+
"after previously being included in subclasses (#{subclasses}), " \
|
1029
|
+
"which can trigger infinite recursion from `super` due to an MRI 1.9 bug " \
|
1030
|
+
"(https://redmine.ruby-lang.org/issues/3351). To work around this, " \
|
1031
|
+
"either upgrade to MRI 2.0+, include a dup of the module (e.g. " \
|
1032
|
+
"`include #{self}.dup`), or find a way to include `#{self}` in `#{mod}` " \
|
1033
|
+
"before it is included in subclasses (#{subclasses}). See " \
|
1034
|
+
"https://github.com/rspec/rspec-expectations/issues/814 for more info"
|
1035
|
+
|
1036
|
+
super
|
1037
|
+
end
|
1038
|
+
end
|
1039
|
+
end
|
688
1040
|
end
|
689
1041
|
end
|