Update tests (excl. compile-fail)

This commit is contained in:
Alex Orlenko 2019-09-28 15:23:17 +01:00
parent 45159bfda7
commit 54f4627195
12 changed files with 1086 additions and 844 deletions

53
tests/_lua.rs Normal file
View File

@ -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)
}
}

98
tests/byte_string.rs Normal file
View File

@ -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(())
}

View File

@ -1,17 +1,14 @@
#![cfg(feature = "compiletest_rs")]
extern crate compiletest_rs as compiletest;
use std::path::PathBuf; use std::path::PathBuf;
fn run_mode(mode: &'static str) { 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.mode = mode.parse().expect("Invalid mode");
config.src_base = PathBuf::from(format!("tests/{}", 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] #[test]

View File

@ -1,30 +1,33 @@
extern crate rlua; use rlua::{Function, Result, String};
use rlua::{Function, Lua, String}; include!("_lua.rs");
#[test] #[test]
fn test_function() { fn test_function() -> Result<()> {
let lua = Lua::new(); let lua = make_lua();
let globals = lua.globals(); let globals = lua.globals();
lua.exec::<_, ()>( lua.load(
r#" r#"
function concat(arg1, arg2) function concat(arg1, arg2)
return arg1 .. arg2 return arg1 .. arg2
end end
"#, "#,
None,
) )
.unwrap(); .exec()?;
let concat = globals.get::<_, Function>("concat").unwrap(); let concat = globals.get::<_, Function>("concat")?;
assert_eq!(concat.call::<_, String>(("foo", "bar")).unwrap(), "foobar"); assert_eq!(concat.call::<_, String>(("foo", "bar"))?, "foobar");
Ok(())
} }
#[test] #[test]
fn test_bind() { fn test_bind() -> Result<()> {
let lua = Lua::new(); let lua = make_lua();
let globals = lua.globals(); let globals = lua.globals();
lua.exec::<_, ()>( lua.load(
r#" r#"
function concat(...) function concat(...)
local res = "" local res = ""
@ -34,25 +37,27 @@ fn test_bind() {
return res return res
end end
"#, "#,
None,
) )
.unwrap(); .exec()?;
let mut concat = globals.get::<_, Function>("concat").unwrap(); let mut concat = globals.get::<_, Function>("concat")?;
concat = concat.bind("foo").unwrap(); concat = concat.bind("foo")?;
concat = concat.bind("bar").unwrap(); concat = concat.bind("bar")?;
concat = concat.bind(("baz", "baf")).unwrap(); concat = concat.bind(("baz", "baf"))?;
assert_eq!( assert_eq!(
concat.call::<_, String>(("hi", "wut")).unwrap(), concat.call::<_, String>(("hi", "wut"))?,
"foobarbazbafhiwut" "foobarbazbafhiwut"
); );
Ok(())
} }
#[test] #[test]
fn test_rust_function() { fn test_rust_function() -> Result<()> {
let lua = Lua::new(); let lua = make_lua();
let globals = lua.globals(); let globals = lua.globals();
lua.exec::<_, ()>( lua.load(
r#" r#"
function lua_function() function lua_function()
return rust_function() return rust_function()
@ -61,13 +66,14 @@ fn test_rust_function() {
-- Test to make sure chunk return is ignored -- Test to make sure chunk return is ignored
return 1 return 1
"#, "#,
None,
) )
.unwrap(); .exec()?;
let lua_function = globals.get::<_, Function>("lua_function").unwrap(); let lua_function = globals.get::<_, Function>("lua_function")?;
let rust_function = lua.create_function(|_, ()| Ok("hello")).unwrap(); let rust_function = lua.create_function(|_, ()| Ok("hello"))?;
globals.set("rust_function", rust_function).unwrap(); globals.set("rust_function", rust_function)?;
assert_eq!(lua_function.call::<_, String>(()).unwrap(), "hello"); assert_eq!(lua_function.call::<_, String>(())?, "hello");
Ok(())
} }

56
tests/memory.rs Normal file
View File

@ -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"),
}
}

View File

@ -1,44 +1,40 @@
extern crate rlua;
use std::cell::Cell; use std::cell::Cell;
use std::rc::Rc; 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] #[test]
fn scope_func() { fn scope_func() -> Result<()> {
let lua = Lua::new(); let lua = make_lua();
let rc = Rc::new(Cell::new(0)); let rc = Rc::new(Cell::new(0));
lua.scope(|scope| { lua.scope(|scope| {
let r = rc.clone(); let r = rc.clone();
let f = scope let f = scope.create_function(move |_, ()| {
.create_function(move |_, ()| { r.set(42);
r.set(42); Ok(())
Ok(()) })?;
}) lua.globals().set("bad", f.clone())?;
.unwrap(); f.call::<_, ()>(())?;
lua.globals().set("bad", f.clone()).unwrap();
f.call::<_, ()>(()).unwrap();
assert_eq!(Rc::strong_count(&rc), 2); assert_eq!(Rc::strong_count(&rc), 2);
}); Ok(())
})?;
assert_eq!(rc.get(), 42); assert_eq!(rc.get(), 42);
assert_eq!(Rc::strong_count(&rc), 1); assert_eq!(Rc::strong_count(&rc), 1);
match lua match lua.globals().get::<_, Function>("bad")?.call::<_, ()>(()) {
.globals()
.get::<_, Function>("bad")
.unwrap()
.call::<_, ()>(())
{
Err(Error::CallbackError { .. }) => {} Err(Error::CallbackError { .. }) => {}
r => panic!("improper return for destructed function: {:?}", r), r => panic!("improper return for destructed function: {:?}", r),
}; };
Ok(())
} }
#[test] #[test]
fn scope_drop() { fn scope_drop() -> Result<()> {
let lua = Lua::new(); let lua = make_lua();
struct MyUserdata(Rc<()>); struct MyUserdata(Rc<()>);
impl UserData for MyUserdata { impl UserData for MyUserdata {
@ -50,27 +46,26 @@ fn scope_drop() {
let rc = Rc::new(()); let rc = Rc::new(());
lua.scope(|scope| { lua.scope(|scope| {
lua.globals() lua.globals().set(
.set( "test",
"test", scope.create_static_userdata(MyUserdata(rc.clone()))?,
scope )?;
.create_static_userdata(MyUserdata(rc.clone()))
.unwrap(),
)
.unwrap();
assert_eq!(Rc::strong_count(&rc), 2); assert_eq!(Rc::strong_count(&rc), 2);
}); Ok(())
})?;
assert_eq!(Rc::strong_count(&rc), 1); assert_eq!(Rc::strong_count(&rc), 1);
match lua.exec::<_, ()>("test:method()", None) { match lua.load("test:method()").exec() {
Err(Error::CallbackError { .. }) => {} Err(Error::CallbackError { .. }) => {}
r => panic!("improper return for destructed userdata: {:?}", r), r => panic!("improper return for destructed userdata: {:?}", r),
}; };
Ok(())
} }
#[test] #[test]
fn scope_capture() { fn scope_capture() -> Result<()> {
let lua = Lua::new(); let lua = make_lua();
let mut i = 0; let mut i = 0;
lua.scope(|scope| { lua.scope(|scope| {
@ -78,33 +73,31 @@ fn scope_capture() {
.create_function_mut(|_, ()| { .create_function_mut(|_, ()| {
i = 42; i = 42;
Ok(()) Ok(())
}) })?
.unwrap()
.call::<_, ()>(()) .call::<_, ()>(())
.unwrap(); })?;
});
assert_eq!(i, 42); assert_eq!(i, 42);
Ok(())
} }
#[test] #[test]
fn outer_lua_access() { fn outer_lua_access() -> Result<()> {
let lua = Lua::new(); let lua = make_lua();
let table = lua.create_table().unwrap();
let table = lua.create_table()?;
lua.scope(|scope| { lua.scope(|scope| {
scope scope
.create_function_mut(|_, ()| { .create_function_mut(|_, ()| table.set("a", "b"))?
table.set("a", "b").unwrap();
Ok(())
})
.unwrap()
.call::<_, ()>(()) .call::<_, ()>(())
.unwrap(); })?;
}); assert_eq!(table.get::<_, String>("a")?, "b");
assert_eq!(table.get::<_, String>("a").unwrap(), "b");
Ok(())
} }
#[test] #[test]
fn scope_userdata_methods() { fn scope_userdata_methods() -> Result<()> {
struct MyUserData<'a>(&'a Cell<i64>); struct MyUserData<'a>(&'a Cell<i64>);
impl<'a> UserData for MyUserData<'a> { 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); let i = Cell::new(42);
lua.scope(|scope| { let f: Function = lua
let f: Function = lua .load(
.eval( r#"
r#" function(u)
function(u) u:inc()
u:inc() u:inc()
u:inc() u:inc()
u:inc() u:dec()
u:dec() end
end "#,
"#, )
None, .eval()?;
)
.unwrap();
f.call::<_, ()>(scope.create_nonstatic_userdata(MyUserData(&i)).unwrap()) lua.scope(|scope| f.call::<_, ()>(scope.create_nonstatic_userdata(MyUserData(&i))?))?;
.unwrap();
});
assert_eq!(i.get(), 44); assert_eq!(i.get(), 44);
Ok(())
} }
#[test] #[test]
fn scope_userdata_functions() { fn scope_userdata_functions() -> Result<()> {
struct MyUserData<'a>(&'a i64); struct MyUserData<'a>(&'a i64);
impl<'a> UserData for MyUserData<'a> { impl<'a> UserData for MyUserData<'a> {
@ -165,32 +156,31 @@ fn scope_userdata_functions() {
} }
} }
let lua = Lua::new(); let lua = make_lua();
let f = lua
.exec::<_, Function>(
r#"
i = 0
return function(u)
_ = u + u
_ = u - 1
_ = 1 + u
end
"#,
None,
)
.unwrap();
let dummy = 0; let dummy = 0;
lua.scope(|scope| { let f = lua
f.call::<_, ()>(scope.create_nonstatic_userdata(MyUserData(&dummy)).unwrap()) .load(
.unwrap(); r#"
}); i = 0
return function(u)
_ = u + u
_ = u - 1
_ = 1 + u
end
"#,
)
.eval::<Function>()?;
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] #[test]
fn scope_userdata_mismatch() { fn scope_userdata_mismatch() -> Result<()> {
struct MyUserData<'a>(&'a Cell<i64>); struct MyUserData<'a>(&'a Cell<i64>);
impl<'a> UserData for MyUserData<'a> { impl<'a> UserData for MyUserData<'a> {
@ -202,31 +192,31 @@ fn scope_userdata_mismatch() {
} }
} }
let lua = Lua::new(); let lua = make_lua();
lua.exec::<_, ()>(
r#"
function okay(a, b)
a.inc(a)
b.inc(b)
end
function bad(a, b) lua.load(
a.inc(b) r#"
end function okay(a, b)
"#, a.inc(a)
None, b.inc(b)
end
function bad(a, b)
a.inc(b)
end
"#,
) )
.unwrap(); .exec()?;
let a = Cell::new(1); let a = Cell::new(1);
let b = Cell::new(1); let b = Cell::new(1);
let okay: Function = lua.globals().get("okay").unwrap(); let okay: Function = lua.globals().get("okay")?;
let bad: Function = lua.globals().get("bad").unwrap(); let bad: Function = lua.globals().get("bad")?;
lua.scope(|scope| { lua.scope(|scope| {
let au = scope.create_nonstatic_userdata(MyUserData(&a)).unwrap(); let au = scope.create_nonstatic_userdata(MyUserData(&a))?;
let bu = scope.create_nonstatic_userdata(MyUserData(&b)).unwrap(); let bu = scope.create_nonstatic_userdata(MyUserData(&b))?;
assert!(okay.call::<_, ()>((au.clone(), bu.clone())).is_ok()); assert!(okay.call::<_, ()>((au.clone(), bu.clone())).is_ok());
match bad.call::<_, ()>((au, bu)) { match bad.call::<_, ()>((au, bu)) {
Err(Error::CallbackError { ref cause, .. }) => match *cause.as_ref() { Err(Error::CallbackError { ref cause, .. }) => match *cause.as_ref() {
@ -236,5 +226,8 @@ fn scope_userdata_mismatch() {
Err(other) => panic!("wrong error type {:?}", other), Err(other) => panic!("wrong error type {:?}", other),
Ok(_) => panic!("incorrectly returned Ok"), Ok(_) => panic!("incorrectly returned Ok"),
} }
}); Ok(())
})?;
Ok(())
} }

View File

@ -1,20 +1,15 @@
extern crate rlua;
use std::borrow::Cow; use std::borrow::Cow;
use rlua::{Lua, String}; use rlua::{Result, String};
fn with_str<F>(s: &str, f: F) include!("_lua.rs");
where
F: FnOnce(String),
{
let lua = Lua::new();
let string = lua.create_string(s).unwrap();
f(string);
}
#[test] #[test]
fn compare() { fn compare() {
fn with_str<F: FnOnce(String)>(s: &str, f: F) {
f(make_lua().create_string(s).unwrap());
}
// Tests that all comparisons we want to have are usable // 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, "teststring")); // &str
with_str("teststring", |t| assert_eq!(t, b"teststring")); // &[u8] with_str("teststring", |t| assert_eq!(t, b"teststring")); // &[u8]
@ -28,27 +23,24 @@ fn compare() {
} }
#[test] #[test]
fn string_views() { fn string_views() -> Result<()> {
let lua = Lua::new(); let lua = make_lua();
lua.eval::<_, ()>(
lua.load(
r#" r#"
ok = "null bytes are valid utf-8, wh\0 knew?" ok = "null bytes are valid utf-8, wh\0 knew?"
err = "but \xff isn't :(" err = "but \xff isn't :("
empty = "" empty = ""
"#, "#,
None,
) )
.unwrap(); .exec()?;
let globals = lua.globals(); let globals = lua.globals();
let ok: String = globals.get("ok").unwrap(); let ok: String = globals.get("ok")?;
let err: String = globals.get("err").unwrap(); let err: String = globals.get("err")?;
let empty: String = globals.get("empty").unwrap(); let empty: String = globals.get("empty")?;
assert_eq!( assert_eq!(ok.to_str()?, "null bytes are valid utf-8, wh\0 knew?");
ok.to_str().unwrap(),
"null bytes are valid utf-8, wh\0 knew?"
);
assert_eq!( assert_eq!(
ok.as_bytes(), ok.as_bytes(),
&b"null bytes are valid utf-8, wh\0 knew?"[..] &b"null bytes are valid utf-8, wh\0 knew?"[..]
@ -57,14 +49,19 @@ fn string_views() {
assert!(err.to_str().is_err()); assert!(err.to_str().is_err());
assert_eq!(err.as_bytes(), &b"but \xff isn't :("[..]); 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_with_nul(), &[0]);
assert_eq!(empty.as_bytes(), &[]); assert_eq!(empty.as_bytes(), &[]);
Ok(())
} }
#[test] #[test]
fn raw_string() { fn raw_string() -> Result<()> {
let lua = Lua::new(); let lua = make_lua();
let rs = lua.create_string(&[0, 1, 2, 3, 0, 1, 2, 3]).unwrap();
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]); assert_eq!(rs.as_bytes(), &[0, 1, 2, 3, 0, 1, 2, 3]);
Ok(())
} }

View File

@ -1,182 +1,174 @@
extern crate rlua; use rlua::{Nil, Result, Table, Value};
use rlua::{Lua, Nil, Result, Table, Value}; include!("_lua.rs");
#[test] #[test]
fn test_set_get() { fn test_set_get() -> Result<()> {
let lua = Lua::new(); let lua = make_lua();
let globals = lua.globals(); let globals = lua.globals();
globals.set("foo", "bar").unwrap(); globals.set("foo", "bar")?;
globals.set("baz", "baf").unwrap(); globals.set("baz", "baf")?;
assert_eq!(globals.get::<_, String>("foo").unwrap(), "bar"); assert_eq!(globals.get::<_, String>("foo")?, "bar");
assert_eq!(globals.get::<_, String>("baz").unwrap(), "baf"); assert_eq!(globals.get::<_, String>("baz")?, "baf");
Ok(())
} }
#[test] #[test]
fn test_table() { fn test_table() -> Result<()> {
let lua = Lua::new(); let lua = make_lua();
let globals = lua.globals(); let globals = lua.globals();
globals.set("table", lua.create_table().unwrap()).unwrap(); globals.set("table", lua.create_table()?)?;
let table1: Table = globals.get("table").unwrap(); let table1: Table = globals.get("table")?;
let table2: Table = globals.get("table").unwrap(); let table2: Table = globals.get("table")?;
table1.set("foo", "bar").unwrap(); table1.set("foo", "bar")?;
table2.set("baz", "baf").unwrap(); table2.set("baz", "baf")?;
assert_eq!(table2.get::<_, String>("foo").unwrap(), "bar"); assert_eq!(table2.get::<_, String>("foo")?, "bar");
assert_eq!(table1.get::<_, String>("baz").unwrap(), "baf"); assert_eq!(table1.get::<_, String>("baz")?, "baf");
lua.exec::<_, ()>( lua.load(
r#" r#"
table1 = {1, 2, 3, 4, 5} table1 = {1, 2, 3, 4, 5}
table2 = {} table2 = {}
table3 = {1, 2, nil, 4, 5} table3 = {1, 2, nil, 4, 5}
"#, "#,
None,
) )
.unwrap(); .exec()?;
let table1 = globals.get::<_, Table>("table1").unwrap(); let table1 = globals.get::<_, Table>("table1")?;
let table2 = globals.get::<_, Table>("table2").unwrap(); let table2 = globals.get::<_, Table>("table2")?;
let table3 = globals.get::<_, Table>("table3").unwrap(); let table3 = globals.get::<_, Table>("table3")?;
assert_eq!(table1.len().unwrap(), 5); assert_eq!(table1.len()?, 5);
assert_eq!( assert_eq!(
table1 table1
.clone() .clone()
.pairs() .pairs()
.collect::<Result<Vec<(i64, i64)>>>() .collect::<Result<Vec<(i64, i64)>>>()?,
.unwrap(),
vec![(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)] vec![(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)]
); );
assert_eq!( assert_eq!(
table1 table1
.clone() .clone()
.sequence_values() .sequence_values()
.collect::<Result<Vec<i64>>>() .collect::<Result<Vec<i64>>>()?,
.unwrap(),
vec![1, 2, 3, 4, 5] vec![1, 2, 3, 4, 5]
); );
assert_eq!(table2.len().unwrap(), 0); assert_eq!(table2.len()?, 0);
assert_eq!( assert_eq!(
table2 table2
.clone() .clone()
.pairs() .pairs()
.collect::<Result<Vec<(i64, i64)>>>() .collect::<Result<Vec<(i64, i64)>>>()?,
.unwrap(),
vec![] vec![]
); );
assert_eq!( assert_eq!(
table2 table2.sequence_values().collect::<Result<Vec<i64>>>()?,
.sequence_values()
.collect::<Result<Vec<i64>>>()
.unwrap(),
vec![] vec![]
); );
// sequence_values should only iterate until the first border // sequence_values should only iterate until the first border
assert_eq!( assert_eq!(
table3 table3.sequence_values().collect::<Result<Vec<i64>>>()?,
.sequence_values()
.collect::<Result<Vec<i64>>>()
.unwrap(),
vec![1, 2] vec![1, 2]
); );
globals globals.set("table4", lua.create_sequence_from(vec![1, 2, 3, 4, 5])?)?;
.set( let table4 = globals.get::<_, Table>("table4")?;
"table4",
lua.create_sequence_from(vec![1, 2, 3, 4, 5]).unwrap(),
)
.unwrap();
let table4 = globals.get::<_, Table>("table4").unwrap();
assert_eq!( assert_eq!(
table4.pairs().collect::<Result<Vec<(i64, i64)>>>().unwrap(), table4.pairs().collect::<Result<Vec<(i64, i64)>>>()?,
vec![(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)] vec![(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)]
); );
Ok(())
} }
#[test] #[test]
fn test_table_scope() { fn test_table_scope() -> Result<()> {
let lua = Lua::new(); let lua = make_lua();
let globals = lua.globals(); let globals = lua.globals();
lua.exec::<_, ()>( lua.load(
r#" r#"
touter = { touter = {
tin = {1, 2, 3} tin = {1, 2, 3}
} }
"#, "#,
None,
) )
.unwrap(); .exec()?;
// Make sure that table gets do not borrow the table, but instead just borrow lua. // Make sure that table gets do not borrow the table, but instead just borrow lua.
let tin; let tin;
{ {
let touter = globals.get::<_, Table>("touter").unwrap(); let touter = globals.get::<_, Table>("touter")?;
tin = touter.get::<_, Table>("tin").unwrap(); tin = touter.get::<_, Table>("tin")?;
} }
assert_eq!(tin.get::<_, i64>(1).unwrap(), 1); assert_eq!(tin.get::<_, i64>(1)?, 1);
assert_eq!(tin.get::<_, i64>(2).unwrap(), 2); assert_eq!(tin.get::<_, i64>(2)?, 2);
assert_eq!(tin.get::<_, i64>(3).unwrap(), 3); assert_eq!(tin.get::<_, i64>(3)?, 3);
Ok(())
} }
#[test] #[test]
fn test_metatable() { fn test_metatable() -> Result<()> {
let lua = Lua::new(); let lua = make_lua();
let table = lua.create_table().unwrap(); let table = lua.create_table()?;
let metatable = lua.create_table().unwrap(); let metatable = lua.create_table()?;
metatable metatable.set("__index", lua.create_function(|_, ()| Ok("index_value"))?)?;
.set(
"__index",
lua.create_function(|_, ()| Ok("index_value")).unwrap(),
)
.unwrap();
table.set_metatable(Some(metatable)); table.set_metatable(Some(metatable));
assert_eq!(table.get::<_, String>("any_key").unwrap(), "index_value"); assert_eq!(table.get::<_, String>("any_key")?, "index_value");
match table.raw_get::<_, Value>("any_key").unwrap() { match table.raw_get::<_, Value>("any_key")? {
Nil => {} Nil => {}
_ => panic!(), _ => panic!(),
} }
table.set_metatable(None); table.set_metatable(None);
match table.get::<_, Value>("any_key").unwrap() { match table.get::<_, Value>("any_key")? {
Nil => {} Nil => {}
_ => panic!(), _ => panic!(),
}; };
Ok(())
} }
#[test] #[test]
fn test_table_error() { fn test_table_error() -> Result<()> {
let lua = Lua::new(); let lua = make_lua();
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();
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.set(1, 1).is_err());
assert!(bad_table.get::<_, i32>(1).is_err()); assert!(bad_table.get::<_, i32>(1).is_err());
assert!(bad_table.len().is_err()); assert!(bad_table.len().is_err());
assert!(bad_table.raw_set(1, 1).is_ok()); assert!(bad_table.raw_set(1, 1).is_ok());
assert!(bad_table.raw_get::<_, i32>(1).is_ok()); assert!(bad_table.raw_get::<_, i32>(1).is_ok());
assert_eq!(bad_table.raw_len(), 1); assert_eq!(bad_table.raw_len(), 1);
Ok(())
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,16 +1,16 @@
extern crate rlua;
use std::panic::catch_unwind; use std::panic::catch_unwind;
use rlua::{Error, Function, Lua, Result, Thread, ThreadStatus}; use rlua::{Error, Function, Result, Thread, ThreadStatus};
include!("_lua.rs");
#[test] #[test]
fn test_thread() { fn test_thread() -> Result<()> {
let lua = Lua::new(); let lua = make_lua();
let thread = lua
.create_thread( let thread = lua.create_thread(
lua.eval::<_, Function>( lua.load(
r#" r#"
function (s) function (s)
local sum = s local sum = s
for i = 1,4 do for i = 1,4 do
@ -19,101 +19,99 @@ fn test_thread() {
return sum return sum
end end
"#, "#,
None,
)
.unwrap(),
) )
.unwrap(); .eval()?,
)?;
assert_eq!(thread.status(), ThreadStatus::Resumable); 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.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.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.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.status(), ThreadStatus::Resumable);
assert_eq!(thread.resume::<_, i64>(4).unwrap(), 10); assert_eq!(thread.resume::<_, i64>(4)?, 10);
assert_eq!(thread.status(), ThreadStatus::Unresumable); assert_eq!(thread.status(), ThreadStatus::Unresumable);
let accumulate = lua let accumulate = lua.create_thread(
.create_thread( lua.load(
lua.eval::<_, Function>( r#"
r#"
function (sum) function (sum)
while true do while true do
sum = sum + coroutine.yield(sum) sum = sum + coroutine.yield(sum)
end end
end end
"#, "#,
None,
)
.unwrap(),
) )
.unwrap(); .eval::<Function>()?,
)?;
for i in 0..4 { 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_eq!(accumulate.status(), ThreadStatus::Resumable);
assert!(accumulate.resume::<_, ()>("error").is_err()); assert!(accumulate.resume::<_, ()>("error").is_err());
assert_eq!(accumulate.status(), ThreadStatus::Error); assert_eq!(accumulate.status(), ThreadStatus::Error);
let thread = lua let thread = lua
.eval::<_, Thread>( .load(
r#" r#"
coroutine.create(function () coroutine.create(function ()
while true do while true do
coroutine.yield(42) coroutine.yield(42)
end end
end) end)
"#, "#,
None,
) )
.unwrap(); .eval::<Thread>()?;
assert_eq!(thread.status(), ThreadStatus::Resumable); assert_eq!(thread.status(), ThreadStatus::Resumable);
assert_eq!(thread.resume::<_, i64>(()).unwrap(), 42); assert_eq!(thread.resume::<_, i64>(())?, 42);
let thread: Thread = lua let thread: Thread = lua
.eval( .load(
r#" r#"
coroutine.create(function(arg) coroutine.create(function(arg)
assert(arg == 42) assert(arg == 42)
local yieldarg = coroutine.yield(123) local yieldarg = coroutine.yield(123)
assert(yieldarg == 43) assert(yieldarg == 43)
return 987 return 987
end) end)
"#, "#,
None,
) )
.unwrap(); .eval()?;
assert_eq!(thread.resume::<_, u32>(42).unwrap(), 123); assert_eq!(thread.resume::<_, u32>(42)?, 123);
assert_eq!(thread.resume::<_, u32>(43).unwrap(), 987); assert_eq!(thread.resume::<_, u32>(43)?, 987);
match thread.resume::<_, u32>(()) { match thread.resume::<_, u32>(()) {
Err(Error::CoroutineInactive) => {} Err(Error::CoroutineInactive) => {}
Err(_) => panic!("resuming dead coroutine error is not CoroutineInactive kind"), Err(_) => panic!("resuming dead coroutine error is not CoroutineInactive kind"),
_ => panic!("resuming dead coroutine did not return error"), _ => panic!("resuming dead coroutine did not return error"),
} }
Ok(())
} }
#[test] #[test]
fn coroutine_from_closure() { fn coroutine_from_closure() -> Result<()> {
let lua = Lua::new(); let lua = make_lua();
let thrd_main = lua.create_function(|_, ()| Ok(())).unwrap();
lua.globals().set("main", thrd_main).unwrap(); let thrd_main = lua.create_function(|_, ()| Ok(()))?;
let thrd: Thread = lua.eval("coroutine.create(main)", None).unwrap(); lua.globals().set("main", thrd_main)?;
thrd.resume::<_, ()>(()).unwrap(); let thrd: Thread = lua.load("coroutine.create(main)").eval()?;
thrd.resume::<_, ()>(())?;
Ok(())
} }
#[test] #[test]
fn coroutine_panic() { fn coroutine_panic() {
match catch_unwind(|| -> Result<()> { match catch_unwind(|| -> Result<()> {
// check that coroutines propagate panics correctly // check that coroutines propagate panics correctly
let lua = Lua::new(); let lua = make_lua();
let thrd_main = lua.create_function(|_, ()| -> Result<()> { let thrd_main = lua.create_function(|_, ()| -> Result<()> {
panic!("test_panic"); panic!("test_panic");
})?; })?;

View File

@ -1,26 +1,28 @@
extern crate rlua;
use std::os::raw::c_void; use std::os::raw::c_void;
use rlua::{Function, LightUserData, Lua}; use rlua::{Function, LightUserData, Result};
include!("_lua.rs");
#[test] #[test]
fn test_lightuserdata() { fn test_lightuserdata() -> Result<()> {
let lua = Lua::new(); let lua = make_lua();
let globals = lua.globals(); let globals = lua.globals();
lua.exec::<_, ()>( lua.load(
r#" r#"
function id(a) function id(a)
return a return a
end end
"#, "#,
None,
) )
.unwrap(); .exec()?;
let res = globals let res = globals
.get::<_, Function>("id") .get::<_, Function>("id")?
.unwrap() .call::<_, LightUserData>(LightUserData(42 as *mut c_void))?;
.call::<_, LightUserData>(LightUserData(42 as *mut c_void))
.unwrap();
assert_eq!(res, LightUserData(42 as *mut c_void)); assert_eq!(res, LightUserData(42 as *mut c_void));
Ok(())
} }

View File

@ -1,35 +1,36 @@
extern crate failure;
extern crate rlua;
use std::sync::Arc; use std::sync::Arc;
use failure::err_msg; use rlua::{
use rlua::{ExternalError, Function, Lua, MetaMethod, String, UserData, UserDataMethods}; AnyUserData, ExternalError, Function, MetaMethod, Result, String, UserData, UserDataMethods,
};
include!("_lua.rs");
#[test] #[test]
fn test_user_data() { fn test_user_data() -> Result<()> {
struct UserData1(i64); struct UserData1(i64);
struct UserData2(Box<i64>); struct UserData2(Box<i64>);
impl UserData for UserData1 {}; impl UserData for UserData1 {};
impl UserData for UserData2 {}; impl UserData for UserData2 {};
let lua = Lua::new(); let lua = make_lua();
let userdata1 = lua.create_userdata(UserData1(1))?;
let userdata1 = lua.create_userdata(UserData1(1)).unwrap(); let userdata2 = lua.create_userdata(UserData2(Box::new(2)))?;
let userdata2 = lua.create_userdata(UserData2(Box::new(2))).unwrap();
assert!(userdata1.is::<UserData1>()); assert!(userdata1.is::<UserData1>());
assert!(!userdata1.is::<UserData2>()); assert!(!userdata1.is::<UserData2>());
assert!(userdata2.is::<UserData2>()); assert!(userdata2.is::<UserData2>());
assert!(!userdata2.is::<UserData1>()); assert!(!userdata2.is::<UserData1>());
assert_eq!(userdata1.borrow::<UserData1>().unwrap().0, 1); assert_eq!(userdata1.borrow::<UserData1>()?.0, 1);
assert_eq!(*userdata2.borrow::<UserData2>().unwrap().0, 2); assert_eq!(*userdata2.borrow::<UserData2>()?.0, 2);
Ok(())
} }
#[test] #[test]
fn test_methods() { fn test_methods() -> Result<()> {
struct MyUserData(i64); struct MyUserData(i64);
impl UserData for MyUserData { impl UserData for MyUserData {
@ -42,34 +43,35 @@ fn test_methods() {
} }
} }
let lua = Lua::new(); let lua = make_lua();
let globals = lua.globals(); let globals = lua.globals();
let userdata = lua.create_userdata(MyUserData(42)).unwrap(); let userdata = lua.create_userdata(MyUserData(42))?;
globals.set("userdata", userdata.clone()).unwrap(); globals.set("userdata", userdata.clone())?;
lua.exec::<_, ()>( lua.load(
r#" r#"
function get_it() function get_it()
return userdata:get_value() return userdata:get_value()
end end
function set_it(i) function set_it(i)
return userdata:set_value(i) return userdata:set_value(i)
end end
"#, "#,
None,
) )
.unwrap(); .exec()?;
let get = globals.get::<_, Function>("get_it").unwrap(); let get = globals.get::<_, Function>("get_it")?;
let set = globals.get::<_, Function>("set_it").unwrap(); let set = globals.get::<_, Function>("set_it")?;
assert_eq!(get.call::<_, i64>(()).unwrap(), 42); assert_eq!(get.call::<_, i64>(())?, 42);
userdata.borrow_mut::<MyUserData>().unwrap().0 = 64; userdata.borrow_mut::<MyUserData>()?.0 = 64;
assert_eq!(get.call::<_, i64>(()).unwrap(), 64); assert_eq!(get.call::<_, i64>(())?, 64);
set.call::<_, ()>(100).unwrap(); set.call::<_, ()>(100)?;
assert_eq!(get.call::<_, i64>(()).unwrap(), 100); assert_eq!(get.call::<_, i64>(())?, 100);
Ok(())
} }
#[test] #[test]
fn test_metamethods() { fn test_metamethods() -> Result<()> {
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
struct MyUserData(i64); struct MyUserData(i64);
@ -88,35 +90,30 @@ fn test_metamethods() {
if index.to_str()? == "inner" { if index.to_str()? == "inner" {
Ok(data.0) Ok(data.0)
} else { } 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(); let globals = lua.globals();
globals.set("userdata1", MyUserData(7)).unwrap(); globals.set("userdata1", MyUserData(7))?;
globals.set("userdata2", MyUserData(3)).unwrap(); globals.set("userdata2", MyUserData(3))?;
assert_eq!( assert_eq!(
lua.eval::<_, MyUserData>("userdata1 + userdata2", None) lua.load("userdata1 + userdata2").eval::<MyUserData>()?.0,
.unwrap()
.0,
10 10
); );
assert_eq!( assert_eq!(lua.load("userdata1 - userdata2").eval::<MyUserData>()?.0, 4);
lua.eval::<_, MyUserData>("userdata1 - userdata2", None) assert_eq!(lua.load("userdata1:get()").eval::<i64>()?, 7);
.unwrap() assert_eq!(lua.load("userdata2.inner").eval::<i64>()?, 3);
.0, assert!(lua.load("userdata2.nonexist_field").eval::<()>().is_err());
4
); Ok(())
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());
} }
#[test] #[test]
fn test_gc_userdata() { fn test_gc_userdata() -> Result<()> {
struct MyUserdata { struct MyUserdata {
id: u8, id: u8,
} }
@ -130,60 +127,113 @@ fn test_gc_userdata() {
} }
} }
let lua = Lua::new(); let lua = make_lua();
{ lua.globals().set("userdata", MyUserdata { id: 123 })?;
let globals = lua.globals();
globals.set("userdata", MyUserdata { id: 123 }).unwrap();
}
assert!(lua assert!(lua
.eval::<_, ()>( .load(
r#" r#"
local tbl = setmetatable({ local tbl = setmetatable({
userdata = userdata userdata = userdata
}, { __gc = function(self) }, { __gc = function(self)
-- resurrect userdata -- resurrect userdata
hatch = self.userdata hatch = self.userdata
end }) end })
tbl = nil tbl = nil
userdata = nil -- make table and userdata collectable userdata = nil -- make table and userdata collectable
collectgarbage("collect") collectgarbage("collect")
hatch:access() hatch:access()
"#, "#
None
) )
.exec()
.is_err()); .is_err());
Ok(())
} }
#[test] #[test]
fn detroys_userdata() { fn detroys_userdata() -> Result<()> {
struct MyUserdata(Arc<()>); struct MyUserdata(Arc<()>);
impl UserData for MyUserdata {} impl UserData for MyUserdata {}
let rc = Arc::new(()); let rc = Arc::new(());
let lua = Lua::new(); let lua = make_lua();
{ lua.globals().set("userdata", MyUserdata(rc.clone()))?;
let globals = lua.globals();
globals.set("userdata", MyUserdata(rc.clone())).unwrap();
}
assert_eq!(Arc::strong_count(&rc), 2); 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); assert_eq!(Arc::strong_count(&rc), 1);
Ok(())
} }
#[test] #[test]
fn user_value() { fn user_value() -> Result<()> {
let lua = Lua::new();
struct MyUserData; struct MyUserData;
impl UserData for MyUserData {} impl UserData for MyUserData {}
let ud = lua.create_userdata(MyUserData).unwrap(); let lua = make_lua();
ud.set_user_value("hello").unwrap(); let ud = lua.create_userdata(MyUserData)?;
assert_eq!(ud.get_user_value::<String>().unwrap(), "hello"); ud.set_user_value("hello")?;
assert_eq!(ud.get_user_value::<String>()?, "hello");
assert!(ud.get_user_value::<u32>().is_err()); assert!(ud.get_user_value::<u32>().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::<MyUserData>()?.0)
});
methods.add_function("set_value", |_, (ud, value): (AnyUserData, i64)| {
ud.borrow_mut::<MyUserData>()?.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::<MyUserData>()?.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(())
} }