Skip to content

Instantly share code, notes, and snippets.

@thebugcatcher
Last active March 16, 2022 19:58
Show Gist options
  • Save thebugcatcher/1329b1caf8d28a36b40e489b2d898367 to your computer and use it in GitHub Desktop.
Save thebugcatcher/1329b1caf8d28a36b40e489b2d898367 to your computer and use it in GitHub Desktop.
Elixir helper module to test whether a function is delegated to another module.
defmodule GenTestUtils.Module do
@moduledoc """
Helper functions to test parts of an Elixir module
"""
require ExUnit.Assertions
@doc """
Tests whether a module delegates a given MFA to another given MFA
# Usage
```elixir
defmodule GenTestUtils.ModuleA do
def hello(:world), do: "world"
end
```
```elixir
defmodule GenTestUtils.ModuleB do
defdelegate hello(arg), to: GenTestUtils.ModuleA
end
```
```elixir
# in test/**/*_test.exs
import GenTestUtils.Module
test "B delegates `hello/1` to A" do
assert_delegates_function(
{GenTestUtils.ModuleB, :hello, 1},
to: {GenTestUtils.ModuleA, :hello, 1}
)
end
```
# Examples
iex> GenTestUtils.Module.assert_delegates_function(
...> {GenTestUtils.ModuleB, :hello, 1},
...> to: {GenTestUtils.ModuleA, :hello, 1}
...> )
true
"""
def assert_delegates_function({module, function, arity}, to: {m, f, a}) do
ExUnit.Assertions.assert(
delegates_function?({module, function, arity}, to: {m, f, a}),
"Expected #{module}.#{function}/#{arity} to be delegated to " <>
"#{m}.#{f}/#{a}, but it wasn't the case"
)
end
@doc """
Returns `true` or `false` whether a given MFA is delegated to another given
MFA.
# Usage
```elixir
defmodule GenTestUtils.ModuleA do
def hello(:world), do: "world"
end
```
```elixir
defmodule GenTestUtils.ModuleB do
defdelegate hello(arg), to: GenTestUtils.ModuleA
end
```
# Examples
iex> GenTestUtils.Module.delegates_function?(
...> {GenTestUtils.ModuleB, :hello, 1},
...> to: {GenTestUtils.ModuleA, :hello, 1}
...> )
true
iex> GenTestUtils.Module.delegates_function?(
...> {GenTestUtils.ModuleB, :hello2, 1},
...> to: {GenTestUtils.ModuleA, :hello2, 1}
...> )
false
"""
def delegates_function?({module, function, arity}, to: {m, f, a}) do
{_, _, _, _, _, _, docs} = Code.fetch_docs(module)
docs
|> Enum.find(fn
{{:function, ^function, ^arity}, _, _, _, %{delegate_to: {^m, ^f, ^a}}} ->
true
_ ->
false
end)
|> is_nil()
|> Kernel.not()
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment