unit TestLuaWrapper; { Delphi DUnit Test Case ---------------------- This unit contains a skeleton test case class generated by the Test Case Wizard. Modify the generated code to correctly setup and call the methods from the unit being tested. } { .$RTTI EXPLICIT METHODS([vcPublished, vcPublic]) } interface uses TestFramework, System.Classes, LuaBind.Intf, LuaBind, System.Rtti, System.SysUtils; type // Test methods for class TLuaEngine TestTLuaEngine = class(TTestCase) strict private FLuaEngine: TLuaEngine; private public procedure SetUp; override; procedure TearDown; override; published procedure TestLoadScript; procedure TestLoadScript1; procedure TestLoadFromFile; procedure TestDeclareGlobalNil; procedure TestDeclareGlobalNumber; procedure TestDeclareGlobalInteger; procedure TestDeclareGlobalString; procedure TestDeclareGlobalBoolean; procedure TestDeclareGlobalLightUserData; procedure TestDeclareGlobalUserData; /// ///// procedure TestDeclareGlobalFunction; procedure TestGetGlobal; /// ///test core extensions procedure TestExposeDataSet; procedure TestExposeDelphiObject; procedure TestExposeDelphiObjectNoDeps; procedure TestExposeVCLDelphiObject; procedure TestExposeVCLDelphiObjectSetProperty; procedure TestCreateDelphiObject; procedure TestCreateDelphiObjectWithWringConstructor; /// ///// test helper pusher procedure TestPushTableWithIntegerKeys; procedure TestPushTableWithStringKeys; procedure TestPushTableWithTValueValues; procedure TestPushTableFromCompoundObject; /// //// procedure TestExecuteFunction; procedure TestMyDirtyTests; end; implementation uses System.IOUtils, LuaBind.CustomType.DataSet, Datasnap.DBClient, LuaBind.CustomType.PODO, LuaBind.CustomType.UserType, System.Generics.Collections, TestObjects; procedure TestTLuaEngine.SetUp; begin FLuaEngine := TLuaEngine.Create; end; procedure TestTLuaEngine.TearDown; begin FLuaEngine.Free; FLuaEngine := nil; end; procedure TestTLuaEngine.TestLoadScript; var AScript: AnsiString; begin FLuaEngine.LoadScript(AScript); FLuaEngine.Execute; FLuaEngine.LoadScript('local x = 1+2+3;'); FLuaEngine.Execute; ExpectedException := ELuaRuntimeException; FLuaEngine.LoadScript('local x = pippo.makeBooom();'); FLuaEngine.Execute; end; procedure TestTLuaEngine.TestLoadScript1; var AStream: TStream; begin AStream := TFile.OpenRead('test_01.lua'); FLuaEngine.LoadScript(AStream, true); FLuaEngine.Execute; end; procedure TestTLuaEngine.TestMyDirtyTests; begin FLuaEngine.LoadExternalLibraries(TLuaMyTest.Create); FLuaEngine.LoadFromFile('test_mydirtytest.lua'); FLuaEngine.Execute; end; procedure TestTLuaEngine.TestPushTableFromCompoundObject; var father, Child: TPerson; begin father := TPerson.Create; try father.Child := TPerson.Create; try father.FirstName := 'Daniele'; father.LastName := 'Teti'; father.Age := 32; father.Child.FirstName := 'Daniele Son'; father.Child.LastName := 'Teti'; father.Child.Age := 2; father.Child.Child := nil; FLuaEngine.DeclareTable('person', father); FLuaEngine.LoadScript ('s = person.FirstName .. person.LastName .. tostring(person.Age) .. person.Child.FirstName .. person.Child.LastName .. person.Child.Age'); FLuaEngine.Execute; CheckEquals('DanieleTeti32Daniele SonTeti2', FLuaEngine.GetGlobal('s').GetAsString); finally father.Child.Free; end; finally father.Free; end; end; procedure TestTLuaEngine.TestPushTableWithIntegerKeys; begin FLuaEngine.DeclareTable('mytable', [1, 2, 3, 4], ['daniele', 'teti', 'peter', 'parker']); FLuaEngine.LoadScript('s = mytable[1]..mytable[2]..mytable[3]..mytable[4]'); FLuaEngine.Execute; CheckEquals('danieletetipeterparker', FLuaEngine.GetGlobal('s').GetAsString) end; procedure TestTLuaEngine.TestPushTableWithStringKeys; begin FLuaEngine.DeclareTable('mytable', ['a', 'b', 'c', 'd'], ['daniele', 'teti', 'peter', 'parker']); FLuaEngine.LoadScript( 's1 = mytable["a"] .. mytable["b"] .. mytable["c"] .. mytable["d"];' + 's2 = mytable.a .. mytable.b .. mytable.c .. mytable.d'); FLuaEngine.Execute; CheckEquals('danieletetipeterparker', FLuaEngine.GetGlobal('s1').GetAsString); CheckEquals('danieletetipeterparker', FLuaEngine.GetGlobal('s2').GetAsString) end; procedure TestTLuaEngine.TestPushTableWithTValueValues; var dict: TDictionary; begin dict := TDictionary.Create; try dict.AddOrSetValue('hello', 'world'); dict.AddOrSetValue(1234, 'onetwothree'); dict.AddOrSetValue('yes', true); dict.AddOrSetValue('no', false); FLuaEngine.DeclareTable('mytable', dict); FLuaEngine.LoadScript ('s = mytable.hello .. mytable[1234] .. tostring(mytable.yes) .. tostring(mytable["no"])'); FLuaEngine.Execute; CheckEquals('worldonetwothreetruefalse', FLuaEngine.GetGlobal('s').GetAsString) finally dict.Free; end; end; procedure TestTLuaEngine.TestLoadFromFile; begin FLuaEngine.LoadFromFile('test_01.lua'); FLuaEngine.Execute; end; procedure TestTLuaEngine.TestDeclareGlobalNil; begin FLuaEngine.DeclareGlobalNil('_nil'); FLuaEngine.LoadScript(''); FLuaEngine.Execute; CheckTrue(FLuaEngine.GetGlobal('_nil').IsNil); end; procedure TestTLuaEngine.TestDeclareGlobalNumber; var Value : ILuaValue; _tot, _number1, _number2, _number3, _number4: Double; begin _number1 := 1; _number2 := 1.1234; _number3 := 1234.5678; _number4 := 12345678; FLuaEngine.DeclareGlobalNumber('_number1', _number1); FLuaEngine.DeclareGlobalNumber('_number2', _number2); FLuaEngine.DeclareGlobalNumber('_number3', _number3); FLuaEngine.DeclareGlobalNumber('_number4', _number4); FLuaEngine.LoadScript('_tot = _number1 + _number2 + _number3 + _number4;'); FLuaEngine.Execute; Value := FLuaEngine.GetGlobal('_tot'); CheckTrue(Value.IsNumber); CheckFalse(Value.IsInteger); CheckFalse(Value.IsString); CheckFalse(Value.IsNil); CheckFalse(Value.IsBoolean); CheckFalse(Value.IsLightUserData); _tot := _number1 + _number2 + _number3 + _number4; CheckTrue(abs(_tot - Value.GetAsNumber) < 0.0001); ExpectedException := ELuaException; Value.GetAsString; end; procedure TestTLuaEngine.TestDeclareGlobalInteger; var Value : ILuaValue; _tot, _number1, _number2, _number3, _number4: Integer; begin _number1 := 1; _number2 := 1234; _number3 := 12345678; _number4 := 12345678; FLuaEngine.DeclareGlobalInteger('_number1', _number1); FLuaEngine.DeclareGlobalInteger('_number2', _number2); FLuaEngine.DeclareGlobalInteger('_number3', _number3); FLuaEngine.DeclareGlobalInteger('_number4', _number4); FLuaEngine.LoadScript('_tot = _number1 + _number2 + _number3 + _number4;'); FLuaEngine.Execute; Value := FLuaEngine.GetGlobal('_tot'); CheckTrue(Value.IsNumber); /// a sum of integers returns a NUMBER result type.. :-( CheckFalse(Value.IsInteger); CheckFalse(Value.IsString); CheckFalse(Value.IsNil); CheckFalse(Value.IsBoolean); CheckFalse(Value.IsLightUserData); _tot := _number1 + _number2 + _number3 + _number4; CheckTrue(abs(_tot - Value.GetAsNumber) < 0.0001); ExpectedException := ELuaException; Value.GetAsString; end; procedure TestTLuaEngine.TestDeclareGlobalString; var Value : ILuaValue; _tot, _string1, _string2, _string3, _string4: AnsiString; begin _string1 := ''; _string2 := 'hello'; _string3 := 'Lua'; _string4 := 'world àèéùòìçò§£$%'; FLuaEngine.DeclareGlobalString('_string1', _string1); FLuaEngine.DeclareGlobalString('_string2', _string2); FLuaEngine.DeclareGlobalString('_string3', _string3); FLuaEngine.DeclareGlobalString('_string4', _string4); FLuaEngine.LoadScript('_tot = _string1 .. _string2 .. _string3 .. _string4;'); FLuaEngine.Execute; Value := FLuaEngine.GetGlobal('_tot'); CheckFalse(Value.IsNumber); CheckFalse(Value.IsInteger); CheckTrue(Value.IsString); CheckFalse(Value.IsNil); CheckFalse(Value.IsBoolean); CheckFalse(Value.IsLightUserData); _tot := _string1 + _string2 + _string3 + _string4; CheckEquals('helloLuaworld àèéùòìçò§£$%', _tot); ExpectedException := ELuaException; Value.GetAsInteger; end; procedure TestTLuaEngine.TestDeclareGlobalUserData; begin // FLuaEngine.DeclareGlobalUserData('pippo', nil); // FLuaEngine.LoadScript(''); // FLuaEngine.Execute; end; procedure TestTLuaEngine.TestExecuteFunction; var r: AnsiString; begin FLuaEngine.LoadScript('function myfunc(a,b,c) return a..b..c end'); FLuaEngine.Execute; r := FLuaEngine.ExecuteFunction('myfunc', ['hello', 'Lua', 'world']).AsString; CheckEquals('helloLuaworld', r); FLuaEngine.Reset; FLuaEngine.LoadFromFile('test_08.lua'); FLuaEngine.Execute; r := FLuaEngine.ExecuteFunction('myfunc', ['hello', 'Lua', 'world']).AsString; CheckEquals('helloLuaworld', r); end; procedure TestTLuaEngine.TestExposeDataSet; var ds: TClientDataSet; _1: string; _2: string; begin ds := TClientDataSet.Create(nil); try ds.LoadFromFile('samplecds.xml'); ds.Open; FLuaEngine.LoadExternalLibraries(TLuaDataSetExposerLibraries.Create); ExposeDataSet(FLuaEngine, ds, 'people'); FLuaEngine.LoadFromFile('test_02.lua'); FLuaEngine.Execute; finally ds.Free; end; _1 := TFile.ReadAllText('test_02_expected.txt'); _2 := TFile.ReadAllText('test_02.txt'); CheckEquals(_1, _2); end; procedure TestTLuaEngine.TestExposeDelphiObject; var person: TPerson; begin person := TPerson.Create; try FLuaEngine.LoadExternalLibraries(TLuaDelphiObjectExposerLibraries.Create); ExposeDelphiObject(FLuaEngine, person, 'person'); FLuaEngine.LoadFromFile('test_03.lua'); FLuaEngine.Execute; CheckEquals('Teti', FLuaEngine.GetGlobal('last_name').GetAsString); CheckEquals('Daniele', FLuaEngine.GetGlobal('first_name').GetAsString); CheckEquals('Mr. Daniele Teti', FLuaEngine.GetGlobal('full_name').GetAsString); CheckEquals(32, FLuaEngine.GetGlobal('age').GetAsInteger); CheckEquals('Teti', person.LastName); CheckEquals('Daniele', person.FirstName); CheckEquals(32, person.Age); finally person.Free; end; end; procedure TestTLuaEngine.TestExposeDelphiObjectNoDeps; var person: TPerson; begin person := TPerson.Create; try person.FirstName := 'Daniele'; person.LastName := 'Teti'; person.Age := 33; FLuaEngine.DeclareGlobalDelphiObjectAsTable(person, 'person'); // FLuaEngine.ExecuteScript('r = person.FirstName .. person.LastName .. tostring(person.Age)'); // CheckEquals('DanieleTeti33', FLuaEngine.GetGlobal('r').GetAsString); FLuaEngine.LoadScript('x = person:hello("parametro1", "parametro2")'); FLuaEngine.Execute; // FLuaEngine.ExecuteScript('person:BecomeOlder(1)'); CheckEquals('DanieleTeti34', FLuaEngine.GetGlobal('x').GetAsString); finally person.Free; end; end; procedure TestTLuaEngine.TestExposeVCLDelphiObject; var sl: TStringList; begin sl := TStringList.Create; try sl.Add('first'); FLuaEngine.LoadExternalLibraries(TLuaDelphiObjectExposerLibraries.Create); ExposeDelphiObject(FLuaEngine, sl, 'stringlist'); FLuaEngine.LoadFromFile('test_04.lua'); FLuaEngine.Execute; CheckEquals(4, sl.Count); finally sl.Free; end; end; procedure TestTLuaEngine.TestExposeVCLDelphiObjectSetProperty; var sl: TStringList; begin sl := TStringList.Create; try sl.Add('first'); sl.Add('two'); sl.Add('three'); FLuaEngine.LoadExternalLibraries(TLuaDelphiObjectExposerLibraries.Create); ExposeDelphiObject(FLuaEngine, sl, 'stringlist'); FLuaEngine.LoadFromFile('test_05.lua'); FLuaEngine.Execute; CheckEquals(1, sl.Count); CheckEquals('Daniele Teti', sl[0]); finally sl.Free; end; end; procedure TestTLuaEngine.TestCreateDelphiObject; begin FLuaEngine.LoadExternalLibraries(TLuaDelphiObjectExposerLibraries.Create); FLuaEngine.LoadFromFile('test_06.lua'); FLuaEngine.Execute; end; procedure TestTLuaEngine.TestCreateDelphiObjectWithWringConstructor; begin FLuaEngine.LoadExternalLibraries(TLuaDelphiObjectExposerLibraries.Create); FLuaEngine.LoadFromFile('test_07.lua'); ExpectedException := ELuaRuntimeException; FLuaEngine.Execute; end; procedure TestTLuaEngine.TestDeclareGlobalBoolean; var Value : ILuaValue; _tot, _boolean1, _boolean2, _boolean3, _boolean4: boolean; begin _boolean1 := true; _boolean2 := false; _boolean3 := true; _boolean4 := false; FLuaEngine.DeclareGlobalBoolean('_boolean1', _boolean1); FLuaEngine.DeclareGlobalBoolean('_boolean2', _boolean2); FLuaEngine.DeclareGlobalBoolean('_boolean3', _boolean3); FLuaEngine.DeclareGlobalBoolean('_boolean4', _boolean4); FLuaEngine.LoadScript('_tot = _boolean1 or _boolean2 and _boolean3 or _boolean4;'); FLuaEngine.Execute; Value := FLuaEngine.GetGlobal('_tot'); CheckFalse(Value.IsNumber); CheckFalse(Value.IsInteger); CheckFalse(Value.IsString); CheckFalse(Value.IsNil); CheckTrue(Value.IsBoolean); CheckFalse(Value.IsLightUserData); _tot := _boolean1 or _boolean2 and _boolean3 or _boolean4; CheckEquals(_tot, Value.GetAsBoolean); ExpectedException := ELuaException; Value.GetAsString; end; procedure TestTLuaEngine.TestDeclareGlobalFunction; function SayHello(L: Plua_State): Integer; cdecl; var s: AnsiString; begin s := lua_tostring(L, - 1); s := 'before ' + s + ' after'; lua_pop(L, 1); lua_pushstring(L, PAnsiChar(s)); Result := 1; end; var Value: ILuaValue; begin FLuaEngine.DeclareGlobalFunction('sayhello', @SayHello); FLuaEngine.LoadScript('x = sayhello("hello world")'); FLuaEngine.Execute; Value := FLuaEngine.GetGlobal('x'); CheckEquals('before hello world after', Value.GetAsString); end; procedure TestTLuaEngine.TestDeclareGlobalLightUserData; var Value: ILuaValue; _ptr : Pointer; Obj : TStringList; Obj2 : TStringList; function AddToTStringList(L: Plua_State): Integer; cdecl; var sl: TStringList; s : AnsiString; begin s := lua_tostring(L, - 1); lua_pop(L, 1); sl := TStringList(lua_topointer(L, - 1)); lua_pop(L, 1); sl.Add(s); Result := 0; end; begin _ptr := nil; FLuaEngine.DeclareGlobalLightUserData('_ptr', _ptr); FLuaEngine.LoadScript('x = _ptr'); FLuaEngine.Execute; Value := FLuaEngine.GetGlobal('x'); CheckTrue(Value.IsLightUserData); CheckTrue(Value.GetAsLightUserData = nil); // Now try to pass a tstringlist Obj := TStringList.Create; try Obj.Add('Hello World'); _ptr := Pointer(Obj); FLuaEngine.DeclareGlobalLightUserData('_ptr1', _ptr); FLuaEngine.DeclareGlobalFunction('additem', @AddToTStringList); FLuaEngine.LoadScript('x = _ptr1; additem(x,"added from Lua")'); FLuaEngine.Execute; Value := FLuaEngine.GetGlobal('x'); CheckFalse(Value.IsNumber); CheckFalse(Value.IsInteger); CheckFalse(Value.IsString); CheckFalse(Value.IsNil); CheckFalse(Value.IsBoolean); CheckTrue(Value.IsLightUserData); CheckNotNull(Value.GetAsLightUserData); _ptr := Value.GetAsLightUserData; Obj2 := TStringList(_ptr); CheckEquals(2, Obj2.Count); CheckEquals('Hello World', Obj2[0]); CheckEquals('added from Lua', Obj2[1]); finally Obj.Free; end; ExpectedException := ELuaException; Value.GetAsString; end; procedure TestTLuaEngine.TestGetGlobal; var ReturnValue: ILuaValue; AName : AnsiString; begin // TODO: Setup method call parameters ReturnValue := FLuaEngine.GetGlobal(AName); // TODO: Validate method results end; { TPerson } initialization // Register any test cases with the test runner RegisterTest(TestTLuaEngine.Suite); end.