use xbasic::xbasic::XBasic;
mod common;
#[test]
fn function_empty() {
common::test_program(
"
a()
function a()
end function
",
"",
)
}
#[test]
fn function_uncalled() {
common::test_program(
"
function a()
print \"Hello world\"
end function
",
"",
)
}
#[test]
fn function_no_return() {
common::test_program(
"
a()
function a()
print \"hi from function\"
end function
",
"hi from function\n",
)
}
#[test]
fn function_parameter() {
common::test_program(
"
a(\"world\", \"hello\")
function a(b, c)
print c b
end function
",
"hello world\n",
)
}
#[test]
fn function_variable_same_name() {
common::test_program(
"
a = 3
print a()
print a
function a()
return 3 + 4
end function
",
"7\n3\n",
)
}
#[test]
fn function_return() {
common::test_program(
"
print a()
function a()
return 3 + 4
end function
",
"7\n",
)
}
#[test]
fn recursion_ok() {
common::test_program(
"
print fib(20)
function fib(n)
if n = 1 or n = 2 then
return 1
end if
return fib(n - 1) + fib(n - 2)
end function
",
"6765\n",
)
}
#[test]
fn recursion_stack_overflow() {
let tio = common::TestIO::new("");
let mut xb = XBasic::new(tio);
assert!(xb
.run(
"
function a()
a()
end function
a()
"
)
.is_err());
assert!(xb.error_handler.had_errors);
assert_eq!(
xb.error_handler.errors,
["[line 3] Error : Stack overflow."]
);
xb.get_io().check();
}
#[test]
fn function_does_not_exist() {
let tio = common::TestIO::new("");
let mut xb = XBasic::new(tio);
assert!(xb
.run(
"
a()
"
)
.is_err());
assert!(xb.error_handler.had_errors);
assert_eq!(
xb.error_handler.errors,
["[line 2] Error at 'a': Not a function."]
);
xb.get_io().check();
}
#[test]
fn function_already_defined() {
let tio = common::TestIO::new("");
let mut xb = XBasic::new(tio);
assert!(xb
.run(
"
function a()
end function
function a()
end function
"
)
.is_err());
assert!(xb.error_handler.had_errors);
assert_eq!(
xb.error_handler.errors,
["[line 5] Error at 'a': Function is already defined on line 2."]
);
xb.get_io().check();
}
#[test]
fn function_mismatched_arity() {
let tio = common::TestIO::new("");
let mut xb = XBasic::new(tio);
assert!(xb
.run(
"
a(1, 2, 3, 4)
function a(b, c, d)
end function
"
)
.is_err());
assert!(xb.error_handler.had_errors);
assert_eq!(
xb.error_handler.errors,
["[line 2] Error at 'a': Expected 3 arguments, got 4."]
);
xb.get_io().check();
}
#[test]
fn function_named_same_as_param() {
common::test_program(
"
print a(3)
function a(a)
return a + 4
end function
",
"7\n",
)
}
#[test]
fn nested_functions() {
common::test_program(
"
print a(3)
function a(a)
return b(a) + 2
end function
function b(c)
return c + 5
end function
",
"10\n",
)
}
#[test]
fn stack_cool_after_function() {
common::test_program(
"
c = 4
print a(3)
b = 3
print b
print c
print b + c
function a(a)
return b(a) + 2
end function
function b(c)
return c + 5
end function
",
"10\n3\n4\n7\n",
)
}
#[test]
fn return_in_main() {
common::test_program(
"
return
",
"",
)
}
#[test]
fn function_across_multiple_calls() {
let tio = common::TestIO::new("5\n");
let mut xb = XBasic::new(tio);
assert!(xb
.run(
"
function a(b)
return b
end function
"
)
.is_ok());
assert!(xb.run("print a(5)\n").is_ok());
assert!(!xb.error_handler.had_errors);
xb.get_io().check();
}
#[test]
fn function_overwrite_across_runs() {
let tio = common::TestIO::new("5\n");
let mut xb = XBasic::new(tio);
assert!(xb
.run(
"
function a(b)
return b
end function
"
)
.is_ok());
assert!(xb
.run(
"
function a(b)
return b * 2
end function
"
)
.is_err());
xb.clear_errors();
assert!(xb.run("print a(5)\n").is_ok());
assert!(!xb.error_handler.had_errors);
xb.get_io().check();
}
#[test]
fn function_variable_edge_case() {
let tio = common::TestIO::new("done\n");
let mut xb = XBasic::new(tio);
assert!(xb
.run(
"
function func(b)
a = 0
end function
func(3)
z = 0
b = 0
print \"done\"
",
)
.is_ok());
assert!(!xb.error_handler.had_errors);
xb.get_io().check();
}
#[test]
fn function_argument_edge_case() {
let tio = common::TestIO::new("3\ndone\n");
let mut xb = XBasic::new(tio);
assert!(xb
.run(
"
a = test
function func(b)
c = 0
print b
end function
func(3)
z = 0
print \"done\"
",
)
.is_ok());
assert!(!xb.error_handler.had_errors);
xb.get_io().check();
}
#[test]
fn function_doesnt_corrupt_stack() {
let tio = common::TestIO::new("3\n0\n1\n2\n3\n4\n5\n");
let mut xb = XBasic::new(tio);
assert!(xb
.run(
"
function func(b)
print b
end function
func(3)
for x = 0 to 5
print x
next x
",
)
.is_ok());
assert!(!xb.error_handler.had_errors);
xb.get_io().check();
}