Packages

Support package for :mockery

Current section

Files

Jump to
mockery_copy lib mockery copy.ex
Raw

lib/mockery/copy.ex

defmodule Mockery.Copy do
@moduledoc """
Helper to produce a runtime copy of a module that delegates through Mockery.
Use `of/2` to obtain either the original module (when Mockery is disabled)
or a generated module that forwards calls through `Mockery.Proxy`.
"""
@doc """
Prepare `mod` for use with Mockery and return either the original module
or a generated proxy module.
## Behavior
- When mockery is enabled (`config :mockery, enable: true`), this function
dynamically creates a new module which defines the same exported functions
as `mod`. Each function delegates to `Mockery.Proxy`
allowing Mockery to intercept, record, or reroute calls.
- If `:mockery, :enable` config is not `true`, the original `mod` is returned
unchanged.
## Options
- `:name` - an explicit atom to use as the generated module name. If not
provided, a unique module name is generated automatically.
- `:by` - an optional module used as a global mock provider.
## Notes
- The generated module exports the same functions as the original module,
excluding `module_info/0`, `module_info/1` and `__info__/1`.
## Examples
# Create a copy with an automatically generated name
copy = Mockery.Copy.of(MyApp.Foo)
# Create a copy with explicit name and a global mock
copy = Mockery.Copy.of(MyApp.Foo, name: MyApp.FooMock, by: MyApp.FooGlobalMock)
"""
@spec of(
mod :: module,
opts :: [name: module, by: module]
) :: module
def of(mod, opts \\ []) do
case Application.get_env(:mockery, :enable) do
true ->
compile_copy(mod, opts)
_ ->
mod
end
end
defp compile_copy(mod, opts) do
copy_name =
opts[:name] ||
Module.concat([mod, "Mockery", "Mockable#{System.unique_integer([:positive])}"])
by = opts[:by]
funs = mod.module_info()[:exports] -- [module_info: 0, module_info: 1, __info__: 1]
quoted_funs =
for {name, arity} <- funs do
args = Macro.generate_arguments(arity, copy_name)
quote do
def unquote(name)(unquote_splicing(args)) do
Mockery.Proxy.do_proxy(unquote(mod), unquote(name), unquote(args), unquote(by))
end
end
end
location = Macro.Env.location(__ENV__)
{:module, module_name, _, _} = Module.create(copy_name, quoted_funs, location)
module_name
end
end