Просмотр исходного кода

feat(mix eunit): add support for filtering test cases

Thales Macedo Garitezi 1 год назад
Родитель
Сommit
9a003ee3cf
1 измененных файлов с 74 добавлено и 4 удалено
  1. 74 4
      lib/mix/tasks/emqx.eunit.ex

+ 74 - 4
lib/mix/tasks/emqx.eunit.ex

@@ -1,7 +1,11 @@
 defmodule Mix.Tasks.Emqx.Eunit do
   use Mix.Task
 
-  # Code.require_file("emqx.ct.ex", __DIR__)
+  alias EMQXUmbrella.MixProject, as: UMP
+
+  if UMP.new_mix_build?() do
+    Code.require_file("emqx.ct.ex", __DIR__)
+  end
 
   alias Mix.Tasks.Emqx.Ct, as: ECt
 
@@ -29,7 +33,9 @@ defmodule Mix.Tasks.Emqx.Eunit do
     |> String.replace_suffix("-test", "")
     |> then(& System.put_env("PROFILE", &1))
 
-    discover_tests()
+    args
+    |> parse_args!()
+    |> discover_tests()
     |> :eunit.test(
       verbose: true,
       print_depth: 100
@@ -50,9 +56,73 @@ defmodule Mix.Tasks.Emqx.Eunit do
     |> :code.add_path(:cache)
   end
 
-  ## TODO: allow filtering modules and test names
-  defp discover_tests() do
+  defp parse_args!(args) do
+    {opts, _rest} = OptionParser.parse!(
+      args,
+      strict: [
+        cases: :string,
+        modules: :string,
+      ]
+    )
+    cases =
+      opts
+      |> get_name_list(:cases)
+      |> Enum.flat_map(&resolve_test_fns!/1)
+    modules =
+      opts
+      |> get_name_list(:modules)
+      |> Enum.map(&String.to_atom/1)
+
+    %{
+      cases: cases,
+      modules: modules,
+    }
+  end
+
+  defp get_name_list(opts, key) do
+    opts
+    |> Keyword.get(key, "")
+    |> String.split(",", trim: true)
+  end
+
+  defp resolve_test_fns!(mod_fn_str) do
+    {mod, fun} = case String.split(mod_fn_str, ":") do
+                   [mod, fun] ->
+                     {String.to_atom(mod), String.to_atom(fun)}
+                   _ ->
+                     Mix.raise("Bad test case spec; must of `MOD:FUN` form.  Got: #{mod_fn_str}`")
+                 end
+    if not has_test_case?(mod, fun) do
+      Mix.raise("Module #{mod} does not export test case #{fun}")
+    end
+
+    if to_string(fun) =~ ~r/_test_$/ do
+      apply(mod, fun, [])
+    else
+      [Function.capture(mod, fun, 0)]
+    end
+  end
+
+  defp has_test_case?(mod, fun) do
+    try do
+      mod.module_info(:functions)
+      |> Enum.find(& &1 == {fun, 0})
+      |> then(& !! &1)
+    rescue
+      UndefinedFunctionError -> false
+    end
+  end
+
+  defp discover_tests(%{cases: [], modules: []} = _opts) do
     Mix.Dep.Umbrella.cached()
     |> Enum.map(& {:application, &1.app})
   end
+  defp discover_tests(%{cases: cases, modules: modules}) do
+    Enum.concat(
+      [
+        cases,
+        Enum.map(modules, & {:module, &1})
+      ]
+    )
+  end
 end