Skip to content

Commit b3e5bcd

Browse files
committed
Add integration tests
1 parent 848f57b commit b3e5bcd

File tree

3 files changed

+139
-41
lines changed

3 files changed

+139
-41
lines changed

lib/elixir/src/elixir_errors.erl

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -459,18 +459,16 @@ indent_n([H | T], Count, Indent) -> [Indent, H | indent_n(T, Count - 1, Indent)]
459459

460460
prefix(warning) -> highlight(<<"warning:">>, warning);
461461
prefix(error) -> highlight(<<"error:">>, error);
462-
prefix(hint) -> highlight(<<"hint:">>, hint).
462+
prefix(hint) -> <<"hint:">>.
463463

464464
highlight(Message, Severity) ->
465465
case {Severity, application:get_env(elixir, ansi_enabled, false)} of
466466
{warning, true} -> yellow(Message);
467467
{error, true} -> red(Message);
468-
{hint, true} -> blue(Message);
469468
_ -> Message
470469
end.
471470

472471
yellow(Msg) -> ["\e[33m", Msg, "\e[0m"].
473-
blue(Msg) -> ["\e[34m", Msg, "\e[0m"].
474472
red(Msg) -> ["\e[31m", Msg, "\e[0m"].
475473

476474
env_format(Meta, #{file := EnvFile} = E) ->

lib/elixir/test/elixir/module/types/integration_test.exs

Lines changed: 138 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,33 @@ defmodule Module.Types.IntegrationTest do
66
import ExUnit.CaptureIO
77
import Module.Types.Descr
88

9+
defp builtin_protocols do
10+
[
11+
Collectable,
12+
Enumerable,
13+
IEx.Info,
14+
Inspect,
15+
JSON.Encoder,
16+
List.Chars,
17+
String.Chars
18+
]
19+
end
20+
21+
test "built-in protocols" do
22+
builtin_protocols =
23+
for app <- ~w[eex elixir ex_unit iex logger mix]a,
24+
Application.ensure_loaded(app),
25+
module <- Application.spec(app, :modules),
26+
Code.ensure_loaded(module),
27+
function_exported?(module, :__protocol__, 1),
28+
do: module
29+
30+
# If this test fails, update:
31+
# * lib/elixir/lib/module/types/apply.ex
32+
# * lib/elixir/scripts/elixir_docs.ex
33+
assert Enum.sort(builtin_protocols) == builtin_protocols()
34+
end
35+
936
setup_all do
1037
previous = Application.get_env(:elixir, :ansi_enabled, false)
1138
Application.put_env(:elixir, :ansi_enabled, false)
@@ -347,6 +374,66 @@ defmodule Module.Types.IntegrationTest do
347374
assert_warnings(files, warnings)
348375
end
349376

377+
test "protocol dispatch" do
378+
files = %{
379+
"a.ex" => """
380+
defmodule FooBar do
381+
def example1(_.._//_ = data), do: to_string(data)
382+
def example2(_.._//_ = data), do: "hello \#{data} world"
383+
end
384+
"""
385+
}
386+
387+
warnings = [
388+
"""
389+
warning: incompatible value given to string interpolation:
390+
391+
data
392+
393+
it has type:
394+
395+
-dynamic(%Range{first: term(), last: term(), step: term()})-
396+
397+
but expected one of:
398+
399+
%Date{} or %DateTime{} or %NaiveDateTime{} or %Time{} or %URI{} or %Version{} or
400+
%Version.Requirement{} or atom() or binary() or float() or integer() or list(term())
401+
402+
where "data" was given the type:
403+
404+
# type: dynamic(%Range{})
405+
# from: a.ex:3:24
406+
_.._//_ = data
407+
408+
hint: string interpolation in Elixir uses the String.Chars protocol to convert a data structure into a string. Either convert the data type into a string upfront or implement the protocol accordingly
409+
""",
410+
"""
411+
warning: incompatible types given to String.Chars.to_string/1:
412+
413+
to_string(data)
414+
415+
given types:
416+
417+
-dynamic(%Range{first: term(), last: term(), step: term()})-
418+
419+
but expected one of:
420+
421+
%Date{} or %DateTime{} or %NaiveDateTime{} or %Time{} or %URI{} or %Version{} or
422+
%Version.Requirement{} or atom() or binary() or float() or integer() or list(term())
423+
424+
where "data" was given the type:
425+
426+
# type: dynamic(%Range{})
427+
# from: a.ex:2:24
428+
_.._//_ = data
429+
430+
hint: String.Chars is a protocol in Elixir. Either make sure you give valid data types as arguments or implement the protocol accordingly
431+
"""
432+
]
433+
434+
assert_warnings(files, warnings, consolidate_protocols: true)
435+
end
436+
350437
test "returns diagnostics with source and file" do
351438
files = %{
352439
"a.ex" => """
@@ -374,8 +461,7 @@ defmodule Module.Types.IntegrationTest do
374461
assert String.ends_with?(file, "generated.ex")
375462
assert Path.type(file) == :absolute
376463
after
377-
:code.delete(A)
378-
:code.purge(A)
464+
purge(A)
379465
end
380466
end
381467

@@ -1095,40 +1181,42 @@ defmodule Module.Types.IntegrationTest do
10951181
end
10961182
end
10971183

1098-
defp assert_warnings(files, expected) when is_binary(expected) do
1099-
assert capture_compile_warnings(files) == expected
1184+
defp assert_warnings(files, expected, opts \\ [])
1185+
1186+
defp assert_warnings(files, expected, opts) when is_binary(expected) do
1187+
assert capture_compile_warnings(files, opts) == expected
11001188
end
11011189

1102-
defp assert_warnings(files, expecteds) when is_list(expecteds) do
1103-
output = capture_compile_warnings(files)
1190+
defp assert_warnings(files, expecteds, opts) when is_list(expecteds) do
1191+
output = capture_compile_warnings(files, opts)
11041192

11051193
Enum.each(expecteds, fn expected ->
11061194
assert output =~ expected
11071195
end)
11081196
end
11091197

11101198
defp assert_no_warnings(files) do
1111-
assert capture_compile_warnings(files) == ""
1199+
assert capture_compile_warnings(files, []) == ""
11121200
end
11131201

1114-
defp capture_compile_warnings(files) do
1202+
defp capture_compile_warnings(files, opts) do
11151203
in_tmp(fn ->
11161204
paths = generate_files(files)
1117-
capture_io(:stderr, fn -> compile_to_path(paths) end)
1205+
capture_io(:stderr, fn -> compile_to_path(paths, opts) end)
11181206
end)
11191207
end
11201208

11211209
defp with_compile_warnings(files) do
11221210
in_tmp(fn ->
11231211
paths = generate_files(files)
1124-
with_io(:stderr, fn -> compile_to_path(paths) end) |> elem(0)
1212+
with_io(:stderr, fn -> compile_to_path(paths, []) end) |> elem(0)
11251213
end)
11261214
end
11271215

11281216
defp compile_modules(files) do
11291217
in_tmp(fn ->
11301218
paths = generate_files(files)
1131-
{modules, _warnings} = compile_to_path(paths)
1219+
{modules, _warnings} = compile_to_path(paths, [])
11321220

11331221
Map.new(modules, fn module ->
11341222
{^module, binary, _filename} = :code.get_object_code(module)
@@ -1137,13 +1225,43 @@ defmodule Module.Types.IntegrationTest do
11371225
end)
11381226
end
11391227

1140-
defp compile_to_path(paths) do
1228+
defp compile_to_path(paths, opts) do
1229+
if opts[:consolidate_protocols] do
1230+
Code.prepend_path(".")
1231+
1232+
result =
1233+
compile_to_path_with_after_compile(paths, fn ->
1234+
if Keyword.get(opts, :consolidate_protocols, false) do
1235+
paths = [".", Application.app_dir(:elixir, "ebin")]
1236+
protocols = Protocol.extract_protocols(paths)
1237+
1238+
for protocol <- protocols do
1239+
impls = Protocol.extract_impls(protocol, paths)
1240+
{:ok, binary} = Protocol.consolidate(protocol, impls)
1241+
File.write!(Atom.to_string(protocol) <> ".beam", binary)
1242+
purge(protocol)
1243+
end
1244+
end
1245+
end)
1246+
1247+
Code.delete_path(".")
1248+
Enum.each(builtin_protocols(), &purge/1)
1249+
1250+
result
1251+
else
1252+
compile_to_path_with_after_compile(paths, fn -> :ok end)
1253+
end
1254+
end
1255+
1256+
defp compile_to_path_with_after_compile(paths, callback) do
11411257
{:ok, modules, warnings} =
1142-
Kernel.ParallelCompiler.compile_to_path(paths, ".", return_diagnostics: true)
1258+
Kernel.ParallelCompiler.compile_to_path(paths, ".",
1259+
return_diagnostics: true,
1260+
after_compile: callback
1261+
)
11431262

11441263
for module <- modules do
1145-
:code.delete(module)
1146-
:code.purge(module)
1264+
purge(module)
11471265
end
11481266

11491267
{modules, warnings}
@@ -1162,6 +1280,11 @@ defmodule Module.Types.IntegrationTest do
11621280
map
11631281
end
11641282

1283+
defp purge(mod) do
1284+
:code.delete(mod)
1285+
:code.purge(mod)
1286+
end
1287+
11651288
defp in_tmp(fun) do
11661289
path = PathHelpers.tmp_path("checker")
11671290

lib/elixir/test/elixir/protocol_test.exs

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -87,29 +87,6 @@ defmodule ProtocolTest do
8787
end
8888
end
8989

90-
test "built-in protocols" do
91-
builtin_protocols =
92-
for app <- ~w[eex elixir ex_unit iex logger mix]a,
93-
Application.ensure_loaded(app),
94-
module <- Application.spec(app, :modules),
95-
Code.ensure_loaded(module),
96-
function_exported?(module, :__protocol__, 1),
97-
do: module
98-
99-
# If this test fails, update:
100-
# * lib/elixir/lib/module/types/apply.ex
101-
# * lib/elixir/scripts/elixir_docs.ex
102-
assert Enum.sort(builtin_protocols) == [
103-
Collectable,
104-
Enumerable,
105-
IEx.Info,
106-
Inspect,
107-
JSON.Encoder,
108-
List.Chars,
109-
String.Chars
110-
]
111-
end
112-
11390
test "protocol implementations without any" do
11491
assert is_nil(Sample.impl_for(:foo))
11592
assert is_nil(Sample.impl_for(fn x -> x end))

0 commit comments

Comments
 (0)