Class: Muack::Mock

Inherits:
BasicObject
Defined in:
lib/muack/mock.rb

Direct Known Subclasses

Spy, Stub

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(object) ⇒ Mock

Returns a new instance of Mock.



10
11
12
13
14
15
16
# File 'lib/muack/mock.rb', line 10

def initialize object
  @object = object
  @__mock_injected = {}
  [:__mock_defis=, :__mock_disps=].each do |m|
    __send__(m, ::Hash.new{ |h, k| h[k] = [] })
  end
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(msg, *args, &block) ⇒ Object

Public API: Define mocked method



24
25
26
27
28
29
30
31
32
33
# File 'lib/muack/mock.rb', line 24

def method_missing msg, *args, &block
  defi = Definition.new(msg, args, block)
  if injected = __mock_injected[defi.msg]
    defi.original_method = injected.original_method
  else
    __mock_inject_method(defi)
  end
  __mock_defis_push(defi)
  Modifier.new(self, defi)
end

Instance Attribute Details

#objectObject (readonly)

Returns the value of attribute object.



9
10
11
# File 'lib/muack/mock.rb', line 9

def object
  @object
end

Instance Method Details

#__mock_classObject

used for Muack::Modifier#times to determine if it’s a mock or not



46
47
48
# File 'lib/muack/mock.rb', line 46

def __mock_class
  (class << self; self; end).superclass
end

#__mock_defis_pop(defi) ⇒ Object

used for Muack::Modifier#times



41
42
43
# File 'lib/muack/mock.rb', line 41

def __mock_defis_pop defi
  __mock_defis[defi.msg].pop
end

#__mock_defis_push(defi) ⇒ Object

used for Muack::Modifier#times



36
37
38
# File 'lib/muack/mock.rb', line 36

def __mock_defis_push defi
  __mock_defis[defi.msg] << defi
end

#__mock_dispatch(msg, actual_args) ⇒ Object

used for mocked object to dispatch mocked method



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/muack/mock.rb', line 51

def __mock_dispatch msg, actual_args
  if defi = __mock_defis[msg].shift
    __mock_disps_push(defi)
    if __mock_check_args(defi.args, actual_args)
      defi
    else
      Mock.__send__(:raise, # Wrong argument
        Unexpected.new(object, [defi], msg, actual_args))
    end
  else
    defis = __mock_disps[msg]
    if expected = defis.find{ |d| __mock_check_args(d.args, actual_args) }
      Mock.__send__(:raise, # Too many times
        Expected.new(object, expected, defis.size, defis.size+1))
    else
      Mock.__send__(:raise, # Wrong argument
        Unexpected.new(object, defis, msg, actual_args))
    end
  end
end

#__mock_dispatch_call(disp, actual_args, actual_block) ⇒ Object

used for mocked object to dispatch mocked method



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/muack/mock.rb', line 73

def __mock_dispatch_call disp, actual_args, actual_block
  if disp.proxy
    value = yield # need the original context for proxy or AnyInstanceOf
    if disp.block
      disp.block.call(value)
    else
      value
    end
  elsif block = disp.block
    arity = block.arity
    if arity < 0
      block.call(*actual_args             , &actual_block)
    else
      block.call(*actual_args.first(arity), &actual_block)
    end
  end
end

#__mock_resetObject

used for Muack::Session#reset



103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/muack/mock.rb', line 103

def __mock_reset
  __mock_injected.each_value do |defi|
    object.singleton_class.module_eval do
      remove_method(defi.msg)
      # restore original method
      if instance_methods(false).include?(defi.original_method)
        alias_method defi.msg, defi.original_method
        remove_method defi.original_method
      end
    end
  end
end

#__mock_verifyObject

used for Muack::Session#verify



92
93
94
95
96
97
98
99
100
# File 'lib/muack/mock.rb', line 92

def __mock_verify
  __mock_defis.values.all?(&:empty?) || begin
    msg, defis_with_same_msg = __mock_defis.find{ |_, v| v.size > 0 }
    args, defis = defis_with_same_msg.group_by(&:args).first
    dsize = __mock_disps[msg].select{ |d| d.args == args }.size
    Mock.__send__(:raise,   # Too little times
      Expected.new(object, defis.first, defis.size + dsize, dsize))
  end
end

#inspectObject

Public API: Bacon needs this, or we often ended up with stack overflow



19
20
21
# File 'lib/muack/mock.rb', line 19

def inspect
  "Muack::API.#{__mock_class.name[/\w+$/].downcase}(#{object.inspect})"
end