Files
ShaguTweaks-ClassicAPI/tests/test_initialization_hooks.lua

65 lines
3.3 KiB
Lua

local root=(arg[1] or '.')..'/'
local file=assert(io.open(root..'helpers.lua'));local source=file:read('*a');file:close()
assert(loadstring(source))
local first=assert(string.find(source,'-- One event listener for deferred',1,true))
local last=assert(string.find(source,'ShaguTweaks.hooksecurefunc =',first,true))
local frames,loaded,checks,errors={},{},{},{}
ShaguTweaks={}
function CreateFrame()
local frame={events={},scripts={}}
function frame:RegisterEvent(e) self.events[e]=true end
function frame:UnregisterAllEvents() self.events={} end
function frame:SetScript(k,v) self.scripts[k]=v end
table.insert(frames,frame);return frame
end
function IsAddOnLoaded(name) checks[name]=(checks[name] or 0)+1;return loaded[name] end
function geterrorhandler() return function(message) table.insert(errors,message) end end
local chunk=assert(loadstring('local _G=getfenv(0)\n'..string.sub(source,first,last-1)))
chunk()
assert(table.getn(frames)==0)
local hook=ShaguTweaks.HookAddonOrVariable
local calls={}
local function emit(name,payload)
local oldThis,oldEvent,oldArg=this,event,arg1
this,event,arg1=frames[1],name,payload
frames[1].scripts.OnEvent()
assert(this==frames[1] and event==name and arg1==payload)
this,event,arg1=oldThis,oldEvent,oldArg
end
loaded.Already=true
hook('Already',function(frame)
assert(frame==this and frame.func and event=='ADDON_LOADED' and arg1=='Payload')
table.insert(calls,'first');arg1='changed';event='changed';this=nil
hook('Nested',function() table.insert(calls,'nested') end)
-- Reentrant events may not drain/overwrite the active callback snapshot.
emit('ADDON_LOADED','Inner')
end)
hook('Already',function() assert(arg1=='Payload');table.insert(calls,'second') end)
_G.ExistingGlobal={}
hook('ExistingGlobal',function() table.insert(calls,'global') end)
hook('Missing',function() table.insert(calls,'missing') end)
loaded.Nested=true
assert(table.getn(frames)==1 and table.getn(calls)==0 and not frames[1].scripts.OnUpdate)
emit('ADDON_LOADED','Payload')
assert(table.concat(calls,',')=='first,second,global')
assert(checks.Already==1 and checks.ExistingGlobal==1 and checks.Missing==1)
emit('VARIABLES_LOADED')
assert(calls[4]=='nested' and frames[1].events.ADDON_LOADED)
loaded.Missing=true
emit('PLAYER_ENTERING_WORLD')
assert(calls[5]=='missing' and not next(frames[1].events))
emit('ADDON_LOADED');assert(table.getn(calls)==5)
-- Reactivate the same listener; one failed callback must not block the next.
hook('Already',function() error('expected initialization failure') end)
hook('Already',function() table.insert(calls,'after-error') end)
assert(frames[1].events.VARIABLES_LOADED and table.getn(frames)==1)
emit('ADDON_LOADED')
assert(table.getn(errors)==1 and calls[6]=='after-error' and not next(frames[1].events))
emit('ADDON_LOADED');assert(table.getn(errors)==1 and table.getn(calls)==6)
-- Global truthiness preserves the old contract, including numeric zero.
_G.LaterGlobal=false;hook('LaterGlobal',function() table.insert(calls,'later') end)
emit('VARIABLES_LOADED');assert(table.getn(calls)==6)
_G.LaterGlobal=0;emit('PLAYER_ENTERING_WORLD');assert(calls[7]=='later')
assert(not next(frames[1].events) and table.getn(frames)==1)
print('Initialization hooks: one lazy listener, deferred readiness, deduplicated checks, ordered callbacks, nested/reentrant registration, context, error isolation, teardown and rearming passed')