defmodule ESpec do @moduledoc """ The ESpec basic module. Imports a lot of ESpec components. One should `use` the module in spec modules. """ @spec_agent_name :espec_specs_agent defmacro __using__(args) do quote do ESpec.add_spec(__MODULE__) Module.register_attribute(__MODULE__, :examples, accumulate: true) @shared unquote(args)[:shared] || false @before_compile ESpec import ESpec.Context @context [ %ESpec.Context{ description: inspect(__MODULE__), module: __MODULE__, line: __ENV__.line, opts: unquote(args) } ] import ESpec.ExampleHelpers import ESpec.DocTest, only: [doctest: 1, doctest: 2] import ESpec.Expect use ESpec.Expect import ESpec.Assert import ESpec.To import ESpec.Should use ESpec.Should import ESpec.AssertionHelpers import ESpec.AssertReceive import ESpec.RefuteReceive import ESpec.Allow import ESpec.BeforeAndAfterAll import ESpec.Before import ESpec.Finally import ESpec.Let import ExUnit.CaptureIO import ExUnit.CaptureLog use ESpec.DescribedModule end end defmacrop version_safe_start_capture_server do case Version.match?(System.version(), ">= 1.5.0") do true -> quote do ExUnit.CaptureServer.start_link([]) end _ -> quote do ExUnit.CaptureServer.start_link() end end end defmacro __before_compile__(_env) do quote do def examples, do: Enum.reverse(@examples) end end @doc """ Allows to set the config options. ESpec.configure(fn(config) -> config.key value config.another_key another_value end) """ def configure(func), do: ESpec.Configuration.configure(func) @doc "Runs the examples" def run do ESpec.Runner.start() ESpec.Output.start() ESpec.Runner.run() end @doc "Starts ESpec. Starts agents to store specs, mocks, cache 'let' values, etc." def start do {:ok, _} = Application.ensure_all_started(:espec) start_specs_agent() ESpec.Let.Impl.start_agent() ESpec.Mock.start_agent() start_capture_server() end @doc "Stops ESpec components" def stop do stop_specs_agent() ESpec.Let.Impl.stop_agent() ESpec.Mock.stop_agent() ESpec.Runner.stop() ESpec.Output.stop() stop_capture_server() end @doc "Returns all examples." def specs, do: Agent.get(@spec_agent_name, & &1) @doc "Adds example to the agent." def add_spec(module), do: Agent.update(@spec_agent_name, &[module | &1]) defp start_specs_agent, do: Agent.start_link(fn -> [] end, name: @spec_agent_name) def stop_specs_agent, do: Agent.stop(@spec_agent_name) defp start_capture_server do if Code.ensure_loaded?(ExUnit.CaptureServer) do unless GenServer.whereis(ExUnit.CaptureServer), do: version_safe_start_capture_server() end end defp stop_capture_server do if Code.ensure_loaded?(ExUnit.CaptureServer) do if GenServer.whereis(ExUnit.CaptureServer), do: GenServer.stop(ExUnit.CaptureServer) end end end