mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-31 19:56:38 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			289 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			289 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
| local testing = require('testing_util')
 | |
| local core = require('openmw.core')
 | |
| local async = require('openmw.async')
 | |
| local util = require('openmw.util')
 | |
| local types = require('openmw.types')
 | |
| local world = require('openmw.world')
 | |
| 
 | |
| local function testTimers()
 | |
|     testing.expectAlmostEqual(core.getGameTimeScale(), 30, 'incorrect getGameTimeScale() result')
 | |
|     testing.expectAlmostEqual(core.getSimulationTimeScale(), 1, 'incorrect getSimulationTimeScale result')
 | |
| 
 | |
|     local startGameTime = core.getGameTime()
 | |
|     local startSimulationTime = core.getSimulationTime()
 | |
| 
 | |
|     local ts1, ts2, th1, th2
 | |
|     local cb = async:registerTimerCallback("tfunc", function(arg)
 | |
|         if arg == 'g' then
 | |
|             th1 = core.getGameTime() - startGameTime
 | |
|         else
 | |
|             ts1 = core.getSimulationTime() - startSimulationTime
 | |
|         end
 | |
|     end)
 | |
|     async:newGameTimer(36, cb, 'g')
 | |
|     async:newSimulationTimer(0.5, cb, 's')
 | |
|     async:newUnsavableGameTimer(72, function()
 | |
|         th2 = core.getGameTime() - startGameTime
 | |
|     end)
 | |
|     async:newUnsavableSimulationTimer(1, function()
 | |
|         ts2 = core.getSimulationTime() - startSimulationTime
 | |
|     end)
 | |
| 
 | |
|     while not (ts1 and ts2 and th1 and th2) do
 | |
|         coroutine.yield()
 | |
|     end
 | |
| 
 | |
|     testing.expectGreaterOrEqual(th1, 36, 'async:newGameTimer failed')
 | |
|     testing.expectGreaterOrEqual(ts1, 0.5, 'async:newSimulationTimer failed')
 | |
|     testing.expectGreaterOrEqual(th2, 72, 'async:newUnsavableGameTimer failed')
 | |
|     testing.expectGreaterOrEqual(ts2, 1, 'async:newUnsavableSimulationTimer failed')
 | |
| end
 | |
| 
 | |
| local function testTeleport()
 | |
|     player:teleport('', util.vector3(100, 50, 500), util.transform.rotateZ(math.rad(90)))
 | |
|     coroutine.yield()
 | |
|     testing.expect(player.cell.isExterior, 'teleport to exterior failed')
 | |
|     testing.expectEqualWithDelta(player.position.x, 100, 1, 'incorrect position after teleporting')
 | |
|     testing.expectEqualWithDelta(player.position.y, 50, 1, 'incorrect position after teleporting')
 | |
|     testing.expectEqualWithDelta(player.position.z, 500, 1, 'incorrect position after teleporting')
 | |
|     testing.expectEqualWithDelta(player.rotation:getYaw(), math.rad(90), 0.05, 'incorrect yaw rotation after teleporting')
 | |
|     testing.expectEqualWithDelta(player.rotation:getPitch(), math.rad(0), 0.05, 'incorrect pitch rotation after teleporting')
 | |
| 
 | |
|     local rotationX1, rotationZ1 = player.rotation:getAnglesXZ()
 | |
|     testing.expectEqualWithDelta(rotationX1, math.rad(0), 0.05, 'incorrect x rotation from getAnglesXZ after teleporting')
 | |
|     testing.expectEqualWithDelta(rotationZ1, math.rad(90), 0.05, 'incorrect z rotation from getAnglesXZ after teleporting')
 | |
| 
 | |
|     local rotationZ2, rotationY2, rotationX2 = player.rotation:getAnglesZYX()
 | |
|     testing.expectEqualWithDelta(rotationZ2, math.rad(90), 0.05, 'incorrect z rotation from getAnglesZYX after teleporting')
 | |
|     testing.expectEqualWithDelta(rotationY2, math.rad(0), 0.05, 'incorrect y rotation from getAnglesZYX after teleporting')
 | |
|     testing.expectEqualWithDelta(rotationX2, math.rad(0), 0.05, 'incorrect x rotation from getAnglesZYX after teleporting')
 | |
| 
 | |
|     player:teleport('', player.position, {rotation=util.transform.rotateZ(math.rad(-90)), onGround=true})
 | |
|     coroutine.yield()
 | |
|     testing.expectEqualWithDelta(player.rotation:getYaw(), math.rad(-90), 0.05, 'options.rotation is not working')
 | |
|     testing.expectLessOrEqual(player.position.z, 400, 'options.onGround is not working')
 | |
| 
 | |
|     player:teleport('', util.vector3(50, -100, 0))
 | |
|     coroutine.yield()
 | |
|     testing.expect(player.cell.isExterior, 'teleport to exterior failed')
 | |
|     testing.expectEqualWithDelta(player.position.x, 50, 1, 'incorrect position after teleporting')
 | |
