rspec-expectations 2.13.0 → 3.0.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 +15 -0
- checksums.yaml.gz.sig +0 -0
- data/Changelog.md +413 -23
- data/License.txt +1 -0
- data/README.md +109 -80
- data/lib/rspec/{matchers → expectations}/configuration.rb +44 -14
- data/lib/rspec/expectations/expectation_target.rb +71 -38
- data/lib/rspec/expectations/fail_with.rb +12 -44
- data/lib/rspec/expectations/handler.rb +135 -35
- data/lib/rspec/expectations/minitest_integration.rb +16 -0
- data/lib/rspec/expectations/syntax.rb +60 -94
- data/lib/rspec/expectations/version.rb +1 -1
- data/lib/rspec/expectations.rb +46 -24
- data/lib/rspec/matchers/aliased_matcher.rb +41 -0
- data/lib/rspec/matchers/built_in/all.rb +78 -0
- data/lib/rspec/matchers/built_in/base_matcher.rb +63 -15
- data/lib/rspec/matchers/built_in/be.rb +170 -79
- data/lib/rspec/matchers/built_in/be_between.rb +77 -0
- data/lib/rspec/matchers/built_in/be_instance_of.rb +11 -3
- data/lib/rspec/matchers/built_in/be_kind_of.rb +5 -0
- data/lib/rspec/matchers/built_in/be_within.rb +40 -16
- data/lib/rspec/matchers/built_in/change.rb +275 -74
- data/lib/rspec/matchers/built_in/compound.rb +122 -0
- data/lib/rspec/matchers/built_in/contain_exactly.rb +256 -0
- data/lib/rspec/matchers/built_in/cover.rb +3 -0
- data/lib/rspec/matchers/built_in/eq.rb +60 -6
- data/lib/rspec/matchers/built_in/eql.rb +17 -5
- data/lib/rspec/matchers/built_in/equal.rb +55 -21
- data/lib/rspec/matchers/built_in/exist.rb +74 -10
- data/lib/rspec/matchers/built_in/has.rb +71 -15
- data/lib/rspec/matchers/built_in/include.rb +58 -29
- data/lib/rspec/matchers/built_in/match.rb +19 -1
- data/lib/rspec/matchers/built_in/operators.rb +119 -0
- data/lib/rspec/matchers/built_in/output.rb +150 -0
- data/lib/rspec/matchers/built_in/raise_error.rb +91 -33
- data/lib/rspec/matchers/built_in/respond_to.rb +42 -20
- data/lib/rspec/matchers/built_in/satisfy.rb +19 -3
- data/lib/rspec/matchers/built_in/start_and_end_with.rb +54 -18
- data/lib/rspec/matchers/built_in/throw_symbol.rb +38 -8
- data/lib/rspec/matchers/built_in/yield.rb +237 -55
- data/lib/rspec/matchers/built_in.rb +45 -33
- data/lib/rspec/matchers/composable.rb +179 -0
- data/lib/rspec/matchers/dsl.rb +362 -5
- data/lib/rspec/matchers/generated_descriptions.rb +13 -6
- data/lib/rspec/matchers/matcher_delegator.rb +37 -0
- data/lib/rspec/matchers/pretty.rb +33 -20
- data/lib/rspec/matchers.rb +450 -227
- data.tar.gz.sig +1 -0
- metadata +100 -215
- 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 -175
- data/features/built_in_matchers/be_within.feature +0 -48
- data/features/built_in_matchers/cover.feature +0 -47
- data/features/built_in_matchers/end_with.feature +0 -48
- data/features/built_in_matchers/equality.feature +0 -139
- data/features/built_in_matchers/exist.feature +0 -45
- data/features/built_in_matchers/expect_change.feature +0 -59
- data/features/built_in_matchers/expect_error.feature +0 -144
- data/features/built_in_matchers/have.feature +0 -109
- data/features/built_in_matchers/include.feature +0 -174
- data/features/built_in_matchers/match.feature +0 -52
- data/features/built_in_matchers/operators.feature +0 -227
- data/features/built_in_matchers/predicates.feature +0 -137
- data/features/built_in_matchers/respond_to.feature +0 -84
- data/features/built_in_matchers/satisfy.feature +0 -33
- data/features/built_in_matchers/start_with.feature +0 -48
- data/features/built_in_matchers/throw_symbol.feature +0 -91
- data/features/built_in_matchers/types.feature +0 -116
- data/features/built_in_matchers/yield.feature +0 -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 -368
- data/features/custom_matchers/define_matcher_outside_rspec.feature +0 -38
- data/features/custom_matchers/define_matcher_with_fluent_interface.feature +0 -24
- data/features/customized_message.feature +0 -22
- data/features/diffing.feature +0 -85
- data/features/implicit_docstrings.feature +0 -52
- data/features/step_definitions/additional_cli_steps.rb +0 -22
- data/features/support/env.rb +0 -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 -115
- 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 -51
- data/lib/rspec/matchers/compatibility.rb +0 -14
- data/lib/rspec/matchers/extensions/instance_eval_with_args.rb +0 -39
- data/lib/rspec/matchers/matcher.rb +0 -300
- data/lib/rspec/matchers/method_missing.rb +0 -12
- data/lib/rspec/matchers/operator_matcher.rb +0 -109
- data/lib/rspec-expectations.rb +0 -1
- data/spec/rspec/expectations/differ_spec.rb +0 -170
- data/spec/rspec/expectations/expectation_target_spec.rb +0 -75
- data/spec/rspec/expectations/extensions/kernel_spec.rb +0 -67
- data/spec/rspec/expectations/fail_with_spec.rb +0 -95
- data/spec/rspec/expectations/handler_spec.rb +0 -206
- data/spec/rspec/expectations/syntax_spec.rb +0 -97
- data/spec/rspec/matchers/base_matcher_spec.rb +0 -62
- data/spec/rspec/matchers/be_close_spec.rb +0 -22
- data/spec/rspec/matchers/be_instance_of_spec.rb +0 -63
- data/spec/rspec/matchers/be_kind_of_spec.rb +0 -41
- data/spec/rspec/matchers/be_spec.rb +0 -516
- data/spec/rspec/matchers/be_within_spec.rb +0 -129
- data/spec/rspec/matchers/change_spec.rb +0 -542
- data/spec/rspec/matchers/configuration_spec.rb +0 -238
- 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 -60
- data/spec/rspec/matchers/eql_spec.rb +0 -41
- data/spec/rspec/matchers/equal_spec.rb +0 -78
- data/spec/rspec/matchers/exist_spec.rb +0 -124
- data/spec/rspec/matchers/has_spec.rb +0 -122
- data/spec/rspec/matchers/have_spec.rb +0 -445
- data/spec/rspec/matchers/include_matcher_integration_spec.rb +0 -30
- data/spec/rspec/matchers/include_spec.rb +0 -531
- data/spec/rspec/matchers/match_array_spec.rb +0 -194
- data/spec/rspec/matchers/match_spec.rb +0 -61
- data/spec/rspec/matchers/matcher_spec.rb +0 -471
- data/spec/rspec/matchers/matchers_spec.rb +0 -37
- data/spec/rspec/matchers/method_missing_spec.rb +0 -28
- data/spec/rspec/matchers/operator_matcher_spec.rb +0 -223
- data/spec/rspec/matchers/raise_error_spec.rb +0 -395
- data/spec/rspec/matchers/respond_to_spec.rb +0 -292
- data/spec/rspec/matchers/satisfy_spec.rb +0 -44
- data/spec/rspec/matchers/start_with_end_with_spec.rb +0 -186
- data/spec/rspec/matchers/throw_symbol_spec.rb +0 -116
- data/spec/rspec/matchers/yield_spec.rb +0 -437
- data/spec/spec_helper.rb +0 -54
- data/spec/support/classes.rb +0 -56
- data/spec/support/in_sub_process.rb +0 -38
- data/spec/support/matchers.rb +0 -22
- data/spec/support/ruby_version.rb +0 -10
- data/spec/support/shared_examples.rb +0 -13
|
@@ -1,131 +1,332 @@
|
|
|
1
1
|
module RSpec
|
|
2
2
|
module Matchers
|
|
3
3
|
module BuiltIn
|
|
4
|
+
# @api private
|
|
5
|
+
# Provides the implementation for `change`.
|
|
6
|
+
# Not intended to be instantiated directly.
|
|
4
7
|
class Change
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
include Composable
|
|
9
|
+
|
|
10
|
+
# @api public
|
|
11
|
+
# Specifies the delta of the expected change.
|
|
12
|
+
def by(expected_delta)
|
|
13
|
+
ChangeRelatively.new(@change_details, expected_delta, :by) do |actual_delta|
|
|
14
|
+
values_match?(expected_delta, actual_delta)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# @api public
|
|
19
|
+
# Specifies a minimum delta of the expected change.
|
|
20
|
+
def by_at_least(minimum)
|
|
21
|
+
ChangeRelatively.new(@change_details, minimum, :by_at_least) do |actual_delta|
|
|
22
|
+
actual_delta >= minimum
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# @api public
|
|
27
|
+
# Specifies a maximum delta of the expected change.
|
|
28
|
+
def by_at_most(maximum)
|
|
29
|
+
ChangeRelatively.new(@change_details, maximum, :by_at_most) do |actual_delta|
|
|
30
|
+
actual_delta <= maximum
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# @api public
|
|
35
|
+
# Specifies the new value you expect.
|
|
36
|
+
def to(value)
|
|
37
|
+
ChangeToValue.new(@change_details, value)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# @api public
|
|
41
|
+
# Specifies the original value.
|
|
42
|
+
def from(value)
|
|
43
|
+
ChangeFromValue.new(@change_details, value)
|
|
10
44
|
end
|
|
11
45
|
|
|
46
|
+
# @private
|
|
12
47
|
def matches?(event_proc)
|
|
48
|
+
@event_proc = event_proc
|
|
49
|
+
return false unless Proc === event_proc
|
|
13
50
|
raise_block_syntax_error if block_given?
|
|
51
|
+
@change_details.perform_change(event_proc)
|
|
52
|
+
@change_details.changed?
|
|
53
|
+
end
|
|
14
54
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
55
|
+
def does_not_match?(event_proc)
|
|
56
|
+
raise_block_syntax_error if block_given?
|
|
57
|
+
!matches?(event_proc) && Proc === event_proc
|
|
58
|
+
end
|
|
18
59
|
|
|
19
|
-
|
|
60
|
+
# @api private
|
|
61
|
+
# @return [String]
|
|
62
|
+
def failure_message
|
|
63
|
+
"expected #{@change_details.message} to have changed, but #{positive_failure_reason}"
|
|
20
64
|
end
|
|
21
|
-
alias == matches?
|
|
22
65
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
66
|
+
# @api private
|
|
67
|
+
# @return [String]
|
|
68
|
+
def failure_message_when_negated
|
|
69
|
+
"expected #{@change_details.message} not to have changed, but #{negative_failure_reason}"
|
|
27
70
|
end
|
|
28
71
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
else
|
|
34
|
-
val
|
|
35
|
-
end
|
|
72
|
+
# @api private
|
|
73
|
+
# @return [String]
|
|
74
|
+
def description
|
|
75
|
+
"change #{@change_details.message}"
|
|
36
76
|
end
|
|
37
77
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
elsif @eval_after && !expected_matches_actual?(@expected_after, @actual_after)
|
|
42
|
-
"#{message} should have been changed to #{@expected_after.inspect}, but is now #{@actual_after.inspect}"
|
|
43
|
-
elsif @expected_delta
|
|
44
|
-
"#{message} should have been changed by #{@expected_delta.inspect}, but was changed by #{actual_delta.inspect}"
|
|
45
|
-
elsif @minimum
|
|
46
|
-
"#{message} should have been changed by at least #{@minimum.inspect}, but was changed by #{actual_delta.inspect}"
|
|
47
|
-
elsif @maximum
|
|
48
|
-
"#{message} should have been changed by at most #{@maximum.inspect}, but was changed by #{actual_delta.inspect}"
|
|
49
|
-
else
|
|
50
|
-
"#{message} should have changed, but is still #{@actual_before.inspect}"
|
|
51
|
-
end
|
|
78
|
+
# @private
|
|
79
|
+
def supports_block_expectations?
|
|
80
|
+
true
|
|
52
81
|
end
|
|
53
82
|
|
|
54
|
-
|
|
55
|
-
|
|
83
|
+
private
|
|
84
|
+
|
|
85
|
+
def initialize(receiver=nil, message=nil, &block)
|
|
86
|
+
@change_details = ChangeDetails.new(receiver, message, &block)
|
|
56
87
|
end
|
|
57
88
|
|
|
58
|
-
def
|
|
59
|
-
|
|
89
|
+
def raise_block_syntax_error
|
|
90
|
+
raise SyntaxError,
|
|
91
|
+
"The block passed to the `change` matcher must use `{ ... }` instead of do/end"
|
|
60
92
|
end
|
|
61
93
|
|
|
62
|
-
def
|
|
63
|
-
|
|
64
|
-
|
|
94
|
+
def positive_failure_reason
|
|
95
|
+
return "was not given a block" unless Proc === @event_proc
|
|
96
|
+
"is still #{description_of @change_details.actual_before}"
|
|
65
97
|
end
|
|
66
98
|
|
|
67
|
-
def
|
|
68
|
-
|
|
69
|
-
|
|
99
|
+
def negative_failure_reason
|
|
100
|
+
return "was not given a block" unless Proc === @event_proc
|
|
101
|
+
"did change from #{description_of @change_details.actual_before} to #{description_of @change_details.actual_after}"
|
|
70
102
|
end
|
|
103
|
+
end
|
|
71
104
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
105
|
+
# Used to specify a relative change.
|
|
106
|
+
# @api private
|
|
107
|
+
class ChangeRelatively
|
|
108
|
+
include Composable
|
|
109
|
+
|
|
110
|
+
def initialize(change_details, expected_delta, relativity, &comparer)
|
|
111
|
+
@change_details = change_details
|
|
112
|
+
@expected_delta = expected_delta
|
|
113
|
+
@relativity = relativity
|
|
114
|
+
@comparer = comparer
|
|
75
115
|
end
|
|
76
116
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
@
|
|
80
|
-
self
|
|
117
|
+
# @private
|
|
118
|
+
def failure_message
|
|
119
|
+
"expected #{@change_details.message} to have changed #{@relativity.to_s.gsub("_", " ")} #{description_of @expected_delta}, but #{failure_reason}"
|
|
81
120
|
end
|
|
82
121
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
@
|
|
86
|
-
|
|
122
|
+
# @private
|
|
123
|
+
def matches?(event_proc)
|
|
124
|
+
@event_proc = event_proc
|
|
125
|
+
return false unless Proc === event_proc
|
|
126
|
+
@change_details.perform_change(event_proc)
|
|
127
|
+
@comparer.call(@change_details.actual_delta)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# @private
|
|
131
|
+
def does_not_match?(event_proc)
|
|
132
|
+
raise NotImplementedError, "`expect { }.not_to change { }.#{@relativity}()` is not supported"
|
|
87
133
|
end
|
|
88
134
|
|
|
135
|
+
# @private
|
|
89
136
|
def description
|
|
90
|
-
"change
|
|
137
|
+
"change #{@change_details.message} #{@relativity.to_s.gsub("_", " ")} #{description_of @expected_delta}"
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# @private
|
|
141
|
+
def supports_block_expectations?
|
|
142
|
+
true
|
|
91
143
|
end
|
|
92
144
|
|
|
93
|
-
|
|
145
|
+
private
|
|
94
146
|
|
|
95
|
-
def
|
|
96
|
-
|
|
147
|
+
def failure_reason
|
|
148
|
+
return "was not given a block" unless Proc === @event_proc
|
|
149
|
+
"was changed by #{description_of @change_details.actual_delta}"
|
|
97
150
|
end
|
|
151
|
+
end
|
|
98
152
|
|
|
99
|
-
|
|
100
|
-
|
|
153
|
+
# @api private
|
|
154
|
+
# Base class for specifying a change from and/or to specific values.
|
|
155
|
+
class SpecificValuesChange
|
|
156
|
+
include Composable
|
|
157
|
+
# @private
|
|
158
|
+
MATCH_ANYTHING = ::Object.ancestors.last
|
|
159
|
+
|
|
160
|
+
def initialize(change_details, from, to)
|
|
161
|
+
@change_details = change_details
|
|
162
|
+
@expected_before = from
|
|
163
|
+
@expected_after = to
|
|
101
164
|
end
|
|
102
165
|
|
|
103
|
-
|
|
104
|
-
|
|
166
|
+
# @private
|
|
167
|
+
def matches?(event_proc)
|
|
168
|
+
@event_proc = event_proc
|
|
169
|
+
return false unless Proc === event_proc
|
|
170
|
+
@change_details.perform_change(event_proc)
|
|
171
|
+
@change_details.changed? && matches_before? && matches_after?
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# @private
|
|
175
|
+
def description
|
|
176
|
+
"change #{@change_details.message} #{change_description}"
|
|
105
177
|
end
|
|
106
178
|
|
|
179
|
+
# @private
|
|
180
|
+
def failure_message
|
|
181
|
+
return not_given_a_block_failure unless Proc === @event_proc
|
|
182
|
+
return before_value_failure unless matches_before?
|
|
183
|
+
return did_not_change_failure unless @change_details.changed?
|
|
184
|
+
after_value_failure
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# @private
|
|
188
|
+
def supports_block_expectations?
|
|
189
|
+
true
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
private
|
|
193
|
+
|
|
107
194
|
def matches_before?
|
|
108
|
-
|
|
195
|
+
values_match?(@expected_before, @change_details.actual_before)
|
|
109
196
|
end
|
|
110
197
|
|
|
111
198
|
def matches_after?
|
|
112
|
-
|
|
199
|
+
values_match?(@expected_after, @change_details.actual_after)
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def before_value_failure
|
|
203
|
+
"expected #{@change_details.message} to have initially been #{description_of @expected_before}, but was #{description_of @change_details.actual_before}"
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def after_value_failure
|
|
207
|
+
"expected #{@change_details.message} to have changed to #{description_of @expected_after}, but is now #{description_of @change_details.actual_after}"
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def did_not_change_failure
|
|
211
|
+
"expected #{@change_details.message} to have changed #{change_description}, but did not change"
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def did_change_failure
|
|
215
|
+
"expected #{@change_details.message} not to have changed, but did change from #{description_of @change_details.actual_before} to #{description_of @change_details.actual_after}"
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def not_given_a_block_failure
|
|
219
|
+
"expected #{@change_details.message} to have changed #{change_description}, but was not given a block"
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
# @api private
|
|
224
|
+
# Used to specify a change from a specific value
|
|
225
|
+
# (and, optionally, to a specific value).
|
|
226
|
+
class ChangeFromValue < SpecificValuesChange
|
|
227
|
+
def initialize(change_details, expected_before)
|
|
228
|
+
@description_suffix = nil
|
|
229
|
+
super(change_details, expected_before, MATCH_ANYTHING)
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
# @api public
|
|
233
|
+
# Specifies the new value you expect.
|
|
234
|
+
def to(value)
|
|
235
|
+
@expected_after = value
|
|
236
|
+
@description_suffix = " to #{description_of value}"
|
|
237
|
+
self
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# @private
|
|
241
|
+
def does_not_match?(event_proc)
|
|
242
|
+
if @description_suffix
|
|
243
|
+
raise NotImplementedError, "`expect { }.not_to change { }.to()` is not supported"
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
@event_proc = event_proc
|
|
247
|
+
return false unless Proc === event_proc
|
|
248
|
+
@change_details.perform_change(event_proc)
|
|
249
|
+
!@change_details.changed? && matches_before?
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
# @private
|
|
253
|
+
def failure_message_when_negated
|
|
254
|
+
return not_given_a_block_failure unless Proc === @event_proc
|
|
255
|
+
return before_value_failure unless matches_before?
|
|
256
|
+
did_change_failure
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
private
|
|
260
|
+
|
|
261
|
+
def change_description
|
|
262
|
+
"from #{description_of @expected_before}#{@description_suffix}"
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
# @api private
|
|
267
|
+
# Used to specify a change to a specific value
|
|
268
|
+
# (and, optionally, from a specific value).
|
|
269
|
+
class ChangeToValue < SpecificValuesChange
|
|
270
|
+
def initialize(change_details, expected_after)
|
|
271
|
+
@description_suffix = nil
|
|
272
|
+
super(change_details, MATCH_ANYTHING, expected_after)
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
# @api public
|
|
276
|
+
# Specifies the original value.
|
|
277
|
+
def from(value)
|
|
278
|
+
@expected_before = value
|
|
279
|
+
@description_suffix = " from #{description_of value}"
|
|
280
|
+
self
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
# @private
|
|
284
|
+
def does_not_match?(event_proc)
|
|
285
|
+
raise NotImplementedError, "`expect { }.not_to change { }.to()` is not supported"
|
|
113
286
|
end
|
|
114
287
|
|
|
115
|
-
|
|
116
|
-
|
|
288
|
+
private
|
|
289
|
+
|
|
290
|
+
def change_description
|
|
291
|
+
"to #{description_of @expected_after}#{@description_suffix}"
|
|
117
292
|
end
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
# @private
|
|
296
|
+
# Encapsulates the details of the before/after values.
|
|
297
|
+
class ChangeDetails
|
|
298
|
+
attr_reader :message, :actual_before, :actual_after
|
|
118
299
|
|
|
119
|
-
def
|
|
120
|
-
@
|
|
300
|
+
def initialize(receiver=nil, message=nil, &block)
|
|
301
|
+
@message = message ? "##{message}" : "result"
|
|
302
|
+
@value_proc = block || lambda { receiver.__send__(message) }
|
|
121
303
|
end
|
|
122
304
|
|
|
123
|
-
def
|
|
124
|
-
@
|
|
305
|
+
def perform_change(event_proc)
|
|
306
|
+
@actual_before = evaluate_value_proc
|
|
307
|
+
event_proc.call
|
|
308
|
+
@actual_after = evaluate_value_proc
|
|
125
309
|
end
|
|
126
310
|
|
|
127
|
-
def
|
|
128
|
-
|
|
311
|
+
def changed?
|
|
312
|
+
@actual_before != @actual_after
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
def actual_delta
|
|
316
|
+
@actual_after - @actual_before
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
private
|
|
320
|
+
|
|
321
|
+
def evaluate_value_proc
|
|
322
|
+
case val = @value_proc.call
|
|
323
|
+
when IO # enumerable, but we don't want to dup it.
|
|
324
|
+
val
|
|
325
|
+
when Enumerable, String
|
|
326
|
+
val.dup
|
|
327
|
+
else
|
|
328
|
+
val
|
|
329
|
+
end
|
|
129
330
|
end
|
|
130
331
|
end
|
|
131
332
|
end
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
module RSpec
|
|
2
|
+
module Matchers
|
|
3
|
+
module BuiltIn
|
|
4
|
+
# @api private
|
|
5
|
+
# Base class for `and` and `or` compound matchers.
|
|
6
|
+
class Compound < BaseMatcher
|
|
7
|
+
# @private
|
|
8
|
+
attr_reader :matcher_1, :matcher_2
|
|
9
|
+
|
|
10
|
+
def initialize(matcher_1, matcher_2)
|
|
11
|
+
@matcher_1 = matcher_1
|
|
12
|
+
@matcher_2 = matcher_2
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# @private
|
|
16
|
+
def does_not_match?(actual)
|
|
17
|
+
raise NotImplementedError,
|
|
18
|
+
"`expect(...).not_to matcher.#{conjunction} matcher` is not supported"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @api private
|
|
22
|
+
# @return [String]
|
|
23
|
+
def description
|
|
24
|
+
singleline_message(matcher_1.description, matcher_2.description)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def initialize_copy(other)
|
|
30
|
+
@matcher_1 = @matcher_1.clone
|
|
31
|
+
@matcher_2 = @matcher_2.clone
|
|
32
|
+
super
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def indent_multiline_message(message)
|
|
36
|
+
message.lines.map do |line|
|
|
37
|
+
line =~ /\S/ ? ' ' + line : line
|
|
38
|
+
end.join
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def compound_failure_message
|
|
42
|
+
message_1 = matcher_1.failure_message
|
|
43
|
+
message_2 = matcher_2.failure_message
|
|
44
|
+
|
|
45
|
+
if multiline?(message_1) || multiline?(message_2)
|
|
46
|
+
multiline_message(message_1, message_2)
|
|
47
|
+
else
|
|
48
|
+
singleline_message(message_1, message_2)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def multiline_message(message_1, message_2)
|
|
53
|
+
[
|
|
54
|
+
indent_multiline_message(message_1.sub(/\n+\z/, '')),
|
|
55
|
+
"...#{conjunction}:",
|
|
56
|
+
indent_multiline_message(message_2.sub(/\A\n+/, ''))
|
|
57
|
+
].join("\n\n")
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def multiline?(message)
|
|
61
|
+
message.lines.count > 1
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def singleline_message(message_1, message_2)
|
|
65
|
+
[message_1, conjunction, message_2].join(' ')
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# @api public
|
|
69
|
+
# Matcher used to represent a compound `and` expectation.
|
|
70
|
+
class And < self
|
|
71
|
+
|
|
72
|
+
# @api private
|
|
73
|
+
# @return [String]
|
|
74
|
+
def failure_message
|
|
75
|
+
if @matcher_1_matches
|
|
76
|
+
matcher_2.failure_message
|
|
77
|
+
elsif @matcher_2_matches
|
|
78
|
+
matcher_1.failure_message
|
|
79
|
+
else
|
|
80
|
+
compound_failure_message
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
private
|
|
85
|
+
|
|
86
|
+
def match(expected, actual)
|
|
87
|
+
@matcher_1_matches = matcher_1.matches?(actual)
|
|
88
|
+
@matcher_2_matches = matcher_2.matches?(actual)
|
|
89
|
+
|
|
90
|
+
@matcher_1_matches && @matcher_2_matches
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def conjunction
|
|
94
|
+
"and"
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# @api public
|
|
99
|
+
# Matcher used to represent a compound `or` expectation.
|
|
100
|
+
class Or < self
|
|
101
|
+
|
|
102
|
+
# @api private
|
|
103
|
+
# @return [String]
|
|
104
|
+
def failure_message
|
|
105
|
+
compound_failure_message
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
private
|
|
109
|
+
|
|
110
|
+
def match(expected, actual)
|
|
111
|
+
matcher_1.matches?(actual) || matcher_2.matches?(actual)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def conjunction
|
|
115
|
+
"or"
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|