class Tiramisu::Expectation

Attributes

expected_message[R]
received_messages[R]

Public Class Methods

new(object, expected_message, assert, caller) click to toggle source
# File lib/tiramisu/expectations.rb, line 17
def initialize object, expected_message, assert, caller
  @object = object
  @expected_message = expected_message.to_sym
  @assert = assert
  @caller = caller
  proxify(@object, @expected_message)
end
restore_object_status(obj) click to toggle source
# File lib/tiramisu/expectations.rb, line 4
def self.restore_object_status obj
  return unless obj.instance_variable_get(:@__tiramisu__original_methods__)

  obj.instance_variable_get(:@__tiramisu__original_methods__).each_pair do |n,m|
    obj.define_singleton_method(n, &m)
  end

  obj.instance_variable_set(:@__tiramisu__original_methods__, {})
  obj.instance_variable_set(:@__tiramisu__received_messages__, {})
end

Public Instance Methods

and_raise(type = nil, message = nil, &block) click to toggle source

ensure received message raises as expected

@note if block given it will have precedence over arguments

@example

x = mock(X.new)
expect(x).to_receive(:y).and_raise(NoMethodError)
# call `x.y` for test to pass
# File lib/tiramisu/expectations/raise.rb, line 13
def and_raise type = nil, message = nil, &block
  @raise = block || [type, message]
end
and_return(value = nil, &block) click to toggle source

ensure received message returns expected value

@note if block given it will have precedence over arguments

@example

n = mock(1)
expect(n).to_receive(:+).with(1).and_return(2)
# File lib/tiramisu/expectations/return.rb, line 12
def and_return value = nil, &block
  @return = block || value
end
and_throw(symbol = nil, &block) click to toggle source

ensure received message throws as expected

@note if block given it will have precedence over arguments

@example

x = mock(X.new)
expect(x).to_receive(:y).and_throw(:z)
# File lib/tiramisu/expectations/throw.rb, line 12
def and_throw symbol = nil, &block
  @throw = [symbol, block]
end
assert_message_raised_as_expected() click to toggle source
# File lib/tiramisu/expectations/raise.rb, line 17
def assert_message_raised_as_expected
  return unless @raise
  if @raise.is_a?(Proc)
    received_messages.find {|log| @raise.call(log[:raised])} || Tiramisu.fail([
      'Looks like :%s message never raised as expected' % expected_message,
      'See validation block'
    ], @caller)
  else
    received_messages.each do |log|
      next unless f = Tiramisu.assert_raised_as_expected(log, *@raise)
      Tiramisu.fail(f, log[:caller])
    end
  end
end
assert_message_thrown_as_expected() click to toggle source
# File lib/tiramisu/expectations/throw.rb, line 16
def assert_message_thrown_as_expected
  return unless @throw
  received_messages.each do |log|
    next unless f = Tiramisu.assert_thrown_as_expected(log, *@throw)
    Tiramisu.fail(f, log[:caller])
  end
end
validate() click to toggle source
# File lib/tiramisu/expectations.rb, line 25
def validate
  @received_messages = @object.__tiramisu__received_messages__[expected_message] || []
  return refute_message_received unless @assert
  assert_message_received
  assert_message_received_with_correct_arguments
  assert_message_returned_correct_value
  assert_message_raised_as_expected
  assert_message_thrown_as_expected
end
with(*args, &block) click to toggle source

ensure expected message received with correct arguments

@note if block given it will have precedence over arguments

@example

test :some_test do
  some_object = mock(SomeObject.new)
  expect(some_object).to_receive(:some_method).with(:some, :args)
  # call `some_object.some_method(:some, :args)` for test to pass
end
# File lib/tiramisu/expectations/with.rb, line 15
def with *args, &block
  @with = block || args
  self
end

Private Instance Methods

