Current section

Files

Jump to
xcribe lib formatter.ex
Raw

lib/formatter.ex

defmodule Xcribe.Formatter do
@moduledoc """
An implementation of ExUnit Formatter.
This module is a `GenServer` that receives ExUnits events from your test suite.
It handle the `suite_finished` event and then generates the documentation from
the collected requests.
You must add `Xcribe.Formatter` in the list of formatters in your `test_helper.exs`.
ExUnit.start(formatters: [ExUnit.CLIFormatter, Xcribe.Formatter])
You must keep `ExUnit.CLIFormatter` in the list as well.
The document will be generated if the pre-configured env var has a truthy value.
Other wise the Formatter will ignore the finished event.
All request documented with macro `document/2` (See `Xcribe`) will be parsed
by Xcribe. When the test suite finish `Xcribe.Formatter` will check if all
colleted requests are valid. If some invalid request is found an error output
will apears and documentation will not be generated.
"""
use GenServer
require Logger
alias Xcribe.{
ApiBlueprint,
CLI.Output,
Config,
DocException,
Recorder,
Request,
Request.Error,
Swagger,
Writter
}
@doc false
def init(_config), do: {:ok, nil}
@doc false
def handle_cast({:suite_finished, _run_us, _load_us}, nil) do
if Config.active?() do
check_configurations()
|> get_recorded_requests()
|> validate_records()
|> order_by_path()
|> generate_docs()
|> write()
end
{:noreply, nil}
rescue
e in DocException ->
Output.print_doc_exception(e)
{:noreply, nil}
end
@doc false
def handle_cast(_event, nil), do: {:noreply, nil}
defp check_configurations do
case Config.check_configurations() do
{:error, errs} -> Output.print_configuration_errors(errs) && :error
:ok -> :ok
end
end
defp get_recorded_requests(:ok), do: Recorder.get_all()
defp get_recorded_requests(:error), do: :error
defp validate_records(:error), do: :error
defp validate_records(records) when is_list(records) do
records
|> check_errors()
|> handle_errors()
end
defp check_errors(records), do: Enum.reduce(records, {:ok, []}, &reduce_records/2)
defp reduce_records(%Request{} = request, {:ok, requests}), do: {:ok, [request | requests]}
defp reduce_records(%Request{}, {:error, _errs} = err), do: err
defp reduce_records(%Error{} = err, {:ok, _requests}), do: {:error, [err]}
defp reduce_records(%Error{} = err, {:error, errs}), do: {:error, [err | errs]}
defp handle_errors({:error, errs}), do: Output.print_request_errors(errs) && :error
defp handle_errors({:ok, requests}), do: requests
defp order_by_path(:error), do: :error
defp order_by_path(requests), do: Enum.sort(requests, &(&1.path >= &2.path))
defp generate_docs(:error), do: :error
defp generate_docs(requests) when is_list(requests) do
case Config.doc_format!() do
:api_blueprint -> ApiBlueprint.generate_doc(requests)
:swagger -> Swagger.generate_doc(requests)
end
end
defp write(:error), do: :error
defp write(text) when is_binary(text), do: Writter.write(text)
end