From 2189f84ed757c6fe110ea934770753762aa3098d Mon Sep 17 00:00:00 2001 From: Isaac Yonemoto Date: Tue, 4 Apr 2023 13:52:26 -0500 Subject: [PATCH] tests on minItems and contains --- .formatter.exs | 6 +++ lib/exonerate/combining/one_of.ex | 8 +++- lib/exonerate/context.ex | 8 +++- lib/exonerate/filter/dependencies.ex | 8 +++- lib/exonerate/filter/format.ex | 51 ++++++++++++++++------- lib/exonerate/type/array/find_iterator.ex | 29 ++++++++++--- lib/exonerate/type/string.ex | 8 +++- test/misc_test.exs | 29 ++++++++++++- test/readme_test.exs | 4 ++ test/support/readme.ex | 17 ++++++++ 10 files changed, 143 insertions(+), 25 deletions(-) create mode 100644 .formatter.exs create mode 100644 test/readme_test.exs create mode 100644 test/support/readme.ex diff --git a/.formatter.exs b/.formatter.exs new file mode 100644 index 0000000..45d1f02 --- /dev/null +++ b/.formatter.exs @@ -0,0 +1,6 @@ +# Used by "mix format" +[ + inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"], + # some files in gpt-3.5 have syntax errors. + subdirectories: ["bench"] +] diff --git a/lib/exonerate/combining/one_of.ex b/lib/exonerate/combining/one_of.ex index 38f7196..7a1185d 100644 --- a/lib/exonerate/combining/one_of.ex +++ b/lib/exonerate/combining/one_of.ex @@ -52,7 +52,9 @@ defmodule Exonerate.Combining.OneOf do unquote(lambdas) |> Enum.reduce_while( - {Exonerate.Tools.mismatch(data, unquote(resource), unquote(pointer), path, reason: "no matches"), 0}, + {Exonerate.Tools.mismatch(data, unquote(resource), unquote(pointer), path, + reason: "no matches" + ), 0}, fn fun, {{:error, opts}, index} -> case fun.(data, path) do @@ -98,7 +100,9 @@ defmodule Exonerate.Combining.OneOf do unquote(lambdas) |> Enum.reduce_while( - {Exonerate.Tools.mismatch(data, unquote(resource), unquote(pointer), path, reason: "no matches"), 0}, + {Exonerate.Tools.mismatch(data, unquote(resource), unquote(pointer), path, + reason: "no matches" + ), 0}, fn fun, {{:error, opts}, index} -> case fun.(data, path) do diff --git a/lib/exonerate/context.ex b/lib/exonerate/context.ex index 40506c1..9ab5cf1 100644 --- a/lib/exonerate/context.ex +++ b/lib/exonerate/context.ex @@ -210,7 +210,13 @@ defmodule Exonerate.Context do quote do defp unquote(Tools.call(resource, pointer, opts))(content, path) do require Exonerate.Tools - Exonerate.Tools.mismatch(content, unquote(resource), unquote(type_failure_pointer), path) + + Exonerate.Tools.mismatch( + content, + unquote(resource), + unquote(type_failure_pointer), + path + ) end end, opts diff --git a/lib/exonerate/filter/dependencies.ex b/lib/exonerate/filter/dependencies.ex index 2402a58..346bb9e 100644 --- a/lib/exonerate/filter/dependencies.ex +++ b/lib/exonerate/filter/dependencies.ex @@ -48,7 +48,13 @@ defmodule Exonerate.Filter.Dependencies do :ok else require Exonerate.Tools - Exonerate.Tools.mismatch(content, unquote(resource), unquote(schema_pointer), path) + + Exonerate.Tools.mismatch( + content, + unquote(resource), + unquote(schema_pointer), + path + ) end end end) diff --git a/lib/exonerate/filter/format.ex b/lib/exonerate/filter/format.ex index 84997f1..75532f5 100644 --- a/lib/exonerate/filter/format.ex +++ b/lib/exonerate/filter/format.ex @@ -66,8 +66,11 @@ defmodule Exonerate.Filter.Format do |> String.upcase() |> NaiveDateTime.from_iso8601() |> case do - {:ok, _} -> :ok - {:error, _} -> Exonerate.Tools.mismatch(string, unquote(resource), unquote(pointer), path) + {:ok, _} -> + :ok + + {:error, _} -> + Exonerate.Tools.mismatch(string, unquote(resource), unquote(pointer), path) end end end @@ -106,8 +109,11 @@ defmodule Exonerate.Filter.Format do |> String.upcase() |> DateTime.from_iso8601() |> case do - {:ok, %{utc_offset: _}, _} -> :ok - {:error, _} -> Exonerate.Tools.mismatch(string, unquote(resource), unquote(pointer), path) + {:ok, %{utc_offset: _}, _} -> + :ok + + {:error, _} -> + Exonerate.Tools.mismatch(string, unquote(resource), unquote(pointer), path) end end end @@ -119,8 +125,11 @@ defmodule Exonerate.Filter.Format do require Exonerate.Tools case Date.from_iso8601(string) do - {:ok, _} -> :ok - {:error, _} -> Exonerate.Tools.mismatch(string, unquote(resource), unquote(pointer), path) + {:ok, _} -> + :ok + + {:error, _} -> + Exonerate.Tools.mismatch(string, unquote(resource), unquote(pointer), path) end end end @@ -132,8 +141,11 @@ defmodule Exonerate.Filter.Format do require Exonerate.Tools case Time.from_iso8601(string) do - {:ok, _} -> :ok - {:error, _} -> Exonerate.Tools.mismatch(string, unquote(resource), unquote(pointer), path) + {:ok, _} -> + :ok + + {:error, _} -> + Exonerate.Tools.mismatch(string, unquote(resource), unquote(pointer), path) end end end @@ -146,8 +158,11 @@ defmodule Exonerate.Filter.Format do # NB ipv4strict means no "shortened ipv4 addresses" case :inet.parse_ipv4strict_address(to_charlist(string)) do - {:ok, _} -> :ok - {:error, _} -> Exonerate.Tools.mismatch(string, unquote(resource), unquote(pointer), path) + {:ok, _} -> + :ok + + {:error, _} -> + Exonerate.Tools.mismatch(string, unquote(resource), unquote(pointer), path) end end end @@ -257,7 +272,9 @@ defmodule Exonerate.Filter.Format do :ok tuple when elem(tuple, 0) == :error -> - Exonerate.Tools.mismatch(string, unquote(resource), unquote(pointer), path, reason: elem(tuple, 1)) + Exonerate.Tools.mismatch(string, unquote(resource), unquote(pointer), path, + reason: elem(tuple, 1) + ) end end end @@ -305,7 +322,9 @@ defmodule Exonerate.Filter.Format do :ok {:error, reason} -> - Exonerate.Tools.mismatch(string, unquote(resource), unquote(pointer), path, reason: reason) + Exonerate.Tools.mismatch(string, unquote(resource), unquote(pointer), path, + reason: reason + ) end end end @@ -321,7 +340,9 @@ defmodule Exonerate.Filter.Format do :ok {:error, reason} -> - Exonerate.Tools.mismatch(string, unquote(resource), unquote(pointer), path, reason: reason) + Exonerate.Tools.mismatch(string, unquote(resource), unquote(pointer), path, + reason: reason + ) end end end @@ -337,7 +358,9 @@ defmodule Exonerate.Filter.Format do :ok {:error, reason} -> - Exonerate.Tools.mismatch(string, unquote(resource), unquote(pointer), path, reason: reason) + Exonerate.Tools.mismatch(string, unquote(resource), unquote(pointer), path, + reason: reason + ) end end end diff --git a/lib/exonerate/type/array/find_iterator.ex b/lib/exonerate/type/array/find_iterator.ex index 2c912ca..048a38a 100644 --- a/lib/exonerate/type/array/find_iterator.ex +++ b/lib/exonerate/type/array/find_iterator.ex @@ -41,22 +41,26 @@ defmodule Exonerate.Type.Array.FindIterator do content |> Enum.reduce_while( - {Exonerate.Tools.mismatch(content, unquote(resource), unquote(contains_pointer), path), 0, 0}, + {Exonerate.Tools.mismatch(content, unquote(resource), unquote(contains_pointer), path), + 0, 0}, fn _item, {:ok, index, count} when index >= unquote(length) -> {:halt, {:ok, index, count}} + _item, {:ok, index, count} -> + {:halt, {:ok, index + 1, count}} + item, {{:error, error_so_far}, index, count} -> case unquote(contains_call)(item, Path.join(path, "#{index}")) do :ok when count >= unquote(needed) -> {:cont, {:ok, index + 1, count}} :ok -> - {:cont, {:error, error_so_far}, index + 1, count + 1} + {:cont, {{:error, error_so_far}, index + 1, count + 1}} Exonerate.Tools.error_match(error) -> new_params = Keyword.update(error_so_far, :errors, [error], &[error | &1]) - {:cont, {{:error, error_so_far}, index + 1}} + {:cont, {{:error, error_so_far}, index + 1, count}} end end ) @@ -77,7 +81,21 @@ defmodule Exonerate.Type.Array.FindIterator do path ) - {Exonerate.Tools.error_match(error), _} -> + {:ok, _, _} -> + :ok + + {Exonerate.Tools.error_match(error), count, unquote(needed)} when count >= unquote(length) -> + :ok + + {Exonerate.Tools.error_match(error), count, unquote(needed)} -> + Exonerate.Tools.mismatch( + content, + unquote(resource), + unquote(JsonPointer.join(pointer, "minContains")), + path + ) + + {Exonerate.Tools.error_match(error), _, _} -> error end end @@ -97,7 +115,8 @@ defmodule Exonerate.Type.Array.FindIterator do content |> Enum.reduce_while( - {Exonerate.Tools.mismatch(content, unquote(resource), unquote(contains_pointer), path), 0, 0}, + {Exonerate.Tools.mismatch(content, unquote(resource), unquote(contains_pointer), path), + 0, 0}, fn item, {{:error, params}, index, count} -> case unquote(contains_call)(item, path) do diff --git a/lib/exonerate/type/string.ex b/lib/exonerate/type/string.ex index 39b158f..657caa6 100644 --- a/lib/exonerate/type/string.ex +++ b/lib/exonerate/type/string.ex @@ -45,7 +45,13 @@ defmodule Exonerate.Type.String do unquote(filters) else require Exonerate.Tools - Exonerate.Tools.mismatch(string, unquote(resource), unquote(non_utf_error_pointer), path) + + Exonerate.Tools.mismatch( + string, + unquote(resource), + unquote(non_utf_error_pointer), + path + ) end end end diff --git a/test/misc_test.exs b/test/misc_test.exs index 73e953f..3c5a39b 100644 --- a/test/misc_test.exs +++ b/test/misc_test.exs @@ -68,5 +68,32 @@ defmodule ExonerateTest.MiscTest do end end - test "array with minItems AND contains" + Exonerate.function_from_string( + :def, + :minitems_contains, + """ + { + "minItems": 2, + "contains": {"const": "foo"} + } + """ + ) + + describe "array with minItems AND contains" do + test "doesn't contain enough items" do + assert {:error, _} = minitems_contains(["foo"]) + end + + test "dosn't contain the right item" do + assert {:error, _} = minitems_contains(["bar", "baz"]) + end + + test "doesn't contain either the right item or enough items" do + assert {:error, _} = minitems_contains(["bar"]) + end + + test "contains the right item and enough items" do + assert :ok == minitems_contains(["foo", "bar"]) + end + end end diff --git a/test/readme_test.exs b/test/readme_test.exs new file mode 100644 index 0000000..924a092 --- /dev/null +++ b/test/readme_test.exs @@ -0,0 +1,4 @@ +defmodule ExonerateTest.ReadmeTest do + use ExUnit.Case + doctest ExonerateTest.Readme +end diff --git a/test/support/readme.ex b/test/support/readme.ex new file mode 100644 index 0000000..ce0ca0c --- /dev/null +++ b/test/support/readme.ex @@ -0,0 +1,17 @@ +# bootstraps content for the readme tests + +readme = Path.join(__DIR__, "../../README.md") + +[module, tests] = + readme + |> File.read!() + |> String.split("```elixir") + |> Enum.map(&hd(String.split(&1, "```"))) + |> Enum.slice(2..-1) + +Code.eval_string(module) + +defmodule ExonerateTest.Readme do + @external_resource readme + @moduledoc tests +end