Skip to content

Commit

Permalink
chore: no longer generate empty map patterns
Browse files Browse the repository at this point in the history
Closes #57, Closes #56, Closes #55
  • Loading branch information
zachallaun committed Feb 6, 2024
1 parent 07505d1 commit 1057e23
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 91 deletions.
32 changes: 16 additions & 16 deletions lib/mneme/assertion/pattern_builder.ex
Original file line number Diff line number Diff line change
Expand Up @@ -172,22 +172,8 @@ defmodule Mneme.Assertion.PatternBuilder do
sub_map
end

{patterns, vars} =
Enum.flat_map_reduce(sub_maps ++ [map], vars, fn map, vars ->
enumerate_map_patterns(map, context, vars)
end)

if contains_empty_map_pattern?(patterns) do
{patterns, vars}
else
{[Pattern.new({:%{}, with_meta(context), []}) | patterns], vars}
end
end

defp contains_empty_map_pattern?(patterns) do
Enum.any?(patterns, fn
%Pattern{expr: {:%{}, _, []}} -> true
_ -> false
Enum.flat_map_reduce(sub_maps ++ [map], vars, fn map, vars ->
enumerate_map_patterns(map, context, vars)
end)
end

Expand Down Expand Up @@ -239,9 +225,23 @@ defmodule Mneme.Assertion.PatternBuilder do
|> Map.filter(fn {k, v} -> v != Map.get(defaults, k) end)
|> to_patterns(context, vars)

patterns =
if contains_empty_map_pattern?(patterns) do
patterns
else
[Pattern.new({:%{}, with_meta(context), []}) | patterns]
end

{Enum.map(patterns, &map_to_struct_pattern(&1, struct, context, extra_notes)), vars}
end

defp contains_empty_map_pattern?(patterns) do
Enum.any?(patterns, fn
%Pattern{expr: {:%{}, _, []}} -> true
_ -> false
end)
end

defp enum_to_patterns(values, context, vars) do
{nested_patterns, vars} = Enum.map_reduce(values, vars, &to_patterns(&1, context, &2))
{combine_nested(nested_patterns), vars}
Expand Down
103 changes: 41 additions & 62 deletions test/mneme/assertion/pattern_builder_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -29,77 +29,64 @@ defmodule Mneme.Assertion.PatternBuilderTest do
end

test "atoms" do
auto_assert([":foo"] <- to_pattern_strings(:foo))
auto_assert(["true"] <- to_pattern_strings(true))
auto_assert [":foo"] <- to_pattern_strings(:foo)
auto_assert ["true"] <- to_pattern_strings(true)
end

test "literals" do
auto_assert(["123"] <- to_pattern_strings(123))
auto_assert(["123.5"] <- to_pattern_strings(123.5))
auto_assert(["\"string\""] <- to_pattern_strings("string"))
auto_assert([":atom"] <- to_pattern_strings(:atom))
auto_assert ["123"] <- to_pattern_strings(123)
auto_assert ["123.5"] <- to_pattern_strings(123.5)
auto_assert ["\"string\""] <- to_pattern_strings("string")
auto_assert [":atom"] <- to_pattern_strings(:atom)
end

test "tuples" do
auto_assert(["{1, \"string\", :atom}"] <- to_pattern_strings({1, "string", :atom}))
auto_assert(["{{:nested}, {\"tuples\"}}"] <- to_pattern_strings({{:nested}, {"tuples"}}))
auto_assert ["{1, \"string\", :atom}"] <- to_pattern_strings({1, "string", :atom})
auto_assert ["{{:nested}, {\"tuples\"}}"] <- to_pattern_strings({{:nested}, {"tuples"}})
end

test "lists" do
auto_assert(["[]"] <- to_pattern_strings([]))
auto_assert(["[1, 2, 3]"] <- to_pattern_strings([1, 2, 3]))
auto_assert(["[1, [:nested], 3]"] <- to_pattern_strings([1, [:nested], 3]))
auto_assert ["[]"] <- to_pattern_strings([])
auto_assert ["[1, 2, 3]"] <- to_pattern_strings([1, 2, 3])
auto_assert ["[1, [:nested], 3]"] <- to_pattern_strings([1, [:nested], 3])
end

test "pins and guards" do
ref = make_ref()
auto_assert(["ref when is_reference(ref)"] <- to_pattern_strings(ref))
auto_assert ["ref when is_reference(ref)"] <- to_pattern_strings(ref)

auto_assert(
["^my_ref", "ref when is_reference(ref)"] <-
to_pattern_strings(ref, binding: [my_ref: ref])
)
auto_assert ["^my_ref", "ref when is_reference(ref)"] <-
to_pattern_strings(ref, binding: [my_ref: ref])

self = self()
auto_assert(["pid when is_pid(pid)"] <- to_pattern_strings(self))
auto_assert ["pid when is_pid(pid)"] <- to_pattern_strings(self)

auto_assert(
["^me", "pid when is_pid(pid)"] <- to_pattern_strings(self, binding: [me: self])
)
auto_assert ["^me", "pid when is_pid(pid)"] <- to_pattern_strings(self, binding: [me: self])

{:ok, port} = :gen_tcp.listen(0, [])

try do
auto_assert(["port when is_port(port)"] <- to_pattern_strings(port))
auto_assert ["port when is_port(port)"] <- to_pattern_strings(port)

auto_assert(
["^my_port", "port when is_port(port)"] <-
to_pattern_strings(port, binding: [my_port: port])
)
auto_assert ["^my_port", "port when is_port(port)"] <-
to_pattern_strings(port, binding: [my_port: port])
after
Port.close(port)
end
end

test "maps" do
auto_assert(["%{}"] <- to_pattern_strings(%{}))
auto_assert ["%{}"] <- to_pattern_strings(%{})

auto_assert(["%{}", "%{bar: 2, foo: 1}"] <- to_pattern_strings(%{foo: 1, bar: 2}))
auto_assert ["%{bar: 2, foo: 1}"] <- to_pattern_strings(%{foo: 1, bar: 2})

auto_assert(
["%{}", "%{:foo => 1, \"bar\" => 2}"] <-
to_pattern_strings(%{:foo => 1, "bar" => 2})
)
auto_assert ["%{:foo => 1, \"bar\" => 2}"] <- to_pattern_strings(%{:foo => 1, "bar" => 2})

auto_assert(
["%{}", "%{bar: ref, foo: pid} when is_reference(ref) and is_pid(pid)"] <-
to_pattern_strings(%{foo: self(), bar: make_ref()})
)
auto_assert ["%{bar: ref, foo: pid} when is_reference(ref) and is_pid(pid)"] <-
to_pattern_strings(%{foo: self(), bar: make_ref()})

auto_assert(
["%{}", "%{bar: %{}, foo: [1, 2]}", "%{bar: %{baz: [3, 4]}, foo: [1, 2]}"] <-
to_pattern_strings(%{foo: [1, 2], bar: %{baz: [3, 4]}})
)
auto_assert ["%{bar: %{baz: [3, 4]}, foo: [1, 2]}"] <-
to_pattern_strings(%{foo: [1, 2], bar: %{baz: [3, 4]}})
end

test "dates and times" do
Expand All @@ -108,44 +95,36 @@ defmodule Mneme.Assertion.PatternBuilderTest do
iso8601_datetime = iso8601_date <> "T" <> iso8601_time

{:ok, datetime, 0} = DateTime.from_iso8601(iso8601_datetime)
auto_assert(["~U[2023-01-01 12:00:00Z]"] <- to_pattern_strings(datetime))
auto_assert ["~U[2023-01-01 12:00:00Z]"] <- to_pattern_strings(datetime)

auto_assert(
["^jan1", "~U[2023-01-01 12:00:00Z]"] <-
to_pattern_strings(datetime, binding: [jan1: datetime])
)
auto_assert ["^jan1", "~U[2023-01-01 12:00:00Z]"] <-
to_pattern_strings(datetime, binding: [jan1: datetime])

naive_datetime = NaiveDateTime.from_iso8601!(iso8601_datetime)
auto_assert(["~N[2023-01-01 12:00:00]"] <- to_pattern_strings(naive_datetime))
auto_assert ["~N[2023-01-01 12:00:00]"] <- to_pattern_strings(naive_datetime)

auto_assert(
["^jan1", "~N[2023-01-01 12:00:00]"] <-
to_pattern_strings(naive_datetime, binding: [jan1: naive_datetime])
)
auto_assert ["^jan1", "~N[2023-01-01 12:00:00]"] <-
to_pattern_strings(naive_datetime, binding: [jan1: naive_datetime])

date = Date.from_iso8601!(iso8601_date)
auto_assert(["~D[2023-01-01]"] <- to_pattern_strings(date))
auto_assert(["^jan1", "~D[2023-01-01]"] <- to_pattern_strings(date, binding: [jan1: date]))
auto_assert ["~D[2023-01-01]"] <- to_pattern_strings(date)
auto_assert ["^jan1", "~D[2023-01-01]"] <- to_pattern_strings(date, binding: [jan1: date])

time = Time.from_iso8601!(iso8601_time)
auto_assert(["~T[12:00:00]"] <- to_pattern_strings(time))
auto_assert(["^noon", "~T[12:00:00]"] <- to_pattern_strings(time, binding: [noon: time]))
auto_assert ["~T[12:00:00]"] <- to_pattern_strings(time)
auto_assert ["^noon", "~T[12:00:00]"] <- to_pattern_strings(time, binding: [noon: time])
end

test "URIs don't include deprecated :authority" do
auto_assert(
["%URI{}", "%URI{host: \"example.com\", port: 443, scheme: \"https\"}"] <-
to_pattern_strings(URI.parse("https://example.com"))
)
auto_assert ["%URI{}", "%URI{host: \"example.com\", port: 443, scheme: \"https\"}"] <-
to_pattern_strings(URI.parse("https://example.com"))
end

test "structs" do
auto_assert(
["%Version{}", "%Version{major: 1, minor: 1, patch: 1}"] <-
to_pattern_strings(Version.parse!("1.1.1"))
)
auto_assert ["%Version{}", "%Version{major: 1, minor: 1, patch: 1}"] <-
to_pattern_strings(Version.parse!("1.1.1"))

auto_assert(["%URI{}"] <- to_pattern_strings(%URI{}))
auto_assert ["%URI{}"] <- to_pattern_strings(%URI{})
end
end

Expand Down
12 changes: 2 additions & 10 deletions test_integration/basic_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -104,27 +104,21 @@ defmodule Mneme.Integration.BasicTest do
describe "maps" do
test "basic patterns" do
# y
auto_assert %{} <- Map.put(%{}, :foo, 1)
# k y
auto_assert %{foo: 1} <- Map.put(%{}, :foo, 1)

m = %{foo: 1}
# y
auto_assert ^m <- m
# k y
auto_assert %{} <- m
# k k y
auto_assert %{foo: 1} <- m

my_ref = make_ref()
m = %{ref: my_ref}
# y
auto_assert ^m <- m
# k y
auto_assert %{} <- m
# k k y
auto_assert %{ref: ^my_ref} <- m
# k k k y
# k k y
auto_assert %{ref: ref} when is_reference(ref) <- m
end

Expand All @@ -134,10 +128,8 @@ defmodule Mneme.Integration.BasicTest do
# y
auto_assert ^m <- m
# k y
auto_assert %{} <- m
# k k y
auto_assert %{%{foo: 1} => :bar} <- m
# k k k y
# k k y
auto_assert ^m <- m

# k y
Expand Down
4 changes: 2 additions & 2 deletions test_integration/options_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,13 @@ defmodule Mneme.Integration.OptionsTest do
@mneme target: :ex_unit, default_pattern: :first
test "should replace pattern when rewriting to :ex_unit with default_pattern: :first" do
# auto_assert
assert %{foo: 1} <- %{foo: 1}, %{} = %{foo: 1}
assert %URI{path: "foo"} <- %URI{path: "foo"}, %URI{} = %URI{path: "foo"}
end

@mneme target: :ex_unit
test "should default to using same pattern when rewriting to :ex_unit" do
# auto_assert
assert %{foo: 1} <- %{foo: 1}, %{foo: 1} = %{foo: 1}
assert %URI{path: "foo"} <- %URI{path: "foo"}, %URI{path: "foo"} = %URI{path: "foo"}
end

@mneme :force_update
Expand Down
2 changes: 1 addition & 1 deletion test_integration/vars_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ defmodule Mneme.Integration.VarsTest do
auto_assert ^pid <- self()
# k y
auto_assert pid1 when is_pid(pid1) <- self()
# k k y
# k y
auto_assert %{foo: [pid1]} when is_pid(pid1) <- %{foo: [self()]}
end

Expand Down

0 comments on commit 1057e23

Please sign in to comment.