btakita / pain-point
- Source
- Commits
- Network (3)
- Issues (0)
- Downloads (9)
- Wiki (1)
- Graphs
-
Tree:
ca9a65e
commit ca9a65e7110ccaa37175c741e1cea1aaa9776180
tree bae7de1b619c3d0296c3953e1890da9262c1c6bd
parent 7ac763592449ef25d8ac2e1dfe6dafa45bf8f86d
tree bae7de1b619c3d0296c3953e1890da9262c1c6bd
parent 7ac763592449ef25d8ac2e1dfe6dafa45bf8f86d
| 9ae06ec4 » | btakita | 2008-04-01 | 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 | 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 | 70 | stub.invoke([], block) | |
| 71 | elsif expectation = find_almost_matching_expectation(sym, *args) | ||||
| aa946367 » | btakita | 2008-05-06 | 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 | 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 | 95 | visibility_string = "#{visibility(sym)} :#{sym}" | |
| aa946367 » | btakita | 2008-05-06 | 96 | if target_responds_to?(sym) && !target_metaclass.method_defined?(munge(sym)) | |
| 9ae06ec4 » | btakita | 2008-04-01 | 97 | munged_sym = munge(sym) | |
| aa946367 » | btakita | 2008-05-06 | 98 | target_metaclass.instance_eval do | |
| 9ae06ec4 » | btakita | 2008-04-01 | 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 | 104 | target_metaclass.class_eval(<<-EOF, __FILE__, __LINE__) | |
| 9ae06ec4 » | btakita | 2008-04-01 | 105 | def #{sym}(*args, &block) | |
| 106 | __mock_proxy.message_received :#{sym}, *args, &block | ||||
| 107 | end | ||||
| ca9a65e7 » | btakita | 2008-05-25 | 108 | #{visibility_string} | |
| 9ae06ec4 » | btakita | 2008-04-01 | 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 | 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 | 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 | 146 | def target_metaclass | |
| 147 | class << @target; self; end | ||||
| 9ae06ec4 » | btakita | 2008-04-01 | 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 | 159 | target_metaclass.instance_eval do | |
| 9ae06ec4 » | btakita | 2008-04-01 | 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 | ||||
