[Lua] CE unittesting framework

Upload *YOUR* gamehacking tools/helpers here
Post Reply
UltimatePoto42
Expert Cheater
Expert Cheater
Posts: 125
Joined: Tue May 02, 2017 6:00 am
Reputation: 15

[Lua] CE unittesting framework

Post by UltimatePoto42 »

I2CEUnittests

A CE Lua unittesting framework.

Had trouble getting a Lua unittesting framework to work in CE. So I created a very simple one. It only works on simple types. For more complex types they need to set the appropriate metamethods. It will search recursively for unittest files, or an order list (table/array) can be passed for explicit orders if needed.

I'm posting an archive with the modules and a table setup to launch a testing form. But the framework works with out the form. The testing form should be easy to customize.

This is intended for testing Lua modules, but you can setup the unittests to test table features as well. It times each test in milliseconds which can help find bottle necks in your code.



To just use the framework:

Code: Select all

require('I2CEUnittests')
I2CEUnittests.ProjectsFolder = [[]]
---- Settings (these are the defaults)
-- I2CEUnittests.PrintFilePath = false
-- I2CEUnittests.UnittestsClassMatchPattern = '_unittests$'
-- I2CEUnittests.UnittestsClassHiddenMatchPattern = '^_'
-- I2CEUnittests.TestNameTrimPattern = '_test$'
-- I2CEUnittests.SetupName = 'setup'
-- I2CEUnittests.CleanName = 'clean'
-- I2CEUnittests.NamePaddingLenght = 40
-- I2CEUnittests.LineTab = '    '

---- runAllUnittests(folderOrModulesList, hailtOnFail)
	---- Simplest way to use.
		---- will use current folder or "I2CEUnittests.ProjectsFolder".
		--runAllUnittests()

	---- For a specific order of testing.
		-- local list = {
		-- 	'full.name.for.require', 
		-- 	'some.module.to.test', 
		-- 	'I2CETLua.unittests.AutoAssembler.ceaFile_unittests', 
		-- }
		-- runAllUnittests(list)
---- Will search recursively for unittest files. 
runAllUnittests([[X:\some\folder\with\unittests]])
Here is an example unit test:

Code: Select all

local NAME = 'unittests.example_unittests'
---- unittests modules must end with "_unittests".
---- 	See: "I2CEUnittests.UnittestsClassMatchPattern" to set match pattern.
require('I2CEUnittests')
local ut = I2CEUnittests(NAME)

---- re-requires modules for testing
-- ut:require('example')

---- test environment setup
----	See: "I2CEUnittests.SetupName" to set name.
----    These don't need to be declared and are optional. 
function ut.setup(self)
end
---- test environment clean up
----	See: "I2CEUnittests.CleanName" to set name.
----    These don't need to be declared and are optional. 
function ut.clean(self)
end

---- Best to end test names with "_test" to prevent naming conflicts. 
----	"_test" is trimmed from the end of test names.
----	See: "I2CEUnittests.TestNameTrimPattern" to set match pattern.
function ut.passExample_test(self)
	---- Simple types is all it really works on. 
	---- 	Uses "==" and "~=" at the core of compares.
	---- 	For more complex types they must set the compare metamethods.
	self:assertEqual(1, 1)
	self:assertNotEqual(1, 0)
	self:assertTrue(true)
	self:assertFalse(false)
	self:assertNil(nil)
	self:assertNotNil({ })
	self:assertType('table', { })
	self:assertNotType('table', 'some string')
	self:assertError(error, 'this is an error.')
end
function ut.failExample_test(self)
	---- Individual tests stop at first error. 
	---- 	But the other class Tests will still be finished.
	self:assertEqual(1, 2, 'Oh, no!') ---- Messages can be passed.
	self:assertNotEqual(1, 1)
	self:assertTrue(nil)
	self:assertFalse(nil)
	self:assertNil('nil')
	self:assertNotNil(nil)
	self:assertType('table', 10)
	self:assertNotType('string', 'some string')
	self:assertError(print, 'this is NOT an error.')
end

return ut
Example output:

