Packages
finitomata
0.31.1
0.41.0
0.40.0
0.35.0
0.34.0
0.33.0
0.32.0
0.31.1
0.30.3
0.30.2
0.30.1
0.30.0
0.29.10
0.29.9
0.29.8
0.29.7
0.29.6
0.29.5
0.29.4
0.29.3
0.29.2
0.29.1
0.29.0
0.28.1
0.28.0
0.27.1
0.27.0
0.26.4
0.26.3
0.26.2
0.26.1
0.26.0
0.25.0
0.24.4
0.24.3
0.24.2
0.24.1
0.24.0
0.23.7
0.23.6
0.23.5
0.23.4
0.23.3
0.23.2
0.23.1
0.23.0
0.22.1
0.22.0
0.21.4
0.21.3
0.21.2
0.21.1
0.21.0
0.20.2
0.20.1
0.20.0
0.19.6
0.19.5
0.19.4
0.19.3
0.19.2
0.19.1
0.19.0
0.18.4
0.18.3
0.18.2
0.18.1
0.18.0
0.17.1
0.17.0
0.16.0
0.15.1
0.15.0
0.14.6
0.14.5
0.14.4
0.14.3
0.14.2
0.14.1
0.14.0
0.13.0
0.12.1
0.12.0
0.11.3
0.11.2
0.11.1
0.11.0
0.10.0
0.9.1
0.9.0
0.8.2
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.6.3
0.6.2
0.6.1
0.6.0
0.5.2
0.5.1
0.5.0
0.4.0
0.3.0
0.2.0
0.1.1
0.1.0
The FSM implementation generated from PlantUML textual representation.
Current section
Files
Jump to
Current section
Files
lib/mix/tasks/finitomata_generate_test.ex
defmodule Mix.Tasks.Finitomata.Generate.Test do
@shortdoc "Generates the test scaffold for the `Finitomata` instance"
@moduledoc """
Mix task to generate the `Finitomata.ExUnit` test scaffold.
### Allowed arguments
- **`--module: :string`** __[mandatory]__ the name of the module the test to be generated for
- **`--file: :string`** __[optional, default: derived from `module` name]__ the name of the file
to store the test module definition in
- **`--dir: :string`** __[optional, default: `test/finitomata`]__ the name of the directory
to put the file in
### Example
```sh
mix finitomata.generate.test --module MyApp.MyFSM
```
"""
use Mix.Task
@finitomata_tests_path "test/finitomata"
@impl Mix.Task
@doc false
def run(args) do
Mix.Task.run("compile")
Finitomata.Mix.load_app()
{opts, _pass_thru, []} =
OptionParser.parse(args, strict: [module: :string, file: :string, dir: :string])
module = Keyword.fetch!(opts, :module)
test_dir = Keyword.get(opts, :dir, @finitomata_tests_path)
module = Module.concat([module])
test_file =
Keyword.get(
opts,
:file,
module |> Macro.underscore() |> Kernel.<>("_test.exs")
)
if module?(module) do
paths =
module.fsm()
|> Finitomata.Transition.paths()
|> Enum.map(&{&1, transform_path(module.__config__(:auto_terminate), &1)})
test_module = Module.concat([module, "Test"])
target_file = Path.join(test_dir, test_file)
Mix.Generator.copy_template(
Path.expand("test_template.eex", __DIR__),
target_file,
module: module,
test_module: test_module,
paths: paths
)
File.write!(target_file, Code.format_file!(target_file))
Mix.shell().info([
[:bright, :blue, "* #{inspect(test_module)}", :reset],
" has been created for ",
[:blue, inspect(module), :reset],
", do not forget to:\n",
" ▹ amend assertions to fit your business logic\n",
" ▹ add `listener: :mox` (or actual listener) to `Finitomata` declaration"
])
end
end
@doc false
defp transform_path(auto_terminate?, %Finitomata.Transition.Path{path: path}),
do: transform_path(auto_terminate?, path)
defp transform_path(auto_terminate?, path) do
path
|> Enum.reduce([], fn
{event, state}, [] ->
[[{event, state}]]
{event, state}, [curr | rest] ->
if event |> to_string() |> String.ends_with?("!"),
do: [curr ++ [{event, state}] | rest],
else: [[{event, state}], curr | rest]
end)
|> then(&maybe_join_ending(auto_terminate?, &1))
|> Enum.reverse()
end
defp maybe_join_ending(false, path), do: path
defp maybe_join_ending(true, [[{:__end__, :*}] = last, prev | rest]), do: [prev ++ last | rest]
defp module?(module) do
with {:module, ^module} <- Code.ensure_compiled(module),
true <- function_exported?(module, :fsm, 0) do
true
else
_ ->
Mix.shell().error([
:yellow,
"* #{inspect(module)}",
:reset,
" is not found or is not a `Finitomata` instance"
])
false
end
end
end