summaryrefslogtreecommitdiff
path: root/lib/elixir/test/elixir/code_test.exs
diff options
context:
space:
mode:
Diffstat (limited to 'lib/elixir/test/elixir/code_test.exs')
-rw-r--r--lib/elixir/test/elixir/code_test.exs265
1 files changed, 178 insertions, 87 deletions
diff --git a/lib/elixir/test/elixir/code_test.exs b/lib/elixir/test/elixir/code_test.exs
index 4b1e2e439..3e528d451 100644
--- a/lib/elixir/test/elixir/code_test.exs
+++ b/lib/elixir/test/elixir/code_test.exs
@@ -21,6 +21,41 @@ defmodule CodeTest do
Code.eval_quoted(contents, [], file: "sample.ex", line: 13)
+ describe "with_diagnostics/2" do
+ test "captures warnings" do
+ assert {:warn, [%{message: "hello"}]} =
+ Code.with_diagnostics(fn ->
+ IO.warn("hello")
+ :warn
+ end)
+ end
+
+ test "captures and logs warnings" do
+ assert ExUnit.CaptureIO.capture_io(:stderr, fn ->
+ assert {:warn, [%{message: "hello"}]} =
+ Code.with_diagnostics([log: true], fn ->
+ IO.warn("hello")
+ :warn
+ end)
+ end) =~ "hello"
+ end
+
+ test "can be nested" do
+ assert {:warn, [%{message: "hello"}]} =
+ Code.with_diagnostics(fn ->
+ IO.warn("hello")
+
+ assert {:nested, [%{message: "world"}]} =
+ Code.with_diagnostics(fn ->
+ IO.warn("world")
+ :nested
+ end)
+
+ :warn
+ end)
+ end
+ end
+
describe "eval_string/1,2,3" do
test "correctly evaluates a string of code" do
assert Code.eval_string("1 + 2") == {3, []}
@@ -111,28 +146,45 @@ defmodule CodeTest do
end)
assert output =~ "incompatible types"
+ after
+ :code.purge(CodeTest.CheckerWarning)
+ :code.delete(CodeTest.CheckerWarning)
end
- end
- test "eval_quoted/1" do
- assert Code.eval_quoted(quote(do: 1 + 2)) == {3, []}
- assert CodeTest.Sample.eval_quoted_info() == {CodeTest.Sample, "sample.ex", 13}
+ test "captures checker diagnostics" do
+ {{{:module, _, _, _}, _}, diagnostics} =
+ Code.with_diagnostics(fn ->
+ Code.eval_string(File.read!(fixture_path("checker_warning.exs")), [])
+ end)
+
+ assert [%{message: "incompatible types:" <> _}] = diagnostics
+ after
+ :code.purge(CodeTest.CheckerWarning)
+ :code.delete(CodeTest.CheckerWarning)
+ end
end
- test "eval_quoted/2 with %Macro.Env{} at runtime" do
- alias :lists, as: MyList
- quoted = quote(do: MyList.flatten([[1, 2, 3]]))
+ describe "eval_quoted/1" do
+ test "evaluates expression" do
+ assert Code.eval_quoted(quote(do: 1 + 2)) == {3, []}
+ assert CodeTest.Sample.eval_quoted_info() == {CodeTest.Sample, "sample.ex", 13}
+ end
+
+ test "with %Macro.Env{} at runtime" do
+ alias :lists, as: MyList
+ quoted = quote(do: MyList.flatten([[1, 2, 3]]))
- assert Code.eval_quoted(quoted, [], __ENV__) == {[1, 2, 3], []}
+ assert Code.eval_quoted(quoted, [], __ENV__) == {[1, 2, 3], []}
- # Let's check it discards tracers since the lexical tracker is explicitly nil
- assert Code.eval_quoted(quoted, [], %{__ENV__ | tracers: [:bad]}) == {[1, 2, 3], []}
- end
+ # Let's check it discards tracers since the lexical tracker is explicitly nil
+ assert Code.eval_quoted(quoted, [], %{__ENV__ | tracers: [:bad]}) == {[1, 2, 3], []}
+ end
- test "eval_quoted/2 with %Macro.Env{} at compile time" do
- defmodule CompileTimeEnv do
- alias String.Chars
- {"foo", []} = Code.eval_string("Chars.to_string(:foo)", [], __ENV__)
+ test "with %Macro.Env{} at compile time" do
+ defmodule CompileTimeEnv do
+ alias String.Chars
+ {"foo", []} = Code.eval_string("Chars.to_string(:foo)", [], __ENV__)
+ end
end
end
@@ -144,101 +196,137 @@ defmodule CodeTest do
end
end
- test "eval_quoted_with_env/3" do
- alias :lists, as: MyList
- quoted = quote(do: MyList.flatten([[1, 2, 3]]))
- env = Code.env_for_eval(__ENV__)
- assert Code.eval_quoted_with_env(quoted, [], env) == {[1, 2, 3], [], env}
+ describe "eval_quoted_with_env/3" do
+ test "returns results, bindings, and env" do
+ alias :lists, as: MyList
+ quoted = quote(do: MyList.flatten([[1, 2, 3]]))
+ env = Code.env_for_eval(__ENV__)
+ assert Code.eval_quoted_with_env(quoted, [], env) == {[1, 2, 3], [], env}
- quoted = quote(do: alias(:dict, as: MyDict))
- {:dict, [], env} = Code.eval_quoted_with_env(quoted, [], env)
- assert Macro.Env.fetch_alias(env, :MyDict) == {:ok, :dict}
- end
+ quoted = quote(do: alias(:dict, as: MyDict))
+ {:dict, [], env} = Code.eval_quoted_with_env(quoted, [], env)
+ assert Macro.Env.fetch_alias(env, :MyDict) == {:ok, :dict}
+ end
- test "eval_quoted_with_env/3 with vars" do
- env = Code.env_for_eval(__ENV__)
- {1, [x: 1], env} = Code.eval_quoted_with_env(quote(do: var!(x) = 1), [], env)
- assert Macro.Env.vars(env) == [{:x, nil}]
- end
+ test "manages env vars" do
+ env = Code.env_for_eval(__ENV__)
+ {1, [x: 1], env} = Code.eval_quoted_with_env(quote(do: var!(x) = 1), [], env)
+ assert Macro.Env.vars(env) == [{:x, nil}]
+ end
- test "eval_quoted_with_env/3 with pruning" do
- env = Code.env_for_eval(__ENV__)
+ test "prunes vars" do
+ env = Code.env_for_eval(__ENV__)
- fun = fn quoted, binding ->
- {_, binding, env} = Code.eval_quoted_with_env(quoted, binding, env, prune_binding: true)
- {binding, Macro.Env.vars(env)}
- end
+ fun = fn quoted, binding ->
+ {_, binding, env} = Code.eval_quoted_with_env(quoted, binding, env, prune_binding: true)
+ {binding, Macro.Env.vars(env)}
+ end
- assert fun.(quote(do: 123), []) == {[], []}
- assert fun.(quote(do: 123), x: 2, y: 3) == {[], []}
+ assert fun.(quote(do: 123), []) == {[], []}
+ assert fun.(quote(do: 123), x: 2, y: 3) == {[], []}
- assert fun.(quote(do: var!(x) = 1), []) == {[x: 1], [x: nil]}
- assert fun.(quote(do: var!(x) = 1), x: 2, y: 3) == {[x: 1], [x: nil]}
+ assert fun.(quote(do: var!(x) = 1), []) == {[x: 1], [x: nil]}
+ assert fun.(quote(do: var!(x) = 1), x: 2, y: 3) == {[x: 1], [x: nil]}
- assert fun.(quote(do: var!(x, :foo) = 1), []) == {[{{:x, :foo}, 1}], [x: :foo]}
- assert fun.(quote(do: var!(x, :foo) = 1), x: 2, y: 3) == {[{{:x, :foo}, 1}], [x: :foo]}
+ assert fun.(quote(do: var!(x, :foo) = 1), []) == {[{{:x, :foo}, 1}], [x: :foo]}
+ assert fun.(quote(do: var!(x, :foo) = 1), x: 2, y: 3) == {[{{:x, :foo}, 1}], [x: :foo]}
- assert fun.(quote(do: var!(x, :foo) = 1), [{{:x, :foo}, 2}, {{:y, :foo}, 3}]) ==
- {[{{:x, :foo}, 1}], [x: :foo]}
+ assert fun.(quote(do: var!(x, :foo) = 1), [{{:x, :foo}, 2}, {{:y, :foo}, 3}]) ==
+ {[{{:x, :foo}, 1}], [x: :foo]}
- assert fun.(quote(do: fn -> var!(x, :foo) = 1 end), []) == {[], []}
- assert fun.(quote(do: fn -> var!(x, :foo) = 1 end), x: 1, y: 2) == {[], []}
+ assert fun.(quote(do: fn -> var!(x, :foo) = 1 end), []) == {[], []}
+ assert fun.(quote(do: fn -> var!(x, :foo) = 1 end), x: 1, y: 2) == {[], []}
- assert fun.(quote(do: fn -> var!(x) end), x: 2, y: 3) == {[x: 2], [x: nil]}
+ assert fun.(quote(do: fn -> var!(x) end), x: 2, y: 3) == {[x: 2], [x: nil]}
- assert fun.(quote(do: fn -> var!(x, :foo) end), [{{:x, :foo}, 2}, {{:y, :foo}, 3}]) ==
- {[{{:x, :foo}, 2}], [x: :foo]}
- end
+ assert fun.(quote(do: fn -> var!(x, :foo) end), [{{:x, :foo}, 2}, {{:y, :foo}, 3}]) ==
+ {[{{:x, :foo}, 2}], [x: :foo]}
+ end
- defmodule Tracer do
- def trace(event, env) do
- send(self(), {:trace, event, env})
- :ok
+ defmodule Tracer do
+ def trace(event, env) do
+ send(self(), {:trace, event, env})
+ :ok
+ end
end
- end
- test "eval_quoted_with_env/3 with tracing and pruning" do
- env = %{Code.env_for_eval(__ENV__) | tracers: [Tracer], function: nil}
- binding = [x: 1, y: 2, z: 3]
+ test "with tracing and pruning" do
+ env = %{Code.env_for_eval(__ENV__) | tracers: [Tracer], function: nil}
+ binding = [x: 1, y: 2, z: 3]
- quoted =
- quote do
- defmodule Elixir.CodeTest.TracingPruning do
- var!(y) = :updated
- var!(y)
- var!(x)
+ quoted =
+ quote do
+ defmodule Elixir.CodeTest.TracingPruning do
+ var!(y) = :updated
+ var!(y)
+ var!(x)
+ end
end
- end
- {_, binding, env} = Code.eval_quoted_with_env(quoted, binding, env, prune_binding: true)
- assert Enum.sort(binding) == []
- assert env.versioned_vars == %{}
+ {_, binding, env} = Code.eval_quoted_with_env(quoted, binding, env, prune_binding: true)
+ assert Enum.sort(binding) == []
+ assert env.versioned_vars == %{}
- assert_receive {:trace, {:on_module, _, _}, %{module: CodeTest.TracingPruning} = trace_env}
- assert trace_env.versioned_vars == %{{:result, Kernel} => 5, {:x, nil} => 1, {:y, nil} => 4}
- end
+ assert_receive {:trace, {:on_module, _, _}, %{module: CodeTest.TracingPruning} = trace_env}
+ assert trace_env.versioned_vars == %{{:result, Kernel} => 5, {:x, nil} => 1, {:y, nil} => 4}
+ end
- test "eval_quoted_with_env/3 with defguard" do
- require Integer
- env = Code.env_for_eval(__ENV__)
- quoted = quote do: Integer.is_even(1)
- {false, binding, env} = Code.eval_quoted_with_env(quoted, [], env, prune_binding: true)
- assert binding == []
- assert Macro.Env.vars(env) == []
+ test "with defguard" do
+ require Integer
+ env = Code.env_for_eval(__ENV__)
+ quoted = quote do: Integer.is_even(1)
+ {false, binding, env} = Code.eval_quoted_with_env(quoted, [], env, prune_binding: true)
+ assert binding == []
+ assert Macro.Env.vars(env) == []
+ end
end
- test "compile_file/1" do
- assert Code.compile_file(fixture_path("code_sample.exs")) == []
- refute fixture_path("code_sample.exs") in Code.required_files()
- end
+ describe "compile_file/1" do
+ test "compiles the given path" do
+ assert Code.compile_file(fixture_path("code_sample.exs")) == []
+ refute fixture_path("code_sample.exs") in Code.required_files()
+ end
+
+ test "emits checker warnings" do
+ output =
+ ExUnit.CaptureIO.capture_io(:stderr, fn ->
+ Code.compile_file(fixture_path("checker_warning.exs"))
+ end)
+
+ assert output =~ "incompatible types"
+ after
+ :code.purge(CodeTest.CheckerWarning)
+ :code.delete(CodeTest.CheckerWarning)
+ end
+
+ test "captures checker diagnostics" do
+ {[{CodeTest.CheckerWarning, _}], diagnostics} =
+ Code.with_diagnostics(fn ->
+ Code.compile_file(fixture_path("checker_warning.exs"))
+ end)
+
+ assert [%{message: "incompatible types:" <> _}] = diagnostics
+ after
+ :code.purge(CodeTest.CheckerWarning)
+ :code.delete(CodeTest.CheckerWarning)
+ end
- test "compile_file/1 also emits checker warnings" do
- output =
- ExUnit.CaptureIO.capture_io(:stderr, fn ->
- Code.compile_file(fixture_path("checker_warning.exs"))
- end)
+ test "captures checker diagnostics with logging" do
+ output =
+ ExUnit.CaptureIO.capture_io(:stderr, fn ->
+ {[{CodeTest.CheckerWarning, _}], diagnostics} =
+ Code.with_diagnostics([log: true], fn ->
+ Code.compile_file(fixture_path("checker_warning.exs"))
+ end)
+
+ assert [%{message: "incompatible types:" <> _}] = diagnostics
+ end)
- assert output =~ "incompatible types"
+ assert output =~ "incompatible types"
+ after
+ :code.purge(CodeTest.CheckerWarning)
+ :code.delete(CodeTest.CheckerWarning)
+ end
end
test "require_file/1" do
@@ -317,6 +405,9 @@ defmodule CodeTest do
end)
assert output =~ "incompatible types"
+ after
+ :code.purge(CodeTest.CheckerWarning)
+ :code.delete(CodeTest.CheckerWarning)
end
test "works across lexical scopes" do