Skip to content

Commit

Permalink
Fix tests for elixir 1.14
Browse files Browse the repository at this point in the history
  • Loading branch information
IvanRublev committed Aug 6, 2022
1 parent 0af3c3e commit 6d005f6
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 62 deletions.
19 changes: 12 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Domo

```elixir
Mix.install([:domo], force: true)
```

## About

|[![Elixir CI](https://github.com/IvanRublev/Domo/actions/workflows/ci.yml/badge.svg)](https://github.com/IvanRublev/Domo/actions/workflows/ci.yml)|[![Method TDD](https://img.shields.io/badge/method-TDD-blue)](#domo)|[![hex.pm version](http://img.shields.io/hexpm/v/domo.svg?style=flat)](https://hex.pm/packages/domo)|
|-|-|-|

Expand Down Expand Up @@ -39,18 +45,12 @@ define the invariants relating structs to each other.

## Tour

<p align="center">
<p align="center" class="hidden">
<a href="https://livebook.dev/run?url=https%3A%2F%2Fgithub.com%2FIvanRublev%2FDomo%2Fblob%2Fmaster%2FREADME.md">
<img src="https://livebook.dev/badge/v1/blue.svg" alt="Run in Livebook" />
</a>
</p>

```elixir
# Evaluate this section first!

Mix.install([:domo], force: true)
```

Let's say that we have a `LineItem` and `PurchaseOrder` structs with relating
invariant that is the sum of line item amounts should be less then order's
approved limit. That can be expressed like the following:
Expand Down Expand Up @@ -744,6 +744,11 @@ F.e. with `validate_required/2` call in the `Ecto` changeset.

## Changelog

### v1.5.7 (2022-08-06)

* Fix to resolve mfa() type.
* Fix tests to acknowledge random order of keys in map.

### v1.5.6 (2022-06-12)

* Fix to remove unnecessary code path to make `mix dialyzer` pass on generated code.
Expand Down
4 changes: 2 additions & 2 deletions config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
# is restricted to this project.

# General application configuration
use Mix.Config
import Config

config :domo, :test_structs_path, "test/struct_modules"

if Mix.env() == :test do
if config_env() == :test do
config :domo, :mix_project, MixProjectStubCorrect
end
2 changes: 1 addition & 1 deletion lib/domo/type_ensurer_factory/resolver/fields.ex
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ defmodule Domo.TypeEnsurerFactory.Resolver.Fields do
end

defp resolve_type({:mfa, _meta, _args}, module, precond, _env_preconds, {types, errs, deps}) do
joint_type = {quote(context: module, do: {{module(), nil}, {atom(), nil}, {0..255, nil}}), precond}
joint_type = {quote(context: module, do: {{atom(), nil}, {atom(), nil}, {0..255, nil}}), precond}
{[joint_type | types], errs, deps}
end

Expand Down
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule Domo.MixProject do
use Mix.Project

@version "1.5.6"
@version "1.5.7"
@repo_url "https://github.com/IvanRublev/Domo"

def project do
Expand Down
95 changes: 63 additions & 32 deletions test/domo_func_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -78,15 +78,21 @@ defmodule DomoFuncTest do
end

test "raises an error for arguments mismatching struct's field types with underlying errors" do
message_regex =
"""
the following values should have types defined for fields of the RecipientNestedOrTypes struct:
* Invalid value %Recipient{__fields_pattern__} for field :title of %RecipientNestedOrTypes{}. \
Expected the value matching the :mr | %Recipient{} | :dr type.
Underlying errors:
- Value of field :title is invalid due to Invalid value "mr" for field :title of %Recipient{}. \
Expected the value matching the :mr | :ms | :dr type.\
"""
|> Regex.escape()
|> String.replace("__fields_pattern__", ".*age: 27.*")
|> Regex.compile!()

assert_raise ArgumentError,
"""
the following values should have types defined for fields of the RecipientNestedOrTypes struct:
* Invalid value %Recipient{age: 27, name: "Bob", title: "mr"} for field :title of %RecipientNestedOrTypes{}. \
Expected the value matching the :mr | %Recipient{} | :dr type.
Underlying errors:
- Value of field :title is invalid due to Invalid value "mr" for field :title of %Recipient{}. \
Expected the value matching the :mr | :ms | :dr type.\
""",
message_regex,
fn ->
_ = RecipientNestedOrTypes.new!(title: %Recipient{title: "mr", name: "Bob", age: 27})
end
Expand All @@ -105,12 +111,18 @@ defmodule DomoFuncTest do
end

test "raises an error for arguments mismatching struct type precondition" do
message_regex =
"""
Invalid value %RecipientWithPrecond{__fields_pattern__}. \
Expected the value matching the RecipientWithPrecond.t() type. And a true value from the precondition \
function "&(String.length(&1.name) < 10)" defined for RecipientWithPrecond.t() type.\
"""
|> Regex.escape()
|> String.replace("__fields_pattern__", ".*age: 37.*")
|> Regex.compile!()

assert_raise ArgumentError,
"""
Invalid value %RecipientWithPrecond{age: 37, name: "Bob Thornton", title: :mr}. \
Expected the value matching the RecipientWithPrecond.t() type. And a true value from the precondition \
function "&(String.length(&1.name) < 10)" defined for RecipientWithPrecond.t() type.\
""",
message_regex,
fn ->
_ = RecipientWithPrecond.new!(title: :mr, name: "Bob Thornton", age: 37)
end
Expand Down Expand Up @@ -227,7 +239,7 @@ defmodule DomoFuncTest do
_ = Recipient.new!(name: "Bob", age: 27)
end

assert_raise KeyError, ~r/key :extra_key not found in: %Recipient/, fn ->
assert_raise KeyError, ~r/key :extra_key not found/, fn ->
_ = Recipient.new!(title: :mr, name: "Bob", age: 27, extra_key: true)
end
end
Expand Down Expand Up @@ -270,13 +282,19 @@ defmodule DomoFuncTest do
test "returns :error tuple for struct type precondition" do
assert {:error, error} = RecipientWithPrecond.new(title: :mr, name: "Bob Thornton", age: 37)

assert error == [
t: """
Invalid value %RecipientWithPrecond{age: 37, name: "Bob Thornton", title: :mr}. \
Expected the value matching the RecipientWithPrecond.t() type. And a true value from the precondition \
function "&(String.length(&1.name) < 10)" defined for RecipientWithPrecond.t() type.\
"""
]
assert [t: message] = error

message_regex =
"""
Invalid value %RecipientWithPrecond{__fields_pattern__}. \
Expected the value matching the RecipientWithPrecond.t() type. And a true value from the precondition \
function "&(String.length(&1.name) < 10)" defined for RecipientWithPrecond.t() type.\
"""
|> Regex.escape()
|> String.replace("__fields_pattern__", ".*age: 37.*")
|> Regex.compile!()

assert message =~ message_regex
end

test "returns :error tuple for a missing key" do
Expand Down Expand Up @@ -338,12 +356,18 @@ defmodule DomoFuncTest do
test "raises an error for arguments mismatching struct type precondition", %{joe: joe} do
malformed_joe = %{joe | name: "Bob Thornton"}

message_regex =
"""
Invalid value %RecipientWithPrecond{__fields_pattern__}. \
Expected the value matching the RecipientWithPrecond.t() type. And a true value from the precondition \
function "&(String.length(&1.name) < 10)" defined for RecipientWithPrecond.t() type.\
"""
|> Regex.escape()
|> String.replace("__fields_pattern__", ".*age: 37.*")
|> Regex.compile!()

assert_raise ArgumentError,
"""
Invalid value %RecipientWithPrecond{age: 37, name: "Bob Thornton", title: :mr}. \
Expected the value matching the RecipientWithPrecond.t() type. And a true value from the precondition \
function "&(String.length(&1.name) < 10)" defined for RecipientWithPrecond.t() type.\
""",
message_regex,
fn ->
_ = RecipientWithPrecond.ensure_type!(malformed_joe)
end
Expand Down Expand Up @@ -412,12 +436,19 @@ defmodule DomoFuncTest do
test "returns :error tuple for struct type precondition", %{joe: joe} do
malformed_joe = %{joe | name: "Bob Thornton"}

assert {:error,
t: """
Invalid value %RecipientWithPrecond{age: 37, name: "Bob Thornton", title: :mr}. \
Expected the value matching the RecipientWithPrecond.t() type. And a true value from the precondition \
function "&(String.length(&1.name) < 10)" defined for RecipientWithPrecond.t() type.\
"""} = RecipientWithPrecond.ensure_type(malformed_joe)
assert {:error, t: message} = RecipientWithPrecond.ensure_type(malformed_joe)

message_regex =
"""
Invalid value %RecipientWithPrecond{__fields_pattern__}. \
Expected the value matching the RecipientWithPrecond.t() type. And a true value from the precondition \
function "&(String.length(&1.name) < 10)" defined for RecipientWithPrecond.t() type.\
"""
|> Regex.escape()
|> String.replace("__fields_pattern__", ".*age: 37.*")
|> Regex.compile!()

assert message =~ message_regex
end

test "raises an error if the passed struct's name differs from the module's name" do
Expand Down
43 changes: 25 additions & 18 deletions test/domo_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ defmodule DomoTest do
_ = Account.new!(id: "ak47896", name: "John Smith", money: 2578)
end

assert_raise ArgumentError, ~r/Invalid value %Account{id: \"adk-47896\", money: 2, name: \"John Smith\"}.*\
assert_raise ArgumentError, ~r/Invalid value %Account{.*id: \"adk-47896\".*}.*\
a true value from the precondition.*defined for Account.t\(\) type./s, fn ->
_ = Account.new!(id: "adk-47896", name: "John Smith", money: 2)
end
Expand All @@ -348,7 +348,7 @@ a true value from the precondition.*defined for Account.t\(\) type./s, fn ->
_ = %{account | money: -1} |> Account.ensure_type!()
end

assert_raise ArgumentError, ~r/Invalid value %Account{id: \"adk-47896\", money: 3, name: \"John Smith\"}.*\
assert_raise ArgumentError, ~r/Invalid value %Account{.*id: \"adk-47896\".*}.*\
a true value from the precondition.*defined for Account.t\(\) type./s, fn ->
_ = %{account | money: 3} |> Account.ensure_type!()
end
Expand Down Expand Up @@ -936,7 +936,7 @@ a true value from the precondition.*defined for Account.t\(\) type./s, fn ->

test "skips enforced keys during the struct defaults values ensurance" do
DomoMixTask.start_plan_collection()
compile_struct_with_defaults(":id, field: :hello", enforce_keys: ":id", t: "id: integer(), field: atom()")
compile_struct_with_defaults("id: 0, field: :hello", enforce_keys: ":id", t: "id: integer(), field: atom()")
assert {:ok, []} = DomoMixTask.process_plan({:ok, []}, [])
end

Expand Down Expand Up @@ -1109,22 +1109,29 @@ a true value from the precondition.*defined for Account.t\(\) type./s, fn ->
compile_library_struct()
DomoMixTask.process_plan({:ok, []}, [])

message_regex =
"""
the following values should have types defined for fields of the Library struct:
* Invalid value [%Library.Shelve{__a5_pattern__}, \
%Library.Shelve{__b1_pattern__}] for field :shelves of %Library{}. \
Expected the value matching the [%Library.Shelve{}] type.
Underlying errors:
- The element at index 1 has value %Library.Shelve{__b1_pattern__} that is invalid.
- Value of field :books is invalid due to the following:
- The element at index 1 has value %Library.Book{__howl_title_pattern__} that is invalid.
- Value of field :author is invalid due to Invalid value %Library.Book.Author{__name_allen_pattern__} for field :author of %Library.Book{}. \
Value of field :second_name is invalid due to Invalid value :ginsberg for field :second_name of %Library.Book.Author{}. Expected the value matching the <<_::_*8>> type.
* Invalid value 1 for field :name of %Library{}. Expected the value matching the <<_::_*8>> type.\
"""
|> Regex.escape()
|> String.replace("__a5_pattern__", ".*address: \"A5\".*")
|> String.replace("__b1_pattern__", ".*address: \"B1\".*")
|> String.replace("__howl_title_pattern__", ".*title: \"Howl and Other Poems\".*")
|> String.replace("__name_allen_pattern__", ".*first_name: \"Allen\".*")
|> Regex.compile!()

assert_raise ArgumentError,
"""
the following values should have types defined for fields of the Library struct:
* Invalid value [%Library.Shelve{address: "A5", books: [%Library.Book{author: %Library.Book.Author{first_name: "Jack", second_name: "Kerouac"}, title: "On the Road"}]}, \
%Library.Shelve{address: "B1", books: [%Library.Book{author: %Library.Book.Author{first_name: "William S.", second_name: "Burroughs"}, title: "Naked Lunch"}, \
%Library.Book{author: %Library.Book.Author{first_name: "Allen", second_name: :ginsberg}, title: "Howl and Other Poems"}]}] for field :shelves of %Library{}. \
Expected the value matching the [%Library.Shelve{}] type.
Underlying errors:
- The element at index 1 has value %Library.Shelve{address: "B1", books: [%Library.Book{author: %Library.Book.Author{first_name: "William S.", second_name: "Burroughs"}, title: "Naked Lunch"}, \
%Library.Book{author: %Library.Book.Author{first_name: "Allen", second_name: :ginsberg}, title: "Howl and Other Poems"}]} that is invalid.
- Value of field :books is invalid due to the following:
- The element at index 1 has value %Library.Book{author: %Library.Book.Author{first_name: "Allen", second_name: :ginsberg}, title: "Howl and Other Poems"} that is invalid.
- Value of field :author is invalid due to Invalid value %Library.Book.Author{first_name: "Allen", second_name: :ginsberg} for field :author of %Library.Book{}. \
Value of field :second_name is invalid due to Invalid value :ginsberg for field :second_name of %Library.Book.Author{}. Expected the value matching the <<_::_*8>> type.
* Invalid value 1 for field :name of %Library{}. Expected the value matching the <<_::_*8>> type.\
""",
message_regex,
fn ->
alias Library.Shelve
alias Library.Book
Expand Down
2 changes: 1 addition & 1 deletion test/support/resolver_test_helper.ex
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ defmodule ResolverTestHelper do
quote(context: TwoFieldStruct, do: nonempty_list(any())),
quote(context: TwoFieldStruct, do: maybe_improper_list(any(), any())),
quote(context: TwoFieldStruct, do: nonempty_maybe_improper_list(any(), any())),
quote(context: TwoFieldStruct, do: {module(), atom(), 0..255}),
quote(context: TwoFieldStruct, do: {atom(), atom(), 0..255}),
quote(context: TwoFieldStruct, do: atom()),
quote(context: TwoFieldStruct, do: {}),
quote(context: TwoFieldStruct, do: atom())
Expand Down

0 comments on commit 6d005f6

Please sign in to comment.