Skip to content

Commit 11c2368

Browse files
committed
Support ellipsis in doctest exceptions
1 parent 1de463f commit 11c2368

File tree

2 files changed

+47
-3
lines changed

2 files changed

+47
-3
lines changed

lib/ex_unit/lib/ex_unit/doc_test.ex

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
defmodule ExUnit.DocTest do
2-
@moduledoc """
2+
@moduledoc ~S"""
33
Extract test cases from the documentation.
44
55
Doctests allow us to generate tests from code examples found
@@ -131,7 +131,7 @@ defmodule ExUnit.DocTest do
131131
132132
You can also showcase expressions raising an exception, for example:
133133
134-
iex(1)> raise "some error"
134+
iex> raise "some error"
135135
** (RuntimeError) some error
136136
137137
Doctest will look for a line starting with `** (` and it will parse it
@@ -141,6 +141,19 @@ defmodule ExUnit.DocTest do
141141
Therefore, it is possible to match on multiline messages as long as there
142142
are no empty lines on the message itself.
143143
144+
Asserting on the full exception message might not be possible because it is
145+
non-deterministic, or it might result in brittle tests if the exact message
146+
changes and gets more detailed.
147+
Since Elixir 1.19.0, doctests allow the use of an ellipsis (`...`) at the
148+
end of messages:
149+
150+
iex> raise "some error in pid: #{inspect(self())}"
151+
** (RuntimeError) some error in pid: ...
152+
153+
iex> raise "some error in pid:\n#{inspect(self())}"
154+
** (RuntimeError) some error in pid:
155+
...
156+
144157
## When not to use doctest
145158
146159
In general, doctests are not recommended when your code examples contain
@@ -565,7 +578,7 @@ defmodule ExUnit.DocTest do
565578
"Doctest failed: expected exception #{inspect(exception)} but got " <>
566579
"#{inspect(actual_exception)} with message #{inspect(actual_message)}"
567580

568-
actual_message != message ->
581+
not error_message_matches?(actual_message, message) ->
569582
"Doctest failed: wrong message for #{inspect(actual_exception)}\n" <>
570583
"expected:\n" <>
571584
" #{inspect(message)}\n" <>
@@ -588,6 +601,15 @@ defmodule ExUnit.DocTest do
588601
end
589602
end
590603

604+
defp error_message_matches?(actual, expected) when actual == expected, do: true
605+
606+
defp error_message_matches?(actual, expected) do
607+
case String.replace_suffix(expected, "...", "") do
608+
^expected -> false
609+
ellipsis_removed -> String.starts_with?(actual, ellipsis_removed)
610+
end
611+
end
612+
591613
defp test_import(_mod, false), do: []
592614
defp test_import(mod, _), do: [quote(do: import(unquote(mod)))]
593615

lib/ex_unit/test/ex_unit/doc_test_test.exs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,26 @@ defmodule ExUnit.DocTestTest.PatternMatching do
548548
end
549549
|> ExUnit.BeamHelpers.write_beam()
550550

551+
defmodule ExUnit.DocTestTest.Ellipsis do
552+
@doc """
553+
iex> ExUnit.DocTestTest.Ellipsis.same_line_err(self())
554+
** (ArgumentError) Unexpected: ...
555+
"""
556+
def same_line_err(arg) do
557+
raise ArgumentError, message: "Unexpected: #{inspect(arg)}"
558+
end
559+
560+
@doc """
561+
iex> ExUnit.DocTestTest.Ellipsis.multi_line_err(self())
562+
** (ArgumentError) Unexpected:
563+
...
564+
"""
565+
def multi_line_err(arg) do
566+
raise ArgumentError, message: "Unexpected:\n#{inspect(arg)}"
567+
end
568+
end
569+
|> ExUnit.BeamHelpers.write_beam()
570+
551571
defmodule ExUnit.DocTestTest do
552572
use ExUnit.Case
553573

@@ -574,6 +594,8 @@ defmodule ExUnit.DocTestTest do
574594
doctest ExUnit.DocTestTest.HaikuIndent4UsingInspectOpts,
575595
inspect_opts: [custom_options: [indent: 4]]
576596

597+
doctest ExUnit.DocTestTest.Ellipsis
598+
577599
import ExUnit.CaptureIO
578600

579601
test "multiple functions filtered with :only" do

0 commit comments

Comments
 (0)