Testing HashSets in doctest

147 views Asked by At

I am trying to test HashSet using doctest via iex. If I run the line below, it gives the same result, but the #HashSet<["rockerboo"]>} can not be represented in the syntax. I can't think of a way to represent it properly, and I can't find any examples of it. Thanks!

  @doc """
  Adds user to HashSet in state

  ## Examples
      iex> Elirc.Channel.add_user_to_state("rockerboo", %{users: HashSet.new})
      %{users: #HashSet<["rockerboo"]>}
  """
  def add_user_to_state(user, state) do
    %{state | users: HashSet.put(state.users, user) }
  end

When running mix test, I get the following error.

 Doctest did not compile, got: (TokenMissingError) lib/elirc/channel.ex:99: missing terminator: } (for "{" starting at line 99)
 code: %{users: #HashSet<["rockerboo"]>}

Line 99 is %{state...

3

There are 3 answers

0
Paweł Obrok On BEST ANSWER

You can construct your HashSet in a different way so that it's a valid Elixir expression. For example this worked for me:

## Examples
  iex> Elirc.Channel.add_user_to_state("rockerboo", %{users: HashSet.new})
  %{users: ["rockerboo"] |> Enum.into(HashSet.new)}

This is also the approach that is recommended by the ExUnit.DocTest documentation under "Opaque Types"

0
José Valim On

Paweł's answer is correct. Another alternative is to "massage" the data in the doctest. For example, this would work:

  iex> state = Elirc.Channel.add_user_to_state("rockerboo", %{users: HashSet.new})
  iex> state.users
  #HashSet<["rockerboo"]>

Or:

  iex> state = Elirc.Channel.add_user_to_state("rockerboo", %{users: HashSet.new})
  iex> Enum.to_list(state.users)
  ["rockerboo"]

I have expanded the doctest section linked by Paweł to include both his and mine examples: https://github.com/elixir-lang/elixir/blob/64e5f4876007d840edee3040c43e8f98095b8e3d/lib/ex_unit/lib/ex_unit/doc_test.ex#L77

4
bitwalker On

Well your problem is that you are trying to represent something that isn't possible, a HashDict entry with either no key or no value. HashDict.put(state.users, "rockerboo") would fail because put requires 3 arguments, a HashDict, a key, and a value. Assuming you had something like name: "rockerboo" though:

iex> %{users: Enum.into([name: "rockerboo"], HashDict.new)} %{users: #HashDict<[name: "rockerboo"]>}

The above works as expected.