Files
Guda-ClassicAPI/Core/ClassicAPISelfTest.lua
T

191 lines
7.6 KiB
Lua

-- Guda ClassicAPI runtime self-test
-- Read-only diagnostics for the test branch. Run /gudatest in game.
-- Lua 5.0 compatible.
local addon = Guda
local SelfTest = {}
addon.Modules.ClassicAPISelfTest = SelfTest
local function Bool(v)
return v and "yes" or "no"
end
local function ExtractItemID(link)
if not link then return nil end
local _, _, id = string.find(link, "item:(%d+)")
return id and tonumber(id) or nil
end
local function IsKnownQuality(value)
value = tonumber(value)
return value ~= nil and value >= 0
end
local function AddMismatch(state, text)
state.mismatches = state.mismatches + 1
if state.mismatches <= 12 then
addon:Print("|cffff6060Mismatch:|r %s", text)
end
end
local function CompareContainer(state, bagID, label)
local api = addon.Modules.ClassicAPI
local numSlots = GetContainerNumSlots(bagID) or 0
for slotID = 1, numSlots do
local texture, count, locked, quality, readable =
GetContainerItemInfo(bagID, slotID)
local link = GetContainerItemLink(bagID, slotID)
local vanillaOccupied = texture ~= nil or link ~= nil
local ok, info = pcall(api.GetContainerItemInfo, api, bagID, slotID)
if not ok then
AddMismatch(state, format("%s %d:%d ClassicAPI call errored", label, bagID, slotID))
else
local classicOccupied = info ~= nil
state.checked = state.checked + 1
if vanillaOccupied ~= classicOccupied then
AddMismatch(state, format("%s %d:%d occupancy Vanilla=%s ClassicAPI=%s",
label, bagID, slotID, Bool(vanillaOccupied), Bool(classicOccupied)))
elseif vanillaOccupied and info then
local vanillaID = ExtractItemID(link)
local classicID = info.itemID and tonumber(info.itemID) or nil
if vanillaID and classicID and vanillaID ~= classicID then
AddMismatch(state, format("%s %d:%d itemID %s ~= %s",
label, bagID, slotID, tostring(vanillaID), tostring(classicID)))
end
if (count or 1) ~= (info.stackCount or 1) then
AddMismatch(state, format("%s %d:%d count %s ~= %s",
label, bagID, slotID, tostring(count), tostring(info.stackCount)))
end
if (locked and true or false) ~= (info.isLocked and true or false) then
AddMismatch(state, format("%s %d:%d locked state differs",
label, bagID, slotID))
end
if link and info.hyperlink and link ~= info.hyperlink then
AddMismatch(state, format("%s %d:%d hyperlink differs",
label, bagID, slotID))
end
-- ClassicAPI deliberately leaves cache-dependent fields nil
-- when static item data is cold. Vanilla 1.12 can also return
-- quality=-1 for an occupied slot while the item cache is not
-- authoritative yet. Treat nil/negative quality as unknown,
-- but still fail on any disagreement between two known values.
if texture and info.iconFileID and texture ~= info.iconFileID then
AddMismatch(state, format("%s %d:%d texture differs",
label, bagID, slotID))
end
if IsKnownQuality(quality) and IsKnownQuality(info.quality) then
if tonumber(quality) ~= tonumber(info.quality) then
AddMismatch(state, format("%s %d:%d quality %s ~= %s",
label, bagID, slotID, tostring(quality), tostring(info.quality)))
end
elseif vanillaOccupied then
state.qualityUnknown = state.qualityUnknown + 1
end
if readable ~= nil and info.isReadable ~= nil
and (readable and true or false) ~= (info.isReadable and true or false) then
AddMismatch(state, format("%s %d:%d readable state differs",
label, bagID, slotID))
end
end
end
end
end
function SelfTest:Run()
local api = addon.Modules.ClassicAPI
addon:Print("|cffffd200=== Guda ClassicAPI self-test ===|r")
if not api then
addon:Print("|cffff6060FAIL: ClassicAPI integration module is missing.|r")
return false
end
local status = api:GetStatus()
addon:Print("ClassicAPI fast path: %s", status.available and "|cff60ff60ACTIVE|r" or "|cffff6060MISSING|r")
addon:Print("C_Container info=%s itemID=%s charges=%s",
Bool(status.containerInfo), Bool(status.containerItemID), Bool(status.containerCharges))
addon:Print("Frame helpers: EnumerateFrames=%s GetFramesRegisteredForEvent=%s",
Bool(type(EnumerateFrames) == "function"),
Bool(type(GetFramesRegisteredForEvent) == "function"))
if not status.available then
addon:Print("|cffff6060FAIL: required C_Container fast-path functions are unavailable.|r")
return false
end
local state = { checked = 0, mismatches = 0, qualityUnknown = 0 }
for bagID = 0, 4 do
CompareContainer(state, bagID, "bag")
end
-- Keyring exists on the target 1.12/Turtle client. pcall is inside the
-- comparator, so a ClassicAPI incompatibility is reported instead of
-- aborting the test.
if (GetContainerNumSlots(-2) or 0) > 0 then
CompareContainer(state, -2, "keyring")
end
if addon.Modules.BankScanner and addon.Modules.BankScanner.IsBankOpen
and addon.Modules.BankScanner:IsBankOpen() then
for _, bagID in ipairs(addon.Constants.BANK_BAGS or {}) do
CompareContainer(state, bagID, "bank")
end
else
addon:Print("Bank comparison skipped (open a bank and run /gudatest again).")
end
local budget = addon.Modules.Utils and addon.Modules.Utils.GetFrameBudget
and addon.Modules.Utils:GetFrameBudget() or nil
if budget then
addon:Print("Queue frame budget: %.1f ms", budget * 1000)
end
if addon.Modules.InventoryIndex and addon.Modules.InventoryIndex.GetStats then
local s = addon.Modules.InventoryIndex:GetStats()
addon:Print("Inventory index: current=%d static=%d dirty(current/static)=%s/%s",
s.currentItems or 0, s.staticItems or 0,
Bool(s.currentDirty), Bool(s.staticDirty))
end
if addon.Modules.ItemButtonPerformance and addon.Modules.ItemButtonPerformance.GetStats then
local s = addon.Modules.ItemButtonPerformance:GetStats()
addon:Print("ItemButton perf: watcher=%s polling=%s sharedGlows=%d active=%s",
Bool(s.cursorWatcherFound), Bool(s.cursorPollingEnabled),
s.sharedGlowDrivers or 0, Bool(s.sharedGlowActive))
end
if state.qualityUnknown > 0 then
addon:Print("Quality comparison skipped for %d slot(s) with uncached/unknown quality.",
state.qualityUnknown)
end
if state.mismatches == 0 then
addon:Print("|cff60ff60PASS: %d container slots checked, no API mismatches.|r", state.checked)
return true
end
if state.mismatches > 12 then
addon:Print("... %d additional mismatch(es) hidden.", state.mismatches - 12)
end
addon:Print("|cffff6060FAIL: %d mismatch(es) across %d checked slots.|r",
state.mismatches, state.checked)
return false
end
SLASH_GUDACLASSICAPITEST1 = "/gudatest"
SlashCmdList["GUDACLASSICAPITEST"] = function()
SelfTest:Run()
end
addon:Debug("ClassicAPI /gudatest runtime diagnostics loaded")