assert_message_received() click to toggle source
# File lib/tiramisu/expectations.rb, line 84
def assert_message_received
  Tiramisu.fail('Expected %s to receive %s message' % [
    Tiramisu.pp(@object),
    Tiramisu.pp(expected_message)
  ], @caller) if received_messages.empty?
end
assert_message_received_with_correct_arguments() click to toggle source
# File lib/tiramisu/expectations/with.rb, line 21
def assert_message_received_with_correct_arguments
  return unless @with
  if @with.is_a?(Proc)
    received_messages.find {|log| @with.call(log[:arguments])} || Tiramisu.fail([
      'Looks like :%s message never was called with expected arguments' % expected_message,
      'See validation block'
    ], @caller)
  else
    received_messages.find {|log| log[:arguments] == @with} || Tiramisu.fail([
      'Looks like :%s message never was called with expected arguments:' % expected_message,
      Array(@with).map {|x| Tiramisu.pp(x)}.join(', ')
    ], @caller)
  end
end
assert_message_returned_correct_value() click to toggle source
# File lib/tiramisu/expectations/return.rb, line 17
def assert_message_returned_correct_value
  return unless @return
  if @return.is_a?(Proc)
    received_messages.find {|log| @return.call(log[:returned])} || Tiramisu.fail([
      'Looks like :%s message never returned expected value' % expected_message,
      'See validation block'
    ], @caller)
  else
    received_messages.find {|log| log[:returned] == @return} || Tiramisu.fail([
      'Looks like :%s message never returned expected value:' % expected_message,
      Array(@return).map {|x| Tiramisu.pp(x)}.join(', ')
    ], @caller)
  end
end
mount_original_methods_depot(object) click to toggle source
# File lib/tiramisu/expectations.rb, line 69
def mount_original_methods_depot object
  return if object.respond_to?(:__tiramisu__original_methods__)
  def object.__tiramisu__original_methods__; @__tiramisu__original_methods__ ||= {} end
end
mount_received_messages_depot(object) click to toggle source
# File lib/tiramisu/expectations.rb, line 74
def mount_received_messages_depot object
  return if object.respond_to?(:__tiramisu__received_messages__)
  def object.__tiramisu__received_messages__; @__tiramisu__received_messages__ ||= {} end
end
proxify(object, method) click to toggle source
# File lib/tiramisu/expectations.rb, line 36
def proxify object, method
  mount_original_methods_depot(object)
  mount_received_messages_depot(object)
  store_original_method(object, method)

  object.define_singleton_method method do |*a,&b|
    log = {arguments: a, block: b, caller: Tiramisu.relative_location(caller[0])}
    (__tiramisu__received_messages__[method] ||= []).push(log)

    if __tiramisu__original_methods__[method]
      return begin
        log[:returned] = __tiramisu__original_methods__[method].call(*a, &b)
      rescue UncaughtThrowError => e
        log[:thrown] = Tiramisu.extract_thrown_symbol(e)
      rescue Exception => e
        log[:raised] = e
      end
    end

    if respond_to?(:method_missing)
      return begin
        log[:returned] = __send__(:method_missing, method, *a, &b)
      rescue UncaughtThrowError => e
        log[:thrown] = Tiramisu.extract_thrown_symbol(e)
      rescue Exception => e
        log[:raised] = e
      end
    end

    log[:raised] = NoMethodError.new("undefined method `%s' for %s:%s" % [method, self.inspect, self.class])
  end
end
refute_message_received() click to toggle source
# File lib/tiramisu/expectations.rb, line 91
def refute_message_received
  Tiramisu.fail('Not Expected %s to receive %s message' % [
    Tiramisu.pp(@object),
    Tiramisu.pp(expected_message)
  ], @caller) if received_messages.any?
end
store_original_method(object, method) click to toggle source
# File lib/tiramisu/expectations.rb, line 79
def store_original_method object, method
  return unless object.respond_to?(method)
  object.__tiramisu__original_methods__[method] ||= object.method(method)
end