mod value_ext; use value_ext::*; extern crate haru; use haru::ast::grammar; use haru::compiler; use haru::hanayo; use haru::vmbindings::value::Value; use haru::vmbindings::vm::{Vm, VmOpcode}; use haru::vmbindings::vmerror::VmError; #[cfg(test)] pub mod hanayo_tests { use super::*; macro_rules! eval { ($x:expr) => {{ let prog = grammar::start($x).unwrap(); let mut c = compiler::Compiler::new(true); for stmt in prog { stmt.emit(&mut c); } c.cpushop(VmOpcode::OP_HALT); let mut vm = c.into_vm(); hanayo::init(&mut vm); vm.gc_enable(); vm.execute(); vm }}; } // #region vm extensions #[test] fn of_expr_simple() { let vm: Vm = eval!( " y = 1 of Int " ); assert_eq!(vm.global().get("y").unwrap().unwraps().int(), 1); } #[test] fn of_expr_record() { let vm: Vm = eval!( " record Y end record X prototype = Y end y = X of Y " ); assert_eq!(vm.global().get("y").unwrap().unwraps().int(), 1); } #[test] fn of_expr_parent() { let vm: Vm = eval!( " record Z end record Y prototype = Z end record X prototype = Y end y = X of Z " ); assert_eq!(vm.global().get("y").unwrap().unwraps().int(), 1); } #[test] fn of_expr_not_parent() { let vm: Vm = eval!( " record Z end record Y prototype = Z end record A end record X prototype = Y end y = X of A " ); assert_eq!(vm.global().get("y").unwrap().unwraps().int(), 0); } #[test] fn literal_prototype() { let vm: Vm = eval!( " y = (10).prototype == Int " ); assert_eq!(vm.global().get("y").unwrap().unwraps().int(), 1); } #[test] fn vm_call_native() { let vm: Vm = eval!( " [1,2,3].map(print) " ); assert_eq!(vm.stack.len(), 0); } // #endregion // #region int #[test] fn int_constructor() { let vm: Vm = eval!( " y = Int(1) " ); assert_eq!(vm.global().get("y").unwrap().unwraps().int(), 1); } #[test] fn int_constructor_float() { let vm: Vm = eval!( " y = Int(1.2) " ); assert_eq!(vm.global().get("y").unwrap().unwraps().int(), 1); } #[test] fn int_constructor_str() { let vm: Vm = eval!( " y = Int('10') " ); assert_eq!(vm.global().get("y").unwrap().unwraps().int(), 10); } #[test] fn int_constructor_str_invalid() { let vm: Vm = eval!( " try Int('1?') case InvalidArgumentError y = 1 end " ); assert_eq!(vm.global().get("y").unwrap().unwraps().int(), 1); } #[test] fn int_constructor_invalid() { let vm: Vm = eval!( " try Int([0]) case InvalidArgumentError y = 1 end " ); assert_eq!(vm.global().get("y").unwrap().unwraps().int(), 1); } #[test] fn int_chr() { let vm: Vm = eval!( " y = (97).chr() " ); assert_eq!(vm.global().get("y").unwrap().unwraps().string(), "a"); } #[test] fn int_hex() { let vm: Vm = eval!( " y = (16).hex() " ); assert_eq!(vm.global().get("y").unwrap().unwraps().string(), "0x10"); } // #end // #region float #[test] fn float_constructor() { let vm: Vm = eval!( " y = Float(1.0) " ); assert_eq!(vm.global().get("y").unwrap().unwraps().float(), 1.0); } #[test] fn float_constructor_int() { let vm: Vm = eval!( " y = Float(1) " ); assert_eq!(vm.global().get("y").unwrap().unwraps().float(), 1.0); } #[test] fn float_constructor_str() { let vm: Vm = eval!( " y = Float('10.55') " ); assert_eq!(vm.global().get("y").unwrap().unwraps().float(), 10.55); } #[test] fn float_constructor_str_invalid() { let vm: Vm = eval!( " try Float('1?') case InvalidArgumentError y = 1 end " ); assert_eq!(vm.global().get("y").unwrap().unwraps().int(), 1); } #[test] fn float_constructor_invalid() { let vm: Vm = eval!( " try Float([0]) case InvalidArgumentError y = 1 end " ); assert_eq!(vm.global().get("y").unwrap().unwraps().int(), 1); } // #end // #region array #[test] fn array_constructor_no_args() { let vm: Vm = eval!( " y = Array() " ); let arr = vm.global().get("y").unwrap().unwraps().array(); assert_eq!(arr.len(), 0); } #[test] fn array_constructor() { let vm: Vm = eval!( " y = Array(1,2,3) " ); let arr = vm.global().get("y").unwrap().unwraps().array(); assert_eq!(arr.len(), 3); assert_eq!(arr[0].unwraps(), Value::Int(1)); assert_eq!(arr[1].unwraps(), Value::Int(2)); assert_eq!(arr[2].unwraps(), Value::Int(3)); } #[test] fn array_length() { let vm: Vm = eval!( " y = [1,2,3].length() " ); assert_eq!(vm.global().get("y").unwrap().unwraps().int(), 3); } #[test] fn array_delete() { let vm: Vm = eval!( " y = [1,2,3] y.delete!(1,1) " ); let arr = vm.global().get("y").unwrap().unwraps().array(); assert_eq!(arr.len(), 2); assert_eq!(arr[0].unwraps(), Value::Int(1)); assert_eq!(arr[1].unwraps(), Value::Int(3)); } #[test] fn array_push() { let vm: Vm = eval!( " y = [] y.push(10) " ); let arr = vm.global().get("y").unwrap().unwraps().array(); assert_eq!(arr.len(), 1); assert_eq!(arr[0].unwraps(), Value::Int(10)); } #[test] fn array_pop() { let vm: Vm = eval!( " y = [1,2] y.pop() " ); let arr = vm.global().get("y").unwrap().unwraps().array(); assert_eq!(arr.len(), 1); assert_eq!(arr[0].unwraps(), Value::Int(1)); } #[test] fn array_index() { let vm: Vm = eval!( " a = ['a', 'b', 'c'] y = a.index('b') " ); assert_eq!(vm.global().get("y").unwrap().unwraps(), Value::Int(1)); } #[test] fn array_insert() { let vm: Vm = eval!( " y = [1,2,3] y.insert!(1, 4) " ); let arr = vm.global().get("y").unwrap().unwraps().array(); assert_eq!(arr.len(), 4); assert_eq!(arr[0].unwraps(), Value::Int(1)); assert_eq!(arr[1].unwraps(), Value::Int(4)); assert_eq!(arr[2].unwraps(), Value::Int(2)); assert_eq!(arr[3].unwraps(), Value::Int(3)); } #[test] fn array_sort_in_place() { let vm: Vm = eval!( " y = [6,3,1] y.sort!() " ); let arr = vm.global().get("y").unwrap().unwraps().array(); assert_eq!(arr.len(), 3); assert_eq!(arr[0].unwraps(), Value::Int(1)); assert_eq!(arr[1].unwraps(), Value::Int(3)); assert_eq!(arr[2].unwraps(), Value::Int(6)); } #[test] fn array_sort() { let vm: Vm = eval!( " x = [6,3,1] y = x.sort() " ); let arr = vm.global().get("y").unwrap().unwraps().array(); assert_eq!(arr.len(), 3); assert_eq!(arr[0].unwraps(), Value::Int(1)); assert_eq!(arr[1].unwraps(), Value::Int(3)); assert_eq!(arr[2].unwraps(), Value::Int(6)); } #[test] fn array_map() { let vm: Vm = eval!( " a=[3,5,64,2] y = a.map(f(x) = x+1) " ); let arr = vm.global().get("y").unwrap().unwraps().array(); assert_eq!(arr.len(), 4); assert_eq!(arr[0].unwraps(), Value::Int(4)); assert_eq!(arr[1].unwraps(), Value::Int(6)); assert_eq!(arr[2].unwraps(), Value::Int(65)); assert_eq!(arr[3].unwraps(), Value::Int(3)); } #[test] fn array_map_native() { let vm: Vm = eval!( " a=['1','2','3'] y = a.map(Int) " ); let arr = vm.global().get("y").unwrap().unwraps().array(); assert_eq!(arr.len(), 3); assert_eq!(arr[0].unwraps(), Value::Int(1)); assert_eq!(arr[1].unwraps(), Value::Int(2)); assert_eq!(arr[2].unwraps(), Value::Int(3)); } #[test] fn array_filter() { let vm: Vm = eval!( " a=[3,5,64,2] y = a.filter(f(x) = x>5) " ); let arr = vm.global().get("y").unwrap().unwraps().array(); assert_eq!(arr.len(), 1); assert_eq!(arr[0].unwraps(), Value::Int(64)); } #[test] fn array_reduce() { let vm: Vm = eval!( " a=[1,2,3,4,5] y = a.reduce(f(x, y) = x + y, 0) " ); assert_eq!(vm.global().get("y").unwrap().unwraps(), Value::Int(15)); } #[test] fn array_chained_functional() { let vm: Vm = eval!( " a=[1,2,3,5,6] y = a.map(_(x) = x+1).filter(_(x) = x>5).reduce(_(prev, curr) = prev+curr, 0) " ); assert_eq!(vm.global().get("y").unwrap().unwraps(), Value::Int(13)); } #[test] fn array_join() { let vm: Vm = eval!( " a=[1,2,3,4,5,6] y = a.join('') " ); assert_eq!(vm.global().get("y").unwrap().unwraps().string(), "123456"); } // #endregion // #region string #[test] fn string_constructor_no_args() { let vm: Vm = eval!( " y = String() " ); assert_eq!(vm.global().get("y").unwrap().unwraps().string(), ""); } #[test] fn string_constructor() { let vm: Vm = eval!( " y = String(10) " ); assert_eq!(vm.global().get("y").unwrap().unwraps().string(), "10"); } #[test] fn string_length() { let vm: Vm = eval!( " y = '日本'.length() " ); assert_eq!(vm.global().get("y").unwrap().unwraps().int(), 2); } #[test] fn string_bytesize() { let vm: Vm = eval!( " y = '日本'.bytesize() " ); assert_eq!(vm.global().get("y").unwrap().unwraps().int(), 6); } #[test] fn string_startswith() { let vm: Vm = eval!( " y = 'abc'.startswith?('a') " ); assert_eq!(vm.global().get("y").unwrap().unwraps().int(), 1); } #[test] fn string_endswith() { let vm: Vm = eval!( " y = 'abc'.endswith?('bc') " ); assert_eq!(vm.global().get("y").unwrap().unwraps().int(), 1); } #[test] fn string_delete() { let vm: Vm = eval!( " s = 'λκj' y = s.delete(1,1) " ); assert_eq!(vm.global().get("y").unwrap().unwraps().string(), "λj"); } #[test] fn string_delete_rest() { let vm: Vm = eval!( " s = 'λκj' y = s.delete(1,-1) " ); assert_eq!(vm.global().get("y").unwrap().unwraps().string(), "λ"); } #[test] fn string_delete_in_place() { let vm: Vm = eval!( " s = 'λκj' s.delete!(1,1) " ); assert_eq!(vm.global().get("s").unwrap().unwraps().string(), "λj"); } #[test] fn string_delete_in_place_rest() { let vm: Vm = eval!( " s = 'λκj' s.delete!(1,-1) " ); assert_eq!(vm.global().get("s").unwrap().unwraps().string(), "λ"); } #[test] fn string_copy() { let vm: Vm = eval!( " s = 'λκj' y = s.copy(1,2) " ); assert_eq!(vm.global().get("y").unwrap().unwraps().string(), "κj"); } #[test] fn string_copy_rest() { let vm: Vm = eval!( " s = 'λκj' y = s.copy(1,-1) " ); assert_eq!(vm.global().get("y").unwrap().unwraps().string(), "κj"); } #[test] fn string_index() { let vm: Vm = eval!( " s = 'λκj' y = s.index('κ') " ); assert_eq!(vm.global().get("y").unwrap().unwraps(), Value::Int(1)); } #[test] fn string_insert() { let vm: Vm = eval!( " s = 'λκj' s.insert!(1,'a') " ); assert_eq!(vm.global().get("s").unwrap().unwraps().string(), "λaκj"); } #[test] fn string_split() { let vm: Vm = eval!( " s = 'a b c' y = s.split(' ') " ); let arr = vm.global().get("y").unwrap().unwraps().array(); assert_eq!(arr.len(), 3); assert_eq!(arr[0].unwraps().string(), "a"); assert_eq!(arr[1].unwraps().string(), "b"); assert_eq!(arr[2].unwraps().string(), "c"); } #[test] fn string_chars() { let vm: Vm = eval!( " s = 'λκj' y = s.chars() " ); let arr = vm.global().get("y").unwrap().unwraps().array(); assert_eq!(arr.len(), 3); assert_eq!(arr[0].unwraps().string(), "λ"); assert_eq!(arr[1].unwraps().string(), "κ"); assert_eq!(arr[2].unwraps().string(), "j"); } #[test] fn string_ord() { let vm: Vm = eval!( " s = 'a' y = s.ord() " ); assert_eq!(vm.global().get("y").unwrap().unwraps().int(), 97); } // #endregion // #region record #[test] fn record_new() { let vm: Vm = eval!( " y = Record() " ); vm.global().get("y").unwrap().unwraps().record(); } #[test] fn record_keys() { let vm: Vm = eval!( " record x a = 10 b = 10 end y = Record::keys(x) " ); let arr = vm.global().get("y").unwrap().unwraps().array(); assert_eq!(arr.len(), 2); } #[test] fn record_has_key() { let vm: Vm = eval!( " record x a = 10 b = 10 end y = Record::has_key(x, 'a') " ); assert_eq!(vm.global().get("y").unwrap().unwraps().int(), 1); } // #endregion // #region env #[test] fn env_get() { std::env::set_var("test_key", "value"); let vm: Vm = eval!( " y = Env::get('test_key') " ); assert_eq!(vm.global().get("y").unwrap().unwraps().string(), "value"); } #[test] fn env_set() { eval!( " Env::set('test_key_set', 'value') " ); assert_eq!(std::env::var("test_key_set").unwrap(), "value"); } #[test] fn env_vars() { std::env::set_var("a_key", "value"); let vm: Vm = eval!( " y = Env::vars()['a_key'] " ); assert_eq!(vm.global().get("y").unwrap().unwraps().string(), "value"); } // #endregion // #region files #[test] fn file_read() { std::fs::write("/tmp/file_read", "test"); let vm: Vm = eval!( " f = File('/tmp/file_read', 'r') y = f.read() f.close() " ); assert_eq!(vm.global().get("y").unwrap().unwraps().string(), "test"); } #[test] fn file_read_up_to() { std::fs::write("/tmp/file_read_up_to", "test"); let vm: Vm = eval!( " f = File('/tmp/file_read_up_to', 'r') y = f.read_up_to(2) " ); assert_eq!(vm.global().get("y").unwrap().unwraps().string(), "te"); } #[test] fn file_write() { eval!( " f = File('/tmp/file_write', 'wc') f.write('Hello World') f.close() " ); assert_eq!( std::str::from_utf8(&std::fs::read("/tmp/file_write").unwrap()).unwrap(), "Hello World" ); } // #endregion // #region cmd #[test] fn cmd_constructor_array() { let vm: Vm = eval!( " y = Cmd(['echo', 'hello world']).out() " ); assert_eq!( vm.global().get("y").unwrap().unwraps().string(), "hello world\n" ); } #[test] fn cmd_constructor_array_invalid() { let vm: Vm = eval!( " try Cmd([1]).out() case InvalidArgumentError y = 1 end " ); assert_eq!(vm.global().get("y").unwrap().unwraps().int(), 1); } #[test] fn cmd_constructor_string() { let vm: Vm = eval!( " y = Cmd('echo hello world').out() " ); assert_eq!( vm.global().get("y").unwrap().unwraps().string(), "hello world\n" ); } #[test] fn cmd_constructor_string_invalid() { let vm: Vm = eval!( " try Cmd(1).out() case InvalidArgumentError y = 1 end " ); assert_eq!(vm.global().get("y").unwrap().unwraps().int(), 1); } #[test] fn cmd_err() { let vm: Vm = eval!( " y = Cmd('echo hello world >&2').err() " ); assert_eq!( vm.global().get("y").unwrap().unwraps().string(), "hello world\n" ); } #[test] fn cmd_in() { let vm: Vm = eval!( " y = Cmd('cat -').in('nyaaa').out() " ); assert_eq!(vm.global().get("y").unwrap().unwraps().string(), "nyaaa"); } #[test] fn cmd_outputs() { let vm: Vm = eval!( " y = Cmd('echo hello world').outputs() " ); let arr = vm.global().get("y").unwrap().unwraps().array(); assert_eq!(arr.len(), 2); assert_eq!(arr[0].unwraps().string(), "hello world\n"); assert_eq!(arr[1].unwraps().string(), ""); } // #endregion // #region proc #[test] fn proc_err() { let vm: Vm = eval!( " y = Cmd('echo hello world >&2').spawn().err() " ); assert_eq!( vm.global().get("y").unwrap().unwraps().string(), "hello world\n" ); } #[test] fn proc_in() { let vm: Vm = eval!( " y = Cmd('cat -').spawn().in('nyaaa').out() " ); assert_eq!(vm.global().get("y").unwrap().unwraps().string(), "nyaaa"); } #[test] fn proc_outputs() { let vm: Vm = eval!( " y = Cmd('echo hello world').spawn().outputs() " ); let arr = vm.global().get("y").unwrap().unwraps().array(); assert_eq!(arr.len(), 2); assert_eq!(arr[0].unwraps().string(), "hello world\n"); assert_eq!(arr[1].unwraps().string(), ""); } #[test] fn proc_sleep() { let _vm: Vm = eval!( " y = Cmd('sleep 1s').spawn().wait() " ); } #[test] fn proc_kill() { let _vm: Vm = eval!( " y = Cmd('sleep 1s').spawn().kill() " ); } // #endregion // #region math #[test] fn math_sqrt() { let vm: Vm = eval!( " y = sqrt(4.0) " ); assert_eq!(vm.global().get("y").unwrap().unwraps(), Value::Float(2.0)); } // #endregion // #region other #[test] fn eval() { let vm: Vm = eval!( " eval('y = 10') " ); assert_eq!(vm.global().get("y").unwrap().unwraps(), Value::Int(10)); } #[test] fn eval_interned() { let vm: Vm = eval!( r#" eval('y = "a"') "# ); assert_eq!(vm.global().get("y").unwrap().unwraps().string(), "a"); } // #endregion }