From 6793805ebef1a1e749a52170d8cf48b5b8e5ed8d Mon Sep 17 00:00:00 2001 From: Xurkon <36556990+Xurkon@users.noreply.github.com> Date: Mon, 1 Jun 2026 18:00:06 -0500 Subject: [PATCH] remove staged bloat --- Tests/QuestieLearner_spec.lua | 822 ---------------------------------- 1 file changed, 822 deletions(-) delete mode 100644 Tests/QuestieLearner_spec.lua diff --git a/Tests/QuestieLearner_spec.lua b/Tests/QuestieLearner_spec.lua deleted file mode 100644 index b6f3522..0000000 --- a/Tests/QuestieLearner_spec.lua +++ /dev/null @@ -1,822 +0,0 @@ --- Tests/QuestieLearner_spec.lua -require("Tests/wow_api_mock") - -describe("QuestieLearner", function() - local QuestieLearner - - setup(function() - -- Mocking QuestieLoader module resolution for tests - _G.QuestieLoader.ImportModule = function(_, name) - if name == "QuestieDB" then return _G.QuestieDB end - if name == "QuestieQuest" then return _G.QuestieQuest end - if name == "QuestiePlayer" then return _G.QuestiePlayer end - if name == "QuestLogCache" then return _G.QuestLogCache end - if name == "QuestieCompat" then return _G.QuestieCompat end - if name == "ZoneDB" then return _G.ZoneDB end - if name == "l10n" then return _G.l10n end - if name == "QuestieTooltips" then return _G.QuestieTooltips end - if name == "QuestieLib" then return {} end - return {} - end - - _G.QuestieLoader.CreateModule = function(_, name) - _G[name] = {} - return _G[name] - end - - -- Reset mock state - _G._lastRegisteredTooltip = nil - _G._mock_uiMapId = nil - _G._mock_questObjectives = nil - _G._mock_npcFlags = 2 - - -- Reset QuestLogCache.GetQuest to default - _G.QuestLogCache.GetQuest = function(_, id) return nil end - - -- Load the module - package.loaded["Modules/QuestieLearner"] = nil - QuestieLearner = require("Modules/QuestieLearner") - - -- Initialize sets up dbLearner.global.settings, InjectsLearnedData, etc. - QuestieLearner:Initialize() - end) - - --========================================================================== - -- Existing test: coordinate scaling in OnCombatLogEvent - --========================================================================== - it("should scale coordinates by 100 in OnCombatLogEvent", function() - local unitGUID = "Creature-0-1234-567-89-21878-0000000000" - local unitName = "Felboar" - - _G.QuestieCompat.GetCurrentPlayerPosition = function() - return 946, 0.35, 0.45 - end - - QuestieLearner:OnCombatLogEvent(GetTime(), "UNIT_DIED", nil, nil, nil, unitGUID, unitName, nil, nil, nil) - - local cached = QuestieLearner.private.recentKills[unitGUID] - assert.is_not_nil(cached) - assert.are.equal(35.0, cached.x) - assert.are.equal(45.0, cached.y) - end) - - --========================================================================== - -- Phase 2: GUID-based spawn evidence - --========================================================================== - it("should store GUID spawn evidence in entry[8] after a kill", function() - local npcId = 21878 - local unitGUID = "Creature-0-1234-567-89-21878-000000ABCD" - local unitName = "Felboar" - - -- Clear prior data - Questie.dbLearner.global.npcs = {} - Questie.dbLearner.global.settings.learnNpcs = true - - _G.QuestieCompat.GetCurrentPlayerPosition = function() - return 1241, 0.5234, 0.6789 - end - - QuestieLearner:OnCombatLogEvent(GetTime(), "UNIT_DIED", nil, nil, nil, unitGUID, unitName, nil, nil, nil) - - -- Verify recentKills unchanged - local cached = QuestieLearner.private.recentKills[unitGUID] - assert.is_not_nil(cached) - assert.are.equal(npcId, cached.npcId) - assert.are.equal("Felboar", cached.name) - assert.are.equal(5234, cached.x) - assert.are.equal(6789, cached.y) - - -- Verify entry[8] was created on the learned NPC - local learnedNpc = Questie.dbLearner.global.npcs[npcId] - assert.is_not_nil(learnedNpc) - assert.is_not_nil(learnedNpc[8]) - - -- Spawn UID from last numeric segment of GUID: 000000ABCD → 43981 - local spawnUID = 43981 - assert.is_not_nil(learnedNpc[8][spawnUID], "GUID spawn entry should exist for spawnUID " .. tostring(spawnUID)) - local entry = learnedNpc[8][spawnUID] - assert.are.equal(1241, entry.zoneId) - assert.are.equal(52.34, entry.x) -- same scaled format as recentKills - assert.are.equal(67.89, entry.y) -- same scaled format as recentKills - assert.are.equal("local", entry.source) - assert.are.equal(1, entry.confidence) - end) - - it("should update existing GUID spawn evidence on repeated kill at same UID", function() - local npcId = 21878 - local unitGUID = "Creature-0-1234-567-89-21878-0000005555" - local unitName = "Felboar" - - Questie.dbLearner.global.npcs = {} - Questie.dbLearner.global.settings.learnNpcs = true - - _G.QuestieCompat.GetCurrentPlayerPosition = function() - return 1241, 0.1111, 0.2222 - end - - -- First kill - QuestieLearner:OnCombatLogEvent(GetTime(), "UNIT_DIED", nil, nil, nil, unitGUID, unitName, nil, nil, nil) - local spawnUID = 21845 - local learnedNpc = Questie.dbLearner.global.npcs[npcId] - local entry1 = learnedNpc[8][spawnUID] - assert.is_not_nil(entry1) - local ts1 = entry1.ts - - -- Second kill at same UID — position changes slightly - _G.QuestieCompat.GetCurrentPlayerPosition = function() - return 1241, 0.3333, 0.4444 - end - QuestieLearner:OnCombatLogEvent(GetTime(), "UNIT_DIED", nil, nil, nil, unitGUID, unitName, nil, nil, nil) - local entry2 = learnedNpc[8][spawnUID] - assert.is_not_nil(entry2) - assert.are.equal(33.33, entry2.x) -- same scaled format as recentKills - assert.are.equal(44.44, entry2.y) -- same scaled format as recentKills - assert.is_true(entry2.ts >= ts1) -- timestamp refreshed - end) - - it("should not double-scale already normalized GUID spawn coordinates", function() - local npcId = 15274 - local unitGUID = "Creature-0-1234-567-89-15274-41298" - - Questie.dbLearner.global.npcs = { - [npcId] = { - [1] = "Mana Wyrm", - }, - } - Questie.dbLearner.global.settings.learnNpcs = true - - QuestieLearner:_StoreGuidSpawnEvidence(npcId, unitGUID, 3431, 58.68, 43.19) - - local entry = Questie.dbLearner.global.npcs[npcId][8][41298] - assert.is_not_nil(entry) - assert.are.equal(58.68, entry.x) - assert.are.equal(43.19, entry.y) - end) - - it("should repair legacy 0-10000 GUID spawn coordinates before merging", function() - local npcId = 15274 - local unitGUID = "Creature-0-1234-567-89-15274-41298" - - Questie.dbLearner.global.npcs = { - [npcId] = { - [1] = "Mana Wyrm", - }, - } - Questie.dbLearner.global.settings.learnNpcs = true - - QuestieLearner:_StoreGuidSpawnEvidence(npcId, unitGUID, 3431, 5868, 4319) - - local entry = Questie.dbLearner.global.npcs[npcId][8][41298] - assert.is_not_nil(entry) - assert.are.equal(58.68, entry.x) - assert.are.equal(43.19, entry.y) - end) - - --========================================================================== - -- Existing test: spell cast learning - --========================================================================== - it("should learn spell casts into dbLearner quest objectives when they match a quest objective", function() - local questId = 12345 - local spellId = 29228 - local targetGUID = "Creature-0-1234-567-89-21878-0000000000" - - Questie.dbLearner.global.quests = {} - - _G.QuestieCompat.GetQuestLogTitle = function(index) - return "Test Quest", 1, nil, false, nil, nil, nil, questId - end - - _G.QuestLogCache.GetQuest = function(id) - return { - objectives = { - { type = "spell", text = "Flame Shock the enemy" } - } - } - end - - QuestieLearner:LearnSpellCast(spellId, "Flame Shock", targetGUID, "Enemy NPC") - - assert.is_not_nil(Questie.dbLearner.global.quests[questId]) - assert.is_not_nil(Questie.dbLearner.global.quests[questId][10]) - assert.is_not_nil(Questie.dbLearner.global.quests[questId][10][1]) - assert.are.same({ 21878, "Flame Shock" }, Questie.dbLearner.global.quests[questId][10][1][1]) - end) - - --========================================================================== - -- InjectLearnedData zone key migration (uiMapId → areaId) - --========================================================================== - describe("InjectLearnedData zone migration", function() - it("should migrate NPC spawn zone keys from uiMapId to areaId", function() - Questie.dbLearner.global.npcs = { - [21878] = { - [1] = "Felboar", - [7] = { - [1241] = { -- uiMapId (Sunstrider) → should migrate to 3430 - { 35.0, 45.0 }, - { 40.0, 50.0 }, - }, - }, - }, - } - Questie.dbLearner.global.quests = {} - Questie.dbLearner.global.objects = {} - Questie.dbLearner.global.items = {} - - -- Reload the data by calling InjectLearnedData (already called in Initialize, but re-call with updated data) - QuestieLearner:InjectLearnedData() - - local npcs = Questie.dbLearner.global.npcs - assert.is_nil(npcs[21878][7][1241], - "Old uiMapId key 1241 should be removed after migration") - assert.is_not_nil(npcs[21878][7][3430], - "New areaId key 3430 should exist after migration") - assert.are.equal(2, #npcs[21878][7][3430], - "Should have 2 coords entries in migrated zone") - assert.are.same({ 35.0, 45.0 }, npcs[21878][7][3430][1]) - assert.are.same({ 40.0, 50.0 }, npcs[21878][7][3430][2]) - end) - - it("should merge migrated spawn data with existing areaId data", function() - Questie.dbLearner.global.npcs = { - [21878] = { - [1] = "Felboar", - [7] = { - [1241] = { -- uiMapId → merge into 3430 - { 35.0, 45.0 }, - }, - [3430] = { -- Already correct areaId - { 50.0, 55.0 }, - }, - }, - }, - } - Questie.dbLearner.global.quests = {} - Questie.dbLearner.global.objects = {} - Questie.dbLearner.global.items = {} - - QuestieLearner:InjectLearnedData() - - local npcs = Questie.dbLearner.global.npcs - assert.is_nil(npcs[21878][7][1241], "Old uiMapId key should be removed") - assert.are.equal(2, #npcs[21878][7][3430], - "Merged: 1 existing + 1 migrated = 2 entries") - end) - - it("should migrate object spawn zone keys from uiMapId to areaId", function() - Questie.dbLearner.global.npcs = {} - Questie.dbLearner.global.quests = {} - Questie.dbLearner.global.items = {} - Questie.dbLearner.global.objects = { - [181345] = { - [1] = "Mysterious Pedestal", - [4] = { - [1241] = { -- uiMapId → migrate to 3430 - { 30.0, 40.0 }, - }, - }, - }, - } - - QuestieLearner:InjectLearnedData() - - local objects = Questie.dbLearner.global.objects - assert.is_nil(objects[181345][4][1241], - "Old uiMapId key should be removed from objects") - assert.is_not_nil(objects[181345][4][3430], - "Migrated areaId key should exist") - assert.are.same({ 30.0, 40.0 }, objects[181345][4][3430][1]) - end) - - it("should leave non-mappable zone keys unchanged", function() - Questie.dbLearner.global.npcs = { - [21878] = { - [1] = "Felboar", - [7] = { - [3430] = { -- Already correct areaId — stay - { 35.0, 45.0 }, - }, - [530] = { -- No ZoneDB mapping — stay - { 60.0, 30.0 }, - }, - }, - }, - } - Questie.dbLearner.global.quests = {} - Questie.dbLearner.global.objects = {} - Questie.dbLearner.global.items = {} - - QuestieLearner:InjectLearnedData() - - local npcs = Questie.dbLearner.global.npcs - assert.is_not_nil(npcs[21878][7][3430], "3430 areaId should remain") - assert.is_not_nil(npcs[21878][7][530], "530 (no mapping) should remain") - assert.are.equal(1, #npcs[21878][7][3430], "3430 should still have 1 entry") - assert.are.equal(1, #npcs[21878][7][530], "530 should still have 1 entry") - end) - end) - - --========================================================================== - -- LearnQuestObjectiveNPC icon preservation - --========================================================================== - describe("LearnQuestObjectiveNPC icon preservation", function() - it("should pass the objective icon from QuestLogCache to RegisterObjectiveTooltip", function() - local questId = 1001 - local npcId = 21878 - local objText = "Slay 10 felboars" - local objectiveIndex = 1 - - Questie.dbLearner.global.quests = {} - Questie.dbLearner.global.npcs = {} - - -- Mock QuestLogCache.GetQuestObjectives returns objectives with Icon 136006 - _G._mock_questObjectives = { - { text = "Slay 10 felboars", Icon = 136006, objectiveType = "slay" }, - } - - QuestieLearner:LearnQuestObjectiveNPC(questId, npcId, objText, objectiveIndex) - - -- Verify RegisterObjectiveTooltip was called with the icon - assert.is_not_nil(_G._lastRegisteredTooltip, - "RegisterObjectiveTooltip should have been called") - assert.are.equal(questId, _G._lastRegisteredTooltip.questId) - assert.are.equal("m_" .. npcId, _G._lastRegisteredTooltip.identifier) - assert.are.equal(objText, _G._lastRegisteredTooltip.data.Description) - assert.are.equal(136006, _G._lastRegisteredTooltip.data.Icon, - "Icon from QuestLogCache should be passed to tooltip registration") - end) - - it("should work when QuestLogCache has no matching objective text", function() - local questId = 1002 - local npcId = 21879 - local objText = "Gather 5 moonflowers" - local objectiveIndex = 1 - - Questie.dbLearner.global.quests = {} - Questie.dbLearner.global.npcs = {} - - -- Objectives don't include "moonflowers" - _G._mock_questObjectives = { - { text = "Slay 10 felboars", Icon = 136006 }, - { text = "Collect 5 herbs", Icon = 134217 }, - } - - QuestieLearner:LearnQuestObjectiveNPC(questId, npcId, objText, objectiveIndex) - - -- Should still register, but with nil Icon (graceful fallback) - assert.is_not_nil(_G._lastRegisteredTooltip, - "RegisterObjectiveTooltip should still be called without matching icon") - assert.is_nil(_G._lastRegisteredTooltip.data.Icon, - "Icon should be nil when no matching objective text is found") - end) - - it("should work when QuestLogCache.GetQuestObjectives is nil", function() - local questId = 1003 - local npcId = 21880 - local objText = "Kill 3 worgs" - local objectiveIndex = 1 - - Questie.dbLearner.global.quests = {} - Questie.dbLearner.global.npcs = {} - - -- nil/empty so no icon lookup happens - _G._mock_questObjectives = nil - - QuestieLearner:LearnQuestObjectiveNPC(questId, npcId, objText, objectiveIndex) - - assert.is_not_nil(_G._lastRegisteredTooltip, - "RegisterObjectiveTooltip should be called even with nil objectives") - assert.is_nil(_G._lastRegisteredTooltip.data.Icon, - "Icon should be nil when GetQuestObjectives returns nil") - end) - end) - - --========================================================================== - -- MIN_CONFIDENCE_PINS = 1 - --========================================================================== - describe("Settings defaults", function() - it("should have minConfidencePins default to 1 on fresh data", function() - -- After Initialize, settings should be set with minConfidencePins = 1 - local settings = QuestieLearner:GetSettings() - assert.are.equal(1, settings.minConfidencePins, - "minConfidencePins should be 1 for Ascension play") - end) - - it("should backfill legacy SavedVariables with minConfidencePins = 1", function() - -- Simulate legacy data without minConfidencePins - if Questie.dbLearner.global.settings then - Questie.dbLearner.global.settings.minConfidencePins = nil - end - - -- Re-initialize to trigger backfill - QuestieLearner:Initialize() - local settings = QuestieLearner:GetSettings() - - assert.are.equal(1, settings.minConfidencePins, - "Legacy settings should be backfilled with minConfidencePins = 1") - end) - end) - - --========================================================================== - -- NPC learning API - --========================================================================== - describe("LearnNPC spawn zone tracking", function() - it("should store NPC spawn zoneId correctly", function() - local npcId = 21878 - local spawnZoneId = 3430 -- Eversong Woods - - Questie.dbLearner.global.quests = {} - Questie.dbLearner.global.npcs = {} - - -- Mock player position - _G.QuestieCompat.GetCurrentPlayerPosition = function() - return 3430, 0.35, 0.45 - end - - -- Mock coords - _G.UnitPosition = function(unit) return -8940, -137, 82 end - - QuestieLearner:LearnNPC(npcId, "Felboar", 60, nil, 2, nil, nil, nil, spawnZoneId) - - assert.is_not_nil(Questie.dbLearner.global.npcs[npcId], - "NPC should be learned") - assert.are.equal("Felboar", Questie.dbLearner.global.npcs[npcId][1], - "NPC name should be stored") - -- NPC spawn coords should be stored under the areaId - if Questie.dbLearner.global.npcs[npcId][7] then - assert.is_not_nil(Questie.dbLearner.global.npcs[npcId][7][spawnZoneId], - "Spawn coords should be stored under zoneId " .. spawnZoneId) - end - end) - end) - - --========================================================================== - -- PruneLearnedSpawnOutliers - --========================================================================== - describe("PruneLearnedSpawnOutliers", function() - local function setStaticNPC(npcId, spawnData) - -- Mock static DB return for QuestieDB.QueryNPC - _G.QuestieDB = _G.QuestieDB or {} - _G.QuestieDB.QueryNPC = function(id, ...) - if id == npcId then - return spawnData -- { [7] = { [zoneId] = { {x,y}, ... } } } - end - return nil - end - end - - after_each(function() - -- Restore QuestieDB.QueryNPC to nil (no static data) - _G.QuestieDB = _G.QuestieDB or {} - _G.QuestieDB.QueryNPC = function() return nil end - end) - - it("should remove learned spawns that deviate > threshold from static anchor", function() - local npcId = 21878 - local zoneId = 3430 - local threshold = 15 - - -- Static DB anchor: NPC spawns at (50, 50) with tolerance ±15 - setStaticNPC(npcId, { - [7] = { - [zoneId] = { - { 50.0, 50.0 }, - }, - }, - }) - - -- Learned data: one spawn near anchor, one far away - Questie.dbLearner.global.npcs = { - [npcId] = { - [1] = "Felboar", - [7] = { - [zoneId] = { - { 50.0, 50.0 }, -- within threshold - { 10.0, 10.0 }, -- > 15% away from anchor → pruned - { 51.0, 49.0 }, -- within threshold - }, - }, - }, - } - Questie.dbLearner.global.objects = {} - Questie.dbLearner.global.quests = {} - Questie.dbLearner.global.items = {} - - local changed = QuestieLearner:PruneLearnedSpawnOutliers(threshold) - - assert.is_true(changed) - local spawns = Questie.dbLearner.global.npcs[npcId][7][zoneId] - assert.are.equal(2, #spawns, "Should have 2 spawns after pruning") - end) - - it("should use median cluster when no static anchor exists", function() - local npcId = 21879 - local zoneId = 3430 - local threshold = 10 - - -- No static DB entry - setStaticNPC(npcId, nil) - - -- Three spawns: two clustered at (50,50), one outlier at (10,10) - Questie.dbLearner.global.npcs = { - [npcId] = { - [1] = "Worg", - [7] = { - [zoneId] = { - { 50.0, 50.0 }, - { 50.5, 49.5 }, - { 10.0, 10.0 }, -- outlier - }, - }, - }, - } - Questie.dbLearner.global.objects = {} - Questie.dbLearner.global.quests = {} - Questie.dbLearner.global.items = {} - - local changed = QuestieLearner:PruneLearnedSpawnOutliers(threshold) - - assert.is_true(changed) - local spawns = Questie.dbLearner.global.npcs[npcId][7][zoneId] - assert.are.equal(2, #spawns, "Outlier should be removed") - end) - - it("should call InjectLearnedData after pruning when data changed", function() - local npcId = 21880 - local zoneId = 3430 - - setStaticNPC(npcId, { - [7] = { - [zoneId] = { - { 50.0, 50.0 }, - }, - }, - }) - - Questie.dbLearner.global.npcs = { - [npcId] = { - [1] = "Tiger", - [7] = { - [zoneId] = { - { 50.0, 50.0 }, - { 5.0, 5.0 }, -- outlier - }, - }, - }, - } - Questie.dbLearner.global.objects = {} - Questie.dbLearner.global.quests = {} - Questie.dbLearner.global.items = {} - - local injectCalled = false - local origInject = QuestieLearner.InjectLearnedData - QuestieLearner.InjectLearnedData = function(self) - injectCalled = true - return origInject(self) - end - - local changed = QuestieLearner:PruneLearnedSpawnOutliers(15) - - QuestieLearner.InjectLearnedData = origInject - - assert.is_true(changed, "Data should be changed") - assert.is_true(injectCalled, "InjectLearnedData should be called after pruning") - end) - - it("should not call InjectLearnedData when no spawns were pruned", function() - local npcId = 21881 - local zoneId = 3430 - - setStaticNPC(npcId, { - [7] = { - [zoneId] = { - { 50.0, 50.0 }, - }, - }, - }) - - -- All spawns within threshold — nothing pruned - Questie.dbLearner.global.npcs = { - [npcId] = { - [1] = "Bear", - [7] = { - [zoneId] = { - { 50.0, 50.0 }, - { 55.0, 45.0 }, -- still within 15 threshold - }, - }, - }, - } - Questie.dbLearner.global.objects = {} - Questie.dbLearner.global.quests = {} - Questie.dbLearner.global.items = {} - - local injectCalled = false - local origInject = QuestieLearner.InjectLearnedData - QuestieLearner.InjectLearnedData = function(self) - injectCalled = true - return origInject(self) - end - - local changed = QuestieLearner:PruneLearnedSpawnOutliers(15) - - QuestieLearner.InjectLearnedData = origInject - - assert.is_false(changed, "No data should be changed") - assert.is_false(injectCalled, "InjectLearnedData should NOT be called when nothing changed") - end) - - it("should prune object spawns stored in [4] without static anchor", function() - local objectId = 181345 - local zoneId = 3430 - local threshold = 10 - - -- Objects store spawns in [4], not [7] - Questie.dbLearner.global.npcs = {} - Questie.dbLearner.global.quests = {} - Questie.dbLearner.global.items = {} - Questie.dbLearner.global.objects = { - [objectId] = { - [1] = "Pedestal", - [4] = { - [zoneId] = { - { 30.0, 30.0 }, - { 30.5, 29.5 }, - { 80.0, 80.0 }, -- outlier - }, - }, - }, - } - - local changed = QuestieLearner:PruneLearnedSpawnOutliers(threshold) - - assert.is_true(changed) - local spawns = Questie.dbLearner.global.objects[objectId][4][zoneId] - assert.are.equal(2, #spawns, "Object outlier should be pruned") - end) - - it("should return false when there is nothing to prune", function() - Questie.dbLearner.global.npcs = {} - Questie.dbLearner.global.objects = {} - Questie.dbLearner.global.quests = {} - Questie.dbLearner.global.items = {} - - local changed = QuestieLearner:PruneLearnedSpawnOutliers(15) - - assert.is_false(changed, "Should return false when nothing to prune") - end) - end) - - --========================================================================== - -- _MergeSpawnEvidence (via OnCombatLogEvent integration) - --========================================================================== - describe("_MergeSpawnEvidence integration", function() - local function setStaticNPC(npcId, spawnData) - _G.QuestieDB = _G.QuestieDB or {} - _G.QuestieDB.QueryNPC = function(id, ...) - if id == npcId then return spawnData end - return nil - end - end - - after_each(function() - _G.QuestieDB = _G.QuestieDB or {} - _G.QuestieDB.QueryNPC = function() return nil end - end) - - it("should merge when 3+ kills at same spawn point and >60% threshold exceeded", function() - local npcId = 21878 - local unitGUID = "Creature-0-1234-567-89-21878-0000001111" - local unitName = "Felboar" - local zoneId = 3430 - - setStaticNPC(npcId, { - [7] = { - [zoneId] = { - { 50.0, 50.0 }, -- different from learned - }, - }, - }) - - Questie.dbLearner.global.npcs = {} - Questie.dbLearner.global.settings.learnNpcs = true - - -- Three kills at different GUIDs but same zone+coords - local sameX, sameY = 0.1111, 0.2222 - for i = 1, 3 do - local guid = "Creature-0-1234-567-89-21878-" .. string.format("%010d", 1000 + i) - _G.QuestieCompat.GetCurrentPlayerPosition = function() - return zoneId, sameX, sameY - end - QuestieLearner:OnCombatLogEvent(GetTime(), "UNIT_DIED", - nil, nil, nil, guid, unitName, nil, nil, nil) - end - - -- After 3rd kill, _MergeSpawnEvidence should have injected spawn override - local override = QuestieDB.npcDataOverrides[npcId] - local spawnList = override and override[7] and override[7][zoneId] - assert.is_not_nil(spawnList, "Spawn override should be injected") - assert.is_true(#spawnList >= 1, "At least one spawn should be injected") - end) - - it("should NOT merge when < 3 kills (insufficient evidence)", function() - local npcId = 21879 - local zoneId = 3430 - - setStaticNPC(npcId, { - [7] = { - [zoneId] = { - { 50.0, 50.0 }, - }, - }, - }) - - Questie.dbLearner.global.npcs = { - [npcId] = { - [1] = "Worg", - [8] = { - [1001] = { zoneId = zoneId, x = 11.0, y = 22.0, ts = time(), source = "local", confidence = 1 }, - [1002] = { zoneId = zoneId, x = 11.0, y = 22.0, ts = time(), source = "local", confidence = 1 }, - }, - }, - } - Questie.dbLearner.global.settings.learnNpcs = true - - -- Only 2 kills — below threshold - -- (simulate by directly setting guidSpawns as above) - - -- Verify no override was created - local overrideBefore = QuestieDB.npcDataOverrides[npcId] - assert.is_nil(overrideBefore, - "No override should exist with only 2 kills") - end) - - it("should NOT merge when top spawn is at or below 60% confidence", function() - local npcId = 21880 - local zoneId = 3430 - - -- Static DB has a spawn at (50, 50) - setStaticNPC(npcId, { - [7] = { - [zoneId] = { - { 50.0, 50.0 }, - }, - }, - }) - - Questie.dbLearner.global.npcs = { - [npcId] = { - [1] = "Bear", - [8] = { - [1001] = { zoneId = zoneId, x = 11.0, y = 22.0, ts = time(), source = "local", confidence = 1 }, - [1002] = { zoneId = zoneId, x = 11.0, y = 22.0, ts = time(), source = "local", confidence = 1 }, - [1003] = { zoneId = zoneId, x = 33.0, y = 44.0, ts = time(), source = "local", confidence = 1 }, - }, - }, - } - Questie.dbLearner.global.settings.learnNpcs = true - - -- 2 kills at (11,22), 1 kill at (33,44) = 50% each for top - -- Top is at 50% ≤ 60%, should not override - - local overrideBefore = QuestieDB.npcDataOverrides[npcId] - assert.is_nil(overrideBefore, - "No override at 50% confidence (below 60% threshold)") - end) - - it("should NOT override when learned spawn matches static DB entry", function() - local npcId = 21881 - local zoneId = 3430 - local staticX, staticY = 50.0, 50.0 - - -- Static DB has spawn at (50, 50) - setStaticNPC(npcId, { - [7] = { - [zoneId] = { - { staticX, staticY }, - }, - }, - }) - - -- Learned evidence: 3 kills at same coords as static (within rounding) - local learnedX = 50.0 - local learnedY = 50.0 - - Questie.dbLearner.global.npcs = { - [npcId] = { - [1] = "Tiger", - [8] = { - [1001] = { zoneId = zoneId, x = learnedX, y = learnedY, ts = time(), source = "local", confidence = 1 }, - [1002] = { zoneId = zoneId, x = learnedX, y = learnedY, ts = time(), source = "local", confidence = 1 }, - [1003] = { zoneId = zoneId, x = learnedX, y = learnedY, ts = time(), source = "local", confidence = 1 }, - }, - }, - } - Questie.dbLearner.global.settings.learnNpcs = true - - -- All 3 kills agree at 100% but matches static — no override needed - local overrideBefore = QuestieDB.npcDataOverrides[npcId] - assert.is_nil(overrideBefore, - "No override when learned matches static DB") - end) - end) -end)