Page MenuHomePhorge

No OneTemporary

Size
8 KB
Referenced Files
None
Subscribers
None
diff --git a/lib/open_api_spex/cast/integer.ex b/lib/open_api_spex/cast/integer.ex
index 2b88adb..461bfd3 100644
--- a/lib/open_api_spex/cast/integer.ex
+++ b/lib/open_api_spex/cast/integer.ex
@@ -1,75 +1,75 @@
defmodule OpenApiSpex.Cast.Integer do
@moduledoc false
alias OpenApiSpex.Cast
def cast(%{value: value} = ctx) when is_integer(value) do
case cast_integer(ctx) do
{:cast, ctx} -> cast(ctx)
result -> result
end
end
- def cast(%{value: value}) when is_number(value) do
- {:ok, round(value)}
+ def cast(%{value: value} = ctx) when is_number(value) do
+ cast(%{ctx | value: round(value)})
end
def cast(%{value: value} = ctx) when is_binary(value) do
case Float.parse(value) do
{value, ""} -> cast(%{ctx | value: value})
_ -> Cast.error(ctx, {:invalid_type, :integer})
end
end
def cast(ctx) do
Cast.error(ctx, {:invalid_type, :integer})
end
## Private functions
defp cast_integer(%{value: value, schema: %{minimum: minimum, exclusiveMinimum: true}} = ctx)
when is_integer(value) and is_integer(minimum) do
if value > minimum do
Cast.success(ctx, [:minimum, :exclusiveMinimum])
else
Cast.error(ctx, {:exclusive_min, minimum, value})
end
end
defp cast_integer(%{value: value, schema: %{minimum: minimum}} = ctx)
when is_integer(value) and is_integer(minimum) do
if value >= minimum do
Cast.success(ctx, :minimum)
else
Cast.error(ctx, {:minimum, minimum, value})
end
end
defp cast_integer(%{value: value, schema: %{maximum: maximum, exclusiveMaximum: true}} = ctx)
when is_integer(value) and is_integer(maximum) do
if value < maximum do
Cast.success(ctx, [:maximum, :exclusiveMaximum])
else
Cast.error(ctx, {:exclusive_max, maximum, value})
end
end
defp cast_integer(%{value: value, schema: %{maximum: maximum}} = ctx)
when is_integer(value) and is_integer(maximum) do
if value <= maximum do
Cast.success(ctx, :maximum)
else
Cast.error(ctx, {:maximum, maximum, value})
end
end
defp cast_integer(%{value: value, schema: %{multipleOf: multiple}} = ctx)
when is_integer(value) and is_integer(multiple) do
if Integer.mod(value, multiple) > 0 do
Cast.error(ctx, {:multiple_of, multiple, value})
else
Cast.success(ctx, :multipleOf)
end
end
defp cast_integer(ctx), do: Cast.ok(ctx)
end
diff --git a/test/operation2_test.exs b/test/operation2_test.exs
index b8c8ace..668521c 100644
--- a/test/operation2_test.exs
+++ b/test/operation2_test.exs
@@ -1,187 +1,208 @@
defmodule OpenApiSpex.Operation2Test do
use ExUnit.Case
alias OpenApiSpex.{Operation, Operation2, Schema}
alias OpenApiSpex.Cast.Error
defmodule SchemaFixtures do
@user %Schema{
type: :object,
properties: %{
user: %Schema{
type: :object,
properties: %{
email: %Schema{type: :string}
}
}
}
}
@user_list %Schema{
type: :array,
items: @user
}
@schemas %{"User" => @user, "UserList" => @user_list}
def user, do: @user
def user_list, do: @user_list
def schemas, do: @schemas
end
defmodule OperationFixtures do
@user_index %Operation{
operationId: "UserController.index",
parameters: [
Operation.parameter(:name, :query, :string, "Filter by user name"),
Operation.parameter(:age, :query, :integer, "User's age")
],
responses: %{
200 => Operation.response("User", "application/json", SchemaFixtures.user())
}
}
def user_index, do: @user_index
@create_user %Operation{
operationId: "UserController.create",
parameters: [
Operation.parameter(:name, :query, :string, "Filter by user name")
],
requestBody:
Operation.request_body("request body", "application/json", SchemaFixtures.user(),
required: true
),
responses: %{
200 => Operation.response("User list", "application/json", SchemaFixtures.user_list())
}
}
def create_user, do: @create_user
end
defmodule SpecModule do
def spec do
paths = %{
"/users" => %{
"post" => OperationFixtures.create_user()
}
}
%OpenApiSpex.OpenApi{
info: nil,
paths: paths,
components: %{
schemas: SchemaFixtures.schemas()
}
}
end
end
defmodule RenderError do
def init(_) do
nil
end
def call(_conn, _errors) do
raise "should not have errors"
end
end
describe "cast/4" do
test "cast request body" do
conn = create_conn(%{"user" => %{"email" => "foo@bar.com"}})
assert {:ok, conn} =
Operation2.cast(
OperationFixtures.create_user(),
conn,
"application/json",
SchemaFixtures.schemas()
)
assert %Plug.Conn{} = conn
end
test "cast request body - invalid data type" do
conn = create_conn(%{"user" => %{"email" => 123}})
assert {:error, errors} =
Operation2.cast(
OperationFixtures.create_user(),
conn,
"application/json",
SchemaFixtures.schemas()
)
assert [error] = errors
assert %Error{} = error
assert error.reason == :invalid_type
end
test "validate undefined query param name" do
query_params = %{"unknown" => "asdf"}
assert {:error, [error]} = do_index_cast(query_params)
assert %Error{} = error
assert error.reason == :unexpected_field
assert error.name == "unknown"
assert error.path == ["unknown"]
end
test "validate invalid data type for query param" do
query_params = %{"age" => "asdf"}
assert {:error, [error]} = do_index_cast(query_params)
assert %Error{} = error
assert error.reason == :invalid_type
assert error.type == :integer
assert error.value == "asdf"
end
test "validate missing required query param" do
parameter =
Operation.parameter(:name, :query, :string, "Filter by user name", required: true)
operation = %{OperationFixtures.user_index() | parameters: [parameter]}
assert {:error, [error]} = do_index_cast(%{}, operation: operation)
assert %Error{} = error
assert error.reason == :missing_field
assert error.name == :name
end
+ test "validate invalid value for integer range" do
+ parameter =
+ Operation.parameter(
+ :age,
+ :query,
+ %Schema{type: :integer, minimum: 1, maximum: 99},
+ "Filter by user age",
+ required: true
+ )
+
+ operation = %{OperationFixtures.user_index() | parameters: [parameter]}
+
+ assert {:error, [error]} = do_index_cast(%{"age" => 100}, operation: operation)
+ assert %Error{} = error
+ assert error.reason == :maximum
+
+ assert {:error, [error]} = do_index_cast(%{"age" => 0}, operation: operation)
+ assert %Error{} = error
+ assert error.reason == :minimum
+ end
+
defp do_index_cast(query_params, opts \\ []) do
conn =
:get
|> Plug.Test.conn("/api/users?" <> URI.encode_query(query_params))
|> Plug.Conn.put_req_header("content-type", "application/json")
|> Plug.Conn.fetch_query_params()
|> build_params()
operation = opts[:operation] || OperationFixtures.user_index()
Operation2.cast(
operation,
conn,
"application/json",
SchemaFixtures.schemas()
)
end
defp create_conn(body_params) do
:post
|> Plug.Test.conn("/api/users")
|> Plug.Conn.put_req_header("content-type", "application/json")
|> Plug.Conn.fetch_query_params()
|> Map.put(:body_params, body_params)
|> build_params()
end
defp build_params(conn) do
params =
conn.path_params
|> Map.merge(conn.query_params)
|> Map.merge(conn.body_params)
%{conn | params: params}
end
end
end

File Metadata

Mime Type
text/x-diff
Expires
Fri, Nov 29, 6:52 PM (1 d, 18 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41280
Default Alt Text
(8 KB)

Event Timeline