rspec-expectations 2.0.0.a1
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.
- data/.document +5 -0
- data/.gitignore +5 -0
- data/License.txt +22 -0
- data/README.markdown +8 -0
- data/Rakefile +43 -0
- data/VERSION +1 -0
- data/VERSION.yml +5 -0
- data/lib/rspec/expectations.rb +36 -0
- data/lib/rspec/expectations/differs/default.rb +62 -0
- data/lib/rspec/expectations/differs/load-diff-lcs.rb +12 -0
- data/lib/rspec/expectations/errors.rb +12 -0
- data/lib/rspec/expectations/extensions.rb +1 -0
- data/lib/rspec/expectations/extensions/kernel.rb +52 -0
- data/lib/rspec/expectations/fail_with.rb +43 -0
- data/lib/rspec/expectations/handler.rb +50 -0
- data/lib/rspec/matchers.rb +195 -0
- data/lib/rspec/matchers/be.rb +210 -0
- data/lib/rspec/matchers/be_close.rb +32 -0
- data/lib/rspec/matchers/be_instance_of.rb +26 -0
- data/lib/rspec/matchers/be_kind_of.rb +26 -0
- data/lib/rspec/matchers/change.rb +151 -0
- data/lib/rspec/matchers/compatibility.rb +14 -0
- data/lib/rspec/matchers/dsl.rb +14 -0
- data/lib/rspec/matchers/eql.rb +42 -0
- data/lib/rspec/matchers/equal.rb +53 -0
- data/lib/rspec/matchers/errors.rb +5 -0
- data/lib/rspec/matchers/exist.rb +16 -0
- data/lib/rspec/matchers/extensions/instance_exec.rb +23 -0
- data/lib/rspec/matchers/generated_descriptions.rb +36 -0
- data/lib/rspec/matchers/has.rb +35 -0
- data/lib/rspec/matchers/have.rb +151 -0
- data/lib/rspec/matchers/include.rb +44 -0
- data/lib/rspec/matchers/match.rb +21 -0
- data/lib/rspec/matchers/match_array.rb +71 -0
- data/lib/rspec/matchers/matcher.rb +86 -0
- data/lib/rspec/matchers/method_missing.rb +9 -0
- data/lib/rspec/matchers/operator_matcher.rb +78 -0
- data/lib/rspec/matchers/pretty.rb +37 -0
- data/lib/rspec/matchers/raise_error.rb +129 -0
- data/lib/rspec/matchers/respond_to.rb +71 -0
- data/lib/rspec/matchers/satisfy.rb +47 -0
- data/lib/rspec/matchers/simple_matcher.rb +133 -0
- data/lib/rspec/matchers/throw_symbol.rb +104 -0
- data/lib/rspec/matchers/wrap_expectation.rb +55 -0
- data/rspec-expectations.gemspec +104 -0
- data/spec/rspec/expectations/differs/default_spec.rb +128 -0
- data/spec/rspec/expectations/extensions/kernel_spec.rb +45 -0
- data/spec/rspec/expectations/fail_with_spec.rb +88 -0
- data/spec/rspec/expectations/handler_spec.rb +206 -0
- data/spec/rspec/expectations/wrap_expectation_spec.rb +30 -0
- data/spec/spec.opts +6 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/suite.rb +1 -0
- data/spec/support/macros.rb +29 -0
- metadata +135 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
Rspec::Matchers.constants.each do |c|
|
2
|
+
if Class === (klass = Rspec::Matchers.const_get(c))
|
3
|
+
if klass.public_instance_methods.any? {|m| ['failure_message_for_should',:failure_message_for_should].include?(m)}
|
4
|
+
klass.class_eval do
|
5
|
+
alias_method :failure_message, :failure_message_for_should
|
6
|
+
end
|
7
|
+
end
|
8
|
+
if klass.public_instance_methods.any? {|m| ['failure_message_for_should_not',:failure_message_for_should_not].include?(m)}
|
9
|
+
klass.class_eval do
|
10
|
+
alias_method :negative_failure_message, :failure_message_for_should_not
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Rspec
|
2
|
+
module Matchers
|
3
|
+
module DSL
|
4
|
+
# See Rspec::Matchers
|
5
|
+
def define(name, &declarations)
|
6
|
+
define_method name do |*expected|
|
7
|
+
Rspec::Matchers::Matcher.new name, *expected, &declarations
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
Rspec::Matchers.extend Rspec::Matchers::DSL
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Rspec
|
2
|
+
module Matchers
|
3
|
+
# :call-seq:
|
4
|
+
# should eql(expected)
|
5
|
+
# should_not eql(expected)
|
6
|
+
#
|
7
|
+
# Passes if actual and expected are of equal value, but not necessarily the same object.
|
8
|
+
#
|
9
|
+
# See http://www.ruby-doc.org/core/classes/Object.html#M001057 for more information about equality in Ruby.
|
10
|
+
#
|
11
|
+
# == Examples
|
12
|
+
#
|
13
|
+
# 5.should eql(5)
|
14
|
+
# 5.should_not eql(3)
|
15
|
+
def eql(expected)
|
16
|
+
Matcher.new :eql, expected do |_expected_|
|
17
|
+
match do |actual|
|
18
|
+
actual.eql?(_expected_)
|
19
|
+
end
|
20
|
+
|
21
|
+
failure_message_for_should do |actual|
|
22
|
+
<<-MESSAGE
|
23
|
+
|
24
|
+
expected #{_expected_.inspect}
|
25
|
+
got #{actual.inspect}
|
26
|
+
|
27
|
+
(compared using eql?)
|
28
|
+
MESSAGE
|
29
|
+
end
|
30
|
+
|
31
|
+
failure_message_for_should_not do |actual|
|
32
|
+
<<-MESSAGE
|
33
|
+
|
34
|
+
expected #{actual.inspect} not to equal #{_expected_.inspect}
|
35
|
+
|
36
|
+
(compared using eql?)
|
37
|
+
MESSAGE
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Rspec
|
2
|
+
module Matchers
|
3
|
+
|
4
|
+
# :call-seq:
|
5
|
+
# should equal(expected)
|
6
|
+
# should_not equal(expected)
|
7
|
+
#
|
8
|
+
# Passes if actual and expected are the same object (object identity).
|
9
|
+
#
|
10
|
+
# See http://www.ruby-doc.org/core/classes/Object.html#M001057 for more information about equality in Ruby.
|
11
|
+
#
|
12
|
+
# == Examples
|
13
|
+
#
|
14
|
+
# 5.should equal(5) #Fixnums are equal
|
15
|
+
# "5".should_not equal("5") #Strings that look the same are not the same object
|
16
|
+
def equal(expected)
|
17
|
+
Matcher.new :equal, expected do |_expected_|
|
18
|
+
match do |actual|
|
19
|
+
actual.equal?(_expected_)
|
20
|
+
end
|
21
|
+
|
22
|
+
def inspect_object(o)
|
23
|
+
"#<#{o.class}:#{o.object_id}> => #{o.inspect}"
|
24
|
+
end
|
25
|
+
|
26
|
+
failure_message_for_should do |actual|
|
27
|
+
<<-MESSAGE
|
28
|
+
|
29
|
+
expected #{inspect_object(_expected_)}
|
30
|
+
got #{inspect_object(actual)}
|
31
|
+
|
32
|
+
Compared using equal?, which compares object identity,
|
33
|
+
but expected and actual are not the same object. Use
|
34
|
+
'actual.should == expected' if you don't care about
|
35
|
+
object identity in this example.
|
36
|
+
|
37
|
+
MESSAGE
|
38
|
+
end
|
39
|
+
|
40
|
+
failure_message_for_should_not do |actual|
|
41
|
+
<<-MESSAGE
|
42
|
+
|
43
|
+
expected not #{inspect_object(actual)}
|
44
|
+
got #{inspect_object(_expected_)}
|
45
|
+
|
46
|
+
Compared using equal?, which compares object identity.
|
47
|
+
|
48
|
+
MESSAGE
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
unless respond_to?(:instance_exec)
|
2
|
+
# based on Bounded Spec InstanceExec (Mauricio Fernandez)
|
3
|
+
# http://eigenclass.org/hiki/bounded+space+instance_exec
|
4
|
+
class Object
|
5
|
+
module InstanceExecHelper; end
|
6
|
+
include InstanceExecHelper
|
7
|
+
def instance_exec(*args, &block)
|
8
|
+
begin
|
9
|
+
orig_critical, Thread.critical = Thread.critical, true
|
10
|
+
n = 0
|
11
|
+
n += 1 while respond_to?(method_name="__instance_exec#{n}")
|
12
|
+
InstanceExecHelper.module_eval{ define_method(method_name, &block) }
|
13
|
+
ensure
|
14
|
+
Thread.critical = orig_critical
|
15
|
+
end
|
16
|
+
begin
|
17
|
+
return send(method_name, *args)
|
18
|
+
ensure
|
19
|
+
InstanceExecHelper.module_eval{ remove_method(method_name) } rescue nil
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Rspec
|
2
|
+
module Matchers
|
3
|
+
class << self
|
4
|
+
attr_accessor :last_matcher, :last_should # :nodoc:
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.clear_generated_description
|
8
|
+
self.last_matcher = nil
|
9
|
+
self.last_should = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.generated_description
|
13
|
+
return nil if last_should.nil?
|
14
|
+
"#{last_should.to_s.gsub('_',' ')} #{last_description}"
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def self.last_description
|
20
|
+
last_matcher.respond_to?(:description) ? last_matcher.description : <<-MESSAGE
|
21
|
+
When you call a matcher in an example without a String, like this:
|
22
|
+
|
23
|
+
specify { object.should matcher }
|
24
|
+
|
25
|
+
or this:
|
26
|
+
|
27
|
+
it { should matcher }
|
28
|
+
|
29
|
+
RSpec expects the matcher to have a #description method. You should either
|
30
|
+
add a String to the example this matcher is being used in, or give it a
|
31
|
+
description method. Then you won't have to suffer this lengthy warning again.
|
32
|
+
MESSAGE
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Rspec
|
2
|
+
module Matchers
|
3
|
+
|
4
|
+
class Has
|
5
|
+
|
6
|
+
def initialize(expected, *args)
|
7
|
+
@expected, @args = expected, args
|
8
|
+
end
|
9
|
+
|
10
|
+
def matches?(actual)
|
11
|
+
actual.__send__(predicate(@expected), *@args)
|
12
|
+
end
|
13
|
+
|
14
|
+
def failure_message_for_should
|
15
|
+
"expected ##{predicate(@expected)}(#{@args[0].inspect}) to return true, got false"
|
16
|
+
end
|
17
|
+
|
18
|
+
def failure_message_for_should_not
|
19
|
+
"expected ##{predicate(@expected)}(#{@args[0].inspect}) to return false, got true"
|
20
|
+
end
|
21
|
+
|
22
|
+
def description
|
23
|
+
"have key #{@args[0].inspect}"
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def predicate(sym)
|
29
|
+
"#{sym.to_s.sub("have_","has_")}?".to_sym
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
module Rspec
|
2
|
+
module Matchers
|
3
|
+
class Have #:nodoc:
|
4
|
+
def initialize(expected, relativity=:exactly)
|
5
|
+
@expected = (expected == :no ? 0 : expected)
|
6
|
+
@relativity = relativity
|
7
|
+
@actual = nil
|
8
|
+
end
|
9
|
+
|
10
|
+
def relativities
|
11
|
+
@relativities ||= {
|
12
|
+
:exactly => "",
|
13
|
+
:at_least => "at least ",
|
14
|
+
:at_most => "at most "
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
def matches?(collection_owner)
|
19
|
+
if collection_owner.respond_to?(@collection_name)
|
20
|
+
collection = collection_owner.__send__(@collection_name, *@args, &@block)
|
21
|
+
elsif (@plural_collection_name && collection_owner.respond_to?(@plural_collection_name))
|
22
|
+
collection = collection_owner.__send__(@plural_collection_name, *@args, &@block)
|
23
|
+
elsif (collection_owner.respond_to?(:length) || collection_owner.respond_to?(:size))
|
24
|
+
collection = collection_owner
|
25
|
+
else
|
26
|
+
collection_owner.__send__(@collection_name, *@args, &@block)
|
27
|
+
end
|
28
|
+
@actual = collection.size if collection.respond_to?(:size)
|
29
|
+
@actual = collection.length if collection.respond_to?(:length)
|
30
|
+
raise not_a_collection if @actual.nil?
|
31
|
+
return @actual >= @expected if @relativity == :at_least
|
32
|
+
return @actual <= @expected if @relativity == :at_most
|
33
|
+
return @actual == @expected
|
34
|
+
end
|
35
|
+
|
36
|
+
def not_a_collection
|
37
|
+
"expected #{@collection_name} to be a collection but it does not respond to #length or #size"
|
38
|
+
end
|
39
|
+
|
40
|
+
def failure_message_for_should
|
41
|
+
"expected #{relative_expectation} #{@collection_name}, got #{@actual}"
|
42
|
+
end
|
43
|
+
|
44
|
+
def failure_message_for_should_not
|
45
|
+
if @relativity == :exactly
|
46
|
+
return "expected target not to have #{@expected} #{@collection_name}, got #{@actual}"
|
47
|
+
elsif @relativity == :at_most
|
48
|
+
return <<-EOF
|
49
|
+
Isn't life confusing enough?
|
50
|
+
Instead of having to figure out the meaning of this:
|
51
|
+
should_not have_at_most(#{@expected}).#{@collection_name}
|
52
|
+
We recommend that you use this instead:
|
53
|
+
should have_at_least(#{@expected + 1}).#{@collection_name}
|
54
|
+
EOF
|
55
|
+
elsif @relativity == :at_least
|
56
|
+
return <<-EOF
|
57
|
+
Isn't life confusing enough?
|
58
|
+
Instead of having to figure out the meaning of this:
|
59
|
+
should_not have_at_least(#{@expected}).#{@collection_name}
|
60
|
+
We recommend that you use this instead:
|
61
|
+
should have_at_most(#{@expected - 1}).#{@collection_name}
|
62
|
+
EOF
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def description
|
67
|
+
"have #{relative_expectation} #{@collection_name}"
|
68
|
+
end
|
69
|
+
|
70
|
+
def respond_to?(sym)
|
71
|
+
@expected.respond_to?(sym) || super
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def method_missing(sym, *args, &block)
|
77
|
+
@collection_name = sym
|
78
|
+
if inflector = (defined?(ActiveSupport::Inflector) ? ActiveSupport::Inflector : (defined?(Inflector) ? Inflector : nil))
|
79
|
+
@plural_collection_name = inflector.pluralize(sym.to_s)
|
80
|
+
end
|
81
|
+
@args = args
|
82
|
+
@block = block
|
83
|
+
self
|
84
|
+
end
|
85
|
+
|
86
|
+
def relative_expectation
|
87
|
+
"#{relativities[@relativity]}#{@expected}"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# :call-seq:
|
92
|
+
# should have(number).named_collection__or__sugar
|
93
|
+
# should_not have(number).named_collection__or__sugar
|
94
|
+
#
|
95
|
+
# Passes if receiver is a collection with the submitted
|
96
|
+
# number of items OR if the receiver OWNS a collection
|
97
|
+
# with the submitted number of items.
|
98
|
+
#
|
99
|
+
# If the receiver OWNS the collection, you must use the name
|
100
|
+
# of the collection. So if a <tt>Team</tt> instance has a
|
101
|
+
# collection named <tt>#players</tt>, you must use that name
|
102
|
+
# to set the expectation.
|
103
|
+
#
|
104
|
+
# If the receiver IS the collection, you can use any name
|
105
|
+
# you like for <tt>named_collection</tt>. We'd recommend using
|
106
|
+
# either "elements", "members", or "items" as these are all
|
107
|
+
# standard ways of describing the things IN a collection.
|
108
|
+
#
|
109
|
+
# This also works for Strings, letting you set an expectation
|
110
|
+
# about its length
|
111
|
+
#
|
112
|
+
# == Examples
|
113
|
+
#
|
114
|
+
# # Passes if team.players.size == 11
|
115
|
+
# team.should have(11).players
|
116
|
+
#
|
117
|
+
# # Passes if [1,2,3].length == 3
|
118
|
+
# [1,2,3].should have(3).items #"items" is pure sugar
|
119
|
+
#
|
120
|
+
# # Passes if "this string".length == 11
|
121
|
+
# "this string".should have(11).characters #"characters" is pure sugar
|
122
|
+
def have(n)
|
123
|
+
Matchers::Have.new(n)
|
124
|
+
end
|
125
|
+
alias :have_exactly :have
|
126
|
+
|
127
|
+
# :call-seq:
|
128
|
+
# should have_at_least(number).items
|
129
|
+
#
|
130
|
+
# Exactly like have() with >=.
|
131
|
+
#
|
132
|
+
# == Warning
|
133
|
+
#
|
134
|
+
# +should_not+ +have_at_least+ is not supported
|
135
|
+
def have_at_least(n)
|
136
|
+
Matchers::Have.new(n, :at_least)
|
137
|
+
end
|
138
|
+
|
139
|
+
# :call-seq:
|
140
|
+
# should have_at_most(number).items
|
141
|
+
#
|
142
|
+
# Exactly like have() with <=.
|
143
|
+
#
|
144
|
+
# == Warning
|
145
|
+
#
|
146
|
+
# +should_not+ +have_at_most+ is not supported
|
147
|
+
def have_at_most(n)
|
148
|
+
Matchers::Have.new(n, :at_most)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Rspec
|
2
|
+
module Matchers
|
3
|
+
# :call-seq:
|
4
|
+
# should include(expected)
|
5
|
+
# should_not include(expected)
|
6
|
+
#
|
7
|
+
# Passes if actual includes expected. This works for
|
8
|
+
# collections and Strings. You can also pass in multiple args
|
9
|
+
# and it will only pass if all args are found in collection.
|
10
|
+
#
|
11
|
+
# == Examples
|
12
|
+
#
|
13
|
+
# [1,2,3].should include(3)
|
14
|
+
# [1,2,3].should include(2,3) #would pass
|
15
|
+
# [1,2,3].should include(2,3,4) #would fail
|
16
|
+
# [1,2,3].should_not include(4)
|
17
|
+
# "spread".should include("read")
|
18
|
+
# "spread".should_not include("red")
|
19
|
+
def include(*expected)
|
20
|
+
Matcher.new :include, *expected do |*_expected_|
|
21
|
+
match do |actual|
|
22
|
+
helper(actual, *_expected_)
|
23
|
+
end
|
24
|
+
|
25
|
+
def helper(actual, *_expected_)
|
26
|
+
_expected_.each do |expected|
|
27
|
+
if actual.is_a?(Hash)
|
28
|
+
if expected.is_a?(Hash)
|
29
|
+
expected.each_pair do |k,v|
|
30
|
+
return false unless actual[k] == v
|
31
|
+
end
|
32
|
+
else
|
33
|
+
return false unless actual.has_key?(expected)
|
34
|
+
end
|
35
|
+
else
|
36
|
+
return false unless actual.include?(expected)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
true
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|