Page MenuHomePhorge

No OneTemporary

Size
26 KB
Referenced Files
None
Subscribers
None
diff --git a/lib/open_api_spex/cast.ex b/lib/open_api_spex/cast.ex
index c68fa7b..5097a47 100644
--- a/lib/open_api_spex/cast.ex
+++ b/lib/open_api_spex/cast.ex
@@ -1,58 +1,73 @@
defmodule OpenApiSpex.Cast do
alias OpenApiSpex.Reference
- alias OpenApiSpex.Cast.{Array, Context, Object, Primitive}
+ alias OpenApiSpex.Cast.{Array, Error, Object, Primitive}
@primitives [:boolean, :integer, :number, :string]
+ defstruct value: nil,
+ schema: nil,
+ schemas: %{},
+ path: [],
+ key: nil,
+ index: 0,
+ errors: []
+
def cast(schema, value, schemas) do
- ctx = %Context{schema: schema, value: value, schemas: schemas}
+ ctx = %__MODULE__{schema: schema, value: value, schemas: schemas}
cast(ctx)
end
# nil schema
- def cast(%Context{value: value, schema: nil}),
+ def cast(%__MODULE__{value: value, schema: nil}),
do: {:ok, value}
- def cast(%Context{schema: %Reference{}} = ctx) do
+ def cast(%__MODULE__{schema: %Reference{}} = ctx) do
schema = Reference.resolve_schema(ctx.schema, ctx.schemas)
cast(%{ctx | schema: schema})
end
# nullable: true
- def cast(%Context{value: nil, schema: %{nullable: true}}) do
+ def cast(%__MODULE__{value: nil, schema: %{nullable: true}}) do
{:ok, nil}
end
# nullable: false
- def cast(%Context{value: nil} = ctx) do
- Context.error(ctx, {:null_value})
+ def cast(%__MODULE__{value: nil} = ctx) do
+ error(ctx, {:null_value})
end
# Enum
- def cast(%Context{schema: %{enum: []}} = ctx) do
+ def cast(%__MODULE__{schema: %{enum: []}} = ctx) do
cast(%{ctx | enum: nil})
end
# Enum
- def cast(%Context{schema: %{enum: enum}} = ctx) when is_list(enum) do
+ def cast(%__MODULE__{schema: %{enum: enum}} = ctx) when is_list(enum) do
with {:ok, value} <- cast(%{ctx | schema: %{ctx.schema | enum: nil}}) do
if value in enum do
{:ok, value}
else
- Context.error(ctx, {:invalid_enum})
+ error(ctx, {:invalid_enum})
end
end
end
## Specific types
- def cast(%Context{schema: %{type: type}} = ctx) when type in @primitives,
+ def cast(%__MODULE__{schema: %{type: type}} = ctx) when type in @primitives,
do: Primitive.cast(ctx)
- def cast(%Context{schema: %{type: :array}} = ctx),
+ def cast(%__MODULE__{schema: %{type: :array}} = ctx),
do: Array.cast(ctx)
- def cast(%Context{schema: %{type: :object}} = ctx),
+ def cast(%__MODULE__{schema: %{type: :object}} = ctx),
do: Object.cast(ctx)
- def cast(%{} = ctx), do: cast(struct(Context, ctx))
+ def cast(%{} = ctx), do: cast(struct(__MODULE__, ctx))
+ def cast(ctx) when is_list(ctx), do: cast(struct(__MODULE__, ctx))
+
+ # Add an error
+ def error(ctx, error_args) do
+ error = Error.new(ctx, error_args)
+ {:error, [error | ctx.errors]}
+ end
end
diff --git a/lib/open_api_spex/cast/array.ex b/lib/open_api_spex/cast/array.ex
index 0bfc2d7..8f526a3 100644
--- a/lib/open_api_spex/cast/array.ex
+++ b/lib/open_api_spex/cast/array.ex
@@ -1,39 +1,38 @@
defmodule OpenApiSpex.Cast.Array do
@moduledoc false
alias OpenApiSpex.Cast
- alias OpenApiSpex.Cast.Context
@spec cast(atom() | %{value: any()}) ::
{:error, nonempty_maybe_improper_list()} | {:ok, [any()]}
def cast(%{value: []}), do: {:ok, []}
def cast(%{value: items} = ctx) when is_list(items) do
case cast_items(ctx) do
{items, []} -> {:ok, items}
{_, errors} -> {:error, errors}
end
end
def cast(ctx),
- do: Context.error(ctx, {:invalid_type, :array})
+ do: Cast.error(ctx, {:invalid_type, :array})
## Private functions
defp cast_items(%{value: items} = ctx) do
cast_results =
items
|> Enum.with_index()
|> Enum.map(fn {item, index} ->
path = [index | ctx.path]
Cast.cast(%{ctx | value: item, schema: ctx.schema.items, path: path})
end)
errors =
for({:error, errors} <- cast_results, do: errors)
|> Enum.concat()
items = for {:ok, item} <- cast_results, do: item
{items, errors}
end
end
diff --git a/lib/open_api_spex/cast/context.ex b/lib/open_api_spex/cast/context.ex
deleted file mode 100644
index 21dcf1e..0000000
--- a/lib/open_api_spex/cast/context.ex
+++ /dev/null
@@ -1,16 +0,0 @@
-defmodule OpenApiSpex.Cast.Context do
- alias OpenApiSpex.Cast.Error
-
- defstruct value: nil,
- schema: nil,
- schemas: %{},
- path: [],
- key: nil,
- index: 0,
- errors: []
-
- def error(ctx, error_args) do
- error = Error.new(ctx, error_args)
- {:error, [error | ctx.errors]}
- end
-end
diff --git a/lib/open_api_spex/cast/object.ex b/lib/open_api_spex/cast/object.ex
index 98432d1..fe432ee 100644
--- a/lib/open_api_spex/cast/object.ex
+++ b/lib/open_api_spex/cast/object.ex
@@ -1,94 +1,94 @@
defmodule OpenApiSpex.Cast.Object do
@moduledoc false
alias OpenApiSpex.Cast
- alias OpenApiSpex.Cast.{Error, Context}
+ alias OpenApiSpex.Cast.Error
def cast(%{value: value} = ctx) when not is_map(value) do
- Context.error(ctx, {:invalid_type, :object})
+ Cast.error(ctx, {:invalid_type, :object})
end
def cast(%{value: value, schema: %{properties: nil}}) do
{:ok, value}
end
def cast(%{value: value, schema: schema} = ctx) do
schema_properties = schema.properties || %{}
with :ok <- check_unrecognized_properties(ctx, schema_properties),
value = cast_atom_keys(value, schema_properties),
ctx = %{ctx | value: value},
:ok <- check_required_fields(ctx, schema),
{:ok, value} <- cast_properties(%{ctx | schema: schema_properties}) do
ctx = to_struct(%{ctx | value: value})
{:ok, ctx}
end
end
defp check_unrecognized_properties(%{value: value} = ctx, expected_keys) do
input_keys = value |> Map.keys() |> Enum.map(&to_string/1)
schema_keys = expected_keys |> Map.keys() |> Enum.map(&to_string/1)
extra_keys = input_keys -- schema_keys
if extra_keys == [] do
:ok
else
[name | _] = extra_keys
- Context.error(ctx, {:unexpected_field, name})
+ Cast.error(ctx, {:unexpected_field, name})
end
end
defp check_required_fields(%{value: input_map} = ctx, schema) do
required = schema.required || []
input_keys = Map.keys(input_map)
missing_keys = required -- input_keys
if missing_keys == [] do
:ok
else
errors =
Enum.map(missing_keys, fn key ->
ctx = %{ctx | path: [key | ctx.path]}
Error.new(ctx, {:missing_field, key})
end)
{:error, ctx.errors ++ errors}
end
end
defp cast_atom_keys(input_map, properties) do
Enum.reduce(properties, %{}, fn {key, _}, output ->
string_key = to_string(key)
case input_map do
%{^key => value} -> Map.put(output, key, value)
%{^string_key => value} -> Map.put(output, key, value)
_ -> output
end
end)
end
defp cast_properties(%{value: object, schema: schema_properties} = ctx) do
Enum.reduce(object, {:ok, %{}}, fn
{key, value}, {:ok, output} ->
cast_property(%{ctx | key: key, value: value, schema: schema_properties}, output)
_, error ->
error
end)
end
defp cast_property(%{key: key, schema: schema_properties} = ctx, output) do
prop_schema = Map.get(schema_properties, key)
path = [key | ctx.path]
with {:ok, value} <- Cast.cast(%{ctx | path: path, schema: prop_schema}) do
{:ok, Map.put(output, key, value)}
end
end
defp to_struct(%{value: value = %_{}}), do: value
defp to_struct(%{value: value, schema: %{"x-struct": nil}}), do: value
defp to_struct(%{value: value, schema: %{"x-struct": module}}),
do: struct(module, value)
end
diff --git a/lib/open_api_spex/cast/primitive.ex b/lib/open_api_spex/cast/primitive.ex
index 3afa442..c283cde 100644
--- a/lib/open_api_spex/cast/primitive.ex
+++ b/lib/open_api_spex/cast/primitive.ex
@@ -1,67 +1,68 @@
defmodule OpenApiSpex.Cast.Primitive do
@moduledoc false
- alias OpenApiSpex.Cast.{Context, String}
+ alias OpenApiSpex.Cast
+ alias OpenApiSpex.Cast.String
def cast(%{schema: %{type: :boolean}} = ctx),
do: cast_boolean(ctx)
def cast(%{schema: %{type: :integer}} = ctx),
do: cast_integer(ctx)
def cast(%{schema: %{type: :number}} = ctx),
do: cast_number(ctx)
def cast(%{schema: %{type: :string}} = ctx),
do: String.cast(ctx)
## Private functions
defp cast_boolean(%{value: value}) when is_boolean(value) do
{:ok, value}
end
defp cast_boolean(%{value: "true"}), do: {:ok, true}
defp cast_boolean(%{value: "false"}), do: {:ok, false}
defp cast_boolean(ctx) do
- Context.error(ctx, {:invalid_type, :boolean})
+ Cast.error(ctx, {:invalid_type, :boolean})
end
defp cast_integer(%{value: value}) when is_integer(value) do
{:ok, value}
end
defp cast_integer(%{value: value}) when is_number(value) do
{:ok, round(value)}
end
defp cast_integer(%{value: value} = ctx) when is_binary(value) do
case Float.parse(value) do
{value, ""} -> cast_integer(%{ctx | value: value})
- _ -> Context.error(ctx, {:invalid_type, :integer})
+ _ -> Cast.error(ctx, {:invalid_type, :integer})
end
end
defp cast_integer(ctx) do
- Context.error(ctx, {:invalid_type, :integer})
+ Cast.error(ctx, {:invalid_type, :integer})
end
defp cast_number(%{value: value}) when is_number(value) do
{:ok, value}
end
defp cast_number(%{value: value}) when is_integer(value) do
{:ok, value / 1}
end
defp cast_number(%{value: value} = ctx) when is_binary(value) do
case Float.parse(value) do
{value, ""} -> {:ok, value}
- _ -> Context.error(ctx, {:invalid_type, :number})
+ _ -> Cast.error(ctx, {:invalid_type, :number})
end
end
defp cast_number(ctx) do
- Context.error(ctx, {:invalid_type, :number})
+ Cast.error(ctx, {:invalid_type, :number})
end
end
diff --git a/lib/open_api_spex/cast/string.ex b/lib/open_api_spex/cast/string.ex
index 6f43b6b..2250025 100644
--- a/lib/open_api_spex/cast/string.ex
+++ b/lib/open_api_spex/cast/string.ex
@@ -1,40 +1,40 @@
defmodule OpenApiSpex.Cast.String do
@moduledoc false
- alias OpenApiSpex.Cast.Context
+ alias OpenApiSpex.Cast
def cast(%{value: value} = ctx) when is_binary(value) do
cast_binary(ctx)
end
def cast(ctx) do
- Context.error(ctx, {:invalid_type, :string})
+ Cast.error(ctx, {:invalid_type, :string})
end
## Private functions
defp cast_binary(%{value: value, schema: %{pattern: pattern}} = ctx) when not is_nil(pattern) do
if Regex.match?(pattern, value) do
{:ok, value}
else
- Context.error(ctx, {:invalid_format, pattern})
+ Cast.error(ctx, {:invalid_format, pattern})
end
end
defp cast_binary(%{value: value, schema: %{minLength: min_length}} = ctx)
when is_integer(min_length) do
# Note: This is not part of the JSON Shema spec: trim string before measuring length
# It's just too important to miss
trimmed = String.trim(value)
length = String.length(trimmed)
if length < min_length do
- Context.error(ctx, {:min_length, length})
+ Cast.error(ctx, {:min_length, length})
else
{:ok, value}
end
end
defp cast_binary(%{value: value}) do
{:ok, value}
end
end
diff --git a/test/cast/array_test.exs b/test/cast/array_test.exs
index 1a2463f..056f31c 100644
--- a/test/cast/array_test.exs
+++ b/test/cast/array_test.exs
@@ -1,35 +1,35 @@
defmodule OpenApiSpec.Cast.ArrayTest do
use ExUnit.Case
- alias OpenApiSpex.Cast.{Array, Context, Error}
- alias OpenApiSpex.Schema
+ alias OpenApiSpex.Cast.{Array, Error}
+ alias OpenApiSpex.{Cast, Schema}
- defp cast(map), do: Array.cast(struct(Context, map))
+ defp cast(map), do: Array.cast(struct(Cast, map))
describe "cast/4" do
test "array" do
schema = %Schema{type: :array}
assert cast(value: [], schema: schema) == {:ok, []}
assert cast(value: [1, 2, 3], schema: schema) == {:ok, [1, 2, 3]}
assert cast(value: ["1", "2", "3"], schema: schema) == {:ok, ["1", "2", "3"]}
assert {:error, [error]} = cast(value: %{}, schema: schema)
assert %Error{} = error
assert error.reason == :invalid_type
assert error.value == %{}
end
test "array with items schema" do
items_schema = %Schema{type: :integer}
schema = %Schema{type: :array, items: items_schema}
assert cast(value: [], schema: schema) == {:ok, []}
assert cast(value: [1, 2, 3], schema: schema) == {:ok, [1, 2, 3]}
assert cast(value: ["1", "2", "3"], schema: schema) == {:ok, [1, 2, 3]}
assert {:error, [error]} = cast(value: [1, "two"], schema: schema)
assert %Error{} = error
assert error.reason == :invalid_type
assert error.value == "two"
assert error.path == [1]
end
end
end
diff --git a/test/cast/object_test.exs b/test/cast/object_test.exs
index bdac17e..9345ac3 100644
--- a/test/cast/object_test.exs
+++ b/test/cast/object_test.exs
@@ -1,90 +1,90 @@
defmodule OpenApiSpex.ObjectTest do
use ExUnit.Case
- alias OpenApiSpex.Cast.{Context, Object, Error}
- alias OpenApiSpex.Schema
+ alias OpenApiSpex.{Cast, Schema}
+ alias OpenApiSpex.Cast.{Object, Error}
- defp cast(ctx), do: Object.cast(struct(Context, ctx))
+ defp cast(ctx), do: Object.cast(struct(Cast, ctx))
describe "cast/3" do
test "not an object" do
schema = %Schema{type: :object}
assert {:error, [error]} = cast(value: ["hello"], schema: schema)
assert %Error{} = error
assert error.reason == :invalid_type
assert error.value == ["hello"]
end
test "properties:nil, given unknown input property" do
schema = %Schema{type: :object}
assert cast(value: %{}, schema: schema) == {:ok, %{}}
assert cast(value: %{"unknown" => "hello"}, schema: schema) ==
{:ok, %{"unknown" => "hello"}}
end
test "with empty schema properties, given unknown input property" do
schema = %Schema{type: :object, properties: %{}}
assert cast(value: %{}, schema: schema) == {:ok, %{}}
assert {:error, [error]} = cast(value: %{"unknown" => "hello"}, schema: schema)
assert %Error{} = error
end
test "with schema properties set, given known input property" do
schema = %Schema{
type: :object,
properties: %{age: nil}
}
assert cast(value: %{}, schema: schema) == {:ok, %{}}
assert cast(value: %{"age" => "hello"}, schema: schema) == {:ok, %{age: "hello"}}
end
test "required fields" do
schema = %Schema{
type: :object,
properties: %{age: nil, name: nil},
required: [:age, :name]
}
assert {:error, [error, error2]} = cast(value: %{}, schema: schema)
assert %Error{} = error
assert error.reason == :missing_field
assert error.name == :age
assert error.path == [:age]
assert error2.reason == :missing_field
assert error2.name == :name
assert error2.path == [:name]
end
test "cast property against schema" do
schema = %Schema{
type: :object,
properties: %{age: %Schema{type: :integer}}
}
assert cast(value: %{}, schema: schema) == {:ok, %{}}
assert {:error, [error]} = cast(value: %{"age" => "hello"}, schema: schema)
assert %Error{} = error
assert error.reason == :invalid_type
assert error.path == [:age]
end
defmodule User do
defstruct [:name]
end
test "optionally casts to struct" do
schema = %Schema{
type: :object,
"x-struct": User,
properties: %{
name: %Schema{type: :string}
}
}
assert {:ok, user} = cast(value: %{"name" => "Name"}, schema: schema)
assert user == %User{name: "Name"}
end
end
end
diff --git a/test/cast/primitive_test.exs b/test/cast/primitive_test.exs
index b89e38f..3fcff0d 100644
--- a/test/cast/primitive_test.exs
+++ b/test/cast/primitive_test.exs
@@ -1,52 +1,52 @@
defmodule OpenApiSpex.PrimitiveTest do
use ExUnit.Case
- alias OpenApiSpex.Cast.{Context, Primitive, Error}
- alias OpenApiSpex.Schema
+ alias OpenApiSpex.{Cast, Schema}
+ alias OpenApiSpex.Cast.{Primitive, Error}
- defp cast(ctx), do: Primitive.cast(struct(Context, ctx))
+ defp cast(ctx), do: Primitive.cast(struct(Cast, ctx))
describe "cast/3" do
test "boolean" do
schema = %Schema{type: :boolean}
assert cast(value: true, schema: schema) == {:ok, true}
assert cast(value: false, schema: schema) == {:ok, false}
assert cast(value: "true", schema: schema) == {:ok, true}
assert cast(value: "false", schema: schema) == {:ok, false}
assert {:error, [error]} = cast(value: "other", schema: schema)
assert %Error{reason: :invalid_type} = error
assert error.value == "other"
end
test "integer" do
schema = %Schema{type: :integer}
assert cast(value: 1, schema: schema) == {:ok, 1}
assert cast(value: 1.5, schema: schema) == {:ok, 2}
assert cast(value: "1", schema: schema) == {:ok, 1}
assert cast(value: "1.5", schema: schema) == {:ok, 2}
assert {:error, [error]} = cast(value: "other", schema: schema)
assert %Error{reason: :invalid_type} = error
assert error.value == "other"
end
test "number" do
schema = %Schema{type: :number}
assert cast(value: 1, schema: schema) == {:ok, 1.0}
assert cast(value: 1.5, schema: schema) == {:ok, 1.5}
assert cast(value: "1", schema: schema) == {:ok, 1.0}
assert cast(value: "1.5", schema: schema) == {:ok, 1.5}
assert {:error, [error]} = cast(value: "other", schema: schema)
assert %Error{reason: :invalid_type} = error
assert error.value == "other"
end
# Additional string tests are covered in CastStringTest
test "string" do
schema = %Schema{type: :string}
assert cast(value: "hello", schema: schema) == {:ok, "hello"}
assert cast(value: "", schema: schema) == {:ok, ""}
assert {:error, [error]} = cast(value: %{}, schema: schema)
assert %Error{reason: :invalid_type} = error
assert error.value == %{}
end
end
end
diff --git a/test/cast/string_test.exs b/test/cast/string_test.exs
index cabd59a..790e36b 100644
--- a/test/cast/string_test.exs
+++ b/test/cast/string_test.exs
@@ -1,35 +1,35 @@
defmodule OpenApiSpex.CastStringTest do
use ExUnit.Case
- alias OpenApiSpex.Cast.{Context, Error, String}
- alias OpenApiSpex.Schema
+ alias OpenApiSpex.{Cast, Schema}
+ alias OpenApiSpex.Cast.{Error, String}
- defp cast(ctx), do: String.cast(struct(Context, ctx))
+ defp cast(ctx), do: String.cast(struct(Cast, ctx))
describe "cast/1" do
test "basics" do
schema = %Schema{type: :string}
assert cast(value: "hello", schema: schema) == {:ok, "hello"}
assert cast(value: "", schema: schema) == {:ok, ""}
assert {:error, [error]} = cast(value: %{}, schema: schema)
assert %Error{reason: :invalid_type} = error
assert error.value == %{}
end
test "string with pattern" do
schema = %Schema{type: :string, pattern: ~r/\d-\d/}
assert cast(value: "1-2", schema: schema) == {:ok, "1-2"}
assert {:error, [error]} = cast(value: "hello", schema: schema)
assert error.reason == :invalid_format
assert error.value == "hello"
assert error.format == ~r/\d-\d/
end
# Note: we measure length of string after trimming leading and trailing whitespace
test "minLength" do
schema = %Schema{type: :string, minLength: 1}
assert {:error, [error]} = cast(value: " ", schema: schema)
assert %Error{} = error
assert error.reason == :min_length
end
end
end
diff --git a/test/cast_test.exs b/test/cast_test.exs
index c9bc1c4..425c9d9 100644
--- a/test/cast_test.exs
+++ b/test/cast_test.exs
@@ -1,197 +1,197 @@
defmodule OpenApiSpec.CastTest do
use ExUnit.Case
- alias OpenApiSpex.Cast.{Context, Error}
alias OpenApiSpex.{Cast, Schema, Reference}
+ alias OpenApiSpex.Cast.Error
- def cast(ctx), do: Cast.cast(struct(Context, ctx))
+ def cast(ctx), do: Cast.cast(ctx)
describe "cast/3" do
- # Note: full tests for primitives are covered in CastPrimitiveTest
+ # Note: full tests for primitives are covered in Cast.PrimitiveTest
test "primitives" do
tests = [
{:string, "1", :ok},
{:string, "", :ok},
{:string, true, :invalid},
{:string, nil, :invalid},
{:integer, 1, :ok},
{:integer, "1", :ok},
{:integer, %{}, :invalid},
{:integer, nil, :invalid},
{:array, nil, :invalid},
{:object, nil, :invalid}
]
for {type, input, expected} <- tests do
case expected do
:ok -> assert {:ok, _} = cast(value: input, schema: %Schema{type: type})
:invalid -> assert {:error, _} = cast(value: input, schema: %Schema{type: type})
end
end
end
test "array type, nullable, given nil" do
schema = %Schema{type: :array, nullable: true}
assert {:ok, nil} = cast(value: nil, schema: schema)
end
test "array type, given nil" do
schema = %Schema{type: :array}
assert {:error, [error]} = cast(value: nil, schema: schema)
assert error.reason == :null_value
assert Error.message_with_path(error) == "#: null value where array expected"
end
test "array" do
schema = %Schema{type: :array}
assert cast(value: [], schema: schema) == {:ok, []}
assert cast(value: [1, 2, 3], schema: schema) == {:ok, [1, 2, 3]}
assert cast(value: ["1", "2", "3"], schema: schema) == {:ok, ["1", "2", "3"]}
assert {:error, [error]} = cast(value: %{}, schema: schema)
assert %Error{} = error
assert error.reason == :invalid_type
assert error.value == %{}
end
test "array with items schema" do
items_schema = %Schema{type: :integer}
schema = %Schema{type: :array, items: items_schema}
assert cast(value: [], schema: schema) == {:ok, []}
assert cast(value: [1, 2, 3], schema: schema) == {:ok, [1, 2, 3]}
assert cast(value: ["1", "2", "3"], schema: schema) == {:ok, [1, 2, 3]}
assert {:error, errors} = cast(value: [1, "two"], schema: schema)
assert [%Error{} = error] = errors
assert error.reason == :invalid_type
assert error.value == "two"
assert error.path == [1]
end
- # Additional object tests found in CastObjectTest
+ # Additional object tests found in Cast.ObjectTest
test "object with schema properties set, given known input property" do
schema = %Schema{
type: :object,
properties: %{age: nil}
}
assert cast(value: %{}, schema: schema) == {:ok, %{}}
assert cast(value: %{"age" => "hello"}, schema: schema) == {:ok, %{age: "hello"}}
end
test "reference" do
age_schema = %Schema{type: :integer}
assert cast(
value: "20",
schema: %Reference{"$ref": "#/components/schemas/Age"},
schemas: %{"Age" => age_schema}
) == {:ok, 20}
end
test "reference nested in object" do
age_schema = %Schema{type: :integer}
schema = %Schema{
type: :object,
properties: %{
age: %Reference{"$ref": "#/components/schemas/Age"}
}
}
assert cast(
value: %{"age" => "20"},
schema: schema,
schemas: %{"Age" => age_schema}
) == {:ok, %{age: 20}}
end
test "paths" do
schema = %Schema{
type: :object,
properties: %{
age: %Schema{type: :integer}
}
}
assert {:error, errors} = cast(value: %{"age" => "twenty"}, schema: schema)
assert [error] = errors
assert %Error{} = error
assert error.path == [:age]
end
test "nested paths" do
schema = %Schema{
type: :object,
properties: %{
data: %Schema{
type: :object,
properties: %{
age: %Schema{type: :integer}
}
}
}
}
assert {:error, errors} = cast(value: %{"data" => %{"age" => "twenty"}}, schema: schema)
assert [error] = errors
assert %Error{} = error
assert error.path == [:data, :age]
assert Error.message_with_path(error) == "#/data/age: Invalid integer. Got: string"
end
test "paths involving arrays" do
schema = %Schema{
type: :object,
properties: %{
data: %Schema{
type: :array,
items: %Schema{
type: :object,
properties: %{
age: %Schema{type: :integer}
}
}
}
}
}
assert {:error, errors} =
cast(value: %{"data" => [%{"age" => "20"}, %{"age" => "twenty"}]}, schema: schema)
assert [error] = errors
assert %Error{} = error
assert error.path == [:data, 1, :age]
assert Error.message_with_path(error) == "#/data/1/age: Invalid integer. Got: string"
end
test "multiple errors" do
schema = %Schema{
type: :array,
items: %Schema{type: :integer}
}
value = [1, "two", 3, "four"]
assert {:error, errors} = cast(value: value, schema: schema)
assert [error, error2] = errors
assert %Error{} = error
assert error.reason == :invalid_type
assert error.path == [1]
assert Error.message_with_path(error) == "#/1: Invalid integer. Got: string"
assert Error.message_with_path(error2) == "#/3: Invalid integer. Got: string"
end
test "enum - invalid" do
schema = %Schema{type: :string, enum: ["one"]}
assert {:error, [error]} = cast(value: "two", schema: schema)
assert %Error{} = error
assert error.reason == :invalid_enum
end
test "enum - valid" do
schema = %Schema{type: :string, enum: ["one"]}
assert {:ok, "one"} = cast(value: "one", schema: schema)
end
end
end

File Metadata

Mime Type
text/x-diff
Expires
Sat, Nov 30, 2:28 PM (1 d, 18 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41444
Default Alt Text
(26 KB)

Event Timeline