diff --git a/.credo.exs b/.credo.exs index 97103fa..7cad977 100644 --- a/.credo.exs +++ b/.credo.exs @@ -10,7 +10,7 @@ configs: [ %{ # - # Run any exec using `mix credo -C `. If no exec name is given + # Run any config using `mix credo -C `. If no config name is given # "default" is used. # name: "default", @@ -39,6 +39,10 @@ # strict: false, # + # To modify the timeout for parsing files, change this value: + # + parse_timeout: 5000, + # # If you want to use uncolored output by default, you can change `color` # to `false` below: # @@ -51,107 +55,76 @@ # # {Credo.Check.Design.DuplicatedCode, false} # - checks: [ - # - ## Consistency Checks - # - {Credo.Check.Consistency.ExceptionNames, []}, - {Credo.Check.Consistency.LineEndings, []}, - {Credo.Check.Consistency.MultiAliasImportRequireUse, false}, - {Credo.Check.Consistency.ParameterPatternMatching, []}, - {Credo.Check.Consistency.SpaceAroundOperators, false}, - {Credo.Check.Consistency.SpaceInParentheses, false}, - {Credo.Check.Consistency.TabsOrSpaces, []}, - {Credo.Check.Consistency.UnusedVariableNames, false}, + checks: %{ + enabled: [ + # + ## Consistency Checks + # + {Credo.Check.Consistency.ExceptionNames, []}, + {Credo.Check.Consistency.LineEndings, []}, + {Credo.Check.Consistency.ParameterPatternMatching, []}, + {Credo.Check.Consistency.TabsOrSpaces, []}, - # - ## Design Checks - # - # You can customize the priority of any check - # Priority values are: `low, normal, high, higher` - # - {Credo.Check.Design.AliasUsage, - [priority: :low, if_nested_deeper_than: 4, if_called_more_often_than: 2]}, - {Credo.Check.Design.DuplicatedCode, false}, - {Credo.Check.Design.TagTODO, false}, - {Credo.Check.Design.TagFIXME, false}, + # + ## Design Checks + # + # You can customize the priority of any check + # Priority values are: `low, normal, high, higher` + # + {Credo.Check.Design.AliasUsage, + [priority: :low, if_nested_deeper_than: 4, if_called_more_often_than: 2]}, - # - ## Readability Checks - # - {Credo.Check.Readability.AliasAs, false}, - {Credo.Check.Readability.AliasOrder, false}, - {Credo.Check.Readability.FunctionNames, []}, - {Credo.Check.Readability.LargeNumbers, []}, - {Credo.Check.Readability.MaxLineLength, false}, - {Credo.Check.Readability.ModuleAttributeNames, []}, - {Credo.Check.Readability.ModuleDoc, []}, - {Credo.Check.Readability.ModuleNames, []}, - {Credo.Check.Readability.MultiAlias, false}, - {Credo.Check.Readability.ParenthesesInCondition, []}, - {Credo.Check.Readability.ParenthesesOnZeroArityDefs, []}, - {Credo.Check.Readability.PredicateFunctionNames, false}, - {Credo.Check.Readability.PreferImplicitTry, []}, - {Credo.Check.Readability.RedundantBlankLines, [max_blank_lines: 1]}, - {Credo.Check.Readability.Semicolons, []}, - {Credo.Check.Readability.SinglePipe, false}, - {Credo.Check.Readability.SpaceAfterCommas, false}, - {Credo.Check.Readability.Specs, false}, - {Credo.Check.Readability.StringSigils, []}, - {Credo.Check.Readability.TrailingBlankLine, []}, - {Credo.Check.Readability.TrailingWhiteSpace, []}, - # TODO: enable by default in Credo 1.1 - {Credo.Check.Readability.UnnecessaryAliasExpansion, false}, - {Credo.Check.Readability.VariableNames, []}, + # + ## Readability Checks + # + {Credo.Check.Readability.FunctionNames, []}, + {Credo.Check.Readability.LargeNumbers, []}, + {Credo.Check.Readability.ModuleAttributeNames, []}, + {Credo.Check.Readability.ModuleDoc, []}, + {Credo.Check.Readability.ModuleNames, []}, + {Credo.Check.Readability.ParenthesesInCondition, []}, + {Credo.Check.Readability.ParenthesesOnZeroArityDefs, []}, + {Credo.Check.Readability.PreferImplicitTry, []}, + {Credo.Check.Readability.RedundantBlankLines, [max_blank_lines: 1]}, + {Credo.Check.Readability.Semicolons, []}, + {Credo.Check.Readability.StringSigils, []}, + {Credo.Check.Readability.TrailingBlankLine, []}, + {Credo.Check.Readability.TrailingWhiteSpace, []}, + {Credo.Check.Readability.VariableNames, []}, - # - # Controversial and experimental checks (opt-in, just replace `false` with `[]`) - # + # + # Controversial and experimental checks (opt-in, just replace `false` with `[]`) + # - # - ## Refactoring Opportunities - # - {Credo.Check.Refactor.ABCSize, false}, - {Credo.Check.Refactor.AppendSingleItem, false}, - {Credo.Check.Refactor.CaseTrivialMatches, false}, - {Credo.Check.Refactor.CondStatements, false}, - {Credo.Check.Refactor.CyclomaticComplexity, [max_complexity: 18]}, - {Credo.Check.Refactor.DoubleBooleanNegation, false}, - {Credo.Check.Refactor.FunctionArity, []}, - {Credo.Check.Refactor.LongQuoteBlocks, false}, - {Credo.Check.Refactor.MapInto, false}, - {Credo.Check.Refactor.MatchInCondition, false}, - {Credo.Check.Refactor.ModuleDependencies, false}, - {Credo.Check.Refactor.NegatedConditionsInUnless, []}, - {Credo.Check.Refactor.NegatedConditionsWithElse, []}, - {Credo.Check.Refactor.Nesting, false}, - {Credo.Check.Refactor.PipeChainStart, false}, - {Credo.Check.Refactor.UnlessWithElse, []}, - {Credo.Check.Refactor.VariableRebinding, false}, - {Credo.Check.Refactor.WithClauses, []}, + # + ## Refactoring Opportunities + # + {Credo.Check.Refactor.CyclomaticComplexity, [max_complexity: 18]}, + {Credo.Check.Refactor.FunctionArity, []}, + {Credo.Check.Refactor.NegatedConditionsInUnless, []}, + {Credo.Check.Refactor.NegatedConditionsWithElse, []}, + {Credo.Check.Refactor.UnlessWithElse, []}, + {Credo.Check.Refactor.WithClauses, []}, - # - ## Warnings - # - {Credo.Check.Warning.BoolOperationOnSameValues, []}, - {Credo.Check.Warning.ExpensiveEmptyEnumCheck, []}, - {Credo.Check.Warning.IExPry, []}, - {Credo.Check.Warning.IoInspect, []}, - {Credo.Check.Warning.LazyLogging, false}, - {Credo.Check.Warning.MapGetUnsafePass, false}, - {Credo.Check.Warning.OperationOnSameValues, []}, - {Credo.Check.Warning.OperationWithConstantResult, false}, - {Credo.Check.Warning.RaiseInsideRescue, []}, - {Credo.Check.Warning.UnsafeToAtom, false}, - {Credo.Check.Warning.UnusedEnumOperation, []}, - {Credo.Check.Warning.UnusedFileOperation, []}, - {Credo.Check.Warning.UnusedKeywordOperation, []}, - {Credo.Check.Warning.UnusedListOperation, []}, - {Credo.Check.Warning.UnusedPathOperation, []}, - {Credo.Check.Warning.UnusedRegexOperation, []}, - {Credo.Check.Warning.UnusedStringOperation, []}, - {Credo.Check.Warning.UnusedTupleOperation, []} - ] + # + ## Warnings + # + {Credo.Check.Warning.BoolOperationOnSameValues, []}, + {Credo.Check.Warning.ExpensiveEmptyEnumCheck, []}, + {Credo.Check.Warning.IExPry, []}, + {Credo.Check.Warning.IoInspect, []}, + {Credo.Check.Warning.OperationOnSameValues, []}, + {Credo.Check.Warning.RaiseInsideRescue, []}, + {Credo.Check.Warning.UnusedEnumOperation, []}, + {Credo.Check.Warning.UnusedFileOperation, []}, + {Credo.Check.Warning.UnusedKeywordOperation, []}, + {Credo.Check.Warning.UnusedListOperation, []}, + {Credo.Check.Warning.UnusedPathOperation, []}, + {Credo.Check.Warning.UnusedRegexOperation, []}, + {Credo.Check.Warning.UnusedStringOperation, []}, + {Credo.Check.Warning.UnusedTupleOperation, []} + ] + } } ] } diff --git a/.github/workflows/elixir.yml b/.github/workflows/elixir.yml index f054162..c5dd59c 100644 --- a/.github/workflows/elixir.yml +++ b/.github/workflows/elixir.yml @@ -15,11 +15,11 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - elixir: [1.11] - otp: [23.3] + elixir: [1.13] + otp: [25.3] steps: - name: checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: setup @@ -28,7 +28,7 @@ jobs: elixir-version: ${{ matrix.elixir }} otp-version: ${{ matrix.otp }} - name: Retrieve Cached Dependencies - uses: actions/cache@v2 + uses: actions/cache@v4 id: mix-cache with: path: | @@ -51,10 +51,10 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - elixir: [1.11] - otp: [23.3] + elixir: [1.13] + otp: [25.3] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup elixir @@ -63,7 +63,7 @@ jobs: elixir-version: ${{ matrix.elixir }} otp-version: ${{ matrix.otp }} - name: Retrieve Cached Dependencies - uses: actions/cache@v2 + uses: actions/cache@v4 id: mix-cache with: path: | @@ -80,10 +80,10 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - elixir: [1.11] - otp: [23.3] + elixir: [1.13] + otp: [25.3] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: fetch-depth: 0 - uses: erlef/setup-beam@v1 @@ -91,7 +91,7 @@ jobs: elixir-version: ${{ matrix.elixir }} otp-version: ${{ matrix.otp }} - name: Retrieve Cached Dependencies - uses: actions/cache@v2 + uses: actions/cache@v4 id: mix-cache with: path: | diff --git a/config/config.exs b/config/config.exs deleted file mode 100644 index af80b06..0000000 --- a/config/config.exs +++ /dev/null @@ -1,30 +0,0 @@ -# This file is responsible for configuring your application -# and its dependencies with the aid of the Mix.Config module. -use Mix.Config - -# This configuration is loaded before any dependency and is restricted -# to this project. If another project depends on this project, this -# file won't be loaded nor affect the parent project. For this reason, -# if you want to provide default values for your application for -# 3rd-party users, it should be done in your "mix.exs" file. - -# You can configure your application as: -# -# config :norm, key: :value -# -# and access this configuration in your application as: -# -# Application.get_env(:norm, :key) -# -# You can also configure a 3rd-party app: -# -# config :logger, level: :info -# - -# It is also possible to import configuration files, relative to this -# directory. For example, you can emulate configuration per environment -# by uncommenting the line below and defining dev.exs, test.exs and such. -# Configuration from the imported file will override the ones defined -# here (which is why it is important to import them last). -# -# import_config "#{Mix.env()}.exs" diff --git a/lib/norm/conformer.ex b/lib/norm/conformer.ex index f67d4b9..949de56 100644 --- a/lib/norm/conformer.ex +++ b/lib/norm/conformer.ex @@ -29,11 +29,7 @@ defmodule Norm.Conformer do |> Enum.join(" ") end - defp build_path(keys) do - keys - |> Enum.map(&format_val/1) - |> Enum.join("/") - end + defp build_path(keys), do: Enum.map_join(keys, "/", &format_val/1) defp format_val(nil), do: "nil" defp format_val(msg) when is_binary(msg), do: "\"#{msg}\"" diff --git a/lib/norm/core/all_of.ex b/lib/norm/core/all_of.ex index cd5f75c..b3636f5 100644 --- a/lib/norm/core/all_of.ex +++ b/lib/norm/core/all_of.ex @@ -25,4 +25,3 @@ defmodule Norm.Core.AllOf do end end end - diff --git a/lib/norm/core/schema.ex b/lib/norm/core/schema.ex index 7a89c2b..5fc8d0f 100644 --- a/lib/norm/core/schema.ex +++ b/lib/norm/core/schema.ex @@ -46,19 +46,17 @@ defmodule Norm.Core.Schema do # Conforming a struct def conform(%{specs: specs, struct: target}, input, path) when not is_nil(target) do # Ensure we're mapping the correct struct - cond do - Map.get(input, :__struct__) != target -> - short_name = - target - |> Atom.to_string() - |> String.replace("Elixir.", "") - - {:error, [Conformer.error(path, input, "#{short_name}")]} - - true -> - with {:ok, conformed} <- check_specs(specs, Map.from_struct(input), path) do - {:ok, struct(target, conformed)} - end + if Map.get(input, :__struct__) != target do + short_name = + target + |> Atom.to_string() + |> String.replace("Elixir.", "") + + {:error, [Conformer.error(path, input, "#{short_name}")]} + else + with {:ok, conformed} <- check_specs(specs, Map.from_struct(input), path) do + {:ok, struct(target, conformed)} + end end end diff --git a/lib/norm/core/selection.ex b/lib/norm/core/selection.ex index 39217df..68aa51c 100644 --- a/lib/norm/core/selection.ex +++ b/lib/norm/core/selection.ex @@ -41,7 +41,7 @@ defmodule Norm.Core.Selection do defp build_all_selectors(schema) do schema.specs |> Enum.map(fn - {name, %Schema{}=inner_schema} -> {name, build_all_selectors(inner_schema)} + {name, %Schema{} = inner_schema} -> {name, build_all_selectors(inner_schema)} {name, _} -> name end) end @@ -49,9 +49,9 @@ defmodule Norm.Core.Selection do defp validate_selectors!([]), do: true defp validate_selectors!([{_key, inner} | rest]), do: validate_selectors!(inner) and validate_selectors!(rest) defp validate_selectors!([_key | rest]), do: validate_selectors!(rest) - defp validate_selectors!(other), do: raise ArgumentError, "select expects a list of keys but received: #{inspect other}" + defp validate_selectors!(other), do: raise(ArgumentError, "select expects a list of keys but received: #{inspect other}") - defp assert_spec!(%Schema{}=schema, key) do + defp assert_spec!(%Schema{} = schema, key) do case Schema.key_present?(schema, key) do false -> raise SpecError, {:selection, key, schema} true -> Schema.spec(schema, key) diff --git a/lib/norm/core/spec.ex b/lib/norm/core/spec.ex index b988622..fae9b76 100644 --- a/lib/norm/core/spec.ex +++ b/lib/norm/core/spec.ex @@ -110,6 +110,7 @@ defmodule Norm.Core.Spec do end end + # credo:disable-for-next-line Credo.Check.Refactor.CyclomaticComplexity defp build_generator(gen) do case gen do :is_atom -> StreamData.atom(:alphanumeric) diff --git a/lib/norm/errors.ex b/lib/norm/errors.ex index a29ee52..77243c6 100644 --- a/lib/norm/errors.ex +++ b/lib/norm/errors.ex @@ -2,10 +2,7 @@ defmodule Norm.MismatchError do defexception [:message] def exception(errors) do - msg = - errors - |> Enum.map(&Norm.Conformer.error_to_msg/1) - |> Enum.join("\n") + msg = Enum.map_join(errors, "\n", &Norm.Conformer.error_to_msg/1) %__MODULE__{message: "Could not conform input:\n" <> msg} end @@ -56,9 +53,9 @@ defmodule Norm.SpecError do end defp format(atom, _) when is_atom(atom), do: ":#{atom}" defp format(str, _) when is_binary(str), do: ~s|"#{str}"| - defp format(%Spec{}=s, _), do: inspect(s) - defp format(%Spec.And{}=s, _), do: inspect(s) - defp format(%Spec.Or{}=s, _), do: inspect(s) + defp format(%Spec{} = s, _), do: inspect(s) + defp format(%Spec.And{} = s, _), do: inspect(s) + defp format(%Spec.Or{} = s, _), do: inspect(s) defp format(%Schema{specs: specs}, i) do f = fn {key, spec_or_schema}, i -> format(key, i) <> " => " <> format(spec_or_schema, i + 1) @@ -67,8 +64,7 @@ defmodule Norm.SpecError do specs = specs |> Enum.map(& f.(&1, i)) - |> Enum.map(&pad(&1, (i + 1) * 2)) - |> Enum.join("\n") + |> Enum.map_join("\n", &pad(&1, (i + 1) * 2)) "%{\n" <> specs <> "\n" <> pad("}", i * 2) end @@ -79,8 +75,7 @@ defmodule Norm.SpecError do formatted = specs |> Enum.map(&format(&1, i)) - |> Enum.map(&pad(&1, (i + 1) * 2)) - |> Enum.join("\n") + |> Enum.map_join("\n", &pad(&1, (i + 1) * 2)) if length(specs) > 0 do "alt([\n#{formatted}\n" <> pad("])", i * 2) @@ -92,8 +87,7 @@ defmodule Norm.SpecError do formatted = specs |> Enum.map(&format(&1, i)) - |> Enum.map(&pad(&1, (i + 1) * 2)) - |> Enum.join("\n") + |> Enum.map_join("\n", &pad(&1, (i + 1) * 2)) if length(specs) > 0 do "one_of([\n#{formatted}\n" <> pad("])", i * 2) diff --git a/mix.exs b/mix.exs index f9d98ec..220f276 100644 --- a/mix.exs +++ b/mix.exs @@ -2,19 +2,20 @@ defmodule Norm.MixProject do use Mix.Project @version "0.13.0" + @source_url "https://github.com/elixir-toniq/norm" def project do [ app: :norm, version: @version, - elixir: "~> 1.7", + elixir: "~> 1.11", elixirc_paths: elixirc_paths(Mix.env()), start_permanent: Mix.env() == :prod, deps: deps(), description: description(), package: package(), name: "Norm", - source_url: "https://github.com/keathley/norm", + source_url: @source_url, docs: docs() ] end @@ -31,7 +32,7 @@ defmodule Norm.MixProject do defp deps do [ {:credo, "~> 1.4", only: [:dev, :test], runtime: false}, - {:stream_data, "~> 0.5", optional: true}, + {:stream_data, "~> 0.6 or ~> 1.0", optional: true}, {:ex_doc, "~> 0.19", only: [:dev, :test]} ] end @@ -49,14 +50,14 @@ defmodule Norm.MixProject do [ name: "norm", licenses: ["MIT"], - links: %{"GitHub" => "https://github.com/keathley/norm"} + links: %{"GitHub" => @source_url} ] end def docs do [ source_ref: "v#{@version}", - source_url: "https://github.com/keathley/norm", + source_url: @source_url, main: "Norm" ] end diff --git a/mix.lock b/mix.lock index 3b56535..c47ec23 100644 --- a/mix.lock +++ b/mix.lock @@ -1,14 +1,14 @@ %{ - "bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"}, - "credo": {:hex, :credo, "1.5.6", "e04cc0fdc236fefbb578e0c04bd01a471081616e741d386909e527ac146016c6", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "4b52a3e558bd64e30de62a648518a5ea2b6e3e5d2b164ef5296244753fc7eb17"}, + "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, + "credo": {:hex, :credo, "1.7.6", "b8f14011a5443f2839b04def0b252300842ce7388f3af177157c86da18dfbeea", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "146f347fb9f8cbc5f7e39e3f22f70acbef51d441baa6d10169dd604bfbc55296"}, "earmark": {:hex, :earmark, "1.4.4", "4821b8d05cda507189d51f2caeef370cf1e18ca5d7dfb7d31e9cafe6688106a4", [:mix], [], "hexpm", "1f93aba7340574847c0f609da787f0d79efcab51b044bb6e242cae5aca9d264d"}, - "earmark_parser": {:hex, :earmark_parser, "1.4.29", "149d50dcb3a93d9f3d6f3ecf18c918fb5a2d3c001b5d3305c926cddfbd33355b", [:mix], [], "hexpm", "4902af1b3eb139016aed210888748db8070b8125c2342ce3dcae4f38dcc63503"}, - "ex_doc": {:hex, :ex_doc, "0.29.1", "b1c652fa5f92ee9cf15c75271168027f92039b3877094290a75abcaac82a9f77", [:mix], [{:earmark_parser, "~> 1.4.19", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "b7745fa6374a36daf484e2a2012274950e084815b936b1319aeebcf7809574f6"}, - "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, - "jason": {:hex, :jason, "1.2.2", "ba43e3f2709fd1aa1dce90aaabfd039d000469c05c56f0b8e31978e03fa39052", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "18a228f5f0058ee183f29f9eae0805c6e59d61c3b006760668d8d18ff0d12179"}, - "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, - "makeup_elixir": {:hex, :makeup_elixir, "0.16.0", "f8c570a0d33f8039513fbccaf7108c5d750f47d8defd44088371191b76492b0b", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "28b2cbdc13960a46ae9a8858c4bebdec3c9a6d7b4b9e7f4ed1502f8159f338e7"}, - "makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"}, - "nimble_parsec": {:hex, :nimble_parsec, "1.2.3", "244836e6e3f1200c7f30cb56733fd808744eca61fd182f731eac4af635cc6d0b", [:mix], [], "hexpm", "c8d789e39b9131acf7b99291e93dae60ab48ef14a7ee9d58c6964f59efb570b0"}, - "stream_data": {:hex, :stream_data, "0.5.0", "b27641e58941685c75b353577dc602c9d2c12292dd84babf506c2033cd97893e", [:mix], [], "hexpm", "012bd2eec069ada4db3411f9115ccafa38540a3c78c4c0349f151fc761b9e271"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.39", "424642f8335b05bb9eb611aa1564c148a8ee35c9c8a8bba6e129d51a3e3c6769", [:mix], [], "hexpm", "06553a88d1f1846da9ef066b87b57c6f605552cfbe40d20bd8d59cc6bde41944"}, + "ex_doc": {:hex, :ex_doc, "0.34.0", "ab95e0775db3df71d30cf8d78728dd9261c355c81382bcd4cefdc74610bef13e", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "60734fb4c1353f270c3286df4a0d51e65a2c1d9fba66af3940847cc65a8066d7"}, + "file_system": {:hex, :file_system, "1.0.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"}, + "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"}, + "makeup": {:hex, :makeup, "1.1.2", "9ba8837913bdf757787e71c1581c21f9d2455f4dd04cfca785c70bbfff1a76a3", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cce1566b81fbcbd21eca8ffe808f33b221f9eee2cbc7a1706fc3da9ff18e6cac"}, + "makeup_elixir": {:hex, :makeup_elixir, "0.16.2", "627e84b8e8bf22e60a2579dad15067c755531fea049ae26ef1020cad58fe9578", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "41193978704763f6bbe6cc2758b84909e62984c7752b3784bd3c218bb341706b"}, + "makeup_erlang": {:hex, :makeup_erlang, "1.0.0", "6f0eff9c9c489f26b69b61440bf1b238d95badae49adac77973cbacae87e3c2e", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "ea7a9307de9d1548d2a72d299058d1fd2339e3d398560a0e46c27dab4891e4d2"}, + "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, + "stream_data": {:hex, :stream_data, "1.1.0", "ef3a7cac0f200c43caf3e6caf9be63115851b4f1cde3f21afaab220adc40e3d7", [:mix], [], "hexpm", "cccc411d5facf1bab86e7c671382d164f05f8992574c95349d3c8b317e14d953"}, } diff --git a/test/norm/contract_test.exs b/test/norm/contract_test.exs index 4004a07..8f65217 100644 --- a/test/norm/contract_test.exs +++ b/test/norm/contract_test.exs @@ -39,7 +39,10 @@ defmodule Norm.ContractTest do end test "bad contract" do - assert_raise ArgumentError, ~r/got: `@contract\(foo\(n\)\)`/, fn -> + expected = if version().minor >= 13, + do: ~r/got: `@contract foo\(n\)`/, else: ~r/got: `@contract\(foo\(n\)\)`/ + + assert_raise ArgumentError, expected, fn -> defmodule BadContract do use Norm @@ -94,7 +97,7 @@ defmodule Norm.ContractTest do defmodule Reflection do use Norm - def int(), do: spec(is_integer()) + def int, do: spec(is_integer()) @contract foo(a :: int(), int()) :: int() def foo(a, b), do: a + b @@ -105,4 +108,6 @@ defmodule Norm.ContractTest do assert inspect(contract) == "%Norm.Contract{args: [a: #Norm.Spec, arg2: #Norm.Spec], result: #Norm.Spec}" end + + defp version, do: Version.parse!(System.version()) end diff --git a/test/norm/core/delegate_test.exs b/test/norm/core/delegate_test.exs index ae2c5a8..bbf8553 100644 --- a/test/norm/core/delegate_test.exs +++ b/test/norm/core/delegate_test.exs @@ -2,7 +2,7 @@ defmodule Norm.Core.DelegateTest do use Norm.Case, async: true defmodule TreeTest do - def spec() do + def spec do schema(%{ "value" => spec(is_integer()), "left" => delegate(&TreeTest.spec/0), diff --git a/test/norm/core/schema_test.exs b/test/norm/core/schema_test.exs index e70b8c6..17c88eb 100644 --- a/test/norm/core/schema_test.exs +++ b/test/norm/core/schema_test.exs @@ -153,11 +153,11 @@ defmodule Norm.Core.SchemaTest do assert input == conform!(input, User.s()) assert {:error, errors} = conform(%User{name: :foo, age: "31", email: 42}, User.s()) - assert errors == [ + assert MapSet.equal?(MapSet.new(errors), MapSet.new([ %{spec: "is_integer()", input: "31", path: [:age]}, %{spec: "is_binary()", input: 42, path: [:email]}, %{spec: "is_binary()", input: :foo, path: [:name]} - ] + ])) end test "only checks the keys that have specs" do diff --git a/test/norm/core/spec_test.exs b/test/norm/core/spec_test.exs index c70b553..4d19e5a 100644 --- a/test/norm/core/spec_test.exs +++ b/test/norm/core/spec_test.exs @@ -15,7 +15,9 @@ defmodule Norm.Core.SpecTest do assert {:error, errors} = conform(nil, hex) assert errors == [%{spec: "is_binary()", input: nil, path: []}] assert {:error, errors} = conform("bad", hex) - assert errors == [%{spec: "&(String.starts_with?(&1, \"#\"))", input: "bad", path: []}] + + spec = if version().minor >= 13, do: "&String.starts_with?(&1, \"#\")", else: "&(String.starts_with?(&1, \"#\"))" + assert errors == [%{spec: spec, input: "bad", path: []}] end test "'and' and 'or' can be chained" do @@ -144,4 +146,6 @@ defmodule Norm.Core.SpecTest do "#Norm.Spec" end end + + defp version, do: Version.parse!(System.version()) end diff --git a/test/norm_test.exs b/test/norm_test.exs index 809ff2d..09ec4b6 100644 --- a/test/norm_test.exs +++ b/test/norm_test.exs @@ -225,7 +225,7 @@ defmodule NormTest do test "can enforce distinct elements" do spec = coll_of(spec(is_integer()), distinct: true) - assert {:error, errors} = conform([1,1,1], spec) + assert {:error, errors} = conform([1, 1, 1], spec) assert errors == [%{spec: "distinct?", input: [1, 1, 1], path: []}] end