867 lines
32 KiB
Lua
867 lines
32 KiB
Lua
local function read(path)
|
|
local f = assert(io.open(path, "r"), "cannot open " .. path)
|
|
local c = f:read("*a")
|
|
f:close()
|
|
return c
|
|
end
|
|
|
|
local function has(content, needle)
|
|
return string.find(content, needle, 1, true) ~= nil
|
|
end
|
|
|
|
describe("QuestieLearner data source mode", function()
|
|
it("adds a mode selector and explicit fallback options in the database tab", function()
|
|
local dbOptions = read("Modules/Options/DatabaseTab/QuestieOptionsDatabase.lua")
|
|
local advanced = read("Modules/Options/AdvancedTab/QuestieOptionsAdvanced.lua")
|
|
assert.is_true(has(dbOptions, "Data Source Mode"))
|
|
assert.is_true(has(dbOptions, "auto = l10n(\"Auto (current behavior)\")"))
|
|
assert.is_true(has(dbOptions, "learner = l10n(\"Learner Only\")"))
|
|
assert.is_true(has(dbOptions, "static = l10n(\"Static Only\")"))
|
|
assert.is_true(has(dbOptions, "none = l10n(\"Neither (base DB only)\")"))
|
|
assert.is_true(has(dbOptions, "local function GetLearnerSelectedMode()"))
|
|
assert.is_true(has(dbOptions, "get = function() return GetLearnerSelectedMode() end"))
|
|
assert.is_true(has(dbOptions, "Runtime mode:"))
|
|
assert.is_true(has(advanced, "local function RefreshLearnerRuntime()"))
|
|
assert.is_true(has(advanced, "RefreshLearnerRuntime()"))
|
|
end)
|
|
|
|
it("defaults the learner mode to auto and exposes the live refresh hook", function()
|
|
local learner = read("Modules/QuestieLearner.lua")
|
|
local defaults = read("Modules/Options/QuestieOptionsDefaults.lua")
|
|
assert.is_true(has(defaults, "dataSourceMode = \"auto\""))
|
|
assert.is_true(has(learner, "function QuestieLearner:GetDataSourceMode()"))
|
|
assert.is_true(has(learner, "function QuestieLearner:IsLearnerLiveEnabled()"))
|
|
assert.is_true(has(learner, "function QuestieLearner:ApplyDataSourceMode()"))
|
|
assert.is_true(has(learner, "function QuestieLearner:RefreshLiveState()"))
|
|
end)
|
|
|
|
it("gates static suppression and tooltip fallback on the selected mode", function()
|
|
local quest = read("Modules/Quest/QuestieQuest.lua")
|
|
local priv = read("Modules/Quest/QuestieQuestPrivates.lua")
|
|
local tip = read("Modules/Tooltips/Tooltip.lua")
|
|
assert.is_true(has(quest, "dataSourceMode == \"auto\" or dataSourceMode == \"learner\""))
|
|
assert.is_true(has(priv, "dataSourceMode == \"none\""))
|
|
assert.is_true(has(tip, "mode ~= \"static\" and mode ~= \"none\""))
|
|
end)
|
|
|
|
it("exposes learner tooltip controls and tooltip resize support", function()
|
|
local general = read("Modules/Options/GeneralTab/QuestieOptionsGeneral.lua")
|
|
local defaults = read("Modules/Options/QuestieOptionsDefaults.lua")
|
|
local tip = read("Modules/Tooltips/Tooltip.lua")
|
|
local handler = read("Modules/Tooltips/TooltipHandler.lua")
|
|
local learner = read("Modules/QuestieLearner.lua")
|
|
assert.is_true(has(defaults, "learnerTooltips = true"))
|
|
assert.is_true(has(defaults, "learnerTooltipShowSpawn = true"))
|
|
assert.is_true(has(defaults, "learnerTooltipShowConfidence = true"))
|
|
assert.is_true(has(defaults, "learnerTooltipShowTotalSpawns = true"))
|
|
assert.is_true(has(defaults, "learnerTooltipAutoResize = true"))
|
|
assert.is_true(has(defaults, "learnerTooltipUseSecondary = false"))
|
|
assert.is_true(has(general, "Learner Tooltips"))
|
|
assert.is_true(has(general, "Enable learner tooltips"))
|
|
assert.is_true(has(general, "Show total spawns learned"))
|
|
assert.is_true(has(general, "Use secondary learner tooltip"))
|
|
assert.is_true(has(tip, "function QuestieTooltips:ResizeTooltip(tooltip)"))
|
|
assert.is_true(has(handler, "QuestieTooltips:ResizeTooltip(GameTooltip)"))
|
|
assert.is_true(has(handler, "QuestieTooltips:ResizeTooltip(self)"))
|
|
assert.is_true(has(learner, "learnerTooltipShowSpawn"))
|
|
assert.is_true(has(learner, "_CountLearnedNpcSpawns(entry)"))
|
|
assert.is_true(has(learner, "_ShowLearnerTooltipFrame(GameTooltip, rendered)"))
|
|
end)
|
|
|
|
it("allows learner mode to draw pins from a single learned spawn when needed", function()
|
|
local priv = read("Modules/Quest/QuestieQuestPrivates.lua")
|
|
assert.is_true(has(priv, "local staticHasSpawns = spawns and next(spawns) ~= nil"))
|
|
assert.is_true(has(priv, "local canUseLearnerSpawns = dataSourceMode == \"learner\""))
|
|
assert.is_true(has(priv, "or not staticHasSpawns"))
|
|
end)
|
|
|
|
it("keeps learner-only pin builders off the static DB lookup path", function()
|
|
local priv = read("Modules/Quest/QuestieQuestPrivates.lua")
|
|
assert.is_true(has(priv, "local npcData = QuestieDB:GetNPC(npcId)"))
|
|
assert.is_true(has(priv, "local name = npcData and npcData.name or nil"))
|
|
assert.is_true(has(priv, "local spawns = npcData and npcData.spawns or {}"))
|
|
assert.is_true(has(priv, "local rank = npcData and npcData.rank"))
|
|
assert.is_true(has(priv, "local objectData = QuestieDB:GetObject(objectId)"))
|
|
assert.is_true(has(priv, "local name = objectData and objectData.name or nil"))
|
|
assert.is_true(has(priv, "local spawns = objectData and objectData.spawns or {}"))
|
|
end)
|
|
|
|
it("maps object objectives from learner object captures before refresh", function()
|
|
local learner = read("Modules/QuestieLearner.lua")
|
|
assert.is_true(has(learner, "_Learner.recentObjects = _Learner.recentObjects or {}"))
|
|
assert.is_true(has(learner, "function QuestieLearner:LearnQuestObjectiveObject(questId, objectId, objText, objectiveIndex)"))
|
|
assert.is_true(has(learner, "objType == \"object\""))
|
|
assert.is_true(has(learner, "self:LearnQuestObjectiveObject(questId, objectId, objText, j)"))
|
|
assert.is_true(has(learner, "_Learner.recentObjects[objectId]"))
|
|
end)
|
|
end)
|
|
|
|
describe("QuestieLearner missing base DB fallback", function()
|
|
local QuestieLearner
|
|
|
|
before_each(function()
|
|
dofile("Tests/wow_api_mock.lua")
|
|
Questie.dbLearner.global.settings.enabled = false
|
|
Questie.dbLearner.global.settings.dataSourceMode = "static"
|
|
QuestieDB.baseDatabaseMissing = true
|
|
QuestieDB.IsBaseDatabaseMissing = function()
|
|
return true
|
|
end
|
|
QuestieLearner = dofile("Modules/QuestieLearner.lua")
|
|
end)
|
|
|
|
it("forces learner mode and live recording when the base DB is missing", function()
|
|
assert.equals("learner", QuestieLearner:GetDataSourceMode())
|
|
assert.is_true(QuestieLearner:IsEnabled())
|
|
end)
|
|
end)
|
|
|
|
describe("QuestieLearner learner mode activation", function()
|
|
local QuestieLearner
|
|
|
|
before_each(function()
|
|
dofile("Tests/wow_api_mock.lua")
|
|
Questie.dbLearner.global.settings.enabled = false
|
|
Questie.dbLearner.global.settings.dataSourceMode = "learner"
|
|
QuestieDB.baseDatabaseMissing = false
|
|
QuestieDB.IsBaseDatabaseMissing = function()
|
|
return false
|
|
end
|
|
QuestieLearner = dofile("Modules/QuestieLearner.lua")
|
|
end)
|
|
|
|
it("re-enables learner recording when learner mode is applied", function()
|
|
QuestieLearner:ApplyDataSourceMode()
|
|
assert.is_true(Questie.dbLearner.global.settings.enabled)
|
|
assert.is_true(QuestieLearner:IsEnabled())
|
|
end)
|
|
|
|
it("refreshes live learner caches and quest pins when runtime settings change", function()
|
|
local clearCount = 0
|
|
local resetCount = 0
|
|
|
|
QuestieDB.ClearModeCaches = function()
|
|
clearCount = clearCount + 1
|
|
end
|
|
QuestieQuest.SmoothReset = function()
|
|
resetCount = resetCount + 1
|
|
end
|
|
|
|
QuestieLearner:RefreshLiveState()
|
|
|
|
assert.is_true(clearCount >= 1)
|
|
assert.is_true(resetCount >= 1)
|
|
end)
|
|
end)
|
|
|
|
describe("QuestieDB learner mode merges learner overrides", function()
|
|
before_each(function()
|
|
dofile("Tests/wow_api_mock.lua")
|
|
dofile("Database/QuestieDB.lua")
|
|
dofile("Database/npcDB.lua")
|
|
Questie.dbLearner.global.settings.enabled = true
|
|
Questie.dbLearner.global.settings.dataSourceMode = "learner"
|
|
Questie.dbLearner.global.npcs = {
|
|
[7001] = {
|
|
[1] = "Learner NPC",
|
|
},
|
|
}
|
|
QuestieDB.npcDataOverrides = {
|
|
[7001] = {
|
|
[1] = "Learner NPC",
|
|
[7] = {
|
|
[44] = {
|
|
{ 12.5, 34.5 },
|
|
},
|
|
},
|
|
},
|
|
}
|
|
QuestieDB.private = QuestieDB.private or {}
|
|
QuestieDB.private.npcCache = {}
|
|
end)
|
|
|
|
it("prefers the learner override spawn table when raw learner data is incomplete", function()
|
|
local npc = QuestieDB:GetNPC(7001)
|
|
assert.is_table(npc)
|
|
assert.is_table(npc.spawns)
|
|
assert.is_table(npc.spawns[44])
|
|
assert.equals(1, table.getn(npc.spawns[44]))
|
|
assert.equals(12.5, npc.spawns[44][1][1])
|
|
assert.equals(34.5, npc.spawns[44][1][2])
|
|
end)
|
|
end)
|
|
|
|
describe("QuestieDB quest build guards missing objective tables", function()
|
|
local originalImport
|
|
local originalQueryItemSingle
|
|
|
|
before_each(function()
|
|
dofile("Tests/wow_api_mock.lua")
|
|
|
|
local questieLib = {
|
|
GetTbcLevel = function()
|
|
return 1, 1
|
|
end,
|
|
}
|
|
local questieCorrections = {
|
|
hiddenQuests = {},
|
|
killCreditObjectiveFirst = {},
|
|
}
|
|
|
|
originalImport = QuestieLoader.ImportModule
|
|
QuestieLoader.ImportModule = function(self, name)
|
|
if name == "QuestieLib" then
|
|
return questieLib
|
|
end
|
|
if name == "QuestieCorrections" then
|
|
return questieCorrections
|
|
end
|
|
return originalImport(self, name)
|
|
end
|
|
|
|
dofile("Database/QuestieDB.lua")
|
|
dofile("Database/questDB.lua")
|
|
|
|
Questie.dbLearner.global.settings.enabled = true
|
|
Questie.dbLearner.global.settings.dataSourceMode = "learner"
|
|
QuestieDB.private.questCache = {}
|
|
QuestieDB.questDataOverrides = {}
|
|
|
|
originalQueryItemSingle = QuestieDB.QueryItemSingle
|
|
QuestieDB.QueryItemSingle = function(itemId, field)
|
|
if field == "name" then
|
|
return "Test Item " .. tostring(itemId)
|
|
end
|
|
return originalQueryItemSingle(itemId, field)
|
|
end
|
|
end)
|
|
|
|
after_each(function()
|
|
if originalQueryItemSingle then
|
|
QuestieDB.QueryItemSingle = originalQueryItemSingle
|
|
end
|
|
if originalImport then
|
|
QuestieLoader.ImportModule = originalImport
|
|
end
|
|
end)
|
|
|
|
it("does not crash when required source items exist but objectives are missing", function()
|
|
local questId = 900001
|
|
QuestieDB.questDataOverrides[questId] = {
|
|
[1] = "Source Item Quest",
|
|
[21] = {
|
|
[1] = 20482,
|
|
},
|
|
}
|
|
|
|
local ok, quest = pcall(function()
|
|
return QuestieDB:GetQuest(questId)
|
|
end)
|
|
|
|
assert.is_true(ok)
|
|
assert.is_table(quest)
|
|
assert.is_table(quest.SpecialObjectives)
|
|
assert.is_table(quest.SpecialObjectives[20482])
|
|
assert.equals("Test Item 20482", quest.SpecialObjectives[20482].Description)
|
|
end)
|
|
end)
|
|
|
|
describe("QuestieDB missing quest logs are deduplicated", function()
|
|
local originalImport
|
|
local originalDebug
|
|
local originalQueryQuest
|
|
|
|
before_each(function()
|
|
dofile("Tests/wow_api_mock.lua")
|
|
|
|
local questieLib = {
|
|
GetTbcLevel = function()
|
|
return 1, 1
|
|
end,
|
|
}
|
|
local questieCorrections = {
|
|
hiddenQuests = {},
|
|
killCreditObjectiveFirst = {},
|
|
}
|
|
|
|
originalImport = QuestieLoader.ImportModule
|
|
QuestieLoader.ImportModule = function(self, name)
|
|
if name == "QuestieLib" then
|
|
return questieLib
|
|
end
|
|
if name == "QuestieCorrections" then
|
|
return questieCorrections
|
|
end
|
|
return originalImport(self, name)
|
|
end
|
|
|
|
dofile("Database/QuestieDB.lua")
|
|
dofile("Database/questDB.lua")
|
|
|
|
QuestieDB.private.questCache = {}
|
|
QuestieDB.private.missingQuestLog = {}
|
|
|
|
originalDebug = Questie.Debug
|
|
Questie.Debug = function(self, level, ...)
|
|
_G._questie_debug_calls = (_G._questie_debug_calls or 0) + 1
|
|
end
|
|
|
|
originalQueryQuest = QuestieDB.QueryQuest
|
|
QuestieDB.QueryQuest = function()
|
|
return nil
|
|
end
|
|
end)
|
|
|
|
after_each(function()
|
|
if originalQueryQuest then
|
|
QuestieDB.QueryQuest = originalQueryQuest
|
|
end
|
|
if originalDebug then
|
|
Questie.Debug = originalDebug
|
|
end
|
|
if originalImport then
|
|
QuestieLoader.ImportModule = originalImport
|
|
end
|
|
_G._questie_debug_calls = nil
|
|
end)
|
|
|
|
it("logs a missing quest only once per quest id", function()
|
|
local questId = 900002
|
|
|
|
assert.is_nil(QuestieDB:GetQuest(questId))
|
|
assert.is_nil(QuestieDB:GetQuest(questId))
|
|
assert.equals(1, _G._questie_debug_calls)
|
|
end)
|
|
end)
|
|
|
|
describe("QuestieLearner quest accept resolution", function()
|
|
local QuestieLearner
|
|
local originalGetNumQuestLogEntries
|
|
local originalGetQuestLogSelection
|
|
local originalGetQuestLogTitle
|
|
local originalGetQuestIDFromLogIndex
|
|
local originalGetQuestLogIndexByID
|
|
local originalLearnQuest
|
|
local originalUnitGUID
|
|
|
|
before_each(function()
|
|
dofile("Tests/wow_api_mock.lua")
|
|
Questie.dbLearner.global.settings.enabled = true
|
|
Questie.dbLearner.global.settings.dataSourceMode = "learner"
|
|
|
|
originalGetNumQuestLogEntries = _G.GetNumQuestLogEntries
|
|
originalGetQuestLogSelection = QuestieCompat.GetQuestLogSelection
|
|
originalGetQuestLogTitle = QuestieCompat.GetQuestLogTitle
|
|
originalGetQuestIDFromLogIndex = QuestieCompat.GetQuestIDFromLogIndex
|
|
originalGetQuestLogIndexByID = QuestieCompat.GetQuestLogIndexByID
|
|
originalUnitGUID = _G.UnitGUID
|
|
|
|
_G.GetNumQuestLogEntries = function()
|
|
return 1
|
|
end
|
|
_G.UnitGUID = function()
|
|
return nil
|
|
end
|
|
|
|
QuestieCompat.GetQuestLogSelection = function()
|
|
return 1
|
|
end
|
|
|
|
QuestieCompat.GetQuestLogTitle = function(index)
|
|
if index == 1 then
|
|
return "Real Quest", 10, nil, false, nil, nil, nil, 4321
|
|
end
|
|
return nil
|
|
end
|
|
|
|
QuestieCompat.GetQuestIDFromLogIndex = function(index)
|
|
if index == 1 then
|
|
return 4321
|
|
end
|
|
return nil
|
|
end
|
|
|
|
QuestieCompat.GetQuestLogIndexByID = function(questId)
|
|
if questId == 4321 then
|
|
return 1
|
|
end
|
|
return nil
|
|
end
|
|
|
|
QuestieLearner = dofile("Modules/QuestieLearner.lua")
|
|
originalLearnQuest = QuestieLearner.LearnQuest
|
|
end)
|
|
|
|
after_each(function()
|
|
QuestieLearner.LearnQuest = originalLearnQuest
|
|
_G.GetNumQuestLogEntries = originalGetNumQuestLogEntries
|
|
_G.UnitGUID = originalUnitGUID
|
|
QuestieCompat.GetQuestLogSelection = originalGetQuestLogSelection
|
|
QuestieCompat.GetQuestLogTitle = originalGetQuestLogTitle
|
|
QuestieCompat.GetQuestIDFromLogIndex = originalGetQuestIDFromLogIndex
|
|
QuestieCompat.GetQuestLogIndexByID = originalGetQuestLogIndexByID
|
|
end)
|
|
|
|
it("uses a real quest log entry instead of raw accepted event args", function()
|
|
local capturedQuestId = nil
|
|
QuestieLearner.LearnQuest = function(self, questId, data)
|
|
capturedQuestId = questId
|
|
end
|
|
|
|
QuestieLearner:OnQuestAccepted(615514513, nil)
|
|
|
|
assert.equals(4321, capturedQuestId)
|
|
end)
|
|
|
|
it("refuses impossible quest ids when they do not resolve to the quest log", function()
|
|
local capturedQuestId = nil
|
|
QuestieCompat.GetQuestLogSelection = function()
|
|
return nil
|
|
end
|
|
QuestieCompat.GetQuestLogTitle = function()
|
|
return nil
|
|
end
|
|
QuestieCompat.GetQuestIDFromLogIndex = function()
|
|
return nil
|
|
end
|
|
QuestieCompat.GetQuestLogIndexByID = function()
|
|
return nil
|
|
end
|
|
QuestieLearner.LearnQuest = function(self, questId, data)
|
|
capturedQuestId = questId
|
|
end
|
|
|
|
QuestieLearner:OnQuestAccepted(615514513, nil)
|
|
|
|
assert.is_nil(capturedQuestId)
|
|
end)
|
|
end)
|
|
|
|
describe("QuestieLearner quest turn-in resolution", function()
|
|
local QuestieLearner
|
|
local originalLearnQuest
|
|
local originalGetQuestID
|
|
local originalGetRewardText
|
|
local originalUnitGUID
|
|
|
|
before_each(function()
|
|
dofile("Tests/wow_api_mock.lua")
|
|
|
|
originalGetQuestID = _G.GetQuestID
|
|
originalGetRewardText = _G.GetRewardText
|
|
originalUnitGUID = _G.UnitGUID
|
|
|
|
Questie.dbLearner.global.settings.enabled = true
|
|
Questie.dbLearner.global.settings.dataSourceMode = "learner"
|
|
|
|
_G.GetQuestID = function()
|
|
return 4321
|
|
end
|
|
_G.GetRewardText = function()
|
|
return "Reward text"
|
|
end
|
|
_G.UnitGUID = function()
|
|
return nil
|
|
end
|
|
|
|
QuestieLearner = dofile("Modules/QuestieLearner.lua")
|
|
originalLearnQuest = QuestieLearner.LearnQuest
|
|
end)
|
|
|
|
after_each(function()
|
|
QuestieLearner.LearnQuest = originalLearnQuest
|
|
_G.GetQuestID = originalGetQuestID
|
|
_G.GetRewardText = originalGetRewardText
|
|
_G.UnitGUID = originalUnitGUID
|
|
end)
|
|
|
|
it("rejects malformed turn-in quest ids unless they resolve to a recent completion", function()
|
|
local capturedQuestId = nil
|
|
QuestieLearner.LearnQuest = function(self, questId, data)
|
|
capturedQuestId = questId
|
|
end
|
|
|
|
QuestieLearner:OnQuestTurnedIn(545915281, nil, nil)
|
|
|
|
assert.is_nil(capturedQuestId)
|
|
end)
|
|
|
|
it("uses the recent quest-complete cache when the raw turn-in quest id is malformed", function()
|
|
local capturedQuestId = nil
|
|
QuestieLearner.LearnQuest = function(self, questId, data)
|
|
capturedQuestId = questId
|
|
end
|
|
|
|
QuestieLearner:OnQuestComplete()
|
|
QuestieLearner:OnQuestTurnedIn(545915281, nil, nil)
|
|
|
|
assert.equals(4321, capturedQuestId)
|
|
end)
|
|
end)
|
|
|
|
describe("QuestieLearner GUID and loot learning", function()
|
|
local QuestieLearner
|
|
local originalGetNPC
|
|
local originalGetItemInfo
|
|
local originalLearnItem
|
|
local originalLearnItemDrop
|
|
local originalGetLootSourceInfo
|
|
local originalGetNumLootItems
|
|
local originalGetLootSlotInfo
|
|
local originalGetLootSlotLink
|
|
|
|
before_each(function()
|
|
dofile("Tests/wow_api_mock.lua")
|
|
Questie.dbLearner.global.settings.enabled = true
|
|
Questie.dbLearner.global.settings.dataSourceMode = "learner"
|
|
Questie.dbLearner.global.settings.learnItems = true
|
|
Questie.dbLearner.global.settings.learnNpcs = true
|
|
|
|
QuestieDB.npcData = {
|
|
[15297] = { [1] = "Arcanist Helion" },
|
|
}
|
|
originalGetNPC = QuestieDB.GetNPC
|
|
QuestieDB.GetNPC = function(self, id)
|
|
if id == 168 then
|
|
return { name = "Something Else" }
|
|
end
|
|
return originalGetNPC and originalGetNPC(self, id) or nil
|
|
end
|
|
|
|
originalGetItemInfo = _G.GetItemInfo
|
|
_G.GetItemInfo = function(link)
|
|
if link == "item:20470" then
|
|
return "Quest Token", nil, nil, 1, 1, 3, 1, nil, nil, nil, nil, 1, 0
|
|
end
|
|
return nil
|
|
end
|
|
originalGetLootSourceInfo = _G.GetLootSourceInfo
|
|
_G.GetLootSourceInfo = function()
|
|
return "Creature-0-0-0-0-15297-0000000000", 1
|
|
end
|
|
originalGetNumLootItems = _G.GetNumLootItems
|
|
_G.GetNumLootItems = function()
|
|
return 1
|
|
end
|
|
originalGetLootSlotInfo = _G.GetLootSlotInfo
|
|
_G.GetLootSlotInfo = function()
|
|
return nil, "Quest Token", nil, nil, 1
|
|
end
|
|
originalGetLootSlotLink = _G.GetLootSlotLink
|
|
_G.GetLootSlotLink = function()
|
|
return "item:20470"
|
|
end
|
|
dofile("Modules/QuestieLearner.lua")
|
|
QuestieLearner = _G.QuestieLearner
|
|
originalLearnItem = QuestieLearner.LearnItem
|
|
originalLearnItemDrop = QuestieLearner.LearnItemDrop
|
|
end)
|
|
|
|
after_each(function()
|
|
QuestieDB.GetNPC = originalGetNPC
|
|
_G.GetItemInfo = originalGetItemInfo
|
|
_G.GetLootSourceInfo = originalGetLootSourceInfo
|
|
_G.GetNumLootItems = originalGetNumLootItems
|
|
_G.GetLootSlotInfo = originalGetLootSlotInfo
|
|
_G.GetLootSlotLink = originalGetLootSlotLink
|
|
if QuestieLearner then
|
|
QuestieLearner.LearnItem = originalLearnItem
|
|
QuestieLearner.LearnItemDrop = originalLearnItemDrop
|
|
end
|
|
end)
|
|
|
|
it("prefers the exact NPC name over a mismatched GUID entry id", function()
|
|
local resolvedId, unitType = QuestieLearner:ResolveNpcIdFromGuidAndName("Creature-0-0-0-0-168-0000000000", "Arcanist Helion")
|
|
assert.equals(15297, resolvedId)
|
|
assert.equals("Creature", unitType)
|
|
end)
|
|
|
|
it("ignores non-quest loot items and only learns quest-item drops", function()
|
|
local learnedItemId = nil
|
|
local dropItemId = nil
|
|
local dropNpcId = nil
|
|
|
|
QuestieLearner.LearnItem = function(self, itemId, name, itemLevel, requiredLevel, itemClassId, itemSubClassId)
|
|
if itemClassId == 12 then
|
|
learnedItemId = itemId
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
QuestieLearner.LearnItemDrop = function(self, itemId, npcId)
|
|
dropItemId = itemId
|
|
dropNpcId = npcId
|
|
end
|
|
|
|
local originalGetItemInfo = _G.GetItemInfo
|
|
_G.GetItemInfo = function(link)
|
|
if link == "item:20470" then
|
|
return "Quest Token", nil, nil, 1, 1, nil, nil, nil, nil, nil, nil, 1, 0
|
|
end
|
|
return originalGetItemInfo(link)
|
|
end
|
|
|
|
QuestieLearner:OnLootOpened()
|
|
|
|
assert.is_nil(learnedItemId)
|
|
assert.is_nil(dropItemId)
|
|
assert.is_nil(dropNpcId)
|
|
|
|
_G.GetItemInfo = originalGetItemInfo
|
|
end)
|
|
end)
|
|
|
|
describe("QuestieDB learner source fallback", function()
|
|
before_each(function()
|
|
dofile("Tests/wow_api_mock.lua")
|
|
dofile("Database/QuestieDB.lua")
|
|
dofile("Database/npcDB.lua")
|
|
dofile("Database/objectDB.lua")
|
|
dofile("Database/questDB.lua")
|
|
dofile("Database/itemDB.lua")
|
|
|
|
Questie.dbLearner.global.settings.enabled = true
|
|
Questie.dbLearner.global.settings.dataSourceMode = "learner"
|
|
Questie.dbLearner.global.npcs = {
|
|
[9001] = {
|
|
[1] = "Learner Whelp",
|
|
[7] = {
|
|
[44] = {
|
|
{ 12.3, 45.6 },
|
|
},
|
|
},
|
|
[8] = {
|
|
[44] = {
|
|
{ 13.3, 46.6 },
|
|
},
|
|
},
|
|
[9] = 44,
|
|
},
|
|
}
|
|
Questie.dbLearner.global.objects = {
|
|
[9002] = {
|
|
[1] = "Learner Cache",
|
|
[4] = {
|
|
[44] = {
|
|
{ 11.1, 22.2 },
|
|
},
|
|
},
|
|
[5] = 44,
|
|
},
|
|
}
|
|
|
|
QuestieDB.QueryNPC = function() return nil end
|
|
QuestieDB.QueryObject = function() return nil end
|
|
QuestieDB.QueryQuest = function() return nil end
|
|
QuestieDB.QueryItem = function() return nil end
|
|
QuestieDB.private.npcCache = {}
|
|
QuestieDB.private.objectCache = {}
|
|
QuestieDB.private.questCache = {}
|
|
QuestieDB.private.itemCache = {}
|
|
end)
|
|
|
|
it("returns learner NPC data when static queries are unavailable", function()
|
|
local npc = QuestieDB:GetNPC(9001)
|
|
assert.is_table(npc)
|
|
assert.equals("Learner Whelp", npc.name)
|
|
assert.is_table(npc.spawns)
|
|
assert.is_table(npc.waypoints)
|
|
assert.equals(44, npc.zoneID)
|
|
end)
|
|
|
|
it("turns learner kill evidence into NPC spawn coordinates immediately in learner mode", function()
|
|
Questie.dbLearner.global.npcs[9003] = {
|
|
[1] = "Learner Kill",
|
|
[8] = {
|
|
[101] = {
|
|
zoneId = 44,
|
|
x = 18.5,
|
|
y = 27.25,
|
|
},
|
|
},
|
|
}
|
|
|
|
local npc = QuestieDB:GetNPC(9003)
|
|
assert.is_table(npc)
|
|
assert.is_table(npc.spawns)
|
|
assert.is_table(npc.spawns[44])
|
|
assert.equals(1, #npc.spawns[44])
|
|
assert.equals(18.5, npc.spawns[44][1][1])
|
|
assert.equals(27.25, npc.spawns[44][1][2])
|
|
end)
|
|
|
|
it("collapses many nearby kills (distinct GUIDs) into one spawn pin", function()
|
|
-- Five kills of respawns at the same spot: distinct GUID keys, slightly
|
|
-- drifting player coords. This must render as ONE pin, not five.
|
|
Questie.dbLearner.global.npcs[9005] = {
|
|
[1] = "Respawning Boar",
|
|
[8] = {
|
|
[201] = { zoneId = 44, x = 50.0, y = 50.0 },
|
|
[202] = { zoneId = 44, x = 50.4, y = 50.3 },
|
|
[203] = { zoneId = 44, x = 49.7, y = 50.6 },
|
|
[204] = { zoneId = 44, x = 50.9, y = 49.8 },
|
|
[205] = { zoneId = 44, x = 50.2, y = 50.1 },
|
|
},
|
|
}
|
|
|
|
local npc = QuestieDB:GetNPC(9005)
|
|
assert.is_table(npc)
|
|
assert.is_table(npc.spawns[44])
|
|
assert.equals(1, #npc.spawns[44])
|
|
end)
|
|
|
|
it("keeps genuinely separate spawn locations as distinct pins", function()
|
|
Questie.dbLearner.global.npcs[9006] = {
|
|
[1] = "Field Boars",
|
|
[8] = {
|
|
[301] = { zoneId = 44, x = 20.0, y = 20.0 },
|
|
[302] = { zoneId = 44, x = 20.3, y = 20.2 }, -- same spot as 301
|
|
[303] = { zoneId = 44, x = 70.0, y = 65.0 }, -- far corner
|
|
},
|
|
}
|
|
|
|
local npc = QuestieDB:GetNPC(9006)
|
|
assert.is_table(npc)
|
|
assert.is_table(npc.spawns[44])
|
|
assert.equals(2, #npc.spawns[44])
|
|
end)
|
|
|
|
it("honors the spawn dedup radius knob (0 disables proximity merge)", function()
|
|
Questie.dbLearner.global.settings.spawnDedupRadius = 0
|
|
Questie.dbLearner.global.npcs[9007] = {
|
|
[1] = "Drifting Kills",
|
|
[8] = {
|
|
[401] = { zoneId = 44, x = 50.0, y = 50.0 },
|
|
[402] = { zoneId = 44, x = 50.4, y = 50.3 },
|
|
[403] = { zoneId = 44, x = 49.7, y = 50.6 },
|
|
[404] = { zoneId = 44, x = 50.9, y = 49.8 },
|
|
[405] = { zoneId = 44, x = 50.2, y = 50.1 },
|
|
},
|
|
}
|
|
|
|
local npc = QuestieDB:GetNPC(9007)
|
|
assert.is_table(npc)
|
|
assert.is_table(npc.spawns[44])
|
|
-- With merging off, each distinct kill coordinate stays its own pin.
|
|
assert.equals(5, #npc.spawns[44])
|
|
end)
|
|
|
|
it("widens merging when the dedup radius is increased", function()
|
|
Questie.dbLearner.global.settings.spawnDedupRadius = 12
|
|
Questie.dbLearner.global.npcs[9008] = {
|
|
[1] = "Loose Cluster",
|
|
[8] = {
|
|
[501] = { zoneId = 44, x = 40.0, y = 40.0 },
|
|
[502] = { zoneId = 44, x = 48.0, y = 46.0 }, -- ~10 away: merges at radius 12
|
|
},
|
|
}
|
|
|
|
local npc = QuestieDB:GetNPC(9008)
|
|
assert.is_table(npc)
|
|
assert.is_table(npc.spawns[44])
|
|
assert.equals(1, #npc.spawns[44])
|
|
end)
|
|
|
|
it("returns learner object data when static queries are unavailable", function()
|
|
local obj = QuestieDB:GetObject(9002)
|
|
assert.is_table(obj)
|
|
assert.equals("Learner Cache", obj.name)
|
|
assert.is_table(obj.spawns)
|
|
assert.equals(44, obj.zoneID)
|
|
end)
|
|
end)
|
|
|
|
describe("QuestieDB partial base DB missing", function()
|
|
before_each(function()
|
|
dofile("Tests/wow_api_mock.lua")
|
|
dofile("Database/QuestieDB.lua")
|
|
end)
|
|
|
|
it("does not report the base DB missing when only one store failed", function()
|
|
QuestieDB.baseDatabaseMissing = true
|
|
QuestieDB.baseDatabaseMissingKeys = { itemData = true }
|
|
assert.is_false(QuestieDB:IsBaseDatabaseMissing())
|
|
assert.is_true(QuestieDB:IsStoreMissing("itemData"))
|
|
assert.is_false(QuestieDB:IsStoreMissing("npcData"))
|
|
end)
|
|
|
|
it("reports the base DB missing only when every core store failed", function()
|
|
QuestieDB.baseDatabaseMissing = true
|
|
QuestieDB.baseDatabaseMissingKeys = {
|
|
npcData = true, objectData = true, questData = true, itemData = true,
|
|
}
|
|
assert.is_true(QuestieDB:IsBaseDatabaseMissing())
|
|
end)
|
|
|
|
it("honors the static selection for a present store even when another is missing", function()
|
|
QuestieDB.baseDatabaseMissing = true
|
|
QuestieDB.baseDatabaseMissingKeys = { itemData = true }
|
|
Questie.dbLearner.global.settings.dataSourceMode = "static"
|
|
Questie.dbLearner.global.npcs = {
|
|
[9100] = { [1] = "Should Not Win", [7] = { [44] = { { 1, 2 } } }, [9] = 44 },
|
|
}
|
|
QuestieDB.private.npcCache = {}
|
|
local queried = false
|
|
QuestieDB.QueryNPC = function() queried = true; return nil end
|
|
|
|
pcall(function() QuestieDB:GetNPC(9100) end)
|
|
assert.is_true(queried)
|
|
end)
|
|
end)
|
|
|
|
describe("QuestieDB mode cohesion", function()
|
|
before_each(function()
|
|
dofile("Tests/wow_api_mock.lua")
|
|
dofile("Database/QuestieDB.lua")
|
|
dofile("Database/npcDB.lua")
|
|
Questie.dbLearner.global.settings.enabled = true
|
|
Questie.dbLearner.global.npcs = {
|
|
[9200] = { [1] = "Learner Only NPC", [7] = { [44] = { { 5, 6 } } }, [9] = 44 },
|
|
}
|
|
QuestieDB.QueryNPC = function() return nil end
|
|
QuestieDB.baseDatabaseMissing = false
|
|
QuestieDB.baseDatabaseMissingKeys = {}
|
|
QuestieDB.private.npcCache = {}
|
|
end)
|
|
|
|
it("does NOT leak learner data into static mode when the store is present", function()
|
|
Questie.dbLearner.global.settings.dataSourceMode = "static"
|
|
QuestieDB.private.npcCache = {}
|
|
assert.is_nil(QuestieDB:GetNPC(9200))
|
|
end)
|
|
|
|
it("does NOT leak learner data into none mode when the store is present", function()
|
|
Questie.dbLearner.global.settings.dataSourceMode = "none"
|
|
QuestieDB.private.npcCache = {}
|
|
assert.is_nil(QuestieDB:GetNPC(9200))
|
|
end)
|
|
|
|
it("DOES overlay learner data in auto mode when the static DB lacks it", function()
|
|
Questie.dbLearner.global.settings.dataSourceMode = "auto"
|
|
QuestieDB.private.npcCache = {}
|
|
local npc = QuestieDB:GetNPC(9200)
|
|
assert.is_table(npc)
|
|
assert.equals("Learner Only NPC", npc.name)
|
|
end)
|
|
|
|
it("clears every cache including the zone cache on mode switch", function()
|
|
QuestieDB.private.questCache[1] = {}
|
|
QuestieDB.private.zoneCache[1] = {}
|
|
QuestieDB:ClearModeCaches()
|
|
assert.is_nil(QuestieDB.private.questCache[1])
|
|
assert.is_nil(QuestieDB.private.zoneCache[1])
|
|
end)
|
|
end)
|
|
|
|
describe("QuestieLearner mode switch redraw wiring", function()
|
|
it("drives a full real-time refresh via SmoothReset, not the mis-named event handler", function()
|
|
local function read(path)
|
|
local f = assert(io.open(path, "r")); local c = f:read("*a"); f:close(); return c
|
|
end
|
|
local dbOptions = read("Modules/Options/DatabaseTab/QuestieOptionsDatabase.lua")
|
|
assert.is_true(string.find(dbOptions, "QuestieQuest:SmoothReset()", 1, true) ~= nil)
|
|
-- The old import name resolved to nil and silently skipped the redraw.
|
|
assert.is_nil(string.find(dbOptions, "ImportModule(\"QuestieEventHandler\")", 1, true))
|
|
end)
|
|
end)
|