       assert_received {:block_result, 42}
 
   """
+  @spec capture_io((() -> any())) :: String.t()
   def capture_io(fun) when is_function(fun, 0) do
     capture_io(:stdio, [], fun)
   end
 
+  @spec capture_io(atom(), (() -> any())) :: String.t()
   def capture_io(device, fun) when is_atom(device) and is_function(fun, 0) do
     capture_io(device, [], fun)
   end
 
+  @spec capture_io(String.t(), (() -> any())) :: String.t()
   def capture_io(input, fun) when is_binary(input) and is_function(fun, 0) do
     capture_io(:stdio, [input: input], fun)
   end
 
+  @spec capture_io(list(), (() -> any())) :: String.t()
   def capture_io(options, fun) when is_list(options) and is_function(fun, 0) do
     capture_io(:stdio, options, fun)
   end
 
+  @spec capture_io(atom(), String.t(), (() -> any())) :: String.t()
   def capture_io(device, input, fun)
       when is_atom(device) and is_binary(input) and is_function(fun, 0) do
     capture_io(device, [input: input], fun)
   end
 
+  @spec capture_io(atom(), list(), (() -> any())) :: String.t()
   def capture_io(device, options, fun)
       when is_atom(device) and is_list(options) and is_function(fun, 0) do
     do_capture_io(map_dev(device), options, fun)

  A developer can set a string as an input. The default input
  is an empty string (which is equivalent to `:eof`).

  ## Options

    * `:capture_prompt` - When capturing `:stdio`, if set to `false`,

      true

      iex> capture_io(:stderr, fn -> IO.write(:stderr, "john") end) == "john"
      true

      iex> capture_io(:standard_error, fn -> IO.write(:stderr, "john") end) == "john"
      true

      iex> capture_io("this is input", fn ->