Code: Select all

================================================================================
Running All Tests in folder: [Projects Folder]
--------------------------------------------------------------------------------
Running : I2CETLua.unittests.AutoAssembler.ceaFile_unittests
    autoAssembleFile                          Passed    .   in   47   ms
--------------------------------------------------------------------------------
Running : I2CETLua.unittests.AutoAssembler.commands_unittests
    checkForLuaGlobal                         Passed    .   in   0    ms
    checkParameter                            Passed    .   in   0    ms
    defineSymbolAA                            Passed    .   in   0    ms
    getCodeLines                              Passed    .   in   125  ms
    getOpcodeAddressAA                        Passed    .   in   0    ms
    getParameters                             Passed    .   in   0    ms
    i2aobScanAA                               Passed    .   in   1029 ms
    i2aobScanModuleAA                         Passed    .   in   203  ms
    i2assertAA                                Passed    .   in   0    ms
    padAA                                     Passed    .   in   0    ms
    parseNumberOrAddress                      Passed    .   in   0    ms
    registerLabelAA                           Passed    .   in   0    ms
    repBytesAA                                Passed    .   in   0    ms
    undefineSymbolAA                          Passed    .   in   0    ms
    unregisterLabelAA                         Passed    .   in   0    ms
--------------------------------------------------------------------------------
Running : I2CETLua.unittests.Teleporter.Teleporter_unittests
    setup                                     Complete  .   in   0    ms
    getData                                   Passed    .   in   0    ms
    loadLocation                              Passed    .   in   0    ms
    saveLocation                              Passed    .   in   15   ms
    teleportBack                              Passed    .   in   0    ms
    teleportToWaypoint                        Passed    .   in   0    ms
    teleport                                  Passed    .   in   0    ms
    clean                                     Complete  .   in   0    ms
--------------------------------------------------------------------------------
All tests completed in:  4.385 s
    Executed in:     3.370 s
    Modules Ran:     14
      Tests Ran:     131
    Modules Passed:  14
      Tests Passed:  131
Example output with a fail:

Code: Select all

================================================================================
Running All Tests in folder: [current folder]
--------------------------------------------------------------------------------
Running : unittests.example_unittests
    setup                                     Complete  .   in   0    ms
    failExample_test                          FAILED    X   in   0    ms  
    ::example_unittests.lua:45: assertEqual failed!
                    expected : number   : 1
                    real     : number   : 2
                    Oh, no!
    passExample                               Passed    .   in   0    ms
    clean                                     Complete  .   in   0    ms
--------------------------------------------------------------------------------
All tests completed in:  0.013 s
    Executed in:     0.000 s
    Modules Ran:     1
      Tests Ran:     2
    Modules Passed:  0
      Tests Passed:  1
    --------------------
    Modules FAILED:  1
      Tests FAILED:  1
Setup for the testing form is simple:

Code: Select all

require('I2CEUnittests')
I2CEUnittests.ProjectsFolder = [[C:\Some\Folder\With\Lua\Unittests]]
require('I2CEUnittests.UnittestsForm')
local form = UnittestsForm('TestForm')
form.show()
Image

A full example of a more complex unittest:

Code: Select all

local NAME = 'I2CETLua.unittests.objects.GroupedMemory_unittests'


require('I2CEUnittests')
local ut = I2CEUnittests(NAME)


ut:require('I2CETLua.objects.GroupedMemory')


require('I2CETLua.objects.Memory')

local memoryName = 'GroupedMemory_unittests'
local memoryNameLocal = 'GroupedMemory_unittests_Local'
local memoryAddress
local memoryAddressLocal

