import ExUnit.AssertionsError Handling - Dealing gracefully with things that go wrong
parse_number = fn string ->
case Integer.parse(string) do
{number, ""} -> {:ok, number}
_ -> {:error, :invalid_format}
end
endassert parse_number.("123") == ___assert parse_number.("abc") == ___divide = fn x, y ->
case y do
0 -> {:error, :division_by_zero}
_ -> {:ok, x / y}
end
end
result =
case divide.(10, 2) do
{:ok, value} -> "Result: #{value}"
{:error, reason} -> "Error: #{reason}"
endassert result == ___result =
try do
10 / 0
rescue
ArithmeticError -> "Cannot divide by zero!"
endassert result == ___safe_list_access = fn list, index ->
try do
{:ok, Enum.at(list, index)}
rescue
FunctionClauseError -> {:error, :invalid_argument}
e in Protocol.UndefinedError -> {:error, "#{e.value} is not a list"}
end
endassert safe_list_access.([1, 2, 3], 1) == ___assert safe_list_access.([1, 2, 3], "a") == ___assert safe_list_access.("abc", 0) == ___risky_operation = fn input ->
try do
case input do
"divide" -> 10 / 0
"access" -> Map.fetch!(%{}, :missing_key)
"convert" -> String.to_integer("not_a_number")
_ -> {:ok, "success"}
end
rescue
ArithmeticError -> {:error, :arithmetic}
KeyError -> {:error, :missing_key}
ArgumentError -> {:error, :invalid_argument}
end
endassert risky_operation.("divide") == ___assert risky_operation.("access") == ___assert risky_operation.("convert") == ___assert risky_operation.("safe") == ___result =
try do
throw(:early_return)
"this won't be reached"
catch
:early_return -> "caught thrown value"
endassert result == ___cleanup_called =
try do
raise "something went wrong"
rescue
RuntimeError -> :returned_value
after
IO.puts("Executed but not returned")
endassert cleanup_called == ___{result, value} =
try do
{:success, "it worked"}
after
IO.puts("Executed but not returned")
endassert result == ___assert value == ___defmodule CustomError do
defexception message: "something custom went wrong"
end
result =
try do
raise CustomError, message: "custom failure"
rescue
e in CustomError -> "caught custom error: #{e.message}"
endassert result == ___result =
try do
Map.fetch!(%{a: 1}, :b)
rescue
KeyError -> "key not found"
endassert result == ___result =
try do
exit(:normal)
catch
:exit, :normal -> "caught normal exit"
endassert result == ___handle_database_operation = fn operation ->
try do
case operation do
:connection_error -> raise "connection failed"
:timeout -> exit(:timeout)
:invalid_query -> throw(:bad_query)
:success -> {:ok, "data retrieved"}
end
rescue
e in RuntimeError -> {:error, {:exception, e.message}}
catch
:exit, :timeout -> {:error, :timeout}
:bad_query -> {:error, :invalid_query}
end
endassert handle_database_operation.(:connection_error) == ___assert handle_database_operation.(:timeout) == ___assert handle_database_operation.(:invalid_query) == ___assert handle_database_operation.(:success) == ___enriched_error = fn ->
try do
String.to_integer("not a number")
rescue
e in ArgumentError ->
{:error,
%{
type: :conversion_error,
original: e,
context: "user input processing",
message: "Failed to convert string to integer"
}}
end
end
{:error, error_info} = enriched_error.()assert error_info.type == ___assert error_info.context == ___