Skip to content

Commit

Permalink
Use Decimal to improve precision of multipleOf validation
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanchrobot committed Sep 8, 2021
1 parent 81c8b03 commit 6ddd87a
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 17 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
[![License](https://img.shields.io/hexpm/l/ex_json_schema.svg)](https://github.com/jonasschmidt/ex_json_schema/blob/master/LICENSE)
[![Last Updated](https://img.shields.io/github/last-commit/jonasschmidt/ex_json_schema.svg)](https://github.com/jonasschmidt/ex_json_schema/commits/master)

A JSON Schema validator with support for the draft 4, draft 6 and draft 7 specifications and zero dependencies. Passes the official [JSON Schema Test Suite](https://github.com/json-schema/JSON-Schema-Test-Suite).
A JSON Schema validator with support for the draft 4, draft 6 and draft 7 specifications. Passes the official [JSON Schema Test Suite](https://github.com/json-schema/JSON-Schema-Test-Suite).

## Installation

Expand Down
32 changes: 16 additions & 16 deletions lib/ex_json_schema/validator/multiple_of.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ defmodule ExJsonSchema.Validator.MultipleOf do
alias ExJsonSchema.Validator.Error

@behaviour ExJsonSchema.Validator
@zero Decimal.new(0)

@impl ExJsonSchema.Validator
def validate(_, _, {"multipleOf", multiple_of}, data, _) do
Expand All @@ -19,28 +20,27 @@ defmodule ExJsonSchema.Validator.MultipleOf do
[]
end

defp do_validate(_, 0) do
[]
end

defp do_validate(0, _) do
# "Expected multipleOf to be > 1."
[%Error{error: %Error.MultipleOf{expected: 0}}]
defp do_validate(multiple_of, data) when is_number(multiple_of) and is_number(data) do
dec_multiple_of = dec(multiple_of)
dec_data = dec(data)

cond do
dec_multiple_of == @zero -> [%Error{error: %Error.MultipleOf{expected: 0}}]
dec_data == @zero -> []
Decimal.integer?(Decimal.div(dec_data, dec_multiple_of)) -> []
true -> [%Error{error: %Error.MultipleOf{expected: multiple_of}}]
end
end

defp do_validate(_, data) when not is_number(data) do
defp do_validate(_, _) do
[]
end

defp do_validate(multiple_of, data) when is_number(multiple_of) and is_number(data) do
if Float.ceil(data / multiple_of) == Float.floor(data / multiple_of) do
[]
defp dec(number) do
if is_float(number) do
Decimal.from_float(number)
else
[%Error{error: %Error.MultipleOf{expected: multiple_of}}]
Decimal.new(number)
end
end

defp do_validate(_, _) do
[]
end
end
1 change: 1 addition & 0 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ defmodule ExJsonSchema.Mixfile do

defp deps do
[
{:decimal, "~> 2.0"},
{:dialyxir, "~> 0.5", only: [:test], runtime: false},
{:ex_doc, ">= 0.0.0", only: :dev, runtime: false},
{:excoveralls, "~> 0.10", only: :test},
Expand Down
19 changes: 19 additions & 0 deletions test/ex_json_schema/validator_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,25 @@ defmodule ExJsonSchema.ValidatorTest do
[{"Expected value to be a multiple of 2.", "#"}],
[%Error{error: %Error.MultipleOf{expected: 2}, path: "#"}]
)

assert_validation_errors(
%{"multipleOf" => 0.1},
123.45,
[{"Expected value to be a multiple of 0.1.", "#"}],
[%Error{error: %Error.MultipleOf{expected: 0.1}, path: "#"}]
)

assert valid?(%{"multipleOf" => 5}, 0)
end

test "multiple of validator division by 0" do
assert ExJsonSchema.Validator.MultipleOf.validate(nil, nil, {"multipleOf", 0}, 5, nil) ==
[%Error{error: %Error.MultipleOf{expected: 0}}]
end

test "multiple of precision" do
assert valid?(%{"multipleOf" => 0.01}, 147.41)
assert valid?(%{"multipleOf" => 0.01}, 147.42)
end

test "validation errors for minimum length" do
Expand Down

0 comments on commit 6ddd87a

Please sign in to comment.