rspec-expectations 2.14.0 → 3.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data/.document +1 -1
- data/.yardopts +1 -1
- data/Changelog.md +976 -25
- data/{License.txt → LICENSE.md} +5 -3
- data/README.md +162 -26
- data/lib/rspec/expectations/block_snippet_extractor.rb +253 -0
- data/lib/rspec/expectations/configuration.rb +230 -0
- data/lib/rspec/expectations/expectation_target.rb +127 -51
- data/lib/rspec/expectations/fail_with.rb +17 -57
- data/lib/rspec/expectations/failure_aggregator.rb +229 -0
- data/lib/rspec/expectations/handler.rb +146 -32
- data/lib/rspec/expectations/minitest_integration.rb +58 -0
- data/lib/rspec/expectations/syntax.rb +68 -100
- data/lib/rspec/expectations/version.rb +1 -1
- data/lib/rspec/expectations.rb +58 -23
- data/lib/rspec/matchers/aliased_matcher.rb +116 -0
- data/lib/rspec/matchers/built_in/all.rb +86 -0
- data/lib/rspec/matchers/built_in/base_matcher.rb +191 -20
- data/lib/rspec/matchers/built_in/be.rb +114 -114
- data/lib/rspec/matchers/built_in/be_between.rb +77 -0
- data/lib/rspec/matchers/built_in/be_instance_of.rb +15 -4
- data/lib/rspec/matchers/built_in/be_kind_of.rb +10 -1
- data/lib/rspec/matchers/built_in/be_within.rb +35 -18
- data/lib/rspec/matchers/built_in/change.rb +389 -80
- data/lib/rspec/matchers/built_in/compound.rb +290 -0
- data/lib/rspec/matchers/built_in/contain_exactly.rb +310 -0
- data/lib/rspec/matchers/built_in/count_expectation.rb +169 -0
- data/lib/rspec/matchers/built_in/cover.rb +3 -0
- data/lib/rspec/matchers/built_in/eq.rb +30 -8
- data/lib/rspec/matchers/built_in/eql.rb +23 -8
- data/lib/rspec/matchers/built_in/equal.rb +55 -22
- data/lib/rspec/matchers/built_in/exist.rb +74 -10
- data/lib/rspec/matchers/built_in/has.rb +141 -22
- data/lib/rspec/matchers/built_in/have_attributes.rb +114 -0
- data/lib/rspec/matchers/built_in/include.rb +184 -32
- data/lib/rspec/matchers/built_in/match.rb +95 -1
- data/lib/rspec/matchers/built_in/operators.rb +128 -0
- data/lib/rspec/matchers/built_in/output.rb +207 -0
- data/lib/rspec/matchers/built_in/raise_error.rb +192 -44
- data/lib/rspec/matchers/built_in/respond_to.rb +154 -28
- data/lib/rspec/matchers/built_in/satisfy.rb +39 -9
- data/lib/rspec/matchers/built_in/start_or_end_with.rb +94 -0
- data/lib/rspec/matchers/built_in/throw_symbol.rb +58 -14
- data/lib/rspec/matchers/built_in/yield.rb +240 -161
- data/lib/rspec/matchers/built_in.rb +47 -33
- data/lib/rspec/matchers/composable.rb +171 -0
- data/lib/rspec/matchers/dsl.rb +531 -10
- data/lib/rspec/matchers/english_phrasing.rb +58 -0
- data/lib/rspec/matchers/fail_matchers.rb +42 -0
- data/lib/rspec/matchers/generated_descriptions.rb +14 -8
- data/lib/rspec/matchers/matcher_delegator.rb +61 -0
- data/lib/rspec/matchers/matcher_protocol.rb +105 -0
- data/lib/rspec/matchers/multi_matcher_diff.rb +82 -0
- data/lib/rspec/matchers.rb +520 -173
- data.tar.gz.sig +0 -0
- metadata +141 -242
- metadata.gz.sig +2 -0
- data/features/README.md +0 -48
- data/features/Upgrade.md +0 -53
- data/features/built_in_matchers/README.md +0 -90
- data/features/built_in_matchers/be.feature +0 -175
- data/features/built_in_matchers/be_within.feature +0 -48
- data/features/built_in_matchers/cover.feature +0 -47
- data/features/built_in_matchers/end_with.feature +0 -48
- data/features/built_in_matchers/equality.feature +0 -139
- data/features/built_in_matchers/exist.feature +0 -45
- data/features/built_in_matchers/expect_change.feature +0 -59
- data/features/built_in_matchers/expect_error.feature +0 -144
- data/features/built_in_matchers/have.feature +0 -109
- data/features/built_in_matchers/include.feature +0 -174
- data/features/built_in_matchers/match.feature +0 -52
- data/features/built_in_matchers/operators.feature +0 -227
- data/features/built_in_matchers/predicates.feature +0 -137
- data/features/built_in_matchers/respond_to.feature +0 -84
- data/features/built_in_matchers/satisfy.feature +0 -33
- data/features/built_in_matchers/start_with.feature +0 -48
- data/features/built_in_matchers/throw_symbol.feature +0 -91
- data/features/built_in_matchers/types.feature +0 -116
- data/features/built_in_matchers/yield.feature +0 -161
- data/features/custom_matchers/access_running_example.feature +0 -53
- data/features/custom_matchers/define_diffable_matcher.feature +0 -27
- data/features/custom_matchers/define_matcher.feature +0 -368
- data/features/custom_matchers/define_matcher_outside_rspec.feature +0 -38
- data/features/custom_matchers/define_matcher_with_fluent_interface.feature +0 -24
- data/features/customized_message.feature +0 -22
- data/features/diffing.feature +0 -85
- data/features/implicit_docstrings.feature +0 -52
- data/features/step_definitions/additional_cli_steps.rb +0 -22
- data/features/support/env.rb +0 -14
- data/features/syntax_configuration.feature +0 -71
- data/features/test_frameworks/test_unit.feature +0 -44
- data/lib/rspec/expectations/deprecation.rb +0 -17
- data/lib/rspec/expectations/differ.rb +0 -133
- data/lib/rspec/expectations/errors.rb +0 -9
- data/lib/rspec/expectations/extensions/array.rb +0 -9
- data/lib/rspec/expectations/extensions/object.rb +0 -29
- data/lib/rspec/expectations/extensions.rb +0 -2
- data/lib/rspec/matchers/be_close.rb +0 -9
- data/lib/rspec/matchers/built_in/have.rb +0 -124
- data/lib/rspec/matchers/built_in/match_array.rb +0 -51
- data/lib/rspec/matchers/built_in/start_and_end_with.rb +0 -48
- data/lib/rspec/matchers/compatibility.rb +0 -14
- data/lib/rspec/matchers/configuration.rb +0 -108
- data/lib/rspec/matchers/extensions/instance_eval_with_args.rb +0 -39
- data/lib/rspec/matchers/matcher.rb +0 -300
- data/lib/rspec/matchers/method_missing.rb +0 -12
- data/lib/rspec/matchers/operator_matcher.rb +0 -109
- data/lib/rspec/matchers/pretty.rb +0 -70
- data/lib/rspec/matchers/test_unit_integration.rb +0 -11
- data/lib/rspec-expectations.rb +0 -1
- data/spec/rspec/expectations/differ_spec.rb +0 -192
- data/spec/rspec/expectations/expectation_target_spec.rb +0 -82
- data/spec/rspec/expectations/extensions/kernel_spec.rb +0 -67
- data/spec/rspec/expectations/fail_with_spec.rb +0 -114
- data/spec/rspec/expectations/handler_spec.rb +0 -227
- data/spec/rspec/expectations/syntax_spec.rb +0 -139
- data/spec/rspec/matchers/base_matcher_spec.rb +0 -62
- data/spec/rspec/matchers/be_close_spec.rb +0 -22
- data/spec/rspec/matchers/be_instance_of_spec.rb +0 -63
- data/spec/rspec/matchers/be_kind_of_spec.rb +0 -41
- data/spec/rspec/matchers/be_spec.rb +0 -516
- data/spec/rspec/matchers/be_within_spec.rb +0 -137
- data/spec/rspec/matchers/change_spec.rb +0 -553
- data/spec/rspec/matchers/configuration_spec.rb +0 -206
- data/spec/rspec/matchers/cover_spec.rb +0 -69
- data/spec/rspec/matchers/description_generation_spec.rb +0 -190
- data/spec/rspec/matchers/dsl_spec.rb +0 -57
- data/spec/rspec/matchers/eq_spec.rb +0 -60
- data/spec/rspec/matchers/eql_spec.rb +0 -41
- data/spec/rspec/matchers/equal_spec.rb +0 -78
- data/spec/rspec/matchers/exist_spec.rb +0 -124
- data/spec/rspec/matchers/has_spec.rb +0 -122
- data/spec/rspec/matchers/have_spec.rb +0 -455
- data/spec/rspec/matchers/include_matcher_integration_spec.rb +0 -30
- data/spec/rspec/matchers/include_spec.rb +0 -531
- data/spec/rspec/matchers/match_array_spec.rb +0 -194
- data/spec/rspec/matchers/match_spec.rb +0 -61
- data/spec/rspec/matchers/matcher_spec.rb +0 -471
- data/spec/rspec/matchers/matchers_spec.rb +0 -37
- data/spec/rspec/matchers/method_missing_spec.rb +0 -28
- data/spec/rspec/matchers/operator_matcher_spec.rb +0 -223
- data/spec/rspec/matchers/raise_error_spec.rb +0 -485
- data/spec/rspec/matchers/respond_to_spec.rb +0 -292
- data/spec/rspec/matchers/satisfy_spec.rb +0 -44
- data/spec/rspec/matchers/start_with_end_with_spec.rb +0 -186
- data/spec/rspec/matchers/throw_symbol_spec.rb +0 -116
- data/spec/rspec/matchers/yield_spec.rb +0 -514
- data/spec/spec_helper.rb +0 -54
- data/spec/support/classes.rb +0 -56
- data/spec/support/in_sub_process.rb +0 -38
- data/spec/support/matchers.rb +0 -22
- data/spec/support/ruby_version.rb +0 -10
- data/spec/support/shared_examples.rb +0 -13
@@ -1,44 +1,113 @@
|
|
1
|
+
RSpec::Support.require_rspec_support "method_signature_verifier"
|
2
|
+
|
1
3
|
module RSpec
|
2
4
|
module Matchers
|
3
5
|
module BuiltIn
|
4
|
-
|
6
|
+
# @api private
|
7
|
+
# Provides the implementation for `respond_to`.
|
8
|
+
# Not intended to be instantiated directly.
|
9
|
+
class RespondTo < BaseMatcher
|
5
10
|
def initialize(*names)
|
6
11
|
@names = names
|
7
12
|
@expected_arity = nil
|
13
|
+
@expected_keywords = []
|
14
|
+
@ignoring_method_signature_failure = false
|
15
|
+
@unlimited_arguments = nil
|
16
|
+
@arbitrary_keywords = nil
|
17
|
+
end
|
18
|
+
|
19
|
+
# @api public
|
20
|
+
# Specifies the number of expected arguments.
|
21
|
+
#
|
22
|
+
# @example
|
23
|
+
# expect(obj).to respond_to(:message).with(3).arguments
|
24
|
+
def with(n)
|
25
|
+
@expected_arity = n
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
# @api public
|
30
|
+
# Specifies keyword arguments, if any.
|
31
|
+
#
|
32
|
+
# @example
|
33
|
+
# expect(obj).to respond_to(:message).with_keywords(:color, :shape)
|
34
|
+
# @example with an expected number of arguments
|
35
|
+
# expect(obj).to respond_to(:message).with(3).arguments.and_keywords(:color, :shape)
|
36
|
+
def with_keywords(*keywords)
|
37
|
+
@expected_keywords = keywords
|
38
|
+
self
|
39
|
+
end
|
40
|
+
alias :and_keywords :with_keywords
|
41
|
+
|
42
|
+
# @api public
|
43
|
+
# Specifies that the method accepts any keyword, i.e. the method has
|
44
|
+
# a splatted keyword parameter of the form **kw_args.
|
45
|
+
#
|
46
|
+
# @example
|
47
|
+
# expect(obj).to respond_to(:message).with_any_keywords
|
48
|
+
def with_any_keywords
|
49
|
+
@arbitrary_keywords = true
|
50
|
+
self
|
8
51
|
end
|
52
|
+
alias :and_any_keywords :with_any_keywords
|
9
53
|
|
54
|
+
# @api public
|
55
|
+
# Specifies that the number of arguments has no upper limit, i.e. the
|
56
|
+
# method has a splatted parameter of the form *args.
|
57
|
+
#
|
58
|
+
# @example
|
59
|
+
# expect(obj).to respond_to(:message).with_unlimited_arguments
|
60
|
+
def with_unlimited_arguments
|
61
|
+
@unlimited_arguments = true
|
62
|
+
self
|
63
|
+
end
|
64
|
+
alias :and_unlimited_arguments :with_unlimited_arguments
|
65
|
+
|
66
|
+
# @api public
|
67
|
+
# No-op. Intended to be used as syntactic sugar when using `with`.
|
68
|
+
#
|
69
|
+
# @example
|
70
|
+
# expect(obj).to respond_to(:message).with(3).arguments
|
71
|
+
def argument
|
72
|
+
self
|
73
|
+
end
|
74
|
+
alias :arguments :argument
|
75
|
+
|
76
|
+
# @private
|
10
77
|
def matches?(actual)
|
11
78
|
find_failing_method_names(actual, :reject).empty?
|
12
79
|
end
|
13
|
-
alias == matches?
|
14
80
|
|
81
|
+
# @private
|
15
82
|
def does_not_match?(actual)
|
16
83
|
find_failing_method_names(actual, :select).empty?
|
17
84
|
end
|
18
85
|
|
19
|
-
|
20
|
-
|
86
|
+
# @api private
|
87
|
+
# @return [String]
|
88
|
+
def failure_message
|
89
|
+
"expected #{actual_formatted} to respond to #{@failing_method_names.map { |name| description_of(name) }.join(', ')}#{with_arity}"
|
21
90
|
end
|
22
91
|
|
23
|
-
|
24
|
-
|
92
|
+
# @api private
|
93
|
+
# @return [String]
|
94
|
+
def failure_message_when_negated
|
95
|
+
failure_message.sub(/to respond to/, 'not to respond to')
|
25
96
|
end
|
26
97
|
|
98
|
+
# @api private
|
99
|
+
# @return [String]
|
27
100
|
def description
|
28
101
|
"respond to #{pp_names}#{with_arity}"
|
29
102
|
end
|
30
103
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
def argument
|
37
|
-
self
|
104
|
+
# @api private
|
105
|
+
# Used by other matchers to suppress a check
|
106
|
+
def ignoring_method_signature_failure!
|
107
|
+
@ignoring_method_signature_failure = true
|
38
108
|
end
|
39
|
-
alias :arguments :argument
|
40
109
|
|
41
|
-
|
110
|
+
private
|
42
111
|
|
43
112
|
def find_failing_method_names(actual, filter_method)
|
44
113
|
@actual = actual
|
@@ -48,25 +117,82 @@ module RSpec
|
|
48
117
|
end
|
49
118
|
|
50
119
|
def matches_arity?(actual, name)
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
end
|
120
|
+
ArityCheck.new(@expected_arity, @expected_keywords, @arbitrary_keywords, @unlimited_arguments).matches?(actual, name)
|
121
|
+
rescue NameError
|
122
|
+
return true if @ignoring_method_signature_failure
|
123
|
+
raise ArgumentError, "The #{matcher_name} matcher requires that " \
|
124
|
+
"the actual object define the method(s) in " \
|
125
|
+
"order to check arity, but the method " \
|
126
|
+
"`#{name}` is not defined. Remove the arity " \
|
127
|
+
"check or define the method to continue."
|
60
128
|
end
|
61
129
|
|
62
130
|
def with_arity
|
63
|
-
|
64
|
-
|
131
|
+
str = ''.dup
|
132
|
+
str << " with #{with_arity_string}" if @expected_arity
|
133
|
+
str << " #{str.length == 0 ? 'with' : 'and'} #{with_keywords_string}" if @expected_keywords && @expected_keywords.count > 0
|
134
|
+
str << " #{str.length == 0 ? 'with' : 'and'} unlimited arguments" if @unlimited_arguments
|
135
|
+
str << " #{str.length == 0 ? 'with' : 'and'} any keywords" if @arbitrary_keywords
|
136
|
+
str
|
137
|
+
end
|
138
|
+
|
139
|
+
def with_arity_string
|
140
|
+
"#{@expected_arity} argument#{@expected_arity == 1 ? '' : 's'}"
|
141
|
+
end
|
142
|
+
|
143
|
+
def with_keywords_string
|
144
|
+
kw_str = case @expected_keywords.count
|
145
|
+
when 1
|
146
|
+
@expected_keywords.first.inspect
|
147
|
+
when 2
|
148
|
+
@expected_keywords.map(&:inspect).join(' and ')
|
149
|
+
else
|
150
|
+
"#{@expected_keywords[0...-1].map(&:inspect).join(', ')}, and #{@expected_keywords.last.inspect}"
|
151
|
+
end
|
152
|
+
|
153
|
+
"keyword#{@expected_keywords.count == 1 ? '' : 's'} #{kw_str}"
|
65
154
|
end
|
66
155
|
|
67
156
|
def pp_names
|
68
|
-
|
69
|
-
|
157
|
+
@names.length == 1 ? "##{@names.first}" : description_of(@names)
|
158
|
+
end
|
159
|
+
|
160
|
+
# @private
|
161
|
+
class ArityCheck
|
162
|
+
def initialize(expected_arity, expected_keywords, arbitrary_keywords, unlimited_arguments)
|
163
|
+
expectation = Support::MethodSignatureExpectation.new
|
164
|
+
|
165
|
+
if expected_arity.is_a?(Range)
|
166
|
+
expectation.min_count = expected_arity.min
|
167
|
+
expectation.max_count = expected_arity.max
|
168
|
+
else
|
169
|
+
expectation.min_count = expected_arity
|
170
|
+
end
|
171
|
+
|
172
|
+
expectation.keywords = expected_keywords
|
173
|
+
expectation.expect_unlimited_arguments = unlimited_arguments
|
174
|
+
expectation.expect_arbitrary_keywords = arbitrary_keywords
|
175
|
+
@expectation = expectation
|
176
|
+
end
|
177
|
+
|
178
|
+
def matches?(actual, name)
|
179
|
+
return true if @expectation.empty?
|
180
|
+
verifier_for(actual, name).with_expectation(@expectation).valid?
|
181
|
+
end
|
182
|
+
|
183
|
+
def verifier_for(actual, name)
|
184
|
+
Support::StrictSignatureVerifier.new(method_signature_for(actual, name))
|
185
|
+
end
|
186
|
+
|
187
|
+
def method_signature_for(actual, name)
|
188
|
+
method_handle = Support.method_handle_for(actual, name)
|
189
|
+
|
190
|
+
if name == :new && method_handle.owner === ::Class && ::Class === actual
|
191
|
+
Support::MethodSignature.new(actual.instance_method(:initialize))
|
192
|
+
else
|
193
|
+
Support::MethodSignature.new(method_handle)
|
194
|
+
end
|
195
|
+
end
|
70
196
|
end
|
71
197
|
end
|
72
198
|
end
|
@@ -1,28 +1,58 @@
|
|
1
1
|
module RSpec
|
2
2
|
module Matchers
|
3
3
|
module BuiltIn
|
4
|
-
|
5
|
-
|
4
|
+
# @api private
|
5
|
+
# Provides the implementation for `satisfy`.
|
6
|
+
# Not intended to be instantiated directly.
|
7
|
+
class Satisfy < BaseMatcher
|
8
|
+
def initialize(description=nil, &block)
|
9
|
+
@description = description
|
6
10
|
@block = block
|
7
11
|
end
|
8
12
|
|
13
|
+
# @private
|
9
14
|
def matches?(actual, &block)
|
10
15
|
@block = block if block
|
11
16
|
@actual = actual
|
12
17
|
@block.call(actual)
|
13
18
|
end
|
14
|
-
alias == matches?
|
15
19
|
|
16
|
-
|
17
|
-
|
20
|
+
# @private
|
21
|
+
def description
|
22
|
+
@description ||= "satisfy #{block_representation}"
|
18
23
|
end
|
19
24
|
|
20
|
-
|
21
|
-
|
25
|
+
# @api private
|
26
|
+
# @return [String]
|
27
|
+
def failure_message
|
28
|
+
"expected #{actual_formatted} to #{description}"
|
22
29
|
end
|
23
30
|
|
24
|
-
|
25
|
-
|
31
|
+
# @api private
|
32
|
+
# @return [String]
|
33
|
+
def failure_message_when_negated
|
34
|
+
"expected #{actual_formatted} not to #{description}"
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
if RSpec::Support::RubyFeatures.ripper_supported?
|
40
|
+
def block_representation
|
41
|
+
if (block_snippet = extract_block_snippet)
|
42
|
+
"expression `#{block_snippet}`"
|
43
|
+
else
|
44
|
+
'block'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def extract_block_snippet
|
49
|
+
return nil unless @block
|
50
|
+
Expectations::BlockSnippetExtractor.try_extracting_single_line_body_of(@block, matcher_name)
|
51
|
+
end
|
52
|
+
else
|
53
|
+
def block_representation
|
54
|
+
'block'
|
55
|
+
end
|
26
56
|
end
|
27
57
|
end
|
28
58
|
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Matchers
|
3
|
+
module BuiltIn
|
4
|
+
# @api private
|
5
|
+
# Base class for the `end_with` and `start_with` matchers.
|
6
|
+
# Not intended to be instantiated directly.
|
7
|
+
class StartOrEndWith < BaseMatcher
|
8
|
+
def initialize(*expected)
|
9
|
+
@actual_does_not_have_ordered_elements = false
|
10
|
+
@expected = expected.length == 1 ? expected.first : expected
|
11
|
+
end
|
12
|
+
|
13
|
+
# @api private
|
14
|
+
# @return [String]
|
15
|
+
def failure_message
|
16
|
+
super.tap do |msg|
|
17
|
+
if @actual_does_not_have_ordered_elements
|
18
|
+
msg << ", but it does not have ordered elements"
|
19
|
+
elsif !actual.respond_to?(:[])
|
20
|
+
msg << ", but it cannot be indexed using #[]"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# @api private
|
26
|
+
# @return [String]
|
27
|
+
def description
|
28
|
+
return super unless Hash === expected
|
29
|
+
english_name = EnglishPhrasing.split_words(self.class.matcher_name)
|
30
|
+
description_of_expected = surface_descriptions_in(expected).inspect
|
31
|
+
"#{english_name} #{description_of_expected}"
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def match(_expected, actual)
|
37
|
+
return false unless actual.respond_to?(:[])
|
38
|
+
|
39
|
+
begin
|
40
|
+
return true if subsets_comparable? && subset_matches?
|
41
|
+
element_matches?
|
42
|
+
rescue ArgumentError
|
43
|
+
@actual_does_not_have_ordered_elements = true
|
44
|
+
return false
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def subsets_comparable?
|
49
|
+
# Structs support the Enumerable interface but don't really have
|
50
|
+
# the semantics of a subset of a larger set...
|
51
|
+
return false if Struct === expected
|
52
|
+
|
53
|
+
expected.respond_to?(:length)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# For RSpec 3.1, the base class was named `StartAndEndWith`. For SemVer reasons,
|
58
|
+
# we still provide this constant until 4.0.
|
59
|
+
# @deprecated Use StartOrEndWith instead.
|
60
|
+
# @private
|
61
|
+
StartAndEndWith = StartOrEndWith
|
62
|
+
|
63
|
+
# @api private
|
64
|
+
# Provides the implementation for `start_with`.
|
65
|
+
# Not intended to be instantiated directly.
|
66
|
+
class StartWith < StartOrEndWith
|
67
|
+
private
|
68
|
+
|
69
|
+
def subset_matches?
|
70
|
+
values_match?(expected, actual[0, expected.length])
|
71
|
+
end
|
72
|
+
|
73
|
+
def element_matches?
|
74
|
+
values_match?(expected, actual[0])
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# @api private
|
79
|
+
# Provides the implementation for `end_with`.
|
80
|
+
# Not intended to be instantiated directly.
|
81
|
+
class EndWith < StartOrEndWith
|
82
|
+
private
|
83
|
+
|
84
|
+
def subset_matches?
|
85
|
+
values_match?(expected, actual[-expected.length, expected.length])
|
86
|
+
end
|
87
|
+
|
88
|
+
def element_matches?
|
89
|
+
values_match?(expected, actual[-1])
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -1,14 +1,24 @@
|
|
1
1
|
module RSpec
|
2
2
|
module Matchers
|
3
3
|
module BuiltIn
|
4
|
+
# @api private
|
5
|
+
# Provides the implementation for `throw_symbol`.
|
6
|
+
# Not intended to be instantiated directly.
|
4
7
|
class ThrowSymbol
|
5
|
-
|
8
|
+
include Composable
|
9
|
+
|
10
|
+
def initialize(expected_symbol=nil, expected_arg=nil)
|
6
11
|
@expected_symbol = expected_symbol
|
7
12
|
@expected_arg = expected_arg
|
8
13
|
@caught_symbol = @caught_arg = nil
|
9
14
|
end
|
10
15
|
|
16
|
+
# rubocop:disable Metrics/MethodLength
|
17
|
+
# @private
|
11
18
|
def matches?(given_proc)
|
19
|
+
@block = given_proc
|
20
|
+
return false unless Proc === given_proc
|
21
|
+
|
12
22
|
begin
|
13
23
|
if @expected_symbol.nil?
|
14
24
|
given_proc.call
|
@@ -30,44 +40,78 @@ module RSpec
|
|
30
40
|
# Ruby 1.8 uses NameError with `symbol'
|
31
41
|
# Ruby 1.9 uses ArgumentError with :symbol
|
32
42
|
rescue NameError, ArgumentError => e
|
33
|
-
unless e.message
|
43
|
+
unless (match_data = e.message.match(/uncaught throw (`|\:)([a-zA-Z0-9_]*)(')?/))
|
34
44
|
other_exception = e
|
35
45
|
raise
|
36
46
|
end
|
37
|
-
@caught_symbol =
|
47
|
+
@caught_symbol = match_data.captures[1].to_sym
|
38
48
|
rescue => other_exception
|
39
49
|
raise
|
40
50
|
ensure
|
51
|
+
# rubocop:disable Lint/EnsureReturn
|
41
52
|
unless other_exception
|
42
53
|
if @expected_symbol.nil?
|
43
|
-
return
|
54
|
+
return !!@caught_symbol
|
44
55
|
else
|
45
56
|
if @expected_arg.nil?
|
46
57
|
return @caught_symbol == @expected_symbol
|
47
58
|
else
|
48
|
-
return (@caught_symbol == @expected_symbol)
|
59
|
+
return (@caught_symbol == @expected_symbol) && values_match?(@expected_arg, @caught_arg)
|
49
60
|
end
|
50
61
|
end
|
51
62
|
end
|
63
|
+
# rubocop:enable Lint/EnsureReturn
|
52
64
|
end
|
53
65
|
end
|
54
|
-
|
66
|
+
# rubocop:enable Metrics/MethodLength
|
67
|
+
|
68
|
+
def does_not_match?(given_proc)
|
69
|
+
!matches?(given_proc) && Proc === given_proc
|
70
|
+
end
|
55
71
|
|
56
|
-
|
57
|
-
|
72
|
+
# @api private
|
73
|
+
# @return [String]
|
74
|
+
def failure_message
|
75
|
+
"expected #{expected} to be thrown, #{actual_result}"
|
58
76
|
end
|
59
77
|
|
60
|
-
|
61
|
-
|
78
|
+
# @api private
|
79
|
+
# @return [String]
|
80
|
+
def failure_message_when_negated
|
81
|
+
"expected #{expected('no Symbol')}#{' not' if @expected_symbol} to be thrown, #{actual_result}"
|
62
82
|
end
|
63
83
|
|
84
|
+
# @api private
|
85
|
+
# @return [String]
|
64
86
|
def description
|
65
87
|
"throw #{expected}"
|
66
88
|
end
|
67
89
|
|
68
|
-
private
|
90
|
+
# @api private
|
91
|
+
# Indicates this matcher matches against a block.
|
92
|
+
# @return [True]
|
93
|
+
def supports_block_expectations?
|
94
|
+
true
|
95
|
+
end
|
96
|
+
|
97
|
+
# @api private
|
98
|
+
def supports_value_expectations?
|
99
|
+
false
|
100
|
+
end
|
101
|
+
|
102
|
+
# @api private
|
103
|
+
def expects_call_stack_jump?
|
104
|
+
true
|
105
|
+
end
|
106
|
+
|
107
|
+
private
|
108
|
+
|
109
|
+
def actual_result
|
110
|
+
return "but was not a block" unless Proc === @block
|
111
|
+
"got #{caught}"
|
112
|
+
end
|
69
113
|
|
70
|
-
def expected(symbol_desc
|
114
|
+
def expected(symbol_desc='a Symbol')
|
71
115
|
throw_description(@expected_symbol || symbol_desc, @expected_arg)
|
72
116
|
end
|
73
117
|
|
@@ -76,10 +120,10 @@ module RSpec
|
|
76
120
|
end
|
77
121
|
|
78
122
|
def throw_description(symbol, arg)
|
79
|
-
symbol_description = symbol.is_a?(String) ? symbol : symbol
|
123
|
+
symbol_description = symbol.is_a?(String) ? symbol : description_of(symbol)
|
80
124
|
|
81
125
|
arg_description = if arg
|
82
|
-
" with #{arg
|
126
|
+
" with #{description_of arg}"
|
83
127
|
elsif @expected_arg && @caught_symbol == @expected_symbol
|
84
128
|
" with no argument"
|
85
129
|
else
|