|     testing.expectEqualWithDelta(player.position.y, -100, 1, 'incorrect position after teleporting')
 | |
|     testing.expectEqualWithDelta(player.rotation:getYaw(), math.rad(-90), 0.05, 'teleporting changes rotation')
 | |
| end
 | |
| 
 | |
| local function testGetGMST()
 | |
|     testing.expectEqual(core.getGMST('non-existed gmst'), nil)
 | |
|     testing.expectEqual(core.getGMST('Water_RippleFrameCount'), 4)
 | |
|     testing.expectEqual(core.getGMST('Inventory_DirectionalDiffuseR'), 0.5)
 | |
|     testing.expectEqual(core.getGMST('Level_Up_Level2'), 'something')
 | |
| end
 | |
| 
 | |
| local function testMWScript()
 | |
|     local variableStoreCount = 18
 | |
|     local variableStore = world.mwscript.getGlobalVariables(player)
 | |
|     testing.expectEqual(variableStoreCount, #variableStore)
 | |
|     
 | |
|     variableStore.year = 5
 | |
|     testing.expectEqual(5, variableStore.year)
 | |
|     variableStore.year = 1
 | |
|     local indexCheck = 0
 | |
|     for index, value in ipairs(variableStore) do
 | |
|         testing.expectEqual(variableStore[index], value)
 | |
|         indexCheck = indexCheck + 1
 | |
|     end
 | |
|     testing.expectEqual(variableStoreCount, indexCheck)
 | |
|     indexCheck = 0
 | |
|     for index, value in pairs(variableStore) do
 | |
|         testing.expectEqual(variableStore[index], value)
 | |
|         indexCheck = indexCheck + 1
 | |
|     end
 | |
|     testing.expectEqual(variableStoreCount, indexCheck)
 | |
| end
 | |
| 
 | |
| local function testRecordStore(store, storeName, skipPairs)
 | |
|     testing.expect(store.records)
 | |
|     local firstRecord = store.records[1]
 | |
|     if not firstRecord then
 | |
|         return
 | |
|     end
 | |
|     testing.expectEqual(firstRecord.id, store.records[firstRecord.id].id)
 | |
|     local status, _ = pcall(function()
 | |
|         for index, value in ipairs(store.records) do
 | |
|             if value.id == firstRecord.id then
 | |
|                 testing.expectEqual(index, 1, storeName)
 | |
|                 break
 | |
|             end
 | |
|         end
 | |
|     end)
 | |
| 
 | |
|     testing.expectEqual(status, true, storeName)
 | |
|     
 | |
| end
 | |
| 
 | |
| local function testRecordStores()
 | |
|     for key, type in pairs(types) do
 | |
|         if type.records then
 | |
|             testRecordStore(type, key)
 | |
|         end
 | |
|     end
 | |
|     testRecordStore(core.magic.enchantments, "enchantments")
 | |
|     testRecordStore(core.magic.effects, "effects", true)
 | |
|     testRecordStore(core.magic.spells, "spells")
 | |
| 
 | |
|     testRecordStore(core.stats.Attribute, "Attribute")
 | |
|     testRecordStore(core.stats.Skill, "Skill")
 | |
| 
 | |
|     testRecordStore(core.sound, "sound")
 | |
|     testRecordStore(core.factions, "factions")
 | |
| 
 | |
|     testRecordStore(types.NPC.classes, "classes")
 | |
|     testRecordStore(types.NPC.races, "races")
 | |
|     testRecordStore(types.Player.birthSigns, "birthSigns")
 | |
| end
 | |
| 
 | |
| local function testRecordCreation()
 | |
|     local newLight = {
 | |
|         isCarriable = true,
 | |
|         isDynamic = true,
 | |
|         isFire =false,
 | |
|         isFlicker = false,
 | |
|         isFlickerSlow = false,
 | |
|         isNegative = false,
 | |
|         isOffByDefault = false,
 | |
|         isPulse = false,
 | |
|         weight = 1,
 | |
|         value = 10,
 | |
|         duration = 12,
 | |
|         radius = 30,
 | |
|         color = 5,
 | |
|         name = "TestLight",
 | |
|         model = "meshes\\marker_door.dae"
 | |
|     }
 | |
|     local draft = types.Light.createRecordDraft(newLight)
 | |
|     local record = world.createRecord(draft)
 | |
|     for key, value in pairs(newLight) do
 | |
|         testing.expectEqual(record[key], value)
 | |
|     end
 | |
| end
 | |
| 
 | |
| local function testUTF8Chars()
 | |
|     testing.expectEqual(utf8.codepoint("😀"), 0x1F600)
 | |
| 
 | |
|     local chars = {}
 | |
| 
 | |
|     for codepoint = 0, 0x10FFFF do
 | |
|         local char = utf8.char(codepoint)
 | |
|         local charSize = string.len(char)
 | |
| 
 | |
|         testing.expect(not chars[char], nil, "Duplicate UTF-8 character: " .. char)
 | |
|         chars[char] = true
 | |
| 
 | |
|         if codepoint <= 0x7F then
 | |
|             testing.expectEqual(charSize, 1)
 | |
|         elseif codepoint <= 0x7FF then
 | |
|             testing.expectEqual(charSize, 2)
 | |
|         elseif codepoint <= 0xFFFF then
 | |
|             testing.expectEqual(charSize, 3)
 | |
|         elseif codepoint <= 0x10FFFF then
 | |
|             testing.expectEqual(charSize, 4)
 | |
|         end
 | |
| 
 | |
|         testing.expectEqual(utf8.codepoint(char), codepoint)
 | |
|         testing.expectEqual(utf8.len(char), 1)
 | |
|     end
 | |
| end
 | |
| 
 | |
| local function testUTF8Strings()
 | |
|     local utf8str = "Hello, 你好, 🌎!"
 | |
| 
 | |
|     local str = ""
 | |
|     for utf_char in utf8str:gmatch(utf8.charpattern) do
 | |
|         str = str .. utf_char
 | |
|     end
 | |
|     testing.expectEqual(str, utf8str)
 | |
| 
 | |
|     testing.expectEqual(utf8.len(utf8str), 13)
 | |
|     testing.expectEqual(utf8.offset(utf8str, 9), 11)
 | |
| end
 | |
| 
 | |
| local function testMemoryLimit()
 | |
|     local ok, err = pcall(function()
 | |
|         local t = {}
 | |
|         local n = 1
 | |
|         while true do
 | |
|             t[n] = n
 | |
|             n = n + 1
 | |
|         end
 | |
|     end)
 | |
|     testing.expectEqual(ok, false, 'Script reaching memory limit should fail')
 | |
|     testing.expectEqual(err, 'not enough memory')
 | |
| end
 | |
| 
 | |
| local function initPlayer()
 | |
|     player:teleport('', util.vector3(4096, 4096, 867.237), util.transform.identity)
 | |
|     coroutine.yield()
 | |
| end
 | |
| 
 | |
| tests = {
 | |
|     {'timers', testTimers},
 | |
|     {'rotating player with controls.yawChange should change rotation', function()
 | |
|         initPlayer()
 | |
|         testing.runLocalTest(player, 'playerYawRotation')
 | |
|     end},
 | |
|     {'rotating player with controls.pitchChange should change rotation', function()
 | |
|         initPlayer()
 | |
|         testing.runLocalTest(player, 'playerPitchRotation')
 | |
|     end},
 | |
|     {'rotating player with controls.pitchChange and controls.yawChange should change rotation', function()
 | |
|         initPlayer()
 | |
|         testing.runLocalTest(player, 'playerPitchAndYawRotation')
 | |
|     end},
 | |
|     {'rotating player should not lead to nan rotation', function()
 | |
|         initPlayer()
 | |
|         testing.runLocalTest(player, 'playerRotation')
 | |
|     end},
 | |
|     {'playerForwardRunning', function()
 | |
|         initPlayer()
 | |
|         testing.runLocalTest(player, 'playerForwardRunning')
 | |
|     end},
 | |
|     {'playerDiagonalWalking', function()
 | |
|         initPlayer()
 | |
|         testing.runLocalTest(player, 'playerDiagonalWalking')
 | |
|     end},
 | |
|     {'findPath', function()
 | |
|         initPlayer()
 | |
|         testing.runLocalTest(player, 'findPath')
 | |
|     end},
 | |
|     {'findRandomPointAroundCircle', function()
 | |
|         initPlayer()
 | |
|         testing.runLocalTest(player, 'findRandomPointAroundCircle')
 | |
|     end},
 | |
|     {'castNavigationRay', function()
 | |
|         initPlayer()
 | |
|         testing.runLocalTest(player, 'castNavigationRay')
 | |
|     end},
 | |
|     {'findNearestNavMeshPosition', function()
 | |
|         initPlayer()
 | |
|         testing.runLocalTest(player, 'findNearestNavMeshPosition')
 | |
|     end},
 | |
|     {'teleport', testTeleport},
 | |
|     {'getGMST', testGetGMST},
 | |
|     {'recordStores', testRecordStores},
 | |
|     {'recordCreation', testRecordCreation},
 | |
|     {'utf8Chars', testUTF8Chars},
 | |
|     {'utf8Strings', testUTF8Strings},
 | |
|     {'mwscript', testMWScript},
 | |
|     {'testMemoryLimit', testMemoryLimit},
 | |
|     {'playerMemoryLimit', function()
 | |
|         initPlayer()
 | |
|         testing.runLocalTest(player, 'playerMemoryLimit')
 | |
|     end}
 | |
| }
 | |
| 
 | |
| return {
 | |
|     engineHandlers = {
 | |
|         onUpdate = testing.testRunner(tests),
 | |
|         onPlayerAdded = function(p) player = p end,
 | |
|     },
 | |
|     eventHandlers = testing.eventHandlers,
 | |
| }
 |