diff --git a/.formatter.exs b/.formatter.exs new file mode 100644 index 0000000..00950e6 --- /dev/null +++ b/.formatter.exs @@ -0,0 +1,4 @@ +[ + inputs: ["mix.exs", "{config,lib,test}/**/*.{ex,exs}"], + line_length: 120 +] diff --git a/.gitignore b/.gitignore index 95304df..2629fea 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,7 @@ GitHub.sublime-settings .tags_sorted_by_file .vagrant .DS_Store +.elixir_ls/* # Ignore released binaries rel/*/ diff --git a/.travis.yml b/.travis.yml index 30ceef8..90c4641 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,5 +20,3 @@ script: - "mix coveralls.travis" # Run static code analysis - "mix credo" - # Check code style - - "mix dogma" diff --git a/bin/hooks/pre-commit.sh b/bin/hooks/pre-commit.sh index b4b5116..686fb0b 100755 --- a/bin/hooks/pre-commit.sh +++ b/bin/hooks/pre-commit.sh @@ -1,4 +1,3 @@ mix test mix coveralls mix credo -mix dogma diff --git a/config/dogma.exs b/config/dogma.exs deleted file mode 100644 index 251297e..0000000 --- a/config/dogma.exs +++ /dev/null @@ -1,16 +0,0 @@ -use Mix.Config -alias Dogma.Rule - -config :dogma, - rule_set: Dogma.RuleSet.All, - exclude: [ - ~r(\Alib/eview/tasks.ex), # TODO: https://github.com/lpil/dogma/issues/221 - ~r(\Arel/), - ~r(\Adeps/), - ], - override: [ - %Rule.LineLength{ max_length: 120 }, - %Rule.TakenName{ enabled: false }, # TODO: https://github.com/lpil/dogma/issues/201 - %Rule.InfixOperatorPadding{ enabled: false }, - %Rule.FunctionArity{ max: 5 }, - ] diff --git a/lib/eview.ex b/lib/eview.ex index c2f531f..a54980b 100644 --- a/lib/eview.ex +++ b/lib/eview.ex @@ -18,20 +18,16 @@ defmodule EView do def init(options), do: options - @spec call(Conn.t, any) :: Conn.t + @spec call(Conn.t(), any) :: Conn.t() def call(conn, _options) do conn |> register_before_send(&update_reponse_body/1) end - defp update_reponse_body(%{resp_body: []} = conn), - do: conn - defp update_reponse_body(%{resp_body: ""} = conn), - do: conn - defp update_reponse_body(%{resp_body: nil} = conn), - do: conn - defp update_reponse_body(%{resp_body: resp_body} = conn), - do: put_response(conn, resp_body) + defp update_reponse_body(%{resp_body: []} = conn), do: conn + defp update_reponse_body(%{resp_body: ""} = conn), do: conn + defp update_reponse_body(%{resp_body: nil} = conn), do: conn + defp update_reponse_body(%{resp_body: resp_body} = conn), do: put_response(conn, resp_body) @doc """ Update `body` and add all meta objects that is required by API Manifest structure. @@ -47,9 +43,10 @@ defmodule EView do resp = result |> wrap_body(conn) - |> Poison.encode_to_iodata! + |> Poison.encode_to_iodata!() %{conn | resp_body: resp} + {:error, _} -> %{conn | resp_body: resp_body} end diff --git a/lib/eview/changeset/validators/card_number.ex b/lib/eview/changeset/validators/card_number.ex index c56e8c8..5ebd738 100644 --- a/lib/eview/changeset/validators/card_number.ex +++ b/lib/eview/changeset/validators/card_number.ex @@ -9,12 +9,16 @@ if Code.ensure_loaded?(Ecto) and Code.ensure_loaded?(CreditCard) do def validate_card_number(changeset, field, opts \\ []) do allowed_card_types = opts[:allowed_card_types] || @allowed_card_types - validate_change changeset, field, :credit_card, fn _, value -> + + validate_change(changeset, field, :credit_card, fn _, value -> if CreditCard.valid?(value, %{allowed_card_types: allowed_card_types}), - do: [], - else: [{field, {message(opts, "is not a valid card number"), [validation: :card_number, - allowed_card_types: allowed_card_types]}}] - end + do: [], + else: [ + {field, + {message(opts, "is not a valid card number"), + [validation: :card_number, allowed_card_types: allowed_card_types]}} + ] + end) end defp message(opts, key \\ :message, default) do diff --git a/lib/eview/changeset/validators/email_validator.ex b/lib/eview/changeset/validators/email_validator.ex index d3a9e27..9444469 100644 --- a/lib/eview/changeset/validators/email_validator.ex +++ b/lib/eview/changeset/validators/email_validator.ex @@ -5,17 +5,19 @@ if Code.ensure_loaded?(Ecto) do """ import Ecto.Changeset - @email_regex Regex.compile!(~S((?:[a-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+\/=?^_`{|}~-]+\)*|") <> - ~S((?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f]\)*"\)) <> - ~S(@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9]\)?\.\)+[a-z0-9](?:[a-z0-9-]*[a-z0-9]\)?) <> - ~S(|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?\)\.\){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?) <> - ~S(|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]) <> - ~S(|\\[\x01-\x09\x0b\x0c\x0e-\x7f]\)+\)\]\))) + @email_regex Regex.compile!( + ~S((?:[a-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+\/=?^_`{|}~-]+\)*|") <> + ~S((?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f]\)*"\)) <> + ~S(@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9]\)?\.\)+[a-z0-9](?:[a-z0-9-]*[a-z0-9]\)?) <> + ~S(|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?\)\.\){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?) <> + ~S(|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]) <> + ~S(|\\[\x01-\x09\x0b\x0c\x0e-\x7f]\)+\)\]\)) + ) def validate_email(changeset, field, opts \\ []) do - validate_change changeset, field, {:email, @email_regex}, fn _, value -> + validate_change(changeset, field, {:email, @email_regex}, fn _, value -> if value =~ @email_regex, do: [], else: [{field, {message(opts, "is not a valid email"), [validation: :email]}}] - end + end) end defp message(opts, key \\ :message, default) do diff --git a/lib/eview/changeset/validators/metadata_validator.ex b/lib/eview/changeset/validators/metadata_validator.ex index c3cfc42..b4ac2a2 100644 --- a/lib/eview/changeset/validators/metadata_validator.ex +++ b/lib/eview/changeset/validators/metadata_validator.ex @@ -14,9 +14,9 @@ if Code.ensure_loaded?(Ecto) do @jsonpath_joiner "." def validate_metadata(changeset, field, opts \\ []) do - validate_change changeset, field, :metadata, fn _, value -> + validate_change(changeset, field, :metadata, fn _, value -> get_metadata_errors(field, value, opts) - end + end) end defp get_metadata_errors(field, metadata, _opts) when is_map(metadata) do @@ -34,43 +34,58 @@ if Code.ensure_loaded?(Ecto) do # Check max length of key defp field_validation_reducer(parent, {key, _}, acc) when is_binary(key) and byte_size(key) > @max_key_length do - [{field_path(parent, key), - {"key should be up to %{max} characters", [validation: :length, max: @max_key_length]}} - | acc] + [ + {field_path(parent, key), + {"key should be up to %{max} characters", [validation: :length, max: @max_key_length]}} + | acc + ] end # Check binary value max length defp field_validation_reducer(parent, {key, val}, acc) when is_binary(val) and byte_size(val) > @max_value_length do - [{field_path(parent, key), - {"value should be up to %{max} characters", [validation: :length, max: @max_value_length]}} - | acc] + [ + {field_path(parent, key), + {"value should be up to %{max} characters", [validation: :length, max: @max_value_length]}} + | acc + ] end # Check list values defp field_validation_reducer(parent, {key, list}, acc) when is_list(list) and length(list) > @max_list_length do - [{field_path(parent, key), - {"lists should be up to %{max} elements", [validation: :length, max: @max_list_length]}} - | acc] + [ + {field_path(parent, key), + {"lists should be up to %{max} elements", [validation: :length, max: @max_list_length]}} + | acc + ] end # Check list elements length defp field_validation_reducer(parent, {key, list}, acc) when is_list(list) do - {errors, _} = Enum.reduce(list, {[], 0}, fn - %Decimal{}, {el_acc, i} -> - {el_acc, i + 1} - elem, {el_acc, i} when is_float(elem) or is_number(elem) -> - {el_acc, i + 1} - elem, {el_acc, i} when is_binary(elem) and byte_size(elem) <= @max_list_value_length -> - {el_acc, i + 1} - elem, {el_acc, i} when is_binary(elem) and byte_size(elem) > @max_list_value_length -> - {[{join_atoms(field_path(parent, key), "[#{i}]"), - {"list keys should be up to %{max} characters", [validation: :length, max: @max_key_length]}} - | el_acc], i + 1} - _, {el_acc, i} -> - {[{field_path(parent, key), - {"one of keys is invalid", [validation: :cast, type: [:integer, :float, :decimal, :string]]}} - | el_acc], i + 1} - end) + {errors, _} = + Enum.reduce(list, {[], 0}, fn + %Decimal{}, {el_acc, i} -> + {el_acc, i + 1} + + elem, {el_acc, i} when is_float(elem) or is_number(elem) -> + {el_acc, i + 1} + + elem, {el_acc, i} when is_binary(elem) and byte_size(elem) <= @max_list_value_length -> + {el_acc, i + 1} + + elem, {el_acc, i} when is_binary(elem) and byte_size(elem) > @max_list_value_length -> + {[ + {join_atoms(field_path(parent, key), "[#{i}]"), + {"list keys should be up to %{max} characters", [validation: :length, max: @max_key_length]}} + | el_acc + ], i + 1} + + _, {el_acc, i} -> + {[ + {field_path(parent, key), + {"one of keys is invalid", [validation: :cast, type: [:integer, :float, :decimal, :string]]}} + | el_acc + ], i + 1} + end) errors ++ acc end @@ -81,16 +96,17 @@ if Code.ensure_loaded?(Ecto) do # Pass valid binary keys and values defp field_validation_reducer(_parent, {key, val}, acc) - when is_binary(key) and byte_size(key) <= @max_key_length - and is_binary(val) and byte_size(val) <= @max_value_length do + when is_binary(key) and byte_size(key) <= @max_key_length and is_binary(val) and + byte_size(val) <= @max_value_length do acc end # Everything else is an error defp field_validation_reducer(parent, {key, _val}, acc) do - [{field_path(parent, key), - {"is invalid", [validation: :cast, type: [:integer, :float, :decimal, :string]]}} - | acc] + [ + {field_path(parent, key), {"is invalid", [validation: :cast, type: [:integer, :float, :decimal, :string]]}} + | acc + ] end # Join atom in JSON Path style diff --git a/lib/eview/changeset/validators/phone_number.ex b/lib/eview/changeset/validators/phone_number.ex index 924e300..f73f976 100644 --- a/lib/eview/changeset/validators/phone_number.ex +++ b/lib/eview/changeset/validators/phone_number.ex @@ -8,11 +8,11 @@ if Code.ensure_loaded?(Ecto) do @phone_regex ~r/^\+[0-9]{9,16}$/ def validate_phone_number(changeset, field, opts \\ []) do - validate_change changeset, field, {:phone_number, @phone_regex}, fn _, value -> + validate_change(changeset, field, {:phone_number, @phone_regex}, fn _, value -> if value =~ @phone_regex, - do: [], + do: [], else: [{field, {message(opts, "is not a valid phone number"), [validation: :phone_number]}}] - end + end) end defp message(opts, key \\ :message, default) do diff --git a/lib/eview/helpers/changeset_validations_parser.ex b/lib/eview/helpers/changeset_validations_parser.ex index 48706be..08e9042 100644 --- a/lib/eview/helpers/changeset_validations_parser.ex +++ b/lib/eview/helpers/changeset_validations_parser.ex @@ -15,12 +15,7 @@ if Code.ensure_loaded?(Ecto) do defp construct_rule(%Ecto.Changeset{validations: validations}, field, {message, opts}) do validation_name = opts[:validation] - get_rule( - field, - validation_name, - put_validation(validations, validation_name, field, opts), - message, - opts) + get_rule(field, validation_name, put_validation(validations, validation_name, field, opts), message, opts) end # Special case for cast validation that stores type in field that dont match validation name @@ -35,17 +30,16 @@ if Code.ensure_loaded?(Ecto) do end # Embeds - defp put_validation(validations, nil, field, [type: :map]) do + defp put_validation(validations, nil, field, type: :map) do [{field, {:cast, :map}} | validations] end # Embeds Many - defp put_validation(validations, nil, field, [type: {_, _} = type]) do + defp put_validation(validations, nil, field, type: {_, _} = type) do [{field, {:cast, type}} | validations] end - defp put_validation(validations, _, _field, _opts), - do: validations + defp put_validation(validations, _, _field, _opts), do: validations # Embeds defp get_rule(field, nil, validations, message, [type: {_, _}] = opts) do @@ -128,21 +122,21 @@ if Code.ensure_loaded?(Ecto) do _, acc -> acc end) - |> Enum.uniq + |> Enum.uniq() end - defp cast_rules_type([h | _] = rules) when is_tuple(h), - do: rules |> Enum.into(%{}) - defp cast_rules_type(rules), - do: rules + defp cast_rules_type([h | _] = rules) when is_tuple(h), do: rules |> Enum.into(%{}) + defp cast_rules_type(rules), do: rules # Recursively flatten errors map - defp errors_flatener({field, [%{rule: _}|_] = rules}, prefix, entry_type) when is_list(rules) do - [%{ - entry_type: entry_type, - entry: prefix <> @jsonpath_joiner <> to_string(field), - rules: rules - }] + defp errors_flatener({field, [%{rule: _} | _] = rules}, prefix, entry_type) when is_list(rules) do + [ + %{ + entry_type: entry_type, + entry: prefix <> @jsonpath_joiner <> to_string(field), + rules: rules + } + ] end defp errors_flatener({field, errors}, prefix, entry_type) when is_map(errors) do @@ -151,17 +145,21 @@ if Code.ensure_loaded?(Ecto) do end defp errors_flatener({field, errors}, prefix, entry_type) when is_list(errors) do - {acc, _} = errors - |> Enum.reduce({[], 0}, fn inner_errors, {acc, i} -> - inner_rules = inner_errors - |> Enum.flat_map(&errors_flatener( - &1, - "#{prefix}#{@jsonpath_joiner}" <> to_string(field) <> "[#{i}]", - entry_type - )) - - {acc ++ inner_rules, i + 1} - end) + {acc, _} = + errors + |> Enum.reduce({[], 0}, fn inner_errors, {acc, i} -> + inner_rules = + inner_errors + |> Enum.flat_map( + &errors_flatener( + &1, + "#{prefix}#{@jsonpath_joiner}" <> to_string(field) <> "[#{i}]", + entry_type + ) + ) + + {acc ++ inner_rules, i + 1} + end) acc end diff --git a/lib/eview/helpers/sanitization.ex b/lib/eview/helpers/sanitization.ex index bbf86b4..eaf0b00 100644 --- a/lib/eview/helpers/sanitization.ex +++ b/lib/eview/helpers/sanitization.ex @@ -11,7 +11,7 @@ defmodule EView.Helpers.Sanitizer do def sanitize(term) when is_tuple(term) do term - |> Tuple.to_list + |> Tuple.to_list() |> sanitize() end diff --git a/lib/eview/plugs/idempotency.ex b/lib/eview/plugs/idempotency.ex index cf17e3f..c51c476 100644 --- a/lib/eview/plugs/idempotency.ex +++ b/lib/eview/plugs/idempotency.ex @@ -14,12 +14,13 @@ defmodule EView.Plugs.Idempotency do def init(opts), do: opts - @spec call(Conn.t, any) :: Conn.t + @spec call(Conn.t(), any) :: Conn.t() def call(conn, _options) do case get_req_header(conn, "x-idempotency-key") do [idempotency_key | _] -> conn |> put_resp_header("x-idempotency-key", idempotency_key) + _ -> conn end diff --git a/lib/eview/renders/meta_view.ex b/lib/eview/renders/meta_view.ex index 49f5637..d3088e2 100644 --- a/lib/eview/renders/meta_view.ex +++ b/lib/eview/renders/meta_view.ex @@ -23,7 +23,7 @@ defmodule EView.Renders.Meta do end defp get_resourse_url(conn, resrouce_id, 201) when not is_nil(resrouce_id) do - get_resourse_url(conn) <> "/" <> to_string(resrouce_id) + get_resourse_url(conn) <> "/" <> to_string(resrouce_id) end defp get_resourse_url(conn, _resrouce_id, _status) do @@ -50,7 +50,7 @@ defmodule EView.Renders.Meta do defp get_request_id(conn) do conn |> get_resp_header("x-request-id") - |> List.first + |> List.first() end defp put_impotency_key(meta, %Plug.Conn{} = conn) do @@ -58,6 +58,7 @@ defmodule EView.Renders.Meta do [idempotency_key | _] -> meta |> Map.put(:idempotency_key, idempotency_key) + _ -> meta end diff --git a/lib/eview/renders/root_render.ex b/lib/eview/renders/root_render.ex index 72d6435..4290d96 100644 --- a/lib/eview/renders/root_render.ex +++ b/lib/eview/renders/root_render.ex @@ -30,32 +30,36 @@ defmodule EView.Renders.Root do end # Add `paging` property. To use it just add `paging` in `render/2` assigns. - defp put_paging(%{meta: %{type: "list"}} = data, - %{paging: %{ + defp put_paging(%{meta: %{type: "list"}} = data, %{ + paging: %{ page_number: page_number, page_size: page_size, total_pages: total_pages, - total_entries: total_entries, - }}) do - + total_entries: total_entries + } + }) do Map.put(data, :paging, %{ page_number: page_number, page_size: page_size, total_pages: total_pages, - total_entries: total_entries, + total_entries: total_entries }) end # Add `paging` property. To use it just add `paging` in `render/2` assigns. - defp put_paging(%{meta: %{type: "list"}} = data, - %{paging: %{ - limit: limit, - cursors: %{starting_after: _, ending_before: _}, - has_more: has_more - } = paging}) when is_integer(limit) and is_boolean(has_more) do + defp put_paging(%{meta: %{type: "list"}} = data, %{ + paging: + %{ + limit: limit, + cursors: %{starting_after: _, ending_before: _}, + has_more: has_more + } = paging + }) + when is_integer(limit) and is_boolean(has_more) do data |> Map.put(:paging, paging) end + defp put_paging(data, _assigns), do: data # Add `urgent` property. To use it just add `urgent` in `render/2` assigns. @@ -65,8 +69,9 @@ defmodule EView.Renders.Root do # Add `sandbox` property. To use it just add `sandbox` in `render/2` assigns. if Code.ensure_loaded?(Mix) do defp put_sandbox(data, %{sandbox: sandbox}) do - if Mix.env in [:test, :dev], do: Map.put(data, :sandbox, sandbox), else: data + if Mix.env() in [:test, :dev], do: Map.put(data, :sandbox, sandbox), else: data end end + defp put_sandbox(data, _assigns), do: data end diff --git a/lib/eview/test/acceptance_case.ex b/lib/eview/test/acceptance_case.ex index 8723b30..8dcc896 100644 --- a/lib/eview/test/acceptance_case.ex +++ b/lib/eview/test/acceptance_case.ex @@ -10,11 +10,11 @@ defmodule EView.AcceptanceCase do using(opts) do quote location: :keep, bind_quoted: [opts: opts] do unless opts[:otp_app] do - throw "You need to specify `otp_app` when using AcceptanceCase." + throw("You need to specify `otp_app` when using AcceptanceCase.") end unless opts[:endpoint] do - throw "You need to specify `endpoint` when using AcceptanceCase." + throw("You need to specify `endpoint` when using AcceptanceCase.") end # Configure acceptance testing on different host:port @@ -41,13 +41,12 @@ defmodule EView.AcceptanceCase do defp process_request_headers(headers) do meta = Phoenix.Ecto.SQL.Sandbox.metadata_for(@repo, self()) - encoded = {:v1, meta} - |> :erlang.term_to_binary - |> Base.url_encode64 + encoded = + {:v1, meta} + |> :erlang.term_to_binary() + |> Base.url_encode64() - headers ++ @headers ++ [ - {"content-type", "application/json"}, - {"user-agent", "BeamMetadata (#{encoded})"}] + headers ++ @headers ++ [{"content-type", "application/json"}, {"user-agent", "BeamMetadata (#{encoded})"}] end else defp process_request_headers(headers) do @@ -58,13 +57,13 @@ defmodule EView.AcceptanceCase do defp process_request_body(body) do case body do {:multipart, _} -> body - _ -> body |> Poison.encode! + _ -> body |> Poison.encode!() end end defp process_response_body(body) do body - |> Poison.decode! + |> Poison.decode!() end if is_atom(opts[:repo]) and not is_nil(opts[:repo]) and Code.ensure_loaded?(Ecto) do @@ -72,8 +71,9 @@ defmodule EView.AcceptanceCase do :ok = Ecto.Adapters.SQL.Sandbox.checkout(@repo) unless tags[:async] do - Ecto.Adapters.SQL.Sandbox.mode(@repo, {:shared, self()}) + Ecto.Adapters.SQL.Sandbox.mode(@repo, {:shared, self()}) end + :ok end end diff --git a/lib/eview/views/error_view.ex b/lib/eview/views/error_view.ex index 1225c8f..755fb4f 100644 --- a/lib/eview/views/error_view.ex +++ b/lib/eview/views/error_view.ex @@ -13,12 +13,14 @@ defmodule EView.Views.Error do # This bitch don't want to handle before_send %{ type: :request_malformed, - invalid: [%{ - entry_type: :request, - rules: [ - %{rule: :json} - ] - }], + invalid: [ + %{ + entry_type: :request, + rules: [ + %{rule: :json} + ] + } + ], message: "Malformed request. Probably, you have sent corrupted JSON." } |> put_type(assigns) @@ -74,10 +76,12 @@ defmodule EView.Views.Error do def render("406.json", assigns) do %{ type: :content_type_invalid, - invalid: [%{ - entry_type: :header, - entry: "Accept" - }], + invalid: [ + %{ + entry_type: :header, + entry: "Accept" + } + ], message: "Accept header is missing or invalid. Try to set 'Accept: application/json' header." } |> put_type(assigns) @@ -100,12 +104,14 @@ defmodule EView.Views.Error do # This bitch don't want to handle before_send %{ type: :request_too_large, - invalid: [%{ - entry_type: :request, - rules: [ - %{rule: :size} - ] - }], + invalid: [ + %{ + entry_type: :request, + rules: [ + %{rule: :size} + ] + } + ], message: "Request body is too large." } |> put_type(assigns) @@ -116,12 +122,15 @@ defmodule EView.Views.Error do # This bitch don't want to handle before_send %{ type: :content_type_invalid, - invalid: [%{ - entry_type: :header, - entry: "Content-Type" - }], - message: "Invalid Content-Type header. Try to set 'Content-Type: application/json' header: " <> - "http://docs.apimanifest.apiary.io/#introduction/interacting-with-api/content-type." + invalid: [ + %{ + entry_type: :header, + entry: "Content-Type" + } + ], + message: + "Invalid Content-Type header. Try to set 'Content-Type: application/json' header: " <> + "http://docs.apimanifest.apiary.io/#introduction/interacting-with-api/content-type." } |> put_type(assigns) |> put_message(assigns) @@ -130,8 +139,9 @@ defmodule EView.Views.Error do def render("424.json", assigns) do %{ type: :failed_dependency, - message: "The method could not be performed on the resource because the requested action depended on another " <> - "action and that action failed." + message: + "The method could not be performed on the resource because the requested action depended on another " <> + "action and that action failed." } |> put_type(assigns) |> put_message(assigns) @@ -152,17 +162,20 @@ defmodule EView.Views.Error do body |> Map.put(:type, type) end + defp put_type(body, _), do: body defp put_invalid(body, %{invalid: invalid}) when is_map(invalid) do body |> Map.put(:invalid, invalid) end + defp put_invalid(body, _), do: body defp put_message(body, %{message: message}) when is_binary(message) do body |> Map.put(:message, message) end + defp put_message(body, _), do: body end diff --git a/lib/eview/views/phoenix_error_view.ex b/lib/eview/views/phoenix_error_view.ex index 88975e1..0eefc44 100644 --- a/lib/eview/views/phoenix_error_view.ex +++ b/lib/eview/views/phoenix_error_view.ex @@ -14,6 +14,7 @@ defmodule EView.Views.PhoenixError do |> render_template(assigns) |> EView.Renders.Root.render(assigns[:conn]) end + def render(template, assigns) do template |> render_template(assigns) diff --git a/lib/eview/views/validation_error_view.ex b/lib/eview/views/validation_error_view.ex index a086833..1950543 100644 --- a/lib/eview/views/validation_error_view.ex +++ b/lib/eview/views/validation_error_view.ex @@ -26,10 +26,11 @@ defmodule EView.Views.ValidationError do * `ex_json_schema` validation errors. """ def render("422.json", %Ecto.Changeset{} = ch), do: render("422.json", ch, "json_data_property") - def render("422.json", %{changeset: ch}), do: render("422.json", ch) + def render("422.json", %{changeset: ch}), do: render("422.json", ch) def render("422.query.json", %Ecto.Changeset{} = ch), do: render("422.json", ch, "query_parameter") - def render("422.query.json", %{changeset: ch}), do: render("422.json", ch, "query_parameter") + def render("422.query.json", %{changeset: ch}), do: render("422.json", ch, "query_parameter") + def render("422.query.json", %{schema: errors} = params) when is_list(errors) do render("422.json", params, "query_parameter") end @@ -38,8 +39,9 @@ defmodule EView.Views.ValidationError do %{ type: :validation_failed, invalid: EView.Helpers.ChangesetValidationsParser.changeset_to_rules(changeset, entry_type), - message: "Validation failed. You can find validators description at our API Manifest: " <> - "http://docs.apimanifest.apiary.io/#introduction/interacting-with-api/errors." + message: + "Validation failed. You can find validators description at our API Manifest: " <> + "http://docs.apimanifest.apiary.io/#introduction/interacting-with-api/errors." } end end @@ -51,14 +53,16 @@ defmodule EView.Views.ValidationError do Render a JSON Schema validation error. """ def render("422.json", %{schema: errors}, entry_type \\ "json_data_property") when is_list(errors) do - errors = errors - |> Enum.map(&(map_schema_errors(&1, entry_type))) + errors = + errors + |> Enum.map(&map_schema_errors(&1, entry_type)) %{ type: :validation_failed, invalid: errors, - message: "Validation failed. You can find validators description at our API Manifest: " <> - "http://docs.apimanifest.apiary.io/#introduction/interacting-with-api/errors." + message: + "Validation failed. You can find validators description at our API Manifest: " <> + "http://docs.apimanifest.apiary.io/#introduction/interacting-with-api/errors." } end diff --git a/mix.exs b/mix.exs index 2a226b8..b409d0f 100644 --- a/mix.exs +++ b/mix.exs @@ -4,19 +4,21 @@ defmodule EView.Mixfile do @version "0.12.5" def project do - [app: :eview, - description: "Plug that converts response to Nebo #15 API spec format.", - package: package(), - version: @version, - elixir: "~> 1.4", - elixirc_paths: elixirc_paths(Mix.env), - compilers: [] ++ Mix.compilers, - build_embedded: Mix.env == :prod, - start_permanent: Mix.env == :prod, - deps: deps(), - test_coverage: [tool: ExCoveralls], - preferred_cli_env: [coveralls: :test], - docs: [source_ref: "v#\{@version\}", main: "readme", extras: ["README.md"]]] + [ + app: :eview, + description: "Plug that converts response to Nebo #15 API spec format.", + package: package(), + version: @version, + elixir: "~> 1.4", + elixirc_paths: elixirc_paths(Mix.env()), + compilers: [] ++ Mix.compilers(), + build_embedded: Mix.env() == :prod, + start_permanent: Mix.env() == :prod, + deps: deps(), + test_coverage: [tool: ExCoveralls], + preferred_cli_env: [coveralls: :test], + docs: [source_ref: "v#\{@version\}", main: "readme", extras: ["README.md"]] + ] end # Configuration for the OTP application @@ -28,7 +30,7 @@ defmodule EView.Mixfile do # Specifies which paths to compile per environment. defp elixirc_paths(:test), do: ["lib", "web", "test/support"] - defp elixirc_paths(_), do: ["lib", "web"] + defp elixirc_paths(_), do: ["lib", "web"] # Dependencies can be Hex packages: # @@ -44,27 +46,30 @@ defmodule EView.Mixfile do # # Type "mix help deps" for more examples and options defp deps do - [{:plug, "~> 1.3"}, - {:poison, "~> 3.1"}, - {:ecto, "~> 2.1", optional: true}, - {:credit_card, "~> 1.0", optional: true}, - {:nex_json_schema, "~> 0.7.0", optional: true}, - {:postgrex, "~> 0.13.2", only: [:dev, :test]}, - {:cowboy, "~> 1.1", only: [:dev, :test]}, - {:httpoison, "~> 0.12.0", only: [:dev, :test]}, - {:phoenix, github: "phoenixframework/phoenix", only: [:dev, :test]}, - {:ex_doc, ">= 0.0.0", only: [:dev, :test]}, - {:excoveralls, ">= 0.5.0", only: [:dev, :test]}, - {:dogma, ">= 0.1.0", only: [:dev, :test]}, - {:credo, ">= 0.4.8", only: [:dev, :test]}] + [ + {:plug, "~> 1.3"}, + {:poison, "~> 3.1"}, + {:ecto, "~> 2.1", optional: true}, + {:credit_card, "~> 1.0", optional: true}, + {:nex_json_schema, "~> 0.7.0", optional: true}, + {:postgrex, "~> 0.13.2", only: [:dev, :test]}, + {:cowboy, "~> 1.1", only: [:dev, :test]}, + {:httpoison, "~> 0.12.0", only: [:dev, :test]}, + {:phoenix, github: "phoenixframework/phoenix", only: [:dev, :test]}, + {:ex_doc, ">= 0.0.0", only: [:dev, :test]}, + {:excoveralls, ">= 0.5.0", only: [:dev, :test]}, + {:credo, ">= 0.4.8", only: [:dev, :test]} + ] end # Settings for publishing in Hex package manager: defp package do - [contributors: ["Nebo #15"], - maintainers: ["Nebo #15"], - licenses: ["LISENSE.md"], - links: %{github: "https://github.com/Nebo15/eview"}, - files: ~w(lib LICENSE.md mix.exs README.md)] + [ + contributors: ["Nebo #15"], + maintainers: ["Nebo #15"], + licenses: ["LISENSE.md"], + links: %{github: "https://github.com/Nebo15/eview"}, + files: ~w(lib LICENSE.md mix.exs README.md) + ] end end diff --git a/mix.lock b/mix.lock index bc1fe83..e3ea7c9 100644 --- a/mix.lock +++ b/mix.lock @@ -1,4 +1,5 @@ -%{"bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], []}, +%{ + "bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], []}, "certifi": {:hex, :certifi, "1.2.1", "c3904f192bd5284e5b13f20db3ceac9626e14eeacfbb492e19583cf0e37b22be", [:rebar3], []}, "connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], []}, "cowboy": {:hex, :cowboy, "1.1.2", "61ac29ea970389a88eca5a65601460162d370a70018afe6f949a29dca91f3bb0", [:rebar3], [{:cowlib, "~> 1.0.2", [hex: :cowlib, optional: false]}, {:ranch, "~> 1.3.2", [hex: :ranch, optional: false]}]}, @@ -7,7 +8,6 @@ "credo": {:hex, :credo, "0.8.4", "4e50acac058cf6292d6066e5b0d03da5e1483702e1ccde39abba385c9f03ead4", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, optional: false]}]}, "db_connection": {:hex, :db_connection, "1.1.2", "2865c2a4bae0714e2213a0ce60a1b12d76a6efba0c51fbda59c9ab8d1accc7a8", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, optional: false]}, {:poolboy, "~> 1.5", [hex: :poolboy, optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, optional: true]}]}, "decimal": {:hex, :decimal, "1.4.0", "fac965ce71a46aab53d3a6ce45662806bdd708a4a95a65cde8a12eb0124a1333", [:mix], []}, - "dogma": {:hex, :dogma, "0.1.15", "5bceba9054b2b97a4adcb2ab4948ca9245e5258b883946e82d32f785340fd411", [:mix], [{:poison, ">= 2.0.0", [hex: :poison, optional: false]}]}, "earmark": {:hex, :earmark, "1.2.2", "f718159d6b65068e8daeef709ccddae5f7fdc770707d82e7d126f584cd925b74", [:mix], []}, "ecto": {:hex, :ecto, "2.1.4", "d1ba932813ec0e0d9db481ef2c17777f1cefb11fc90fa7c142ff354972dfba7e", [:mix], [{:db_connection, "~> 1.1", [hex: :db_connection, optional: true]}, {:decimal, "~> 1.2", [hex: :decimal, optional: false]}, {:mariaex, "~> 0.8.0", [hex: :mariaex, optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, optional: true]}, {:poolboy, "~> 1.5", [hex: :poolboy, optional: false]}, {:postgrex, "~> 0.13.0", [hex: :postgrex, optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, optional: true]}]}, "ex_doc": {:hex, :ex_doc, "0.16.2", "3b3e210ebcd85a7c76b4e73f85c5640c011d2a0b2f06dcdf5acdb2ae904e5084", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, optional: false]}]}, @@ -29,4 +29,5 @@ "postgrex": {:hex, :postgrex, "0.13.3", "c277cfb2a9c5034d445a722494c13359e361d344ef6f25d604c2353185682bfc", [:mix], [{:connection, "~> 1.0", [hex: :connection, optional: false]}, {:db_connection, "~> 1.1", [hex: :db_connection, optional: false]}, {:decimal, "~> 1.0", [hex: :decimal, optional: false]}]}, "ranch": {:hex, :ranch, "1.3.2", "e4965a144dc9fbe70e5c077c65e73c57165416a901bd02ea899cfd95aa890986", [:rebar3], []}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.1", "28a4d65b7f59893bc2c7de786dec1e1555bd742d336043fe644ae956c3497fbe", [:make, :rebar], []}, - "unicode_util_compat": {:hex, :unicode_util_compat, "0.2.0", "dbbccf6781821b1c0701845eaf966c9b6d83d7c3bfc65ca2b78b88b8678bfa35", [:rebar3], []}} + "unicode_util_compat": {:hex, :unicode_util_compat, "0.2.0", "dbbccf6781821b1c0701845eaf966c9b6d83d7c3bfc65ca2b78b88b8678bfa35", [:rebar3], []}, +} diff --git a/test/acceptance/eview_test.exs b/test/acceptance/eview_test.exs index be77663..11cd280 100644 --- a/test/acceptance/eview_test.exs +++ b/test/acceptance/eview_test.exs @@ -3,73 +3,75 @@ defmodule EViewAcceptanceTest do async: true, otp_app: :eview, endpoint: Demo.Endpoint, - headers: [{"x-request-id", "my_request_id_000000"}, - {"x-idempotency-key", "TestIdempotencyKey"}] + headers: [{"x-request-id", "my_request_id_000000"}, {"x-idempotency-key", "TestIdempotencyKey"}] use Plug.Test test "renders meta and data objects" do assert %{ - "meta" => %{ - "code" => 200, - "request_id" => "my_request_id_000000", - "idempotency_key" => "TestIdempotencyKey", - "type" => "object", - "url" => "http://localhost:4001/page" - }, - "data" => %{ - "hello" => "Bob" - } - } = "page" - |> post!(%{ - data: %{ - hello: "Bob", - } - }) - |> get_body - |> refute_key(:urgent) - |> refute_key(:paging) - |> refute_key(:sandbox) + "meta" => %{ + "code" => 200, + "request_id" => "my_request_id_000000", + "idempotency_key" => "TestIdempotencyKey", + "type" => "object", + "url" => "http://localhost:4001/page" + }, + "data" => %{ + "hello" => "Bob" + } + } = + "page" + |> post!(%{ + data: %{ + hello: "Bob" + } + }) + |> get_body + |> refute_key(:urgent) + |> refute_key(:paging) + |> refute_key(:sandbox) end test "overrides object type" do assert %{ - "data" => %{ - "type" => "mytype" - }, - } = "page" - |> post!(%{ - data: %{ - type: "mytype", - hello: "Bob" - } - }) - |> get_body + "data" => %{ + "type" => "mytype" + } + } = + "page" + |> post!(%{ + data: %{ + type: "mytype", + hello: "Bob" + } + }) + |> get_body end test "meta code is http status" do assert %{ - "meta" => %{ - "code" => 401 - } - } = "page" - |> post!(%{ - data: %{ - hello: "Bob", - }, - status: 401 - }) - |> get_body - |> refute_key(:urgent) - |> refute_key(:paging) - |> refute_key(:sandbox) + "meta" => %{ + "code" => 401 + } + } = + "page" + |> post!(%{ + data: %{ + hello: "Bob" + }, + status: 401 + }) + |> get_body + |> refute_key(:urgent) + |> refute_key(:paging) + |> refute_key(:sandbox) end test "skips paging for objects" do "page" |> post!(%{ data: %{ - hello: "Bob", + hello: "Bob" }, paging: %{ limit: 50, @@ -86,25 +88,26 @@ defmodule EViewAcceptanceTest do test "renders sandbox data" do assert %{ - "sandbox" => %{ - "otp_code" => "123" - }, - } = "page" - |> post!(%{ - data: %{ - hello: "Bob", - }, - sandbox: %{ - otp_code: "123" - }, - env: "test" - }) - |> get_body + "sandbox" => %{ + "otp_code" => "123" + } + } = + "page" + |> post!(%{ + data: %{ + hello: "Bob" + }, + sandbox: %{ + otp_code: "123" + }, + env: "test" + }) + |> get_body "page" |> post!(%{ data: %{ - hello: "Bob", + hello: "Bob" }, sandbox: %{ otp_code: "123" @@ -117,225 +120,243 @@ defmodule EViewAcceptanceTest do test "renders urgent data" do assert %{ - "urgent" => %{ - "balance" => 100 - }, - } = "page" - |> post!(%{ - data: %{ - hello: "Bob", - }, - urgent: %{ - balance: 100 - }, - env: "test" - }) - |> get_body + "urgent" => %{ + "balance" => 100 + } + } = + "page" + |> post!(%{ + data: %{ + hello: "Bob" + }, + urgent: %{ + balance: 100 + }, + env: "test" + }) + |> get_body end test "renders list" do assert %{ - "meta" => %{ - "code" => 200, - "request_id" => "my_request_id_000000", - "idempotency_key" => "TestIdempotencyKey", - "type" => "list", - "url" => "http://localhost:4001/page" - }, - "data" => [%{ - "hello" => "Bob" - }] - } = "page" - |> post!(%{ - data: [%{ - hello: "Bob", - }] - }) - |> get_body - |> refute_key(:urgent) - |> refute_key(:paging) - |> refute_key(:sandbox) + "meta" => %{ + "code" => 200, + "request_id" => "my_request_id_000000", + "idempotency_key" => "TestIdempotencyKey", + "type" => "list", + "url" => "http://localhost:4001/page" + }, + "data" => [ + %{ + "hello" => "Bob" + } + ] + } = + "page" + |> post!(%{ + data: [ + %{ + hello: "Bob" + } + ] + }) + |> get_body + |> refute_key(:urgent) + |> refute_key(:paging) + |> refute_key(:sandbox) end test "renders errors" do assert %{ - "meta" => %{ - "code" => 422, - "request_id" => "my_request_id_000000", - "idempotency_key" => "TestIdempotencyKey", - "type" => "object", - "url" => "http://localhost:4001/page" - }, - "error" => %{ - "type" => "invalid_data" - } - } = "page" - |> post!(%{ - status: 422, - data: %{ - type: "invalid_data", - } - }) - |> get_body - |> refute_key(:urgent) - |> refute_key(:paging) - |> refute_key(:sandbox) + "meta" => %{ + "code" => 422, + "request_id" => "my_request_id_000000", + "idempotency_key" => "TestIdempotencyKey", + "type" => "object", + "url" => "http://localhost:4001/page" + }, + "error" => %{ + "type" => "invalid_data" + } + } = + "page" + |> post!(%{ + status: 422, + data: %{ + type: "invalid_data" + } + }) + |> get_body + |> refute_key(:urgent) + |> refute_key(:paging) + |> refute_key(:sandbox) end test "renders 404 error" do assert %{ - "meta" => %{ - "code" => 404, - "type" => "object", - "url" => "http://localhost:4001/not_found" - }, - "error" => %{ - "type" => "not_found" - } - } = "not_found" - |> post!(%{ - data: %{ - type: "invalid_data", - } - }) - |> get_body - |> refute_key(:urgent) - |> refute_key(:paging) - |> refute_key(:sandbox) + "meta" => %{ + "code" => 404, + "type" => "object", + "url" => "http://localhost:4001/not_found" + }, + "error" => %{ + "type" => "not_found" + } + } = + "not_found" + |> post!(%{ + data: %{ + type: "invalid_data" + } + }) + |> get_body + |> refute_key(:urgent) + |> refute_key(:paging) + |> refute_key(:sandbox) end test "renders 500 error" do assert %{ - "meta" => %{ - "code" => 500, - "type" => "object", - "url" => "http://localhost:4001/page" - }, - "error" => %{ - "type" => "internal_error" - } - } = "page" - |> post!(%{ - data: %{ - type: "invalid_data", - }, - status: "not_boolean" - }) - |> get_body - |> refute_key(:urgent) - |> refute_key(:paging) - |> refute_key(:sandbox) + "meta" => %{ + "code" => 500, + "type" => "object", + "url" => "http://localhost:4001/page" + }, + "error" => %{ + "type" => "internal_error" + } + } = + "page" + |> post!(%{ + data: %{ + type: "invalid_data" + }, + status: "not_boolean" + }) + |> get_body + |> refute_key(:urgent) + |> refute_key(:paging) + |> refute_key(:sandbox) end test "renders invalid content-type error" do assert %{ - "meta" => %{ - "code" => 415, - "type" => "object", - "url" => "http://localhost:4001/page" - }, - "error" => %{ - "invalid" => [ - %{ - "entry_type" => "header", - "entry" => "Content-Type" - } - ], - "message" => "Invalid Content-Type header. Try to set 'Content-Type: application/json' header: " <> - "http://docs.apimanifest.apiary.io/#introduction/interacting-with-api/content-type.", - "type" => "content_type_invalid" - } - } = "page" - |> post!(%{ - data: %{ - type: "invalid_data", - } - }, [{"content-type", "application/unknown"}]) - |> get_body - |> refute_key(:urgent) - |> refute_key(:paging) - |> refute_key(:sandbox) + "meta" => %{ + "code" => 415, + "type" => "object", + "url" => "http://localhost:4001/page" + }, + "error" => %{ + "invalid" => [ + %{ + "entry_type" => "header", + "entry" => "Content-Type" + } + ], + "message" => + "Invalid Content-Type header. Try to set 'Content-Type: application/json' header: " <> + "http://docs.apimanifest.apiary.io/#introduction/interacting-with-api/content-type.", + "type" => "content_type_invalid" + } + } = + "page" + |> post!( + %{ + data: %{ + type: "invalid_data" + } + }, + [{"content-type", "application/unknown"}] + ) + |> get_body + |> refute_key(:urgent) + |> refute_key(:paging) + |> refute_key(:sandbox) end test "renders changeset validation errors" do assert %{ - "meta" => %{ - "code" => 422, - "type" => "object", - "url" => "http://localhost:4001/page_via_changeset" - }, - "error" => %{ - "invalid" => [ - %{ - "entry" => "$.loans_count", - "entry_type" => "json_data_property", - "rules" => [ - %{"rule" => "required"} - ] - }, - %{ - "entry" => "$.originator", - "entry_type" => "json_data_property", - "rules" => [ - %{ - "rule" => "required" - } - ] - } - ], - "message" => "Validation failed. You can find validators description at our API Manifest: " <> - "http://docs.apimanifest.apiary.io/#introduction/interacting-with-api/errors.", - "type" => "validation_failed" - } - } = "page_via_changeset" - |> post!(%{ - data: %{ - type: "invalid_data", - }, - status: "not_boolean" - }) - |> get_body - |> refute_key(:urgent) - |> refute_key(:paging) - |> refute_key(:sandbox) + "meta" => %{ + "code" => 422, + "type" => "object", + "url" => "http://localhost:4001/page_via_changeset" + }, + "error" => %{ + "invalid" => [ + %{ + "entry" => "$.loans_count", + "entry_type" => "json_data_property", + "rules" => [ + %{"rule" => "required"} + ] + }, + %{ + "entry" => "$.originator", + "entry_type" => "json_data_property", + "rules" => [ + %{ + "rule" => "required" + } + ] + } + ], + "message" => + "Validation failed. You can find validators description at our API Manifest: " <> + "http://docs.apimanifest.apiary.io/#introduction/interacting-with-api/errors.", + "type" => "validation_failed" + } + } = + "page_via_changeset" + |> post!(%{ + data: %{ + type: "invalid_data" + }, + status: "not_boolean" + }) + |> get_body + |> refute_key(:urgent) + |> refute_key(:paging) + |> refute_key(:sandbox) end test "renders json schema validation errors" do assert %{ - "meta" => %{ - "code" => 422, - "type" => "object", - "url" => "http://localhost:4001/page_via_schema" - }, - "error" => %{ - "invalid" => [ - %{ - "entry" => "$.originator", - "entry_type" => "json_data_property", - "rules" => [ - %{ - "description" => "value is not allowed in enum", - "params" => ["a", "b"], - "rule" => "inclusion" - } - ] - } - ], - "message" => "Validation failed. You can find validators description at our API Manifest: " <> - "http://docs.apimanifest.apiary.io/#introduction/interacting-with-api/errors.", - "type" => "validation_failed" - } - } = "page_via_schema" - |> post!(%{ - data: %{ - originator: "me", - }, - status: "not_boolean" - }) - |> get_body - |> refute_key(:urgent) - |> refute_key(:paging) - |> refute_key(:sandbox) + "meta" => %{ + "code" => 422, + "type" => "object", + "url" => "http://localhost:4001/page_via_schema" + }, + "error" => %{ + "invalid" => [ + %{ + "entry" => "$.originator", + "entry_type" => "json_data_property", + "rules" => [ + %{ + "description" => "value is not allowed in enum", + "params" => ["a", "b"], + "rule" => "inclusion" + } + ] + } + ], + "message" => + "Validation failed. You can find validators description at our API Manifest: " <> + "http://docs.apimanifest.apiary.io/#introduction/interacting-with-api/errors.", + "type" => "validation_failed" + } + } = + "page_via_schema" + |> post!(%{ + data: %{ + originator: "me" + }, + status: "not_boolean" + }) + |> get_body + |> refute_key(:urgent) + |> refute_key(:paging) + |> refute_key(:sandbox) end defp refute_key(map, elem) when is_map(map) do diff --git a/test/acceptance/idempotency_plug_test.exs b/test/acceptance/idempotency_plug_test.exs index f3f92de..d7d8de5 100644 --- a/test/acceptance/idempotency_plug_test.exs +++ b/test/acceptance/idempotency_plug_test.exs @@ -1,20 +1,20 @@ defmodule EView.Plugs.IdempotencyAcceptanceTest do - use EView.AcceptanceCase, + use EView.AcceptanceCase, async: true, otp_app: :eview, endpoint: Demo.Endpoint, - headers: [{"x-request-id", "my_request_id_000000"}, - {"x-idempotency-key", "TestIdempotencyKey"}] + headers: [{"x-request-id", "my_request_id_000000"}, {"x-idempotency-key", "TestIdempotencyKey"}] use Plug.Test test "renders 404 error" do - %{headers: headers} = post!("not_found", %{ - data: %{ - type: "invalid_data", - } - }) + %{headers: headers} = + post!("not_found", %{ + data: %{ + type: "invalid_data" + } + }) - refute is_nil(Enum.find(headers, fn(x) -> x == {"x-idempotency-key", "TestIdempotencyKey"} end)) + refute is_nil(Enum.find(headers, fn x -> x == {"x-idempotency-key", "TestIdempotencyKey"} end)) end end diff --git a/test/test_helper.exs b/test/test_helper.exs index 766b5ef..da22c3a 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -1,4 +1,5 @@ [:ecto, :postgrex, :cowboy, :httpoison, :poison, :phoenix, :timex, :jvalid, :timex_ecto] |> Enum.map(&Application.ensure_all_started/1) + Demo.start() ExUnit.start() diff --git a/test/unit/changeset_validations_parser_test.exs b/test/unit/changeset_validations_parser_test.exs index 61bed7c..fcc03e4 100644 --- a/test/unit/changeset_validations_parser_test.exs +++ b/test/unit/changeset_validations_parser_test.exs @@ -6,18 +6,18 @@ defmodule EView.ChangesetValidationsParserTest do use Ecto.Schema schema "posts" do - field :title, :string, default: "" - field :body - field :uuid, :binary_id - field :decimal, :decimal - field :upvotes, :integer, default: 0 - field :topics, {:array, :string} - field :phones, {:array, :map} - field :uuids, {:array, Ecto.UUID} - field :virtual, :string, virtual: true - field :published_at, :naive_datetime - field :metadata, :map - field :email + field(:title, :string, default: "") + field(:body) + field(:uuid, :binary_id) + field(:decimal, :decimal) + field(:upvotes, :integer, default: 0) + field(:topics, {:array, :string}) + field(:phones, {:array, :map}) + field(:uuids, {:array, Ecto.UUID}) + field(:virtual, :string, virtual: true) + field(:published_at, :naive_datetime) + field(:metadata, :map) + field(:email) end end @@ -25,9 +25,9 @@ defmodule EView.ChangesetValidationsParserTest do use Ecto.Schema schema "posts" do - field :title, :string, default: "" - embeds_many :posts, EView.ChangesetValidationsParserTest.Post - embeds_one :post, EView.ChangesetValidationsParserTest.Post + field(:title, :string, default: "") + embeds_many(:posts, EView.ChangesetValidationsParserTest.Post) + embeds_one(:post, EView.ChangesetValidationsParserTest.Post) end end @@ -46,66 +46,76 @@ defmodule EView.ChangesetValidationsParserTest do changeset = %{upvotes: "not_a_integer"} |> changeset() refute changeset.valid? - assert %{invalid: [ - %{ - entry: "$.upvotes", - entry_type: "json_data_property", - rules: [ - %{ - rule: :cast, - params: [:integer] - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + assert %{ + invalid: [ + %{ + entry: "$.upvotes", + entry_type: "json_data_property", + rules: [ + %{ + rule: :cast, + params: [:integer] + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) end test "query entry type" do changeset = %{upvotes: "not_a_integer"} |> changeset() refute changeset.valid? - assert %{invalid: [ - %{ - entry: "$.upvotes", - entry_type: "query_parameter", - rules: [ - %{ - rule: :cast, - params: [:integer] - } - ] - } - ]} = EView.Views.ValidationError.render("422.query.json", changeset) + assert %{ + invalid: [ + %{ + entry: "$.upvotes", + entry_type: "query_parameter", + rules: [ + %{ + rule: :cast, + params: [:integer] + } + ] + } + ] + } = EView.Views.ValidationError.render("422.query.json", changeset) end test "cast list with UUID" do changeset = changeset(%Post{}, %{"uuids" => ["invalid"]}) - assert %{invalid: [ - %{ - entry: "$.uuids", - rules: [ - %{ - rule: :cast, - params: [:uuid] - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + + assert %{ + invalid: [ + %{ + entry: "$.uuids", + rules: [ + %{ + rule: :cast, + params: [:uuid] + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) end test "cast list with phones" do changeset = changeset(%Post{}, %{"phones" => ["invalid"]}) - assert %{invalid: [ - %{ - entry: "$.phones", - rules: [ - %{ - rule: :cast, - params: [:maps_array] - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + + assert %{ + invalid: [ + %{ + entry: "$.phones", + rules: [ + %{ + rule: :cast, + params: [:maps_array] + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) end test "cast list with phone" do @@ -115,32 +125,37 @@ defmodule EView.ChangesetValidationsParserTest do |> cast_embed(:posts, with: &changeset/2) |> cast_embed(:post, with: &changeset/2) - assert %{invalid: [ - %{ - entry: "$.post", - rules: [ - %{ - rule: :cast, - params: [:map] - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + assert %{ + invalid: [ + %{ + entry: "$.post", + rules: [ + %{ + rule: :cast, + params: [:map] + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) end test "cast list with strings" do changeset = changeset(%Post{}, %{"topics" => ["string", "string", :atom]}) - assert %{invalid: [ - %{ - entry: "$.topics", - rules: [ - %{ - rule: :cast, - params: [:strings_array] - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + + assert %{ + invalid: [ + %{ + entry: "$.topics", + rules: [ + %{ + rule: :cast, + params: [:strings_array] + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) end test "cast embed" do @@ -149,104 +164,112 @@ defmodule EView.ChangesetValidationsParserTest do |> blog_changeset() |> validate_required(:title) - assert %{invalid: [ - %{ - entry: "$.posts", - rules: [ - %{ - rule: :cast, - params: [:maps_array] - } - ] - }, - %{ - entry: "$.title", - rules: [ - %{ - rule: :required, - params: [] - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + assert %{ + invalid: [ + %{ + entry: "$.posts", + rules: [ + %{ + rule: :cast, + params: [:maps_array] + } + ] + }, + %{ + entry: "$.title", + rules: [ + %{ + rule: :required, + params: [] + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) changeset = %{posts: ["invalid type"]} |> blog_changeset() |> validate_required(:title) - assert %{invalid: [ - %{ - entry: "$.posts", - rules: [ - %{ - rule: :cast, - params: [:maps_array] - } - ] - }, - %{ - entry: "$.title", - rules: [ - %{ - rule: :required, - params: [] - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + assert %{ + invalid: [ + %{ + entry: "$.posts", + rules: [ + %{ + rule: :cast, + params: [:maps_array] + } + ] + }, + %{ + entry: "$.title", + rules: [ + %{ + rule: :required, + params: [] + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) changeset = %{posts: [%{upvotes: 11}, %{upvotes: "not_a_integer"}], post: %{upvotes: "not_a_integer"}} |> blog_changeset() |> validate_required(:title) - assert %{invalid: [ - %{ - entry: "$.post.upvotes", - rules: [ - %{ - rule: :cast, - params: [:integer] - } - ] - }, - %{ - entry: "$.posts[1].upvotes", - rules: [ - %{ - rule: :cast, - params: [:integer] - } - ] - }, - %{ - entry: "$.title", - rules: [ - %{ - rule: :required, - params: [] - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + assert %{ + invalid: [ + %{ + entry: "$.post.upvotes", + rules: [ + %{ + rule: :cast, + params: [:integer] + } + ] + }, + %{ + entry: "$.posts[1].upvotes", + rules: [ + %{ + rule: :cast, + params: [:integer] + } + ] + }, + %{ + entry: "$.title", + rules: [ + %{ + rule: :required, + params: [] + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) end test "validate_required/2" do changeset = %{} |> changeset() |> validate_required(:title) refute changeset.valid? - assert %{invalid: [ - %{ - entry: "$.title", - rules: [ - %{ - rule: :required, - params: [] - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + assert %{ + invalid: [ + %{ + entry: "$.title", + rules: [ + %{ + rule: :required, + params: [] + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) end test "validate_format/3" do @@ -257,17 +280,19 @@ defmodule EView.ChangesetValidationsParserTest do refute changeset.valid? - assert %{invalid: [ - %{ - entry: "$.title", - rules: [ - %{ - rule: :format, - params: ["~r/@/"] - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + assert %{ + invalid: [ + %{ + entry: "$.title", + rules: [ + %{ + rule: :format, + params: ["~r/@/"] + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) end test "validate_inclusion/3" do @@ -275,19 +300,22 @@ defmodule EView.ChangesetValidationsParserTest do %{"title" => "hello"} |> changeset() |> validate_inclusion(:title, ~w(world universe)) + refute changeset.valid? - assert %{invalid: [ - %{ - entry: "$.title", - rules: [ - %{ - rule: :inclusion, - params: ["world", "universe"] - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + assert %{ + invalid: [ + %{ + entry: "$.title", + rules: [ + %{ + rule: :inclusion, + params: ["world", "universe"] + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) end test "validate_subset/3" do @@ -298,17 +326,19 @@ defmodule EView.ChangesetValidationsParserTest do refute changeset.valid? - assert %{invalid: [ - %{ - entry: "$.topics", - rules: [ - %{ - rule: :subset, - params: ["cat", "dog"] - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + assert %{ + invalid: [ + %{ + entry: "$.topics", + rules: [ + %{ + rule: :subset, + params: ["cat", "dog"] + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) end test "validate_exclusion/3" do @@ -316,19 +346,22 @@ defmodule EView.ChangesetValidationsParserTest do %{"title" => "world"} |> changeset() |> validate_exclusion(:title, ~w(world)) + refute changeset.valid? - assert %{invalid: [ - %{ - entry: "$.title", - rules: [ - %{ - rule: :exclusion, - params: ["world"] - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + assert %{ + invalid: [ + %{ + entry: "$.title", + rules: [ + %{ + rule: :exclusion, + params: ["world"] + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) end test "validate_length/3 with string" do @@ -336,73 +369,85 @@ defmodule EView.ChangesetValidationsParserTest do %{"title" => "world"} |> changeset() |> validate_length(:title, min: 6, max: 5, is: 3) + refute changeset.valid? - assert %{invalid: [ - %{ - entry: "$.title", - rules: [ - %{ - rule: :length, - params: %{min: 6, max: 5, is: 3} - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + assert %{ + invalid: [ + %{ + entry: "$.title", + rules: [ + %{ + rule: :length, + params: %{min: 6, max: 5, is: 3} + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) changeset = %{"title" => "world"} |> changeset() |> validate_length(:title, min: 6) + refute changeset.valid? - assert %{invalid: [ - %{ - entry: "$.title", - rules: [ - %{ - rule: :length, - params: %{min: 6} - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + assert %{ + invalid: [ + %{ + entry: "$.title", + rules: [ + %{ + rule: :length, + params: %{min: 6} + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) changeset = %{"title" => "world"} |> changeset() |> validate_length(:title, max: 4) + refute changeset.valid? - assert %{invalid: [ - %{ - entry: "$.title", - rules: [ - %{ - rule: :length, - params: %{max: 4} - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + assert %{ + invalid: [ + %{ + entry: "$.title", + rules: [ + %{ + rule: :length, + params: %{max: 4} + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) changeset = %{"title" => "world"} |> changeset() |> validate_length(:title, is: 10) + refute changeset.valid? - assert %{invalid: [ - %{ - entry: "$.title", - rules: [ - %{ - rule: :length, - params: %{is: 10} - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + assert %{ + invalid: [ + %{ + entry: "$.title", + rules: [ + %{ + rule: :length, + params: %{is: 10} + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) end test "validate_length/3 with list" do @@ -410,73 +455,85 @@ defmodule EView.ChangesetValidationsParserTest do %{"topics" => ["Politics", "Security"]} |> changeset() |> validate_length(:topics, min: 3, max: 3, is: 3) + refute changeset.valid? - assert %{invalid: [ - %{ - entry: "$.topics", - rules: [ - %{ - rule: :length, - params: %{min: 3, max: 3, is: 3} - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + assert %{ + invalid: [ + %{ + entry: "$.topics", + rules: [ + %{ + rule: :length, + params: %{min: 3, max: 3, is: 3} + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) changeset = %{"topics" => ["Politics", "Security"]} |> changeset() |> validate_length(:topics, min: 6, foo: true) + refute changeset.valid? - assert %{invalid: [ - %{ - entry: "$.topics", - rules: [ - %{ - rule: :length, - params: %{min: 6, foo: true} - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + assert %{ + invalid: [ + %{ + entry: "$.topics", + rules: [ + %{ + rule: :length, + params: %{min: 6, foo: true} + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) changeset = %{"topics" => ["Politics", "Security", "Economy"]} |> changeset() |> validate_length(:topics, max: 2) + refute changeset.valid? - assert %{invalid: [ - %{ - entry: "$.topics", - rules: [ - %{ - rule: :length, - params: %{max: 2} - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + assert %{ + invalid: [ + %{ + entry: "$.topics", + rules: [ + %{ + rule: :length, + params: %{max: 2} + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) changeset = %{"topics" => ["Politics", "Security"]} |> changeset() |> validate_length(:topics, is: 10) + refute changeset.valid? - assert %{invalid: [ - %{ - entry: "$.topics", - rules: [ - %{ - rule: :length, - params: %{is: 10} - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + assert %{ + invalid: [ + %{ + entry: "$.topics", + rules: [ + %{ + rule: :length, + params: %{is: 10} + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) end test "validate_number/3" do @@ -485,37 +542,44 @@ defmodule EView.ChangesetValidationsParserTest do %{"upvotes" => -1} |> changeset() |> validate_number(:upvotes, greater_than: 0) + refute changeset.valid? - assert %{invalid: [ - %{ - entry: "$.upvotes", - rules: [ - %{ - rule: :number, - params: %{greater_than: 0} - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + assert %{ + invalid: [ + %{ + entry: "$.upvotes", + rules: [ + %{ + rule: :number, + params: %{greater_than: 0} + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) # Multiple validations with multiple errors changeset = %{"upvotes" => 3} |> changeset() |> validate_number(:upvotes, greater_than: 100, less_than: 0) + refute changeset.valid? - assert %{invalid: [ - %{ - entry: "$.upvotes", - rules: [ - %{ - rule: :number, - params: %{greater_than: 100, less_than: 0} - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + + assert %{ + invalid: [ + %{ + entry: "$.upvotes", + rules: [ + %{ + rule: :number, + params: %{greater_than: 100, less_than: 0} + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) end test "validate_confirmation/3" do @@ -523,111 +587,129 @@ defmodule EView.ChangesetValidationsParserTest do %{"title" => "title"} |> changeset() |> validate_confirmation(:title, required: true) + refute changeset.valid? - assert %{invalid: [ - %{ - entry: "$.title_confirmation", - rules: [ - %{ - rule: :required, - params: [] - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + assert %{ + invalid: [ + %{ + entry: "$.title_confirmation", + rules: [ + %{ + rule: :required, + params: [] + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) changeset = %{"title" => "title", "title_confirmation" => nil} |> changeset() |> validate_confirmation(:title) + refute changeset.valid? - assert %{invalid: [ - %{ - entry: "$.title_confirmation", - rules: [ - %{ - rule: :confirmation, - params: [] - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + assert %{ + invalid: [ + %{ + entry: "$.title_confirmation", + rules: [ + %{ + rule: :confirmation, + params: [] + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) changeset = %{"title" => "title", "title_confirmation" => "not title"} |> changeset() |> validate_confirmation(:title) + refute changeset.valid? - assert %{invalid: [ - %{ - entry: "$.title_confirmation", - rules: [ - %{ - rule: :confirmation, - params: [] - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + assert %{ + invalid: [ + %{ + entry: "$.title_confirmation", + rules: [ + %{ + rule: :confirmation, + params: [] + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) changeset = %{"title" => "title", "title_confirmation" => "not title"} |> changeset() |> validate_confirmation(:title, message: "doesn't match field below") + refute changeset.valid? - assert %{invalid: [ - %{ - entry: "$.title_confirmation", - rules: [ - %{ - rule: :confirmation, - params: [] - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + assert %{ + invalid: [ + %{ + entry: "$.title_confirmation", + rules: [ + %{ + rule: :confirmation, + params: [] + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) # With blank change changeset = %{"password" => "", "password_confirmation" => "password"} |> changeset() |> validate_confirmation(:password) + refute changeset.valid? - assert %{invalid: [ - %{ - entry: "$.password_confirmation", - rules: [ - %{ - rule: :confirmation, - params: [] - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + assert %{ + invalid: [ + %{ + entry: "$.password_confirmation", + rules: [ + %{ + rule: :confirmation, + params: [] + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) # With missing change changeset = %{"password_confirmation" => "password"} |> changeset() |> validate_confirmation(:password) + refute changeset.valid? - assert %{invalid: [ - %{ - entry: "$.password_confirmation", - rules: [ - %{ - rule: :confirmation, - params: [] - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + assert %{ + invalid: [ + %{ + entry: "$.password_confirmation", + rules: [ + %{ + rule: :confirmation, + params: [] + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) end test "validate_acceptance/3" do @@ -635,37 +717,43 @@ defmodule EView.ChangesetValidationsParserTest do %{"terms_of_service" => "false"} |> changeset() |> validate_acceptance(:terms_of_service) + refute changeset.valid? - assert %{invalid: [ - %{ - entry: "$.terms_of_service", - rules: [ - %{ - rule: :acceptance, - params: [] - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + assert %{ + invalid: [ + %{ + entry: "$.terms_of_service", + rules: [ + %{ + rule: :acceptance, + params: [] + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) changeset = %{} |> changeset() |> validate_acceptance(:terms_of_service, message: "must be abided") + refute changeset.valid? - assert %{invalid: [ - %{ - entry: "$.terms_of_service", - rules: [ - %{ - rule: :acceptance, - params: [] - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + assert %{ + invalid: [ + %{ + entry: "$.terms_of_service", + rules: [ + %{ + rule: :acceptance, + params: [] + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) end test "validate_email/3" do @@ -673,26 +761,30 @@ defmodule EView.ChangesetValidationsParserTest do %{"email" => "email@example.com"} |> changeset() |> EView.Changeset.Validators.Email.validate_email(:email) + assert changeset.valid? changeset = %{"email" => "plainaddress"} |> changeset() |> EView.Changeset.Validators.Email.validate_email(:email) + refute changeset.valid? - assert %{invalid: [ - %{ - entry: "$.email", - rules: [ - %{ - rule: :email, - params: [_], - description: "is not a valid email" - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + assert %{ + invalid: [ + %{ + entry: "$.email", + rules: [ + %{ + rule: :email, + params: [_], + description: "is not a valid email" + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) end test "validate_phone_number/3" do @@ -700,26 +792,30 @@ defmodule EView.ChangesetValidationsParserTest do %{"virtual" => "+380631112233"} |> changeset() |> EView.Changeset.Validators.PhoneNumber.validate_phone_number(:virtual) + assert changeset.valid? changeset = %{"virtual" => "not_a_number"} |> changeset() |> EView.Changeset.Validators.PhoneNumber.validate_phone_number(:virtual) + refute changeset.valid? - assert %{invalid: [ - %{ - entry: "$.virtual", - rules: [ - %{ - rule: :phone_number, - params: [_], - description: "is not a valid phone number" - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + assert %{ + invalid: [ + %{ + entry: "$.virtual", + rules: [ + %{ + rule: :phone_number, + params: [_], + description: "is not a valid phone number" + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) end test "validate_card_number/3" do @@ -727,46 +823,55 @@ defmodule EView.ChangesetValidationsParserTest do %{"virtual" => "5457000000000007"} |> changeset() |> EView.Changeset.Validators.CardNumber.validate_card_number(:virtual) + assert changeset.valid? changeset = %{"virtual" => "5457000000000001"} |> changeset() |> EView.Changeset.Validators.CardNumber.validate_card_number(:virtual) + refute changeset.valid? - assert %{invalid: [ - %{ - entry: "$.virtual", - rules: [ - %{ - rule: :card_number, - params: [], - description: "is not a valid card number" - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + assert %{ + invalid: [ + %{ + entry: "$.virtual", + rules: [ + %{ + rule: :card_number, + params: [], + description: "is not a valid card number" + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) changeset = %{"virtual" => "5457000000000001"} |> changeset() - |> EView.Changeset.Validators.CardNumber.validate_card_number(:virtual, - message: "is not a valid card number. We accept only: %{allowed_card_types}") + |> EView.Changeset.Validators.CardNumber.validate_card_number( + :virtual, + message: "is not a valid card number. We accept only: %{allowed_card_types}" + ) + refute changeset.valid? - assert %{invalid: [ - %{ - entry: "$.virtual", - rules: [ - %{ - rule: :card_number, - params: [], - description: "is not a valid card number. We accept only: visa, master_card" - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + assert %{ + invalid: [ + %{ + entry: "$.virtual", + rules: [ + %{ + rule: :card_number, + params: [], + description: "is not a valid card number. We accept only: visa, master_card" + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) end test "cast maps" do @@ -774,101 +879,113 @@ defmodule EView.ChangesetValidationsParserTest do %{"metadata" => "{'upvotes': 'not_a_integer'}"} |> changeset() - assert %{invalid: [ - %{ - entry: "$.metadata", - rules: [ - %{ - rule: :cast, - params: [:map] - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + assert %{ + invalid: [ + %{ + entry: "$.metadata", + rules: [ + %{ + rule: :cast, + params: [:map] + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) end test "validate_metadata/3" do changeset = - %{"metadata" => %{ - "my_key": "meta_value", - "int_key": 1337, - "list_key": ["a", "b", "c"] - }} + %{ + "metadata" => %{ + my_key: "meta_value", + int_key: 1337, + list_key: ["a", "b", "c"] + } + } |> changeset() |> EView.Changeset.Validators.Metadata.validate_metadata(:metadata) + assert changeset.valid? changeset = %{"metadata" => "not_an_object"} |> changeset() |> EView.Changeset.Validators.Metadata.validate_metadata(:metadata) + refute changeset.valid? - assert %{invalid: [ - %{ - entry: "$.metadata", - rules: [ - %{ - rule: :cast, - params: [:map] - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + assert %{ + invalid: [ + %{ + entry: "$.metadata", + rules: [ + %{ + rule: :cast, + params: [:map] + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) changeset = - %{"metadata" => %{ - "lo" <> String.duplicate("o", 100) <> "ong_key" => "val", - "foo" => String.duplicate("bar", 300), - "list" => 1..200, - "string_list" => ["a", String.duplicate("bar", 300)] - }} + %{ + "metadata" => %{ + ("lo" <> String.duplicate("o", 100) <> "ong_key") => "val", + "foo" => String.duplicate("bar", 300), + "list" => 1..200, + "string_list" => ["a", String.duplicate("bar", 300)] + } + } |> changeset() |> EView.Changeset.Validators.Metadata.validate_metadata(:metadata) refute changeset.valid? - assert %{invalid: [ - %{ - entry: "$.metadata.foo", - rules: [ - %{ - description: "value should be up to 500 characters", - rule: :length, - params: %{max: 500} - } - ] - }, - %{ - entry: "$.metadata.list", - rules: [ - %{ - description: "is invalid", - rule: :cast, - params: [:integer, :float, :decimal, :string] - } - ] - }, - %{ - entry: "$.metadata.lo" <> _, - rules: [ - %{ - description: "key should be up to 100 characters", - rule: :length, - params: %{max: 100} - } - ] - }, - %{ - entry: "$.metadata.string_list[1]" <> _, - rules: [ - %{ - description: "list keys should be up to 100 characters", - rule: :length, - params: %{max: 100} - } - ] - } - ]} = EView.Views.ValidationError.render("422.json", changeset) + assert %{ + invalid: [ + %{ + entry: "$.metadata.foo", + rules: [ + %{ + description: "value should be up to 500 characters", + rule: :length, + params: %{max: 500} + } + ] + }, + %{ + entry: "$.metadata.list", + rules: [ + %{ + description: "is invalid", + rule: :cast, + params: [:integer, :float, :decimal, :string] + } + ] + }, + %{ + entry: "$.metadata.lo" <> _, + rules: [ + %{ + description: "key should be up to 100 characters", + rule: :length, + params: %{max: 100} + } + ] + }, + %{ + entry: "$.metadata.string_list[1]" <> _, + rules: [ + %{ + description: "list keys should be up to 100 characters", + rule: :length, + params: %{max: 100} + } + ] + } + ] + } = EView.Views.ValidationError.render("422.json", changeset) end end diff --git a/test/unit/eview_test.exs b/test/unit/eview_test.exs index a166456..df3660f 100644 --- a/test/unit/eview_test.exs +++ b/test/unit/eview_test.exs @@ -17,8 +17,8 @@ defmodule EView.Test do result = resp_body - |> List.to_string - |> Poison.decode! + |> List.to_string() + |> Poison.decode!() |> Map.get("data") assert %{"a" => 1} = result @@ -30,11 +30,17 @@ defmodule EView.Test do page_size: 5, total_pages: 5, total_entries: 25, - entries: [], + entries: [] } + conn = %Plug.Conn{ - scheme: :http, host: "test", port: 80, request_path: "test", assigns: %{paging: paging} + scheme: :http, + host: "test", + port: 80, + request_path: "test", + assigns: %{paging: paging} } + assert Map.delete(paging, :entries) == Root.render([%{id: 1}, %{id: 2}], conn).paging end end diff --git a/test/unit/sanitizer_test.exs b/test/unit/sanitizer_test.exs index 908b473..f6d1b15 100644 --- a/test/unit/sanitizer_test.exs +++ b/test/unit/sanitizer_test.exs @@ -8,7 +8,7 @@ defmodule EView.Helpers.SanitizerTest do end test "turns map into sanitized maps" do - assert %{a: [1, 2]} = Sanitizer.sanitize(%{a: {1,2}}) + assert %{a: [1, 2]} = Sanitizer.sanitize(%{a: {1, 2}}) end test "turns lists into sanitized lists" do