edgurgel / mimic

A mocking library for Elixir
https://hexdocs.pm/mimic
Apache License 2.0
429 stars 34 forks source link

`Protocol.UndefinedError` when printing out a struct that is from a stubbed module #55

Closed sevenseacat closed 4 months ago

sevenseacat commented 1 year ago

This was a super-bizarro one that I just came across! I've tried to minimize the example as much as I can.

Given a module that defines a struct, eg.

defmodule Log do
  defstruct [:name]
  def hello, do: nil
end

I can use that struct quite happily in tests -

# in test
dbg(%Log{})

# prints out
%Log{} #=> %Log{name: nil}

but if I want to stub out a function on that module, it throws up a really confusing error

# in test 
stub(Log, :hello, fn -> "hello" end)
dbg(%Log{})

# prints out 
%Log{} #=> #Inspect.Error<
  got Protocol.UndefinedError with message:

      """
      protocol Enumerable not implemented for nil of type Atom. This protocol is implemented for
      the following type(s): DBConnection.PrepareStream, DBConnection.Stream, Date.Range, 
      Ecto.Adapters.SQL.Stream, File.Stream, Floki.HTMLTree, Function, GenEvent.Stream, HashDict, 
      HashSet, IO.Stream, IP.Prefix, Jason.OrderedObject, List, Map, MapSet, MerkleMap, 
      Phoenix.LiveView.LiveStream, Postgrex.Stream, Range, Stream, StreamData
      """

  while inspecting:

      %{__struct__: Log, name: nil}

  Stacktrace:

    (elixir 1.14.3) lib/enum.ex:1: Enumerable.impl_for!/1
    (elixir 1.14.3) lib/enum.ex:166: Enumerable.reduce/3
    (elixir 1.14.3) lib/enum.ex:4307: Enum.reduce/3
    (elixir 1.14.3) lib/inspect.ex:595: Inspect.Any.inspect/2
    (elixir 1.14.3) lib/inspect/algebra.ex:341: Inspect.Algebra.to_doc/2
    (elixir 1.14.3) lib/kernel.ex:2254: Kernel.inspect/2
    (elixir 1.14.3) lib/macro.ex:2576: Macro.dbg_format_ast_to_debug/2
    (elixir 1.14.3) lib/macro.ex:2546: Macro.__dbg__/3
    test/my_app/my_test.exs:44: MyApp.MyTest."test stuff"/1
    (ex_unit 1.14.3) lib/ex_unit/runner.ex:512: ExUnit.Runner.exec_test/1
    (stdlib 4.3.1) timer.erl:235: :timer.tc/1
    (ex_unit 1.14.3) lib/ex_unit/runner.ex:463: anonymous fn/4 in ExUnit.Runner.spawn_test_monitor/4
>

I can't work out if this is an error in displaying the struct, or actually using the struct for things. As I want to use the struct in assertions for tests, trying to print out test failures is itself raising protocol errors like this, and it's rather confusing!

bvobart commented 7 months ago

Did you ever end up fixing this issue? I'm running into the exact same problem in my Elixir project, though I am using IO.inspect instead of dbg. As you said, it makes printing out test failures fail with these protocol errors, making it incredibly difficult to debug why my tests are failing.

sevenseacat commented 6 months ago

I didn't, unfortunately - I ended up working around it to not do it :(

edgurgel commented 4 months ago

Hey team Mimic 1.8.0 1.8.1 should fix this issue. Please reopen if that's not the case!