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]])
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
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
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
Code: Select all
require('I2CEUnittests')
I2CEUnittests.ProjectsFolder = [[C:\Some\Folder\With\Lua\Unittests]]
require('I2CEUnittests.UnittestsForm')
local form = UnittestsForm('TestForm')
form.show()
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