free_mutant/spec/support/fake_actor.rb
2016-04-10 14:33:47 -07:00

109 lines
2.3 KiB
Ruby

require 'mutant/actor'
# A fake actor used from specs
module FakeActor
class Expectation
include Concord::Public.new(:name, :message, :block)
include Equalizer.new(:name, :message)
def self.new(_name, _message, _block = nil)
super
end
def verify(other)
unless eql?(other)
fail "Got:\n#{other.inspect}\nExpected:\n#{inspect}"
end
block.call(other.message) if block
end
end # Expectation
class MessageSequence
include Adamantium::Flat, Concord::Public.new(:messages)
def self.new
super([])
end
def add(name, *message_arguments, &block)
messages << Expectation.new(name, Mutant::Actor::Message.new(*message_arguments), block)
self
end
def sending(expectation)
fail "Unexpected send: #{expectation.inspect}" if messages.empty?
expected = messages.shift
expected.verify(expectation)
self
end
def receiving(name)
fail "No message to read for #{name.inspect}" if messages.empty?
expected = messages.shift
fail "Unexpected message #{expected.inspect} for #{name.inspect}" unless expected.name.eql?(name)
expected.message
end
def consumed?
messages.empty?
end
end # MessageSequence
class Env
include Concord.new(:messages, :mailbox_names)
def spawn
mailbox = mailbox(next_name)
yield mailbox if block_given?
mailbox.sender
end
def mailbox(name)
Mailbox.new(name, @messages)
end
def new_mailbox
mailbox(:current)
end
private
def next_name
@mailbox_names.shift.tap do |name|
name or fail 'Tried to spawn actor when no name available'
end
end
end # Env
class Mailbox
include Concord.new(:name, :messages)
def receiver
Receiver.new(name, messages)
end
def sender
Sender.new(name, messages)
end
def bind(sender)
Mutant::Actor::Binding.new(self, sender)
end
end # Mailbox
class Sender
include Concord.new(:name, :messages)
def call(message)
messages.sending(Expectation.new(name, message))
end
end # Sender
class Receiver
include Concord::Public.new(:name, :messages)
def call
messages.receiving(name)
end
end # Receiver
end # FakeActor