Skip to content

Commit 2272dd1

Browse files
committed
Better error message for Binary.Chars.List.to_binary. Closes #1144
1 parent 24c6623 commit 2272dd1

File tree

4 files changed

+109
-6
lines changed

4 files changed

+109
-6
lines changed

lib/elixir/lib/binary/chars.ex

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,15 @@ defimpl Binary.Chars, for: List do
5858
5959
"""
6060
def to_binary(thing) do
61-
iolist_to_binary(thing)
61+
try do
62+
iolist_to_binary(thing)
63+
rescue
64+
ArgumentError ->
65+
raise Protocol.UndefinedError,
66+
protocol: __MODULE__,
67+
structure: thing,
68+
extra: "Only iolists are supported"
69+
end
6270
end
6371
end
6472

lib/elixir/lib/exception.ex

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,14 @@ defexception FunctionClauseError, [module: nil, function: nil, arity: nil] do
6767
end
6868
end
6969

70-
defexception Protocol.UndefinedError, [protocol: nil, structure: nil] do
70+
defexception Protocol.UndefinedError, [protocol: nil, structure: nil, extra: nil] do
7171
def message(exception) do
72-
"protocol #{inspect exception.protocol} not implemented for #{inspect exception.structure}"
72+
msg = "protocol #{inspect exception.protocol} not implemented for #{inspect exception.structure}"
73+
if exception.extra do
74+
msg <> ". " <> exception.extra
75+
else
76+
msg
77+
end
7378
end
7479
end
7580

lib/elixir/test/elixir/binary/chars_test.exs

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,89 @@ defmodule Binary.Chars.ListTest do
7171
assert to_binary([]) == ""
7272
end
7373
end
74+
75+
defmodule Binary.Chars.ErrorsTest do
76+
use ExUnit.Case, async: true
77+
78+
test :list do
79+
assert to_binary([0,1, 2, 3,255]) == <<0,1,2,3,255>>
80+
assert to_binary([0,[1, "hello"], 2, [["bye"]]]) == <<0,1,104,101,108,108,111,2,98,121,101>>
81+
82+
assert_raise Protocol.UndefinedError, "protocol Binary.Chars.List not implemented for [256]. Only iolists are supported", fn ->
83+
to_binary([256])
84+
end
85+
assert_raise Protocol.UndefinedError, "protocol Binary.Chars.List not implemented for [1001,10001,100001]. Only iolists are supported", fn ->
86+
to_binary([1001, 10001, 100001])
87+
end
88+
assert_raise Protocol.UndefinedError, "protocol Binary.Chars.List not implemented for [:atom,13,\"hello\"]. Only iolists are supported", fn ->
89+
to_binary([:atom, 13, "hello"])
90+
end
91+
end
92+
93+
test :tuple do
94+
assert_raise Protocol.UndefinedError, "protocol Binary.Chars not implemented for {1,2,3}", fn ->
95+
to_binary({1,2,3})
96+
end
97+
end
98+
99+
test :nested_in_tuple do
100+
assert_raise Protocol.UndefinedError, "protocol Binary.Chars not implemented for {1,[2],:atom}", fn ->
101+
to_binary({1, [2], :atom})
102+
end
103+
end
104+
105+
test :nested_tuple do
106+
assert_raise Protocol.UndefinedError, "protocol Binary.Chars.List not implemented for [1,{[2],:atom}]. Only iolists are supported", fn ->
107+
to_binary([1, {[2], :atom}])
108+
end
109+
end
110+
111+
test :nested_pid do
112+
assert_raise Protocol.UndefinedError, %r"^protocol Binary\.Chars\.List not implemented for \[#PID<.+?>,:atom\]\. Only iolists are supported$", fn ->
113+
to_binary([self(), :atom])
114+
end
115+
end
116+
117+
test :nested_fun do
118+
assert_raise Protocol.UndefinedError, %r"^protocol Binary\.Chars\.List not implemented for \[:atom,#Function<.+?>\]\. Only iolists are supported$", fn ->
119+
to_binary([:atom, fn -> end])
120+
end
121+
end
122+
123+
test :record do
124+
# FIXME: is this expected error message?
125+
assert_raise UndefinedFunctionError, "undefined function: Binary.Chars.ArgumentError.to_binary/1", fn ->
126+
to_binary(ArgumentError[])
127+
end
128+
129+
# FIXME: is this expected error message?
130+
assert_raise UndefinedFunctionError, "undefined function: Binary.Chars.File.Stat.to_binary/1", fn ->
131+
to_binary(File.Stat[])
132+
end
133+
end
134+
135+
test :pid do
136+
assert_raise Protocol.UndefinedError, %r"^protocol Binary\.Chars not implemented for #PID<.+?>$", fn ->
137+
to_binary(self())
138+
end
139+
end
140+
141+
test :ref do
142+
assert_raise Protocol.UndefinedError, %r"^protocol Binary\.Chars not implemented for #Reference<.+?>$", fn ->
143+
to_binary(make_ref()) == ""
144+
end
145+
end
146+
147+
test :function do
148+
assert_raise Protocol.UndefinedError, %r"^protocol Binary\.Chars not implemented for #Function<.+?>$", fn ->
149+
to_binary(fn -> end)
150+
end
151+
end
152+
153+
test :port do
154+
[port|_] = Port.list
155+
assert_raise Protocol.UndefinedError, %r"^protocol Binary\.Chars not implemented for #Port<.+?>$", fn ->
156+
to_binary(port)
157+
end
158+
end
159+
end

lib/ex_unit/lib/ex_unit/assertions.ex

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -290,10 +290,14 @@ defmodule ExUnit.Assertions do
290290
1 + "test"
291291
end
292292
"""
293-
def assert_raise(exception, message, function) when is_binary(message) and is_function(function) do
293+
def assert_raise(exception, message, function) when is_function(function) do
294294
error = assert_raise(exception, function)
295-
assert message == error.message, message, error.message,
296-
prelude: "Expected #{inspect error}'s message", reason: "a match"
295+
is_match = case message do
296+
re when is_regex(re) -> error.message =~ re
297+
bin when is_binary(bin) -> error.message == bin
298+
end
299+
assert is_match, message, error.message,
300+
prelude: "Expected #{inspect error}'s message", reason: "match"
297301
error
298302
end
299303

0 commit comments

Comments
 (0)