local groupedMemory = GroupedMemory({
	List = {
		Memory({
			Name = memoryName, 
			Type = MemoryTypes.Single, 
		}), 
		Memory({
			Name = memoryName..'+4', 
			Type = MemoryTypes.Single, 
		}), 
		Memory({
			Name = memoryName..'+8', 
			Type = MemoryTypes.Single, 
		}), 
		Memory({
			Name = memoryName..'+C', 
			Type = MemoryTypes.Dword, 
		}), 
	}, 
})
local groupedMemoryLocal = GroupedMemory({
	List = {
		Memory({
			Name = memoryNameLocal, 
			Type = MemoryTypes.Single, 
			TargetSelf = true, 
		}), 
		Memory({
			Name = memoryNameLocal..'+4', 
			Type = MemoryTypes.Single, 
			TargetSelf = true, 
		}), 
		Memory({
			Name = memoryNameLocal..'+8', 
			Type = MemoryTypes.Single, 
			TargetSelf = true, 
		}), 
		Memory({
			Name = memoryNameLocal..'+C', 
			Type = MemoryTypes.Dword, 
			TargetSelf = true, 
		}), 
	}, 
})


function ut.setup(self)
	if getAddressSafe(memoryName) then
		unregisterSymbol(memoryName)
	end
	if getAddressSafe(memoryNameLocal, true) or getAddressSafe(memoryNameLocal) then
		unregisterSymbol(memoryNameLocal)
	end
	memoryAddress = allocateSharedMemory(0x400)
	memoryAddressLocal = allocateSharedMemoryLocal(0x400)
	registerSymbol(memoryName, memoryAddress)
	registerSymbol(memoryNameLocal, memoryAddressLocal)
end

function ut.clean(self)
	deAlloc(memoryAddress)
	deAlloc(memoryAddressLocal)
	if getAddressSafe(memoryName) then
		unregisterSymbol(memoryName)
	end
	if getAddressSafe(memoryNameLocal, true) then
		unregisterSymbol(memoryNameLocal)
	end
end


function ut.getAddress_test(self)
	local memAddress = getAddress(memoryName)
	self:assertEqual(memAddress, groupedMemory:getAddress(1))
	memAddress = getAddress(memoryName..'+4')
	self:assertEqual(memAddress, groupedMemory:getAddress(2))
	memAddress = getAddress(memoryName..'+8')
	self:assertEqual(memAddress, groupedMemory:getAddress(3))
	memAddress = getAddress(memoryName..'+C')
	self:assertEqual(memAddress, groupedMemory:getAddress(4))
	----
	memAddress = getAddress(memoryNameLocal)
	self:assertEqual(memAddress, groupedMemoryLocal:getAddress(1))
	memAddress = getAddress(memoryNameLocal..'+4')
	self:assertEqual(memAddress, groupedMemoryLocal:getAddress(2))
	memAddress = getAddress(memoryNameLocal..'+8')
	self:assertEqual(memAddress, groupedMemoryLocal:getAddress(3))
	memAddress = getAddress(memoryNameLocal..'+C')
	self:assertEqual(memAddress, groupedMemoryLocal:getAddress(4))
	----
	self:assertError(groupedMemory.getAddress, groupedMemory, 5)
end

function ut.read_test(self)
	writeFloat(memoryName, 100)
	writeFloat(memoryName..'+4', 200)
	writeFloat(memoryName..'+8', 300)
	writeInteger(memoryName..'+C', 400)
	self:assertEqual(100, groupedMemory:read(1))
	self:assertEqual(200, groupedMemory:read(2))
	self:assertEqual(300, groupedMemory:read(3))
	self:assertEqual(400, groupedMemory:read(4))
	----
	writeFloatLocal(memoryNameLocal, 100)
	writeFloatLocal(memoryNameLocal..'+4', 200)
	writeFloatLocal(memoryNameLocal..'+8', 300)
	writeIntegerLocal(memoryNameLocal..'+C', 400)
	self:assertEqual(100, groupedMemoryLocal:read(1))
	self:assertEqual(200, groupedMemoryLocal:read(2))
	self:assertEqual(300, groupedMemoryLocal:read(3))
	self:assertEqual(400, groupedMemoryLocal:read(4))
	----
	self:assertError(groupedMemory.read, groupedMemory, 5)
end

