using Lua.Runtime; using Lua.Standard; namespace Lua.Tests; public class LuaApiTests { LuaState state = default!; [OneTimeSetUp] public void SetUp() { state = LuaState.Create(); state.OpenStandardLibraries(); } [Test] public async Task TestArithmetic() { var source = """ metatable = { __add = function(a, b) local t = { } for i = 1, #a do t[i] = a[i] + b[i] end return t end } local a = { 1, 2, 3 } local b = { 4, 5, 6 } setmetatable(a, metatable) return a, b """; var result = await state.DoStringAsync(source); var a = result[0].Read(); var b = result[1].Read(); var c = await state.MainThread.Arithmetic(a, b, OpCode.Add); var table = c.Read(); Assert.Multiple(() => { Assert.That(table[1].Read(), Is.EqualTo(5)); Assert.That(table[2].Read(), Is.EqualTo(7)); Assert.That(table[3].Read(), Is.EqualTo(9)); }); } [Test] public async Task TestUnary() { var source = """ metatable = { __unm = function(a) local t = { } for i = 1, #a do t[i] = -a[i] end return t end } local a = { 1, 2, 3 } setmetatable(a, metatable) return a """; var result = await state.DoStringAsync(source); var a = result[0].Read(); var c = await state.MainThread.Unary(a, OpCode.Unm); var table = c.Read(); Assert.Multiple(() => { Assert.That(table[1].Read(), Is.EqualTo(-1)); Assert.That(table[2].Read(), Is.EqualTo(-2)); Assert.That(table[3].Read(), Is.EqualTo(-3)); }); } [Test] public async Task TestCompare() { var source = """ metatable = { __eq = function(a, b) if(#a ~= #b) then return false end for i = 1, #a do if(a[i] ~= b[i]) then return false end end return true end } local a = { 1, 2, 3 } local b = { 4, 5, 6 } local c = { 1, 2, 3 } setmetatable(a, metatable) return a, b, c """; var result = await state.DoStringAsync(source); var a = result[0].Read(); var b = result[1].Read(); var c = result[2].Read(); var ab = await state.MainThread.Compare(a, b, OpCode.Eq); Assert.False(ab); var ac = await state.MainThread.Compare(a, c, OpCode.Eq); Assert.True(ac); } [Test] public async Task TestGetTable() { var source = """ metatable = { __index = {x=1} } local a = {} setmetatable(a, metatable) return a """; var result = await state.DoStringAsync(source); var a = result[0].Read(); Assert.That(await state.MainThread.GetTable(a, "x"), Is.EqualTo(new LuaValue(1))); a.Metatable!["__index"] = state.DoStringAsync("return function(a,b) return b end").Result[0]; Assert.That(await state.MainThread.GetTable(a, "x"), Is.EqualTo(new LuaValue("x"))); } [Test] public async Task TestSetTable() { var source = """ metatable = { __newindex = {} } local a = {} a.x = 1 setmetatable(a, metatable) return a """; var result = await state.DoStringAsync(source); var a = result[0].Read(); await state.MainThread.SetTable(a, "a", "b"); var b = a.Metatable!["__newindex"].Read()["a"]; Assert.True(b.Read() == "b"); } [Test] public async Task Test_Metamethod_Concat() { var source = @" metatable = { __concat = function(a, b) local t = { } for i = 1, #a do table.insert(t, a[i]) end for i = 1, #b do table.insert(t, b[i]) end return t end } local a = { 1, 2, 3 } local b = { 4, 5, 6 } local c = { 7, 8, 9 } setmetatable(a, metatable) setmetatable(c, metatable) return a,b,c "; var result = await state.DoStringAsync(source); Assert.That(result, Has.Length.EqualTo(3)); var a = result[0]; var b = result[1]; var c = result[2]; var d = await state.MainThread.Concat([a, b, c]); var table = d.Read(); Assert.That(table.ArrayLength, Is.EqualTo(9)); Assert.Multiple(() => { Assert.That(table[1].Read(), Is.EqualTo(1)); Assert.That(table[2].Read(), Is.EqualTo(2)); Assert.That(table[3].Read(), Is.EqualTo(3)); Assert.That(table[4].Read(), Is.EqualTo(4)); Assert.That(table[5].Read(), Is.EqualTo(5)); Assert.That(table[6].Read(), Is.EqualTo(6)); Assert.That(table[7].Read(), Is.EqualTo(7)); Assert.That(table[8].Read(), Is.EqualTo(8)); Assert.That(table[9].Read(), Is.EqualTo(9)); }); } [Test] public async Task Test_Metamethod_MetaCallViaMeta() { var source = """ local a = {name ="a"} setmetatable(a, { __call = function(a, b, c) return a.name..b.name..c.name end }) local b = setmetatable({name="b"}, {__unm = a, __add= a, __concat =a }) local c ={name ="c"} return a,b,c """; var result = await state.DoStringAsync(source); var a = result[0]; var b = result[1]; var c = result[2]; var d = await state.MainThread.Arithmetic(b, c, OpCode.Add); Assert.True(d.TryRead(out string s)); Assert.That(s, Is.EqualTo("abc")); d = await state.MainThread.Unary(b, OpCode.Unm); Assert.True(d.TryRead(out s)); Assert.That(s, Is.EqualTo("abb")); d = await state.MainThread.Concat([c, b]); Assert.True(d.TryRead(out s)); Assert.That(s, Is.EqualTo("acb")); var aResult = await state.MainThread.Call(a, [b, c]); Assert.That(aResult, Has.Length.EqualTo(1)); Assert.That(aResult[0].Read(), Is.EqualTo("abc")); } [Test] public async Task Test_Metamethod_MetaCallViaMeta_VarArg() { var source = """ local a = {name ="a"} setmetatable(a, { __call = function(a, ...) local args = {...} local b,c =args[1],args[2] return a.name..b.name..c.name end }) local b = setmetatable({name="b"}, {__unm = a, __add= a, __concat =a }) local c ={name ="c"} return a,b,c """; var result = await state.DoStringAsync(source); var a = result[0]; var b = result[1]; var c = result[2]; var d = await state.MainThread.Arithmetic(b, c, OpCode.Add); Assert.True(d.TryRead(out string s)); Assert.That(s, Is.EqualTo("abc")); d = await state.MainThread.Unary(b, OpCode.Unm); Assert.True(d.TryRead(out s)); Assert.That(s, Is.EqualTo("abb")); d = await state.MainThread.Concat([c, b]); Assert.True(d.TryRead(out s)); Assert.That(s, Is.EqualTo("acb")); var aResult = await state.MainThread.Call(a, [b, c]); Assert.That(aResult, Has.Length.EqualTo(1)); Assert.That(aResult[0].Read(), Is.EqualTo("abc")); } }