defmodule Mix.Tasks.ExUnitJumpstart do @moduledoc false @app :ex_unit_jumpstart @doc "Generate cfg from mix.exs and app config" @spec parse_args(OptionParser.argv()) :: Keyword.t() def parse_args(argv) do opts = [strict: [version: :string]] {overrides, _} = OptionParser.parse!(argv, opts) user_config = Keyword.merge(Application.get_all_env(@app), overrides) mix_config = Mix.Project.config() create_config(mix_config, user_config) end @doc "Generate cfg based on params" @spec create_config(Keyword.t(), Keyword.t()) :: Keyword.t() def create_config(mix_config, user_config) do defaults = [ test_dir: "test", code_dir: "lib", template_dir: "priv/templates" ] # Override values from user config cfg = Keyword.merge(defaults, user_config) # Calculate values from other things Keyword.merge( [ test_dir: cfg[:test_dir], code_dir: cfg[:code_dir] ], cfg ) end # Expand cfg vars in keys @doc false @spec expand_keys(Keyword.t(), list(atom)) :: Keyword.t() def expand_keys(cfg, keys) do Enum.reduce(Keyword.take(cfg, keys), cfg, fn {key, value}, acc -> Keyword.put(acc, key, expand_value(value, acc)) end) end # Expand vars in value or list of values @doc false @spec expand_value(atom | binary | list, Keyword.t()) :: binary | list(binary) def expand_value(values, cfg) when is_list(values) do Enum.map(values, &expand_vars(&1, cfg)) end def expand_value(value, cfg), do: expand_vars(value, cfg) # Expand references in values @doc false @spec expand_vars(binary | nil | atom | list, Keyword.t()) :: binary def expand_vars(value, _cfg) when is_binary(value), do: value def expand_vars(nil, _cfg), do: "" def expand_vars(key, cfg) when is_atom(key) do case Keyword.fetch(cfg, key) do {:ok, value} -> expand_vars(value, cfg) :error -> to_string(key) end end def expand_vars(terms, cfg) when is_list(terms) do terms |> Enum.map(&expand_vars(&1, cfg)) |> Enum.join("") end def expand_vars(value, _cfg), do: to_string(value) end defmodule Mix.Tasks.ExUnitJumpstart.Init do @moduledoc """ Initialize template files. ## Command line options * `--test_dir` - target directory ## Usage # Copy default templates into your project mix ex_unit_jumpstart.init """ @shortdoc "Initialize template files" use Mix.Task @app :ex_unit_jumpstart @impl Mix.Task def run(args) do cfg = Mix.Tasks.ExUnitJumpstart.parse_args(args) template_dir = cfg[:template_dir] app_dir = Application.app_dir(@app, ["priv", "templates"]) IO.puts("Copying templates to #{template_dir}") :ok = File.mkdir_p(template_dir) {:ok, _files} = File.cp_r(app_dir, template_dir) end end defmodule Mix.Tasks.ExUnitJumpstart.Generate do @moduledoc """ Create ExUnitJumpstart test files and update existing ones. ## Usage mix ex_unit_jumpstart.generate """ @shortdoc "Create ExUnitJumpstart scripts and files" use Mix.Task alias MixExUnitJumpstart.Templates @impl Mix.Task def run(args) do cfg = Mix.Tasks.ExUnitJumpstart.parse_args(args) code_files = ExUnitJumpstart.GetCodeFiles.get_code_files(cfg) test_files = ExUnitJumpstart.GetTestFiles.get_test_files(cfg) ExUnitJumpstart.MoveFiles.move_misplaced_test_files(cfg, code_files, test_files) ExUnitJumpstart.CreateFiles.create_missing_test_files(cfg, code_files, test_files) # refetch test files after moving and creating test_files = ExUnitJumpstart.GetTestFiles.get_test_files(cfg) ExUnitJumpstart.UnitTestGenerator.create_unit_tests(cfg, code_files, test_files) end # defp write_template(cfg, dest_dir, template), # do: write_template(cfg, dest_dir, template, template) # defp write_template(cfg, dest_dir, template, file) do # output_file = cfg[:target_prefix] <> file # # target_file = Path.join(dest_dir, output_file) # # Mix.shell.info "Generating #{target_file} from template #{template}" # Templates.write_template(cfg, dest_dir, template, output_file) # end end