Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F116141
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
26 KB
Referenced Files
None
Subscribers
None
View Options
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
Details
Attached
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)
Attached To
Mode
R22 open_api_spex
Attached
Detach File
Event Timeline
Log In to Comment