Doctest the output of inspect call

Sorry for the confusing title, I’m not sure how to convey my issue.

I have a struct/module with custom Inspect protocol implementation that outputs string.

defimpl Inspect, for: GenGraph.Query do
  @doc false
  @spec insect(GenGraph.Query.t(), %Inspect.Opts{}) :: binary()
  def inspect(query, _opts) do
    GenGraph.Query.to_cypher(query)
  end
end

In my main module, I have a macro that generates GenGraph.Query, but with the custom Inspect protocol implementation, it should outputs the string representation of the query instead:

  ## Examples

      iex> GenGraph.match p in "Person"
      MATCH (p:Person)

However, I got the following exception:

Doctest did not compile, got: (SyntaxError) lib/gen_graph.ex:33: syntax error before: '('

If I try to wrap the expected output with double quotes, the doctest failed:

Doctest failed
code:  GenGraph.match p in "Person" === "MATCH (p:Person)"
left:  MATCH (p:Person)
right: "MATCH (p:Person)"

My question is: Is this use case supposed?

I read https://hexdocs.pm/ex_unit/ExUnit.DocTest.html#module-opaque-types, but it feels like I’m not really performing a test as all if my expected and actual are doing the same expression, i.e.:

iex> GenGraph.match p in "Person"
GenGraph.match p in "Person"

Of course that would pass, but what’s the point?

Does this work?

iex> inspect(GenGraph.match p in "Person")
"MATCH (p:Person)"

Basically making the inspect explicit.

I believe doctests support either valid Elixir syntax as output or opaque data structures that start with # - that’s also the general convention of inspect - either return valid Elixir syntax or a data structure matching the pattern of #Name<Data>.

2 Likes

It does work! But it does make my doctest quite long, as the queries can be long. But also, quotes are hard to escape.

iex> inspect(GenGraph.match(%{"name" => "Son Tran-Nguyen"} in "Person", as: p))
"MATCH (p:Person) WHERE person.name = \"Son Tran-Nguyen\""

I would expect the above to pass, but no.

Doctest did not compile, got: (SyntaxError) lib/gen_graph.ex:39: syntax error before: 'Son'
code: "MATCH (p:Person) WHERE person.name = "Son Tran-Nguyen""

Yes, I read about the case of opaque data structure. However, I’m not sure how to use the # syntax for my case.

You could implement inspect as:

defimpl Inspect, for: GenGraph.Query do
  import Inspect.Algebra

  @doc false
  @spec insect(GenGraph.Query.t(), %Inspect.Opts{}) :: binary()
  def inspect(query, _opts) do
    "#GenGraph.Query<" <> GenGraph.Query.to_cypher(query) <> ">"
  end
end

Which will produce inspect output like:

#GenGraph.Query<MATCH (p:Person) WHERE person.name = "Son Tran-Nguyen">
2 Likes

That’s awesome and really nice to know (maybe that can be added to the documentation). Thank you!

Is the import Inspect.Algebra used in the code snippet?