rspec-expectations 2.99.0.beta1 → 2.99.0.beta2
Sign up to get free protection for your applications and to get access to all the features.
- data/Changelog.md +35 -1
- data/features/step_definitions/additional_cli_steps.rb +10 -0
- data/features/test_frameworks/test_unit.feature +40 -0
- data/lib/rspec/expectations/caller_filter.rb +50 -45
- data/lib/rspec/expectations/deprecation.rb +8 -0
- data/lib/rspec/expectations/handler.rb +5 -1
- data/lib/rspec/expectations/version.rb +1 -1
- data/lib/rspec/matchers.rb +10 -1
- data/lib/rspec/matchers/be_close.rb +4 -1
- data/lib/rspec/matchers/built_in/base_matcher.rb +8 -9
- data/lib/rspec/matchers/built_in/be_within.rb +2 -1
- data/lib/rspec/matchers/built_in/change.rb +37 -1
- data/lib/rspec/matchers/built_in/has.rb +2 -1
- data/lib/rspec/matchers/built_in/have.rb +6 -2
- data/lib/rspec/matchers/built_in/raise_error.rb +2 -1
- data/lib/rspec/matchers/built_in/respond_to.rb +2 -1
- data/lib/rspec/matchers/built_in/satisfy.rb +2 -1
- data/lib/rspec/matchers/built_in/throw_symbol.rb +2 -1
- data/lib/rspec/matchers/built_in/yield.rb +4 -2
- data/lib/rspec/matchers/match_aliases.rb +22 -0
- data/lib/rspec/matchers/matcher.rb +18 -1
- data/lib/rspec/matchers/operator_matcher.rb +70 -70
- data/lib/rspec/matchers/test_unit_integration.rb +22 -5
- data/spec/rspec/expectations_spec.rb +1 -1
- data/spec/rspec/matchers/base_matcher_spec.rb +27 -12
- data/spec/rspec/matchers/be_close_spec.rb +4 -1
- data/spec/rspec/matchers/be_spec.rb +2 -2
- data/spec/rspec/matchers/change_spec.rb +76 -1
- data/spec/rspec/matchers/equal_spec.rb +26 -0
- data/spec/rspec/matchers/have_spec.rb +26 -18
- data/spec/rspec/matchers/matcher_spec.rb +13 -0
- data/spec/rspec/matchers/operator_matcher_spec.rb +25 -6
- data/spec/spec_helper.rb +0 -21
- data/spec/support/helper_methods.rb +28 -3
- data/spec/support/shared_examples.rb +42 -0
- metadata +20 -8
- checksums.yaml +0 -15
- data/spec/rspec/matchers/matchers_spec.rb +0 -37
@@ -2,6 +2,8 @@ module RSpec
|
|
2
2
|
module Matchers
|
3
3
|
module BuiltIn
|
4
4
|
class RaiseError
|
5
|
+
include MatchAliases
|
6
|
+
|
5
7
|
def initialize(expected_error_or_message=Exception, expected_message=nil, &block)
|
6
8
|
@block = block
|
7
9
|
@actual_error = nil
|
@@ -51,7 +53,6 @@ module RSpec
|
|
51
53
|
ensure
|
52
54
|
return (@raised_expected_error & @with_expected_message) ? (@eval_block ? @eval_block_passed : true) : false
|
53
55
|
end
|
54
|
-
alias == matches?
|
55
56
|
|
56
57
|
def does_not_match?(given_proc)
|
57
58
|
!matches?(given_proc, :negative_expectation)
|
@@ -2,6 +2,8 @@ module RSpec
|
|
2
2
|
module Matchers
|
3
3
|
module BuiltIn
|
4
4
|
class RespondTo
|
5
|
+
include MatchAliases
|
6
|
+
|
5
7
|
def initialize(*names)
|
6
8
|
@names = names
|
7
9
|
@expected_arity = nil
|
@@ -10,7 +12,6 @@ module RSpec
|
|
10
12
|
def matches?(actual)
|
11
13
|
find_failing_method_names(actual, :reject).empty?
|
12
14
|
end
|
13
|
-
alias == matches?
|
14
15
|
|
15
16
|
def does_not_match?(actual)
|
16
17
|
find_failing_method_names(actual, :select).empty?
|
@@ -2,6 +2,8 @@ module RSpec
|
|
2
2
|
module Matchers
|
3
3
|
module BuiltIn
|
4
4
|
class Satisfy
|
5
|
+
include MatchAliases
|
6
|
+
|
5
7
|
def initialize(&block)
|
6
8
|
@block = block
|
7
9
|
end
|
@@ -11,7 +13,6 @@ module RSpec
|
|
11
13
|
@actual = actual
|
12
14
|
@block.call(actual)
|
13
15
|
end
|
14
|
-
alias == matches?
|
15
16
|
|
16
17
|
def failure_message_for_should
|
17
18
|
"expected #{@actual} to satisfy block"
|
@@ -2,6 +2,8 @@ module RSpec
|
|
2
2
|
module Matchers
|
3
3
|
module BuiltIn
|
4
4
|
class ThrowSymbol
|
5
|
+
include MatchAliases
|
6
|
+
|
5
7
|
def initialize(expected_symbol = nil, expected_arg=nil)
|
6
8
|
@expected_symbol = expected_symbol
|
7
9
|
@expected_arg = expected_arg
|
@@ -51,7 +53,6 @@ module RSpec
|
|
51
53
|
end
|
52
54
|
end
|
53
55
|
end
|
54
|
-
alias == matches?
|
55
56
|
|
56
57
|
def failure_message_for_should
|
57
58
|
"expected #{expected} to be thrown, got #{caught}"
|
@@ -181,6 +181,8 @@ module RSpec
|
|
181
181
|
end
|
182
182
|
|
183
183
|
class YieldWithArgs
|
184
|
+
include MatchAliases
|
185
|
+
|
184
186
|
def initialize(*args)
|
185
187
|
@expected = args
|
186
188
|
end
|
@@ -190,7 +192,6 @@ module RSpec
|
|
190
192
|
@actual = @probe.single_yield_args
|
191
193
|
@probe.yielded_once?(:yield_with_args) && args_match?
|
192
194
|
end
|
193
|
-
alias == matches?
|
194
195
|
|
195
196
|
def failure_message_for_should
|
196
197
|
"expected given block to yield with arguments, but #{positive_failure_reason}"
|
@@ -251,6 +252,8 @@ module RSpec
|
|
251
252
|
end
|
252
253
|
|
253
254
|
class YieldSuccessiveArgs
|
255
|
+
include MatchAliases
|
256
|
+
|
254
257
|
def initialize(*args)
|
255
258
|
@expected = args
|
256
259
|
end
|
@@ -260,7 +263,6 @@ module RSpec
|
|
260
263
|
@actual = @probe.successive_yield_args
|
261
264
|
args_match?
|
262
265
|
end
|
263
|
-
alias == matches?
|
264
266
|
|
265
267
|
def failure_message_for_should
|
266
268
|
"expected given block to yield successively with arguments, but yielded with unexpected arguments" +
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Matchers
|
3
|
+
module MatchAliases
|
4
|
+
def ==(other)
|
5
|
+
return true if equal?(other)
|
6
|
+
|
7
|
+
matched = matches?(other)
|
8
|
+
|
9
|
+
if matched
|
10
|
+
RSpec.deprecate("Using `matcher == value` as an alias for `#matches?`", :replacement => "`matcher === value`")
|
11
|
+
end
|
12
|
+
|
13
|
+
matched
|
14
|
+
end
|
15
|
+
|
16
|
+
def ===(other)
|
17
|
+
matches?(other)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
@@ -11,7 +11,7 @@ module RSpec
|
|
11
11
|
include RSpec::Matchers::Pretty
|
12
12
|
include RSpec::Matchers
|
13
13
|
|
14
|
-
attr_reader :
|
14
|
+
attr_reader :actual, :rescued_exception
|
15
15
|
attr_accessor :matcher_execution_context
|
16
16
|
|
17
17
|
# @api private
|
@@ -34,6 +34,23 @@ module RSpec
|
|
34
34
|
:@expected_exception
|
35
35
|
].to_set
|
36
36
|
|
37
|
+
def expected
|
38
|
+
if @expected.size == 1
|
39
|
+
RSpec.warn_deprecation(
|
40
|
+
"Custom matchers in 3.x will set expected to be a single value "+
|
41
|
+
"(when provided as such) rather than an array. This may change "+
|
42
|
+
"the behaviour of your matcher.\n"+
|
43
|
+
"To continue to access this as an array use `expected_array`\n"+
|
44
|
+
"Called from: #{ RSpec::CallerFilter.first_non_rspec_line }\n\n"
|
45
|
+
)
|
46
|
+
end
|
47
|
+
@expected
|
48
|
+
end
|
49
|
+
|
50
|
+
def expected_as_array
|
51
|
+
@expected
|
52
|
+
end
|
53
|
+
|
37
54
|
# @api private
|
38
55
|
def for_expected(*expected)
|
39
56
|
@expected = expected
|
@@ -1,95 +1,95 @@
|
|
1
1
|
module RSpec
|
2
2
|
module Matchers
|
3
|
-
|
4
|
-
class
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
module BuiltIn
|
4
|
+
class OperatorMatcher
|
5
|
+
class << self
|
6
|
+
def registry
|
7
|
+
@registry ||= {}
|
8
|
+
end
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
def register(klass, operator, matcher)
|
11
|
+
registry[klass] ||= {}
|
12
|
+
registry[klass][operator] = matcher
|
13
|
+
end
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
15
|
+
def unregister(klass, operator)
|
16
|
+
registry[klass] && registry[klass].delete(operator)
|
17
|
+
end
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
19
|
+
def get(klass, operator)
|
20
|
+
klass.ancestors.each { |ancestor|
|
21
|
+
matcher = registry[ancestor] && registry[ancestor][operator]
|
22
|
+
return matcher if matcher
|
23
|
+
}
|
23
24
|
|
24
|
-
|
25
|
+
nil
|
26
|
+
end
|
25
27
|
end
|
26
|
-
end
|
27
28
|
|
28
|
-
|
29
|
-
|
30
|
-
|
29
|
+
def initialize(actual)
|
30
|
+
@actual = actual
|
31
|
+
end
|
31
32
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
33
|
+
def self.use_custom_matcher_or_delegate(operator)
|
34
|
+
define_method(operator) do |expected|
|
35
|
+
if uses_generic_implementation_of?(operator) && matcher = OperatorMatcher.get(@actual.class, operator)
|
36
|
+
@actual.__send__(::RSpec::Matchers.last_should, matcher.new(expected))
|
37
|
+
else
|
38
|
+
eval_match(@actual, operator, expected)
|
39
|
+
end
|
38
40
|
end
|
39
|
-
end
|
40
41
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
42
|
+
negative_operator = operator.sub(/^=/, '!')
|
43
|
+
if negative_operator != operator && respond_to?(negative_operator)
|
44
|
+
define_method(negative_operator) do |expected|
|
45
|
+
opposite_should = ::RSpec::Matchers.last_should == :should ? :should_not : :should
|
46
|
+
raise "RSpec does not support `#{::RSpec::Matchers.last_should} #{negative_operator} expected`. " +
|
47
|
+
"Use `#{opposite_should} #{operator} expected` instead."
|
48
|
+
end
|
47
49
|
end
|
48
50
|
end
|
49
|
-
end
|
50
51
|
|
51
|
-
|
52
|
-
|
53
|
-
|
52
|
+
['==', '===', '=~', '>', '>=', '<', '<='].each do |operator|
|
53
|
+
use_custom_matcher_or_delegate operator
|
54
|
+
end
|
54
55
|
|
55
|
-
|
56
|
-
|
57
|
-
|
56
|
+
def fail_with_message(message)
|
57
|
+
RSpec::Expectations.fail_with(message, @expected, @actual)
|
58
|
+
end
|
58
59
|
|
59
|
-
|
60
|
-
|
61
|
-
|
60
|
+
def description
|
61
|
+
"#{@operator} #{@expected.inspect}"
|
62
|
+
end
|
62
63
|
|
63
|
-
|
64
|
+
private
|
64
65
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
66
|
+
if Method.method_defined?(:owner) # 1.8.6 lacks Method#owner :-(
|
67
|
+
def uses_generic_implementation_of?(op)
|
68
|
+
Expectations.method_handle_for(@actual, op).owner == ::Kernel
|
69
|
+
rescue NameError
|
70
|
+
false
|
71
|
+
end
|
72
|
+
else
|
73
|
+
def uses_generic_implementation_of?(op)
|
74
|
+
# This is a bit of a hack, but:
|
75
|
+
#
|
76
|
+
# {}.method(:=~).to_s # => "#<Method: Hash(Kernel)#=~>"
|
77
|
+
#
|
78
|
+
# In the absence of Method#owner, this is the best we
|
79
|
+
# can do to see if the method comes from Kernel.
|
80
|
+
Expectations.method_handle_for(@actual, op).to_s.include?('(Kernel)')
|
81
|
+
rescue NameError
|
82
|
+
false
|
83
|
+
end
|
82
84
|
end
|
83
|
-
end
|
84
85
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
86
|
+
def eval_match(actual, operator, expected)
|
87
|
+
::RSpec::Matchers.last_matcher = self
|
88
|
+
@operator, @expected = operator, expected
|
89
|
+
__delegate_operator(actual, operator, expected)
|
90
|
+
end
|
89
91
|
end
|
90
|
-
end
|
91
92
|
|
92
|
-
module BuiltIn
|
93
93
|
class PositiveOperatorMatcher < OperatorMatcher
|
94
94
|
def __delegate_operator(actual, operator, expected)
|
95
95
|
if actual.__send__(operator, expected)
|
@@ -3,9 +3,26 @@
|
|
3
3
|
# and a 1.9 bug can lead to infinite recursion from the `super` call in our
|
4
4
|
# method_missing hook. See this gist for more info:
|
5
5
|
# https://gist.github.com/845896
|
6
|
-
if defined?(MiniTest::
|
7
|
-
MiniTest::
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
if defined?(MiniTest::TestCase)
|
7
|
+
MiniTest::TestCase.add_setup_hook do |instance|
|
8
|
+
unless ::RSpec::Matchers === instance
|
9
|
+
::RSpec.deprecate("rspec-expectations' built-in integration with minitest < 5.x",
|
10
|
+
:replacement => "`include RSpec::Matchers` from within `Minitest::TestCase`")
|
11
|
+
|
12
|
+
MiniTest::TestCase.send(:include, RSpec::Matchers)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
elsif defined?(Test::Unit::TestCase)
|
16
|
+
Test::Unit::TestCase.class_eval do
|
17
|
+
def setup
|
18
|
+
unless ::RSpec::Matchers === self
|
19
|
+
::RSpec.deprecate("rspec-expectations' built-in integration with Test::Unit",
|
20
|
+
:replacement => "`include RSpec::Matchers` from within `Test::Unit::TestCase`")
|
21
|
+
|
22
|
+
Test::Unit::TestCase.send(:include, RSpec::Matchers)
|
23
|
+
end
|
24
|
+
|
25
|
+
super if defined?(super)
|
26
|
+
end
|
27
|
+
end
|
11
28
|
end
|
@@ -50,7 +50,7 @@ module RSpec
|
|
50
50
|
expect(Expectations.method_handle_for(object, :foo).call).to eq :bar
|
51
51
|
end
|
52
52
|
|
53
|
-
it 'fetches method definitions for basic objects', :if => RUBY_VERSION.to_i >= 2 do
|
53
|
+
it 'fetches method definitions for basic objects', :if => (RUBY_VERSION.to_i >= 2 && RUBY_ENGINE != 'rbx') do
|
54
54
|
object = BasicClass.new
|
55
55
|
expect(Expectations.method_handle_for(object, :foo).call).to eq :bar
|
56
56
|
end
|
@@ -39,24 +39,39 @@ module RSpec::Matchers::BuiltIn
|
|
39
39
|
|
40
40
|
end
|
41
41
|
|
42
|
-
describe "
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
42
|
+
describe "#failure_message_for_should" do
|
43
|
+
context "when the parameter to .new is omitted" do
|
44
|
+
it "describes what was expected" do
|
45
|
+
matcher_class = Class.new(BaseMatcher) do
|
46
|
+
def name=(name)
|
47
|
+
@name = name
|
48
|
+
end
|
48
49
|
|
49
|
-
|
50
|
-
|
50
|
+
def match(expected, actual)
|
51
|
+
false
|
52
|
+
end
|
51
53
|
end
|
54
|
+
|
55
|
+
matcher = matcher_class.new
|
56
|
+
matcher.name = "be something"
|
57
|
+
matcher.matches?("foo")
|
58
|
+
expect(matcher.failure_message_for_should).to eq('expected "foo" to be something')
|
52
59
|
end
|
60
|
+
end
|
61
|
+
end
|
53
62
|
|
54
|
-
|
55
|
-
|
63
|
+
it_behaves_like "an RSpec matcher", :valid_value => 3, :invalid_value => 4 do
|
64
|
+
matcher_class = Class.new(BaseMatcher) do
|
65
|
+
def initialize(expected)
|
66
|
+
@expected = expected
|
67
|
+
end
|
56
68
|
|
57
|
-
|
58
|
-
|
69
|
+
def matches?(actual)
|
70
|
+
(@actual = actual) == @expected
|
71
|
+
end
|
59
72
|
end
|
73
|
+
|
74
|
+
let(:matcher) { matcher_class.new(3) }
|
60
75
|
end
|
61
76
|
end
|
62
77
|
end
|
@@ -8,7 +8,10 @@ module RSpec
|
|
8
8
|
end
|
9
9
|
|
10
10
|
it "is deprecated" do
|
11
|
-
|
11
|
+
expect_deprecation_with_type('be_close(3.0, 0.5)',
|
12
|
+
'be_within(0.5).of(3.0)',
|
13
|
+
'the be_close matcher'
|
14
|
+
)
|
12
15
|
be_close(3.0, 0.5)
|
13
16
|
end
|
14
17
|
|
@@ -264,7 +264,7 @@ end
|
|
264
264
|
|
265
265
|
describe "expect(...).to be_false" do
|
266
266
|
it "is deprecated" do
|
267
|
-
|
267
|
+
expect_deprecation_with_call_site(__FILE__, __LINE__ + 1, /be_false/)
|
268
268
|
expect(false).to be_false
|
269
269
|
end
|
270
270
|
|
@@ -288,7 +288,7 @@ end
|
|
288
288
|
|
289
289
|
describe "expect(...).to be_true" do
|
290
290
|
it "is deprecated" do
|
291
|
-
|
291
|
+
expect_deprecation_with_call_site(__FILE__, __LINE__ + 1, /be_true/)
|
292
292
|
expect(true).to be_true
|
293
293
|
end
|
294
294
|
|