Repository: msz/hammox
Pull request #52 (2020-10-03 08:40:50)

Validation of behavior and implementation modules
:wave:
relates to https://github.com/msz/hammox/issues/22

saneery: @msz Hi! How can I trigger CI?
msz: Don't worry about CI, it doesn't run on PRs from forks for security
msz: I merged #51, could you rebase and resolve the conflict?

Patch:
diff --git a/lib/hammox.ex b/lib/hammox.ex
index f9eb09d..0cb3bab 100644
--- a/lib/hammox.ex
+++ b/lib/hammox.ex
@@ -127,9 +127,13 @@ defmodule Hammox do
     do: protect(module_name, module_name, funs)
 
   @spec protect(mfa :: mfa(), behaviour_name :: module()) :: fun()
-  def protect({module_name, function_name, arity}, behaviour_name)
+  def protect({module_name, function_name, arity} = mfa, behaviour_name)
       when is_atom(module_name) and is_atom(function_name) and is_integer(arity) and
              is_atom(behaviour_name) do
+    module_exist?(module_name)
+    module_exist?(behaviour_name)
+    mfa_exist?(mfa)
+
     code = {module_name, function_name}
 
     typespecs = fetch_typespecs!(behaviour_name, function_name, arity)
@@ -372,4 +376,32 @@ defmodule Hammox do
     {:type, _, :fun, [{:type, _, :product, arg_typespecs}, _]} = function_typespec
     Enum.at(arg_typespecs, arg_index)
   end
+
+  defp module_exist?(module_name) do
+    case Code.ensure_compiled(module_name) do
+      {:module, _} ->
+        true
+
+      _ ->
+        raise(ArgumentError,
+          message:
+            "Could not find module #{Utils.module_to_string(module_name)}."
+        )
+    end
+  end
+
+  defp mfa_exist?({module_name, function_name, arity}) do
+    case function_exported?(module_name, function_name, arity) do
+      true ->
+        true
+
+      _ ->
+        raise(ArgumentError,
+          message:
+            "Could not find function #{Utils.module_to_string(module_name)}.#{function_name}/#{
+              arity
+            }."
+        )
+    end
+  end
 end


Test patch:
diff --git a/test/hammox_test.exs b/test/hammox_test.exs
index 84319ad..bc40bb8 100644
--- a/test/hammox_test.exs
+++ b/test/hammox_test.exs
@@ -14,7 +14,34 @@ defmodule HammoxTest do
     test "throws when typespec does not exist" do
       assert_raise(Hammox.TypespecNotFoundError, fn ->
         Hammox.protect(
-          {Hammox.Test.SmallImplementation, :nonexistent_fuc, 0},
+          {Hammox.Test.SmallImplementation, :nospec_fun, 0},
+          Hammox.Test.SmallBehaviour
+        )
+      end)
+    end
+
+    test "throws when behaviour module does not exist" do
+      assert_raise(ArgumentError, fn ->
+        Hammox.protect(
+          {Hammox.Test.SmallImplementation, :foo, 0},
+          NotExistModule
+        )
+      end)
+    end
+
+    test "throws when implementation module does not exist" do
+      assert_raise(ArgumentError, fn ->
+        Hammox.protect(
+          {NotExistModule, :foo, 0},
+          Hammox.Test.SmallBehaviour
+        )
+      end)
+    end
+
+    test "throws when implementation function does not exist" do
+      assert_raise(ArgumentError, fn ->
+        Hammox.protect(
+          {Hammox.Test.SmallImplementation, :nonexistent_fun, 0},
           Hammox.Test.SmallBehaviour
         )
       end)
diff --git a/test/support/small_implementation.ex b/test/support/small_implementation.ex
index b9b488d..8a70808 100644
--- a/test/support/small_implementation.ex
+++ b/test/support/small_implementation.ex
@@ -11,4 +11,8 @@ defmodule Hammox.Test.SmallImplementation do
   def other_foo(_) do
     1
   end
+
+  def nospec_fun() do
+    1
+  end
 end