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,31 +1,36 @@
|
|
|
1
1
|
module RSpec
|
|
2
2
|
module Expectations
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
"WARNING: ignoring the provided expectation message argument " +
|
|
7
|
-
"(#{msg.inspect}) since it is not a string."
|
|
8
|
-
end
|
|
9
|
-
|
|
4
|
+
# @private
|
|
5
|
+
module ExpectationHelper
|
|
10
6
|
def self.check_message(msg)
|
|
11
|
-
|
|
7
|
+
unless msg.nil? || msg.respond_to?(:to_str) || msg.respond_to?(:call)
|
|
8
|
+
::Kernel.warn [
|
|
9
|
+
"WARNING: ignoring the provided expectation message argument (",
|
|
10
|
+
msg.inspect,
|
|
11
|
+
") since it is not a string or a proc."
|
|
12
|
+
].join
|
|
13
|
+
end
|
|
12
14
|
end
|
|
13
|
-
end
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
# Returns an RSpec-3+ compatible matcher, wrapping a legacy one
|
|
17
|
+
# in an adapter if necessary.
|
|
18
|
+
#
|
|
19
|
+
# @private
|
|
20
|
+
def self.modern_matcher_from(matcher)
|
|
21
|
+
LegacyMacherAdapter::RSpec2.wrap(matcher) ||
|
|
22
|
+
LegacyMacherAdapter::RSpec1.wrap(matcher) || matcher
|
|
23
|
+
end
|
|
16
24
|
|
|
17
|
-
def self.
|
|
25
|
+
def self.setup(handler, matcher, message)
|
|
18
26
|
check_message(message)
|
|
19
|
-
::RSpec::Matchers.
|
|
20
|
-
::RSpec::Matchers.last_matcher = matcher
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
match = matcher.matches?(actual, &block)
|
|
24
|
-
return match if match
|
|
27
|
+
::RSpec::Matchers.last_expectation_handler = handler
|
|
28
|
+
::RSpec::Matchers.last_matcher = modern_matcher_from(matcher)
|
|
29
|
+
end
|
|
25
30
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
31
|
+
def self.handle_failure(matcher, message, failure_message_method)
|
|
32
|
+
message = message.call if message.respond_to?(:call)
|
|
33
|
+
message ||= matcher.__send__(failure_message_method)
|
|
29
34
|
|
|
30
35
|
if matcher.respond_to?(:diffable?) && matcher.diffable?
|
|
31
36
|
::RSpec::Expectations.fail_with message, matcher.expected, matcher.actual
|
|
@@ -35,26 +40,121 @@ module RSpec
|
|
|
35
40
|
end
|
|
36
41
|
end
|
|
37
42
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
::RSpec::Matchers.last_matcher = matcher
|
|
43
|
-
return ::RSpec::Matchers::BuiltIn::NegativeOperatorMatcher.new(actual) if matcher.nil?
|
|
43
|
+
# @private
|
|
44
|
+
class PositiveExpectationHandler
|
|
45
|
+
def self.handle_matcher(actual, initial_matcher, message=nil, &block)
|
|
46
|
+
matcher = ExpectationHelper.setup(self, initial_matcher, message)
|
|
44
47
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
return match unless match
|
|
48
|
+
return ::RSpec::Matchers::BuiltIn::PositiveOperatorMatcher.new(actual) unless initial_matcher
|
|
49
|
+
matcher.matches?(actual, &block) or ExpectationHelper.handle_failure(matcher, message, :failure_message)
|
|
50
|
+
end
|
|
49
51
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
52
|
+
def self.verb
|
|
53
|
+
"should"
|
|
54
|
+
end
|
|
53
55
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
+
def self.should_method
|
|
57
|
+
:should
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def self.opposite_should_method
|
|
61
|
+
:should_not
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# @private
|
|
66
|
+
class NegativeExpectationHandler
|
|
67
|
+
def self.handle_matcher(actual, initial_matcher, message=nil, &block)
|
|
68
|
+
matcher = ExpectationHelper.setup(self, initial_matcher, message)
|
|
69
|
+
|
|
70
|
+
return ::RSpec::Matchers::BuiltIn::NegativeOperatorMatcher.new(actual) unless initial_matcher
|
|
71
|
+
!(does_not_match?(matcher, actual, &block) or ExpectationHelper.handle_failure(matcher, message, :failure_message_when_negated))
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def self.does_not_match?(matcher, actual, &block)
|
|
75
|
+
if matcher.respond_to?(:does_not_match?)
|
|
76
|
+
matcher.does_not_match?(actual, &block)
|
|
56
77
|
else
|
|
57
|
-
|
|
78
|
+
!matcher.matches?(actual, &block)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def self.verb
|
|
83
|
+
"should not"
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def self.should_method
|
|
87
|
+
:should_not
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def self.opposite_should_method
|
|
91
|
+
:should
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Wraps a matcher written against one of the legacy protocols in
|
|
96
|
+
# order to present the current protocol.
|
|
97
|
+
#
|
|
98
|
+
# @private
|
|
99
|
+
class LegacyMacherAdapter < Matchers::MatcherDelegator
|
|
100
|
+
def initialize(matcher)
|
|
101
|
+
super
|
|
102
|
+
::RSpec.warn_deprecation(<<-EOS.gsub(/^\s+\|/, ''), :type => "legacy_matcher")
|
|
103
|
+
|#{matcher.class.name || matcher.inspect} implements a legacy RSpec matcher
|
|
104
|
+
|protocol. For the current protocol you should expose the failure messages
|
|
105
|
+
|via the `failure_message` and `failure_message_when_negated` methods.
|
|
106
|
+
|(Used from #{CallerFilter.first_non_rspec_line})
|
|
107
|
+
EOS
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def self.wrap(matcher)
|
|
111
|
+
new(matcher) if interface_matches?(matcher)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Starting in RSpec 1.2 (and continuing through all 2.x releases),
|
|
115
|
+
# the failure message protocol was:
|
|
116
|
+
# * `failure_message_for_should`
|
|
117
|
+
# * `failure_message_for_should_not`
|
|
118
|
+
# @private
|
|
119
|
+
class RSpec2 < self
|
|
120
|
+
def failure_message
|
|
121
|
+
base_matcher.failure_message_for_should
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def failure_message_when_negated
|
|
125
|
+
base_matcher.failure_message_for_should_not
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def self.interface_matches?(matcher)
|
|
129
|
+
(
|
|
130
|
+
!matcher.respond_to?(:failure_message) &&
|
|
131
|
+
matcher.respond_to?(:failure_message_for_should)
|
|
132
|
+
) || (
|
|
133
|
+
!matcher.respond_to?(:failure_message_when_negated) &&
|
|
134
|
+
matcher.respond_to?(:failure_message_for_should_not)
|
|
135
|
+
)
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Before RSpec 1.2, the failure message protocol was:
|
|
140
|
+
# * `failure_message`
|
|
141
|
+
# * `negative_failure_message`
|
|
142
|
+
# @private
|
|
143
|
+
class RSpec1 < self
|
|
144
|
+
def failure_message
|
|
145
|
+
base_matcher.failure_message
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def failure_message_when_negated
|
|
149
|
+
base_matcher.negative_failure_message
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Note: `failure_message` is part of the RSpec 3 protocol
|
|
153
|
+
# (paired with `failure_message_when_negated`), so we don't check
|
|
154
|
+
# for `failure_message` here.
|
|
155
|
+
def self.interface_matches?(matcher)
|
|
156
|
+
!matcher.respond_to?(:failure_message_when_negated) &&
|
|
157
|
+
matcher.respond_to?(:negative_failure_message)
|
|
58
158
|
end
|
|
59
159
|
end
|
|
60
160
|
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require 'rspec/expectations'
|
|
2
|
+
|
|
3
|
+
Minitest::Test.class_eval do
|
|
4
|
+
include ::RSpec::Matchers
|
|
5
|
+
|
|
6
|
+
def expect(*a, &b)
|
|
7
|
+
assert(true) # so each expectation gets counted in minitest's assertion stats
|
|
8
|
+
super
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
module RSpec::Expectations
|
|
13
|
+
remove_const :ExpectationNotMetError
|
|
14
|
+
ExpectationNotMetError = ::Minitest::Assertion
|
|
15
|
+
end
|
|
16
|
+
|
|
@@ -4,38 +4,7 @@ module RSpec
|
|
|
4
4
|
# Provides methods for enabling and disabling the available
|
|
5
5
|
# syntaxes provided by rspec-expectations.
|
|
6
6
|
module Syntax
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
# @method should
|
|
10
|
-
# Passes if `matcher` returns true. Available on every `Object`.
|
|
11
|
-
# @example
|
|
12
|
-
# actual.should eq expected
|
|
13
|
-
# actual.should match /expression/
|
|
14
|
-
# @param [Matcher]
|
|
15
|
-
# matcher
|
|
16
|
-
# @param [String] message optional message to display when the expectation fails
|
|
17
|
-
# @return [Boolean] true if the expectation succeeds (else raises)
|
|
18
|
-
# @see RSpec::Matchers
|
|
19
|
-
|
|
20
|
-
# @method should_not
|
|
21
|
-
# Passes if `matcher` returns false. Available on every `Object`.
|
|
22
|
-
# @example
|
|
23
|
-
# actual.should_not eq expected
|
|
24
|
-
# @param [Matcher]
|
|
25
|
-
# matcher
|
|
26
|
-
# @param [String] message optional message to display when the expectation fails
|
|
27
|
-
# @return [Boolean] false if the negative expectation succeeds (else raises)
|
|
28
|
-
# @see RSpec::Matchers
|
|
29
|
-
|
|
30
|
-
# @method expect
|
|
31
|
-
# Supports `expect(actual).to matcher` syntax by wrapping `actual` in an
|
|
32
|
-
# `ExpectationTarget`.
|
|
33
|
-
# @example
|
|
34
|
-
# expect(actual).to eq(expected)
|
|
35
|
-
# expect(actual).to_not eq(expected)
|
|
36
|
-
# @return [ExpectationTarget]
|
|
37
|
-
# @see ExpectationTarget#to
|
|
38
|
-
# @see ExpectationTarget#to_not
|
|
7
|
+
module_function
|
|
39
8
|
|
|
40
9
|
# @api private
|
|
41
10
|
# Determines where we add `should` and `should_not`.
|
|
@@ -43,22 +12,44 @@ module RSpec
|
|
|
43
12
|
@default_should_host ||= ::Object.ancestors.last
|
|
44
13
|
end
|
|
45
14
|
|
|
15
|
+
# @api private
|
|
16
|
+
# Instructs rspec-expectations to warn on first usage of `should` or `should_not`.
|
|
17
|
+
# Enabled by default. This is largely here to facilitate testing.
|
|
18
|
+
def warn_about_should!
|
|
19
|
+
@warn_about_should = true
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# @api private
|
|
23
|
+
# Generates a deprecation warning for the given method if no warning
|
|
24
|
+
# has already been issued.
|
|
25
|
+
def warn_about_should_unless_configured(method_name)
|
|
26
|
+
if @warn_about_should
|
|
27
|
+
RSpec.deprecate(
|
|
28
|
+
"Using `#{method_name}` from rspec-expectations' old `:should` syntax without explicitly enabling the syntax",
|
|
29
|
+
:replacement => "the new `:expect` syntax or explicitly enable `:should`"
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
@warn_about_should = false
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
46
36
|
# @api private
|
|
47
37
|
# Enables the `should` syntax.
|
|
48
38
|
def enable_should(syntax_host = default_should_host)
|
|
39
|
+
@warn_about_should = false if syntax_host == default_should_host
|
|
49
40
|
return if should_enabled?(syntax_host)
|
|
50
41
|
|
|
51
|
-
syntax_host.
|
|
42
|
+
syntax_host.module_exec do
|
|
52
43
|
def should(matcher=nil, message=nil, &block)
|
|
44
|
+
::RSpec::Expectations::Syntax.warn_about_should_unless_configured(__method__)
|
|
53
45
|
::RSpec::Expectations::PositiveExpectationHandler.handle_matcher(self, matcher, message, &block)
|
|
54
46
|
end
|
|
55
47
|
|
|
56
48
|
def should_not(matcher=nil, message=nil, &block)
|
|
49
|
+
::RSpec::Expectations::Syntax.warn_about_should_unless_configured(__method__)
|
|
57
50
|
::RSpec::Expectations::NegativeExpectationHandler.handle_matcher(self, matcher, message, &block)
|
|
58
51
|
end
|
|
59
52
|
end
|
|
60
|
-
|
|
61
|
-
::RSpec::Expectations::ExpectationTarget.enable_deprecated_should if expect_enabled?
|
|
62
53
|
end
|
|
63
54
|
|
|
64
55
|
# @api private
|
|
@@ -66,12 +57,10 @@ module RSpec
|
|
|
66
57
|
def disable_should(syntax_host = default_should_host)
|
|
67
58
|
return unless should_enabled?(syntax_host)
|
|
68
59
|
|
|
69
|
-
syntax_host.
|
|
60
|
+
syntax_host.module_exec do
|
|
70
61
|
undef should
|
|
71
62
|
undef should_not
|
|
72
63
|
end
|
|
73
|
-
|
|
74
|
-
::RSpec::Expectations::ExpectationTarget.disable_deprecated_should
|
|
75
64
|
end
|
|
76
65
|
|
|
77
66
|
# @api private
|
|
@@ -79,15 +68,11 @@ module RSpec
|
|
|
79
68
|
def enable_expect(syntax_host = ::RSpec::Matchers)
|
|
80
69
|
return if expect_enabled?(syntax_host)
|
|
81
70
|
|
|
82
|
-
syntax_host.
|
|
83
|
-
def expect(
|
|
84
|
-
|
|
85
|
-
raise ArgumentError.new("You must pass an argument or a block to #expect but not both.") unless target.size == 1
|
|
86
|
-
::RSpec::Expectations::ExpectationTarget.new(target.first)
|
|
71
|
+
syntax_host.module_exec do
|
|
72
|
+
def expect(value=::RSpec::Expectations::ExpectationTarget::UndefinedValue, &block)
|
|
73
|
+
::RSpec::Expectations::ExpectationTarget.for(value, block)
|
|
87
74
|
end
|
|
88
75
|
end
|
|
89
|
-
|
|
90
|
-
::RSpec::Expectations::ExpectationTarget.enable_deprecated_should if should_enabled?
|
|
91
76
|
end
|
|
92
77
|
|
|
93
78
|
# @api private
|
|
@@ -95,11 +80,9 @@ module RSpec
|
|
|
95
80
|
def disable_expect(syntax_host = ::RSpec::Matchers)
|
|
96
81
|
return unless expect_enabled?(syntax_host)
|
|
97
82
|
|
|
98
|
-
syntax_host.
|
|
83
|
+
syntax_host.module_exec do
|
|
99
84
|
undef expect
|
|
100
85
|
end
|
|
101
|
-
|
|
102
|
-
::RSpec::Expectations::ExpectationTarget.disable_deprecated_should
|
|
103
86
|
end
|
|
104
87
|
|
|
105
88
|
# @api private
|
|
@@ -113,52 +96,35 @@ module RSpec
|
|
|
113
96
|
def expect_enabled?(syntax_host = ::RSpec::Matchers)
|
|
114
97
|
syntax_host.method_defined?(:expect)
|
|
115
98
|
end
|
|
116
|
-
|
|
117
|
-
# @api private
|
|
118
|
-
# Generates a positive expectation expression.
|
|
119
|
-
def positive_expression(target_expression, matcher_expression)
|
|
120
|
-
expression_generator.positive_expression(target_expression, matcher_expression)
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
# @api private
|
|
124
|
-
# Generates a negative expectation expression.
|
|
125
|
-
def negative_expression(target_expression, matcher_expression)
|
|
126
|
-
expression_generator.negative_expression(target_expression, matcher_expression)
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
# @api private
|
|
130
|
-
# Selects which expression generator to use based on the configured syntax.
|
|
131
|
-
def expression_generator
|
|
132
|
-
if expect_enabled?
|
|
133
|
-
ExpectExpressionGenerator
|
|
134
|
-
else
|
|
135
|
-
ShouldExpressionGenerator
|
|
136
|
-
end
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
# @api private
|
|
140
|
-
# Generates expectation expressions for the `should` syntax.
|
|
141
|
-
module ShouldExpressionGenerator
|
|
142
|
-
def self.positive_expression(target_expression, matcher_expression)
|
|
143
|
-
"#{target_expression}.should #{matcher_expression}"
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
def self.negative_expression(target_expression, matcher_expression)
|
|
147
|
-
"#{target_expression}.should_not #{matcher_expression}"
|
|
148
|
-
end
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
# @api private
|
|
152
|
-
# Generates expectation expressions for the `expect` syntax.
|
|
153
|
-
module ExpectExpressionGenerator
|
|
154
|
-
def self.positive_expression(target_expression, matcher_expression)
|
|
155
|
-
"expect(#{target_expression}).to #{matcher_expression}"
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
def self.negative_expression(target_expression, matcher_expression)
|
|
159
|
-
"expect(#{target_expression}).not_to #{matcher_expression}"
|
|
160
|
-
end
|
|
161
|
-
end
|
|
162
99
|
end
|
|
163
100
|
end
|
|
164
101
|
end
|
|
102
|
+
|
|
103
|
+
# The legacy `:should` syntax adds the following methods directly to
|
|
104
|
+
# `BasicObject` so that they are available off of any object. Note, however,
|
|
105
|
+
# that this syntax does not always play nice with delegate/proxy objects.
|
|
106
|
+
# We recommend you use the non-monkeypatching `:expect` syntax instead.
|
|
107
|
+
class BasicObject
|
|
108
|
+
# @method should
|
|
109
|
+
# Passes if `matcher` returns true. Available on every `Object`.
|
|
110
|
+
# @example
|
|
111
|
+
# actual.should eq expected
|
|
112
|
+
# actual.should match /expression/
|
|
113
|
+
# @param [Matcher]
|
|
114
|
+
# matcher
|
|
115
|
+
# @param [String] message optional message to display when the expectation fails
|
|
116
|
+
# @return [Boolean] true if the expectation succeeds (else raises)
|
|
117
|
+
# @note This is only available when you have enabled the `:should` syntax.
|
|
118
|
+
# @see RSpec::Matchers
|
|
119
|
+
|
|
120
|
+
# @method should_not
|
|
121
|
+
# Passes if `matcher` returns false. Available on every `Object`.
|
|
122
|
+
# @example
|
|
123
|
+
# actual.should_not eq expected
|
|
124
|
+
# @param [Matcher]
|
|
125
|
+
# matcher
|
|
126
|
+
# @param [String] message optional message to display when the expectation fails
|
|
127
|
+
# @return [Boolean] false if the negative expectation succeeds (else raises)
|
|
128
|
+
# @note This is only available when you have enabled the `:should` syntax.
|
|
129
|
+
# @see RSpec::Matchers
|
|
130
|
+
end
|
data/lib/rspec/expectations.rb
CHANGED
|
@@ -1,47 +1,69 @@
|
|
|
1
|
-
require 'rspec/
|
|
1
|
+
require 'rspec/support'
|
|
2
|
+
RSpec::Support.require_rspec_support "caller_filter"
|
|
3
|
+
RSpec::Support.require_rspec_support "warnings"
|
|
4
|
+
|
|
2
5
|
require 'rspec/matchers'
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
|
|
7
|
+
RSpec::Support.define_optimized_require_for_rspec(:expectations) { |f| require_relative(f) }
|
|
8
|
+
|
|
9
|
+
%w[
|
|
10
|
+
expectation_target
|
|
11
|
+
configuration
|
|
12
|
+
fail_with
|
|
13
|
+
handler
|
|
14
|
+
version
|
|
15
|
+
].each { |file| RSpec::Support.require_rspec_expectations(file) }
|
|
11
16
|
|
|
12
17
|
module RSpec
|
|
13
|
-
# RSpec::Expectations
|
|
18
|
+
# RSpec::Expectations provides a simple, readable API to express
|
|
19
|
+
# the expected outcomes in a code example. To express an expected
|
|
20
|
+
# outcome, wrap an object or block in `expect`, call `to` or `to_not`
|
|
21
|
+
# (aliased as `not_to`) and pass it a matcher object:
|
|
14
22
|
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
23
|
+
# expect(order.total).to eq(Money.new(5.55, :USD))
|
|
24
|
+
# expect(list).to include(user)
|
|
25
|
+
# expect(message).not_to match(/foo/)
|
|
26
|
+
# expect { do_something }.to raise_error
|
|
17
27
|
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
28
|
+
# The last form (the block form) is needed to match against ruby constructs
|
|
29
|
+
# that are not objects, but can only be observed when executing a block
|
|
30
|
+
# of code. This includes raising errors, throwing symbols, yielding,
|
|
31
|
+
# and changing values.
|
|
32
|
+
#
|
|
33
|
+
# When `expect(...).to` is invoked with a matcher, it turns around
|
|
34
|
+
# and calls `matcher.matches?(<object wrapped by expect>)`. For example,
|
|
21
35
|
# in the expression:
|
|
22
36
|
#
|
|
23
|
-
# order.total.
|
|
37
|
+
# expect(order.total).to eq(Money.new(5.55, :USD))
|
|
24
38
|
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
# `
|
|
28
|
-
# `eq.
|
|
39
|
+
# ...`eq(Money.new(5.55, :USD))` returns a matcher object, and it results
|
|
40
|
+
# in the equivalent of `eq.matches?(order.total)`. If `matches?` returns
|
|
41
|
+
# `true`, the expectation is met and execution continues. If `false`, then
|
|
42
|
+
# the spec fails with the message returned by `eq.failure_message`.
|
|
29
43
|
#
|
|
30
44
|
# Given the expression:
|
|
31
45
|
#
|
|
32
|
-
# order.entries.
|
|
46
|
+
# expect(order.entries).not_to include(entry)
|
|
33
47
|
#
|
|
34
|
-
# the `
|
|
48
|
+
# ...the `not_to` method (also available as `to_not`) invokes the equivalent of
|
|
35
49
|
# `include.matches?(order.entries)`, but it interprets `false` as success, and
|
|
36
50
|
# `true` as a failure, using the message generated by
|
|
37
|
-
# `eq.
|
|
51
|
+
# `eq.failure_message_when_negated`.
|
|
38
52
|
#
|
|
39
53
|
# rspec-expectations ships with a standard set of useful matchers, and writing
|
|
40
|
-
# your own matchers is quite simple.
|
|
54
|
+
# your own matchers is quite simple.
|
|
41
55
|
#
|
|
42
56
|
# See [RSpec::Matchers](../RSpec/Matchers) for more information about the
|
|
43
57
|
# built-in matchers that ship with rspec-expectations, and how to write your
|
|
44
58
|
# own custom matchers.
|
|
45
59
|
module Expectations
|
|
60
|
+
# Exception raised when an expectation fails.
|
|
61
|
+
#
|
|
62
|
+
# @note We subclass Exception so that in a stub implementation if
|
|
63
|
+
# the user sets an expectation, it can't be caught in their
|
|
64
|
+
# code by a bare `rescue`.
|
|
65
|
+
# @api public
|
|
66
|
+
ExpectationNotMetError = Class.new(::Exception)
|
|
46
67
|
end
|
|
47
68
|
end
|
|
69
|
+
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module RSpec
|
|
2
|
+
module Matchers
|
|
3
|
+
# Decorator that wraps a matcher and overrides `description`
|
|
4
|
+
# using the provided block in order to support an alias
|
|
5
|
+
# of a matcher. This is intended for use when composing
|
|
6
|
+
# matchers, so that you can use an expression like
|
|
7
|
+
# `include( a_value_within(0.1).of(3) )` rather than
|
|
8
|
+
# `include( be_within(0.1).of(3) )`, and have the corresponding
|
|
9
|
+
# description read naturally.
|
|
10
|
+
#
|
|
11
|
+
# @api private
|
|
12
|
+
class AliasedMatcher < MatcherDelegator
|
|
13
|
+
def initialize(base_matcher, description_block)
|
|
14
|
+
@description_block = description_block
|
|
15
|
+
super(base_matcher)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Forward messages on to the wrapped matcher.
|
|
19
|
+
# Since many matchers provide a fluent interface
|
|
20
|
+
# (e.g. `a_value_within(0.1).of(3)`), we need to wrap
|
|
21
|
+
# the returned value if it responds to `description`,
|
|
22
|
+
# so that our override can be applied when it is eventually
|
|
23
|
+
# used.
|
|
24
|
+
def method_missing(*)
|
|
25
|
+
return_val = super
|
|
26
|
+
return return_val unless return_val.respond_to?(:description)
|
|
27
|
+
AliasedMatcher.new(return_val, @description_block)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Provides the description of the aliased matcher. Aliased matchers
|
|
31
|
+
# are designed to behave identically to the original matcher except
|
|
32
|
+
# for this method. The description is different to reflect the aliased
|
|
33
|
+
# name.
|
|
34
|
+
#
|
|
35
|
+
# @api private
|
|
36
|
+
def description
|
|
37
|
+
@description_block.call(super)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
module RSpec
|
|
2
|
+
module Matchers
|
|
3
|
+
module BuiltIn
|
|
4
|
+
# @api private
|
|
5
|
+
# Provides the implementation for `all`.
|
|
6
|
+
# Not intended to be instantiated directly.
|
|
7
|
+
class All < BaseMatcher
|
|
8
|
+
|
|
9
|
+
# @private
|
|
10
|
+
attr_reader :matcher, :failed_objects
|
|
11
|
+
|
|
12
|
+
def initialize(matcher)
|
|
13
|
+
@matcher = matcher
|
|
14
|
+
@failed_objects = {}
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# @private
|
|
18
|
+
def does_not_match?(actual)
|
|
19
|
+
raise NotImplementedError, '`expect().not_to all( matcher )` is not supported.'
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# @api private
|
|
23
|
+
# @return [String]
|
|
24
|
+
def failure_message
|
|
25
|
+
all_messages = [improve_hash_formatting(super)]
|
|
26
|
+
failed_objects.each do |index, matcher_failure_message|
|
|
27
|
+
all_messages << failure_message_for_item(index, matcher_failure_message)
|
|
28
|
+
end
|
|
29
|
+
all_messages.join("\n\n")
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# @api private
|
|
33
|
+
# @return [String]
|
|
34
|
+
def description
|
|
35
|
+
described_items = surface_descriptions_in(matcher)
|
|
36
|
+
improve_hash_formatting "all#{to_sentence(described_items)}"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def match(_, actual)
|
|
42
|
+
index_failed_objects
|
|
43
|
+
failed_objects.empty?
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def index_failed_objects
|
|
47
|
+
actual.each_with_index do |actual_item, index|
|
|
48
|
+
cloned_matcher = matcher.clone
|
|
49
|
+
matches = cloned_matcher.matches?(actual_item)
|
|
50
|
+
failed_objects[index] = cloned_matcher.failure_message unless matches
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def failure_message_for_item(index, failure_message)
|
|
55
|
+
failure_message = indent_multiline_message( add_new_line_if_needed(failure_message) )
|
|
56
|
+
indent_multiline_message("object at index #{index} failed to match:#{failure_message}")
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def add_new_line_if_needed(message)
|
|
60
|
+
message.start_with?("\n") ? message : "\n#{message}"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def indent_multiline_message(message)
|
|
64
|
+
message = message.sub(/\n+\z/, '')
|
|
65
|
+
message.lines.map do |line|
|
|
66
|
+
line =~ /\S/ ? ' ' + line : line
|
|
67
|
+
end.join
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def initialize_copy(other)
|
|
71
|
+
@matcher = @matcher.clone
|
|
72
|
+
super
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|