xbasic 0.1.1

A library that allows adding a scripting language onto your project with ease. This lets your users write their own arbitrary logic.
Documentation
use xbasic::xbasic::XBasic;

mod common;

#[test]
fn if_test_true() {
	common::test_program(
		"if 3 = 3 then\nprint \"1\"\nend if\nprint \"done\"\n",
		"1\ndone\n",
	);
}

#[test]
fn if_test_false() {
	common::test_program(
		"if 3 = 4 then\nprint \"1\"\nend if\nprint \"done\"\n",
		"done\n",
	);
}

#[test]
fn if_no_terminator() {
	let mut tio = common::TestIO::new("");
	{
		let mut xb = XBasic::new(&mut tio);
		assert!(xb.run("if 3 = 4 then\n").is_err());
		assert!(xb.error_handler.had_errors);
		assert_eq!(
			xb.error_handler.errors,
			["[line 2] Error at end: Expected END IF after IF statement."]
		);
	}
	tio.check();
}

// TODO
/*#[test]
fn if_single_line() {
	common::test_program("if 3 = 3 then print \"hi\"\n", "hi\n")
}*/

#[test]
fn if_else_true() {
	common::test_program(
		"if 3 = 3 then\nprint \"1\"\nelse\nprint \"2\"\nend if\nprint \"done\"\n",
		"1\ndone\n",
	);
}

#[test]
fn if_else_false() {
	common::test_program(
		"if 3 = 4 then\nprint \"1\"\nelse\nprint \"2\"\nend if\nprint \"done\"\n",
		"2\ndone\n",
	);
}

#[test]
fn if_elseif() {
	common::test_program(
		"if 3 = 4 then
    print \"1\"
    elseif 5 = 3 then
    print \"2\"
    end if
    print \"done\"
    ",
		"done\n",
	);

	common::test_program(
		"if 3 = 3 then
    print \"1\"
    elseif 5 = 5 then
    print \"2\"
    end if
    print \"done\"
    ",
		"1\ndone\n",
	);

	common::test_program(
		"if 3 = 4 then
    print \"1\"
    elseif 5 = 5 then
    print \"2\"
    end if
    print \"done\"
    ",
		"2\ndone\n",
	);
}

#[test]
fn if_elseif_else() {
	common::test_program(
		"if 3 = 4 then
    print \"1\"
    elseif 5 = 3 then
    print \"2\"
    else
    print 3
    end if
    print \"done\"
    ",
		"3\ndone\n",
	);

	common::test_program(
		"if 3 = 3 then
    print \"1\"
    elseif 5 = 5 then
    print \"2\"
    else
    print 3
    end if
    print \"done\"
    ",
		"1\ndone\n",
	);

	common::test_program(
		"if 3 = 4 then
    print \"1\"
    elseif 5 = 5 then
    print \"2\"
    else
    print 3
    end if
    print \"done\"
    ",
		"2\ndone\n",
	);
}

#[test]
fn if_elseif_missing_then() {
	let mut tio = common::TestIO::new("");
	{
		let mut xb = XBasic::new(&mut tio);
		assert!(xb
			.run(
				"if 5 = 3 then
    print \"hi\"
elseif 3 = 5
    print \"bye\"\
end if
	"
			)
			.is_err());
		assert!(xb.error_handler.had_errors);
		assert_eq!(
			xb.error_handler.errors,
			["[line 3] Error at newline: Expected THEN after ELSEIF statement condition."]
		);
	}
	tio.check();
}

#[test]
fn while_loop() {
	common::test_program(
		"while a < 10
        print a
        a = a + 1
    wend
    ",
		"0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n",
	);
}

#[test]
fn for_loop() {
	common::test_program(
		"for x = 0 to 10
    print x
next x
    ",
		"0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n",
	)
}

#[test]
fn for_loop_backwards() {
	common::test_program(
		"for x = 10 to 0
    print x
next x
    ",
		"",
	)
}

#[test]
fn for_loop_same_number() {
	common::test_program(
		"for x = 10 to 10
    print x
next x
    ",
		"10\n",
	)
}

#[test]
fn for_loop_invalid_next() {
	let mut tio = common::TestIO::new("");
	{
		let mut xb = XBasic::new(&mut tio);
		assert!(xb
			.run(
				"for x = 0 to 10
    print x
next y
	"
			)
			.is_err());
		assert!(xb.error_handler.had_errors);
		assert_eq!(
			xb.error_handler.errors,
			["[line 3] Error at 'y': Incorrect variable after NEXT."]
		);
	}
	tio.check();
}

#[test]
fn for_loop_edge_case() {
	common::test_program(
		"x = 15
	for x = 0 to x

	    print x

	next x
	print \"x is\" x


	",
		"0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\nx is 16\n",
	)
}