diff --git a/lykiadb-server/src/engine/interpreter.rs b/lykiadb-server/src/engine/interpreter.rs index 6191a6e..724e75c 100644 --- a/lykiadb-server/src/engine/interpreter.rs +++ b/lykiadb-server/src/engine/interpreter.rs @@ -689,7 +689,7 @@ impl Output { } assert_eq!(self.out, rv) } - + // TODO(vck): Remove this pub fn expect_str(&mut self, rv: Vec) { assert_eq!(self.out.iter().map(|x| x.to_string()).collect::>(), rv) } @@ -726,12 +726,6 @@ pub mod test_helpers { out.write().unwrap().expect(output); } - pub fn assert_out_str(code: &str, output: Vec) { - let (out, mut runtime) = get_runtime(); - runtime.interpret(code).unwrap(); - out.write().unwrap().expect_str(output); - } - pub fn assert_err(code: &str, error: &str) { let (_, mut runtime) = get_runtime(); let result = runtime.interpret(code); diff --git a/lykiadb-server/tests/interpreter/functions/anonymous b/lykiadb-server/tests/interpreter/functions/anonymous new file mode 100644 index 0000000..e524850 --- /dev/null +++ b/lykiadb-server/tests/interpreter/functions/anonymous @@ -0,0 +1,51 @@ +#[name=anonymous_fn_0, run=interpreter]> + +var $pr = function a() { + test_utils::out("hello"); +}; + +$pr(); +a(); + +--- + +hello +hello + + +#[name=anonymous_fn_1_iife, run=interpreter]> + +(function a() { + test_utils::out("hello"); +})(); + +a(); + +--- + +hello +hello + + +#[name=anonymous_fn_2, run=interpreter]> + +var $pr = function() { + test_utils::out("hello"); +}; + +$pr(); + +--- + +hello + + +#[name=anonymous_fn_3_iife, run=interpreter]> + +(function() { + test_utils::out("hello"); +})(); + +--- + +hello \ No newline at end of file diff --git a/lykiadb-server/tests/interpreter/functions/hof b/lykiadb-server/tests/interpreter/functions/hof new file mode 100644 index 0000000..e1ef6f9 --- /dev/null +++ b/lykiadb-server/tests/interpreter/functions/hof @@ -0,0 +1,47 @@ +#[name=higher_order_0, run=interpreter]> + +function f($x, $q) { + $x($q); +}; + +function g($q) { + test_utils::out($q); +}; + +for (var $i = 0; $i < 10; $i = $i + 1) { + f(g, $i); +} + +--- + +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 + + +#[name=higher_order_1, run=interpreter]> + +function makeCounter() { + var $i = 0; + function count() { + $i = $i + 1; + test_utils::out($i); + }; + + return count; +}; +var $count = makeCounter(); +$count(); +$count(); + +--- + +1 +2 diff --git a/lykiadb-server/tests/interpreter/functions/resolving_read b/lykiadb-server/tests/interpreter/functions/resolving_read new file mode 100644 index 0000000..4e41c02 --- /dev/null +++ b/lykiadb-server/tests/interpreter/functions/resolving_read @@ -0,0 +1,140 @@ +#[name=resolving_read_0, run=interpreter]> + +var $a = "global"; +{ + function showA() { + test_utils::out($a); + }; + + showA(); + var $a = "block"; + showA(); +} + +--- + +global +global + + +#[name=resolving_read_1, run=interpreter]> + +var $a = "global"; +{ + function showA() { + test_utils::out($a); + }; + + showA(); + var $a = "block"; + showA(); + + function showB() { + test_utils::out($a); + }; + + showB(); +} + +--- + +global +global +block + +#[name=resolving_read_2, run=interpreter]> + +{ + var $a = "global"; + { + function showA() { + test_utils::out($a); + }; + + showA(); + var $a = "block"; + showA(); + } +} + +--- + +global +global + + +#[name=resolve_object, run=interpreter]> + +var $text = 'outer $text'; + +var $a = { + myFun: function() { + function pre_define() { + test_utils::out($text); + }; + pre_define(); + + var $text = 'inner $text'; + + function post_define() { + test_utils::out($text); + }; + post_define(); + } +}; + +$a.myFun(); + +--- + +outer $text +inner $text + + +#[name=resolve_deeper_object, run=interpreter]> + +var $text = 'outer $text'; + +var $a = { + b: { + c0: { + myFun: function() { + function pre_define() { + test_utils::out($text); + }; + pre_define(); + + var $text = 'c0 inner $text'; + + function post_define() { + test_utils::out($text); + }; + post_define(); + } + }, + c1: { + myFun: function() { + function pre_define() { + test_utils::out($text); + }; + pre_define(); + + var $text = 'c1 inner $text'; + + function post_define() { + test_utils::out($text); + }; + post_define(); + } + } + } +}; +$a.b.c0.myFun(); +$a.b.c1.myFun(); + +--- + +outer $text +c0 inner $text +outer $text +c1 inner $text \ No newline at end of file diff --git a/lykiadb-server/tests/interpreter/functions/resolving_write b/lykiadb-server/tests/interpreter/functions/resolving_write new file mode 100644 index 0000000..0a3185c --- /dev/null +++ b/lykiadb-server/tests/interpreter/functions/resolving_write @@ -0,0 +1,61 @@ +#[name=resolving_write_0, run=interpreter]> + +var $a = "global"; +{ + function showA() { + test_utils::out($a); + }; + + var $a = "block"; + + function showB() { + test_utils::out($a); + }; + + + showA(); + showB(); + + $a = "test"; + + showA(); + showB(); +} + +--- + +global +block +global +test + + +#[name=resolving_write_1, run=interpreter]> + +var $a = "global"; +{ + var $showA = function() { + test_utils::out($a); + }; + + var $a = "block"; + + var $showB = function() { + test_utils::out($a); + }; + + $showA(); + $showB(); + + $a = "test"; + + $showA(); + $showB(); +} + +--- + +global +block +global +test diff --git a/lykiadb-server/tests/interpreter/programs b/lykiadb-server/tests/interpreter/programs new file mode 100644 index 0000000..ac62526 --- /dev/null +++ b/lykiadb-server/tests/interpreter/programs @@ -0,0 +1,31 @@ +#[name=multiple_programs, run=interpreter]> + +function resolvedFirst() { + var $a = "global"; + { + function showA() { + test_utils::out($a); + }; + + showA(); + var $a = "block"; + showA(); + } +}; +resolvedFirst(); + +--- + +global +global + +--- + +resolvedFirst(); + +--- + +global +global +global +global \ No newline at end of file diff --git a/lykiadb-server/tests/runtime/functions.rs b/lykiadb-server/tests/runtime/functions.rs deleted file mode 100644 index 9419fc7..0000000 --- a/lykiadb-server/tests/runtime/functions.rs +++ /dev/null @@ -1,360 +0,0 @@ -use lykiadb_server::{ - engine::interpreter::test_helpers::{assert_out, get_runtime}, - value::RV, -}; -use std::sync::Arc; - -#[test] -fn test_higher_order_0() { - assert_out( - "function f($x, $q) { - $x($q); - }; - - function g($q) { - test_utils::out($q); - }; - - for (var $i=0; $i<10; $i = $i + 1) { - f(g, $i); - }", - vec![ - RV::Num(0.0), - RV::Num(1.0), - RV::Num(2.0), - RV::Num(3.0), - RV::Num(4.0), - RV::Num(5.0), - RV::Num(6.0), - RV::Num(7.0), - RV::Num(8.0), - RV::Num(9.0), - ], - ); -} - -#[test] -fn test_high_order_1() { - assert_out( - "function makeCounter() { - var $i = 0; - function count() { - $i = $i + 1; - test_utils::out($i); - }; - - return count; - }; - var $count = makeCounter(); - $count(); - $count();", - vec![RV::Num(1.0), RV::Num(2.0)], - ); -} - -#[test] -fn test_resolving_read_0() { - assert_out( - "var $a = \"global\"; - { - function showA() { - test_utils::out($a); - }; - - showA(); - var $a = \"block\"; - showA(); - }", - vec![ - RV::Str(Arc::new("global".to_string())), - RV::Str(Arc::new("global".to_string())), - ], - ); -} - -#[test] -fn test_resolving_read_1() { - assert_out( - "var $a = \"global\"; - { - function showA() { - test_utils::out($a); - }; - - showA(); - var $a = \"block\"; - showA(); - function showB() { - test_utils::out($a); - }; - showB(); - }", - vec![ - RV::Str(Arc::new("global".to_string())), - RV::Str(Arc::new("global".to_string())), - RV::Str(Arc::new("block".to_string())), - ], - ); -} - -#[test] -fn test_resolving_read_2() { - assert_out( - "{ - var $a = \"global\"; - { - function showA() { - test_utils::out($a); - }; - - showA(); - var $a = \"block\"; - showA(); - } - }", - vec![ - RV::Str(Arc::new("global".to_string())), - RV::Str(Arc::new("global".to_string())), - ], - ); -} - -#[test] -fn test_resolving_write_0() { - assert_out( - "var $a = \"global\"; - { - function showA() { - test_utils::out($a); - }; - - var $a = \"block\"; - - function showB() { - test_utils::out($a); - }; - - // - showA(); - showB(); - // - $a = \"test\"; - // - showA(); - showB(); - }", - vec![ - RV::Str(Arc::new("global".to_string())), - RV::Str(Arc::new("block".to_string())), - RV::Str(Arc::new("global".to_string())), - RV::Str(Arc::new("test".to_string())), - ], - ); -} - -#[test] -fn test_anonymous_fn_0() { - assert_out( - "var $pr = function a() { - test_utils::out(\"hello\"); - }; - - $pr(); - a(); - ", - vec![ - RV::Str(Arc::new("hello".to_string())), - RV::Str(Arc::new("hello".to_string())), - ], - ); -} - -#[test] -fn test_anonymous_fn_1() { - assert_out( - "(function a() { - test_utils::out(\"hello\"); - })(); - - a(); - ", - vec![ - RV::Str(Arc::new("hello".to_string())), - RV::Str(Arc::new("hello".to_string())), - ], - ); -} - -#[test] -fn test_anonymous_fn_2() { - assert_out( - "var $pr = function() { - test_utils::out(\"hello\"); - }; - - $pr(); - ", - vec![RV::Str(Arc::new("hello".to_string()))], - ); -} - -#[test] -fn test_anonymous_fn_3() { - assert_out( - "(function() { - test_utils::out(\"hello\"); - })(); - ", - vec![RV::Str(Arc::new("hello".to_string()))], - ); -} - -#[test] -fn test_resolving_write_1() { - assert_out( - "var $a = \"global\"; - { - var $showA = function() { - test_utils::out($a); - }; - - var $a = \"block\"; - - var $showB = function() { - test_utils::out($a); - }; - - // - $showA(); - $showB(); - // - $a = \"test\"; - // - $showA(); - $showB(); - }", - vec![ - RV::Str(Arc::new("global".to_string())), - RV::Str(Arc::new("block".to_string())), - RV::Str(Arc::new("global".to_string())), - RV::Str(Arc::new("test".to_string())), - ], - ); -} - -#[test] -fn test_resolve_object() { - assert_out( - " - - var $text = 'outer $text'; - - var $a = { - myFun: function() { - function pre_define() { - test_utils::out($text); - }; - pre_define(); - // - var $text = 'inner $text'; - // - function post_define() { - test_utils::out($text); - }; - post_define(); - } - }; - $a.myFun(); - ", - vec![ - RV::Str(Arc::new("outer $text".to_string())), - RV::Str(Arc::new("inner $text".to_string())), - ], - ); -} - -#[test] -fn test_resolve_deeper_object() { - assert_out( - " - var $text = 'outer $text'; - - var $a = { - b: { - c0: { - myFun: function() { - function pre_define() { - test_utils::out($text); - }; - pre_define(); - // - var $text = 'c0 inner $text'; - // - function post_define() { - test_utils::out($text); - }; - post_define(); - } - }, - c1: { - myFun: function() { - function pre_define() { - test_utils::out($text); - }; - pre_define(); - // - var $text = 'c1 inner $text'; - // - function post_define() { - test_utils::out($text); - }; - post_define(); - } - } - } - }; - $a.b.c0.myFun(); - $a.b.c1.myFun(); - ", - vec![ - RV::Str(Arc::new("outer $text".to_string())), - RV::Str(Arc::new("c0 inner $text".to_string())), - RV::Str(Arc::new("outer $text".to_string())), - RV::Str(Arc::new("c1 inner $text".to_string())), - ], - ); -} - -#[test] -fn test_resolve_multiple_programs() { - let (out, mut runtime) = get_runtime(); - - let prog_0 = " - function resolvedFirst() { - var $a = \"global\"; - { - function showA() { - test_utils::out($a); - }; - - showA(); - var $a = \"block\"; - showA(); - } - }; - resolvedFirst(); - "; - runtime.interpret(prog_0).unwrap(); - out.write().unwrap().expect(vec![ - RV::Str(Arc::new("global".to_string())), - RV::Str(Arc::new("global".to_string())), - ]); - runtime.interpret("resolvedFirst();").unwrap(); - - out.write().unwrap().expect(vec![ - RV::Str(Arc::new("global".to_string())), - RV::Str(Arc::new("global".to_string())), - RV::Str(Arc::new("global".to_string())), - RV::Str(Arc::new("global".to_string())), - ]); -} diff --git a/lykiadb-server/tests/runtime/mod.rs b/lykiadb-server/tests/runtime/mod.rs index e298122..25a94de 100644 --- a/lykiadb-server/tests/runtime/mod.rs +++ b/lykiadb-server/tests/runtime/mod.rs @@ -1,2 +1 @@ mod blocks; -mod functions; diff --git a/lykiadb-server/tests/util.rs b/lykiadb-server/tests/util.rs index ae8e12a..9d27d8f 100644 --- a/lykiadb-server/tests/util.rs +++ b/lykiadb-server/tests/util.rs @@ -1,22 +1,29 @@ use lykiadb_server::{ - engine::interpreter::test_helpers::{assert_err, assert_out, assert_out_str}, + engine::interpreter::test_helpers::{assert_err, assert_out, get_runtime}, value::RV, }; use std::{collections::HashMap, sync::Arc}; -fn run_plan(input: &str, output: &str, flags: HashMap<&str, &str>) { - if flags.get("expect") == Some(&"error") { - assert_err(input, output); - } else { - assert_out(input, vec![RV::Str(Arc::new(output.to_string()))]); +fn run_plan(io_parts: Vec, flags: HashMap<&str, &str>) { + for chunk in io_parts.chunks(2) { + if flags.get("expect") == Some(&"error") { + assert_err(&chunk[0], &chunk[1]); + } else { + assert_out(&chunk[0], vec![RV::Str(Arc::new(chunk[1].to_string()))]); + } } } -fn run_interpreter(input: &str, output: &str, flags: HashMap<&str, &str>) { - if flags.get("expect") == Some(&"error") { - assert_err(input, output); - } else { - assert_out_str(input, output.to_string().split("\n").map(|x| x.to_string()).collect()); +fn run_interpreter(io_parts: Vec, flags: HashMap<&str, &str>) { + let (out, mut runtime) = get_runtime(); + + for chunk in io_parts.chunks(2) { + if flags.get("expect") == Some(&"error") { + assert_err(&chunk[0], &chunk[1]); + } else { + runtime.interpret(&chunk[0]).unwrap(); + out.write().unwrap().expect_str(chunk[1].to_string().split("\n").map(|x| x.to_string()).collect()); + } } } @@ -46,14 +53,14 @@ pub fn run_test(input: &str) { acc }); - let io_parts: Vec<&str> = rest.split("---").collect(); + let io_parts = rest.split("---").map(|x| x.trim().to_string()).collect(); match flags.get("run") { Some(&"plan") => { - run_plan(io_parts[0].trim(), io_parts[1].trim(), flags.clone()); + run_plan(io_parts, flags.clone()); } Some(&"interpreter") => { - run_interpreter(io_parts[0].trim(), io_parts[1].trim(), flags.clone()); + run_interpreter(io_parts, flags.clone()); } _ => panic!("Unknown directive"), }