Doctest: how to deal with inconsistent map key ordering?

Considering that the order of Map keys isn’t guaranteed, is there any reliable way to check KeyErrors in doctests?

Doctest failed: wrong message for KeyError

expected:

"key {:c, 999} not found in: %{a: 10, b: 10}"

actual:

"key {:c, 999} not found in: %{b: 10, a: 10}"

How do you mean check?

Ideally I’d just like to assert in the doctests that “some KeyError is raised, but I don’t care about the exact verbiage of the message”.

Seems like =~ would do the trick then :face_with_monocle:

I think you may need to use assert_raise in that case:
iex> assert_raise KeyError, fn -> map.c end

As far as I can tell a “pure” doctest will always assert on the full exception text (with the caveat that multi-line exceptions are not supported: Handling multi-newline exception messages in doctests? (Elixir v1.12.0))

2 Likes

You can do something like this:

## Examples

    iex> catch_error Map.fetch!(%{a: 10, b: 10}, {:c, 999})
    {:badkey, {:c, 999}}

On Elixir 1.19+ we can use ... to match anything until the end of the message, including multiline output. Support ellipsis in doctest exceptions by sabiwara · Pull Request #14233 · elixir-lang/elixir · GitHub

8 Likes

Thanks for the answers.

I’ll mention I also found one other workaround, which is, at least for the doctests, to pare your examples down to have only one key in the error-inspected map:

@doc """
…

    iex> difference!(%{a: 10}, %{a: 11})
    ** (KeyError) key {:a, 11} not found in: %{a: 10}

    iex> difference!(%{a: 10}, %{a: 3, b: 4})
    ** (KeyError) key {:b, 4} not found in: %{a: 10}
"""
1 Like

Oooh! That’s really exciting :tada:

1 Like