You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

322 lines
9.0 KiB

local Util = require("Util");
local TestUtil = require("TestUtil");
-- Test doubles and tests.
g_test_settings = {
wbt_print = false; -- If WBT:Print(...) should be print.
}
--------------------------------------------------------------------------------
-- Blizzard-like event framework
--------------------------------------------------------------------------------
local EventManager = {};
EventManager.frames = {};
function EventManager:Reset()
frames = {};
end
function EventManager:FireEvent(event, ...)
for _, frame in pairs(self.frames) do
frame:HandleEvent(event, ...);
end
end
function EventManager:RegisterFrame(f)
if f.name then
self.frames[f.name] = f;
else
table.insert(self.frames, f);
end
end
local Frame = {};
function Frame:New(name)
local f = {};
f.name = name; -- Can be nil.
f.events = {};
f.event_handler = nil;
setmetatable(f, self);
self.__index = self; -- XXX: Should be f.__index = self ?
return f;
end
function CreateFrame(_, name)
local f = Frame:New(name);
EventManager:RegisterFrame(f);
return f;
end
function Frame:RegisterEvent(event)
self.events[event] = true;
end
function Frame:UnregisterEvent(event)
self.events[event] = nil;
end
function Frame:SetScript(triggerKind, eventHandler)
self.trigger_kind = triggerKind;
self.event_handler = eventHandler;
end
function Frame:HandleEvent(event, ...)
if self.trigger_kind ~= "OnEvent" then
-- print("Fake Frame: Only 'OnEvent' supported. My trigger kind: ", self.trigger_kind);
return;
end
if self.events[event] then
-- print(self.name)
self:event_handler(event, ...);
return;
end
end
--------------------------------------------------------------------------------
-- Ace, LibStub and other 3rd party:
--------------------------------------------------------------------------------
local AceAddon = {};
function AceAddon:New()
local o = {};
setmetatable(o, self);
self.__index = self;
return o;
end
function AceAddon:RegisterChatCommand(...)
return;
end
function AceAddon:Print(text)
if g_test_settings.wbt_print then
print("WBT:", text);
end
end
function LibStub(addonName)
local ls = {};
function ls:NewAddon(addonName, aceModule)
return AceAddon:New();
end
function ls:New(dbName, defaultDb)
return defaultDb;
end
function ls:Embed(...)
return;
end
function ls:AddToBlizOptions(...)
return;
end
function ls:RegisterOptionsTable(addonName, optionsTable, ...)
return;
end
function ls:Embed(comClass)
function RegisterComm(...)
return;
end
comClass.RegisterComm = RegisterComm;
end
return ls;
end
--------------------------------------------------------------------------------
-- WBT test doubles
--------------------------------------------------------------------------------
local GUI = {};
function GUI:New()
local o = {};
setmetatable(o, self);
self.__index = self;
return o;
end
function GUI.SetupAceGUI() return; end
function GUI.Init() return; end
function GUI:Update() return; end
function GUI:UpdateWindowTitle() return; end
--------------------------------------------------------------------------------
-- WoW API
--------------------------------------------------------------------------------
-- Fake "world" object. Set fields as necessary before testing.
local g_game = {
servertime = 1677434396,
world = {
shard_id = 44
},
player = {
-- Static
name = "Chainorth",
realmname = "Stormreaver",
-- Dynamic
map_id = 507, -- Isle of Giants
coords = { -- Oondasta spawn point.
x = 0.50,
y = 0.56
},
}
}
function GetUnitName(unit)
if unit == "player" then
return "Playerone"
end
return "Notplayer";
end
function UnitExists(unit)
return unit == "mouseover";
end
function UnitGUID(unit)
if unit == "mouseover" then
return "Creature-field2-field3-field4-" .. tostring(g_game.world.shard_id)
end
error("NYI")
end
function GetRealmName()
return g_game.player.realm_name;
end
-- XXX: Not correct, but doesn't matter right now.
function GetNormalizedRealmName()
return g_game.player.realm_name;
end
function GetServerTime()
return g_game.servertime;
end
local Coord = {};
function Coord:GetXY()
return g_game.player.coords.x,
g_game.player.coords.y;
end
C_Map = {};
function C_Map.GetPlayerMapPosition(mapId, unitname)
return Coord;
end
function C_Map.GetBestMapForUnit(_)
return g_game.player.map_id;
end
--------------------------------------------------------------------------------
-- WoW lua API
--------------------------------------------------------------------------------
function strsplit(sep, str)
local t={}
for match in string.gmatch(str, "([^"..sep.."]+)") do
table.insert(t, match)
end
return table.unpack(t)
end
--------------------------------------------------------------------------------
-- Blizzard-like addon loader for WBT
--------------------------------------------------------------------------------
-- Returns an instance of WBT, and tries to perform loading in the same way
-- as Blizzard (probably) does it. (An option would be to change how module
-- imports are done, and instead import with 'require' instead of file varargs.)
local function LoadWBT()
local addonName = "addonname_unused";
local addonTable = {};
-- Load in same order as in .toc file:
assert(loadfile("Util.lua")) (addonName, addonTable);
assert(loadfile("Sound.lua")) (addonName, addonTable);
assert(loadfile("BossData.lua")) (addonName, addonTable);
assert(loadfile("Com.lua")) (addonName, addonTable);
assert(loadfile("NameplateTracker.lua"))(addonName, addonTable);
addonTable.GUI = GUI; -- GUI is a fake defined in this file.
assert(loadfile("Options.lua")) (addonName, addonTable);
assert(loadfile("KillInfo.lua")) (addonName, addonTable);
local WBT = assert(loadfile("WorldBossTimers.lua"))(addonName, addonTable);
return WBT;
end
--------------------------------------------------------------------------------
-- Tests
--------------------------------------------------------------------------------
function TestStrSplit()
a, b, c = strsplit("-", "a-b1-c22");
assert(a == "a", a);
assert(b == "b1", b);
assert(c == "c22", c);
end
local function FireDetectShard()
EventManager:FireEvent("UPDATE_MOUSEOVER_UNIT", "mouseover");
end
local function TestSharingWithoutShardId()
g_test_settings.wbt_print = false;
local bossname = "Oondasta";
EventManager:Reset();
local WBT = LoadWBT();
WBT.AceAddon:OnEnable();
-- Detect current shard:
local test_shard_id = 44;
g_game.world.shard_id = test_shard_id;
FireDetectShard();
-- Get shared a timer without shard_id
local event = "CHAT_MSG_SAY";
local msg = TestUtil.CreateShareMsg(bossname, g_game.servertime, 9, nil);
local sender = "Shareson";
EventManager:FireEvent(event, msg, sender);
local ki = WBT.GetPrimaryKillInfo();
assert(ki:HasUnknownShard(), ki.shard_id)
-- Get new KillInfo with shard ID. The new KillInfo should now be prioritized.
-- Regardless of if the player's current shard id is known or not.
local event = "CHAT_MSG_SAY";
local msg = TestUtil.CreateShareMsg(bossname, g_game.servertime, 8, test_shard_id);
local sender = "Sharesontwo";
EventManager:FireEvent(event, msg, sender);
local ki = WBT.GetPrimaryKillInfo();
assert(ki.shard_id == 44, ki.shard_id)
end
local function TestShare(bossname, expectSuccess)
EventManager:Reset();
local WBT = LoadWBT();
WBT.AceAddon:OnEnable();
-- Detect current shard:
g_game.world.shard_id = 44;
FireDetectShard();
-- Assert no timer:
assert(Util.TableIsEmpty(WBT.db.global.kill_infos), "Incorrect setup.");
-- Share the timer:
local event = "CHAT_MSG_SAY";
local msg = TestUtil.CreateShareMsg(bossname, g_game.servertime, 9, g_game.world.shard_id);
local sender = "Shareson";
EventManager:FireEvent(event, msg, sender);
-- Assert parsed:
local nTimers = Util.TableLength(WBT.db.global.kill_infos);
local nTimersExp = expectSuccess and 1 or 0;
assert(nTimers == nTimersExp, "Incorrect number of timers: " .. nTimers);
end
function main()
TestStrSplit();
TestSharingWithoutShardId();
TestShare("Oondasta", true);
TestShare("Sha of Anger", true);
TestShare("A. Harvester", true);
TestShare("NotBoss", false);
TestShare("Sha of Rage", false);
end
main()