Class: Spec::Api::MessageExpectation

Inherits:
Object
  • Object
show all
Defined in:
lib/spec/api/mocks/message_expectation.rb

Overview

Represents the expection of the reception of a message

Instance Method Summary collapse

Constructor Details

#initialize(mock_name, expectation_ordering, expected_from, sym, method_block) ⇒ MessageExpectation

Returns a new instance of MessageExpectation.



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/spec/api/mocks/message_expectation.rb', line 7

def initialize(mock_name, expectation_ordering, expected_from, sym, method_block)
  @mock_name = mock_name
  @expected_from = expected_from
  @sym = sym
  @method_block = method_block
  @return_block = lambda {}
  @received_count = 0
  @expected_received_count = 1
  @args_expectation = ArgumentExpectation.new([:any_args])
  @consecutive = false
  @exception_to_raise = nil
  @symbol_to_throw = nil
  @ordering = expectation_ordering
  @ordered = false
  @at_least = nil
  @at_most = nil
  @args_to_yield = nil
end

Instance Method Details

#and_raise(exception = Exception) ⇒ Object



181
182
183
# File 'lib/spec/api/mocks/message_expectation.rb', line 181

def and_raise(exception=Exception)
  @exception_to_raise = exception
end

#and_return(value = nil, &return_block) ⇒ Object



175
176
177
178
179
# File 'lib/spec/api/mocks/message_expectation.rb', line 175

def and_return(value=nil, &return_block)
  Kernel::raise AmbiguousReturnError unless @method_block.nil?
  @consecutive = value.instance_of? Array
  @return_block = block_given? ? return_block : lambda { value }
end

#and_throw(symbol) ⇒ Object



185
186
187
# File 'lib/spec/api/mocks/message_expectation.rb', line 185

def and_throw(symbol)
  @symbol_to_throw = symbol
end

#and_yield(*args) ⇒ Object



189
190
191
# File 'lib/spec/api/mocks/message_expectation.rb', line 189

def and_yield(*args)
  @args_to_yield = args
end

#any_number_of_timesObject



154
155
156
157
# File 'lib/spec/api/mocks/message_expectation.rb', line 154

def any_number_of_times
  @expected_received_count = :any
  self
end

#at_least(n) ⇒ Object



131
132
133
134
# File 'lib/spec/api/mocks/message_expectation.rb', line 131

def at_least(n)
  set_expected_received_count :at_least, n
  self
end

#at_most(n) ⇒ Object



136
137
138
139
# File 'lib/spec/api/mocks/message_expectation.rb', line 136

def at_most(n)
  set_expected_received_count :at_most, n
  self
end

#exactly(n) ⇒ Object



126
127
128
129
# File 'lib/spec/api/mocks/message_expectation.rb', line 126

def exactly(n)
  set_expected_received_count :exactly, n
  self
end

#handle_order_constraintObject



63
64
65
66
67
68
# File 'lib/spec/api/mocks/message_expectation.rb', line 63

def handle_order_constraint
  return unless @ordered
  return @ordering.consume(@self) if @ordering.ready_for?(self)
  message = "Mock '#{@mock_name}' received '#{@sym}' out of order"
  Kernel::raise(Spec::Api::MockExpectationError, message) 
end

#invoke(args, block) ⇒ Object

This method is called when a method is invoked on a mock



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/spec/api/mocks/message_expectation.rb', line 71

def invoke(args, block)
  
  handle_order_constraint

  begin
    Kernel::raise @exception_to_raise.new unless @exception_to_raise.nil?
    Kernel::throw @symbol_to_throw unless @symbol_to_throw.nil?

    if !@method_block.nil?
      return invoke_method_block(args)
    elsif !@args_to_yield.nil?
      return invoke_with_yield(block)
    else
      return invoke_return_block(args, block)
    end
  ensure
    @received_count += 1
  end
end

#invoke_method_block(args) ⇒ Object



91
92
93
94
95
96
97
# File 'lib/spec/api/mocks/message_expectation.rb', line 91

def invoke_method_block(args)
  begin
    @method_block.call(*args)
  rescue Spec::Api::ExpectationNotMetError => detail
    Kernel::raise Spec::Api::MockExpectationError, "Call expectation violated with: " + detail
  end
