1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
|
class FlexMock
# This class contains helper methods for mock containers. Since
# MockContainer is a module that is designed to be mixed into other
# classes, (particularly testing framework test cases), we don't
# want to pollute the method namespace of the class that mixes in
# MockContainer. So we have aggressively moved a number of
# MockContainer methods out of that class and into
# MockBuilder to isoloate the names.
#
class MockBuilder
def initialize(container)
@container = container
end
def define_a_mock(location, *args, &block)
opts = parse_creation_args(args)
if opts.safe_mode && ! block_given?
raise UsageError, "a block is required in safe mode"
end
result = create_double(opts)
flexmock_mock_setup(opts.mock, opts, location, &block)
run_post_creation_hooks(opts, location)
result
end
FlexOpts = Struct.new(
:name, :defs, :safe_mode, :mock,
:domain_obj, :base_class,
:extended, :extended_data
) do
def data
self.extended_data ||= {}
end
end
# Parse the list of flexmock() arguments and populate the opts object.
def parse_creation_args(args)
opts = FlexOpts.new
while ! args.empty?
case args.first
when Symbol
unless parse_create_symbol(args, opts)
opts.name = args.shift.to_s
end
when String, Symbol
opts.name = args.shift.to_s
when Hash
opts.defs = args.shift
when FlexMock
opts.mock = args.shift
else
opts.domain_obj = args.shift
end
end
set_base_class(opts)
opts
end
# Create the test double based on the args options.
def create_double(opts)
if opts.extended
result = opts.extended.create(container, opts)
elsif opts.domain_obj
result = create_partial(opts)
else
result = create_mock(opts)
end
opts.mock ||= result
result
end
# Run any post creation hooks specified by an extension.
def run_post_creation_hooks(opts, location)
if opts.extended
opts.extended.post_create(opts, location)
end
end
# Setup the test double with its expections and such.
def flexmock_mock_setup(mock, opts, location)
mock.flexmock_based_on(opts.base_class) if opts.base_class
mock.flexmock_define_expectation(location, opts.defs)
yield(mock) if block_given?
container.flexmock_remember(mock)
end
attr_reader :container
private :container
private
# Set the base class if not defined and partials are based.
def set_base_class(opts)
if ! opts.base_class && opts.domain_obj && FlexMock.partials_are_based
opts.base_class = opts.domain_obj.singleton_class
end
end
# Handle a symbol in the flexmock() args list.
def parse_create_symbol(args, opts)
case args.first
when :base, :safe
opts.safe_mode = (args.shift == :safe)
opts.domain_obj = args.shift
when :on, :strict
if args.shift == :strict
if !opts.domain_obj
raise ArgumentError, "cannot use :strict outside a partial mock"
end
opts.base_class = opts.domain_obj.singleton_class
else
opts.base_class = args.shift
end
opts.name ||= "#{opts.base_class} Mock"
else
CONTAINER_HELPER.extensions.each do |ext|
handled = ext.handle(args, opts)
return true if handled
end
return false
end
true
end
# Create a mock object in the options.
def create_mock(opts)
opts.mock ||= FlexMock.new(opts.name || "unknown", container)
opts.mock
end
# Create a partial mock object in options.
def create_partial(opts)
opts.mock = PartialMockProxy.make_proxy_for(
opts.domain_obj,
container, opts.name,
opts.safe_mode)
opts.domain_obj
end
end
end
|