use mlua::{Error, Lua, Nil, Result, Table, TableExt, Value}; #[test] fn test_globals_set_get() -> Result<()> { let lua = Lua::new(); let globals = lua.globals(); 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() -> Result<()> { let lua = Lua::new(); let globals = lua.globals(); globals.set("table", lua.create_table()?)?; let table1: Table = globals.get("table")?; let table2: Table = globals.get("table")?; table1.set("foo", "bar")?; table2.set("baz", "baf")?; assert_eq!(table2.get::<_, String>("foo")?, "bar"); assert_eq!(table1.get::<_, String>("baz")?, "baf"); lua.load( r#" table1 = {1, 2, 3, 4, 5} table2 = {} table3 = {1, 2, nil, 4, 5} "#, ) .exec()?; let table1 = globals.get::<_, Table>("table1")?; let table2 = globals.get::<_, Table>("table2")?; let table3 = globals.get::<_, Table>("table3")?; assert_eq!(table1.len()?, 5); assert!(!table1.is_empty()); assert_eq!( table1 .clone() .pairs() .collect::>>()?, vec![(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)] ); assert_eq!( table1 .clone() .sequence_values() .collect::>>()?, vec![1, 2, 3, 4, 5] ); assert_eq!(table1, [1, 2, 3, 4, 5]); assert_eq!(table2.len()?, 0); assert!(table2.is_empty()); assert_eq!( table2 .clone() .pairs() .collect::>>()?, vec![] ); assert_eq!(table2, [0; 0]); // sequence_values should only iterate until the first border assert_eq!(table3, [1, 2]); assert_eq!( table3.sequence_values().collect::>>()?, vec![1, 2] ); globals.set("table4", lua.create_sequence_from(vec![1, 2, 3, 4, 5])?)?; let table4 = globals.get::<_, Table>("table4")?; assert_eq!( table4 .clone() .pairs() .collect::>>()?, vec![(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)] ); table4.raw_insert(4, 35)?; table4.raw_insert(7, 7)?; assert_eq!( table4 .clone() .pairs() .collect::>>()?, vec![(1, 1), (2, 2), (3, 3), (4, 35), (5, 4), (6, 5), (7, 7)] ); table4.raw_remove(1)?; assert_eq!( table4 .clone() .pairs() .collect::>>()?, vec![(1, 2), (2, 3), (3, 35), (4, 4), (5, 5), (6, 7)] ); Ok(()) } #[test] fn test_table_push_pop() -> Result<()> { let lua = Lua::new(); // Test raw access let table1 = lua.create_sequence_from(vec![123])?; table1.raw_push(321)?; assert_eq!(table1, [123, 321]); assert_eq!(table1.raw_pop::()?, 321); assert_eq!(table1.raw_pop::()?, 123); assert_eq!(table1.raw_pop::()?, Value::Nil); // An extra pop should do nothing assert_eq!(table1.raw_len(), 0); assert_eq!(table1, [0; 0]); // Test access through metamethods let table2 = lua .load( r#" local proxy_table = {234} table2 = setmetatable({}, { __len = function() return #proxy_table end, __index = proxy_table, __newindex = proxy_table, }) return table2 "#, ) .eval::()?; table2.push(345)?; assert_eq!(table2.len()?, 2); assert_eq!( table2 .clone() .sequence_values::() .collect::>>()?, vec![] ); assert_eq!(table2.pop::()?, 345); assert_eq!(table2.pop::()?, 234); assert_eq!(table2.pop::()?, Value::Nil); assert_eq!(table2.len()?, 0); Ok(()) } #[test] fn test_table_clear() -> Result<()> { let lua = Lua::new(); // Check readonly error #[cfg(feature = "luau")] { let t = lua.create_table()?; t.set_readonly(true); assert!(matches!( t.clear(), Err(Error::RuntimeError(err)) if err.contains("attempt to modify a readonly table") )); } let t = lua.create_table()?; // Set array and hash parts t.push("abc")?; t.push("bcd")?; t.set("a", "1")?; t.set("b", "2")?; t.clear()?; assert_eq!(t.len()?, 0); assert_eq!(t.pairs::().count(), 0); // Test table with metamethods let t2 = lua .load( r#" setmetatable({1, 2, 3, a = "1"}, { __index = function() error("index error") end, __newindex = function() error("newindex error") end, __len = function() error("len error") end, __pairs = function() error("pairs error") end, }) "#, ) .eval::
()?; assert_eq!(t2.raw_len(), 3); assert!(!t2.is_empty()); t2.clear()?; assert_eq!(t2.raw_len(), 0); assert!(t2.is_empty()); assert_eq!(t2.raw_get::<_, Value>("a")?, Value::Nil); assert_ne!(t2.get_metatable(), None); Ok(()) } #[test] fn test_table_sequence_from() -> Result<()> { let lua = Lua::new(); let get_table = lua.create_function(|_, t: Table| Ok(t))?; assert_eq!(get_table.call::<_, Table>(vec![1, 2, 3])?, [1, 2, 3]); assert_eq!(get_table.call::<_, Table>([4, 5, 6])?, [4, 5, 6]); assert_eq!(get_table.call::<_, Table>([7, 8, 9].as_slice())?, [7, 8, 9]); Ok(()) } #[test] fn test_table_pairs() -> Result<()> { let lua = Lua::new(); let table = lua .load( r#" { foo = "bar", baz = "baf", [123] = 456, [789] = 101112, 5, } "#, ) .eval::
()?; let table2 = table.clone(); for (i, kv) in table.pairs::().enumerate() { let (k, _v) = kv.unwrap(); match i { // Try to add a new key 0 => table2.set("new_key", "new_value")?, // Try to delete the 2nd key 1 => { table2.set(k, Value::Nil)?; lua.gc_collect()?; } _ => {} } } Ok(()) } #[test] fn test_table_for_each() -> Result<()> { let lua = Lua::new(); let table = lua .load( r#" { foo = "bar", baz = "baf", [123] = 456, [789] = 101112, 5, } "#, ) .eval::
()?; let mut i = 0; table.for_each::(|k, _| { if i == 0 { // Delete first key table.set(k, Value::Nil)?; lua.gc_collect()?; } Ok(i += 1) })?; assert_eq!(i, 5); Ok(()) } #[test] fn test_table_scope() -> Result<()> { let lua = Lua::new(); let globals = lua.globals(); lua.load( r#" touter = { tin = {1, 2, 3} } "#, ) .exec()?; // Make sure that table gets do not borrow the table, but instead just borrow lua. let tin; { let touter = globals.get::<_, Table>("touter")?; tin = touter.get::<_, Table>("tin")?; } 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() -> Result<()> { let lua = Lua::new(); 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")?, "index_value"); match table.raw_get::<_, Value>("any_key")? { Nil => {} _ => panic!(), } table.set_metatable(None); match table.get::<_, Value>("any_key")? { Nil => {} _ => panic!(), }; Ok(()) } #[test] fn test_table_eq() -> Result<()> { let lua = Lua::new(); let globals = lua.globals(); lua.load( r#" table1 = {1} table2 = {1} table3 = table1 table4 = {1} setmetatable(table4, { __eq = function(a, b) return a[1] == b[1] end }) "#, ) .exec()?; let table1 = globals.get::<_, Table>("table1")?; let table2 = globals.get::<_, Table>("table2")?; let table3 = globals.get::<_, Table>("table3")?; let table4 = globals.get::<_, Table>("table4")?; assert!(table1 != table2); assert!(!table1.equals(&table2)?); assert!(table1 == table3); assert!(table1.equals(&table3)?); assert!(table1 != table4); assert!(table1.equals(&table4)?); Ok(()) } #[test] fn test_table_error() -> Result<()> { let lua = Lua::new(); 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(()) } #[test] fn test_table_call() -> Result<()> { let lua = Lua::new(); lua.load( r#" table = {a = 1, b = 2} setmetatable(table, { __call = function(t, key) return "call_"..t[key] end }) function table.func(key) return "func_"..key end function table:method(key) return "method_"..self[key] end "#, ) .exec()?; let table: Table = lua.globals().get("table")?; assert_eq!(table.call::<_, String>("b")?, "call_2"); assert_eq!(table.call_function::<_, String>("func", "a")?, "func_a"); assert_eq!(table.call_method::<_, String>("method", "a")?, "method_1"); // Test calling non-callable table let table2 = lua.create_table()?; assert!(matches!( table2.call::<_, ()>(()), Err(Error::RuntimeError(_)) )); Ok(()) } #[cfg(all(feature = "unstable", not(feature = "send")))] #[test] fn test_owned_table() -> Result<()> { let lua = Lua::new(); let table = lua.create_table()?.into_owned(); drop(lua); table.to_ref().set("abc", 123)?; assert_eq!(table.to_ref().get::<_, i64>("abc")?, 123); Ok(()) }