Merge branch 'tooltip-ascensiondb-precedence' into questie-learner-comms-improvements

This commit is contained in:
Xurkon
2026-06-05 18:22:12 -05:00
8 changed files with 754 additions and 11 deletions
+2 -1
View File
@@ -237,7 +237,8 @@ end
---@param questLogIndex number
---@param questId number
function _QuestEventHandler:QuestAccepted(questLogIndex, questId)
questId = questId or select(8, GetQuestLogTitle(questLogIndex))
local _, _, _, _, _, _, _, questLogQuestId = GetQuestLogTitle(questLogIndex)
questId = questId or questLogQuestId
Questie:Debug(Questie.DEBUG_DEVELOP, "[Quest Event] QUEST_ACCEPTED", questLogIndex, questId)
if questLog[questId] and questLog[questId].timer then
+5 -1
View File
@@ -40,6 +40,10 @@ local function IsAscensionProtected(dbType, id, key)
return protected and protected[key] == true
end
local function HasAscensionQuestObjectiveData(questId)
return IsAscensionProtected("QUEST", questId, 10)
end
local function NormalizeSpawnZoneKey(zoneKey)
-- Convert raw area IDs (e.g. 3431 from GetAreaID()) to the canonical map IDs
-- used by AscensionDB and the rendering system (e.g. 1241 for Sunstrider Isle).
@@ -1721,7 +1725,7 @@ function QuestieLearner:LearnQuestObjectiveNPC(questId, npcId, objText, objectiv
-- 3. Register with tooltip system immediately. Preserve the objective icon so
-- nameplates can render the correct learned slay/loot/talk marker.
local QuestieTooltips = QuestieLoader:ImportModule("QuestieTooltips")
if QuestieTooltips and QuestieTooltips.RegisterObjectiveTooltip then
if QuestieTooltips and QuestieTooltips.RegisterObjectiveTooltip and not HasAscensionQuestObjectiveData(questId) then
local objectiveIcon
local QuestLogCache = QuestieLoader:ImportModule("QuestLogCache")
local objectives = QuestLogCache and QuestLogCache.GetQuestObjectives and QuestLogCache.GetQuestObjectives(questId)
+4 -2
View File
@@ -120,7 +120,8 @@ function QuestiePlayer:GetCurrentZoneId()
return uiMapId
end
return ZoneDB.instanceIdToUiMapId[select(8, GetInstanceInfo())]
local _, _, _, _, _, _, _, instanceMapID = GetInstanceInfo()
return ZoneDB.instanceIdToUiMapId[instanceMapID]
end
function QuestiePlayer:GetCurrentUiMapId()
@@ -129,7 +130,8 @@ function QuestiePlayer:GetCurrentUiMapId()
if uiMapId then
return uiMapId
end
return ZoneDB.instanceIdToUiMapId[select(8, GetInstanceInfo())]
local _, _, _, _, _, _, _, instanceMapID = GetInstanceInfo()
return ZoneDB.instanceIdToUiMapId[instanceMapID]
end
---@return number
+42 -1
View File
@@ -43,6 +43,31 @@ local _tooltipLastText = ""
local _InitObjectiveTexts
local function _GetQuestObjectiveSummary(questId)
if not QuestieDB or not QuestieDB.GetQuest then
return nil
end
local quest = QuestieDB:GetQuest(questId)
if not quest or not quest.ObjectiveData then
return nil
end
local summary = {}
for _, objective in ipairs(quest.ObjectiveData) do
local text = objective and (objective.Text or objective.Description)
if type(text) == "string" and text ~= "" then
tinsert(summary, text)
end
end
if table.getn(summary) == 0 then
return nil
end
return summary
end
---@param questId number
---@param key string monster: m_, items: i_, objects: o_ + string name of the objective
---@param objective table
@@ -205,7 +230,7 @@ function QuestieTooltips:GetTooltip(key)
return nil
end
if QuestiePlayer.numberOfGroupMembers > MAX_GROUP_MEMBER_COUNT then
if (QuestiePlayer.numberOfGroupMembers or 0) > MAX_GROUP_MEMBER_COUNT then
return nil -- temporary disable tooltips in raids, we should make a proper fix
end
@@ -345,11 +370,27 @@ elseif key:sub(1,2) == "o_" then
if QuestieTooltips.lookupByKey[key] then
local playerName = UnitName("player")
local hasObjectiveEntries = false
for _, tooltip in next, QuestieTooltips.lookupByKey[key] do
if not tooltip.name then
hasObjectiveEntries = true
break
end
end
for k, tooltip in next, QuestieTooltips.lookupByKey[key] do
if tooltip.name then
if Questie.db.profile.showQuestsInNpcTooltip then
local questString = QuestieLib:GetColoredQuestName(tooltip.questId, Questie.db.profile.enableTooltipsQuestLevel, true, true)
tinsert(tooltipLines, questString)
if not hasObjectiveEntries then
local objectiveSummary = _GetQuestObjectiveSummary(tooltip.questId)
if objectiveSummary then
for _, objectiveText in ipairs(objectiveSummary) do
tinsert(tooltipLines, " |cFFcbcbcb" .. objectiveText .. "|r")
end
end
end
end
else
local objective = tooltip.objective
+2 -2
View File
@@ -413,7 +413,7 @@ function QuestieTracker.Initialize()
for i = 1, questsWatched do
local questIndex = GetQuestIndexForWatch(i)
if questIndex then
local questId = select(8, GetQuestLogTitle(questIndex))
local _, _, _, _, _, _, _, questId = GetQuestLogTitle(questIndex)
if questId then
tempQuestIDs[i] = questId
end
@@ -2277,7 +2277,7 @@ function QuestieTracker:HookBaseTracker()
-- Intercept and return a Questie boolean value
IsQuestWatched = function(index)
local questId = select(8, GetQuestLogTitle(index))
local _, _, _, _, _, _, _, questId = GetQuestLogTitle(index)
if questId == 0 then
-- When an objective progresses in TBC "index" is the questId, but when a quest is manually added to the quest watch
-- (e.g. shift clicking it in the quest log) "index" is the questLogIndex.
+15 -4
View File
@@ -197,10 +197,21 @@ describe("Audit Pass 9 - file-by-file findings (snapshot at HEAD)", function()
assert.is_true(has(d, "if(dbItem and dbItem.name and (not dbItem.Hidden)) then"))
end)
it("[N5] select(8, GetInstanceInfo()) left in QuestiePlayer (5.0 rewrite unfinished)", function()
assert.is_true(has(read("Modules/QuestiePlayer.lua"), "select(8, GetInstanceInfo())"))
-- QuestieLearner was rewritten away from it:
assert.is_true(has(read("Modules/QuestieLearner.lua"), "Lua 5.0 compat"))
it("[N5] explicit unpack replaced select(8, ...) in live quest/instance lookups", function()
local player = read("Modules/QuestiePlayer.lua")
local handler = read("Modules/Quest/QuestEventHandler.lua")
local tracker = read("Modules/Tracker/QuestieTracker.lua")
assert.is_true(has(player, "local _, _, _, _, _, _, _, instanceMapID = GetInstanceInfo()"))
assert.is_false(has(player, "select(8, GetInstanceInfo())"))
assert.is_true(has(handler, "local _, _, _, _, _, _, _, questLogQuestId = GetQuestLogTitle(questLogIndex)"))
assert.is_false(has(handler, "select(8, GetQuestLogTitle(questLogIndex))"))
assert.is_true(has(tracker, "local _, _, _, _, _, _, _, questId = GetQuestLogTitle(questIndex)"))
assert.is_true(has(tracker, "local _, _, _, _, _, _, _, questId = GetQuestLogTitle(index)"))
assert.is_false(has(tracker, "select(8, GetQuestLogTitle(questIndex))"))
assert.is_false(has(tracker, "select(8, GetQuestLogTitle(index))"))
end)
it("[9.1->11.1] CORRECTED: % modulo IS used (the 'avoided' claim was wrong)", function()
+618
View File
@@ -0,0 +1,618 @@
describe("QuestieLearner kill-path batching", function()
local queuedTimers
local broadcasts
local QuestieLearner
before_each(function()
dofile("Tests/wow_api_mock.lua")
queuedTimers = {}
broadcasts = {}
QuestieCompat.C_Timer.After = function(_, fn)
queuedTimers[table.getn(queuedTimers) + 1] = fn
end
local originalImportModule = QuestieLoader.ImportModule
QuestieLoader.ImportModule = function(self, name)
if name == "QuestieLearnerComms" then
return {
BroadcastLearnedData = function(_, op, typ, id, data)
broadcasts[table.getn(broadcasts) + 1] = {
op = op,
typ = typ,
id = id,
data = data,
}
end,
}
end
return originalImportModule(self, name)
end
Questie.dbLearner.global.settings.enabled = true
Questie.dbLearner.global.settings.learnNpcs = true
Questie.dbLearner.global.settings.learnQuests = true
Questie.dbLearner.global.settings.learnItems = true
Questie.dbLearner.global.settings.learnObjects = true
Questie.dbLearner.global.settings.minConfidencePins = 1
Questie.dbLearner.global.npcs = {}
Questie.dbLearner.global.quests = {}
Questie.dbLearner.global.items = {}
Questie.dbLearner.global.objects = {}
QuestieDB.npcDataOverrides = {}
QuestieDB.questDataOverrides = {}
QuestieDB.itemDataOverrides = {}
QuestieDB.objectDataOverrides = {}
QuestieDB.private = {
npcCache = {
[1001] = { name = "Cached Boar" },
},
}
QuestiePlayer.currentQuestlog = {}
QuestieLearner = dofile("Modules/QuestieLearner.lua")
end)
it("coalesces repeated NPC live updates instead of invalidating DB cache per kill", function()
QuestieLearner:LearnNPC(1001, "Laggy Boar", nil, nil, nil, nil, 41.25, 52.5, 44)
QuestieLearner:LearnNPC(1001, "Laggy Boar", nil, nil, nil, nil, 41.35, 52.6, 44)
assert.is_nil(QuestieDB.npcDataOverrides[1001])
assert.is_table(QuestieDB.private.npcCache[1001])
assert.equals(2, table.getn(queuedTimers))
queuedTimers[1]()
assert.is_table(QuestieDB.npcDataOverrides[1001])
assert.is_nil(QuestieDB.private.npcCache[1001])
assert.is_table(QuestieDB.npcDataOverrides[1001][7])
local flushedSpawnCount = table.getn(QuestieDB.npcDataOverrides[1001][7][44])
QuestieLearner:LearnNPC(1001, "Laggy Boar", nil, nil, nil, nil, 80.0, 80.0, 44)
assert.equals(flushedSpawnCount, table.getn(QuestieDB.npcDataOverrides[1001][7][44]))
assert.equals(3, table.getn(queuedTimers))
end)
it("coalesces repeated quest-pin refreshes into one flush", function()
local updateCount = 0
local originalUpdateQuest = QuestieQuest.UpdateQuest
QuestieQuest.UpdateQuest = function(_, questId)
updateCount = updateCount + 1
end
QuestiePlayer.currentQuestlog = { [5001] = true }
Questie.dbLearner.global.quests = {}
QuestieDB.questDataOverrides = {}
QuestieLearner:LearnQuestObjectiveNPC(5001, 7001, "Pin Boar slain", 1)
QuestieLearner:LearnQuestObjectiveNPC(5001, 7001, "Pin Boar slain", 1)
assert.is_true(table.getn(queuedTimers) >= 1)
for i = 1, table.getn(queuedTimers) do
queuedTimers[i]()
end
assert.equals(1, updateCount)
QuestieQuest.UpdateQuest = originalUpdateQuest
end)
it("suppresses an already queued pin refresh after switching to manual mode", function()
local updateCount = 0
local originalUpdateQuest = QuestieQuest.UpdateQuest
QuestieQuest.UpdateQuest = function(_, questId)
updateCount = updateCount + 1
end
QuestiePlayer.currentQuestlog = { [5003] = true }
Questie.dbLearner.global.quests = {}
QuestieDB.questDataOverrides = {}
QuestieLearner:LearnQuestObjectiveNPC(5003, 7003, "Manual Boar slain", 1)
assert.is_true(table.getn(queuedTimers) >= 1)
Questie.dbLearner.global.settings.pinRefreshMode = "manual"
queuedTimers[1]()
assert.equals(0, updateCount)
QuestieQuest.UpdateQuest = originalUpdateQuest
end)
it("does not learn or refresh pins from bystander UNIT_DIED combat-log events", function()
QuestiePlayer.currentQuestlog = { [5002] = true }
QuestieDB.GetQuest = function()
return {
Objectives = {
{
Id = 7002,
Index = 1,
spawnList = { [7002] = true },
AlreadySpawned = {},
},
},
}
end
QuestieLearner:OnCombatLogEvent(
1234,
"UNIT_DIED",
nil,
nil,
nil,
"Creature-0-0-0-0-7002-0000000001",
"Bystander Boar",
nil
)
assert.is_nil(Questie.dbLearner.global.npcs[7002])
assert.is_nil(QuestieDB.npcDataOverrides[7002])
assert.equals(0, table.getn(queuedTimers))
end)
it("still learns and batches local PARTY_KILL combat-log events", function()
QuestieLearner:OnCombatLogEvent(
1234,
"PARTY_KILL",
UnitGUID("player"),
UnitName("player"),
nil,
"Creature-0-0-0-0-7003-0000000001",
"Tagged Boar",
nil
)
assert.is_table(Questie.dbLearner.global.npcs[7003])
assert.equals("Tagged Boar", Questie.dbLearner.global.npcs[7003][1])
assert.equals(2, table.getn(queuedTimers))
end)
it("cross-links quest giver NPCs and objects learned after the quest without duplicate pin flushes", function()
local updateCount = 0
local originalUpdateQuest = QuestieQuest.UpdateQuest
QuestieQuest.UpdateQuest = function(_, questId)
updateCount = updateCount + 1
end
Questie.db.profile.learnerBroadcast = false
QuestiePlayer.currentQuestlog = { [6001] = true }
QuestieLearner:LearnQuest(6001, {
[1] = "Cross Link Givers",
[2] = { [1] = { 7101 }, [2] = { 8101 } },
[3] = { [1] = { 7102 }, [2] = { 8102 } },
})
queuedTimers = {}
QuestieLearner:LearnNPC(7101, "Starter Guard", nil, nil, nil, nil, 10, 20, 44)
QuestieLearner:LearnNPC(7102, "Finisher Guard", nil, nil, nil, nil, 30, 40, 44)
QuestieLearner:LearnObject(8101, "Starter Chest")
QuestieLearner:LearnObject(8102, "Finisher Chest")
assert.same({ 6001 }, Questie.dbLearner.global.npcs[7101][10])
assert.same({ 6001 }, Questie.dbLearner.global.npcs[7102][11])
assert.same({ 6001 }, Questie.dbLearner.global.objects[8101][2])
assert.same({ 6001 }, Questie.dbLearner.global.objects[8102][3])
assert.same({ 6001 }, QuestieDB.npcDataOverrides[7101][10])
assert.same({ 6001 }, QuestieDB.npcDataOverrides[7102][11])
assert.same({ 6001 }, QuestieDB.objectDataOverrides[8101][2])
assert.same({ 6001 }, QuestieDB.objectDataOverrides[8102][3])
for i = 1, table.getn(queuedTimers) do
queuedTimers[i]()
end
assert.equals(1, updateCount)
QuestieQuest.UpdateQuest = originalUpdateQuest
end)
it("cross-links item objective drop NPCs into quest creature objectives", function()
Questie.db.profile.learnerBroadcast = false
QuestiePlayer.currentQuestlog = { [6002] = true }
QuestieLearner:LearnQuest(6002, {
[1] = "Cross Link Drops",
[10] = {
[3] = {
{ 2201, 0, 1, "Collect one tusk" },
},
},
})
QuestieLearner:LearnItem(2201, "Quest Tusk", 1, 1, 12, 0)
QuestieLearner:LearnItemDrop(2201, 7201)
assert.equals(7201, Questie.dbLearner.global.quests[6002][10][1][1][1])
assert.equals(7201, QuestieDB.questDataOverrides[6002][10][1][1][1])
QuestieLearner:LearnItemDrop(2201, 7201)
assert.equals(1, table.getn(Questie.dbLearner.global.quests[6002][10][1]))
assert.equals(1, table.getn(QuestieDB.questDataOverrides[6002][10][1]))
end)
it("defers learner objective tooltip registration to protected AscensionDB quest data", function()
Questie.db.profile.learnerBroadcast = false
QuestiePlayer.currentQuestlog = {}
QuestieDB.ascensionOverrideKeys = {
QUEST = {
[8334] = {
[10] = true,
},
},
}
_G._lastRegisteredTooltip = nil
QuestieLearner:LearnQuestObjectiveNPC(8334, 15271, "Tender slain", 1)
assert.is_table(Questie.dbLearner.global.quests[8334])
assert.is_nil(_G._lastRegisteredTooltip)
end)
it("coalesces repeated learner broadcasts into one latest update", function()
QuestieLearner:LearnItem(2001, "Quest Tusk", 1, 1, 12, 0)
QuestieLearner:LearnItem(2001, "Quest Tusk", 1, 1, 12, 0)
assert.equals(0, table.getn(broadcasts))
assert.equals(1, table.getn(queuedTimers))
queuedTimers[1]()
assert.equals(1, table.getn(broadcasts))
assert.equals("NEW", broadcasts[1].op)
assert.equals("ITEM", broadcasts[1].typ)
assert.equals(2001, broadcasts[1].id)
end)
it("coalesces repeated inbound network merges into one inject pass", function()
local injectCount = 0
local originalInject = QuestieLearner.InjectLearnedData
QuestieLearner.InjectLearnedData = function(self)
injectCount = injectCount + 1
QuestieLearner.data = Questie.dbLearner.global
end
QuestieLearner:HandleNetworkData("NPC", 3001, { [1] = "Net Boar", [7] = { [44] = { { 11, 22 } } } }, "NEW")
QuestieLearner:HandleNetworkData("NPC", 3001, { [1] = "Net Boar", [7] = { [44] = { { 11, 22 }, { 33, 44 } } } }, "UPDATE")
assert.equals(0, injectCount)
assert.equals(1, table.getn(queuedTimers))
queuedTimers[1]()
assert.equals(1, injectCount)
assert.equals("Net Boar", Questie.dbLearner.global.npcs[3001][1])
assert.equals(2, table.getn(Questie.dbLearner.global.npcs[3001][7][44]))
QuestieLearner.InjectLearnedData = originalInject
end)
it("forwards OnEvent payload arguments to learner handlers", function()
local originalCreateFrame = _G.CreateFrame
local originalStrsplit = _G.strsplit
local createdFrame = nil
local captured = {
questTurnedIn = nil,
questAccepted = nil,
combatLog = nil,
itemInfoReceived = nil,
questTrackingCleared = nil,
}
_G.CreateFrame = function()
createdFrame = {
RegisterEvent = function() end,
SetScript = function(self, scriptName, fn)
if scriptName == "OnEvent" then
self._onEvent = fn
end
end,
}
return createdFrame
end
_G.strsplit = function(sep, str)
local parts = {}
local pattern = string.format("([^%s]+)", sep)
for part in string.gmatch(str, pattern) do
parts[#parts + 1] = part
end
return unpack(parts)
end
QuestieLearner = dofile("Modules/QuestieLearner.lua")
local originalOnQuestTurnedIn = QuestieLearner.OnQuestTurnedIn
local originalOnQuestAccepted = QuestieLearner.OnQuestAccepted
local originalOnCombatLogEvent = QuestieLearner.OnCombatLogEvent
local originalOnGetItemInfoReceived = QuestieLearner.OnGetItemInfoReceived
local originalClearQuestObjectiveTracking = QuestieLearner.ClearQuestObjectiveTracking
QuestieLearner.OnQuestTurnedIn = function(self, questId, npcId, questFlags)
captured.questTurnedIn = { questId, npcId, questFlags }
end
QuestieLearner.OnQuestAccepted = function(self, questId, questGiver)
captured.questAccepted = { questId, questGiver }
end
QuestieLearner.OnCombatLogEvent = function(self, timestamp, eventType, srcGUID, srcName, srcFlags, dstGUID, dstName, dstFlags, spellId, spellName)
captured.combatLog = { timestamp, eventType, srcGUID, srcName, srcFlags, dstGUID, dstName, dstFlags, spellId, spellName }
end
QuestieLearner.OnGetItemInfoReceived = function(self, itemId)
captured.itemInfoReceived = { itemId }
end
QuestieLearner.ClearQuestObjectiveTracking = function(self, questId)
captured.questTrackingCleared = { questId }
end
QuestieLearner:RegisterEvents()
local frame = createdFrame
frame._onEvent(frame, "QUEST_TURNED_IN", 101, 202, 303)
frame._onEvent(frame, "QUEST_ACCEPTED", 404, 505)
frame._onEvent(frame, "COMBAT_LOG_EVENT_UNFILTERED", 1, "SPELL_DAMAGE", "src-guid", "Src", 2, "dst-guid", "Dst", 4, 777, "Fireball")
frame._onEvent(frame, "GET_ITEM_INFO_RECEIVED", 888)
frame._onEvent(frame, "QUEST_REMOVED", 999)
assert.same({ 101, 202, 303 }, captured.questTurnedIn)
assert.same({ 404, 505 }, captured.questAccepted)
assert.same({ 1, "SPELL_DAMAGE", "src-guid", "Src", 2, "dst-guid", "Dst", 4, 777, "Fireball" }, captured.combatLog)
assert.same({ 888 }, captured.itemInfoReceived)
assert.same({ 999 }, captured.questTrackingCleared)
QuestieLearner.OnQuestTurnedIn = originalOnQuestTurnedIn
QuestieLearner.OnQuestAccepted = originalOnQuestAccepted
QuestieLearner.OnCombatLogEvent = originalOnCombatLogEvent
QuestieLearner.OnGetItemInfoReceived = originalOnGetItemInfoReceived
QuestieLearner.ClearQuestObjectiveTracking = originalClearQuestObjectiveTracking
_G.CreateFrame = originalCreateFrame
_G.strsplit = originalStrsplit
end)
end)
describe("QuestieLearnerComms queue draining", function()
local sentMessages
local processedMessages
local QuestieLearnerComms
local currentTime
before_each(function()
dofile("Tests/wow_api_mock.lua")
sentMessages = {}
processedMessages = {}
currentTime = 1000
local originalImportModule = QuestieLoader.ImportModule
QuestieLoader.ImportModule = function(self, name)
if name == "QuestieLearner" then
return _G.QuestieLearner
end
return originalImportModule(self, name)
end
QuestieLoader.CreateModule = function(self, name)
_G[name] = { private = {} }
return _G[name]
end
_G.LibStub = function(name, silent)
if name == "AceComm-3.0" then
return { RegisterComm = function() end }
elseif name == "LibDeflate" then
return {
CompressDeflate = function(_, s) return s end,
EncodeForPrint = function(_, s) return s end,
DecodeForPrint = function(_, s) return s end,
DecompressDeflate = function(_, s) return s end,
}
elseif name == "AceSerializer-3.0" then
return {
Serialize = function(_, payload)
return payload.op .. ":" .. tostring(payload.id)
end,
Deserialize = function(_, serialized)
local op, id = string.match(serialized, "([^:]+):(.+)")
return true, {
_ver = 2,
op = op,
typ = "NPC",
id = tonumber(id) or id,
d = { [1] = "net" },
}
end,
}
elseif name == "XXH_Lua_Lib" then
return nil
elseif name == "HereBeDragonsQuestie-2.0" then
return {}
end
return {}
end
_G.QuestieLearner = {
HandleNetworkData = function(_, typ, id, d, op)
processedMessages[table.getn(processedMessages) + 1] = {
typ = typ,
id = id,
op = op,
}
end,
}
_G.GetChannelName = function() return 1 end
_G.JoinPermanentChannel = function() end
_G.ChatFrame_RemoveChannel = function() end
_G.DEFAULT_CHAT_FRAME = { GetID = function() return 1 end }
_G.SendChatMessage = function(msg, mode, nilarg, channel)
sentMessages[table.getn(sentMessages) + 1] = msg
end
_G.InCombatLockdown = function() return false end
_G.random = function() return 0 end
_G.GetTime = function()
return currentTime
end
QuestieCompat.C_Timer.NewTicker = function(delay, fn)
return { Cancel = function() end }
end
dofile("Modules/Network/QuestieLearnerComms.lua")
QuestieLearnerComms = _G.QuestieLearnerComms
QuestieLearnerComms:Initialize()
end)
it("drains outgoing and incoming queues in FIFO order without front-removal", function()
QuestieLearnerComms:BroadcastLearnedData("NEW", "NPC", 101, { foo = "a" })
QuestieLearnerComms:BroadcastLearnedData("UPDATE", "NPC", 102, { foo = "b" })
QuestieLearnerComms:OnCommReceived("QuestieLearner", "NEW:201", "CHANNEL", "Alice")
QuestieLearnerComms:OnCommReceived("QuestieLearner", "UPDATE:202", "CHANNEL", "Bob")
QuestieLearnerComms.private:ProcessQueues()
currentTime = currentTime + 4
QuestieLearnerComms.private:ProcessQueues()
currentTime = currentTime + 4
QuestieLearnerComms.private:ProcessQueues()
assert.equals(2, table.getn(sentMessages))
assert.equals("NEW:101", sentMessages[1])
assert.equals("UPDATE:102", sentMessages[2])
assert.equals(2, table.getn(processedMessages))
assert.equals(201, processedMessages[1].id)
assert.equals(202, processedMessages[2].id)
end)
end)
describe("QuestieComms packet sizing", function()
local serializeCount
local sendCount
local QuestieComms
before_each(function()
dofile("Tests/wow_api_mock.lua")
serializeCount = 0
sendCount = 0
local originalCreateModule = QuestieLoader.CreateModule
local originalImportModule = QuestieLoader.ImportModule
QuestieLoader.CreateModule = function(self, name)
_G[name] = { private = {} }
return _G[name]
end
QuestieLoader.ImportModule = function(self, name)
if name == "QuestieSerializer" then
return {
Serialize = function(_, payload)
serializeCount = serializeCount + 1
return "packet:" .. tostring(payload.id or payload[1] or "x")
end,
Deserialize = function() return true, {} end,
}
end
return originalImportModule(self, name)
end
_G.LibStub = function(name, silent)
if name == "AceComm-3.0" then
return { RegisterComm = function() end }
elseif name == "LibDeflate" then
return {
CompressDeflate = function(_, s) return s end,
EncodeForPrint = function(_, s) return s end,
DecodeForPrint = function(_, s) return s end,
DecompressDeflate = function(_, s) return s end,
}
elseif name == "AceSerializer-3.0" then
return {
Serialize = function(_, payload) return "packet:" .. tostring(payload.id or payload[1] or "x") end,
Deserialize = function() return true, {} end,
}
elseif name == "XXH_Lua_Lib" then
return nil
elseif name == "HereBeDragonsQuestie-2.0" then
return {}
end
return {}
end
_G.QuestiePlayer.GetGroupType = function() return "party" end
_G.QuestiePlayer.numberOfGroupMembers = 5
_G.QuestieDB.QuestPointers = {
[101] = true,
[102] = true,
[103] = true,
}
_G.QuestieDB.QueryQuestSingle = function()
return 0
end
_G.QuestieDB.GetQuest = function(questId)
return {
Objectives = {
[1] = { Id = questId * 10 },
},
}
end
_G.QuestLogCache.questLog_DO_NOT_MODIFY = {
[101] = { questTag = "Normal" },
[102] = { questTag = "Normal" },
[103] = { questTag = "Normal" },
}
_G.QuestLogCache.GetQuestObjectives = function()
return {
{ type = "monster", numFulfilled = 0, numRequired = 1 },
}
end
_G.ZoneDB.GetUiMapIdByAreaId = function()
return 1
end
_G.HBD = {
GetZoneDistance = function() return 1 end,
GetPlayerZone = function() return 1 end,
}
_G.GetChannelName = function() return 1 end
_G.SendChatMessage = function() end
_G.Questie.SendCommMessage = function()
sendCount = sendCount + 1
end
_G.UnitInBattleground = function() return false end
_G.random = function() return 0 end
_G.GetTime = function() return 0 end
_G.tinsert = table.insert
QuestieCompat.C_Timer.After = function(_, fn) end
QuestieCompat.C_Timer.NewTicker = function(_, fn)
return { Cancel = function() end }
end
QuestieComms = dofile("Modules/Network/QuestieComms.lua")
QuestieComms.private.CreatePacket = function()
return {
data = {},
write = function() end,
}
end
serializeCount = 0
end)
it("serializes each quest once while packing broadcast blocks", function()
QuestieComms.private:BroadcastQuestLog("QC_ID_BROADCAST_FULL_QUESTLIST", "WHISPER", "Tester")
assert.equals(3, serializeCount)
serializeCount = 0
QuestieComms.private:BroadcastQuestLogV2("QC_ID_BROADCAST_FULL_QUESTLIST", "WHISPER", "Tester")
assert.equals(3, serializeCount)
end)
it("suppresses outgoing QuestieComms immediately when disabled", function()
Questie.db.profile.questieCommsEnabled = false
local packet = QuestieComms.private:CreatePacket(QuestieComms.private.QC_ID_BROADCAST_QUEST_REMOVE)
packet.data.writeMode = QuestieComms.private.QC_WRITE_ALLGROUP
packet.data.priority = "NORMAL"
packet.data.id = 101
packet:write()
assert.equals(0, sendCount)
end)
end)
+66
View File
@@ -0,0 +1,66 @@
describe("Questie tooltip precedence", function()
local function contains(lines, needle)
for _, line in ipairs(lines or {}) do
if string.find(line, needle, 1, true) then
return true
end
end
return false
end
before_each(function()
dofile("Tests/wow_api_mock.lua")
local originalImportModule = QuestieLoader.ImportModule
QuestieLoader.ImportModule = function(self, name)
if name == "QuestieLib" then
return {
GetColoredQuestName = function(_, questId)
return "Quest " .. tostring(questId)
end,
Colorize = function(_, text)
return text
end,
}
end
return originalImportModule(self, name)
end
Questie.db.profile.showQuestsInNpcTooltip = true
Questie.db.profile.enableTooltipsQuestLevel = false
Questie.db.profile.enableTooltipsNPCID = false
QuestiePlayer.numberOfGroupMembers = 0
QuestieCompat.IsInGroup = function() return false end
QuestieCompat.UnitInParty = function() return false end
QuestieDB.GetQuest = function(_, questId)
if questId ~= 8334 then
return nil
end
return {
ObjectiveData = {
[1] = { Type = "monster", Id = 15271, Text = "Tender slain" },
[2] = { Type = "monster", Id = 15294, Text = "Feral Tender slain" },
},
}
end
dofile("Modules/Tooltips/Tooltip.lua")
QuestieTooltips.lookupByKey["m_15271"] = {
["8334 Tender 15271"] = {
questId = 8334,
name = "Tender",
starterId = 15271,
},
}
end)
it("adds AscensionDB objective text under quest titles when no objective tooltip is registered", function()
local lines = QuestieTooltips:GetTooltip("m_15271")
assert.is_true(contains(lines, "Quest 8334"))
assert.is_true(contains(lines, "Tender slain"))
assert.is_true(contains(lines, "Feral Tender slain"))
end)
end)