/* * This file is part of LuaInterface. * * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. * Copyright (C) 2012 Megax * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ using System; using System.Text; using System.Threading; using System.Reflection; using System.Collections.Generic; using LuaInterface.Exceptions; namespace LuaInterface.Tests { /* * Automated test cases for LuaInterface * * Author: Fabio Mascarenhas * Version: 1.0 */ public class TestLuaInterface { private Lua _Lua; /* * Executed before each test case */ public void Init() { _Lua = new Lua(); GC.Collect(); // runs GC to expose unprotected delegates } /* * Executed after each test case */ public void Destroy() { _Lua = null; } #if false // I've commented out the nunit based tests until they can run standalone - so that users don't need nunit to run TestLua /* * Tests if DoString is correctly returning values */ [Test] public void DoString() { object[] res=lua.DoString("a=2\nreturn a,3"); //Console.WriteLine("a="+res[0]+", b="+res[1]); Assertion.AssertEquals(res[0],2); Assertion.AssertEquals(res[1],3); } /* * Tests getting of global numeric variables */ [Test] public void GetGlobalNumber() { lua.DoString("a=2"); double num=lua.GetNumber("a"); //Console.WriteLine("a="+num); Assertion.AssertEquals(num,2); } /* * Tests setting of global numeric variables */ [Test] public void SetGlobalNumber() { lua.DoString("a=2"); lua["a"]=3; double num=lua.GetNumber("a"); //Console.WriteLine("a="+num); Assertion.AssertEquals(num,3); } /* * Tests getting of numeric variables from tables * by specifying variable path */ [Test] public void GetNumberInTable() { lua.DoString("a={b={c=2}}"); double num=lua.GetNumber("a.b.c"); //Console.WriteLine("a.b.c="+num); Assertion.AssertEquals(num,2); } /* * Tests setting of numeric variables from tables * by specifying variable path */ [Test] public void SetNumberInTable() { lua.DoString("a={b={c=2}}"); lua["a.b.c"]=3; double num=lua.GetNumber("a.b.c"); //Console.WriteLine("a.b.c="+num); Assertion.AssertEquals(num,3); } /* * Tests getting of global string variables */ [Test] public void GetGlobalString() { lua.DoString("a=\"test\""); string str=lua.GetString("a"); //Console.WriteLine("a="+str); Assertion.AssertEquals(str,"test"); } /* * Tests setting of global string variables */ [Test] public void SetGlobalString() { lua.DoString("a=\"test\""); lua["a"]="new test"; string str=lua.GetString("a"); //Console.WriteLine("a="+str); Assertion.AssertEquals(str,"new test"); } /* * Tests getting of string variables from tables * by specifying variable path */ [Test] public void GetStringInTable() { lua.DoString("a={b={c=\"test\"}}"); string str=lua.GetString("a.b.c"); //Console.WriteLine("a.b.c="+str); Assertion.AssertEquals(str,"test"); } /* * Tests setting of string variables from tables * by specifying variable path */ [Test] public void SetStringInTable() { lua.DoString("a={b={c=\"test\"}}"); lua["a.b.c"]="new test"; string str=lua.GetString("a.b.c"); //Console.WriteLine("a.b.c="+str); Assertion.AssertEquals(str,"new test"); } /* * Tests getting and setting of global table variables */ [Test] public void GetAndSetTable() { lua.DoString("a={b={c=2}}\nb={c=3}"); LuaTable tab=lua.GetTable("b"); lua["a.b"]=tab; double num=lua.GetNumber("a.b.c"); //Console.WriteLine("a.b.c="+num); Assertion.AssertEquals(num,3); } /* * Tests getting of numeric field of a table */ [Test] public void GetTableNumericField1() { lua.DoString("a={b={c=2}}"); LuaTable tab=lua.GetTable("a.b"); double num=(double)tab["c"]; //Console.WriteLine("a.b.c="+num); Assertion.AssertEquals(num,2); } /* * Tests getting of numeric field of a table * (the field is inside a subtable) */ [Test] public void GetTableNumericField2() { lua.DoString("a={b={c=2}}"); LuaTable tab=lua.GetTable("a"); double num=(double)tab["b.c"]; //Console.WriteLine("a.b.c="+num); Assertion.AssertEquals(num,2); } /* * Tests setting of numeric field of a table */ [Test] public void SetTableNumericField1() { lua.DoString("a={b={c=2}}"); LuaTable tab=lua.GetTable("a.b"); tab["c"]=3; double num=lua.GetNumber("a.b.c"); //Console.WriteLine("a.b.c="+num); Assertion.AssertEquals(num,3); } /* * Tests setting of numeric field of a table * (the field is inside a subtable) */ [Test] public void SetTableNumericField2() { lua.DoString("a={b={c=2}}"); LuaTable tab=lua.GetTable("a"); tab["b.c"]=3; double num=lua.GetNumber("a.b.c"); //Console.WriteLine("a.b.c="+num); Assertion.AssertEquals(num,3); } /* * Tests getting of string field of a table */ [Test] public void GetTableStringField1() { lua.DoString("a={b={c=\"test\"}}"); LuaTable tab=lua.GetTable("a.b"); string str=(string)tab["c"]; //Console.WriteLine("a.b.c="+str); Assertion.AssertEquals(str,"test"); } /* * Tests getting of string field of a table * (the field is inside a subtable) */ [Test] public void GetTableStringField2() { lua.DoString("a={b={c=\"test\"}}"); LuaTable tab=lua.GetTable("a"); string str=(string)tab["b.c"]; //Console.WriteLine("a.b.c="+str); Assertion.AssertEquals(str,"test"); } /* * Tests setting of string field of a table */ [Test] public void SetTableStringField1() { lua.DoString("a={b={c=\"test\"}}"); LuaTable tab=lua.GetTable("a.b"); tab["c"]="new test"; string str=lua.GetString("a.b.c"); //Console.WriteLine("a.b.c="+str); Assertion.AssertEquals(str,"new test"); } /* * Tests setting of string field of a table * (the field is inside a subtable) */ [Test] public void SetTableStringField2() { lua.DoString("a={b={c=\"test\"}}"); LuaTable tab=lua.GetTable("a"); tab["b.c"]="new test"; string str=lua.GetString("a.b.c"); //Console.WriteLine("a.b.c="+str); Assertion.AssertEquals(str,"new test"); } /* * Tests calling of a global function with zero arguments */ [Test] public void CallGlobalFunctionNoArgs() { lua.DoString("a=2\nfunction f()\na=3\nend"); lua.GetFunction("f").Call(); double num=lua.GetNumber("a"); //Console.WriteLine("a="+num); Assertion.AssertEquals(num,3); } /* * Tests calling of a global function with one argument */ [Test] public void CallGlobalFunctionOneArg() { lua.DoString("a=2\nfunction f(x)\na=a+x\nend"); lua.GetFunction("f").Call(1); double num=lua.GetNumber("a"); //Console.WriteLine("a="+num); Assertion.AssertEquals(num,3); } /* * Tests calling of a global function with two arguments */ [Test] public void CallGlobalFunctionTwoArgs() { lua.DoString("a=2\nfunction f(x,y)\na=x+y\nend"); lua.GetFunction("f").Call(1,3); double num=lua.GetNumber("a"); //Console.WriteLine("a="+num); Assertion.AssertEquals(num,4); } /* * Tests calling of a global function that returns one value */ [Test] public void CallGlobalFunctionOneReturn() { lua.DoString("function f(x)\nreturn x+2\nend"); object[] ret=lua.GetFunction("f").Call(3); //Console.WriteLine("ret="+ret[0]); Assertion.AssertEquals(1,ret.Length); Assertion.AssertEquals(5,ret[0]); } /* * Tests calling of a global function that returns two values */ [Test] public void CallGlobalFunctionTwoReturns() { lua.DoString("function f(x,y)\nreturn x,x+y\nend"); object[] ret=lua.GetFunction("f").Call(3,2); //Console.WriteLine("ret="+ret[0]+","+ret[1]); Assertion.AssertEquals(2,ret.Length); Assertion.AssertEquals(3,ret[0]); Assertion.AssertEquals(5,ret[1]); } /* * Tests calling of a function inside a table */ [Test] public void CallTableFunctionTwoReturns() { lua.DoString("a={}\nfunction a.f(x,y)\nreturn x,x+y\nend"); object[] ret=lua.GetFunction("a.f").Call(3,2); //Console.WriteLine("ret="+ret[0]+","+ret[1]); Assertion.AssertEquals(2,ret.Length); Assertion.AssertEquals(3,ret[0]); Assertion.AssertEquals(5,ret[1]); } /* * Tests setting of a global variable to a CLR object value */ [Test] public void SetGlobalObject() { TestClass t1=new TestClass(); t1.testval=4; lua["netobj"]=t1; object o=lua["netobj"]; TestClass t2=(TestClass)lua["netobj"]; Assertion.AssertEquals(t2.testval,4); Assertion.Assert(t1==t2); } /* * Tests if CLR object is being correctly collected by Lua */ [Test] public void GarbageCollection() { TestClass t1=new TestClass(); t1.testval=4; lua["netobj"]=t1; TestClass t2=(TestClass)lua["netobj"]; Assertion.Assert(lua.translator.objects[0]!=null); lua.DoString("netobj=nil;collectgarbage();"); Assertion.Assert(lua.translator.objects[0]==null); } /* * Tests setting of a table field to a CLR object value */ [Test] public void SetTableObjectField1() { lua.DoString("a={b={c=\"test\"}}"); LuaTable tab=lua.GetTable("a.b"); TestClass t1=new TestClass(); t1.testval=4; tab["c"]=t1; TestClass t2=(TestClass)lua["a.b.c"]; //Console.WriteLine("a.b.c="+t2.testval); Assertion.AssertEquals(t2.testval,4); Assertion.Assert(t1==t2); } /* * Tests reading and writing of an object's field */ [Test] public void AccessObjectField() { TestClass t1=new TestClass(); t1.val=4; lua["netobj"]=t1; lua.DoString("var=netobj.val"); double var=(double)lua["var"]; //Console.WriteLine("value from Lua="+var); Assertion.AssertEquals(4,var); lua.DoString("netobj.val=3"); Assertion.AssertEquals(3,t1.val); //Console.WriteLine("new val (from Lua)="+t1.val); } /* * Tests reading and writing of an object's non-indexed * property */ [Test] public void AccessObjectProperty() { TestClass t1=new TestClass(); t1.testval=4; lua["netobj"]=t1; lua.DoString("var=netobj.testval"); double var=(double)lua["var"]; //Console.WriteLine("value from Lua="+var); Assertion.AssertEquals(4,var); lua.DoString("netobj.testval=3"); Assertion.AssertEquals(3,t1.testval); //Console.WriteLine("new val (from Lua)="+t1.testval); } /* * Tests calling of an object's method with no overloads */ [Test] public void CallObjectMethod() { TestClass t1=new TestClass(); t1.testval=4; lua["netobj"]=t1; lua.DoString("netobj:setVal(3)"); Assertion.AssertEquals(3,t1.testval); //Console.WriteLine("new val(from C#)="+t1.testval); lua.DoString("val=netobj:getVal()"); int val=(int)lua.GetNumber("val"); Assertion.AssertEquals(3,val); //Console.WriteLine("new val(from Lua)="+val); } /* * Tests calling of an object's method with overloading */ [Test] public void CallObjectMethodByType() { TestClass t1=new TestClass(); lua["netobj"]=t1; lua.DoString("netobj:setVal('str')"); Assertion.AssertEquals("str",t1.getStrVal()); //Console.WriteLine("new val(from C#)="+t1.getStrVal()); } /* * Tests calling of an object's method with no overloading * and out parameters */ [Test] public void CallObjectMethodOutParam() { TestClass t1=new TestClass(); lua["netobj"]=t1; lua.DoString("a,b=netobj:outVal()"); int a=(int)lua.GetNumber("a"); int b=(int)lua.GetNumber("b"); Assertion.AssertEquals(3,a); Assertion.AssertEquals(5,b); //Console.WriteLine("function returned (from lua)="+a+","+b); } /* * Tests calling of an object's method with overloading and * out params */ [Test] public void CallObjectMethodOverloadedOutParam() { TestClass t1=new TestClass(); lua["netobj"]=t1; lua.DoString("a,b=netobj:outVal(2)"); int a=(int)lua.GetNumber("a"); int b=(int)lua.GetNumber("b"); Assertion.AssertEquals(2,a); Assertion.AssertEquals(5,b); //Console.WriteLine("function returned (from lua)="+a+","+b); } /* * Tests calling of an object's method with ref params */ [Test] public void CallObjectMethodByRefParam() { TestClass t1=new TestClass(); lua["netobj"]=t1; lua.DoString("a,b=netobj:outVal(2,3)"); int a=(int)lua.GetNumber("a"); int b=(int)lua.GetNumber("b"); Assertion.AssertEquals(2,a); Assertion.AssertEquals(5,b); //Console.WriteLine("function returned (from lua)="+a+","+b); } /* * Tests calling of two versions of an object's method that have * the same name and signature but implement different interfaces */ [Test] public void CallObjectMethodDistinctInterfaces() { TestClass t1=new TestClass(); lua["netobj"]=t1; lua.DoString("a=netobj:foo()"); lua.DoString("b=netobj['LuaInterface.Tests.IFoo1.foo'](netobj)"); int a=(int)lua.GetNumber("a"); int b=(int)lua.GetNumber("b"); Assertion.AssertEquals(5,a); Assertion.AssertEquals(3,b); //Console.WriteLine("function returned (from lua)="+a+","+b); } /* * Tests instantiating an object with no-argument constructor */ [Test] public void CreateNetObjectNoArgsCons() { lua.DoString("load_assembly(\"TestLua\")"); lua.DoString("TestClass=import_type(\"LuaInterface.Tests.TestClass\")"); lua.DoString("test=TestClass()"); lua.DoString("test:setVal(3)"); object[] res=lua.DoString("return test"); TestClass test=(TestClass)res[0]; //Console.WriteLine("returned: "+test.testval); Assertion.AssertEquals(3,test.testval); } /* * Tests instantiating an object with one-argument constructor */ [Test] public void CreateNetObjectOneArgCons() { lua.DoString("load_assembly(\"TestLua\")"); lua.DoString("TestClass=import_type(\"LuaInterface.Tests.TestClass\")"); lua.DoString("test=TestClass(3)"); object[] res=lua.DoString("return test"); TestClass test=(TestClass)res[0]; //Console.WriteLine("returned: "+test.testval); Assertion.AssertEquals(3,test.testval); } /* * Tests instantiating an object with overloaded constructor */ [Test] public void CreateNetObjectOverloadedCons() { lua.DoString("load_assembly(\"TestLua\")"); lua.DoString("TestClass=import_type(\"LuaInterface.Tests.TestClass\")"); lua.DoString("test=TestClass('str')"); object[] res=lua.DoString("return test"); TestClass test=(TestClass)res[0]; //Console.WriteLine("returned: "+test.getStrVal()); Assertion.AssertEquals("str",test.getStrVal()); } /* * Tests getting item of a CLR array */ [Test] public void ReadArrayField() { string[] arr=new string[] { "str1", "str2", "str3" }; lua["netobj"]=arr; lua.DoString("val=netobj[1]"); string val=lua.GetString("val"); Assertion.AssertEquals("str2",val); //Console.WriteLine("new val(from array to Lua)="+val); } /* * Tests setting item of a CLR array */ [Test] public void WriteArrayField() { string[] arr=new string[] { "str1", "str2", "str3" }; lua["netobj"]=arr; lua.DoString("netobj[1]='test'"); Assertion.AssertEquals("test",arr[1]); //Console.WriteLine("new val(from Lua to array)="+arr[1]); } /* * Tests creating a new CLR array */ [Test] public void CreateArray() { lua.DoString("load_assembly(\"TestLua\")"); lua.DoString("TestClass=import_type(\"LuaInterface.Tests.TestClass\")"); lua.DoString("arr=TestClass[3]"); lua.DoString("for i=0,2 do arr[i]=TestClass(i+1) end"); TestClass[] arr=(TestClass[])lua["arr"]; Assertion.AssertEquals(arr[1].testval,2); } /* * Tests passing a Lua function to a delegate * with value-type arguments */ [Test] public void LuaDelegateValueTypes() { lua.DoString("load_assembly('TestLua')"); lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); lua.DoString("test=TestClass()"); lua.DoString("function func(x,y) return x+y; end"); lua.DoString("test=TestClass()"); lua.DoString("a=test:callDelegate1(func)"); int a=(int)lua.GetNumber("a"); Assertion.AssertEquals(5,a); //Console.WriteLine("delegate returned: "+a); } /* * Tests passing a Lua function to a delegate * with value-type arguments and out params */ [Test] public void LuaDelegateValueTypesOutParam() { lua.DoString("load_assembly('TestLua')"); lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); lua.DoString("test=TestClass()"); lua.DoString("function func(x) return x,x*2; end"); lua.DoString("test=TestClass()"); lua.DoString("a=test:callDelegate2(func)"); int a=(int)lua.GetNumber("a"); Assertion.AssertEquals(6,a); //Console.WriteLine("delegate returned: "+a); } /* * Tests passing a Lua function to a delegate * with value-type arguments and ref params */ [Test] public void LuaDelegateValueTypesByRefParam() { lua.DoString("load_assembly('TestLua')"); lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); lua.DoString("test=TestClass()"); lua.DoString("function func(x,y) return x+y; end"); lua.DoString("test=TestClass()"); lua.DoString("a=test:callDelegate3(func)"); int a=(int)lua.GetNumber("a"); Assertion.AssertEquals(5,a); //Console.WriteLine("delegate returned: "+a); } /* * Tests passing a Lua function to a delegate * with value-type arguments that returns a reference type */ [Test] public void LuaDelegateValueTypesReturnReferenceType() { lua.DoString("load_assembly('TestLua')"); lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); lua.DoString("test=TestClass()"); lua.DoString("function func(x,y) return TestClass(x+y); end"); lua.DoString("test=TestClass()"); lua.DoString("a=test:callDelegate4(func)"); int a=(int)lua.GetNumber("a"); Assertion.AssertEquals(5,a); //Console.WriteLine("delegate returned: "+a); } /* * Tests passing a Lua function to a delegate * with reference type arguments */ [Test] public void LuaDelegateReferenceTypes() { lua.DoString("load_assembly('TestLua')"); lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); lua.DoString("test=TestClass()"); lua.DoString("function func(x,y) return x.testval+y.testval; end"); lua.DoString("test=TestClass()"); lua.DoString("a=test:callDelegate5(func)"); int a=(int)lua.GetNumber("a"); Assertion.AssertEquals(5,a); //Console.WriteLine("delegate returned: "+a); } /* * Tests passing a Lua function to a delegate * with reference type arguments and an out param */ [Test] public void LuaDelegateReferenceTypesOutParam() { lua.DoString("load_assembly('TestLua')"); lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); lua.DoString("test=TestClass()"); lua.DoString("function func(x) return x,TestClass(x*2); end"); lua.DoString("test=TestClass()"); lua.DoString("a=test:callDelegate6(func)"); int a=(int)lua.GetNumber("a"); Assertion.AssertEquals(6,a); //Console.WriteLine("delegate returned: "+a); } /* * Tests passing a Lua function to a delegate * with reference type arguments and a ref param */ [Test] public void LuaDelegateReferenceTypesByRefParam() { lua.DoString("load_assembly('TestLua')"); lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); lua.DoString("test=TestClass()"); lua.DoString("function func(x,y) return TestClass(x+y.testval); end"); lua.DoString("a=test:callDelegate7(func)"); int a=(int)lua.GetNumber("a"); Assertion.AssertEquals(5,a); //Console.WriteLine("delegate returned: "+a); } /* * Tests passing a Lua table as an interface and * calling one of its methods with value-type params */ [Test] public void LuaInterfaceValueTypes() { lua.DoString("load_assembly('TestLua')"); lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); lua.DoString("test=TestClass()"); lua.DoString("itest={}"); lua.DoString("function itest:test1(x,y) return x+y; end"); lua.DoString("test=TestClass()"); lua.DoString("a=test:callInterface1(itest)"); int a=(int)lua.GetNumber("a"); Assertion.AssertEquals(5,a); //Console.WriteLine("interface returned: "+a); } /* * Tests passing a Lua table as an interface and * calling one of its methods with value-type params * and an out param */ [Test] public void LuaInterfaceValueTypesOutParam() { lua.DoString("load_assembly('TestLua')"); lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); lua.DoString("test=TestClass()"); lua.DoString("itest={}"); lua.DoString("function itest:test2(x) return x,x*2; end"); lua.DoString("test=TestClass()"); lua.DoString("a=test:callInterface2(itest)"); int a=(int)lua.GetNumber("a"); Assertion.AssertEquals(6,a); //Console.WriteLine("interface returned: "+a); } /* * Tests passing a Lua table as an interface and * calling one of its methods with value-type params * and a ref param */ [Test] public void LuaInterfaceValueTypesByRefParam() { lua.DoString("load_assembly('TestLua')"); lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); lua.DoString("test=TestClass()"); lua.DoString("itest={}"); lua.DoString("function itest:test3(x,y) return x+y; end"); lua.DoString("test=TestClass()"); lua.DoString("a=test:callInterface3(itest)"); int a=(int)lua.GetNumber("a"); Assertion.AssertEquals(5,a); //Console.WriteLine("interface returned: "+a); } /* * Tests passing a Lua table as an interface and * calling one of its methods with value-type params * returning a reference type param */ [Test] public void LuaInterfaceValueTypesReturnReferenceType() { lua.DoString("load_assembly('TestLua')"); lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); lua.DoString("test=TestClass()"); lua.DoString("itest={}"); lua.DoString("function itest:test4(x,y) return TestClass(x+y); end"); lua.DoString("test=TestClass()"); lua.DoString("a=test:callInterface4(itest)"); int a=(int)lua.GetNumber("a"); Assertion.AssertEquals(5,a); //Console.WriteLine("interface returned: "+a); } /* * Tests passing a Lua table as an interface and * calling one of its methods with reference type params */ [Test] public void LuaInterfaceReferenceTypes() { lua.DoString("load_assembly('TestLua')"); lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); lua.DoString("test=TestClass()"); lua.DoString("itest={}"); lua.DoString("function itest:test5(x,y) return x.testval+y.testval; end"); lua.DoString("test=TestClass()"); lua.DoString("a=test:callInterface5(itest)"); int a=(int)lua.GetNumber("a"); Assertion.AssertEquals(5,a); //Console.WriteLine("interface returned: "+a); } /* * Tests passing a Lua table as an interface and * calling one of its methods with reference type params * and an out param */ [Test] public void LuaInterfaceReferenceTypesOutParam() { lua.DoString("load_assembly('TestLua')"); lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); lua.DoString("test=TestClass()"); lua.DoString("itest={}"); lua.DoString("function itest:test6(x) return x,TestClass(x*2); end"); lua.DoString("test=TestClass()"); lua.DoString("a=test:callInterface6(itest)"); int a=(int)lua.GetNumber("a"); Assertion.AssertEquals(6,a); //Console.WriteLine("interface returned: "+a); } /* * Tests passing a Lua table as an interface and * calling one of its methods with reference type params * and a ref param */ [Test] public void LuaInterfaceReferenceTypesByRefParam() { lua.DoString("load_assembly('TestLua')"); lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); lua.DoString("test=TestClass()"); lua.DoString("itest={}"); lua.DoString("function itest:test7(x,y) return TestClass(x+y.testval); end"); lua.DoString("a=test:callInterface7(itest)"); int a=(int)lua.GetNumber("a"); Assertion.AssertEquals(5,a); //Console.WriteLine("interface returned: "+a); } /* * Tests passing a Lua table as an interface and * accessing one of its value-type properties */ [Test] public void LuaInterfaceValueProperty() { lua.DoString("load_assembly('TestLua')"); lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); lua.DoString("test=TestClass()"); lua.DoString("itest={}"); lua.DoString("function itest:get_intProp() return itest.int_prop; end"); lua.DoString("function itest:set_intProp(val) itest.int_prop=val; end"); lua.DoString("a=test:callInterface8(itest)"); int a=(int)lua.GetNumber("a"); Assertion.AssertEquals(3,a); //Console.WriteLine("interface returned: "+a); } /* * Tests passing a Lua table as an interface and * accessing one of its reference type properties */ [Test] public void LuaInterfaceReferenceProperty() { lua.DoString("load_assembly('TestLua')"); lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); lua.DoString("test=TestClass()"); lua.DoString("itest={}"); lua.DoString("function itest:get_refProp() return TestClass(itest.int_prop); end"); lua.DoString("function itest:set_refProp(val) itest.int_prop=val.testval; end"); lua.DoString("a=test:callInterface9(itest)"); int a=(int)lua.GetNumber("a"); Assertion.AssertEquals(3,a); //Console.WriteLine("interface returned: "+a); } /* * Tests making an object from a Lua table and calling the base * class version of one of the methods the table overrides. */ [Test] public void LuaTableBaseMethod() { lua.DoString("load_assembly('TestLua')"); lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); lua.DoString("test={}"); lua.DoString("function test:overridableMethod(x,y) return 2*self.base:overridableMethod(x,y); end"); lua.DoString("make_object(test,'LuaInterface.Tests.TestClass')"); lua.DoString("a=TestClass:callOverridable(test,2,3)"); int a=(int)lua.GetNumber("a"); lua.DoString("free_object(test)"); Assertion.AssertEquals(10,a); //Console.WriteLine("interface returned: "+a); } /* * Tests getting an object's method by its signature * (from object) */ [Test] public void GetMethodBySignatureFromObj() { lua.DoString("load_assembly('mscorlib')"); lua.DoString("load_assembly('TestLua')"); lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); lua.DoString("test=TestClass()"); lua.DoString("setMethod=get_method_bysig(test,'setVal','System.String')"); lua.DoString("setMethod('test')"); TestClass test=(TestClass)lua["test"]; Assertion.AssertEquals("test",test.getStrVal()); //Console.WriteLine("interface returned: "+test.getStrVal()); } /* * Tests getting an object's method by its signature * (from type) */ [Test] public void GetMethodBySignatureFromType() { lua.DoString("load_assembly('mscorlib')"); lua.DoString("load_assembly('TestLua')"); lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); lua.DoString("test=TestClass()"); lua.DoString("setMethod=get_method_bysig(TestClass,'setVal','System.String')"); lua.DoString("setMethod(test,'test')"); TestClass test=(TestClass)lua["test"]; Assertion.AssertEquals("test",test.getStrVal()); //Console.WriteLine("interface returned: "+test.getStrVal()); } /* * Tests getting a type's method by its signature */ [Test] public void GetStaticMethodBySignature() { lua.DoString("load_assembly('mscorlib')"); lua.DoString("load_assembly('TestLua')"); lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); lua.DoString("make_method=get_method_bysig(TestClass,'makeFromString','System.String')"); lua.DoString("test=make_method('test')"); TestClass test=(TestClass)lua["test"]; Assertion.AssertEquals("test",test.getStrVal()); //Console.WriteLine("interface returned: "+test.getStrVal()); } /* * Tests getting an object's constructor by its signature */ [Test] public void GetConstructorBySignature() { lua.DoString("load_assembly('mscorlib')"); lua.DoString("load_assembly('TestLua')"); lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); lua.DoString("test_cons=get_constructor_bysig(TestClass,'System.String')"); lua.DoString("test=test_cons('test')"); TestClass test=(TestClass)lua["test"]; Assertion.AssertEquals("test",test.getStrVal()); //Console.WriteLine("interface returned: "+test.getStrVal()); } #endif void TestOk(bool flag) { if(flag) Console.WriteLine("Test Passed."); else Console.WriteLine("Test Failed!!!!"); } /* * Tests capturing an exception */ public void ThrowException() { Init(); _Lua.DoString("luanet.load_assembly('mscorlib')"); _Lua.DoString("luanet.load_assembly('TestLua')"); _Lua.DoString("TestClass=luanet.import_type('LuaInterface.Tests.TestClass')"); _Lua.DoString("test=TestClass()"); _Lua.DoString("err,errMsg=pcall(test.exceptionMethod,test)"); bool err = (bool)_Lua["err"]; Exception errMsg = (Exception)_Lua["errMsg"]; TestOk(!err); TestOk(errMsg.InnerException != null); if(errMsg.InnerException != null) TestOk("exception test" == errMsg.InnerException.Message); //Console.WriteLine("interface returned: "+errMsg.ToString()); Destroy(); } /* * Tests capturing an exception */ public void ThrowUncaughtException() { Init(); _Lua.DoString("luanet.load_assembly('mscorlib')"); _Lua.DoString("luanet.load_assembly('TestLua')"); _Lua.DoString("TestClass=luanet.import_type('LuaInterface.Tests.TestClass')"); _Lua.DoString("test=TestClass()"); try { _Lua.DoString("test:exceptionMethod()"); Console.WriteLine("Test failed!!! Should have thrown an exception all the way out of Lua"); } catch (Exception) { Console.WriteLine("Uncaught exception success"); } Destroy(); } /* * Tests nullable fields */ public void TestNullable() { Init(); _Lua.DoString("luanet.load_assembly('mscorlib')"); _Lua.DoString("luanet.load_assembly('TestLua')"); _Lua.DoString("TestClass=luanet.import_type('LuaInterface.Tests.TestClass')"); _Lua.DoString("test=TestClass()"); _Lua.DoString("val=test.NullableBool"); TestOk(((object)_Lua["val"]) == null); _Lua.DoString("test.NullableBool = true"); _Lua.DoString("val=test.NullableBool"); TestOk(((bool)_Lua["val"]) == true); Destroy(); } /* * Tests structure assignment */ public void TestStructs() { Init(); _Lua.DoString("luanet.load_assembly('TestLua')"); _Lua.DoString("TestClass=luanet.import_type('LuaInterface.Tests.TestClass')"); _Lua.DoString("test=TestClass()"); _Lua.DoString("TestStruct=luanet.import_type('LuaInterface.Tests.TestStruct')"); _Lua.DoString("struct=TestStruct(2)"); _Lua.DoString("test.Struct = struct"); _Lua.DoString("val=test.Struct.val"); TestOk(((double)_Lua["val"]) == 2.0); Destroy(); } public void TestMethodOverloads() { Init(); _Lua.DoString("luanet.load_assembly('mscorlib')"); _Lua.DoString("luanet.load_assembly('TestLua')"); _Lua.DoString("TestClass=luanet.import_type('LuaInterface.Tests.TestClass')"); _Lua.DoString("test=TestClass()"); _Lua.DoString("test:MethodOverload()"); _Lua.DoString("test:MethodOverload(test)"); _Lua.DoString("test:MethodOverload(1,1,1)"); _Lua.DoString("test:MethodOverload(2,2,i)\r\nprint(i)"); } private void TestDispose() { GC.Collect(); long startingMem = System.Diagnostics.Process.GetCurrentProcess().WorkingSet64; for(int i = 0; i < 10000; i++) { using (Lua lua = new Lua()) { _Calc(lua, i); } } Console.WriteLine("Was using " + startingMem / 1024 / 1024 + "MB, now using: " + System.Diagnostics.Process.GetCurrentProcess().WorkingSet64 / 1024 / 1024 + "MB"); } private void _Calc(Lua lua, int i) { lua.DoString( "sqrt = math.sqrt;" + "sqr = function(x) return math.pow(x,2); end;" + "log = math.log;" + "log10 = math.log10;" + "exp = math.exp;" + "sin = math.sin;" + "cos = math.cos;" + "tan = math.tan;" + "abs = math.abs;" ); lua.DoString("function calcVP(a,b) return a+b end"); LuaFunction lf = lua.GetFunction("calcVP"); /*Object[] ret = */lf.Call(i, 20); } private void TestThreading() { Init(); var doWork = new DoWorkClass(); _Lua.RegisterFunction("dowork", doWork, typeof(DoWorkClass).GetMethod("DoWork")); bool failureDetected = false; int completed = 0; int iterations = 500; for(int i = 0; i < iterations; i++) { ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object o) { try { _Lua.DoString("dowork()"); } catch { failureDetected = true; } completed++; })); } while(completed < iterations && !failureDetected) Thread.Sleep(50); if(failureDetected) Console.WriteLine("==Problem with threading!=="); } private void TestPrivateMethod() { Init(); _Lua.DoString("luanet.load_assembly('mscorlib')"); _Lua.DoString("luanet.load_assembly('TestLua')"); _Lua.DoString("TestClass=luanet.import_type('LuaInterface.Tests.TestClass')"); _Lua.DoString("test=TestClass()"); try { _Lua.DoString("test:_PrivateMethod()"); } catch { Console.WriteLine("Test Passed"); return; } Console.WriteLine("Test Failed"); } /* * Tests functions */ public void TestFunctions() { Init(); _Lua.DoString("luanet.load_assembly('mscorlib')"); _Lua.DoString("luanet.load_assembly('TestLua')"); _Lua.RegisterFunction("p", null, typeof(System.Console).GetMethod("WriteLine", new Type[] { typeof(String) })); /// Lua command that works (prints to console) _Lua.DoString("p('Foo')"); /// Yet this works... _Lua.DoString("string.gsub('some string', '(%w+)', function(s) p(s) end)"); /// This fails if you don't fix Lua5.1 lstrlib.c/add_value to treat LUA_TUSERDATA the same as LUA_FUNCTION _Lua.DoString("string.gsub('some string', '(%w+)', p)"); Destroy(); } /* * Tests making an object from a Lua table and calling one of * methods the table overrides. */ public void LuaTableOverridedMethod() { Init(); _Lua.DoString("luanet.load_assembly('TestLua')"); _Lua.DoString("TestClass=luanet.import_type('LuaInterface.Tests.TestClass')"); _Lua.DoString("test={}"); _Lua.DoString("function test:overridableMethod(x,y) return x*y; end"); _Lua.DoString("luanet.make_object(test,'LuaInterface.Tests.TestClass')"); _Lua.DoString("a=TestClass.callOverridable(test,2,3)"); int a = (int)_Lua.GetNumber("a"); _Lua.DoString("luanet.free_object(test)"); TestOk(6 == a); //Console.WriteLine("interface returned: "+a); } /* * Tests making an object from a Lua table and calling a method * the table does not override. */ public void LuaTableInheritedMethod() { Init(); _Lua.DoString("luanet.load_assembly('TestLua')"); _Lua.DoString("TestClass=luanet.import_type('LuaInterface.Tests.TestClass')"); _Lua.DoString("test={}"); _Lua.DoString("function test:overridableMethod(x,y) return x*y; end"); _Lua.DoString("luanet.make_object(test,'LuaInterface.Tests.TestClass')"); _Lua.DoString("test:setVal(3)"); _Lua.DoString("a=test.testval"); int a = (int)_Lua.GetNumber("a"); _Lua.DoString("luanet.free_object(test)"); TestOk(3 == a); //Console.WriteLine("interface returned: "+a); } /// /// Basic multiply method which expects 2 floats /// /// /// /// private float _TestException(float val, float val2) { return val * val2; } public void TestEventException() { Init(); //Register a C# function MethodInfo testException = this.GetType().GetMethod("_TestException", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance, null, new Type[] { typeof(float), typeof(float) }, null); _Lua.RegisterFunction("Multiply", this, testException); //create the lua event handler code for the entity //includes the bad code! _Lua.DoString("function OnClick(sender, eventArgs)\r\n" + "--Multiply expects 2 floats, but instead receives 2 strings\r\n" + "Multiply(asd, we)\r\n" + "end"); //create the lua event handler code for the entity //good code //lua.DoString("function OnClick(sender, eventArgs)\r\n" + // "--Multiply expects 2 floats\r\n" + // "Multiply(2, 50)\r\n" + // "end"); //Create the event handler script _Lua.DoString("function SubscribeEntity(e)\r\ne.Clicked:Add(OnClick)\r\nend"); //Create the entity object var entity = new Entity(); //Register the entity object with the event handler inside lua LuaFunction lf = _Lua.GetFunction("SubscribeEntity"); lf.Call(new object[1] { entity }); try { //Cause the event to be fired entity.Click(); Console.WriteLine("Test failed!!! Should have thrown an exception all the way out of Lua"); } catch (LuaException) { Console.WriteLine("Event exception success"); } } public void TestExceptionWithChunkOverload() { Init(); try { _Lua.DoString("thiswillthrowanerror", "MyChunk"); } catch(Exception e) { if (e.Message.StartsWith("[string \"MyChunk\"]")) Console.WriteLine("Chunk overload passed"); else Console.WriteLine("Chunk overload failed"); } } public void TestGenerics() { Init(); //Im not sure support for generic classes is possible to implement, see: http://msdn.microsoft.com/en-us/library/system.reflection.methodinfo.containsgenericparameters.aspx //specifically the line that says: "If the ContainsGenericParameters property returns true, the method cannot be invoked" //TestClassGeneric genericClass = new TestClassGeneric(); //_Lua.RegisterFunction("genericMethod", genericClass, typeof(TestClassGeneric<>).GetMethod("GenericMethod")); //_Lua.RegisterFunction("regularMethod", genericClass, typeof(TestClassGeneric<>).GetMethod("RegularMethod")); //try //{ // _Lua.DoString("genericMethod('thestring')"); //} //catch { } //try //{ // _Lua.DoString("regularMethod()"); //} //catch { } //if (genericClass.GenericMethodSuccess && genericClass.RegularMethodSuccess && genericClass.Validate("thestring")) // Console.WriteLine("Generic class passed"); //else // Console.WriteLine("Generic class failed"); bool passed = true; TestClassWithGenericMethod classWithGenericMethod = new TestClassWithGenericMethod(); _Lua.RegisterFunction("genericMethod2", classWithGenericMethod, typeof(TestClassWithGenericMethod).GetMethod("GenericMethod")); try { _Lua.DoString("genericMethod2(100)"); } catch { } if(!classWithGenericMethod.GenericMethodSuccess || !classWithGenericMethod.Validate(100)) //note the gotcha: numbers are all being passed to generic methods as doubles passed = false; try { _Lua.DoString("luanet.load_assembly('TestLua')"); _Lua.DoString("TestClass=luanet.import_type('LuaInterface.Tests.TestClass')"); _Lua.DoString("test=TestClass(56)"); _Lua.DoString("genericMethod2(test)"); } catch { } if(!classWithGenericMethod.GenericMethodSuccess || (classWithGenericMethod.PassedValue as TestClass).val != 56) passed = false; if(passed) Console.WriteLine("Class with generic method passed"); else Console.WriteLine("Class with generic method failed"); } public static int func(int x, int y) { return x + y; } public int funcInstance(int x, int y) { return x + y; } public void RegisterFunctionStressTest() { LuaFunction fc = null; const int Count = 200; // it seems to work with 41 Init(); var t = new MyClass(); for(int i = 1; i < Count - 1; ++i) fc = _Lua.RegisterFunction("func" + i, t, typeof(MyClass).GetMethod("Func1")); fc = _Lua.RegisterFunction("func" + (Count - 1), t, typeof(MyClass).GetMethod("Func1")); _Lua.DoString("print(func1())"); } /* * Sample test script that shows some of the capabilities of * LuaInterface */ public static void Main() { Console.WriteLine("Starting interpreter..."); var l = new Lua(); // Pause so we can connect with the debugger // Thread.Sleep(30000); Console.WriteLine("Reading test.lua file..."); l.DoFile("test.lua"); double width = l.GetNumber("width"); double height = l.GetNumber("height"); string message = l.GetString("message"); double color_r = l.GetNumber("color.r"); double color_g = l.GetNumber("color.g"); double color_b = l.GetNumber("color.b"); Console.WriteLine("Printing values of global variables width, height and message..."); Console.WriteLine("width: " + width); Console.WriteLine("height: " + height); Console.WriteLine("message: " + message); Console.WriteLine("Printing values of the 'color' table's fields..."); Console.WriteLine("color.r: " + color_r); Console.WriteLine("color.g: " + color_g); Console.WriteLine("color.b: " + color_b); width = 150; Console.WriteLine("Changing width's value and calling Lua function print to show it..."); l["width"] = width; l.GetFunction("print").Call(width); message = "LuaNet Interface Test"; Console.WriteLine("Changing message's value and calling Lua function print to show it..."); l["message"] = message; l.GetFunction("print").Call(message); color_r = 30; color_g = 10; color_b = 200; Console.WriteLine("Changing color's fields' values and calling Lua function print to show it..."); l["color.r"] = color_r; l["color.g"] = color_g; l["color.b"] = color_b; l.DoString("print(color.r,color.g,color.b)"); Console.WriteLine("Printing values of the tree table's fields..."); double leaf1 = l.GetNumber("tree.branch1.leaf1"); string leaf2 = l.GetString("tree.branch1.leaf2"); string leaf3 = l.GetString("tree.leaf3"); Console.WriteLine("leaf1: " + leaf1); Console.WriteLine("leaf2: " + leaf2); Console.WriteLine("leaf3: " + leaf3); leaf1 = 30; leaf2 = "new leaf2"; Console.WriteLine("Changing tree's fields' values and calling Lua function print to show it..."); l["tree.branch1.leaf1"] = leaf1; l["tree.branch1.leaf2"] = leaf2; l.DoString("print(tree.branch1.leaf1,tree.branch1.leaf2)"); Console.WriteLine("Returning values from Lua with 'return'..."); object[] vals = l.DoString("return 2,3"); Console.WriteLine("Returned: " + vals[0] + " and " + vals[1]); Console.WriteLine("Calling a Lua function that returns multiple values..."); object[] vals1 = l.GetFunction("func").Call(2, 3); Console.WriteLine("Returned: " + vals1[0] + " and " + vals1[1]); Console.WriteLine("Creating a table and filling it from C#..."); l.NewTable("tab"); l.NewTable("tab.tab"); l["tab.a"] = "a!"; l["tab.b"] = 5.5; l["tab.tab.c"] = 6.5; l.DoString("print(tab.a,tab.b,tab.tab.c)"); Console.WriteLine("Setting a table as another table's field..."); l["tab.a"] = l["tab.tab"]; l.DoString("print(tab.a.c)"); Console.WriteLine("Registering a C# static method and calling it from Lua..."); // Pause so we can connect with the debugger // Thread.Sleep(30000); l.RegisterFunction("func1", null, typeof(TestLuaInterface).GetMethod("func")); vals1 = l.GetFunction("func1").Call(2, 3); Console.WriteLine("Returned: " + vals1[0]); TestLuaInterface obj = new TestLuaInterface(); Console.WriteLine("Registering a C# instance method and calling it from Lua..."); l.RegisterFunction("func2", obj, typeof(TestLuaInterface).GetMethod("funcInstance")); vals1 = l.GetFunction("func2").Call(2, 3); Console.WriteLine("Returned: " + vals1[0]); Console.WriteLine("Testing throwing an exception..."); obj.ThrowUncaughtException(); Console.WriteLine("Testing catching an exception..."); obj.ThrowException(); Console.WriteLine("Testing inheriting a method from Lua..."); obj.LuaTableInheritedMethod(); Console.WriteLine("Testing overriding a C# method with Lua..."); obj.LuaTableOverridedMethod(); Console.WriteLine("Stress test RegisterFunction (based on a reported bug).."); obj.RegisterFunctionStressTest(); Console.WriteLine("Test structures..."); obj.TestStructs(); Console.WriteLine("Test Nullable types..."); obj.TestNullable(); Console.WriteLine("Test functions..."); obj.TestFunctions(); Console.WriteLine("Test method overloads..."); obj.TestMethodOverloads(); Console.WriteLine("Test accessing private method..."); obj.TestPrivateMethod(); Console.WriteLine("Test event exceptions..."); obj.TestEventException(); Console.WriteLine("Test chunk overload exception..."); obj.TestExceptionWithChunkOverload(); Console.WriteLine("Test generics..."); obj.TestGenerics(); Console.WriteLine("Test threading..."); obj.TestThreading(); Console.WriteLine("Test memory leakage..."); obj.TestDispose(); Console.WriteLine("Press enter to exit."); Console.ReadLine(); } } }