Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions lib/nimble_options.ex
Original file line number Diff line number Diff line change
Expand Up @@ -601,8 +601,8 @@ defmodule NimbleOptions do
end
end

defp validate_type(:integer, key, value, redact) when not is_integer(value) do
structured_error_tuple(key, value, "integer", redact)
defp validate_type(:integer = type, key, value, redact) when not is_integer(value) do
structured_error_tuple(key, value, {:type, type}, "integer", redact)
end

defp validate_type(:non_neg_integer, key, value, redact)
Expand Down Expand Up @@ -1019,19 +1019,31 @@ defmodule NimbleOptions do
{:error, %ValidationError{key: key, message: message, redact: redact, value: value}}
end

# FIX: remove after error types are implemented
defp structured_error_tuple(key, value, expected, redact?) do
structured_error_tuple(key, value, expected, inspect(value), redact?)
structured_error_tuple(key, value, false, expected, redact?)
end

defp structured_error_tuple(key, value, expected, got, redact?) do
defp structured_error_tuple(key, value, type, expected, redact?) do
structured_error_tuple(key, value, type, expected, inspect(value), redact?)
end

defp structured_error_tuple(key, value, validation, expected, got, redact?) do
message =
if redact? do
"invalid value for #{render_key(key)}: expected #{expected}"
else
"invalid value for #{render_key(key)}: expected #{expected}, got: #{got}"
end

{:error, %ValidationError{key: key, message: message, redact: redact?, value: value}}
{:error,
%ValidationError{
key: key,
message: message,
redact: redact?,
value: value,
validation: validation
}}
end

defp render_key({__MODULE__, :key}), do: "map key"
Expand Down
5 changes: 4 additions & 1 deletion lib/nimble_options/validation_error.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ defmodule NimbleOptions.ValidationError do
key: atom(),
keys_path: [atom()],
redact: boolean,
validation: :required | {:type, term()},
value: term()
}

Expand All @@ -28,8 +29,10 @@ defmodule NimbleOptions.ValidationError do
* `:value` (`t:term/0`) - The value that failed to validate. This field is `nil` if there
was no value provided.

* `:validation` (`:required` or `{:type, type}`) - The validation that failed.

"""
defexception [:message, :key, :value, keys_path: [], redact: false]
defexception [:message, :key, :validation, :value, keys_path: [], redact: false]

@impl true
def message(%__MODULE__{message: message, keys_path: keys_path}) do
Expand Down
5 changes: 4 additions & 1 deletion test/nimble_options_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ defmodule NimbleOptionsTest do
%ValidationError{
key: :min_demand,
value: 1.5,
validation: {:type, :integer},
message: "invalid value for :min_demand option: expected integer, got: 1.5"
}}

Expand All @@ -300,6 +301,7 @@ defmodule NimbleOptionsTest do
%ValidationError{
key: :min_demand,
value: :an_atom,
validation: {:type, :integer},
message: "invalid value for :min_demand option: expected integer, got: :an_atom"
}}
end
Expand All @@ -312,6 +314,7 @@ defmodule NimbleOptionsTest do
%ValidationError{
key: :min_demand,
value: 1.5,
validation: {:type, :integer},
message: "invalid value for :min_demand option: expected integer",
redact: true
}}
Expand Down Expand Up @@ -2250,7 +2253,7 @@ defmodule NimbleOptionsTest do
end

# No other test is passing in `opts` as a map, so these are just some white box tests for sanity checking
describe "can use a map for validate/2" do
test "can use a map for validate/2" do
schema = []
opts = %{}
assert NimbleOptions.validate(opts, schema) == {:ok, %{}}
Expand Down