From db5e754d861c022ea336528f4444e4fa55f41fc7 Mon Sep 17 00:00:00 2001
From: Sloane Perrault <sloane@perrault.email>
Date: Sun, 2 Jul 2023 08:19:23 -0400
Subject: [PATCH] modify to catch invalid specs

---
 lib/type_id.ex         |  5 ++++-
 lib/type_id/base_32.ex |  6 ++++++
 test/spec_test.exs     | 20 ++++++++++++++++----
 3 files changed, 26 insertions(+), 5 deletions(-)

diff --git a/lib/type_id.ex b/lib/type_id.ex
index 874e360..c3e2708 100644
--- a/lib/type_id.ex
+++ b/lib/type_id.ex
@@ -147,11 +147,14 @@ defmodule TypeID do
   @spec from_string!(String.t()) :: t() | no_return()
   def from_string!(str) do
     case String.split(str, "_") do
-      [prefix, suffix] ->
+      [prefix, suffix] when prefix != "" ->
         from!(prefix, suffix)
 
       [suffix] ->
         from!("", suffix)
+
+      _ -> 
+        raise ArgumentError, "invalid TypeID"
     end
   end
 
diff --git a/lib/type_id/base_32.ex b/lib/type_id/base_32.ex
index 34804f5..5efd537 100644
--- a/lib/type_id/base_32.ex
+++ b/lib/type_id/base_32.ex
@@ -20,6 +20,8 @@ defmodule TypeID.Base32 do
       do_encode(c23)::8, do_encode(c24)::8, do_encode(c25)::8, do_encode(c26)::8>>
   end
 
+  def encode(_), do: :error
+
   @spec decode(binary()) :: {:ok, binary()} | :error
   def decode(string) when is_binary(string) do
     {:ok, decode!(string)}
@@ -40,6 +42,10 @@ defmodule TypeID.Base32 do
       do_decode(c23)::5, do_decode(c24)::5, do_decode(c25)::5, do_decode(c26)::5>>
   end
 
+  def decode!(_) do
+    raise ArgumentError, "invalid base 32 suffix"
+  end
+
   @compile {:inline, [do_encode: 1]}
   defp do_encode(byte) do
     elem({unquote_splicing(crockford_alphabet)}, byte)
diff --git a/test/spec_test.exs b/test/spec_test.exs
index 024504b..126e04f 100644
--- a/test/spec_test.exs
+++ b/test/spec_test.exs
@@ -1,8 +1,15 @@
 defmodule TypeID.SpecTest do
   use ExUnit.Case
 
-  @valid_specs :code.priv_dir(:typeid_elixir)
-               |> Path.join("spec/valid.yml")
+  specs_path = :code.priv_dir(:typeid_elixir)
+               |> Path.join("/spec")
+
+  @valid_specs specs_path
+               |> Path.join("/valid.yml")
+               |> YamlElixir.read_from_file!()
+
+  @invalid_specs specs_path
+               |> Path.join("/invalid.yml")
                |> YamlElixir.read_from_file!()
 
   describe "valid" do
@@ -15,6 +22,11 @@ defmodule TypeID.SpecTest do
     end
   end
 
-  # describe "invalid" do
-  # end
+  describe "invalid" do
+    for %{"name" => name, "typeid" => typeid, "description" => desc } <- @invalid_specs do
+      test "#{name}: #{desc}" do
+        assert :error = TypeID.from_string(unquote(typeid))
+      end
+    end
+  end
 end