Files
n8n-openai-adapter/lib/elixir/test/elixir/kernel/errors_test.exs
T
José Valim 0e5804fdbf Merge pull request #3666 from lexmag/import-many-friends
Introduce support for Mod.{A, B, C} on imports, alias, require and use
2015-09-25 12:02:30 +02:00

914 lines
26 KiB
Elixir
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
Code.require_file "../test_helper.exs", __DIR__
defmodule Kernel.ErrorsTest do
use ExUnit.Case, async: true
import CompileAssertion
defmodule UnproperMacro do
defmacro unproper(args), do: args
defmacro exit(args), do: args
end
test "invalid token" do
assert_compile_fail SyntaxError,
"nofile:1: unexpected token: \" \" (column 7, codepoint U+00A0)",
'[foo: \u00A0]\noops'
end
test "invalid quoted token" do
assert_compile_fail SyntaxError,
"nofile:1: syntax error before: \"world\"",
'"hello" "world"'
assert_compile_fail SyntaxError,
"nofile:1: syntax error before: Foobar",
'1 Foobar'
assert_compile_fail SyntaxError,
"nofile:1: syntax error before: foo",
'Foo.:foo'
assert_compile_fail SyntaxError,
"nofile:1: syntax error before: \"foo\"",
'Foo.:"foo\#{:bar}"'
assert_compile_fail SyntaxError,
"nofile:1: syntax error before: \"",
'Foo.:"\#{:bar}"'
end
test "invalid identifier" do
msg = fn char, name -> "nofile:1: invalid character '#{char}' in identifier: #{name}" end
assert_compile_fail SyntaxError, msg.(:@, "foo@"), 'foo@'
assert_compile_fail SyntaxError, msg.(:@, "foo@"), 'foo@ '
assert_compile_fail SyntaxError, msg.(:@, "foo@bar"), 'foo@bar'
assert_compile_fail SyntaxError, msg.(:!, "Foo!"), 'Foo!'
end
test "invalid fn" do
assert_compile_fail SyntaxError,
"nofile:1: expected clauses to be defined with -> inside: 'fn'",
'fn 1 end'
end
test "kw missing space" do
msg = "nofile:1: keyword argument must be followed by space after: foo:"
assert_compile_fail SyntaxError, msg, "foo:bar"
assert_compile_fail SyntaxError, msg, "foo:+"
assert_compile_fail SyntaxError, msg, "foo:+1"
end
test "sigil terminator" do
assert_compile_fail TokenMissingError,
"nofile:3: missing terminator: \" (for sigil ~r\" starting at line 1)",
'~r"foo\n\n'
assert_compile_fail TokenMissingError,
"nofile:3: missing terminator: } (for sigil ~r{ starting at line 1)",
'~r{foo\n\n'
end
test "dot terminator" do
assert_compile_fail TokenMissingError,
"nofile:1: missing terminator: \" (for function name starting at line 1)",
'foo."bar'
end
test "string terminator" do
assert_compile_fail TokenMissingError,
"nofile:1: missing terminator: \" (for string starting at line 1)",
'"bar'
end
test "heredoc start" do
assert_compile_fail SyntaxError,
"nofile:1: heredoc start must be followed by a new line after \"\"\"",
'"""bar\n"""'
end
test "heredoc terminator" do
assert_compile_fail TokenMissingError,
"nofile:2: missing terminator: \"\"\" (for heredoc starting at line 1)",
'"""\nbar'
assert_compile_fail SyntaxError,
"nofile:2: invalid location for heredoc terminator, please escape token or move to its own line: \"\"\"",
'"""\nbar"""'
end
test "unexpected end" do
assert_compile_fail SyntaxError,
"nofile:1: unexpected token: end",
'1 end'
end
test "syntax error" do
assert_compile_fail SyntaxError,
"nofile:1: syntax error before: '.'",
'+.foo'
end
test "syntax error before sigil" do
msg = fn x -> "nofile:1: syntax error before: sigil ~s starting with content '#{x}'" end
assert_compile_fail SyntaxError, msg.("bar baz"), '~s(foo) ~s(bar baz)'
assert_compile_fail SyntaxError, msg.(""), '~s(foo) ~s()'
assert_compile_fail SyntaxError, msg.("bar "), '~s(foo) ~s(bar \#{:baz})'
assert_compile_fail SyntaxError, msg.(""), '~s(foo) ~s(\#{:bar} baz)'
end
test "compile error on op ambiguity" do
msg = "nofile:1: \"a -1\" looks like a function call but there is a variable named \"a\", " <>
"please use explicit parentheses or even spaces"
assert_compile_fail CompileError, msg, 'a = 1; a -1'
max = 1
assert max == 1
assert (max 1, 2) == 2
end
test "syntax error on parens call" do
msg = "nofile:1: unexpected parentheses. If you are making a function call, do not " <>
"insert spaces between the function name and the opening parentheses. " <>
"Syntax error before: '('"
assert_compile_fail SyntaxError, msg, 'foo (hello, world)'
end
test "syntax error on nested no parens call" do
msg = "nofile:1: unexpected comma. Parentheses are required to solve ambiguity"
assert_compile_fail SyntaxError, msg, '[foo 1, 2]'
assert_compile_fail SyntaxError, msg, '[foo bar 1, 2]'
assert_compile_fail SyntaxError, msg, '[do: foo 1, 2]'
assert_compile_fail SyntaxError, msg, 'foo(do: bar 1, 2)'
assert_compile_fail SyntaxError, msg, '{foo 1, 2}'
assert_compile_fail SyntaxError, msg, '{foo bar 1, 2}'
assert_compile_fail SyntaxError, msg, 'foo 1, foo 2, 3'
assert_compile_fail SyntaxError, msg, 'foo 1, @bar 3, 4'
assert_compile_fail SyntaxError, msg, 'foo 1, 2 + bar 3, 4'
assert_compile_fail SyntaxError, msg, 'foo(1, foo 2, 3)'
assert is_list List.flatten [1]
assert is_list Enum.reverse [3, 2, 1], [4, 5, 6]
assert is_list(Enum.reverse [3, 2, 1], [4, 5, 6])
assert false || is_list Enum.reverse [3, 2, 1], [4, 5, 6]
assert [List.flatten List.flatten [1]] == [[1]]
interpret = fn x -> Macro.to_string Code.string_to_quoted! x end
assert interpret.("f 1 + g h 2, 3") == "f(1 + g(h(2, 3)))"
assert interpret.("assert [] = TestRepo.all from p in Post, where: p.title in ^[]") ==
"assert([] = TestRepo.all(from(p in Post, where: p.title() in ^[])))"
end
test "syntax error on atom dot alias" do
msg = "nofile:1: atom cannot be followed by an alias. If the '.' was meant to be " <>
"part of the atom's name, the atom name must be quoted. Syntax error before: '.'"
assert_compile_fail SyntaxError, msg, ':foo.Bar'
assert_compile_fail SyntaxError, msg, ':"foo".Bar'
end
test "syntax error with no token" do
assert_compile_fail TokenMissingError,
"nofile:1: missing terminator: ) (for \"(\" starting at line 1)",
'case 1 ('
end
test "clause with defaults" do
assert_compile_fail CompileError,
"nofile:3: def hello/1 has default values and multiple clauses, " <>
"define a function head with the defaults",
~C'''
defmodule Kernel.ErrorsTest.ClauseWithDefaults1 do
def hello(arg \\ 0), do: nil
def hello(arg \\ 1), do: nil
end
'''
assert_compile_fail CompileError,
"nofile:2: function foo/0 undefined",
~C'''
defmodule Kernel.ErrorsTest.ClauseWithDefaults3 do
def hello(foo, bar \\ foo)
def hello(foo, bar), do: foo + bar
end
'''
end
test "invalid match pattern" do
assert_compile_fail CompileError,
"nofile:2: invalid expression in match",
'''
case true do
true && true -> true
end
'''
end
test "different defs with defaults" do
assert_compile_fail CompileError,
"nofile:3: def hello/3 defaults conflicts with def hello/2",
~C'''
defmodule Kernel.ErrorsTest.DifferentDefsWithDefaults1 do
def hello(a, b \\ nil), do: a + b
def hello(a, b \\ nil, c \\ nil), do: a + b + c
end
'''
assert_compile_fail CompileError,
"nofile:3: def hello/2 conflicts with defaults from def hello/3",
~C'''
defmodule Kernel.ErrorsTest.DifferentDefsWithDefaults2 do
def hello(a, b \\ nil, c \\ nil), do: a + b + c
def hello(a, b \\ nil), do: a + b
end
'''
end
test "bad form" do
assert_compile_fail CompileError,
"nofile:2: function bar/0 undefined",
'''
defmodule Kernel.ErrorsTest.BadForm do
def foo, do: bar
end
'''
end
test "unbound var" do
assert_compile_fail CompileError,
"nofile:1: unbound variable ^x",
'^x = 1'
end
test "unbound not match" do
assert_compile_fail CompileError,
"nofile:1: cannot use ^x outside of match clauses",
'^x'
end
test "unbound expr" do
assert_compile_fail CompileError,
"nofile:1: invalid argument for unary operator ^, expected an existing variable, got: ^is_atom(:foo)",
'^is_atom(:foo) = true'
end
test "literal on map and struct" do
assert_compile_fail SyntaxError,
"nofile:1: syntax error before: '}'",
'%{{:a, :b}}'
assert_compile_fail SyntaxError,
"nofile:1: syntax error before: '{'",
'%{:a, :b}{a: :b}'
assert_compile_fail CompileError,
"nofile:1: expected key-value pairs in a map, got: put_in(foo.bar().baz(), nil)",
'foo = 1; %{put_in(foo.bar.baz, nil), :bar}'
end
test "struct fields on defstruct" do
assert_compile_fail ArgumentError,
"struct field names must be atoms, got: 1",
'''
defmodule Kernel.ErrorsTest.StructFieldsOnDefstruct do
defstruct [1, 2, 3]
end
'''
end
test "struct access on body" do
assert_compile_fail CompileError,
"nofile:3: cannot access struct Kernel.ErrorsTest.StructAccessOnBody, " <>
"the struct was not yet defined or the struct " <>
"is being accessed in the same context that defines it",
'''
defmodule Kernel.ErrorsTest.StructAccessOnBody do
defstruct %{name: "Brasilia"}
%Kernel.ErrorsTest.StructAccessOnBody{}
end
'''
end
test "unbound map key var" do
assert_compile_fail CompileError,
"nofile:1: illegal use of variable x in map key",
'%{x => 1} = %{}'
assert_compile_fail CompileError,
"nofile:1: illegal use of variable x in map key",
'%{x = 1 => 1}'
end
test "struct errors" do
assert_compile_fail CompileError,
"nofile:1: BadStruct.__struct__/0 is undefined, cannot expand struct BadStruct",
'%BadStruct{}'
defmodule BadStruct do
def __struct__ do
[]
end
end
assert_compile_fail CompileError,
"nofile:1: expected Kernel.ErrorsTest.BadStruct.__struct__/0 to return a map, got: []",
'%#{BadStruct}{}'
defmodule GoodStruct do
def __struct__ do
%{name: "john"}
end
end
assert_compile_fail CompileError,
"nofile:1: unknown key :age for struct Kernel.ErrorsTest.GoodStruct",
'%#{GoodStruct}{age: 27}'
end
test "name for defmodule" do
assert_compile_fail CompileError,
"nofile:1: invalid module name: 3",
'defmodule 1 + 2, do: 3'
end
test "invalid unquote" do
assert_compile_fail CompileError,
"nofile:1: unquote called outside quote",
'unquote 1'
end
test "invalid unquote splicing in oneliners" do
assert_compile_fail ArgumentError,
"unquote_splicing only works inside arguments and block contexts, " <>
"wrap it in parens if you want it to work with one-liners",
'''
defmodule Kernel.ErrorsTest.InvalidUnquoteSplicingInOneliners do
defmacro oneliner2 do
quote do: unquote_splicing 1
end
def callme do
oneliner2
end
end
'''
end
test "invalid quote args" do
assert_compile_fail CompileError,
"nofile:1: invalid arguments for quote",
'quote 1'
assert_compile_fail CompileError,
"nofile:1: invalid options for quote, expected a keyword list",
'''
quote :foo do
foo
end
'''
end
test "invalid calls" do
assert_compile_fail CompileError,
"nofile:1: invalid call foo(1)(2)",
'foo(1)(2)'
assert_compile_fail CompileError,
"nofile:1: invalid call 1.foo()",
'1.foo'
end
test "unhandled stab" do
assert_compile_fail CompileError,
"nofile:3: unhandled operator ->",
'''
defmodule Kernel.ErrorsTest.UnhandledStab do
def fun do
casea foo, do: (bar -> baz)
end
end
'''
end
test "undefined non local function" do
assert_compile_fail CompileError,
"nofile:1: undefined function casea/2",
'casea foo, do: @hello :world'
end
test "invalid attribute" do
msg = ~r"cannot inject attribute @foo into function/macro because cannot escape "
assert_raise ArgumentError, msg, fn ->
defmodule InvalidAttribute do
@foo fn -> end
def bar, do: @foo
end
end
end
test "invalid struct field value" do
msg = ~r"invalid value for struct field baz, cannot escape "
assert_raise ArgumentError, msg, fn ->
defmodule InvaliadStructFieldValue do
defstruct baz: fn -> end
end
end
end
test "match attribute in module" do
msg = "invalid write attribute syntax, you probably meant to use: @foo expression"
assert_raise ArgumentError, msg, fn ->
defmodule MatchAttributeInModule do
@foo = 42
end
end
end
test "invalid fn args" do
assert_compile_fail TokenMissingError,
"nofile:1: missing terminator: end (for \"fn\" starting at line 1)",
'fn 1'
end
test "invalid escape" do
assert_compile_fail TokenMissingError,
"nofile:1: invalid escape \\ at end of file",
'1 \\'
end
test "function local conflict" do
assert_compile_fail CompileError,
"nofile:1: imported Kernel.&&/2 conflicts with local function",
'''
defmodule Kernel.ErrorsTest.FunctionLocalConflict do
def other, do: 1 && 2
def _ && _, do: :error
end
'''
end
test "macro local conflict" do
assert_compile_fail CompileError,
"nofile:6: call to local macro &&/2 conflicts with imported Kernel.&&/2, " <>
"please rename the local macro or remove the conflicting import",
'''
defmodule Kernel.ErrorsTest.MacroLocalConflict do
def hello, do: 1 || 2
defmacro _ || _, do: :ok
defmacro _ && _, do: :error
def world, do: 1 && 2
end
'''
end
test "macro with undefined local" do
assert_compile_fail UndefinedFunctionError,
"undefined function: Kernel.ErrorsTest.MacroWithUndefinedLocal.unknown/1 " <>
"(function unknown/1 is not available)",
'''
defmodule Kernel.ErrorsTest.MacroWithUndefinedLocal do
defmacrop bar, do: unknown(1)
def baz, do: bar()
end
'''
end
test "private macro" do
assert_compile_fail UndefinedFunctionError,
"undefined function: Kernel.ErrorsTest.PrivateMacro.foo/0 (function foo/0 is not available)",
'''
defmodule Kernel.ErrorsTest.PrivateMacro do
defmacrop foo, do: 1
defmacro bar, do: __MODULE__.foo
defmacro baz, do: bar
end
'''
end
test "function definition with alias" do
assert_compile_fail CompileError,
"nofile:2: function names should start with lowercase characters or underscore, invalid name Bar",
'''
defmodule Kernel.ErrorsTest.FunctionDefinitionWithAlias do
def Bar do
:baz
end
end
'''
end
test "function import conflict" do
assert_compile_fail CompileError,
"nofile:3: function exit/1 imported from both :erlang and Kernel, call is ambiguous",
'''
defmodule Kernel.ErrorsTest.FunctionImportConflict do
import :erlang, warn: false
def foo, do: exit(:test)
end
'''
end
test "import invalid macro" do
assert_compile_fail CompileError,
"nofile:1: cannot import Kernel.invalid/1 because it doesn't exist",
'import Kernel, only: [invalid: 1]'
end
test "unrequired macro" do
assert_compile_fail SyntaxError,
"nofile:2: you must require Kernel.ErrorsTest.UnproperMacro before invoking " <>
"the macro Kernel.ErrorsTest.UnproperMacro.unproper/1 "
'''
defmodule Kernel.ErrorsTest.UnrequiredMacro do
Kernel.ErrorsTest.UnproperMacro.unproper([])
end
'''
end
test "def defmacro clause change" do
assert_compile_fail CompileError,
"nofile:3: defmacro foo/1 already defined as def",
'''
defmodule Kernel.ErrorsTest.DefDefmacroClauseChange do
def foo(1), do: 1
defmacro foo(x), do: x
end
'''
end
test "internal function overridden" do
assert_compile_fail CompileError,
"nofile:1: function __info__/1 is internal and should not be overridden",
'''
defmodule Kernel.ErrorsTest.InternalFunctionOverridden do
def __info__(_), do: []
end
'''
end
test "no macros" do
assert_compile_fail CompileError,
"nofile:2: could not load macros from module :lists",
'''
defmodule Kernel.ErrorsTest.NoMacros do
import :lists, only: :macros
end
'''
end
test "invalid macro" do
assert_compile_fail CompileError,
"nofile: invalid quoted expression: {:foo, :bar, :baz, :bat}",
'''
defmodule Kernel.ErrorsTest.InvalidMacro do
defmacrop oops do
{:foo, :bar, :baz, :bat}
end
def test, do: oops
end
'''
end
test "unloaded module" do
assert_compile_fail CompileError,
"nofile:1: module Certainly.Doesnt.Exist is not loaded and could not be found",
'import Certainly.Doesnt.Exist'
end
test "scheduled module" do
assert_compile_fail CompileError,
"nofile:4: module Kernel.ErrorsTest.ScheduledModule.Hygiene is not loaded but was defined. " <>
"This happens because you are trying to use a module in the same context it is defined. " <>
"Try defining the module outside the context that requires it.",
'''
defmodule Kernel.ErrorsTest.ScheduledModule do
defmodule Hygiene do
end
import Kernel.ErrorsTest.ScheduledModule.Hygiene
end
'''
end
test "already compiled module" do
assert_compile_fail ArgumentError,
"could not call eval_quoted on module Record " <>
"because it was already compiled",
'Module.eval_quoted Record, quote(do: 1), [], file: __ENV__.file'
end
test "interpolation error" do
assert_compile_fail SyntaxError,
"nofile:1: unexpected token: \")\". \"do\" starting at line 1 is missing terminator \"end\"",
'"foo\#{case 1 do )}bar"'
end
test "in definition module" do
assert_compile_fail CompileError,
"nofile:2: cannot define module Kernel.ErrorsTest.InDefinitionModule " <>
"because it is currently being defined in nofile:1",
'''
defmodule Kernel.ErrorsTest.InDefinitionModule do
defmodule Elixir.Kernel.ErrorsTest.InDefinitionModule, do: true
end
'''
end
test "invalid definition" do
assert_compile_fail CompileError,
"nofile:1: invalid syntax in def 1.(hello)",
'defmodule Kernel.ErrorsTest.InvalidDefinition, do: (def 1.(hello), do: true)'
end
test "duplicated bitstring size" do
assert_compile_fail CompileError,
"nofile:1: duplicated size definition in bitstring",
'<<1 :: size(12)-size(13)>>'
end
test "invalid bitstring specified" do
assert_compile_fail CompileError,
"nofile:1: unknown bitstring specifier :atom",
'<<1 :: :atom>>'
assert_compile_fail CompileError,
"nofile:1: unknown bitstring specifier unknown()",
'<<1 :: unknown>>'
assert_compile_fail CompileError,
"nofile:1: unknown bitstring specifier another(12)",
'<<1 :: another(12)>>'
assert_compile_fail CompileError,
"nofile:1: size in bitstring expects an integer or a variable as argument, got: :a",
'<<1 :: size(:a)>>'
assert_compile_fail CompileError,
"nofile:1: unit in bitstring expects an integer as argument, got: :x",
'<<1 :: unit(:x)>>'
end
test "invalid alias" do
assert_compile_fail CompileError,
"nofile:1: invalid value for keyword :as, expected a simple alias, got nested alias: Sample.Lists",
'alias :lists, as: Sample.Lists'
assert_compile_fail CompileError,
"nofile:1: invalid argument for alias, expected a compile time atom or alias, got: 1 + 2",
'alias 1 + 2'
end
test "invalid alias expansion" do
assert_compile_fail CompileError,
"nofile:1: an alias must expand to an atom at compilation time, but did not in \"foo.Foo\". " <>
"Use Module.concat/2 if you want to dynamically generate aliases",
'foo = :foo; foo.Foo'
end
test "invalid import option" do
assert_compile_fail CompileError,
"nofile:1: unsupported option :ops given to import",
'import :lists, [ops: 1]'
end
test "invalid rescue clause" do
assert_compile_fail CompileError,
"nofile:4: invalid rescue clause. The clause should match on an alias, a variable or be in the \"var in [alias]\" format",
'try do\n1\nrescue\n%UndefinedFunctionError{arity: 1} -> false\nend'
end
test "invalid for without generators" do
assert_compile_fail CompileError,
"nofile:1: for comprehensions must start with a generator",
'for is_atom(:foo), do: :foo'
end
test "invalid for bit generator" do
assert_compile_fail CompileError,
"nofile:1: bitstring fields without size are not allowed in bitstring generators",
'for << x :: binary <- "123" >>, do: x'
end
test "unbound cond" do
assert_compile_fail CompileError,
"nofile:1: unbound variable _ inside cond. If you want the last clause to always match, " <>
"you probably meant to use: true ->",
'cond do _ -> true end'
end
test "fun different arities" do
assert_compile_fail CompileError,
"nofile:1: cannot mix clauses with different arities in function definition",
'fn x -> x; x, y -> x + y end'
end
test "end of expression" do
# All valid examples
Code.eval_quoted '''
1;
2;
3
(;)
(;1)
(1;)
(1; 2)
fn -> 1; 2 end
fn -> ; end
if true do
;
end
try do
;
catch
_, _ -> ;
after
;
end
'''
# All invalid examples
assert_compile_fail SyntaxError,
"nofile:1: syntax error before: ';'",
'1+;\n2'
assert_compile_fail SyntaxError,
"nofile:1: syntax error before: ';'",
'max(1, ;2)'
end
test "new line error" do
assert_compile_fail SyntaxError,
"nofile:3: syntax error before: eol",
'if true do\n foo = [],\n baz\nend'
end
test "invalid var or function on guard" do
assert_compile_fail CompileError,
"nofile:4: unknown variable something_that_does_not_exist or " <>
"cannot invoke local something_that_does_not_exist/0 inside guard",
'''
defmodule Kernel.ErrorsTest.InvalidVarOrFunctionOnGuard do
def bar do
case [] do
[] when something_that_does_not_exist == [] -> :ok
end
end
end
'''
end
test "bodyless function with guard" do
assert_compile_fail CompileError,
"nofile:2: missing do keyword in def",
'''
defmodule Kernel.ErrorsTest.BodyessFunctionWithGuard do
def foo(n) when is_number(n)
end
'''
end
test "invalid args for bodyless clause" do
assert_compile_fail CompileError,
"nofile:2: can use only variables and \\\\ as arguments of bodyless clause",
'''
defmodule Kernel.ErrorsTest.InvalidArgsForBodylessClause do
def foo(arg // nil)
def foo(_), do: :ok
end
'''
end
test "invalid function on match" do
assert_compile_fail CompileError,
"nofile:3: cannot invoke local something_that_does_not_exist/0 inside match",
'''
defmodule Kernel.ErrorsTest.InvalidFunctionOnMatch do
def fun do
case [] do; something_that_does_not_exist() -> :ok; end
end
end
'''
end
test "invalid remote on match" do
assert_compile_fail CompileError,
"nofile:1: cannot invoke remote function Hello.something_that_does_not_exist/0 inside match",
'case [] do; Hello.something_that_does_not_exist() -> :ok; end'
end
test "invalid remote on guard" do
assert_compile_fail CompileError,
"nofile:1: cannot invoke remote function Hello.something_that_does_not_exist/0 inside guard",
'case [] do; [] when Hello.something_that_does_not_exist == [] -> :ok; end'
end
test "typespec errors" do
assert_compile_fail CompileError,
"nofile:2: type foo() undefined",
'''
defmodule Kernel.ErrorsTest.TypespecErrors1 do
@type omg :: foo
end
'''
message = "nofile:2: spec for undefined function omg/0"
assert_compile_fail CompileError, message,
'''
defmodule Kernel.ErrorsTest.TypespecErrors2 do
@spec omg :: atom
end
'''
end
test "bad unquoting" do
assert_compile_fail CompileError,
"nofile: invalid quoted expression: {:foo, 0, 1}",
'''
defmodule Kernel.ErrorsTest.BadUnquoting do
def range(unquote({:foo, 0, 1})), do: :ok
end
'''
end
test "bad multi-call" do
assert_compile_fail CompileError,
"nofile:1: invalid argument for alias, expected a compile time atom or alias, got: 42",
'alias IO.{ANSI, 42}'
assert_compile_fail CompileError,
"nofile:1: :as option is not supported by multi-alias call",
'alias Elixir.{Map}, as: Dict'
assert_compile_fail UndefinedFunctionError,
"undefined function: List.{}/1",
'[List.{Chars}, "one"]'
end
test "macros error stacktrace" do
assert [{:erlang, :+, [1, :foo], _},
{Kernel.ErrorsTest.MacrosErrorStacktrace, :sample, 1, _}|_] =
rescue_stacktrace("""
defmodule Kernel.ErrorsTest.MacrosErrorStacktrace do
defmacro sample(num), do: num + :foo
def other, do: sample(1)
end
""")
end
test "macros function clause stacktrace" do
assert [{__MODULE__, :sample, 1, _}|_] =
rescue_stacktrace("""
defmodule Kernel.ErrorsTest.MacrosFunctionClauseStacktrace do
import Kernel.ErrorsTest
sample(1)
end
""")
end
test "macros interpreted function clause stacktrace" do
assert [{Kernel.ErrorsTest.MacrosInterpretedFunctionClauseStacktrace, :sample, 1, _}|_] =
rescue_stacktrace("""
defmodule Kernel.ErrorsTest.MacrosInterpretedFunctionClauseStacktrace do
defmacro sample(0), do: 0
def other, do: sample(1)
end
""")
end
test "macros compiled callback" do
assert [{Kernel.ErrorsTest, :__before_compile__, [%Macro.Env{module: Kernel.ErrorsTest.MacrosCompiledCallback}], _}|_] =
rescue_stacktrace("""
defmodule Kernel.ErrorsTest.MacrosCompiledCallback do
Module.put_attribute(__MODULE__, :before_compile, Kernel.ErrorsTest)
end
""")
end
defmacro sample(0), do: 0
defmacro before_compile(_) do
quote(do: _)
end
## Helpers
defp rescue_stacktrace(expr) do
result = try do
:elixir.eval(to_char_list(expr), [])
nil
rescue
_ -> System.stacktrace
end
result || raise(ExUnit.AssertionError, message: "Expected function given to rescue_stacktrace to fail")
end
end