use crate::{assert, assert::Assert};
#[test]
fn funcall_test() {
fn f(x: &str) -> String {
format!(
"
def f1():
return 1
def f2(a): return a
def f3(a, b, c):
return a + b + c
def f4(a, *args):
r = a
for i in args:
r += i
return r
def f5(a, **kwargs): return kwargs
def f6(*args): return args
def rec1(): rec1()
def rec2(): rec3()
def rec3(): rec4()
def rec4(): rec5()
def rec5(): rec6()
def rec6(): rec2()
{}",
x
)
}
assert::is_true(&f("(f1() == 1)"));
assert::is_true(&f("(f2(2) == 2)"));
assert::is_true(&f("(f3(1, 2, 3) == 6)"));
assert::is_true(&f("(f4(1, 2, 3) == 6)"));
assert::is_true(&f("(f5(2) == {})"));
assert::is_true(&f("(f5(a=2) == {})"));
assert::is_true(&f("(f5(1, b=2) == {'b': 2})"));
assert::is_true(&f("(f6(1, 2, 3) == (1, 2, 3))"));
assert::fail(&f("rec1()"), "recursion");
assert::fail(&f("rec2()"), "recursion");
assert::fail("def f(a, a=2): pass", "duplicated parameter");
assert::is_true("def f(a, *args, b): return b\nf(1, b=True)");
assert::is_true("def f(a, *args, b=True): return b\nf(1)");
assert::is_true("NAME=True\ndef f(*args, pkg=NAME, **kwargs): return pkg\nf()");
assert::is_true("def f(*args, pkg=False, **kwargs): return pkg\nf(pkg=True)");
assert::is_true("def f(a, b=1, *args, c=False): return c\nf(a=1,c=True)");
assert::fail("def f(a, **kwargs, b=1): pass", "Default parameter after");
assert::fail(
"def f(a, b=1, **kwargs, c=1): pass",
"Default parameter after",
);
assert::fail("def f(a, **kwargs, *args): pass", "parameter after another");
}
#[test]
fn funcall_extra_args_def() {
fn f(x: &str) -> String {
format!(
"
def f3(a, b, c):
return a + b + c
{}",
x
)
}
assert::fail(&f("f3(1,2,3,4)"), "extra positional");
assert::fail(&f("f3(1,2)"), "Missing parameter");
assert::fail(&f("f3(a=1, b=2)"), "Missing parameter");
assert::fail(&f("f3(a=1, b=2, c=3, d=4)"), "extra named");
}
#[test]
fn test_repeated_parameters() {
assert::fail("def f(x,x): pass", "duplicated parameter");
assert::fail("def f(): pass\ndef g(): f(x=1,x=1)", "repeated named");
}
#[test]
fn test_bad_application() {
assert::fail("['1'](2)", "not supported");
assert::fail("\"test\"(2)", "not supported");
assert::fail("(1 == 1)(2)", "not supported");
}
#[test]
fn test_extra_args_native() {
assert::is_true(r#"("bonbon".find("on") == 1)"#);
assert::fail(r#"("bonbon".find(needle = "on") == 1)"#, "extra named");
assert::fail(r#""bonbon".find("on", 2, 3, 4)"#, "Wrong number of");
assert::fail(r#""bonbon".find("on", needless="on")"#, "extra named");
assert::fail(r#""bonbon".find()"#, "Wrong number of");
}
#[test]
fn test_insufficient_args_native() {
assert::fails(
"filter([])",
&["Wrong number of positional", "expected 2", "got 1"],
);
}
#[test]
fn test_parameter_defaults() {
assert::is_true(
"
def f(x=[x for x in [1]]):
return x
f() == [1]",
);
assert::is_true(
"
y = 7
def f(x=y):
y = 1
return x
f() == 7",
);
assert::is_true(
"
def f(x, xs = []):
xs.append(x)
return xs
pre = str(f(8, [6,7]))
f(1)
post = str(f(2))
pre == '[6, 7, 8]' and post == '[1, 2]'",
);
}
#[test]
fn test_parameter_defaults_frozen() {
let mut a = Assert::new();
a.module("f.bzl", "def f(x, xs = []):\n xs.append(x)\n return xs");
a.is_true("load('f.bzl', 'f')\nf(1, [2]) == [2, 1]");
a.fail("load('f.bzl', 'f')\nf(1) == [1]", "Immutable");
}
#[test]
fn test_arguments() {
fn f(x: &str) -> String {
format!(
"
def f(a, b, c=5):
return a * b + c
def g(a=1, b=2):
return a+b
def h(a=1, *, b=2):
return a+b
{}",
x
)
}
assert::is_true(&f("f(*[2, 3]) == 11"));
assert::is_true(&f("f(*[2, 3, 7]) == 13"));
assert::fail(&f("f(*[2])"), "Missing parameter");
assert::is_true(&f("f(**{'b':3, 'a':2}) == 11"));
assert::is_true(&f("f(**{'c':7, 'a':2, 'b':3}) == 13"));
assert::fail(&f("f(**{'a':2})"), "Missing parameter");
assert::fail(&f("f(**{'c':7, 'a':2, 'b':3, 'd':5})"), "extra named");
assert::fail(&f("f(1, a=1, b=2)"), "occurs both");
assert::fail(&f("g(a=1,*[2])"), "occurs both");
assert::fail(&f("h(1, 2)"), "extra positional");
assert::is_true(&f("h(2, b=3) == 5"));
assert::is_true(&f("h(a=2, b=3) == 5"));
assert::fail(
&f("def bad(x, *, *args):\n pass"),
"parameter after another",
);
}
#[test]
fn test_argument_evaluation_order() {
assert::pass(
r#"
r = []
def id(x):
r.append(x)
return x
def f(*args, **kwargs):
return (args, kwargs)
y = f(id(1), id(2), x=id(3), *[id(4)], **dict(z=id(5)))
assert_eq(y, ((1, 2, 4), dict(x=3, z=5)))
assert_eq(r, [1,2,3,4,5])
"#,
);
}
#[test]
fn test_empty_args_kwargs() {
assert::pass(
r#"
def f(x, *args, **kwargs):
assert_eq(args, ())
assert_eq(kwargs, {})
f(1)
"#,
);
assert::fail(
r#"
def f(x, *, y):
pass
f(1)
"#,
"Missing parameter `y`",
);
}