diff --git a/lib/parameter/field.ex b/lib/parameter/field.ex index bae49c6..507ffec 100644 --- a/lib/parameter/field.ex +++ b/lib/parameter/field.ex @@ -172,7 +172,7 @@ defmodule Parameter.Field do :ok end - defp function_valid?(_validator, _arity, message) do - {:error, message} + defp function_valid?(_validator, arity, message) do + {:error, "#{message} with #{arity} arity"} end end diff --git a/lib/parameter/types.ex b/lib/parameter/types.ex index 0bde201..b3e8b45 100644 --- a/lib/parameter/types.ex +++ b/lib/parameter/types.ex @@ -64,6 +64,7 @@ defmodule Parameter.Types do @spec assoc_type?(any) :: boolean def assoc_type?({type, _}), do: type in @assoc_types + def assoc_type?(_), do: false @types_mod %{ any: Parameter.Types.Any, @@ -128,7 +129,7 @@ defmodule Parameter.Types do end def validate({:map, _inner_type}, _values) do - {:error, "invalid array type"} + {:error, "invalid map type"} end def validate({:has_one, inner_type}, values) when is_map(values) do diff --git a/lib/parameter/types/boolean.ex b/lib/parameter/types/boolean.ex index a11e4ad..8ee3c7b 100644 --- a/lib/parameter/types/boolean.ex +++ b/lib/parameter/types/boolean.ex @@ -9,9 +9,15 @@ defmodule Parameter.Types.Boolean do loads boolean type ## Examples + iex> Parameter.Types.Boolean.load(true) + {:ok, true} + iex> Parameter.Types.Boolean.load("true") {:ok, true} + iex> Parameter.Types.Boolean.load("True") + {:ok, true} + iex> Parameter.Types.Boolean.load("false") {:ok, false} diff --git a/lib/parameter/types/float.ex b/lib/parameter/types/float.ex index 7508704..f9dd246 100644 --- a/lib/parameter/types/float.ex +++ b/lib/parameter/types/float.ex @@ -5,6 +5,25 @@ defmodule Parameter.Types.Float do use Parameter.Parametrizable + @doc """ + loads float type + + ## Examples + iex> Parameter.Types.Float.load(1.5) + {:ok, 1.5} + + iex> Parameter.Types.Float.load("2.5") + {:ok, 2.5} + + iex> Parameter.Types.Float.load(1) + {:ok, 1.0} + + iex> Parameter.Types.Float.load("not float") + {:error, "invalid float type"} + + iex> Parameter.Types.Float.load(:atom) + {:error, "invalid float type"} + """ @impl true def load(value) when is_float(value) do {:ok, value} diff --git a/lib/parameter/types/naive_datetime.ex b/lib/parameter/types/naive_datetime.ex index b2257fd..dc33035 100644 --- a/lib/parameter/types/naive_datetime.ex +++ b/lib/parameter/types/naive_datetime.ex @@ -5,6 +5,25 @@ defmodule Parameter.Types.NaiveDateTime do use Parameter.Parametrizable + @doc """ + loads NaiveDateTime type + + ## Examples + iex> Parameter.Types.NaiveDateTime.load(~N[2000-01-01 23:00:07]) + {:ok, ~N[2000-01-01 23:00:07]} + + iex> Parameter.Types.NaiveDateTime.load("2000-01-01 22:00:07") + {:ok, ~N[2000-01-01 22:00:07]} + + iex> Parameter.Types.NaiveDateTime.load({{2021, 05, 11}, {22, 30, 10}}) + {:ok, ~N[2021-05-11 22:30:10]} + + iex> Parameter.Types.NaiveDateTime.load({{2021, 25, 11}, {22, 30, 10}}) + {:error, "invalid naive_datetime type"} + + iex> Parameter.Types.NaiveDateTime.load("2015-25-23") + {:error, "invalid naive_datetime type"} + """ @impl true def load(%NaiveDateTime{} = value) do {:ok, value} diff --git a/test/parameter/field_test.exs b/test/parameter/field_test.exs index 8b1fd05..c76d47b 100644 --- a/test/parameter/field_test.exs +++ b/test/parameter/field_test.exs @@ -36,6 +36,30 @@ defmodule Parameter.FieldTest do assert {:error, "invalid float type"} == Field.new(opts) end + test "fails if name is not an atom" do + opts = [ + name: "main_address", + type: :float, + key: "mainAddress", + required: true, + default: "Hello" + ] + + assert {:error, "invalid atom type"} == Field.new(opts) + end + + test "fails on invalid function" do + opts = [ + name: :address, + type: :float, + on_load: fn val -> val end, + key: "mainAddress", + required: true + ] + + assert {:error, "on_load must be a function with 2 arity"} == Field.new(opts) + end + test "fails if a default value used at the sametime with load_default and dump_default" do opts = [ name: :main_address, diff --git a/test/parameter/schema_test.exs b/test/parameter/schema_test.exs index 5f9f382..3dac565 100644 --- a/test/parameter/schema_test.exs +++ b/test/parameter/schema_test.exs @@ -107,6 +107,30 @@ defmodule Parameter.SchemaTest do end end + describe "fields/1" do + import Parameter.Schema + + param ModuleSchema do + field :first_name, :string + end + + test "module schema schema fields" do + assert [%Parameter.Field{}] = Schema.fields(__MODULE__.ModuleSchema) + end + + test "runtime schema fields" do + schema = + %{ + first_name: [key: "firstName", type: :string, required: true], + address: [required: true, type: {:has_one, %{street: [type: :string, required: true]}}], + phones: [type: {:has_many, %{country: [type: :string, required: true]}}] + } + |> Schema.compile!() + + assert [%Parameter.Field{}, %Parameter.Field{}, %Parameter.Field{}] = Schema.fields(schema) + end + end + defp from_name(parameters, name) do Enum.find(parameters, &(&1.name == name)) end diff --git a/test/parameter/types/float_test.exs b/test/parameter/types/float_test.exs new file mode 100644 index 0000000..c954d59 --- /dev/null +++ b/test/parameter/types/float_test.exs @@ -0,0 +1,4 @@ +defmodule Parameter.Types.FloatTest do + use ExUnit.Case + doctest Parameter.Types.Float +end diff --git a/test/parameter/types/naive_datetime_test.exs b/test/parameter/types/naive_datetime_test.exs new file mode 100644 index 0000000..dfa3aea --- /dev/null +++ b/test/parameter/types/naive_datetime_test.exs @@ -0,0 +1,4 @@ +defmodule Parameter.Types.NaiveDateTimeTest do + use ExUnit.Case + doctest Parameter.Types.NaiveDateTime +end diff --git a/test/parameter/types_test.exs b/test/parameter/types_test.exs index bed4c59..c9d3dd4 100644 --- a/test/parameter/types_test.exs +++ b/test/parameter/types_test.exs @@ -9,6 +9,24 @@ defmodule Parameter.TypesTest do enum values: [:user_online, :user_offline] end + test "base_type?/1" do + assert Types.base_type?(:any) + refute Types.base_type?(:not_type) + end + + test "composite_inner_type?/1" do + assert Types.composite_inner_type?({:array, :any}) + assert Types.composite_inner_type?({:map, :not_type}) + refute Types.composite_inner_type?(:not_type) + end + + test "assoc_type?/1" do + assert Types.assoc_type?({:has_one, :any}) + assert Types.assoc_type?({:has_many, :any}) + refute Types.assoc_type?({:map, :not_type}) + refute Types.assoc_type?(:not_type) + end + describe "load/2" do test "load any type" do assert Types.load(:any, "Test") == {:ok, "Test"} @@ -354,5 +372,37 @@ defmodule Parameter.TypesTest do assert Types.validate({:has_one, :float}, "21") == {:error, "invalid inner data type"} end + + test "validate map with inner type" do + assert Types.validate({:map, :string}, %{}) == :ok + assert Types.validate({:map, :string}, %{key: "value", other_key: "other value"}) == :ok + + assert Types.validate({:map, :string}, %{key: "value", other_key: 22}) == + {:error, "invalid string type"} + + assert Types.validate({:map, :float}, "21") == {:error, "invalid map type"} + assert Types.validate({:map, {:array, :float}}, "21") == {:error, "invalid map type"} + assert Types.validate({:map, {:array, :float}}, %{k: [1.5]}) == :ok + end + + test "validate array with inner type" do + assert Types.validate({:array, :string}, []) == :ok + assert Types.validate({:array, :string}, ["value", "other value"]) == :ok + + assert Types.validate({:array, :float}, ["value", "other value"]) == + {:error, "invalid float type"} + + assert Types.validate({:array, :float}, "21") == {:error, "invalid array type"} + assert Types.validate({:array, {:array, :float}}, "21") == {:error, "invalid array type"} + assert Types.validate({:array, {:array, :float}}, [[1.5, 5.5], [1.2]]) == :ok + end + end + + test "validate!/2" do + assert Types.validate!(:any, %{}) == :ok + + assert_raise ArgumentError, "invalid inner data type", fn -> + Types.validate!({:has_one, :float}, "21") == {:error, "invalid inner data type"} + end end end