end

#invoke_return_block(args, block) ⇒ Object



109
110
111
112
113
114
115
116
117
118
119
# File 'lib/spec/api/mocks/message_expectation.rb', line 109

def invoke_return_block(args, block)
  args << block unless block.nil?
  value = @return_block.call(*args)
    
  if @consecutive
    index = [@received_count, value.size-1].min
    value[index]
  else
    value
  end
end

#invoke_with_yield(block) ⇒ Object



99
100
101
102
103
104
105
106
107
# File 'lib/spec/api/mocks/message_expectation.rb', line 99

def invoke_with_yield(block)
  if block.nil?
    Kernel::raise Spec::Api::MockExpectationError, "Expected block to be passed"
  end
  if @args_to_yield.length != block.arity
    Kernel::raise Spec::Api::MockExpectationError, "Wrong arity of passed block. Expected #{@args_to_yield.size}"
  end
  block.call(*@args_to_yield)
end

#make_count_message(count) ⇒ Object



30
31
32
33
34
# File 'lib/spec/api/mocks/message_expectation.rb', line 30

def make_count_message(count)
  return "at least #{pretty_print(count.abs)}" if count < 0
  return pretty_print(count) if count > 0
  return "never"
end

#matches(sym, args) ⇒ Object



26
27
28
# File 'lib/spec/api/mocks/message_expectation.rb', line 26

def matches(sym, args)
  @sym == sym and @args_expectation.check_args(args)
end

#neverObject

TODO - replace this w/ not syntax in mock



160
161
162
163
# File 'lib/spec/api/mocks/message_expectation.rb', line 160

def never
  @expected_received_count = 0
  self
end

#onceObject



165
166
167
168
# File 'lib/spec/api/mocks/message_expectation.rb', line 165

def once
  @expected_received_count = 1
  self
end

#orderedObject



193
194
195
196
197
# File 'lib/spec/api/mocks/message_expectation.rb', line 193

def ordered
  @ordering.register(self)
  @ordered = true
  self
end

#pretty_print(count) ⇒ Object



36
37
38
39
40
# File 'lib/spec/api/mocks/message_expectation.rb', line 36

def pretty_print(count)
  return "once" if count == 1
  return "twice" if count == 2
  return "#{count} times"
end

#set_expected_received_count(relativity, n) ⇒ Object



141
142
143
144
145
146
147
# File 'lib/spec/api/mocks/message_expectation.rb', line 141

def set_expected_received_count relativity, n
  @at_least = (relativity == :at_least)
  @at_most = (relativity == :at_most)
  @expected_received_count = 1 if n == :once
  @expected_received_count = 2 if n == :twice
  @expected_received_count = n if n.kind_of? Numeric
end

#timesObject



149
150
151
152
# File 'lib/spec/api/mocks/message_expectation.rb', line 149

def times
  #pure sugar
  self
end

#twiceObject



170
171
172
173
# File 'lib/spec/api/mocks/message_expectation.rb', line 170

def twice
  @expected_received_count = 2
  self
end

#verify_messages_receivedObject

This method is called at the end of a spec, after teardown.



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/spec/api/mocks/message_expectation.rb', line 43

def verify_messages_received
  # TODO: this doesn't provide good enough error messages to fix the error.
  # Error msg should tell exactly what went wrong. (AH).
  
  return if @expected_received_count == :any
  return if (@at_least) && (@received_count >= @expected_received_count)
  return if (@at_most) && (@received_count <= @expected_received_count)
  return if @expected_received_count == @received_count
    
  count_message = make_count_message(@expected_received_count)

  message = "Mock '#{@mock_name}' expected '#{@sym}' #{count_message}, but received it #{@received_count} times"
  begin
    Kernel::raise(Spec::Api::MockExpectationError, message)
  rescue => error
    error.backtrace.insert(0, @expected_from)
    Kernel::raise error
  end
end

#with(*args) ⇒ Object



121
122
123
124
# File 'lib/spec/api/mocks/message_expectation.rb', line 121

def with(*args)
  @args_expectation = ArgumentExpectation.new(args)
  self
end