use mlua::{Error, Lua, Nil, Result, Table, TableExt, Value}; #[test] fn test_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_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!(table2.len()?, 0); assert_eq!( table2 .clone() .pairs() .collect::>>()?, vec![] ); assert_eq!( table2.sequence_values().collect::>>()?, vec![] ); // sequence_values should only iterate until the first border 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 .clone() .raw_sequence_values::() .collect::>>()?, vec![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); // 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.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); t2.clear()?; assert_eq!(t2.raw_len(), 0); 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])? .sequence_values() .collect::>>()?, vec![1, 2, 3] ); assert_eq!( get_table .call::<_, Table>([1, 2, 3].as_ref())? .sequence_values() .collect::>>()?, vec![1, 2, 3] ); assert_eq!( get_table .call::<_, Table>([1, 2, 3])? .sequence_values() .collect::>>()?, vec![1, 2, 3] ); 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(()) }