Apply Patch

This commit is contained in:
2026-10-30 16:43:11 +00:00
parent 3a23425849
commit bb7b1fee21
7 changed files with 1256 additions and 0 deletions
+110
View File
@@ -0,0 +1,110 @@
unpack = unpack or table.unpack
getglobal = function(n) return _G[n] end
now = 100
GetTime = function() return now end
SlashCmdList = {}
messages = {}
DEFAULT_CHAT_FRAME = {AddMessage=function(self,s) table.insert(messages,s) end}
DebuffTypeColor = {none={r=.8,g=0,b=0}, Magic={r=0,g=.5,b=1}, Poison={r=0,g=1,b=0}}
frames = {}
local M = {}
function M:GetName() return self.name end
function M:SetAllPoints(x) self.allPoints=x end
function M:GetFrameLevel() return self.level or 1 end
function M:SetFrameLevel(n) self.level=n end
function M:SetFont(path,size,flags) self.font=path; self.fontSize=size end
function M:SetPoint(...) self.point={...} end
function M:ClearAllPoints() self.point=nil end
function M:Show() self.shown=true end
function M:Hide() self.shown=false end
function M:IsShown() return self.shown end
function M:SetWidth(v) self.width=v end
function M:SetHeight(v) self.height=v end
function M:SetText(v) self.text=v end
function M:SetTextColor(...) self.color={...} end
function M:SetVertexColor(...) self.color={...} end
function M:SetTexture(v) self.texture=v end
function M:SetTexCoord(...) self.coords={...} end
function M:SetScript(k,v) self.scripts[k]=v end
function M:RegisterEvent(k) self.events[k]=true end
function M:UnregisterEvent(k) self.events[k]=nil end
function M:SetChecked(v) self.checked=v end
function M:GetChecked() return self.checked end
function M:SetMinMaxValues(a,b) self.min=a; self.max=b end
function M:SetValueStep(v) self.step=v end
function M:SetValue(v)
self.value=v
if self.scripts.OnValueChanged then local old=this; this=self; self.scripts.OnValueChanged(); this=old end
end
function M:GetValue() return self.value end
function M:SetCooldown(start,duration) self.start=start; self.duration=duration; self.calls=(self.calls or 0)+1; self:Show() end
function M:SetReverse(v) self.reverse=v end
function M:SetDrawEdge(v) self.edge=v end
function M:IsOwned(button) return self.owner==button end
function M:SetOwner(button) self.owner=button end
function M:SetUnitAura(unit,index,filter) self.tooltip={unit,index,filter} end
local function New(name)
local f=setmetatable({name=name,shown=true,scripts={},events={}}, {__index=M})
if name then _G[name]=f end
return f
end
function M:CreateFontString(name) return New(name) end
function M:CreateTexture(name) return New(name) end
function CreateFrame(kind,name,parent,template)
if kind=="Cooldown" and noCooldown then error("Unknown frame type") end
local f=New(name); f.parent=parent; f.kind=kind
table.insert(frames,f)
if template=="UICheckButtonTemplate" then New(name.."Text") end
if template=="OptionsSliderTemplate" then New(name.."Text"); New(name.."Low"); New(name.."High") end
return f
end
UIParent=New("UIParent")
GameTooltip=New("GameTooltip")
TargetFrame=New("TargetFrame")
TargetFrameBuffFrame=New("TargetFrameBuffFrame")
for i=1,32 do New("TargetFrameBuff"..i); New("TargetFrameBuff"..i.."Icon") end
for i=1,16 do New("TargetFrameDebuff"..i); New("TargetFrameDebuff"..i.."Icon"); New("TargetFrameDebuff"..i.."Count"); New("TargetFrameDebuff"..i.."Border") end
TargetDebuffButton_Update=function() end
auras={HELPFUL={},HARMFUL={}}
nativeBuffs={}
nativeDebuffs={}
UnitBuff=function(u,i) return nativeBuffs[i] end
UnitDebuff=function(u,i) local a=nativeDebuffs[i]; if a then return unpack(a) end end
calls={index=0,slots=0,bySlot=0}
local epoch=0
local slotMap={}
function Aura(icon,count,duration,expiration,removable,dispel)
return {icon,icon,count or 1,dispel or "Magic",duration or 30,expiration or 130,"player",removable or false}
end
function InstallAPI(batched)
C_UnitAuras={}
C_UnitAuras.UnitAura=function(u,i,filter)
calls.index=calls.index+1
local a=auras[filter][i]
if a then return unpack(a,1,8) end
end
if batched then
C_UnitAuras.GetAuraSlots=function(u,filter,max,token,buf)
calls.slots=calls.slots+1; epoch=epoch+1; slotMap={}
local n=table.getn(auras[filter])
for i=1,n do buf[i]=epoch*1000+i; slotMap[buf[i]]=auras[filter][i] end
for i=n+1,table.getn(buf) do buf[i]=nil end
buf.n=n
return nil,n
end
C_UnitAuras.UnitAuraBySlot=function(u,id)
calls.bySlot=calls.bySlot+1
assert(slotMap[id],"stale slot used")
return unpack(slotMap[id],1,8)
end
end
end
function LoadSettings()
for _,f in ipairs(frames) do
if f.events.ADDON_LOADED then
this=f; arg1="TargetFrameBuff"; f.scripts.OnEvent()
end
end
end
function Tick() TargetFrameBuff_Update(); TargetFrameBuff_OnUpdate(.2) end
+219
View File
@@ -0,0 +1,219 @@
import sys
from pathlib import Path
import xml.etree.ElementTree as ET
sys.path.insert(0, str(Path("work/pythonlibs").resolve()))
from lupa.lua51 import LuaRuntime
addon = Path(__file__).resolve().parents[1]
mock = Path(__file__).with_name("mock_wow.lua").read_text(encoding="utf-8-sig")
passed = 0
def run(name, setup, body):
global passed
lua = LuaRuntime()
lua.execute(mock)
lua.execute(setup)
lua.execute((addon/"Settings.lua").read_text(encoding="utf-8-sig"))
lua.execute((addon/"TargetFrameBuff.lua").read_text(encoding="utf-8-sig"))
lua.execute("TargetFrameBuff_OnLoad(); LoadSettings()")
lua.execute(body)
passed += 1
print("PASS", name)
run("batched scans, reordered icons/timers and fresh tooltip indices",
'InstallAPI(true); auras.HELPFUL={Aura("A",1,30,130),Aura("B",1,40,140)}',
'''
Tick()
assert(calls.index==0)
assert(TargetFrameBuff1Icon.texture=="A" and TargetFrameBuff1.timer.text=="30")
auras.HELPFUL={Aura("B",1,40,150),Aura("A",1,30,125)}
Tick()
assert(TargetFrameBuff1Icon.texture=="B" and TargetFrameBuff1.timer.text=="50")
assert(TargetFrameBuff2Icon.texture=="A" and TargetFrameBuff2.timer.text=="25")
this=TargetFrameBuff2; this.scripts.OnEnter()
assert(GameTooltip.tooltip[2]==2 and GameTooltip.tooltip[3]=="HELPFUL")
auras.HELPFUL={Aura("C",1,50,160)}
Tick()
assert(TargetFrameBuff1Icon.texture=="C" and not TargetFrameBuff2:IsShown())
assert(not GameTooltip:IsShown())
''')
run("overflow debuff stacks, borders and cleanup on reuse", 'InstallAPI(true)', '''
auras.HELPFUL={Aura("Buff",3)}
for i=1,18 do auras.HARMFUL[i]=Aura("Debuff"..i,4,20,120,false,"Poison") end
Tick()
assert(TargetFrameBuff1.auraCount.text==3)
assert(TargetFrameBuff2Icon.texture=="Debuff17")
assert(TargetFrameBuff2.auraIndex==17 and TargetFrameBuff2.auraFilter=="HARMFUL")
assert(TargetFrameBuff2.auraCount.text==4 and TargetFrameBuff2.auraBorder.color[2]==1)
this=TargetFrameBuff2; this.scripts.OnEnter()
assert(GameTooltip.tooltip[2]==17 and GameTooltip.tooltip[3]=="HARMFUL")
auras.HARMFUL={}; auras.HELPFUL={Aura("Buff"),Aura("Plain")}
Tick()
assert(not TargetFrameBuff2.auraCount:IsShown() and not TargetFrameBuff2.auraBorder:IsShown())
assert(not TargetFrameDebuff1:IsShown())
''')
run("removable buff highlight toggle", 'InstallAPI(true); auras.HELPFUL={Aura("Purge",1,30,130,true)}', '''
Tick(); assert(TargetFrameBuff1.auraBorder:IsShown())
SlashCmdList.TARGETFRAMEBUFF("highlight off"); Tick()
assert(not TargetFrameBuff1.auraBorder:IsShown())
SlashCmdList.TARGETFRAMEBUFF("highlight on"); Tick()
assert(TargetFrameBuff1.auraBorder:IsShown())
''')
run("sweep start, refresh, unchanged timer, disable, expiration and missing duration",
'InstallAPI(true); auras.HELPFUL={Aura("A",1,30,130)}', '''
assert(not TargetFrameBuff1.cooldown)
SlashCmdList.TARGETFRAMEBUFF("sweeps on"); Tick()
local cd=TargetFrameBuff1.cooldown
assert(cd.start==100 and cd.duration==30 and cd.reverse==true and cd.edge==true)
local n=cd.calls; Tick(); assert(cd.calls==n)
auras.HELPFUL[1][6]=140; Tick(); assert(cd.start==110 and cd.calls==n+1)
SlashCmdList.TARGETFRAMEBUFF("sweeps off"); Tick(); assert(not cd:IsShown())
SlashCmdList.TARGETFRAMEBUFF("sweeps on"); Tick(); assert(cd:IsShown())
now=141; Tick(); assert(not cd:IsShown() and not TargetFrameBuff1.timer:IsShown())
auras.HELPFUL[1][5]=0; auras.HELPFUL[1][6]=0; Tick(); assert(not cd:IsShown())
''')
run("unknown timers, font size and warning settings", 'InstallAPI(true)', '''
auras.HELPFUL={Aura("A",1,0,0)}; Tick(); assert(not TargetFrameBuff1.timer:IsShown())
auras.HELPFUL={Aura("A",1,10,106)}; Tick()
assert(TargetFrameBuff1.timer.color[2]==1)
SlashCmdList.TARGETFRAMEBUFF("warning 10"); Tick()
assert(TargetFrameBuff1.timer.color[2]==.1)
SlashCmdList.TARGETFRAMEBUFF("size 14"); Tick()
assert(TargetFrameBuff1.timer.fontSize==14)
assert(TargetFrameBuff1.timer.font=="Fonts\\\\FRIZQT__.TTF")
SlashCmdList.TARGETFRAMEBUFF("timers off"); Tick(); assert(not TargetFrameBuff1.timer:IsShown())
SlashCmdList.TARGETFRAMEBUFF("timers on"); Tick(); assert(TargetFrameBuff1.timer:IsShown())
SlashCmdList.TARGETFRAMEBUFF("size 999"); assert(TargetFrameBuffDB.timerSize==14)
''')
run("older ClassicAPI and unsupported Cooldown fallback", '''
InstallAPI(false); noCooldown=true; auras.HELPFUL={Aura("Old",2,20,120)}
''', '''
SlashCmdList.TARGETFRAMEBUFF("sweeps on"); Tick()
assert(TargetFrameBuff1.noCooldown and TargetFrameBuff1.timer.text=="20")
assert(calls.index>0 and calls.slots==0)
auras.HELPFUL={Aura("Refreshed",1,30,140)}; Tick()
assert(TargetFrameBuff1Icon.texture=="Refreshed")
''')
run("native client fallback and settings persistence", '''
nativeBuffs={"Native"}; nativeDebuffs={{"Poison",3,"Poison"}}
TargetFrameBuffDB={timers=false,highlight=false,sweeps=false,timerSize=12,warning=7}
''', '''
Tick()
assert(TargetFrameBuff1Icon.texture=="Native")
assert(TargetFrameDebuff1Count.text==3)
assert(not TargetFrameBuff1.timer)
assert(TargetFrameBuffDB.timers==false and TargetFrameBuffDB.timerSize==12)
SlashCmdList.TARGETFRAMEBUFF("sweeps on"); Tick()
assert(not TargetFrameBuff1.cooldown)
''')
run("full 48-icon scan call budget and target clear", 'InstallAPI(true)', '''
for i=1,32 do auras.HELPFUL[i]=Aura("B"..i) end
for i=1,16 do auras.HARMFUL[i]=Aura("D"..i) end
calls={index=0,slots=0,bySlot=0}; Tick()
assert(calls.index==0 and calls.slots==2 and calls.bySlot==48)
assert(TargetFrameBuff32:IsShown() and TargetFrameDebuff16:IsShown())
auras={HELPFUL={},HARMFUL={}}; Tick()
assert(not TargetFrameBuff1:IsShown() and not TargetFrameDebuff16:IsShown())
''')
run("options panel controls, cancel and defaults", '''
InstallAPI(true)
InterfaceOptions_AddCategory=function(p) registered=p end
InterfaceOptionsFrame_OpenToCategory=function(p) p.refresh() end
''', '''
assert(registered.name=="TargetFrameBuff")
SlashCmdList.TARGETFRAMEBUFF("")
this=TargetFrameBuffOption3; this:SetChecked(true); this.scripts.OnClick()
assert(TargetFrameBuffDB.sweeps==true)
TargetFrameBuffSlider1:SetValue(13); assert(TargetFrameBuffDB.timerSize==13)
registered.cancel()
assert(TargetFrameBuffDB.sweeps==false and TargetFrameBuffDB.timerSize==9)
TargetFrameBuffDB.timerSize=15; registered.default(); assert(TargetFrameBuffDB.timerSize==9)
''')
run("corrupt saved settings recover", 'TargetFrameBuffDB={timerSize=999,warning=-1,timers="bad"}', '''
assert(TargetFrameBuffDB.timerSize==9 and TargetFrameBuffDB.warning==5 and TargetFrameBuffDB.timers==true)
''')
run("aura disappears just before hover and lower count overlay", 'InstallAPI(true); auras.HELPFUL={Aura("A")}; auras.HARMFUL={Aura("D",4)}', '''
Tick()
assert(TargetFrameDebuff1.auraCount.text==4)
assert(not TargetFrameDebuff1Count:IsShown())
auras.HELPFUL={}
this=TargetFrameBuff1; this.scripts.OnEnter()
assert(not GameTooltip:IsShown() and not TargetFrameBuff1.auraIndex)
''')
run("cached countdown avoids aura reads; silent recast fallback", 'InstallAPI(true); auras.HELPFUL={Aura("A",1,30,130)}', '''
calls={index=0,slots=0,bySlot=0}
now=101; TargetFrameBuff_OnUpdate(.2)
assert(calls.slots==0 and TargetFrameBuff1.timer.text=="29")
auras.HELPFUL[1][6]=150
TargetFrameBuff_OnUpdate(.2); assert(calls.slots==0)
TargetFrameBuff_OnUpdate(.1)
assert(calls.slots==2 and TargetFrameBuff1.timer.text=="49")
''')
run("unit event filtering and target change refresh", 'InstallAPI(true); auras.HELPFUL={Aura("A")}', '''
calls={index=0,slots=0,bySlot=0}
event="UNIT_AURA"; arg1="party1"; TargetFrameBuffFrame.scripts.OnEvent()
assert(calls.slots==0)
auras.HELPFUL={Aura("B")}; arg1="target"; TargetFrameBuffFrame.scripts.OnEvent()
assert(calls.slots==2 and TargetFrameBuff1Icon.texture=="B")
auras.HELPFUL={}; event="PLAYER_TARGET_CHANGED"; TargetFrameBuffFrame.scripts.OnEvent()
assert(not TargetFrameBuff1:IsShown())
''')
run("idle countdown stops but fallback discovers new timing", 'InstallAPI(true); auras.HELPFUL={Aura("A",1,0,0)}', '''
local writes=0
TargetFrameBuff1.timer.SetText=function() writes=writes+1 end
calls={index=0,slots=0,bySlot=0}
TargetFrameBuff_OnUpdate(.2); TargetFrameBuff_OnUpdate(.2)
assert(writes==0 and calls.slots==0)
auras.HELPFUL[1][5]=30; auras.HELPFUL[1][6]=130
TargetFrameBuff_OnUpdate(.1)
assert(writes==1 and TargetFrameBuff1.timer:IsShown())
SlashCmdList.TARGETFRAMEBUFF("timers off")
writes=0; TargetFrameBuff_OnUpdate(.2)
assert(writes==0 and not TargetFrameBuff1.timer:IsShown())
''')
run("delta mode removes polling and refreshes timing/reordering", 'InstallAPI(true); C_UnitAuras.GetAuraDataByAuraInstanceID=function() end; auras.HELPFUL={Aura("A")}', '''
assert(TargetFrameBuffFrame.events.UNIT_AURA_DELTA)
calls={index=0,slots=0,bySlot=0}
for i=1,20 do TargetFrameBuff_OnUpdate(.2) end
assert(calls.slots==0)
auras.HELPFUL={Aura("B",3,60,160)}
event="UNIT_AURA_DELTA"; arg1="party1"; arg2={updatedAuraInstanceIDs={1}}
TargetFrameBuffFrame.scripts.OnEvent(); assert(calls.slots==0)
arg1="target"; TargetFrameBuffFrame.scripts.OnEvent()
assert(calls.slots==2 and TargetFrameBuff1Icon.texture=="B" and TargetFrameBuff1.timer.text=="1m")
arg2.updatedAuraInstanceIDs[1]=999
now=101; TargetFrameBuff_OnUpdate(.2)
assert(TargetFrameBuff1.timer.text=="59" and calls.slots==2)
auras.HELPFUL={}; arg2={isFullUpdate=true}; TargetFrameBuffFrame.scripts.OnEvent()
assert(not TargetFrameBuff1:IsShown())
''')
run("delta mode refreshes target switches and spell/pet capability changes", 'InstallAPI(true); C_UnitAuras.GetAuraDataByAuraInstanceID=function() end', '''
auras.HELPFUL={Aura("A")}; event="PLAYER_TARGET_CHANGED"; TargetFrameBuffFrame.scripts.OnEvent()
assert(TargetFrameBuff1Icon.texture=="A")
calls={index=0,slots=0,bySlot=0}; event="UNIT_AURA"; arg1="target"; TargetFrameBuffFrame.scripts.OnEvent()
assert(calls.slots==0)
event="SPELLS_CHANGED"; TargetFrameBuffFrame.scripts.OnEvent(); assert(calls.slots==2)
event="UNIT_PET"; arg1="player"; TargetFrameBuffFrame.scripts.OnEvent(); assert(calls.slots==4)
''')
run("modern sweeps suppress native numbers and bling, clear on removal", '''
InstallAPI(true); auras.HELPFUL={Aura("A")}
local baseCreate=CreateFrame
CreateFrame=function(kind,name,parent,template)
local f=baseCreate(kind,name,parent,template)
if kind=="Cooldown" then
f.SetHideCountdownNumbers=function(self,v) self.hideNumbers=v end
f.SetDrawBling=function(self,v) self.bling=v end
f.Clear=function(self) self.cleared=true; self:Hide() end
end
return f
end
''', '''
SlashCmdList.TARGETFRAMEBUFF("sweeps on")
local cd=TargetFrameBuff1.cooldown
assert(cd.hideNumbers==true and cd.bling==false)
SlashCmdList.TARGETFRAMEBUFF("sweeps off"); assert(cd.cleared and not cd:IsShown())
SlashCmdList.TARGETFRAMEBUFF("sweeps on"); cd.cleared=false
auras.HELPFUL={}; Tick(); assert(cd.cleared and not cd:IsShown())
''')
ET.parse(addon/"TargetFrameBuff.xml")
print("PASS XML parsing")
print(f"{passed} Lua regression scenarios passed; XML parsed.")