btakita / pain-point

A Rails app that uses voting to identify pain points.

This URL has Read+Write access

commit  ca9a65e7110ccaa37175c741e1cea1aaa9776180
tree    bae7de1b619c3d0296c3953e1890da9262c1c6bd
parent  7ac763592449ef25d8ac2e1dfe6dafa45bf8f86d
pain-point / vendor / plugins / rspec / lib / spec / mocks / proxy.rb
9ae06ec4 » btakita 2008-04-01 Adding rspec and rspec on r... 1 module Spec
2 module Mocks
3 class Proxy
4 DEFAULT_OPTIONS = {
5 :null_object => false,
6 }
7
8 def initialize(target, name, options={})
9 @target = target
10 @name = name
11 @error_generator = ErrorGenerator.new target, name
12 @expectation_ordering = OrderGroup.new @error_generator
13 @expectations = []
14 @messages_received = []
15 @stubs = []
16 @proxied_methods = []
17 @options = options ? DEFAULT_OPTIONS.dup.merge(options) : DEFAULT_OPTIONS
18 end
19
20 def null_object?
21 @options[:null_object]
22 end
23
24 def add_message_expectation(expected_from, sym, opts={}, &block)
25 __add sym
26 @expectations << MessageExpectation.new(@error_generator, @expectation_ordering, expected_from, sym, block_given? ? block : nil, 1, opts)
27 @expectations.last
28 end
29
30 def add_negative_message_expectation(expected_from, sym, &block)
31 __add sym
32 @expectations << NegativeMessageExpectation.new(@error_generator, @expectation_ordering, expected_from, sym, block_given? ? block : nil)
33 @expectations.last
34 end
35
36 def add_stub(expected_from, sym, opts={})
37 __add sym
38 @stubs.unshift MessageExpectation.new(@error_generator, @expectation_ordering, expected_from, sym, nil, :any, opts)
39 @stubs.first
40 end
41
42 def verify #:nodoc:
43 verify_expectations
44 ensure
45 reset
46 end
47
48 def reset
49 clear_expectations
50 clear_stubs
51 reset_proxied_methods
52 clear_proxied_methods
53 end
54
55 def received_message?(sym, *args, &block)
56 @messages_received.any? {|array| array == [sym, args, block]}
57 end
58
59 def has_negative_expectation?(sym)
60 @expectations.detect {|expectation| expectation.negative_expectation_for?(sym)}
61 end
62
63 def message_received(sym, *args, &block)
64 if expectation = find_matching_expectation(sym, *args)
65 expectation.invoke(args, block)
aa946367 » btakita 2008-05-06 Using Piston to manage rspe... 66 elsif (stub = find_matching_method_stub(sym, *args))
67 if expectation = find_almost_matching_expectation(sym, *args)
68 expectation.advise(args, block) unless expectation.expected_messages_received?
69 end
9ae06ec4 » btakita 2008-04-01 Adding rspec and rspec on r... 70 stub.invoke([], block)
71 elsif expectation = find_almost_matching_expectation(sym, *args)
aa946367 » btakita 2008-05-06 Using Piston to manage rspe... 72 expectation.advise(args, block) if null_object? unless expectation.expected_messages_received?
73 raise_unexpected_message_args_error(expectation, *args) unless (has_negative_expectation?(sym) or null_object?)
9ae06ec4 » btakita 2008-04-01 Adding rspec and rspec on r... 74 else
75 @target.send :method_missing, sym, *args, &block
76 end
77 end
78
79 def raise_unexpected_message_args_error(expectation, *args)
80 @error_generator.raise_unexpected_message_args_error expectation, *args
81 end
82
83 def raise_unexpected_message_error(sym, *args)
84 @error_generator.raise_unexpected_message_error sym, *args
85 end
86
87 private
88
89 def __add(sym)
90 $rspec_mocks.add(@target) unless $rspec_mocks.nil?
91 define_expected_method(sym)
92 end
93
94 def define_expected_method(sym)
ca9a65e7 » btakita 2008-05-25 Updated rspec, rspec-rails,... 95 visibility_string = "#{visibility(sym)} :#{sym}"
aa946367 » btakita 2008-05-06 Using Piston to manage rspe... 96 if target_responds_to?(sym) && !target_metaclass.method_defined?(munge(sym))
9ae06ec4 » btakita 2008-04-01 Adding rspec and rspec on r... 97 munged_sym = munge(sym)
aa946367 » btakita 2008-05-06 Using Piston to manage rspe... 98 target_metaclass.instance_eval do
9ae06ec4 » btakita 2008-04-01 Adding rspec and rspec on r... 99 alias_method munged_sym, sym if method_defined?(sym.to_s)
100 end
101 @proxied_methods << sym
102 end
103
aa946367 » btakita 2008-05-06 Using Piston to manage rspe... 104 target_metaclass.class_eval(<<-EOF, __FILE__, __LINE__)
9ae06ec4 » btakita 2008-04-01 Adding rspec and rspec on r... 105 def #{sym}(*args, &block)
106 __mock_proxy.message_received :#{sym}, *args, &block
107 end
ca9a65e7 » btakita 2008-05-25 Updated rspec, rspec-rails,... 108 #{visibility_string}
9ae06ec4 » btakita 2008-04-01 Adding rspec and rspec on r... 109 EOF
110 end
111
112 def target_responds_to?(sym)
113 return @target.send(munge(:respond_to?),sym) if @already_proxied_respond_to
114 return @already_proxied_respond_to = true if sym == :respond_to?
115 return @target.respond_to?(sym)
116 end
117
ca9a65e7 » btakita 2008-05-25 Updated rspec, rspec-rails,... 118 def visibility(sym)
119 if Mock === @target
120 'public'
121 elsif target_metaclass.private_method_defined?(sym)
122 'private'
123 elsif target_metaclass.protected_method_defined?(sym)
124 'protected'
125 else
126 'public'
127 end
128 end
129
9ae06ec4 » btakita 2008-04-01 Adding rspec and rspec on r... 130 def munge(sym)
131 "proxied_by_rspec__#{sym.to_s}".to_sym
132 end
133
134 def clear_expectations
135 @expectations.clear
136 end
137
138 def clear_stubs
139 @stubs.clear
140 end
141
142 def clear_proxied_methods
143 @proxied_methods.clear
144 end
145
aa946367 » btakita 2008-05-06 Using Piston to manage rspe... 146 def target_metaclass
147 class << @target; self; end
9ae06ec4 » btakita 2008-04-01 Adding rspec and rspec on r... 148 end
149
150 def verify_expectations
151 @expectations.each do |expectation|
152 expectation.verify_messages_received
153 end
154 end
155
156 def reset_proxied_methods
157 @proxied_methods.each do |sym|
158 munged_sym = munge(sym)
aa946367 » btakita 2008-05-06 Using Piston to manage rspe... 159 target_metaclass.instance_eval do
9ae06ec4 » btakita 2008-04-01 Adding rspec and rspec on r... 160 if method_defined?(munged_sym.to_s)
161 alias_method sym, munged_sym
162 undef_method munged_sym
163 else
164 undef_method sym
165 end
166 end
167 end
168 end
169
170 def find_matching_expectation(sym, *args)
171 @expectations.find {|expectation| expectation.matches(sym, args)}
172 end
173
174 def find_almost_matching_expectation(sym, *args)
175 @expectations.find {|expectation| expectation.matches_name_but_not_args(sym, args)}
176 end
177
178 def find_matching_method_stub(sym, *args)
179 @stubs.find {|stub| stub.matches(sym, args)}
180 end
181
182 end
183 end
184 end