Current section
Files
Jump to
Current section
Files
lib/raxol/plugin/testing.ex
defmodule Raxol.Plugin.Testing do
@moduledoc """
Test helpers for Raxol plugins.
Provides utilities for exercising plugin callbacks in isolation
without starting the full plugin manager infrastructure.
## Usage
use ExUnit.Case
import Raxol.Plugin.Testing
test "handles events" do
{:ok, state} = setup_plugin(MyPlugin, %{key: "value"})
assert_handles_event(MyPlugin, :some_event, state)
end
"""
@compile {:no_warn_undefined, Raxol.Core.Runtime.Plugins.Plugin}
@doc """
Initializes a plugin module with the given config and returns its state.
Calls `module.init(config)` and asserts it returns `{:ok, state}`.
## Examples
{:ok, state} = setup_plugin(MyPlugin, %{})
"""
@spec setup_plugin(module(), map()) :: {:ok, term()} | {:error, term()}
def setup_plugin(module, config \\ %{}) do
module.init(config)
end
@doc """
Asserts that a plugin handles an event without halting.
Calls `module.filter_event(event, state)` and asserts the result
matches `{:ok, _}`. Returns the (possibly modified) event.
## Examples
event = assert_handles_event(MyPlugin, :click, state)
"""
@spec assert_handles_event(module(), term(), term()) :: term()
def assert_handles_event(module, event, state) do
result = module.filter_event(event, state)
case result do
{:ok, returned_event} ->
returned_event
:halt ->
raise ExUnit.AssertionError,
message: "Expected plugin to handle event, but it halted",
expr: {:filter_event, [event, state]}
other ->
raise ExUnit.AssertionError,
message: "Expected {:ok, event}, got: #{inspect(other)}",
expr: {:filter_event, [event, state]}
end
end
@doc """
Asserts that a plugin handles a command successfully.
Calls `module.handle_command(command, args, state)` and asserts the
result matches `{:ok, new_state, result}`. Returns `{new_state, result}`.
## Examples
{new_state, result} = assert_handles_command(MyPlugin, :do_thing, [1, 2], state)
"""
@spec assert_handles_command(module(), atom() | tuple(), list(), term()) :: {term(), term()}
def assert_handles_command(module, command, args, state) do
result = module.handle_command(command, args, state)
case result do
{:ok, new_state, cmd_result} ->
{new_state, cmd_result}
{:error, reason, _new_state} ->
raise ExUnit.AssertionError,
message: "Expected command to succeed, got error: #{inspect(reason)}",
expr: {:handle_command, [command, args, state]}
other ->
raise ExUnit.AssertionError,
message: "Expected {:ok, state, result}, got: #{inspect(other)}",
expr: {:handle_command, [command, args, state]}
end
end
@doc """
Runs a plugin through its full lifecycle: init -> enable -> disable -> terminate.
Asserts each step succeeds. Returns a list of `{callback, result}` tuples
for inspection.
## Examples
steps = simulate_lifecycle(MyPlugin, %{option: true})
assert length(steps) == 4
"""
@spec simulate_lifecycle(module(), map()) :: [{atom(), term()}]
def simulate_lifecycle(module, config \\ %{}) do
{:ok, state} = module.init(config)
init_step = {:init, {:ok, state}}
{:ok, enabled_state} = module.enable(state)
enable_step = {:enable, {:ok, enabled_state}}
{:ok, disabled_state} = module.disable(enabled_state)
disable_step = {:disable, {:ok, disabled_state}}
terminate_result = module.terminate(:normal, disabled_state)
terminate_step = {:terminate, terminate_result}
[init_step, enable_step, disable_step, terminate_step]
end
@doc """
Asserts that a plugin halts a given event.
Calls `module.filter_event(event, state)` and asserts the result is `:halt`.
## Examples
assert_halts_event(MyPlugin, :blocked_event, state)
"""
@spec assert_halts_event(module(), term(), term()) :: :halt
def assert_halts_event(module, event, state) do
result = module.filter_event(event, state)
case result do
:halt ->
:halt
{:ok, _} ->
raise ExUnit.AssertionError,
message: "Expected plugin to halt event, but it passed through",
expr: {:filter_event, [event, state]}
other ->
raise ExUnit.AssertionError,
message: "Expected :halt, got: #{inspect(other)}",
expr: {:filter_event, [event, state]}
end
end
end