Files
n8n-openai-adapter/lib/elixir/test/elixir/code_formatter/calls_test.exs
T

1224 lines
23 KiB
Elixir

Code.require_file("../test_helper.exs", __DIR__)
defmodule Code.Formatter.CallsTest do
use ExUnit.Case, async: true
import CodeFormatterHelpers
@short_length [line_length: 10]
@medium_length [line_length: 20]
describe "next break fits" do
test "does not apply to function calls" do
bad = "foo(very_long_call(bar))"
good = """
foo(
very_long_call(
bar
)
)
"""
assert_format bad, good, @short_length
end
test "does not apply to strings" do
bad = "foo(\"very long string\")"
good = """
foo(
"very long string"
)
"""
assert_format bad, good, @short_length
end
test "for functions" do
assert_same """
foo(fn x -> y end)
"""
assert_same """
foo(fn
a1 -> :ok
b2 -> :error
end)
"""
assert_same """
foo(bar, fn
a1 -> :ok
b2 -> :error
end)
"""
assert_same """
foo(fn x ->
:really_long_atom
end)
""",
@medium_length
assert_same """
foo(bar, fn
a1 ->
:ok
b2 ->
:really_long_error
end)
""",
@medium_length
end
test "for heredocs" do
assert_same """
foo(~c'''
bar
''')
"""
assert_same ~S'''
foo("""
bar
""")
'''
assert_same """
foo(~S'''
bar
''')
"""
assert_same """
foo(~S'''
very long line does trigger another break
''')
""",
@short_length
end
test "for lists" do
bad = "foo([1, 2, 3, 4])"
good = """
foo([
1,
2,
3,
4
])
"""
assert_format bad, good, @short_length
end
test "for {} calls" do
bad = """
alias Foo.{
Bar, Baz
}
"""
good = """
alias Foo.{
Bar,
Baz
}
"""
assert_format bad, good, @medium_length
end
test "for binaries only on eol" do
bad = "foo(<<1, 2, 3, 4>>)"
good = """
foo(
<<1, 2,
3, 4>>
)
"""
assert_format bad, good, @short_length
bad = """
foo(<<
# foo
1,
2,
3,
4>>)
"""
good = """
foo(<<
# foo
1,
2,
3,
4
>>)
"""
assert_format bad, good, @short_length
end
end
describe "local calls" do
test "without arguments" do
assert_format "foo( )", "foo()"
end
test "without arguments doesn't split on line limit" do
assert_same "very_long_function_name()", @short_length
end
test "removes outer parens except for unquote_splicing/1" do
assert_format "(foo())", "foo()"
assert_same "(unquote_splicing(123))"
end
test "with arguments" do
assert_format "foo( :one ,:two,\n :three)", "foo(:one, :two, :three)"
end
test "with arguments splits on line limit" do
bad = """
fun(x, y, z)
"""
good = """
fun(
x,
y,
z
)
"""
assert_format bad, good, @short_length
end
test "with arguments on comma limit" do
bad = """
import(foo(abc, cde), :next)
"""
good = """
import(
foo(abc, cde),
:next
)
"""
assert_format bad, good, @medium_length
end
test "with keyword lists" do
assert_same "foo(foo: 1, bar: 2)"
assert_same "foo(:hello, foo: 1, bar: 2)"
bad = """
foo(:hello, foo: 1, bar: 2)
"""
good = """
foo(
:hello,
foo: 1,
bar: 2
)
"""
assert_format bad, good, @short_length
bad = """
foo(:hello, foo: 1,
bar: 2, baz: 3)
"""
assert_format bad, """
foo(:hello, foo: 1, bar: 2, baz: 3)
"""
end
test "with lists maybe rewritten as keyword lists" do
assert_format "foo([foo: 1, bar: 2])", "foo(foo: 1, bar: 2)"
assert_format "foo(:arg, [foo: 1, bar: 2])", "foo(:arg, foo: 1, bar: 2)"
assert_same "foo(:arg, [:elem, foo: 1, bar: 2])"
end
test "without parens" do
assert_same "import :foo, :bar"
assert_same "bar = if foo, do: bar, else: baz"
assert_same """
for :one,
:two,
:three,
fn ->
:ok
end
"""
assert_same """
for :one, fn ->
:ok
end
"""
end
test "without parens on line limit" do
bad = "import :long_atom, :other_arg"
good = """
import :long_atom,
:other_arg
"""
assert_format bad, good, @short_length
end
test "without parens on comma limit" do
bad = """
import foo(abc, cde), :next
"""
good = """
import foo(
abc,
cde
),
:next
"""
assert_format bad, good, @medium_length
end
test "without parens and with keyword lists preserves multiline" do
assert_same """
defstruct foo: 1,
bar: 2
"""
assert_same """
config :app,
foo: 1
"""
assert_same """
config :app,
foo: 1,
bar: 2
"""
assert_same """
config :app, :key,
foo: 1,
bar: 2
"""
assert_same """
config :app,
:key,
foo: 1,
bar: 2
"""
bad = """
config :app, foo: 1,
bar: 2
"""
assert_format bad, """
config :app,
foo: 1,
bar: 2
"""
end
test "without parens and with keyword lists on comma limit" do
bad = """
import foo(abc, cde), opts: :next
"""
good = """
import foo(
abc,
cde
),
opts: :next
"""
assert_format bad, good, @medium_length
end
test "without parens and with keyword lists on line limit" do
assert_same "import :atom, opts: [foo: :bar]"
bad = "import :atom, opts: [foo: :bar]"
good = """
import :atom,
opts: [foo: :bar]
"""
assert_format bad, good, @medium_length
bad = "import :atom, really_long_key: [foo: :bar]"
good = """
import :atom,
really_long_key: [
foo: :bar
]
"""
assert_format bad, good, @medium_length
assert_same """
import :foo,
one: two,
three: four,
five: [6, 7, 8, 9]
""",
@medium_length
assert_same """
import :really_long_atom_but_no_breaks,
one: two,
three: four
""",
@medium_length
bad = "with :really_long_atom1, :really_long_atom2, opts: [foo: :bar]"
good = """
with :really_long_atom1,
:really_long_atom2,
opts: [
foo: :bar
]
"""
assert_format bad, good, @medium_length
end
test "without parens from option" do
assert_format "foo bar", "foo(bar)"
assert_same "foo bar", locals_without_parens: [foo: 1]
assert_same "foo(bar)", locals_without_parens: [foo: 1]
assert_same "foo bar", locals_without_parens: [foo: :*]
assert_same "foo(bar)", locals_without_parens: [foo: :*]
end
test "without parens on unique argument" do
assert_same "foo(for 1, 2, 3)"
assert_same "foo(bar, for(1, 2, 3))"
assert_same "assert for 1, 2, 3"
assert_same "assert foo, for(1, 2, 3)"
assert_same """
assert for 1, 2, 3 do
:ok
end
"""
assert_same """
assert foo, for(1, 2, 3) do
:ok
end
"""
assert_same """
assert for(1, 2, 3) do
:ok
end
"""
assert_same """
assert (for 1, 2, 3 do
:ok
end)
"""
end
test "call on call" do
assert_same "unquote(call)()"
assert_same "unquote(call)(one, two)"
assert_same """
unquote(call)() do
:ok
end
"""
assert_same """
unquote(call)(one, two) do
:ok
end
"""
end
test "call on call on line limit" do
bad = "foo(bar)(one, two, three)"
good = """
foo(bar)(
one,
two,
three
)
"""
assert_format bad, good, @short_length
end
test "with generators" do
assert_same "foo(bar <- baz, is_bat(bar))"
assert_same "for bar <- baz, is_bat(bar)"
assert_same """
foo(
bar <- baz,
is_bat(bar),
bat <- bar
)
"""
assert_same """
for bar <- baz,
is_bat(bar),
bat <- bar
"""
assert_same """
for bar <- baz,
is_bat(bar),
bat <- bar do
:ok
end
"""
assert_same """
for bar <- baz,
is_bat(bar),
bat <- bar,
into: %{}
"""
end
test "preserves user choice on parens even when it fits" do
assert_same """
call(
:hello,
:foo,
:bar
)
"""
assert_same """
call(
:hello,
:foo,
:bar
) do
1 + 2
end
"""
# Doesn't preserve this because only the ending has a newline
assert_format "call(foo, bar, baz\n)", "call(foo, bar, baz)"
# Doesn't preserve because there are no args
bad = """
call() do
1 + 2
end
"""
assert_format bad, """
call do
1 + 2
end
"""
# Doesn't preserve because we have a single argument with next break fits
bad = """
call(
%{
key: :value
}
)
"""
assert_format bad, """
call(%{
key: :value
})
"""
end
end
describe "remote calls" do
test "with no arguments" do
assert_format "Foo . Bar . baz", "Foo.Bar.baz()"
assert_format ":erlang.\nget_stacktrace", ":erlang.get_stacktrace()"
assert_format "@foo.bar", "@foo.bar"
assert_format "@foo.bar()", "@foo.bar()"
assert_format "(@foo).bar()", "@foo.bar()"
assert_format "__MODULE__.start_link", "__MODULE__.start_link()"
assert_format "Foo.bar.baz.bong", "Foo.bar().baz.bong"
assert_format "(1 + 2).foo", "(1 + 2).foo"
assert_format "(1 + 2).foo()", "(1 + 2).foo()"
end
test "with arguments" do
assert_format "Foo . Bar. baz(1, 2, 3)", "Foo.Bar.baz(1, 2, 3)"
assert_format ":erlang.\nget(\n:some_key)", ":erlang.get(:some_key)"
assert_format ":erlang.\nget(:some_key\n)", ":erlang.get(:some_key)"
assert_same "@foo.bar(1, 2, 3)"
assert_same "__MODULE__.start_link(1, 2, 3)"
assert_same "foo.bar(1).baz(2, 3)"
end
test "inspects function names correctly" do
assert_same ~S[MyModule."my function"(1, 2)]
assert_same ~S[MyModule."Foo.Bar"(1, 2)]
assert_same ~S[Kernel.+(1, 2)]
assert_same ~S[:erlang.+(1, 2)]
assert_same ~S[foo."bar baz"(1, 2)]
end
test "splits on arguments and dot on line limit" do
bad = """
MyModule.Foo.bar(:one, :two, :three)
"""
good = """
MyModule.Foo.bar(
:one,
:two,
:three
)
"""
assert_format bad, good, @medium_length
bad = """
My_function.foo().bar(2, 3).baz(4, 5)
"""
good = """
My_function.foo().bar(
2,
3
).baz(4, 5)
"""
assert_format bad, good, @medium_length
end
test "doesn't split on parens on empty arguments" do
assert_same "Mod.func()", @short_length
end
test "with keyword lists" do
assert_same "mod.foo(foo: 1, bar: 2)"
assert_same "mod.foo(:hello, foo: 1, bar: 2)"
assert_same """
mod.really_long_function_name(
:hello,
foo: 1,
bar: 2
)
""",
@short_length
assert_same """
really_long_module_name.foo(
:hello,
foo: 1,
bar: 2
)
""",
@short_length
end
test "wraps left side in parens if it is an anonymous function" do
assert_same "(fn -> :ok end).foo"
end
test "wraps left side in parens if it is a do-end block" do
assert_same """
(if true do
:ok
end).foo
"""
end
test "wraps left side in parens if it is a do-end block as an argument" do
assert_same """
import (if true do
:ok
end).foo
"""
end
test "call on call" do
assert_same "foo.bar(call)()"
assert_same "foo.bar(call)(one, two)"
assert_same """
foo.bar(call)() do
end
"""
assert_same """
foo.bar(call)(one, two) do
:ok
end
"""
end
test "call on call on line limit" do
bad = "a.b(foo)(one, two, three)"
good = """
a.b(foo)(
one,
two,
three
)
"""
assert_format bad, good, @short_length
end
test "on vars" do
assert_same "foo.bar"
assert_same "foo.bar()"
end
test "on vars before blocks" do
assert_same """
if var.field do
raise "oops"
end
"""
end
test "on vars before brackets" do
assert_same """
exception.opts[:foo]
"""
end
test "preserves user choice on parens even when it fits" do
assert_same """
Remote.call(
:hello,
:foo,
:bar
)
"""
# Doesn't preserve this because only the ending has a newline
assert_format "Remote.call(foo, bar, baz\n)", "Remote.call(foo, bar, baz)"
assert_same """
Remote.call(
:hello,
:foo,
fn -> :bar end
)
"""
end
end
describe "anonymous function calls" do
test "without arguments" do
assert_format "foo . ()", "foo.()"
assert_format "(foo.()).().()", "foo.().().()"
assert_same "@foo.()"
assert_same "(1 + 1).()"
assert_same ":foo.()"
end
test "with arguments" do
assert_format "foo . (1, 2 , 3 )", "foo.(1, 2, 3)"
assert_format "foo . (1, 2 ).(3,4)", "foo.(1, 2).(3, 4)"
assert_same "@foo.(:one, :two)"
assert_same "foo.(1 + 1).(hello)"
end
test "does not split on dot on line limit" do
assert_same "my_function.()", @short_length
end
test "splits on arguments on line limit" do
bad = """
my_function.(1, 2, 3)
"""
good = """
my_function.(
1,
2,
3
)
"""
assert_format bad, good, @short_length
bad = """
my_function.(1, 2).f(3, 4).(5, 6)
"""
good = """
my_function.(
1,
2
).f(3, 4).(
5,
6
)
"""
assert_format bad, good, @short_length
end
test "with keyword lists" do
assert_same "foo.(foo: 1, bar: 2)"
assert_same "foo.(:hello, foo: 1, bar: 2)"
assert_same """
foo.(
:hello,
foo: 1,
bar: 2
)
""",
@short_length
end
test "wraps left side in parens if it is an anonymous function" do
assert_same "(fn -> :ok end).()"
end
test "wraps left side in parens if it is a do-end block" do
assert_same """
(if true do
:ok
end).()
"""
end
test "wraps left side in parens if it is a do-end block as an argument" do
assert_same """
import (if true do
:ok
end).()
"""
end
test "preserves user choice on parens even when it fits" do
assert_same """
call.(
:hello,
:foo,
:bar
)
"""
# Doesn't preserve this because only the ending has a newline
assert_format "call.(foo, bar, baz\n)", "call.(foo, bar, baz)"
end
end
describe "do-end blocks" do
test "with non-block keywords" do
assert_same "foo(do: nil)"
end
test "with forced block keywords" do
good = """
foo do
nil
end
"""
assert_format "foo(do: nil)", good, force_do_end_blocks: true
# Avoid false positives
assert_same "foo(do: 1, do: 2)", force_do_end_blocks: true
assert_same "foo(do: 1, another: 2)", force_do_end_blocks: true
end
test "with multiple keywords" do
assert_same """
foo do
:do
rescue
:rescue
catch
:catch
else
:else
after
:after
end
"""
end
test "with multiple keywords and arrows" do
assert_same """
foo do
a1 -> a2
b1 -> b2
rescue
a1 -> a2
b1 -> b2
catch
a1 -> a2
b1 -> b2
else
a1 -> a2
b1 -> b2
after
a1 -> a2
b1 -> b2
end
"""
end
test "with no extra arguments" do
assert_same """
foo do
:ok
end
"""
end
test "with no extra arguments and line breaks" do
assert_same """
foo do
a1 ->
really_long_line
b1 ->
b2
rescue
c1
catch
d1 -> d1
e1 -> e1
else
f2
after
g1 ->
really_long_line
h1 ->
h2
end
""",
@medium_length
end
test "with extra arguments" do
assert_same """
foo bar, baz do
:ok
end
"""
end
test "with extra arguments and line breaks" do
assert_same """
foo bar do
a1 ->
really_long_line
b1 ->
b2
rescue
c1
catch
d1 -> d1
e1 -> e1
else
f2
after
g1 ->
really_long_line
h1 ->
h2
end
""",
@medium_length
assert_same """
foo really,
long,
list,
of,
arguments do
a1 ->
really_long_line
b1 ->
b2
rescue
c1
catch
d1 -> d1
e1 -> e1
else
f2
after
g1 ->
really_long_line
h1 ->
h2
end
""",
@medium_length
end
test "when empty" do
assert_same """
foo do
end
"""
assert_same """
foo do
rescue
catch
else
after
end
"""
end
test "inside call" do
bad = "foo (bar do :ok end)"
good = """
foo(
bar do
:ok
end
)
"""
assert_format bad, good
bad = "import (bar do :ok end)"
good = """
import (bar do
:ok
end)
"""
assert_format bad, good
end
test "inside operator" do
bad = "foo + bar do :ok end"
good = """
foo +
bar do
:ok
end
"""
assert_format bad, good
end
test "inside operator inside argument" do
bad = "fun foo + (bar do :ok end)"
good = """
fun(
foo +
bar do
:ok
end
)
"""
assert_format bad, good
bad = "if foo + (bar do :ok end) do :ok end"
good = """
if foo +
(bar do
:ok
end) do
:ok
end
"""
assert_format bad, good
end
test "inside operator inside argument with remote call" do
bad = "if foo + (Bar.baz do :ok end) do :ok end"
good = """
if foo +
(Bar.baz do
:ok
end) do
:ok
end
"""
assert_format bad, good
end
test "keeps repeated keys" do
assert_same """
receive do
:ok
after
0 -> 1
after
2 -> 3
end
"""
end
test "preserves user choice even when it fits" do
assert_same """
case do
1 ->
:ok
2 ->
:ok
end
"""
assert_same """
case do
1 ->
:ok
2 ->
:ok
3 ->
:ok
end
"""
end
end
describe "tuple calls" do
test "without arguments" do
assert_format "foo . {}", "foo.{}"
end
test "with arguments" do
assert_format "foo.{bar,baz,bat,}", "foo.{bar, baz, bat}"
end
test "with arguments on line limit" do
bad = "foo.{bar,baz,bat,}"
good = """
foo.{
bar,
baz,
bat
}
"""
assert_format bad, good, @short_length
bad = "really_long_expression.{bar,baz,bat,}"
good = """
really_long_expression.{
bar,
baz,
bat
}
"""
assert_format bad, good, @short_length
end
test "with keywords" do
assert_same "expr.{:hello, foo: bar, baz: bat}"
end
test "preserves user choice on parens even when it fits" do
assert_same """
call.{
:hello,
:foo,
:bar
}
"""
assert_format "call.{foo, bar, baz\n}", "call.{foo, bar, baz}"
end
end
describe "access" do
test "with one argument" do
assert_format "foo[ bar ]", "foo[bar]"
end
test "with arguments on line limit" do
bad = "foo[really_long_argument()]"
good = """
foo[
really_long_argument()
]
"""
assert_format bad, good, @short_length
bad = "really_long_expression[really_long_argument()]"
good = """
really_long_expression[
really_long_argument()
]
"""
assert_format bad, good, @short_length
end
test "with do-end blocks" do
assert_same """
(if true do
false
end)[key]
"""
end
test "with keywords" do
assert_format "expr[[]]", "expr[[]]"
assert_format "expr[foo: bar, baz: bat]", "expr[foo: bar, baz: bat]"
assert_format "expr[[foo: bar, baz: bat]]", "expr[[foo: bar, baz: bat]]"
end
end
end