defmodule Formular.Client.MockError do
@moduledoc """
Error for the mocking configuration.
"""
defexception [:message]
@impl true
def exception({:missing, _missing_formulas}) do
%Formular.Client.MockError{message: "Not all the formulas were mocked"}
end
end
defmodule Formular.Client.Adapter.Mock do
@moduledoc """
A mocking adapter for testing.
An example configuration for this adapter:
```elixir
{
formulas: [
{"my-formula", fn _binding, _opts ->
:ok
end}
]
}
```
"""
alias Formular.Client.Cache
require Logger
def start_link(config, opts) do
Logger.debug(["Starting mock formular intepreter."])
{:ok, pid} = Agent.start_link(fn -> :ok end)
formulas = opts[:formulas] || []
ensure_all_formulas_provided!(config.formulas, formulas)
Enum.each(formulas, fn {name, function} ->
mock_global(name, function)
end)
{:ok, pid}
end
defp ensure_all_formulas_provided!(required, provided) do
case ensure_all_formulas_provided(required, provided) do
:ok ->
:ok
{:missing, missing} ->
msg = """
Not all the formulas were mocked, missing:
#{inspect(missing)}.
"""
Logger.error(msg)
raise Formular.Client.MockError, {:missing, missing}
end
end
defp ensure_all_formulas_provided(required, provided) do
required = required |> Enum.map(&elem(&1, 1))
provided = provided |> Enum.map(&elem(&1, 0))
case required -- provided do
[] ->
:ok
missing ->
{:missing, missing}
end
end
def mock_global(name, function)
when is_binary(function)
when is_function(function, 2) do
Cache.put(name, function)
end
end