From 54f46271952a609444dab8718ff4770e8c76c16f Mon Sep 17 00:00:00 2001 From: Alex Orlenko Date: Sat, 28 Sep 2019 15:23:17 +0100 Subject: [PATCH] Update tests (excl. compile-fail) --- tests/_lua.rs | 53 +++ tests/byte_string.rs | 98 +++++ tests/compile-fail.rs | 11 +- tests/function.rs | 62 ++-- tests/memory.rs | 56 +++ tests/scope.rs | 207 +++++------ tests/string.rs | 59 ++- tests/table.rs | 192 +++++----- tests/tests.rs | 832 +++++++++++++++++++++--------------------- tests/thread.rs | 112 +++--- tests/types.rs | 34 +- tests/userdata.rs | 214 ++++++----- 12 files changed, 1086 insertions(+), 844 deletions(-) create mode 100644 tests/_lua.rs create mode 100644 tests/byte_string.rs create mode 100644 tests/memory.rs diff --git a/tests/_lua.rs b/tests/_lua.rs new file mode 100644 index 0000000..1b57834 --- /dev/null +++ b/tests/_lua.rs @@ -0,0 +1,53 @@ +#[allow(non_camel_case_types)] +type lua_State = libc::c_void; + +#[allow(non_camel_case_types)] +type lua_CFunction = unsafe extern "C" fn(L: *mut lua_State) -> libc::c_int; + +extern "C" { + fn luaL_newstate() -> *mut lua_State; + + fn luaL_requiref( + L: *mut lua_State, + modname: *const libc::c_char, + openf: lua_CFunction, + glb: libc::c_int, + ); + + fn lua_settop(L: *mut lua_State, idx: libc::c_int); + + fn luaopen_base(L: *mut lua_State) -> libc::c_int; + fn luaopen_coroutine(L: *mut lua_State) -> libc::c_int; + fn luaopen_table(L: *mut lua_State) -> libc::c_int; + fn luaopen_io(L: *mut lua_State) -> libc::c_int; + fn luaopen_os(L: *mut lua_State) -> libc::c_int; + fn luaopen_string(L: *mut lua_State) -> libc::c_int; + fn luaopen_math(L: *mut lua_State) -> libc::c_int; + fn luaopen_package(L: *mut lua_State) -> libc::c_int; +} + +#[allow(unused)] +fn make_lua() -> rlua::Lua { + macro_rules! cstr { + ($s:expr) => { + concat!($s, "\0") as *const str as *const ::std::os::raw::c_char + }; + } + + unsafe { + let state = luaL_newstate(); + + // Do not open the debug library, it can be used to cause unsafety. + luaL_requiref(state, cstr!("_G"), luaopen_base, 1); + luaL_requiref(state, cstr!("coroutine"), luaopen_coroutine, 1); + luaL_requiref(state, cstr!("table"), luaopen_table, 1); + luaL_requiref(state, cstr!("io"), luaopen_io, 1); + luaL_requiref(state, cstr!("os"), luaopen_os, 1); + luaL_requiref(state, cstr!("string"), luaopen_string, 1); + luaL_requiref(state, cstr!("math"), luaopen_math, 1); + luaL_requiref(state, cstr!("package"), luaopen_package, 1); + lua_settop(state, -8 - 1); + + rlua::Lua::init_from_ptr(state) + } +} diff --git a/tests/byte_string.rs b/tests/byte_string.rs new file mode 100644 index 0000000..e3c442d --- /dev/null +++ b/tests/byte_string.rs @@ -0,0 +1,98 @@ +use bstr::{BStr, BString}; +use rlua::Result; + +include!("_lua.rs"); + +#[test] +fn byte_string_round_trip() -> Result<()> { + let lua = make_lua(); + + lua.load( + r#" + invalid_sequence_identifier = "\xa0\xa1" + invalid_2_octet_sequence_2nd = "\xc3\x28" + invalid_3_octet_sequence_2nd = "\xe2\x28\xa1" + invalid_3_octet_sequence_3rd = "\xe2\x82\x28" + invalid_4_octet_sequence_2nd = "\xf0\x28\x8c\xbc" + invalid_4_octet_sequence_3rd = "\xf0\x90\x28\xbc" + invalid_4_octet_sequence_4th = "\xf0\x28\x8c\x28" + + an_actual_string = "Hello, world!" + "#, + ) + .exec()?; + + let globals = lua.globals(); + + let isi = globals.get::<_, BString>("invalid_sequence_identifier")?; + assert_eq!(isi, [0xa0, 0xa1].as_ref()); + + let i2os2 = globals.get::<_, BString>("invalid_2_octet_sequence_2nd")?; + assert_eq!(i2os2, [0xc3, 0x28].as_ref()); + + let i3os2 = globals.get::<_, BString>("invalid_3_octet_sequence_2nd")?; + assert_eq!(i3os2, [0xe2, 0x28, 0xa1].as_ref()); + + let i3os3 = globals.get::<_, BString>("invalid_3_octet_sequence_3rd")?; + assert_eq!(i3os3, [0xe2, 0x82, 0x28].as_ref()); + + let i4os2 = globals.get::<_, BString>("invalid_4_octet_sequence_2nd")?; + assert_eq!(i4os2, [0xf0, 0x28, 0x8c, 0xbc].as_ref()); + + let i4os3 = globals.get::<_, BString>("invalid_4_octet_sequence_3rd")?; + assert_eq!(i4os3, [0xf0, 0x90, 0x28, 0xbc].as_ref()); + + let i4os4 = globals.get::<_, BString>("invalid_4_octet_sequence_4th")?; + assert_eq!(i4os4, [0xf0, 0x28, 0x8c, 0x28].as_ref()); + + let aas = globals.get::<_, BString>("an_actual_string")?; + assert_eq!(aas, b"Hello, world!".as_ref()); + + globals.set::<_, &BStr>("bstr_invalid_sequence_identifier", isi.as_ref())?; + globals.set::<_, &BStr>("bstr_invalid_2_octet_sequence_2nd", i2os2.as_ref())?; + globals.set::<_, &BStr>("bstr_invalid_3_octet_sequence_2nd", i3os2.as_ref())?; + globals.set::<_, &BStr>("bstr_invalid_3_octet_sequence_3rd", i3os3.as_ref())?; + globals.set::<_, &BStr>("bstr_invalid_4_octet_sequence_2nd", i4os2.as_ref())?; + globals.set::<_, &BStr>("bstr_invalid_4_octet_sequence_3rd", i4os3.as_ref())?; + globals.set::<_, &BStr>("bstr_invalid_4_octet_sequence_4th", i4os4.as_ref())?; + globals.set::<_, &BStr>("bstr_an_actual_string", aas.as_ref())?; + + lua.load( + r#" + assert(bstr_invalid_sequence_identifier == invalid_sequence_identifier) + assert(bstr_invalid_2_octet_sequence_2nd == invalid_2_octet_sequence_2nd) + assert(bstr_invalid_3_octet_sequence_2nd == invalid_3_octet_sequence_2nd) + assert(bstr_invalid_3_octet_sequence_3rd == invalid_3_octet_sequence_3rd) + assert(bstr_invalid_4_octet_sequence_2nd == invalid_4_octet_sequence_2nd) + assert(bstr_invalid_4_octet_sequence_3rd == invalid_4_octet_sequence_3rd) + assert(bstr_invalid_4_octet_sequence_4th == invalid_4_octet_sequence_4th) + assert(bstr_an_actual_string == an_actual_string) + "#, + ) + .exec()?; + + globals.set::<_, BString>("bstring_invalid_sequence_identifier", isi)?; + globals.set::<_, BString>("bstring_invalid_2_octet_sequence_2nd", i2os2)?; + globals.set::<_, BString>("bstring_invalid_3_octet_sequence_2nd", i3os2)?; + globals.set::<_, BString>("bstring_invalid_3_octet_sequence_3rd", i3os3)?; + globals.set::<_, BString>("bstring_invalid_4_octet_sequence_2nd", i4os2)?; + globals.set::<_, BString>("bstring_invalid_4_octet_sequence_3rd", i4os3)?; + globals.set::<_, BString>("bstring_invalid_4_octet_sequence_4th", i4os4)?; + globals.set::<_, BString>("bstring_an_actual_string", aas)?; + + lua.load( + r#" + assert(bstring_invalid_sequence_identifier == invalid_sequence_identifier) + assert(bstring_invalid_2_octet_sequence_2nd == invalid_2_octet_sequence_2nd) + assert(bstring_invalid_3_octet_sequence_2nd == invalid_3_octet_sequence_2nd) + assert(bstring_invalid_3_octet_sequence_3rd == invalid_3_octet_sequence_3rd) + assert(bstring_invalid_4_octet_sequence_2nd == invalid_4_octet_sequence_2nd) + assert(bstring_invalid_4_octet_sequence_3rd == invalid_4_octet_sequence_3rd) + assert(bstring_invalid_4_octet_sequence_4th == invalid_4_octet_sequence_4th) + assert(bstring_an_actual_string == an_actual_string) + "#, + ) + .exec()?; + + Ok(()) +} diff --git a/tests/compile-fail.rs b/tests/compile-fail.rs index 66a5e41..4acc159 100644 --- a/tests/compile-fail.rs +++ b/tests/compile-fail.rs @@ -1,17 +1,14 @@ -#![cfg(feature = "compiletest_rs")] - -extern crate compiletest_rs as compiletest; - use std::path::PathBuf; fn run_mode(mode: &'static str) { - let mut config = compiletest::Config::default(); + let mut config = compiletest_rs::Config::default(); config.mode = mode.parse().expect("Invalid mode"); config.src_base = PathBuf::from(format!("tests/{}", mode)); - config.target_rustcflags = Some("-L target/debug -L target/debug/deps".to_string()); + config.link_deps(); + config.clean_rmeta(); - compiletest::run_tests(&config); + compiletest_rs::run_tests(&config); } #[test] diff --git a/tests/function.rs b/tests/function.rs index 01e0cf9..0abcf57 100644 --- a/tests/function.rs +++ b/tests/function.rs @@ -1,30 +1,33 @@ -extern crate rlua; +use rlua::{Function, Result, String}; -use rlua::{Function, Lua, String}; +include!("_lua.rs"); #[test] -fn test_function() { - let lua = Lua::new(); +fn test_function() -> Result<()> { + let lua = make_lua(); + let globals = lua.globals(); - lua.exec::<_, ()>( + lua.load( r#" function concat(arg1, arg2) return arg1 .. arg2 end "#, - None, ) - .unwrap(); + .exec()?; - let concat = globals.get::<_, Function>("concat").unwrap(); - assert_eq!(concat.call::<_, String>(("foo", "bar")).unwrap(), "foobar"); + let concat = globals.get::<_, Function>("concat")?; + assert_eq!(concat.call::<_, String>(("foo", "bar"))?, "foobar"); + + Ok(()) } #[test] -fn test_bind() { - let lua = Lua::new(); +fn test_bind() -> Result<()> { + let lua = make_lua(); + let globals = lua.globals(); - lua.exec::<_, ()>( + lua.load( r#" function concat(...) local res = "" @@ -34,25 +37,27 @@ fn test_bind() { return res end "#, - None, ) - .unwrap(); + .exec()?; - let mut concat = globals.get::<_, Function>("concat").unwrap(); - concat = concat.bind("foo").unwrap(); - concat = concat.bind("bar").unwrap(); - concat = concat.bind(("baz", "baf")).unwrap(); + let mut concat = globals.get::<_, Function>("concat")?; + concat = concat.bind("foo")?; + concat = concat.bind("bar")?; + concat = concat.bind(("baz", "baf"))?; assert_eq!( - concat.call::<_, String>(("hi", "wut")).unwrap(), + concat.call::<_, String>(("hi", "wut"))?, "foobarbazbafhiwut" ); + + Ok(()) } #[test] -fn test_rust_function() { - let lua = Lua::new(); +fn test_rust_function() -> Result<()> { + let lua = make_lua(); + let globals = lua.globals(); - lua.exec::<_, ()>( + lua.load( r#" function lua_function() return rust_function() @@ -61,13 +66,14 @@ fn test_rust_function() { -- Test to make sure chunk return is ignored return 1 "#, - None, ) - .unwrap(); + .exec()?; - let lua_function = globals.get::<_, Function>("lua_function").unwrap(); - let rust_function = lua.create_function(|_, ()| Ok("hello")).unwrap(); + let lua_function = globals.get::<_, Function>("lua_function")?; + let rust_function = lua.create_function(|_, ()| Ok("hello"))?; - globals.set("rust_function", rust_function).unwrap(); - assert_eq!(lua_function.call::<_, String>(()).unwrap(), "hello"); + globals.set("rust_function", rust_function)?; + assert_eq!(lua_function.call::<_, String>(())?, "hello"); + + Ok(()) } diff --git a/tests/memory.rs b/tests/memory.rs new file mode 100644 index 0000000..c65fc4a --- /dev/null +++ b/tests/memory.rs @@ -0,0 +1,56 @@ +use std::sync::Arc; + +use rlua::{Error, Result, UserData}; + +include!("_lua.rs"); + +#[test] +fn test_gc_control() -> Result<()> { + let lua = make_lua(); + + assert!(lua.gc_is_running()); + lua.gc_stop(); + assert!(!lua.gc_is_running()); + lua.gc_restart(); + assert!(lua.gc_is_running()); + + struct MyUserdata(Arc<()>); + impl UserData for MyUserdata {} + + let rc = Arc::new(()); + lua.globals() + .set("userdata", lua.create_userdata(MyUserdata(rc.clone()))?)?; + lua.globals().raw_remove("userdata")?; + + assert_eq!(Arc::strong_count(&rc), 2); + lua.gc_collect()?; + lua.gc_collect()?; + assert_eq!(Arc::strong_count(&rc), 1); + + Ok(()) +} + +#[test] +fn test_gc_error() { + let lua = make_lua(); + match lua + .load( + r#" + val = nil + table = {} + setmetatable(table, { + __gc = function() + error("gcwascalled") + end + }) + table = nil + collectgarbage("collect") + "#, + ) + .exec() + { + Err(Error::GarbageCollectorError(_)) => {} + Err(e) => panic!("__gc error did not result in correct error, instead: {}", e), + Ok(()) => panic!("__gc error did not result in error"), + } +} diff --git a/tests/scope.rs b/tests/scope.rs index 6194084..747b9d2 100644 --- a/tests/scope.rs +++ b/tests/scope.rs @@ -1,44 +1,40 @@ -extern crate rlua; - use std::cell::Cell; use std::rc::Rc; -use rlua::{Error, Function, Lua, MetaMethod, String, UserData, UserDataMethods}; +use rlua::{Error, Function, MetaMethod, Result, String, UserData, UserDataMethods}; + +include!("_lua.rs"); #[test] -fn scope_func() { - let lua = Lua::new(); +fn scope_func() -> Result<()> { + let lua = make_lua(); let rc = Rc::new(Cell::new(0)); lua.scope(|scope| { let r = rc.clone(); - let f = scope - .create_function(move |_, ()| { - r.set(42); - Ok(()) - }) - .unwrap(); - lua.globals().set("bad", f.clone()).unwrap(); - f.call::<_, ()>(()).unwrap(); + let f = scope.create_function(move |_, ()| { + r.set(42); + Ok(()) + })?; + lua.globals().set("bad", f.clone())?; + f.call::<_, ()>(())?; assert_eq!(Rc::strong_count(&rc), 2); - }); + Ok(()) + })?; assert_eq!(rc.get(), 42); assert_eq!(Rc::strong_count(&rc), 1); - match lua - .globals() - .get::<_, Function>("bad") - .unwrap() - .call::<_, ()>(()) - { + match lua.globals().get::<_, Function>("bad")?.call::<_, ()>(()) { Err(Error::CallbackError { .. }) => {} r => panic!("improper return for destructed function: {:?}", r), }; + + Ok(()) } #[test] -fn scope_drop() { - let lua = Lua::new(); +fn scope_drop() -> Result<()> { + let lua = make_lua(); struct MyUserdata(Rc<()>); impl UserData for MyUserdata { @@ -50,27 +46,26 @@ fn scope_drop() { let rc = Rc::new(()); lua.scope(|scope| { - lua.globals() - .set( - "test", - scope - .create_static_userdata(MyUserdata(rc.clone())) - .unwrap(), - ) - .unwrap(); + lua.globals().set( + "test", + scope.create_static_userdata(MyUserdata(rc.clone()))?, + )?; assert_eq!(Rc::strong_count(&rc), 2); - }); + Ok(()) + })?; assert_eq!(Rc::strong_count(&rc), 1); - match lua.exec::<_, ()>("test:method()", None) { + match lua.load("test:method()").exec() { Err(Error::CallbackError { .. }) => {} r => panic!("improper return for destructed userdata: {:?}", r), }; + + Ok(()) } #[test] -fn scope_capture() { - let lua = Lua::new(); +fn scope_capture() -> Result<()> { + let lua = make_lua(); let mut i = 0; lua.scope(|scope| { @@ -78,33 +73,31 @@ fn scope_capture() { .create_function_mut(|_, ()| { i = 42; Ok(()) - }) - .unwrap() + })? .call::<_, ()>(()) - .unwrap(); - }); + })?; assert_eq!(i, 42); + + Ok(()) } #[test] -fn outer_lua_access() { - let lua = Lua::new(); - let table = lua.create_table().unwrap(); +fn outer_lua_access() -> Result<()> { + let lua = make_lua(); + + let table = lua.create_table()?; lua.scope(|scope| { scope - .create_function_mut(|_, ()| { - table.set("a", "b").unwrap(); - Ok(()) - }) - .unwrap() + .create_function_mut(|_, ()| table.set("a", "b"))? .call::<_, ()>(()) - .unwrap(); - }); - assert_eq!(table.get::<_, String>("a").unwrap(), "b"); + })?; + assert_eq!(table.get::<_, String>("a")?, "b"); + + Ok(()) } #[test] -fn scope_userdata_methods() { +fn scope_userdata_methods() -> Result<()> { struct MyUserData<'a>(&'a Cell); impl<'a> UserData for MyUserData<'a> { @@ -121,33 +114,31 @@ fn scope_userdata_methods() { } } - let lua = Lua::new(); + let lua = make_lua(); let i = Cell::new(42); - lua.scope(|scope| { - let f: Function = lua - .eval( - r#" - function(u) - u:inc() - u:inc() - u:inc() - u:dec() - end - "#, - None, - ) - .unwrap(); + let f: Function = lua + .load( + r#" + function(u) + u:inc() + u:inc() + u:inc() + u:dec() + end + "#, + ) + .eval()?; - f.call::<_, ()>(scope.create_nonstatic_userdata(MyUserData(&i)).unwrap()) - .unwrap(); - }); + lua.scope(|scope| f.call::<_, ()>(scope.create_nonstatic_userdata(MyUserData(&i))?))?; assert_eq!(i.get(), 44); + + Ok(()) } #[test] -fn scope_userdata_functions() { +fn scope_userdata_functions() -> Result<()> { struct MyUserData<'a>(&'a i64); impl<'a> UserData for MyUserData<'a> { @@ -165,32 +156,31 @@ fn scope_userdata_functions() { } } - let lua = Lua::new(); - let f = lua - .exec::<_, Function>( - r#" - i = 0 - return function(u) - _ = u + u - _ = u - 1 - _ = 1 + u - end - "#, - None, - ) - .unwrap(); + let lua = make_lua(); let dummy = 0; - lua.scope(|scope| { - f.call::<_, ()>(scope.create_nonstatic_userdata(MyUserData(&dummy)).unwrap()) - .unwrap(); - }); + let f = lua + .load( + r#" + i = 0 + return function(u) + _ = u + u + _ = u - 1 + _ = 1 + u + end + "#, + ) + .eval::()?; - assert_eq!(lua.globals().get::<_, i64>("i").unwrap(), 3); + lua.scope(|scope| f.call::<_, ()>(scope.create_nonstatic_userdata(MyUserData(&dummy))?))?; + + assert_eq!(lua.globals().get::<_, i64>("i")?, 3); + + Ok(()) } #[test] -fn scope_userdata_mismatch() { +fn scope_userdata_mismatch() -> Result<()> { struct MyUserData<'a>(&'a Cell); impl<'a> UserData for MyUserData<'a> { @@ -202,31 +192,31 @@ fn scope_userdata_mismatch() { } } - let lua = Lua::new(); - lua.exec::<_, ()>( - r#" - function okay(a, b) - a.inc(a) - b.inc(b) - end + let lua = make_lua(); - function bad(a, b) - a.inc(b) - end - "#, - None, + lua.load( + r#" + function okay(a, b) + a.inc(a) + b.inc(b) + end + + function bad(a, b) + a.inc(b) + end + "#, ) - .unwrap(); + .exec()?; let a = Cell::new(1); let b = Cell::new(1); - let okay: Function = lua.globals().get("okay").unwrap(); - let bad: Function = lua.globals().get("bad").unwrap(); + let okay: Function = lua.globals().get("okay")?; + let bad: Function = lua.globals().get("bad")?; lua.scope(|scope| { - let au = scope.create_nonstatic_userdata(MyUserData(&a)).unwrap(); - let bu = scope.create_nonstatic_userdata(MyUserData(&b)).unwrap(); + let au = scope.create_nonstatic_userdata(MyUserData(&a))?; + let bu = scope.create_nonstatic_userdata(MyUserData(&b))?; assert!(okay.call::<_, ()>((au.clone(), bu.clone())).is_ok()); match bad.call::<_, ()>((au, bu)) { Err(Error::CallbackError { ref cause, .. }) => match *cause.as_ref() { @@ -236,5 +226,8 @@ fn scope_userdata_mismatch() { Err(other) => panic!("wrong error type {:?}", other), Ok(_) => panic!("incorrectly returned Ok"), } - }); + Ok(()) + })?; + + Ok(()) } diff --git a/tests/string.rs b/tests/string.rs index 0a52119..8244cbb 100644 --- a/tests/string.rs +++ b/tests/string.rs @@ -1,20 +1,15 @@ -extern crate rlua; - use std::borrow::Cow; -use rlua::{Lua, String}; +use rlua::{Result, String}; -fn with_str(s: &str, f: F) -where - F: FnOnce(String), -{ - let lua = Lua::new(); - let string = lua.create_string(s).unwrap(); - f(string); -} +include!("_lua.rs"); #[test] fn compare() { + fn with_str(s: &str, f: F) { + f(make_lua().create_string(s).unwrap()); + } + // Tests that all comparisons we want to have are usable with_str("teststring", |t| assert_eq!(t, "teststring")); // &str with_str("teststring", |t| assert_eq!(t, b"teststring")); // &[u8] @@ -28,27 +23,24 @@ fn compare() { } #[test] -fn string_views() { - let lua = Lua::new(); - lua.eval::<_, ()>( +fn string_views() -> Result<()> { + let lua = make_lua(); + + lua.load( r#" - ok = "null bytes are valid utf-8, wh\0 knew?" - err = "but \xff isn't :(" - empty = "" - "#, - None, + ok = "null bytes are valid utf-8, wh\0 knew?" + err = "but \xff isn't :(" + empty = "" + "#, ) - .unwrap(); + .exec()?; let globals = lua.globals(); - let ok: String = globals.get("ok").unwrap(); - let err: String = globals.get("err").unwrap(); - let empty: String = globals.get("empty").unwrap(); + let ok: String = globals.get("ok")?; + let err: String = globals.get("err")?; + let empty: String = globals.get("empty")?; - assert_eq!( - ok.to_str().unwrap(), - "null bytes are valid utf-8, wh\0 knew?" - ); + assert_eq!(ok.to_str()?, "null bytes are valid utf-8, wh\0 knew?"); assert_eq!( ok.as_bytes(), &b"null bytes are valid utf-8, wh\0 knew?"[..] @@ -57,14 +49,19 @@ fn string_views() { assert!(err.to_str().is_err()); assert_eq!(err.as_bytes(), &b"but \xff isn't :("[..]); - assert_eq!(empty.to_str().unwrap(), ""); + assert_eq!(empty.to_str()?, ""); assert_eq!(empty.as_bytes_with_nul(), &[0]); assert_eq!(empty.as_bytes(), &[]); + + Ok(()) } #[test] -fn raw_string() { - let lua = Lua::new(); - let rs = lua.create_string(&[0, 1, 2, 3, 0, 1, 2, 3]).unwrap(); +fn raw_string() -> Result<()> { + let lua = make_lua(); + + let rs = lua.create_string(&[0, 1, 2, 3, 0, 1, 2, 3])?; assert_eq!(rs.as_bytes(), &[0, 1, 2, 3, 0, 1, 2, 3]); + + Ok(()) } diff --git a/tests/table.rs b/tests/table.rs index d77c563..2a29b1d 100644 --- a/tests/table.rs +++ b/tests/table.rs @@ -1,182 +1,174 @@ -extern crate rlua; +use rlua::{Nil, Result, Table, Value}; -use rlua::{Lua, Nil, Result, Table, Value}; +include!("_lua.rs"); #[test] -fn test_set_get() { - let lua = Lua::new(); +fn test_set_get() -> Result<()> { + let lua = make_lua(); + let globals = lua.globals(); - globals.set("foo", "bar").unwrap(); - globals.set("baz", "baf").unwrap(); - assert_eq!(globals.get::<_, String>("foo").unwrap(), "bar"); - assert_eq!(globals.get::<_, String>("baz").unwrap(), "baf"); + globals.set("foo", "bar")?; + globals.set("baz", "baf")?; + assert_eq!(globals.get::<_, String>("foo")?, "bar"); + assert_eq!(globals.get::<_, String>("baz")?, "baf"); + + Ok(()) } #[test] -fn test_table() { - let lua = Lua::new(); +fn test_table() -> Result<()> { + let lua = make_lua(); + let globals = lua.globals(); - globals.set("table", lua.create_table().unwrap()).unwrap(); - let table1: Table = globals.get("table").unwrap(); - let table2: Table = globals.get("table").unwrap(); + globals.set("table", lua.create_table()?)?; + let table1: Table = globals.get("table")?; + let table2: Table = globals.get("table")?; - table1.set("foo", "bar").unwrap(); - table2.set("baz", "baf").unwrap(); + table1.set("foo", "bar")?; + table2.set("baz", "baf")?; - assert_eq!(table2.get::<_, String>("foo").unwrap(), "bar"); - assert_eq!(table1.get::<_, String>("baz").unwrap(), "baf"); + assert_eq!(table2.get::<_, String>("foo")?, "bar"); + assert_eq!(table1.get::<_, String>("baz")?, "baf"); - lua.exec::<_, ()>( + lua.load( r#" - table1 = {1, 2, 3, 4, 5} - table2 = {} - table3 = {1, 2, nil, 4, 5} - "#, - None, + table1 = {1, 2, 3, 4, 5} + table2 = {} + table3 = {1, 2, nil, 4, 5} + "#, ) - .unwrap(); + .exec()?; - let table1 = globals.get::<_, Table>("table1").unwrap(); - let table2 = globals.get::<_, Table>("table2").unwrap(); - let table3 = globals.get::<_, Table>("table3").unwrap(); + let table1 = globals.get::<_, Table>("table1")?; + let table2 = globals.get::<_, Table>("table2")?; + let table3 = globals.get::<_, Table>("table3")?; - assert_eq!(table1.len().unwrap(), 5); + assert_eq!(table1.len()?, 5); assert_eq!( table1 .clone() .pairs() - .collect::>>() - .unwrap(), + .collect::>>()?, vec![(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)] ); assert_eq!( table1 .clone() .sequence_values() - .collect::>>() - .unwrap(), + .collect::>>()?, vec![1, 2, 3, 4, 5] ); - assert_eq!(table2.len().unwrap(), 0); + assert_eq!(table2.len()?, 0); assert_eq!( table2 .clone() .pairs() - .collect::>>() - .unwrap(), + .collect::>>()?, vec![] ); assert_eq!( - table2 - .sequence_values() - .collect::>>() - .unwrap(), + table2.sequence_values().collect::>>()?, vec![] ); // sequence_values should only iterate until the first border assert_eq!( - table3 - .sequence_values() - .collect::>>() - .unwrap(), + table3.sequence_values().collect::>>()?, vec![1, 2] ); - globals - .set( - "table4", - lua.create_sequence_from(vec![1, 2, 3, 4, 5]).unwrap(), - ) - .unwrap(); - let table4 = globals.get::<_, Table>("table4").unwrap(); + globals.set("table4", lua.create_sequence_from(vec![1, 2, 3, 4, 5])?)?; + let table4 = globals.get::<_, Table>("table4")?; assert_eq!( - table4.pairs().collect::>>().unwrap(), + table4.pairs().collect::>>()?, vec![(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)] ); + + Ok(()) } #[test] -fn test_table_scope() { - let lua = Lua::new(); +fn test_table_scope() -> Result<()> { + let lua = make_lua(); + let globals = lua.globals(); - lua.exec::<_, ()>( + lua.load( r#" - touter = { - tin = {1, 2, 3} - } - "#, - None, + touter = { + tin = {1, 2, 3} + } + "#, ) - .unwrap(); + .exec()?; // Make sure that table gets do not borrow the table, but instead just borrow lua. let tin; { - let touter = globals.get::<_, Table>("touter").unwrap(); - tin = touter.get::<_, Table>("tin").unwrap(); + let touter = globals.get::<_, Table>("touter")?; + tin = touter.get::<_, Table>("tin")?; } - assert_eq!(tin.get::<_, i64>(1).unwrap(), 1); - assert_eq!(tin.get::<_, i64>(2).unwrap(), 2); - assert_eq!(tin.get::<_, i64>(3).unwrap(), 3); + assert_eq!(tin.get::<_, i64>(1)?, 1); + assert_eq!(tin.get::<_, i64>(2)?, 2); + assert_eq!(tin.get::<_, i64>(3)?, 3); + + Ok(()) } #[test] -fn test_metatable() { - let lua = Lua::new(); +fn test_metatable() -> Result<()> { + let lua = make_lua(); - let table = lua.create_table().unwrap(); - let metatable = lua.create_table().unwrap(); - metatable - .set( - "__index", - lua.create_function(|_, ()| Ok("index_value")).unwrap(), - ) - .unwrap(); + let table = lua.create_table()?; + let metatable = lua.create_table()?; + metatable.set("__index", lua.create_function(|_, ()| Ok("index_value"))?)?; table.set_metatable(Some(metatable)); - assert_eq!(table.get::<_, String>("any_key").unwrap(), "index_value"); - match table.raw_get::<_, Value>("any_key").unwrap() { + assert_eq!(table.get::<_, String>("any_key")?, "index_value"); + match table.raw_get::<_, Value>("any_key")? { Nil => {} _ => panic!(), } table.set_metatable(None); - match table.get::<_, Value>("any_key").unwrap() { + match table.get::<_, Value>("any_key")? { Nil => {} _ => panic!(), }; + + Ok(()) } #[test] -fn test_table_error() { - let lua = Lua::new(); - let globals = lua.globals(); - lua.exec::<_, ()>( - r#" - table = {} - setmetatable(table, { - __index = function() - error("lua error") - end, - __newindex = function() - error("lua error") - end, - __len = function() - error("lua error") - end - }) - "#, - None, - ) - .unwrap(); +fn test_table_error() -> Result<()> { + let lua = make_lua(); - let bad_table: Table = globals.get("table").unwrap(); + let globals = lua.globals(); + lua.load( + r#" + table = {} + setmetatable(table, { + __index = function() + error("lua error") + end, + __newindex = function() + error("lua error") + end, + __len = function() + error("lua error") + end + }) + "#, + ) + .exec()?; + + let bad_table: Table = globals.get("table")?; assert!(bad_table.set(1, 1).is_err()); assert!(bad_table.get::<_, i32>(1).is_err()); assert!(bad_table.len().is_err()); assert!(bad_table.raw_set(1, 1).is_ok()); assert!(bad_table.raw_get::<_, i32>(1).is_ok()); assert_eq!(bad_table.raw_len(), 1); + + Ok(()) } diff --git a/tests/tests.rs b/tests/tests.rs index 050b101..25dc611 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -1,55 +1,39 @@ -extern crate failure; -extern crate rlua; - use std::iter::FromIterator; use std::panic::catch_unwind; use std::sync::Arc; use std::{error, f32, f64, fmt}; -use failure::err_msg; -use rlua::{ - Error, ExternalError, Function, Lua, Nil, Result, String, Table, UserData, Value, Variadic, -}; +use rlua::{Error, ExternalError, Function, Nil, Result, String, Table, UserData, Value, Variadic}; + +include!("_lua.rs"); #[test] -fn test_load() { - let lua = Lua::new(); - let func = lua.load("return 1+2", None).unwrap(); - let result: i32 = func.call(()).unwrap(); +fn test_load() -> Result<()> { + let lua = make_lua(); + let func = lua.load("return 1+2").into_function()?; + let result: i32 = func.call(())?; assert_eq!(result, 3); - assert!(lua.load("§$%§&$%&", None).is_err()); + assert!(lua.load("§$%§&$%&").exec().is_err()); + + Ok(()) } #[test] -fn test_debug() { - let lua = unsafe { Lua::new_with_debug() }; - match lua.eval("debug", None).unwrap() { - Value::Table(_) => {} - val => panic!("Expected table for debug library, got {:#?}", val), - } - let traceback_output = lua.eval::<_, String>("debug.traceback()", None).unwrap(); - assert_eq!( - traceback_output.to_str().unwrap().split("\n").next(), - "stack traceback:".into() - ); -} +fn test_exec() -> Result<()> { + let lua = make_lua(); -#[test] -fn test_exec() { - let lua = Lua::new(); let globals = lua.globals(); - lua.exec::<_, ()>( + lua.load( r#" - res = 'foo'..'bar' - "#, - None, + res = 'foo'..'bar' + "#, ) - .unwrap(); - assert_eq!(globals.get::<_, String>("res").unwrap(), "foobar"); + .exec()?; + assert_eq!(globals.get::<_, String>("res")?, "foobar"); let module: Table = lua - .exec( + .load( r#" local module = {} @@ -59,27 +43,25 @@ fn test_exec() { return module "#, - None, ) - .unwrap(); - assert!(module.contains_key("func").unwrap()); + .eval()?; + assert!(module.contains_key("func")?); assert_eq!( - module - .get::<_, Function>("func") - .unwrap() - .call::<_, String>(()) - .unwrap(), + module.get::<_, Function>("func")?.call::<_, String>(())?, "hello" ); + + Ok(()) } #[test] -fn test_eval() { - let lua = Lua::new(); - assert_eq!(lua.eval::<_, i32>("1 + 1", None).unwrap(), 2); - assert_eq!(lua.eval::<_, bool>("false == false", None).unwrap(), true); - assert_eq!(lua.eval::<_, i32>("return 1 + 2", None).unwrap(), 3); - match lua.eval::<_, ()>("if true then", None) { +fn test_eval() -> Result<()> { + let lua = make_lua(); + + assert_eq!(lua.load("1 + 1").eval::()?, 2); + assert_eq!(lua.load("false == false").eval::()?, true); + assert_eq!(lua.load("return 1 + 2").eval::()?, 3); + match lua.load("if true then").eval::<()>() { Err(Error::SyntaxError { incomplete_input: true, .. @@ -89,13 +71,15 @@ fn test_eval() { r ), } + + Ok(()) } #[test] -fn test_lua_multi() { - let lua = Lua::new(); - let globals = lua.globals(); - lua.exec::<_, ()>( +fn test_lua_multi() -> Result<()> { + let lua = make_lua(); + + lua.load( r#" function concat(arg1, arg2) return arg1 .. arg2 @@ -104,43 +88,47 @@ fn test_lua_multi() { function mreturn() return 1, 2, 3, 4, 5, 6 end - "#, - None, + "#, ) - .unwrap(); + .exec()?; - let concat = globals.get::<_, Function>("concat").unwrap(); - let mreturn = globals.get::<_, Function>("mreturn").unwrap(); + let globals = lua.globals(); + let concat = globals.get::<_, Function>("concat")?; + let mreturn = globals.get::<_, Function>("mreturn")?; - assert_eq!(concat.call::<_, String>(("foo", "bar")).unwrap(), "foobar"); - let (a, b) = mreturn.call::<_, (u64, u64)>(()).unwrap(); + assert_eq!(concat.call::<_, String>(("foo", "bar"))?, "foobar"); + let (a, b) = mreturn.call::<_, (u64, u64)>(())?; assert_eq!((a, b), (1, 2)); - let (a, b, v) = mreturn.call::<_, (u64, u64, Variadic)>(()).unwrap(); + let (a, b, v) = mreturn.call::<_, (u64, u64, Variadic)>(())?; assert_eq!((a, b), (1, 2)); assert_eq!(v[..], [3, 4, 5, 6]); + + Ok(()) } #[test] -fn test_coercion() { - let lua = Lua::new(); - let globals = lua.globals(); - lua.exec::<_, ()>( +fn test_coercion() -> Result<()> { + let lua = make_lua(); + + lua.load( r#" - int = 123 - str = "123" - num = 123.0 - "#, - None, + int = 123 + str = "123" + num = 123.0 + "#, ) - .unwrap(); + .exec()?; - assert_eq!(globals.get::<_, String>("int").unwrap(), "123"); - assert_eq!(globals.get::<_, i32>("str").unwrap(), 123); - assert_eq!(globals.get::<_, i32>("num").unwrap(), 123); + let globals = lua.globals(); + assert_eq!(globals.get::<_, String>("int")?, "123"); + assert_eq!(globals.get::<_, i32>("str")?, 123); + assert_eq!(globals.get::<_, i32>("num")?, 123); + + Ok(()) } #[test] -fn test_error() { +fn test_error() -> Result<()> { #[derive(Debug)] pub struct TestError; @@ -155,81 +143,78 @@ fn test_error() { "test error" } - fn cause(&self) -> Option<&error::Error> { + fn cause(&self) -> Option<&dyn error::Error> { None } } - let lua = Lua::new(); + let lua = make_lua(); + let globals = lua.globals(); - lua.exec::<_, ()>( + lua.load( r#" - function no_error() + function no_error() + end + + function lua_error() + error("this is a lua error") + end + + function rust_error() + rust_error_function() + end + + function return_error() + local status, res = pcall(rust_error_function) + assert(not status) + return res + end + + function return_string_error() + return "this should be converted to an error" + end + + function test_pcall() + local testvar = 0 + + pcall(function(arg) + testvar = testvar + arg + error("should be ignored") + end, 3) + + local function handler(err) + testvar = testvar + err + return "should be ignored" end - function lua_error() - error("this is a lua error") + local status, res = xpcall(function() + error(5) + end, handler) + assert(not status) + + if testvar ~= 8 then + error("testvar had the wrong value, pcall / xpcall misbehaving "..testvar) end + end - function rust_error() - rust_error_function() - end - - function return_error() - local status, res = pcall(rust_error_function) - assert(not status) - return res - end - - function return_string_error() - return "this should be converted to an error" - end - - function test_pcall() - local testvar = 0 - - pcall(function(arg) - testvar = testvar + arg - error("should be ignored") - end, 3) - - local function handler(err) - testvar = testvar + err - return "should be ignored" - end - - local status, res = xpcall(function() - error(5) - end, handler) - assert(not status) - - if testvar ~= 8 then - error("testvar had the wrong value, pcall / xpcall misbehaving "..testvar) - end - end - - function understand_recursion() - understand_recursion() - end - "#, - None, + function understand_recursion() + understand_recursion() + end + "#, ) - .unwrap(); + .exec()?; - let rust_error_function = lua - .create_function(|_, ()| -> Result<()> { Err(TestError.to_lua_err()) }) - .unwrap(); - globals - .set("rust_error_function", rust_error_function) - .unwrap(); + let rust_error_function = + lua.create_function(|_, ()| -> Result<()> { Err(TestError.to_lua_err()) })?; + globals.set("rust_error_function", rust_error_function)?; - let no_error = globals.get::<_, Function>("no_error").unwrap(); - let lua_error = globals.get::<_, Function>("lua_error").unwrap(); - let rust_error = globals.get::<_, Function>("rust_error").unwrap(); - let return_error = globals.get::<_, Function>("return_error").unwrap(); - let return_string_error = globals.get::<_, Function>("return_string_error").unwrap(); - let test_pcall = globals.get::<_, Function>("test_pcall").unwrap(); - let understand_recursion = globals.get::<_, Function>("understand_recursion").unwrap(); + let no_error = globals.get::<_, Function>("no_error")?; + let lua_error = globals.get::<_, Function>("lua_error")?; + let rust_error = globals.get::<_, Function>("rust_error")?; + let return_error = globals.get::<_, Function>("return_error")?; + let return_string_error = globals.get::<_, Function>("return_string_error")?; + let test_pcall = globals.get::<_, Function>("test_pcall")?; + let understand_recursion = globals.get::<_, Function>("understand_recursion")?; assert!(no_error.call::<_, ()>(()).is_ok()); match lua_error.call::<_, ()>(()) { @@ -250,7 +235,10 @@ fn test_error() { assert!(return_string_error.call::<_, Error>(()).is_ok()); - match lua.eval::<_, ()>("if youre happy and you know it syntax error", None) { + match lua + .load("if youre happy and you know it syntax error") + .exec() + { Err(Error::SyntaxError { incomplete_input: false, .. @@ -258,7 +246,7 @@ fn test_error() { Err(_) => panic!("error is not LuaSyntaxError::Syntax kind"), _ => panic!("error not returned"), } - match lua.eval::<_, ()>("function i_will_finish_what_i()", None) { + match lua.load("function i_will_finish_what_i()").exec() { Err(Error::SyntaxError { incomplete_input: true, .. @@ -267,249 +255,235 @@ fn test_error() { _ => panic!("error not returned"), } - test_pcall.call::<_, ()>(()).unwrap(); + test_pcall.call::<_, ()>(())?; assert!(understand_recursion.call::<_, ()>(()).is_err()); match catch_unwind(|| -> Result<()> { - let lua = Lua::new(); + let lua = make_lua(); let globals = lua.globals(); - lua.exec::<_, ()>( + lua.load( r#" - function rust_panic() - pcall(function () rust_panic_function() end) + function rust_panic() + local _, err = pcall(function () rust_panic_function() end) + if err ~= nil then + error(err) end - "#, - None, - )?; - let rust_panic_function = lua - .create_function(|_, ()| -> Result<()> { panic!("test_panic") }) - .unwrap(); + end + "#, + ) + .exec()?; + let rust_panic_function = + lua.create_function(|_, ()| -> Result<()> { panic!("test_panic") })?; globals.set("rust_panic_function", rust_panic_function)?; let rust_panic = globals.get::<_, Function>("rust_panic")?; rust_panic.call::<_, ()>(()) }) { - Ok(Ok(_)) => panic!("no panic was detected, pcall caught it!"), + Ok(Ok(_)) => panic!("no panic was detected"), Ok(Err(e)) => panic!("error during panic test {:?}", e), Err(p) => assert!(*p.downcast::<&str>().unwrap() == "test_panic"), }; match catch_unwind(|| -> Result<()> { - let lua = Lua::new(); + let lua = make_lua(); let globals = lua.globals(); - lua.exec::<_, ()>( + lua.load( r#" - function rust_panic() - xpcall(function() rust_panic_function() end, function() end) + function rust_panic() + local _, err = pcall(function () rust_panic_function() end) + if err ~= nil then + error(tostring(err)) end - "#, - None, - )?; - let rust_panic_function = lua - .create_function(|_, ()| -> Result<()> { panic!("test_panic") }) - .unwrap(); + end + "#, + ) + .exec()?; + let rust_panic_function = + lua.create_function(|_, ()| -> Result<()> { panic!("test_panic") })?; globals.set("rust_panic_function", rust_panic_function)?; let rust_panic = globals.get::<_, Function>("rust_panic")?; rust_panic.call::<_, ()>(()) }) { - Ok(Ok(_)) => panic!("no panic was detected, xpcall caught it!"), - Ok(Err(e)) => panic!("error during panic test {:?}", e), - Err(p) => assert!(*p.downcast::<&str>().unwrap() == "test_panic"), + Ok(Ok(_)) => panic!("no error was detected"), + Ok(Err(Error::RuntimeError(_))) => {} + Ok(Err(e)) => panic!("unexpected error during panic test {:?}", e), + Err(_) => panic!("panic was detected"), }; + + Ok(()) } #[test] -fn test_result_conversions() { - let lua = Lua::new(); +fn test_result_conversions() -> Result<()> { + let lua = make_lua(); let globals = lua.globals(); - let err = lua - .create_function(|_, ()| { - Ok(Err::( - err_msg("only through failure can we succeed").to_lua_err(), - )) - }) - .unwrap(); - let ok = lua - .create_function(|_, ()| Ok(Ok::<_, Error>("!".to_owned()))) - .unwrap(); + let err = lua.create_function(|_, ()| { + Ok(Err::( + "only through failure can we succeed".to_lua_err(), + )) + })?; + let ok = lua.create_function(|_, ()| Ok(Ok::<_, Error>("!".to_owned())))?; - globals.set("err", err).unwrap(); - globals.set("ok", ok).unwrap(); + globals.set("err", err)?; + globals.set("ok", ok)?; - lua.exec::<_, ()>( + lua.load( r#" - local r, e = err() - assert(r == nil) - assert(tostring(e) == "only through failure can we succeed") + local r, e = err() + assert(r == nil) + assert(tostring(e):find("only through failure can we succeed") ~= nil) - local r, e = ok() - assert(r == "!") - assert(e == nil) - "#, - None, + local r, e = ok() + assert(r == "!") + assert(e == nil) + "#, ) - .unwrap(); + .exec()?; + + Ok(()) } #[test] -fn test_num_conversion() { - let lua = Lua::new(); +fn test_num_conversion() -> Result<()> { + let lua = make_lua(); assert_eq!( - lua.coerce_integer(Value::String(lua.create_string("1").unwrap())), + lua.coerce_integer(Value::String(lua.create_string("1")?))?, Some(1) ); assert_eq!( - lua.coerce_integer(Value::String(lua.create_string("1.0").unwrap())), + lua.coerce_integer(Value::String(lua.create_string("1.0")?))?, Some(1) ); assert_eq!( - lua.coerce_integer(Value::String(lua.create_string("1.5").unwrap())), + lua.coerce_integer(Value::String(lua.create_string("1.5")?))?, None ); assert_eq!( - lua.coerce_number(Value::String(lua.create_string("1").unwrap())), + lua.coerce_number(Value::String(lua.create_string("1")?))?, Some(1.0) ); assert_eq!( - lua.coerce_number(Value::String(lua.create_string("1.0").unwrap())), + lua.coerce_number(Value::String(lua.create_string("1.0")?))?, Some(1.0) ); assert_eq!( - lua.coerce_number(Value::String(lua.create_string("1.5").unwrap())), + lua.coerce_number(Value::String(lua.create_string("1.5")?))?, Some(1.5) ); - assert_eq!(lua.eval::<_, i64>("1.0", None).unwrap(), 1); - assert_eq!(lua.eval::<_, f64>("1.0", None).unwrap(), 1.0); - assert_eq!(lua.eval::<_, String>("1.0", None).unwrap(), "1.0"); + assert_eq!(lua.load("1.0").eval::()?, 1); + assert_eq!(lua.load("1.0").eval::()?, 1.0); + assert_eq!(lua.load("1.0").eval::()?, "1.0"); - assert_eq!(lua.eval::<_, i64>("1.5", None).unwrap(), 1); - assert_eq!(lua.eval::<_, f64>("1.5", None).unwrap(), 1.5); - assert_eq!(lua.eval::<_, String>("1.5", None).unwrap(), "1.5"); + assert_eq!(lua.load("1.5").eval::()?, 1); + assert_eq!(lua.load("1.5").eval::()?, 1.5); + assert_eq!(lua.load("1.5").eval::()?, "1.5"); - assert!(lua.eval::<_, u64>("-1", None).is_err()); - assert_eq!(lua.eval::<_, i64>("-1", None).unwrap(), -1); + assert!(lua.load("-1").eval::().is_err()); + assert_eq!(lua.load("-1").eval::()?, -1); - assert!(lua.unpack::(lua.pack(1u128 << 64).unwrap()).is_err()); - assert!(lua.eval::<_, i64>("math.huge", None).is_err()); + assert!(lua.unpack::(lua.pack(1u128 << 64)?).is_err()); + assert!(lua.load("math.huge").eval::().is_err()); - assert_eq!( - lua.unpack::(lua.pack(f32::MAX).unwrap()).unwrap(), - f32::MAX as f64 - ); - assert!(lua.unpack::(lua.pack(f64::MAX).unwrap()).is_err()); + assert_eq!(lua.unpack::(lua.pack(f32::MAX)?)?, f32::MAX as f64); + assert!(lua.unpack::(lua.pack(f64::MAX)?).is_err()); - assert_eq!( - lua.unpack::(lua.pack(1i128 << 64).unwrap()).unwrap(), - 1i128 << 64 - ); + assert_eq!(lua.unpack::(lua.pack(1i128 << 64)?)?, 1i128 << 64); + + Ok(()) } #[test] -fn test_pcall_xpcall() { - let lua = Lua::new(); +fn test_pcall_xpcall() -> Result<()> { + let lua = make_lua(); let globals = lua.globals(); // make sure that we handle not enough arguments - assert!(lua.exec::<_, ()>("pcall()", None).is_err()); - assert!(lua.exec::<_, ()>("xpcall()", None).is_err()); - assert!(lua.exec::<_, ()>("xpcall(function() end)", None).is_err()); + assert!(lua.load("pcall()").exec().is_err()); + assert!(lua.load("xpcall()").exec().is_err()); + assert!(lua.load("xpcall(function() end)").exec().is_err()); // Make sure that the return values from are correct on success let (r, e) = lua - .eval::<_, (bool, String)>("pcall(function(p) return p end, 'foo')", None) - .unwrap(); + .load("pcall(function(p) return p end, 'foo')") + .eval::<(bool, String)>()?; assert!(r); assert_eq!(e, "foo"); let (r, e) = lua - .eval::<_, (bool, String)>("xpcall(function(p) return p end, print, 'foo')", None) - .unwrap(); + .load("xpcall(function(p) return p end, print, 'foo')") + .eval::<(bool, String)>()?; assert!(r); assert_eq!(e, "foo"); // Make sure that the return values are correct on errors, and that error handling works - lua.exec::<_, ()>( + lua.load( r#" - pcall_error = nil - pcall_status, pcall_error = pcall(error, "testerror") + pcall_error = nil + pcall_status, pcall_error = pcall(error, "testerror") - xpcall_error = nil - xpcall_status, _ = xpcall(error, function(err) xpcall_error = err end, "testerror") - "#, - None, + xpcall_error = nil + xpcall_status, _ = xpcall(error, function(err) xpcall_error = err end, "testerror") + "#, ) - .unwrap(); + .exec()?; - assert_eq!(globals.get::<_, bool>("pcall_status").unwrap(), false); - assert_eq!( - globals.get::<_, String>("pcall_error").unwrap(), - "testerror" - ); + assert_eq!(globals.get::<_, bool>("pcall_status")?, false); + assert_eq!(globals.get::<_, String>("pcall_error")?, "testerror"); - assert_eq!(globals.get::<_, bool>("xpcall_statusr").unwrap(), false); - assert_eq!( - globals.get::<_, String>("xpcall_error").unwrap(), - "testerror" - ); + assert_eq!(globals.get::<_, bool>("xpcall_statusr")?, false); + assert_eq!(globals.get::<_, String>("xpcall_error")?, "testerror"); // Make sure that weird xpcall error recursion at least doesn't cause unsafety or panics. - lua.exec::<_, ()>( + lua.load( r#" - function xpcall_recursion() - xpcall(error, function(err) error(err) end, "testerror") - end - "#, - None, + function xpcall_recursion() + xpcall(error, function(err) error(err) end, "testerror") + end + "#, ) - .unwrap(); + .exec()?; let _ = globals - .get::<_, Function>("xpcall_recursion") - .unwrap() + .get::<_, Function>("xpcall_recursion")? .call::<_, ()>(()); + + Ok(()) } #[test] -fn test_recursive_mut_callback_error() { - let lua = Lua::new(); +fn test_recursive_mut_callback_error() -> Result<()> { + let lua = make_lua(); let mut v = Some(Box::new(123)); - let f = lua - .create_function_mut::<_, (), _>(move |lua, mutate: bool| { - if mutate { - v = None; - } else { - // Produce a mutable reference - let r = v.as_mut().unwrap(); - // Whoops, this will recurse into the function and produce another mutable reference! - lua.globals().get::<_, Function>("f")?.call::<_, ()>(true)?; - println!("Should not get here, mutable aliasing has occurred!"); - println!("value at {:p}", r as *mut _); - println!("value is {}", r); - } + let f = lua.create_function_mut::<_, (), _>(move |lua, mutate: bool| { + if mutate { + v = None; + } else { + // Produce a mutable reference + let r = v.as_mut().unwrap(); + // Whoops, this will recurse into the function and produce another mutable reference! + lua.globals().get::<_, Function>("f")?.call::<_, ()>(true)?; + println!("Should not get here, mutable aliasing has occurred!"); + println!("value at {:p}", r as *mut _); + println!("value is {}", r); + } - Ok(()) - }) - .unwrap(); - lua.globals().set("f", f).unwrap(); - match lua - .globals() - .get::<_, Function>("f") - .unwrap() - .call::<_, ()>(false) - { + Ok(()) + })?; + lua.globals().set("f", f)?; + match lua.globals().get::<_, Function>("f")?.call::<_, ()>(false) { Err(Error::CallbackError { ref cause, .. }) => match *cause.as_ref() { Error::CallbackError { ref cause, .. } => match *cause.as_ref() { Error::RecursiveMutCallback { .. } => {} @@ -519,255 +493,281 @@ fn test_recursive_mut_callback_error() { }, other => panic!("incorrect result: {:?}", other), }; + + Ok(()) } #[test] -fn test_set_metatable_nil() { - let lua = Lua::new(); - lua.exec::<_, ()>( +fn test_set_metatable_nil() -> Result<()> { + let lua = make_lua(); + lua.load( r#" a = {} setmetatable(a, nil) "#, - None, ) - .unwrap(); + .exec()?; + Ok(()) } #[test] -fn test_gc_error() { - let lua = Lua::new(); - match lua.exec::<_, ()>( - r#" - val = nil - table = {} - setmetatable(table, { - __gc = function() - error("gcwascalled") - end - }) - table = nil - collectgarbage("collect") - "#, - None, - ) { - Err(Error::GarbageCollectorError(_)) => {} - Err(e) => panic!("__gc error did not result in correct error, instead: {}", e), - Ok(()) => panic!("__gc error did not result in error"), - } -} +fn test_named_registry_value() -> Result<()> { + let lua = make_lua(); -#[test] -fn test_named_registry_value() { - let lua = Lua::new(); + lua.set_named_registry_value::<_, i32>("test", 42)?; + let f = lua.create_function(move |lua, ()| { + assert_eq!(lua.named_registry_value::<_, i32>("test")?, 42); + Ok(()) + })?; - lua.set_named_registry_value::("test", 42).unwrap(); - let f = lua - .create_function(move |lua, ()| { - assert_eq!(lua.named_registry_value::("test")?, 42); - Ok(()) - }) - .unwrap(); + f.call::<_, ()>(())?; - f.call::<_, ()>(()).unwrap(); - - lua.unset_named_registry_value("test").unwrap(); - match lua.named_registry_value("test").unwrap() { + lua.unset_named_registry_value("test")?; + match lua.named_registry_value("test")? { Nil => {} val => panic!("registry value was not Nil, was {:?}", val), }; + + Ok(()) } #[test] -fn test_registry_value() { - let lua = Lua::new(); +fn test_registry_value() -> Result<()> { + let lua = make_lua(); - let mut r = Some(lua.create_registry_value::(42).unwrap()); - let f = lua - .create_function_mut(move |lua, ()| { - if let Some(r) = r.take() { - assert_eq!(lua.registry_value::(&r)?, 42); - lua.remove_registry_value(r).unwrap(); - } else { - panic!(); - } - Ok(()) - }) - .unwrap(); + let mut r = Some(lua.create_registry_value::(42)?); + let f = lua.create_function_mut(move |lua, ()| { + if let Some(r) = r.take() { + assert_eq!(lua.registry_value::(&r)?, 42); + lua.remove_registry_value(r).unwrap(); + } else { + panic!(); + } + Ok(()) + })?; - f.call::<_, ()>(()).unwrap(); + f.call::<_, ()>(())?; + + Ok(()) } #[test] -fn test_drop_registry_value() { +fn test_drop_registry_value() -> Result<()> { struct MyUserdata(Arc<()>); impl UserData for MyUserdata {} - let lua = Lua::new(); - + let lua = make_lua(); let rc = Arc::new(()); - let r = lua.create_registry_value(MyUserdata(rc.clone())).unwrap(); + let r = lua.create_registry_value(MyUserdata(rc.clone()))?; assert_eq!(Arc::strong_count(&rc), 2); drop(r); lua.expire_registry_values(); - lua.exec::<_, ()>(r#"collectgarbage("collect")"#, None) - .unwrap(); + lua.load(r#"collectgarbage("collect")"#).exec()?; assert_eq!(Arc::strong_count(&rc), 1); + + Ok(()) } #[test] -#[should_panic] -fn test_mismatched_lua_ref() { - let lua1 = Lua::new(); - let lua2 = Lua::new(); +fn test_lua_registry_ownership() -> Result<()> { + let lua1 = make_lua(); + let lua2 = make_lua(); - let s = lua1.create_string("hello").unwrap(); - let f = lua2.create_function(|_, _: String| Ok(())).unwrap(); - - f.call::<_, ()>(s).unwrap(); -} - -#[test] -fn test_lua_registry_ownership() { - let lua1 = Lua::new(); - let lua2 = Lua::new(); - - let r1 = lua1.create_registry_value("hello").unwrap(); - let r2 = lua2.create_registry_value("hello").unwrap(); + let r1 = lua1.create_registry_value("hello")?; + let r2 = lua2.create_registry_value("hello")?; assert!(lua1.owns_registry_value(&r1)); assert!(!lua2.owns_registry_value(&r1)); assert!(lua2.owns_registry_value(&r2)); assert!(!lua1.owns_registry_value(&r2)); + + Ok(()) } #[test] -fn test_mismatched_registry_key() { - let lua1 = Lua::new(); - let lua2 = Lua::new(); +fn test_mismatched_registry_key() -> Result<()> { + let lua1 = make_lua(); + let lua2 = make_lua(); - let r = lua1.create_registry_value("hello").unwrap(); + let r = lua1.create_registry_value("hello")?; match lua2.remove_registry_value(r) { Err(Error::MismatchedRegistryKey) => {} r => panic!("wrong result type for mismatched registry key, {:?}", r), }; + + Ok(()) } #[test] -fn too_many_returns() { - let lua = Lua::new(); - let f = lua - .create_function(|_, ()| Ok(Variadic::from_iter(1..1000000))) - .unwrap(); +fn too_many_returns() -> Result<()> { + let lua = make_lua(); + let f = lua.create_function(|_, ()| Ok(Variadic::from_iter(1..1000000)))?; assert!(f.call::<_, Vec>(()).is_err()); + Ok(()) } #[test] -fn too_many_arguments() { - let lua = Lua::new(); - lua.exec::<_, ()>("function test(...) end", None).unwrap(); +fn too_many_arguments() -> Result<()> { + let lua = make_lua(); + lua.load("function test(...) end").exec()?; let args = Variadic::from_iter(1..1000000); assert!(lua .globals() - .get::<_, Function>("test") - .unwrap() + .get::<_, Function>("test")? .call::<_, ()>(args) .is_err()); + Ok(()) } #[test] -fn too_many_recursions() { - let lua = Lua::new(); - +fn too_many_recursions() -> Result<()> { + let lua = make_lua(); let f = lua - .create_function(move |lua, ()| lua.globals().get::<_, Function>("f")?.call::<_, ()>(())) - .unwrap(); - lua.globals().set("f", f).unwrap(); + .create_function(move |lua, ()| lua.globals().get::<_, Function>("f")?.call::<_, ()>(()))?; + lua.globals().set("f", f)?; assert!(lua .globals() - .get::<_, Function>("f") - .unwrap() + .get::<_, Function>("f")? .call::<_, ()>(()) .is_err()); + + Ok(()) } #[test] -fn too_many_binds() { - let lua = Lua::new(); +fn too_many_binds() -> Result<()> { + let lua = make_lua(); let globals = lua.globals(); - lua.exec::<_, ()>( + lua.load( r#" - function f(...) - end - "#, - None, + function f(...) + end + "#, ) - .unwrap(); + .exec()?; - let concat = globals.get::<_, Function>("f").unwrap(); + let concat = globals.get::<_, Function>("f")?; assert!(concat.bind(Variadic::from_iter(1..1000000)).is_err()); assert!(concat .call::<_, ()>(Variadic::from_iter(1..1000000)) .is_err()); + + Ok(()) } #[test] -fn large_args() { - let lua = Lua::new(); +fn large_args() -> Result<()> { + let lua = make_lua(); let globals = lua.globals(); - globals - .set( - "c", - lua.create_function(|_, args: Variadic| { - let mut s = 0; - for i in 0..args.len() { - s += i; - assert_eq!(i, args[i]); - } - Ok(s) - }) - .unwrap(), - ) - .unwrap(); + globals.set( + "c", + lua.create_function(|_, args: Variadic| { + let mut s = 0; + for i in 0..args.len() { + s += i; + assert_eq!(i, args[i]); + } + Ok(s) + })?, + )?; let f: Function = lua - .eval( + .load( r#" return function(...) return c(...) end "#, - None, ) - .unwrap(); + .eval()?; assert_eq!( - f.call::<_, usize>((0..100).collect::>()) - .unwrap(), + f.call::<_, usize>((0..100).collect::>())?, 4950 ); + + Ok(()) } #[test] -fn large_args_ref() { - let lua = Lua::new(); +fn large_args_ref() -> Result<()> { + let lua = make_lua(); + + let f = lua.create_function(|_, args: Variadic| { + for i in 0..args.len() { + assert_eq!(args[i], i.to_string()); + } + Ok(()) + })?; + + f.call::<_, ()>((0..100).map(|i| i.to_string()).collect::>())?; + + Ok(()) +} + +#[test] +fn chunk_env() -> Result<()> { + let lua = make_lua(); + + let assert: Function = lua.globals().get("assert")?; + + let env1 = lua.create_table()?; + env1.set("assert", assert.clone())?; + + let env2 = lua.create_table()?; + env2.set("assert", assert)?; + + lua.load( + r#" + test_var = 1 + "#, + ) + .set_environment(env1.clone())? + .exec()?; + + lua.load( + r#" + assert(test_var == nil) + test_var = 2 + "#, + ) + .set_environment(env2.clone())? + .exec()?; + + assert_eq!( + lua.load("test_var").set_environment(env1)?.eval::()?, + 1 + ); + + assert_eq!( + lua.load("test_var").set_environment(env2)?.eval::()?, + 2 + ); + + Ok(()) +} + +#[test] +fn context_thread() -> Result<()> { + let lua = make_lua(); let f = lua - .create_function(|_, args: Variadic| { - for i in 0..args.len() { - assert_eq!(args[i], i.to_string()); - } - Ok(()) - }) - .unwrap(); + .load( + r#" + local thread = ... + assert(coroutine.running() == thread) + "#, + ) + .into_function()?; - f.call::<_, ()>((0..100).map(|i| i.to_string()).collect::>()) - .unwrap(); + f.call::<_, ()>(lua.current_thread())?; + + Ok(()) } diff --git a/tests/thread.rs b/tests/thread.rs index d65fb9c..42ec643 100644 --- a/tests/thread.rs +++ b/tests/thread.rs @@ -1,16 +1,16 @@ -extern crate rlua; - use std::panic::catch_unwind; -use rlua::{Error, Function, Lua, Result, Thread, ThreadStatus}; +use rlua::{Error, Function, Result, Thread, ThreadStatus}; + +include!("_lua.rs"); #[test] -fn test_thread() { - let lua = Lua::new(); - let thread = lua - .create_thread( - lua.eval::<_, Function>( - r#" +fn test_thread() -> Result<()> { + let lua = make_lua(); + + let thread = lua.create_thread( + lua.load( + r#" function (s) local sum = s for i = 1,4 do @@ -19,101 +19,99 @@ fn test_thread() { return sum end "#, - None, - ) - .unwrap(), ) - .unwrap(); + .eval()?, + )?; assert_eq!(thread.status(), ThreadStatus::Resumable); - assert_eq!(thread.resume::<_, i64>(0).unwrap(), 0); + assert_eq!(thread.resume::<_, i64>(0)?, 0); assert_eq!(thread.status(), ThreadStatus::Resumable); - assert_eq!(thread.resume::<_, i64>(1).unwrap(), 1); + assert_eq!(thread.resume::<_, i64>(1)?, 1); assert_eq!(thread.status(), ThreadStatus::Resumable); - assert_eq!(thread.resume::<_, i64>(2).unwrap(), 3); + assert_eq!(thread.resume::<_, i64>(2)?, 3); assert_eq!(thread.status(), ThreadStatus::Resumable); - assert_eq!(thread.resume::<_, i64>(3).unwrap(), 6); + assert_eq!(thread.resume::<_, i64>(3)?, 6); assert_eq!(thread.status(), ThreadStatus::Resumable); - assert_eq!(thread.resume::<_, i64>(4).unwrap(), 10); + assert_eq!(thread.resume::<_, i64>(4)?, 10); assert_eq!(thread.status(), ThreadStatus::Unresumable); - let accumulate = lua - .create_thread( - lua.eval::<_, Function>( - r#" + let accumulate = lua.create_thread( + lua.load( + r#" function (sum) while true do sum = sum + coroutine.yield(sum) end end "#, - None, - ) - .unwrap(), ) - .unwrap(); + .eval::()?, + )?; for i in 0..4 { - accumulate.resume::<_, ()>(i).unwrap(); + accumulate.resume::<_, ()>(i)?; } - assert_eq!(accumulate.resume::<_, i64>(4).unwrap(), 10); + assert_eq!(accumulate.resume::<_, i64>(4)?, 10); assert_eq!(accumulate.status(), ThreadStatus::Resumable); assert!(accumulate.resume::<_, ()>("error").is_err()); assert_eq!(accumulate.status(), ThreadStatus::Error); let thread = lua - .eval::<_, Thread>( + .load( r#" - coroutine.create(function () - while true do - coroutine.yield(42) - end - end) - "#, - None, + coroutine.create(function () + while true do + coroutine.yield(42) + end + end) + "#, ) - .unwrap(); + .eval::()?; assert_eq!(thread.status(), ThreadStatus::Resumable); - assert_eq!(thread.resume::<_, i64>(()).unwrap(), 42); + assert_eq!(thread.resume::<_, i64>(())?, 42); let thread: Thread = lua - .eval( + .load( r#" - coroutine.create(function(arg) - assert(arg == 42) - local yieldarg = coroutine.yield(123) - assert(yieldarg == 43) - return 987 - end) - "#, - None, + coroutine.create(function(arg) + assert(arg == 42) + local yieldarg = coroutine.yield(123) + assert(yieldarg == 43) + return 987 + end) + "#, ) - .unwrap(); + .eval()?; - assert_eq!(thread.resume::<_, u32>(42).unwrap(), 123); - assert_eq!(thread.resume::<_, u32>(43).unwrap(), 987); + assert_eq!(thread.resume::<_, u32>(42)?, 123); + assert_eq!(thread.resume::<_, u32>(43)?, 987); match thread.resume::<_, u32>(()) { Err(Error::CoroutineInactive) => {} Err(_) => panic!("resuming dead coroutine error is not CoroutineInactive kind"), _ => panic!("resuming dead coroutine did not return error"), } + + Ok(()) } #[test] -fn coroutine_from_closure() { - let lua = Lua::new(); - let thrd_main = lua.create_function(|_, ()| Ok(())).unwrap(); - lua.globals().set("main", thrd_main).unwrap(); - let thrd: Thread = lua.eval("coroutine.create(main)", None).unwrap(); - thrd.resume::<_, ()>(()).unwrap(); +fn coroutine_from_closure() -> Result<()> { + let lua = make_lua(); + + let thrd_main = lua.create_function(|_, ()| Ok(()))?; + lua.globals().set("main", thrd_main)?; + let thrd: Thread = lua.load("coroutine.create(main)").eval()?; + thrd.resume::<_, ()>(())?; + + Ok(()) } #[test] fn coroutine_panic() { match catch_unwind(|| -> Result<()> { // check that coroutines propagate panics correctly - let lua = Lua::new(); + let lua = make_lua(); let thrd_main = lua.create_function(|_, ()| -> Result<()> { panic!("test_panic"); })?; diff --git a/tests/types.rs b/tests/types.rs index ef4df77..1cc2578 100644 --- a/tests/types.rs +++ b/tests/types.rs @@ -1,26 +1,28 @@ -extern crate rlua; - use std::os::raw::c_void; -use rlua::{Function, LightUserData, Lua}; +use rlua::{Function, LightUserData, Result}; + +include!("_lua.rs"); #[test] -fn test_lightuserdata() { - let lua = Lua::new(); +fn test_lightuserdata() -> Result<()> { + let lua = make_lua(); + let globals = lua.globals(); - lua.exec::<_, ()>( + lua.load( r#" - function id(a) - return a - end - "#, - None, + function id(a) + return a + end + "#, ) - .unwrap(); + .exec()?; + let res = globals - .get::<_, Function>("id") - .unwrap() - .call::<_, LightUserData>(LightUserData(42 as *mut c_void)) - .unwrap(); + .get::<_, Function>("id")? + .call::<_, LightUserData>(LightUserData(42 as *mut c_void))?; + assert_eq!(res, LightUserData(42 as *mut c_void)); + + Ok(()) } diff --git a/tests/userdata.rs b/tests/userdata.rs index 62b1fa3..edfb343 100644 --- a/tests/userdata.rs +++ b/tests/userdata.rs @@ -1,35 +1,36 @@ -extern crate failure; -extern crate rlua; - use std::sync::Arc; -use failure::err_msg; -use rlua::{ExternalError, Function, Lua, MetaMethod, String, UserData, UserDataMethods}; +use rlua::{ + AnyUserData, ExternalError, Function, MetaMethod, Result, String, UserData, UserDataMethods, +}; + +include!("_lua.rs"); #[test] -fn test_user_data() { +fn test_user_data() -> Result<()> { struct UserData1(i64); struct UserData2(Box); impl UserData for UserData1 {}; impl UserData for UserData2 {}; - let lua = Lua::new(); - - let userdata1 = lua.create_userdata(UserData1(1)).unwrap(); - let userdata2 = lua.create_userdata(UserData2(Box::new(2))).unwrap(); + let lua = make_lua(); + let userdata1 = lua.create_userdata(UserData1(1))?; + let userdata2 = lua.create_userdata(UserData2(Box::new(2)))?; assert!(userdata1.is::()); assert!(!userdata1.is::()); assert!(userdata2.is::()); assert!(!userdata2.is::()); - assert_eq!(userdata1.borrow::().unwrap().0, 1); - assert_eq!(*userdata2.borrow::().unwrap().0, 2); + assert_eq!(userdata1.borrow::()?.0, 1); + assert_eq!(*userdata2.borrow::()?.0, 2); + + Ok(()) } #[test] -fn test_methods() { +fn test_methods() -> Result<()> { struct MyUserData(i64); impl UserData for MyUserData { @@ -42,34 +43,35 @@ fn test_methods() { } } - let lua = Lua::new(); + let lua = make_lua(); let globals = lua.globals(); - let userdata = lua.create_userdata(MyUserData(42)).unwrap(); - globals.set("userdata", userdata.clone()).unwrap(); - lua.exec::<_, ()>( + let userdata = lua.create_userdata(MyUserData(42))?; + globals.set("userdata", userdata.clone())?; + lua.load( r#" - function get_it() - return userdata:get_value() - end + function get_it() + return userdata:get_value() + end - function set_it(i) - return userdata:set_value(i) - end - "#, - None, + function set_it(i) + return userdata:set_value(i) + end + "#, ) - .unwrap(); - let get = globals.get::<_, Function>("get_it").unwrap(); - let set = globals.get::<_, Function>("set_it").unwrap(); - assert_eq!(get.call::<_, i64>(()).unwrap(), 42); - userdata.borrow_mut::().unwrap().0 = 64; - assert_eq!(get.call::<_, i64>(()).unwrap(), 64); - set.call::<_, ()>(100).unwrap(); - assert_eq!(get.call::<_, i64>(()).unwrap(), 100); + .exec()?; + let get = globals.get::<_, Function>("get_it")?; + let set = globals.get::<_, Function>("set_it")?; + assert_eq!(get.call::<_, i64>(())?, 42); + userdata.borrow_mut::()?.0 = 64; + assert_eq!(get.call::<_, i64>(())?, 64); + set.call::<_, ()>(100)?; + assert_eq!(get.call::<_, i64>(())?, 100); + + Ok(()) } #[test] -fn test_metamethods() { +fn test_metamethods() -> Result<()> { #[derive(Copy, Clone)] struct MyUserData(i64); @@ -88,35 +90,30 @@ fn test_metamethods() { if index.to_str()? == "inner" { Ok(data.0) } else { - Err(err_msg("no such custom index").to_lua_err()) + Err("no such custom index".to_lua_err()) } }); } } - let lua = Lua::new(); + let lua = make_lua(); let globals = lua.globals(); - globals.set("userdata1", MyUserData(7)).unwrap(); - globals.set("userdata2", MyUserData(3)).unwrap(); + globals.set("userdata1", MyUserData(7))?; + globals.set("userdata2", MyUserData(3))?; assert_eq!( - lua.eval::<_, MyUserData>("userdata1 + userdata2", None) - .unwrap() - .0, + lua.load("userdata1 + userdata2").eval::()?.0, 10 ); - assert_eq!( - lua.eval::<_, MyUserData>("userdata1 - userdata2", None) - .unwrap() - .0, - 4 - ); - assert_eq!(lua.eval::<_, i64>("userdata1:get()", None).unwrap(), 7); - assert_eq!(lua.eval::<_, i64>("userdata2.inner", None).unwrap(), 3); - assert!(lua.eval::<_, ()>("userdata2.nonexist_field", None).is_err()); + assert_eq!(lua.load("userdata1 - userdata2").eval::()?.0, 4); + assert_eq!(lua.load("userdata1:get()").eval::()?, 7); + assert_eq!(lua.load("userdata2.inner").eval::()?, 3); + assert!(lua.load("userdata2.nonexist_field").eval::<()>().is_err()); + + Ok(()) } #[test] -fn test_gc_userdata() { +fn test_gc_userdata() -> Result<()> { struct MyUserdata { id: u8, } @@ -130,60 +127,113 @@ fn test_gc_userdata() { } } - let lua = Lua::new(); - { - let globals = lua.globals(); - globals.set("userdata", MyUserdata { id: 123 }).unwrap(); - } + let lua = make_lua(); + lua.globals().set("userdata", MyUserdata { id: 123 })?; assert!(lua - .eval::<_, ()>( + .load( r#" - local tbl = setmetatable({ - userdata = userdata - }, { __gc = function(self) - -- resurrect userdata - hatch = self.userdata - end }) + local tbl = setmetatable({ + userdata = userdata + }, { __gc = function(self) + -- resurrect userdata + hatch = self.userdata + end }) - tbl = nil - userdata = nil -- make table and userdata collectable - collectgarbage("collect") - hatch:access() - "#, - None + tbl = nil + userdata = nil -- make table and userdata collectable + collectgarbage("collect") + hatch:access() + "# ) + .exec() .is_err()); + + Ok(()) } #[test] -fn detroys_userdata() { +fn detroys_userdata() -> Result<()> { struct MyUserdata(Arc<()>); impl UserData for MyUserdata {} let rc = Arc::new(()); - let lua = Lua::new(); - { - let globals = lua.globals(); - globals.set("userdata", MyUserdata(rc.clone())).unwrap(); - } + let lua = make_lua(); + lua.globals().set("userdata", MyUserdata(rc.clone()))?; assert_eq!(Arc::strong_count(&rc), 2); - drop(lua); // should destroy all objects + + // should destroy all objects + let _ = lua.globals().raw_remove("userdata")?; + lua.gc_collect()?; + assert_eq!(Arc::strong_count(&rc), 1); + + Ok(()) } #[test] -fn user_value() { - let lua = Lua::new(); - +fn user_value() -> Result<()> { struct MyUserData; impl UserData for MyUserData {} - let ud = lua.create_userdata(MyUserData).unwrap(); - ud.set_user_value("hello").unwrap(); - assert_eq!(ud.get_user_value::().unwrap(), "hello"); + let lua = make_lua(); + let ud = lua.create_userdata(MyUserData)?; + ud.set_user_value("hello")?; + assert_eq!(ud.get_user_value::()?, "hello"); assert!(ud.get_user_value::().is_err()); + + Ok(()) +} + +#[test] +fn test_functions() -> Result<()> { + struct MyUserData(i64); + + impl UserData for MyUserData { + fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { + methods.add_function("get_value", |_, ud: AnyUserData| { + Ok(ud.borrow::()?.0) + }); + methods.add_function("set_value", |_, (ud, value): (AnyUserData, i64)| { + ud.borrow_mut::()?.0 = value; + Ok(()) + }); + methods.add_function("get_constant", |_, ()| Ok(7)); + } + } + + let lua = make_lua(); + let globals = lua.globals(); + let userdata = lua.create_userdata(MyUserData(42))?; + globals.set("userdata", userdata.clone())?; + lua.load( + r#" + function get_it() + return userdata:get_value() + end + + function set_it(i) + return userdata:set_value(i) + end + + function get_constant() + return userdata.get_constant() + end + "#, + ) + .exec()?; + let get = globals.get::<_, Function>("get_it")?; + let set = globals.get::<_, Function>("set_it")?; + let get_constant = globals.get::<_, Function>("get_constant")?; + assert_eq!(get.call::<_, i64>(())?, 42); + userdata.borrow_mut::()?.0 = 64; + assert_eq!(get.call::<_, i64>(())?, 64); + set.call::<_, ()>(100)?; + assert_eq!(get.call::<_, i64>(())?, 100); + assert_eq!(get_constant.call::<_, i64>(())?, 7); + + Ok(()) }