lib/spex/testing.ex

defmodule Spex.Testing do
  @moduledoc """
  Test helpers for preparing and manipulating Spex runtime state.
  """

  # By default, this is: Spex.InstanceManager.SimpleInstanceManager
  @default_instance_manager Spex.InstanceManager.default_instance_manager()

  @type opt ::
          {:instance_manager, module()}
          | {:impl_models_dir, Path.t()}

  @doc """
  Prepares after-suite hooks that export collected implementation models.
  """
  @spec prepare_for_test_suite([opt()]) :: :ok
  def prepare_for_test_suite(opts \\ []) do
    instance_manager = Keyword.get(opts, :instance_manager, @default_instance_manager)

    impl_models_dir =
      Keyword.get(opts, :impl_models_dir) ||
        Application.get_env(:spex, :impl_models_dir) ||
        raise(
          ArgumentError,
          "Missing required option :impl_models_dir. Please provide it as an argument or " <>
            "configure it in the application environment; see the `Spex` moduledoc for details."
        )

    ExUnit.after_suite(fn _ ->
      {:ok, impl_models} = instance_manager.all_impl_models()
      impl_models = Enum.map(impl_models, &%{&1 | learning_mode?: false})
      :ok = Spex.ImplModelStore.save(impl_models, impl_models_dir)
    end)
  end

  @doc """
  Inserts or updates a mock instance at a specific state for test setup.
  """
  defdelegate mock_instance!(spec, instance_identifier, state, meta \\ nil),
    to: @default_instance_manager
end