11defmodule 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,17 @@ 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+ if String . ends_with? ( expected , "..." ) do
608+ ellipsis_removed = binary_slice ( expected , 0 .. - 4 // 1 )
609+ String . starts_with? ( actual , ellipsis_removed )
610+ else
611+ false
612+ end
613+ end
614+
591615 defp test_import ( _mod , false ) , do: [ ]
592616 defp test_import ( mod , _ ) , do: [ quote ( do: import ( unquote ( mod ) ) ) ]
593617
0 commit comments