|
|
|
|
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()
|
|
|
|
|
self.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: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
|
|
|
|
|
function GUI:Rebuild() 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",
|
|
|
|
|
connected_realms = {"Stormreaver", "Vashj"},
|
|
|
|
|
-- 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
|
|
|
|
|
|
|
|
|
|
function GetAutoCompleteRealms()
|
|
|
|
|
return g_game.player.connected_realms;
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
C_Timer = {};
|
|
|
|
|
function C_Timer.After(_, fcn)
|
|
|
|
|
fcn();
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function PlaySoundFile(_, _) return; end
|
|
|
|
|
function FlashClientIcon() return; end
|
|
|
|
|
function RequestRaidInfo() return; end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- Change this fields before firing an event that uses combat event info.
|
|
|
|
|
local CombatEventInfo = {
|
|
|
|
|
eventType = "",
|
|
|
|
|
dest_unit_guid = "";
|
|
|
|
|
}
|
|
|
|
|
function CombatLogGetCurrentEventInfo()
|
|
|
|
|
local _ = nil;
|
|
|
|
|
return _, CombatEventInfo.eventType, _, _, _, _, _, CombatEventInfo.dest_unit_guid, _;
|
|
|
|
|
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
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
local WBT; -- Convenient to put it in this scope, in order to write helper fcns.
|
|
|
|
|
|
|
|
|
|
function TestStrSplit()
|
|
|
|
|
local a, b, c = strsplit("-", "a-b1-c22");
|
|
|
|
|
assert(a == "a", a);
|
|
|
|
|
assert(b == "b1", b);
|
|
|
|
|
assert(c == "c22", c);
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local function BuildGUID(boss_name)
|
|
|
|
|
local npc_id = tostring(WBT.BossData.Get(boss_name).ids[1]);
|
|
|
|
|
local shard_id = tostring(g_game.world.shard_id);
|
|
|
|
|
return "Creature-2-3-4-"..shard_id.."-"..npc_id;
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local function FireDetectShard()
|
|
|
|
|
EventManager:FireEvent("UPDATE_MOUSEOVER_UNIT", "mouseover");
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local function FireRestartShardDetection()
|
|
|
|
|
EventManager:FireEvent("ZONE_CHANGED_NEW_AREA");
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local function FireLocalBossDeath()
|
|
|
|
|
CombatEventInfo.eventType = "UNIT_DIED";
|
|
|
|
|
CombatEventInfo.dest_unit_guid = BuildGUID(WBT.BossesInCurrentZone()[1].name);
|
|
|
|
|
EventManager:FireEvent("COMBAT_LOG_EVENT_UNFILTERED");
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local function TestSharingWithoutShardId()
|
|
|
|
|
g_test_settings.wbt_print = false;
|
|
|
|
|
local bossname = "Oondasta";
|
|
|
|
|
EventManager:Reset();
|
|
|
|
|
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();
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
local function TestSavedShard()
|
|
|
|
|
EventManager:Reset();
|
|
|
|
|
WBT = LoadWBT();
|
|
|
|
|
local KillInfo = WBT.KillInfo;
|
|
|
|
|
WBT.AceAddon:OnEnable();
|
|
|
|
|
|
|
|
|
|
-- Initially saved shard should be unknown:
|
|
|
|
|
assert(WBT.GetCurrentShardID() == KillInfo.UNKNOWN_SHARD);
|
|
|
|
|
assert(WBT.GetSavedShardID(WBT.GetCurrentMapId()) == KillInfo.UNKNOWN_SHARD);
|
|
|
|
|
|
|
|
|
|
-- Detect initial shard:
|
|
|
|
|
g_game.world.shard_id = 44;
|
|
|
|
|
FireDetectShard();
|
|
|
|
|
assert(WBT.GetCurrentShardID() == g_game.world.shard_id);
|
|
|
|
|
assert(WBT.GetSavedShardID(WBT.GetCurrentMapId()) == g_game.world.shard_id);
|
|
|
|
|
|
|
|
|
|
-- Reset current shard:
|
|
|
|
|
FireRestartShardDetection();
|
|
|
|
|
assert(WBT.GetCurrentShardID() == KillInfo.UNKNOWN_SHARD);
|
|
|
|
|
assert(WBT.GetSavedShardID(WBT.GetCurrentMapId()) == g_game.world.shard_id);
|
|
|
|
|
|
|
|
|
|
-- Find same shard again:
|
|
|
|
|
FireDetectShard();
|
|
|
|
|
assert(WBT.GetCurrentShardID() == g_game.world.shard_id);
|
|
|
|
|
assert(WBT.GetSavedShardID(WBT.GetCurrentMapId()) == g_game.world.shard_id);
|
|
|
|
|
|
|
|
|
|
-- Reset again:
|
|
|
|
|
FireRestartShardDetection();
|
|
|
|
|
assert(WBT.GetCurrentShardID() == KillInfo.UNKNOWN_SHARD);
|
|
|
|
|
assert(WBT.GetSavedShardID(WBT.GetCurrentMapId()) == g_game.world.shard_id);
|
|
|
|
|
|
|
|
|
|
-- Find new shard:
|
|
|
|
|
g_game.world.shard_id = 55;
|
|
|
|
|
FireDetectShard();
|
|
|
|
|
assert(WBT.GetCurrentShardID() == g_game.world.shard_id);
|
|
|
|
|
assert(WBT.GetSavedShardID(WBT.GetCurrentMapId()) == g_game.world.shard_id);
|
|
|
|
|
|
|
|
|
|
-- Reset once again:
|
|
|
|
|
FireRestartShardDetection();
|
|
|
|
|
assert(WBT.GetCurrentShardID() == KillInfo.UNKNOWN_SHARD);
|
|
|
|
|
assert(WBT.GetSavedShardID(WBT.GetCurrentMapId()) == g_game.world.shard_id);
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local function TestSavedShardKillInfo()
|
|
|
|
|
EventManager:Reset();
|
|
|
|
|
WBT = LoadWBT();
|
|
|
|
|
local Options = WBT.Options;
|
|
|
|
|
WBT.AceAddon:OnEnable();
|
|
|
|
|
local ki;
|
|
|
|
|
|
|
|
|
|
-- Detect shard and kill boss:
|
|
|
|
|
g_game.world.shard_id = 44;
|
|
|
|
|
FireDetectShard();
|
|
|
|
|
FireLocalBossDeath();
|
|
|
|
|
|
|
|
|
|
Options.assume_realm_keeps_shard.set(true);
|
|
|
|
|
ki = WBT.GetPrimaryKillInfo();
|
|
|
|
|
assert(ki);
|
|
|
|
|
Options.assume_realm_keeps_shard.set(false);
|
|
|
|
|
ki = WBT.GetPrimaryKillInfo();
|
|
|
|
|
assert(ki);
|
|
|
|
|
|
|
|
|
|
-- Reset current shard:
|
|
|
|
|
FireRestartShardDetection();
|
|
|
|
|
|
|
|
|
|
Options.assume_realm_keeps_shard.set(true);
|
|
|
|
|
ki = WBT.GetPrimaryKillInfo();
|
|
|
|
|
assert(ki);
|
|
|
|
|
Options.assume_realm_keeps_shard.set(false);
|
|
|
|
|
ki = WBT.GetPrimaryKillInfo();
|
|
|
|
|
assert(ki == nil); -- Now nil
|
|
|
|
|
|
|
|
|
|
-- Find same shard again:
|
|
|
|
|
FireDetectShard();
|
|
|
|
|
|
|
|
|
|
Options.assume_realm_keeps_shard.set(true);
|
|
|
|
|
ki = WBT.GetPrimaryKillInfo();
|
|
|
|
|
assert(ki);
|
|
|
|
|
Options.assume_realm_keeps_shard.set(false);
|
|
|
|
|
ki = WBT.GetPrimaryKillInfo();
|
|
|
|
|
assert(ki); -- Found again
|
|
|
|
|
|
|
|
|
|
-- Find new shard:
|
|
|
|
|
g_game.world.shard_id = 55;
|
|
|
|
|
FireRestartShardDetection();
|
|
|
|
|
FireDetectShard();
|
|
|
|
|
|
|
|
|
|
Options.assume_realm_keeps_shard.set(true);
|
|
|
|
|
ki = WBT.GetPrimaryKillInfo();
|
|
|
|
|
assert(ki == nil); -- Now also nil!
|
|
|
|
|
Options.assume_realm_keeps_shard.set(false);
|
|
|
|
|
ki = WBT.GetPrimaryKillInfo();
|
|
|
|
|
assert(ki == nil); -- Nil again
|
|
|
|
|
|
|
|
|
|
-- Reset the new shard:
|
|
|
|
|
FireRestartShardDetection();
|
|
|
|
|
|
|
|
|
|
Options.assume_realm_keeps_shard.set(true);
|
|
|
|
|
ki = WBT.GetPrimaryKillInfo();
|
|
|
|
|
assert(ki == nil); -- Still nil
|
|
|
|
|
Options.assume_realm_keeps_shard.set(false);
|
|
|
|
|
ki = WBT.GetPrimaryKillInfo();
|
|
|
|
|
assert(ki == nil); -- Still nil
|
|
|
|
|
|
|
|
|
|
-- Find old shard again:
|
|
|
|
|
g_game.world.shard_id = 44;
|
|
|
|
|
FireRestartShardDetection();
|
|
|
|
|
FireDetectShard();
|
|
|
|
|
|
|
|
|
|
Options.assume_realm_keeps_shard.set(true);
|
|
|
|
|
ki = WBT.GetPrimaryKillInfo();
|
|
|
|
|
assert(ki); -- Found again
|
|
|
|
|
Options.assume_realm_keeps_shard.set(false);
|
|
|
|
|
ki = WBT.GetPrimaryKillInfo();
|
|
|
|
|
assert(ki); -- Found again
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local function main()
|
|
|
|
|
TestStrSplit();
|
|
|
|
|
TestSharingWithoutShardId();
|
|
|
|
|
TestShare("Oondasta", true);
|
|
|
|
|
TestShare("Sha of Anger", true);
|
|
|
|
|
TestShare("A. Harvester", true);
|
|
|
|
|
TestShare("NotBoss", false);
|
|
|
|
|
TestShare("Sha of Rage", false);
|
|
|
|
|
TestSavedShard();
|
|
|
|
|
TestSavedShardKillInfo();
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
main()
|