forked from jm/matchy
/
truth_expectations.rb
146 lines (137 loc) · 4.83 KB
/
truth_expectations.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
module Matchy
module Expectations
module TestCaseExtensions
# Simply checks if the receiver matches the expected object.
# TODO: Fill this out to implement much of the RSpec functionality (and then some)
#
# ==== Examples
#
# "hello".should be("hello")
# (13 < 20).should be(true)
#
def be(*obj)
build_matcher(:be, obj) do |receiver, matcher, args|
@receiver, expected = receiver, args[0]
matcher.positive_msg = "Expected #{@receiver.inspect} to be #{expected.inspect}."
matcher.negative_msg = "Expected #{@receiver.inspect} to not be #{expected.inspect}."
expected == @receiver
end
end
# Checks if the given object is within a given object and delta.
#
# ==== Examples
#
# (20.0 - 2.0).should be_close(18.0)
# (13.0 - 4.0).should be_close(9.0, 0.5)
#
def be_close(obj, delta = 0.3)
build_matcher(:be_close, [obj, delta]) do |receiver, matcher, args|
@receiver, expected, delta = receiver, args[0], args[1]
matcher.positive_msg = "Expected #{@receiver.inspect} to be close to #{expected.inspect} (delta: #{delta})."
matcher.negative_msg = "Expected #{@receiver.inspect} to not be close to #{expected.inspect} (delta: #{delta})."
(@receiver - expected).abs < delta
end
end
# Calls +exist?+ on the given object.
#
# ==== Examples
#
# # found_user.exist?
# found_user.should exist
#
def exist
ask_for(:exist, :with_arg => nil)
end
# Calls +eql?+ on the given object (i.e., are the objects the same value?)
#
# ==== Examples
#
# 1.should_not eql(1.0)
# (12 / 6).should eql(6)
#
def eql(*obj)
ask_for(:eql, :with_arg => obj)
end
# Calls +equal?+ on the given object (i.e., do the two objects have the same +object_id+?)
#
# ==== Examples
#
# x = [1,2,3]
# y = [1,2,3]
#
# # Different object_id's...
# x.should_not equal(y)
#
# # The same object_id
# x[0].should equal(y[0])
#
def equal(*obj)
ask_for(:equal, :with_arg => obj)
end
# A last ditch way to implement your testing logic. You probably shouldn't use this unless you
# have to.
#
# ==== Examples
#
# (13 - 4).should satisfy(lambda {|i| i < 20})
# "hello".should_not satisfy(lambda {|s| s =~ /hi/})
#
def satisfy(*obj)
build_matcher(:satisfy, obj) do |receiver, matcher, args|
@receiver, expected = receiver, args[0]
matcher.positive_msg = "Expected #{@receiver.inspect} to satisfy given block."
matcher.negative_msg = "Expected #{@receiver.inspect} to not satisfy given block."
expected.call(@receiver) == true
end
end
# Checks if the given object responds to the given method
#
# ==== Examples
#
# "foo".should respond_to(:length)
# {}.should respond_to(:has_key?)
def respond_to(*meth)
ask_for(:respond_to, :with_arg => meth)
end
# Asks given for success?().
# This is necessary because Rails Integration::Session
# overides method_missing without grace.
#
# ==== Examples
#
# @response.should be_success
def be_success
ask_for(:success, :with_arg => nil)
end
alias_method :old_missing, :method_missing
# ==be_*something(*args)
#
# ===This method_missing acts as a matcher builder.
# If a call to be_xyz() reaches this method_missing (say: obj.should be_xyz),
# a matcher with the name xyz will be built, whose defining property
# is that it returns the value of obj.xyz? for matches?.
# ==== Examples
#
# nil.should be_nil
# 17.should be_kind_of(Fixnum)
# obj.something? #=> true
# obj.should be_something
def method_missing(name, *args, &block)
if (name.to_s =~ /^be_(.+)/)
ask_for($1, :with_arg => args)
else
old_missing(name, *args, &block)
end
end
private
def ask_for(sym, option={})
build_matcher(sym, (option[:with_arg] || [])) do |receiver, matcher, args|
expected, meth = args[0], (sym.to_s + "?" ).to_sym
matcher.positive_msg = "Expected #{receiver.inspect} to return true for #{sym}?, with '#{(expected && expected.inspect) || 'no args'}'."
matcher.negative_msg = "Expected #{receiver.inspect} to not return true for #{sym}?, with '#{(expected && expected.inspect) || 'no args'}'."
expected ? receiver.send(meth, expected) : receiver.send(meth)
end
end
end
end
end