function ut.write_test(self)
	groupedMemory:write(1, 10)
	groupedMemory:write(2, 20)
	groupedMemory:write(3, 30)
	groupedMemory:write(4, 40)
	self:assertEqual(10, readFloat(memoryName))
	self:assertEqual(20, readFloat(memoryName..'+4'))
	self:assertEqual(30, readFloat(memoryName..'+8'))
	self:assertEqual(40, readInteger(memoryName..'+C'))
	----
	groupedMemoryLocal:write(1, 10)
	groupedMemoryLocal:write(2, 20)
	groupedMemoryLocal:write(3, 30)
	groupedMemoryLocal:write(4, 40)
	-- self:assertEqual(10, readFloatLocal(memoryNameLocal))
	-- self:assertEqual(20, readFloatLocal(memoryNameLocal..'+4'))
	-- self:assertEqual(30, readFloatLocal(memoryNameLocal..'+8'))
	-- self:assertEqual(40, readIntegerLocal(memoryNameLocal..'+C'))
	self:assertEqual(10, readFloat(memoryNameLocal))
	self:assertEqual(20, readFloat(memoryNameLocal..'+4'))
	self:assertEqual(30, readFloat(memoryNameLocal..'+8'))
	self:assertEqual(40, readInteger(memoryNameLocal..'+C'))
	----
	self:assertError(groupedMemory.write, groupedMemory, 5)
end

function ut.getAddressAll_test(self)
	local memAddress1 = getAddress(memoryName)
	local memAddress2 = getAddress(memoryName..'+4')
	local memAddress3 = getAddress(memoryName..'+8')
	local memAddress4 = getAddress(memoryName..'+C')
	local a1, a2, a3, a4, a5 = groupedMemory:getAddressAll()
	self:assertEqual(memAddress1, a1)
	self:assertEqual(memAddress2, a2)
	self:assertEqual(memAddress3, a3)
	self:assertEqual(memAddress4, a4)
	self:assertNil(a5)
	local data = groupedMemory:getAddressAll(true)
	self:assertEqual(memAddress1, data[1])
	self:assertEqual(memAddress2, data[2])
	self:assertEqual(memAddress3, data[3])
	self:assertEqual(memAddress4, data[4])
	self:assertNil(data[5])
	----
	local gm = GroupedMemory('test')
	self:assertNil(gm:getAddressAll())
	self:assertNil(gm:getAddressAll(true))
end

function ut.readAll_test(self)
	writeFloat(memoryName, 100)
	writeFloat(memoryName..'+4', 200)
	writeFloat(memoryName..'+8', 300)
	writeInteger(memoryName..'+C', 400)
	local v1, v2, v3, v4 = groupedMemory:readAll()
	self:assertEqual(100, v1)
	self:assertEqual(200, v2)
	self:assertEqual(300, v3)
	self:assertEqual(400, v4)
	local data = groupedMemory:readAll(true)
	self:assertEqual(100, data[1])
	self:assertEqual(200, data[2])
	self:assertEqual(300, data[3])
	self:assertEqual(400, data[4])
	----
	local gm = GroupedMemory('test')
	self:assertNil(gm:readAll())
	self:assertNil(gm:readAll(true))
end

function ut.writeAll_test(self)
	groupedMemory:writeAll(10, 20, 30, 40)
	self:assertEqual(10, readFloat(memoryName))
	self:assertEqual(20, readFloat(memoryName..'+4'))
	self:assertEqual(30, readFloat(memoryName..'+8'))
	self:assertEqual(40, readInteger(memoryName..'+C'))
	writeFloat(memoryName, 100)
	writeFloat(memoryName..'+4', 200)
	writeFloat(memoryName..'+8', 300)
	writeInteger(memoryName..'+C', 400)
	groupedMemory:writeAll({ 10, 20, 30, 40 })
	self:assertEqual(10, readFloat(memoryName))
	self:assertEqual(20, readFloat(memoryName..'+4'))
	self:assertEqual(30, readFloat(memoryName..'+8'))
	self:assertEqual(40, readInteger(memoryName..'+C'))
	----
	local gm = GroupedMemory('test')
	gm:writeAll()
end


return ut

Post Reply

Who is online

Users browsing this forum: No registered users