From 7a039dfd80fedf57ed43860417f9e57298bafe36 Mon Sep 17 00:00:00 2001 From: Andy Kirkpatrick Date: Mon, 9 Sep 2024 05:58:42 +0000 Subject: [PATCH] Support struct default values The required fields must appear first in the defstruct, followed by 2-tuples with the default value protected by `Macro.escape/1` --- lib/mimic/module.ex | 20 ++++++++++++++++++-- test/mimic_test.exs | 15 ++++++++++++++- test/support/test_modules.ex | 2 +- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/lib/mimic/module.ex b/lib/mimic/module.ex index 426b898..29d4199 100644 --- a/lib/mimic/module.ex +++ b/lib/mimic/module.ex @@ -123,11 +123,27 @@ defmodule Mimic.Module do defp generate_mimic_struct(module) do if function_exported?(module, :__info__, 1) && module.__info__(:struct) != nil do - required_fields = for %{field: field, required: true} <- module.__info__(:struct), do: field + struct_info = + module.__info__(:struct) + |> Enum.split_with(& &1.required) + |> Tuple.to_list() + |> List.flatten() + + required_fields = for %{field: field, required: true} <- struct_info, do: field + struct_template = Map.from_struct(module.__struct__()) + + struct_params = + for %{field: field, required: required} <- struct_info do + if required do + field + else + {field, Macro.escape(struct_template[field])} + end + end quote do @enforce_keys unquote(required_fields) - defstruct unquote(for %{field: field} <- module.__info__(:struct), do: field) + defstruct unquote(struct_params) end end end diff --git a/test/mimic_test.exs b/test/mimic_test.exs index b2788d2..769dffc 100644 --- a/test/mimic_test.exs +++ b/test/mimic_test.exs @@ -994,10 +994,23 @@ defmodule Mimic.Test do assert Structs.__info__(:struct) == [ %{field: :foo, required: true}, %{field: :bar, required: true}, - %{field: :default, required: false} + %{field: :default, required: false}, + %{field: :map_default, required: false} ] end + test "copies struct fields with default values" do + Structs + |> stub(:foo, fn -> :stubbed end) + + assert Structs.__struct__() == %Structs{ + foo: nil, + bar: nil, + default: "123", + map_default: %{} + } + end + test "copies struct fields" do StructNoEnforceKeys |> stub(:bar, fn -> :stubbed end) diff --git a/test/support/test_modules.ex b/test/support/test_modules.ex index 5cb1686..ab167ef 100644 --- a/test/support/test_modules.ex +++ b/test/support/test_modules.ex @@ -47,7 +47,7 @@ end defmodule Structs do @moduledoc false @enforce_keys [:foo, :bar] - defstruct [:foo, :bar, default: "123"] + defstruct [:foo, :bar, default: "123", map_default: %{}] def foo, do: nil end