#[cfg(test)]
mod tests {
use crate::parse;
fn verify_program(test_cases: &[(&str, &str)]) {
for (input, expected) in test_cases {
let ast = parse(input).unwrap();
let parsed = ast.to_string();
assert_eq!(&format!("{}", parsed), expected);
}
}
#[test]
fn parse_let_statement() {
let let_tests = [
("let x=5;", "let x = 5;"),
("let y=true;", "let y = true;"),
("let foo=y;", "let foo = y;"),
];
verify_program(&let_tests);
}
#[test]
fn parse_return_statement() {
let let_tests = [
("return 5", "return 5;"),
("return true;", "return true;"),
("return foobar;", "return foobar;"),
];
verify_program(&let_tests);
}
#[test]
fn test_parse_prefix_expression() {
let let_tests = [
("-15;", "(-15)"),
("!5;", "(!5)"),
("!foobar;", "(!foobar)"),
("-foobar;", "(-foobar)"),
("!true;", "(!true)"),
("!false;", "(!false)"),
];
verify_program(&let_tests);
}
#[test]
fn test_parse_infix_expression() {
let let_tests = [
("5 + 5;", "(5 + 5)"),
("5 - 5;", "(5 - 5)"),
("5 * 5;", "(5 * 5)"),
("5 / 5;", "(5 / 5)"),
("5 > 5;", "(5 > 5)"),
("5 < 5;", "(5 < 5)"),
("5 == 5;", "(5 == 5)"),
("5 != 5;", "(5 != 5)"),
("foobar + barfoo;", "(foobar + barfoo)"),
("foobar - barfoo;", "(foobar - barfoo)"),
("foobar * barfoo;", "(foobar * barfoo)"),
("foobar / barfoo;", "(foobar / barfoo)"),
("foobar > barfoo;", "(foobar > barfoo)"),
("foobar < barfoo;", "(foobar < barfoo)"),
("foobar == barfoo;", "(foobar == barfoo)"),
("foobar != barfoo;", "(foobar != barfoo)"),
("true == true", "(true == true)"),
("true != false", "(true != false)"),
("false == false", "(false == false)"),
];
verify_program(&let_tests);
}
#[test]
fn parse_op_expression() {
let tt = [
("-a * b", "((-a) * b)"),
("!-a", "(!(-a))"),
("a + b + c", "((a + b) + c)"),
("a + b - c", "((a + b) - c)"),
("a * b * c", "((a * b) * c)"),
("a * b / c", "((a * b) / c)"),
("a + b / c", "(a + (b / c))"),
("a + b * c + d / e - f", "(((a + (b * c)) + (d / e)) - f)"),
("3 + 4; -5 * 5", "(3 + 4)((-5) * 5)"),
("5 > 4 == 3 < 4", "((5 > 4) == (3 < 4))"),
("5 < 4 != 3 > 4", "((5 < 4) != (3 > 4))"),
("3 + 4 * 5 == 3 * 1 + 4 * 5", "((3 + (4 * 5)) == ((3 * 1) + (4 * 5)))"),
("true", "true"),
("false", "false"),
("3 > 5 == false", "((3 > 5) == false)"),
("3 < 5 == true", "((3 < 5) == true)"),
];
verify_program(&tt);
}
#[test]
fn parse_brace_expression() {
let tt = [
("1 + (2 + 3) + 4", "((1 + (2 + 3)) + 4)"),
("(5 + 5) * 2", "((5 + 5) * 2)"),
("2 / (5 + 5)", "(2 / (5 + 5))"),
("(5 + 5) * 2 * (5 + 5)", "(((5 + 5) * 2) * (5 + 5))"),
("-(5 + 5)", "(-(5 + 5))"),
("!(true == true)", "(!(true == true))"),
];
verify_program(&tt);
}
#[test]
fn test_if_expression() {
let tt = [("if (x < y) { x }", "if (x < y) { x }")];
verify_program(&tt);
}
#[test]
fn test_if_else_expression() {
let tt = [("if (x < y) { x } else { y }", "if (x < y) { x } else { y }")];
verify_program(&tt);
}
#[test]
fn test_fn_else_expression() {
let tt = [
("fn() {};", "fn () { }"),
("fn(x) {};", "fn (x) { }"),
("fn(x, y, z) { x };", "fn (x, y, z) { x }"),
];
verify_program(&tt);
}
#[test]
fn test_fn_call_else_expression() {
let tt = [("add(1, 2 * 3, 4 + 5);", "add(1, (2 * 3), (4 + 5))")];
verify_program(&tt);
}
#[test]
fn test_string_literal_expression() {
let test_case = [(r#""hello world";"#, r#""hello world""#)];
verify_program(&test_case);
}
#[test]
fn test_array_literal_expression() {
let test_case = [("[]", "[]"), ("[1, 2 * 2, 3 + 3]", "[1, (2 * 2), (3 + 3)]")];
verify_program(&test_case);
}
#[test]
fn test_index_expression() {
let test_case = [("a[1]", "(a[1])"), ("a[1 + 1]", "(a[(1 + 1)])")];
verify_program(&test_case);
}
#[test]
fn test_hash_literal_expression() {
let test_case = [
(r#"{"a": 1}"#, r#"{"a": 1}"#),
(r#"{"one": 1, "two": 2, "three": 3}"#, r#"{"one": 1, "two": 2, "three": 3}"#),
(r#"{}"#, r#"{}"#),
(
r#"{"one": 0 + 1, "two": 10 - 8, "three": 15 / 5}"#,
r#"{"one": (0 + 1), "two": (10 - 8), "three": (15 / 5)}"#,
),
];
verify_program(&test_case);
}
}