use super::*; use crate::ast::*; use std::io::Write; use expect_test::{expect, Expect}; fn gen_test(file: &str, program: &str, expected: Expect) { let language = tree_sitter_python::language(); let mut parser = tree_sitter::Parser::new(); let _ = parser.set_language(&language); let tree = parser.parse(file, None).unwrap(); let program = ast::Program::new().with_file(program).unwrap(); let mut output = Vec::new(); let result; { let mut ctx = Context::new(language) .with_input(file.to_owned()) .with_tree(tree) .with_program(program) .with_output_stream(Box::new(&mut output) as Box); result = ctx.eval(); } if let Err(e) = result { writeln!(output, "{e:?}").unwrap(); } expected.assert_eq(&String::from_utf8(output).unwrap()) } #[test] fn bin() { let language = tree_sitter_python::language(); let mut ctx = Context::new(language).with_program(Program::new()); assert_eq!( ctx.eval_expr(&Expr::bin(Expr::int(5), "+", Expr::int(10),)), Ok(Value::Integer(15)) ); assert_eq!( ctx.eval_expr(&Expr::bin(Expr::int(5), "==", Expr::int(10),)), Ok(Value::Boolean(false)) ); assert_eq!( ctx.eval_expr(&Expr::bin(Expr::int(5), "<", Expr::int(10),)), Ok(Value::Boolean(true)) ); assert_eq!( ctx.eval_expr(&Expr::bin( Expr::bin(Expr::int(5), "<", Expr::int(10),), "&&", Expr::false_(), )), Ok(Value::Boolean(false)) ); } #[test] fn test_evaluate_blocks() { let language = tree_sitter_python::language(); let mut ctx = Context::new(language).with_program(Program::new()); assert_eq!( ctx.eval_block(&Block { body: vec![ Statement::Declaration(Declaration { ty: Type::Integer, name: "a".to_owned(), init: None, }), Statement::Bare(Expr::bin(Expr::ident("a"), "+=", Expr::int(5),)), ] }), Ok(Value::Unit) ); assert_eq!( ctx.lookup(&String::from("a")).unwrap().clone(), Variable { ty: Type::Integer, name: "a".to_owned(), value: Value::Integer(5) } ); } #[test] fn test_evaluate_if() { let language = tree_sitter_python::language(); let mut ctx = Context::new(language).with_program(Program::new()); assert_eq!( ctx.eval_block(&Block { body: vec![ Statement::Declaration(Declaration { ty: Type::Integer, name: "a".to_owned(), init: Some(Expr::int(1).boxed()), }), Statement::Bare(Expr::If(IfExpr { condition: Expr::true_().boxed(), then: Block { body: vec![Statement::Bare(Expr::bin( Expr::Ident("a".to_owned()), "+=", Expr::int(5), ))] }, else_: Block { body: vec![Statement::Bare(Expr::bin( Expr::ident("a"), "+=", Expr::int(10), ))] } })) ] }), Ok(Value::Unit) ); assert_eq!( ctx.lookup(&String::from("a")).unwrap().clone(), Variable { ty: Type::Integer, name: "a".to_owned(), value: Value::Integer(6) } ); } #[test] fn test_substring() { let language = tree_sitter_python::language(); let mut ctx = Context::new(language).with_program(Program::new()); assert_eq!( ctx.eval_block(&Block { body: vec![ Statement::Declaration(Declaration { ty: Type::String, name: "a".to_owned(), init: Some(Expr::str("foobar").boxed()), }), Statement::Declaration(Declaration { ty: Type::String, name: "b".to_owned(), init: Some( Expr::call( "substr", [Expr::Ident("a".to_owned()), Expr::int(0), Expr::int(3),] ) .boxed() ), }), ] }), Ok(Value::Unit) ); assert_eq!( ctx.lookup(&String::from("b")).unwrap().clone(), Variable { ty: Type::String, name: "b".to_owned(), value: "foo".into() } ); } #[test] fn test_list() { let language = tree_sitter_python::language(); let mut ctx = Context::new(language).with_program(Program::new()); assert_eq!( ctx.eval_block(&Block { body: vec![Statement::Declaration(Declaration { ty: Type::List, name: "a".to_owned(), init: Some( Expr::List(List { items: vec![Expr::int(5)] }) .boxed() ), }),] }), Ok(Value::Unit) ); assert_eq!( ctx.lookup(&String::from("a")).unwrap().clone(), Variable { ty: Type::List, name: "a".to_owned(), value: vec![5usize.into()].into(), } ); } #[test] fn list_1() { gen_test( "", "BEGIN { list a = [5]; print(a); } ", expect!["[5]"], ); } #[test] fn list_2() { gen_test( "", "BEGIN { list a = [5, 4, 3]; print(length(a)); } ", expect!["3"], ); } #[test] fn list_3() { gen_test( "", r#"BEGIN { list a = [5, 4, 3]; print(member(a, 3)); print(", "); print(member(a, 6)); } "#, expect!["true, false"], ); } #[test] fn list_4() { gen_test( "", r#"BEGIN { list a = [5]; println(a); push(a, 4); println(a); push(a, 3); println(a); pop(a); println(a); pop(a); println(a); } "#, expect![[r#" [5] [5, 4] [5, 4, 3] [5, 4] [5] "#]], ); } #[test] fn list_5() { gen_test( "", r#"BEGIN { list a = [5]; println(isempty(a)); pop(a); println(isempty(a)); } "#, expect![[r#" false true "#]], ); } #[test] fn string_1() { gen_test( "", r#"BEGIN { string a = "Foo"; println(toupper(a)); println(tolower(a)); } "#, expect![[r#" FOO foo "#]], ); } #[test] fn string_2() { gen_test( "", r#"BEGIN { string a = "foo"; println(a, " is upper? ", isupper(a)); println(a, " is lower? ", islower(a)); string b = "Foo"; println(b, " is upper? ", isupper(b)); println(b, " is lower? ", islower(b)); string c = "FOO"; println(c, " is upper? ", isupper(c)); println(c, " is lower? ", islower(c)); } "#, expect![[r#" foo is upper? false foo is lower? true Foo is upper? false Foo is lower? false FOO is upper? true FOO is lower? false "#]], ); } #[test] fn string_3() { gen_test( "", r#"BEGIN { string a = "foo bar baz"; println("a[3:5]: `", substr(a, 3, 5), "`"); println("a[2:9]: `", substr(a, 2, 9), "`"); } "#, expect![[r#" a[3:5]: ` b` a[2:9]: `o bar b` "#]], ); } #[test] fn string_4() { gen_test( "", r#"BEGIN { string a = "foo bar baz"; println("a[9:20]: `", substr(a, 9, 20), "`"); } "#, expect![[r#" a[9:20]: `InvalidStringSlice { length: 11, start: 9, end: 20 } "#]], ); } #[test] fn node_1() { gen_test( "def foo(a, b): hello()", r#"enter function_definition { println(text(node)); println(text(node.name)); }"#, expect![[r#" def foo(a, b): hello() foo "#]], ); }