Updated to latest rspec
[gitorious:georgyos-clone.git] / vendor / plugins / rspec / lib / spec / mocks / argument_expectation.rb
1 module Spec
2   module Mocks
3   
4     class MatcherConstraint
5       def initialize(matcher)
6         @matcher = matcher
7       end
8       
9       def matches?(value)
10         @matcher.matches?(value)
11       end
12     end
13       
14     class LiteralArgConstraint
15       def initialize(literal)
16         @literal_value = literal
17       end
18       
19       def matches?(value)
20         @literal_value == value
21       end
22     end
23     
24     class RegexpArgConstraint
25       def initialize(regexp)
26         @regexp = regexp
27       end
28       
29       def matches?(value)
30         return value =~ @regexp unless value.is_a?(Regexp)
31         value == @regexp
32       end
33     end
34     
35     class AnyArgConstraint
36       def initialize(ignore)
37       end
38       
39       def ==(other)
40         true
41       end
42       
43       # TODO - need this?
44       def matches?(value)
45         true
46       end
47     end
48     
49     class AnyArgsConstraint
50       def description
51         "any args"
52       end
53     end
54     
55     class NoArgsConstraint
56       def description
57         "no args"
58       end
59       
60       def ==(args)
61         args == []
62       end
63     end
64     
65     class NumericArgConstraint
66       def initialize(ignore)
67       end
68       
69       def matches?(value)
70         value.is_a?(Numeric)
71       end
72     end
73     
74     class BooleanArgConstraint
75       def initialize(ignore)
76       end
77       
78       def ==(value)
79         matches?(value)
80       end
81       
82       def matches?(value)
83         return true if value.is_a?(TrueClass)
84         return true if value.is_a?(FalseClass)
85         false
86       end
87     end
88     
89     class StringArgConstraint
90       def initialize(ignore)
91       end
92       
93       def matches?(value)
94         value.is_a?(String)
95       end
96     end
97     
98     class DuckTypeArgConstraint
99       def initialize(*methods_to_respond_to)
100         @methods_to_respond_to = methods_to_respond_to
101       end
102   
103       def matches?(value)
104         @methods_to_respond_to.all? { |sym| value.respond_to?(sym) }
105       end
106       
107       def description
108         "duck_type"
109       end
110     end
111     
112     class HashIncludingConstraint
113       def initialize(expected)
114         @expected = expected
115       end
116       
117       def ==(actual)
118         @expected.each do | key, value |
119           # check key for case that value evaluates to nil
120           return false unless actual.has_key?(key) && actual[key] == value
121         end
122         true
123       rescue NoMethodError => ex
124         return false
125       end
126       
127       def matches?(value)
128         self == value
129       end
130       
131       def description
132         "hash_including(#{@expected.inspect.sub(/^\{/,"").sub(/\}$/,"")})"
133       end
134       
135     end
136     
137
138     class ArgumentExpectation
139       attr_reader :args
140       @@constraint_classes = Hash.new { |hash, key| LiteralArgConstraint}
141       @@constraint_classes[:anything] = AnyArgConstraint
142       @@constraint_classes[:numeric] = NumericArgConstraint
143       @@constraint_classes[:boolean] = BooleanArgConstraint
144       @@constraint_classes[:string] = StringArgConstraint
145       
146       def initialize(args)
147         @args = args
148         if [:any_args] == args
149           @expected_params = nil
150           warn_deprecated(:any_args.inspect, "any_args()")
151         elsif args.length == 1 && args[0].is_a?(AnyArgsConstraint) then @expected_params = nil
152         elsif [:no_args] == args
153           @expected_params = []
154           warn_deprecated(:no_args.inspect, "no_args()")
155         elsif args.length == 1 && args[0].is_a?(NoArgsConstraint) then @expected_params = []
156         else @expected_params = process_arg_constraints(args)
157         end
158       end
159       
160       def process_arg_constraints(constraints)
161         constraints.collect do |constraint| 
162           convert_constraint(constraint)
163         end
164       end
165       
166       def warn_deprecated(deprecated_method, instead)
167         Kernel.warn "The #{deprecated_method} constraint is deprecated. Use #{instead} instead."
168       end
169       
170       def convert_constraint(constraint)
171         if [:anything, :numeric, :boolean, :string].include?(constraint)
172           case constraint
173           when :anything
174             instead = "anything()"
175           when :boolean
176             instead = "boolean()"
177           when :numeric
178             instead = "an_instance_of(Numeric)"
179           when :string
180             instead = "an_instance_of(String)"
181           end
182           warn_deprecated(constraint.inspect, instead)
183           return @@constraint_classes[constraint].new(constraint)
184         end
185         return MatcherConstraint.new(constraint) if is_matcher?(constraint)
186         return RegexpArgConstraint.new(constraint) if constraint.is_a?(Regexp)
187         return LiteralArgConstraint.new(constraint)
188       end
189       
190       def is_matcher?(obj)
191         return obj.respond_to?(:matches?) && obj.respond_to?(:description)
192       end
193       
194       def check_args(args)
195         return true if @expected_params.nil?
196         return true if @expected_params == args
197         return constraints_match?(args)
198       end
199       
200       def constraints_match?(args)
201         return false if args.length != @expected_params.length
202         @expected_params.each_index { |i| return false unless @expected_params[i].matches?(args[i]) }
203         return true
204       end
205   
206     end
207     
208   end
209 end