Current section
Files
Jump to
Current section
Files
lib/struct_assert.ex
defmodule StructAssert do
@moduledoc """
A useful tool for testing sturct and map in Elixir.
"""
use Exporter, default: [assert_subset: 2]
@doc """
assert only a part of struct and map.
defmodule MyStruct do
defstruct a: 1, b: 1, z: 10
end
defmodule Example
use ExUnit.Case
use StructAssert
test "example" do
assert_subset(%MyStruct{}, [a: 1, b: 2])
# code: assert_subset(%MyStruct{}, [a: 1, b: 2])
# left: %{a: 1, b: 1, z: 10}
# right: %{a: 1, b: 2, z: 10}
assert_subset(%MyStruct{}, [a: 1, b: &is_atom(&1)])
# code: assert_subset(%MyStruct{}, [a: 1, b: &(is_atom(&1))])
# left: %{a: 1, z: 10, b: 1}
# right: %{a: 1, z: 10, b: &:erlang.is_atom/1}
end
end
"""
defmacro assert_subset(got, expect) do
expr = build_expr_for_error_message(got,expect)
got_map = got_value_to_map(got)
expect_map = expect_value_to_map(expect)
quote do
got_map = unquote(got_map)
expect_map = unquote(expect_map)
expect = DeepMerge.deep_merge(got_map, expect_map,
fn
(_, original, override) when is_function(original) and is_function(override) -> DeepMerge.continue_deep_merge
(_, original, override) when is_function(override) ->
case override.(original) do
true -> original
_ -> override
end
(_, _original, _override) -> DeepMerge.continue_deep_merge
end
)
assert got_map == expect,
expr: unquote(expr),
left: got_map,
right: expect
end
end
defp build_expr_for_error_message(got,expect) do
got_var_name = got |> Macro.expand(__ENV__) |> Macro.to_string
expect_var_name = expect |> Macro.expand(__ENV__) |> Macro.to_string
"assert_subset(#{got_var_name}, #{expect_var_name})"
end
defp got_value_to_map(got) do
quote do
got = unquote(got)
case got do
%_{} -> Map.from_struct(got)
%{} -> got
end
end
end
defp expect_value_to_map(expect) do
quote do
expect = unquote(expect)
case expect do
%{} -> expect
is_list -> Enum.into(expect, %{})
end
end
end
end