--[[-------------------------------------------------------------------- Copyright (c) 2013, 2014 Johnny C. Lam. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]]-------------------------------------------------------------------- --[[-------------------------------------------------------------------- This file implements parts of the WoW API for development and unit-testing. This file is not meant to be loaded into the addon. It should be used only outside of the WoW environment, such as when loaded by a standalone Lua 5.1 interpreter. --]]-------------------------------------------------------------------- -- Globally-accessible module table. WoWMock = {} --<private-static-properties> local _G = _G local getmetatable = getmetatable local io = io local ipairs = ipairs local loadstring = loadstring local next = next local pairs = pairs local print = print local rawget = rawget local rawset = rawset local select = select local setfenv = setfenv local setmetatable = setmetatable local string = string local table = table local tostring = tostring local type = type local unpack = unpack -- Metatable to provide __index method to tables so that if the requested key -- is missing from the table, then a new key is inserted with the value being -- the same as the missing key. local KeysAreMissingValuesMetatable = { __index = function(t, k) rawset(t, k, k) return k end, } --</private-static-properties> --<private-static-methods> local function DeepCopy(orig) local orig_type = type(orig) local copy if orig_type == 'table' then copy = {} for orig_key, orig_value in next, orig, nil do copy[DeepCopy(orig_key)] = DeepCopy(orig_value) end setmetatable(copy, DeepCopy(getmetatable(orig))) else -- number, string, boolean, etc copy = orig end return copy end local function DoNothing() -- No op. end local function ZeroFunction() return 0 end --</private-static-methods> --<private-static-properties> --[[-------------------------------- Fake library implementations. --]]-------------------------------- -- Forward declaration of LibStub. local LibStub = nil -- AceAddon-3.0 local AceAddon = nil do local lib = {} AceAddon = lib lib.initializationQueue = {} local prototype = {} prototype.GetModule = function(addon, name) addon.modules = addon.modules or {} return addon.modules[name] end prototype.GetName = function(addon) return addon.moduleName or addon.name end prototype.IterateModules = function(addon) return pairs(addon.modules) end prototype.NewModule = function(addon, name, ...) local args = { ... } local mod = lib:NewAddon(string.format("%s_%s", addon.name, name)) mod.moduleName = name -- Mix in default module prototype if addon.modulePrototype then for k, v in pairs(addon.modulePrototype) do mod[k] = v end end -- Embed methods from named libraries. for _, libName in ipairs(args) do local lib = LibStub(libName) if lib then for k, v in pairs(lib) do mod[k] = v end end end addon.modules = addon.modules or {} addon.modules[name] = mod return mod end prototype.SetDefaultModulePrototype = function(addon, proto) addon.modulePrototype = proto end lib.GetAddon = function(lib, name) lib.addons = lib.addons or {} return lib.addons[name] end lib.Fire = function(event, ...) for _, addon in ipairs(lib.initializationQueue) do if event == "ADDON_LOADED" and addon.OnInitialize then --print("Firing", event, addon.name) addon:OnInitialize() elseif event == "PLAYER_LOGIN" and addon.OnEnable then --print("Firing", event, addon.name) addon:OnEnable() elseif addon.SendMessage then addon:SendMessage(event, ...) end end end lib.IterateAddons = function(lib) return pairs(lib.addons) end lib.NewAddon = function(lib, name, ...) local addon local args if type(name) == "nil" then addon = {} name = ... args = { select(2, ...) } elseif type(name) == "table" then addon = name name = ... args = { select(2, ...) } else addon = {} args = { ... } end -- Copy addon prototype. for k, v in pairs(prototype) do addon[k] = v end -- Embed methods from named libraries. for _, libName in ipairs(args) do local lib = LibStub(libName) if lib then for k, v in pairs(lib) do addon[k] = v end end end addon.name = name lib.addons = lib.addons or {} lib.addons[name] = addon lib.initializationQueue[#lib.initializationQueue + 1] = addon return addon end end -- AceConfig-3.0 local AceConfig = nil do local lib = {} AceConfig = lib lib.RegisterOptionsTable = DoNothing end -- AceConfigDialog-3.0 local AceConfigDialog = nil do local lib = {} AceConfigDialog = lib lib.AddToBlizOptions = DoNothing end -- AceConsole-3.0 local AceConsole = nil do local lib = {} AceConsole = lib lib.Print = function(lib, ...) print(...) end lib.Printf = function(lib, ...) print(string.format(...)) end end -- AceDB-3.0 local AceDB = nil do local lib = {} AceDB = lib lib.New = function(lib, name, template) template = template or {} local db = DeepCopy(template) db.RegisterCallback = DoNothing db.RegisterDefaults = DoNothing return db end end -- AceDBOptions-3.0 local AceDBOptions = nil do local lib = {} AceDBOptions = lib lib.GetOptionsTable = DoNothing end -- AceEvent-3.0 local AceEvent = nil do local lib = {} AceEvent = lib local eventHandler = {} lib.RegisterEvent = function(lib, event, handler, arg) eventHandler[lib] = eventHandler[lib] or {} eventHandler[lib][event] = { handler, arg } end lib.RegisterMessage = lib.RegisterEvent lib.SendMessage = function(lib, event, ...) local handler, arg local tbl = eventHandler[lib] and eventHandler[lib][event] if tbl then handler, arg = tbl[1], tbl[2] if type(handler) == "string" then handler = lib[handler] arg = lib end else handler = lib[event] arg = lib end if handler then --print("Firing", event, lib.name) if arg then handler(arg, event, ...) else handler(event, ...) end end end end -- AceGUI-3.0 local AceGUI = nil do local lib = {} AceGUI = lib local widgetFactory = {} local container = {} lib.Create = function(lib, widgetType) local constructor = widgetFactory[widgetType] if constructor then return constructor() end end lib.RegisterAsContainer = function(lib, widget) container[widget] = true widget.AddChild = DoNothing widget.ReleaseChildren = DoNothing end lib.RegisterWidgetType = function(lib, name, constructor, version) widgetFactory[name] = constructor end end -- AceLocale-3.0 local AceLocale = nil do local lib = {} AceLocale = lib lib.GetLocale = function(lib, name) local L if lib.locale and lib.locale[name] then L = lib.locale[name] else L = lib:NewLocale(name, nil) end return L end lib.NewLocale = function(lib, name, locale) local L = setmetatable({}, KeysAreMissingValuesMetatable) lib.locale = lib.locale or {} lib.locale[name] = L return L end end -- AceTimer-3.0 local AceTimer = nil do local lib = {} AceTimer = lib lib.ScheduleRepeatingTimer = DoNothing end -- CallbackHandler-1.0 local CallbackHandler = nil do local lib = {} CallbackHandler = lib lib.New = function(lib, obj) obj.Fire = lib.Fire return obj end lib.Fire = function(lib, ...) end end -- LibBabble-CreatureType-3.0 local LibBabbleCreatureType = nil do local lib = {} LibBabbleCreatureType = lib lib.GetLookupTable = function(lib) local tbl = lib.lookupTable or setmetatable({}, KeysAreMissingValuesMetatable) lib.lookupTable = tbl return tbl end end -- LibTextDump-1.0 local LibTextDump = nil do local lib = {} LibTextDump = lib lib.New = DoNothing end -- LibStub do local lib = {} LibStub = lib lib.library = { ["AceAddon-3.0"] = AceAddon, ["AceConfig-3.0"] = AceConfig, ["AceConfigDialog-3.0"] = AceConfigDialog, ["AceConsole-3.0"] = AceConsole, ["AceDB-3.0"] = AceDB, ["AceDBOptions-3.0"] = AceDBOptions, ["AceEvent-3.0"] = AceEvent, ["AceGUI-3.0"] = AceGUI, ["AceLocale-3.0"] = AceLocale, ["AceTimer-3.0"] = AceTimer, ["CallbackHandler-1.0"] = CallbackHandler, ["LibBabble-CreatureType-3.0"] = LibBabbleCreatureType, ["LibTextDump-1.0"] = LibTextDump, } local mt = { __call = function(lib, name, flag) return lib:GetLibrary(name, flag) end, } lib.GetLibrary = function(lib, name, flag) return lib.library[name] end lib.NewLibrary = function(lib, name, major, minor) local newLib = {} lib.library[name] = newLib return newLib end setmetatable(lib, mt) end --</private-static-properties> --<public-static-properties> --[[---------------------- FrameXML/ChatFrame --]]---------------------- WoWMock.DEFAULT_CHAT_FRAME = { AddMessage = function(frame, text, red, green, blue, alpha) -- Strip out color UI escape sequences. text = string.gsub(text, "|c[0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f]", "") text = string.gsub(text, "|r", "") print(text) end } --[[---------------------- FrameXML/Constants --]]---------------------- -- Inventory slots WoWMock.INVSLOT_AMMO = 0 WoWMock.INVSLOT_HEAD = 1 WoWMock.INVSLOT_NECK = 2 WoWMock.INVSLOT_SHOULDER = 3 WoWMock.INVSLOT_BODY = 4 WoWMock.INVSLOT_CHEST = 5 WoWMock.INVSLOT_WAIST = 6 WoWMock.INVSLOT_LEGS = 7 WoWMock.INVSLOT_FEET = 8 WoWMock.INVSLOT_WRIST = 9 WoWMock.INVSLOT_HAND = 10 WoWMock.INVSLOT_FINGER1 = 11 WoWMock.INVSLOT_FINGER2 = 12 WoWMock.INVSLOT_TRINKET1 = 13 WoWMock.INVSLOT_TRINKET2 = 14 WoWMock.INVSLOT_BACK = 15 WoWMock.INVSLOT_MAINHAND = 16 WoWMock.INVSLOT_OFFHAND = 17 WoWMock.INVSLOT_RANGED = 18 WoWMock.INVSLOT_TABARD = 19 WoWMock.INVSLOT_FIRST_EQUIPPED = WoWMock.INVSLOT_HEAD WoWMock.INVSLOT_LAST_EQUIPPED = WoWMock.INVSLOT_TABARD -- Power Types WoWMock.SPELL_POWER_MANA = 0 WoWMock.SPELL_POWER_RAGE = 1 WoWMock.SPELL_POWER_FOCUS = 2 WoWMock.SPELL_POWER_ENERGY = 3 --WoWMock.SPELL_POWER_CHI = 4 -- This is obsolete now. WoWMock.SPELL_POWER_RUNES = 5 WoWMock.SPELL_POWER_RUNIC_POWER = 6 WoWMock.SPELL_POWER_SOUL_SHARDS = 7 WoWMock.SPELL_POWER_ECLIPSE = 8 WoWMock.SPELL_POWER_HOLY_POWER = 9 WoWMock.SPELL_POWER_ALTERNATE_POWER = 10 WoWMock.SPELL_POWER_DARK_FORCE = 11 WoWMock.SPELL_POWER_CHI = 12 WoWMock.SPELL_POWER_SHADOW_ORBS = 13 WoWMock.SPELL_POWER_BURNING_EMBERS = 14 WoWMock.SPELL_POWER_DEMONIC_FURY = 15 WoWMock.RAID_CLASS_COLORS = { ["HUNTER"] = { r = 0.67, g = 0.83, b = 0.45, colorStr = "ffabd473" }, ["WARLOCK"] = { r = 0.58, g = 0.51, b = 0.79, colorStr = "ff9482c9" }, ["PRIEST"] = { r = 1.0, g = 1.0, b = 1.0, colorStr = "ffffffff" }, ["PALADIN"] = { r = 0.96, g = 0.55, b = 0.73, colorStr = "fff58cba" }, ["MAGE"] = { r = 0.41, g = 0.8, b = 0.94, colorStr = "ff69ccf0" }, ["ROGUE"] = { r = 1.0, g = 0.96, b = 0.41, colorStr = "fffff569" }, ["DRUID"] = { r = 1.0, g = 0.49, b = 0.04, colorStr = "ffff7d0a" }, ["SHAMAN"] = { r = 0.0, g = 0.44, b = 0.87, colorStr = "ff0070de" }, ["WARRIOR"] = { r = 0.78, g = 0.61, b = 0.43, colorStr = "ffc79c6e" }, ["DEATHKNIGHT"] = { r = 0.77, g = 0.12 , b = 0.23, colorStr = "ffc41f3b" }, ["MONK"] = { r = 0.0, g = 1.00 , b = 0.59, colorStr = "ff00ff96" }, } --[[-------------------------- FrameXML/GlobalStrings --]]-------------------------- WoWMock.ITEM_LEVEL = "Item Level %d" --[[--------------------------- FrameXML/SpellBookFrame --]]--------------------------- WoWMock.BOOKTYPE_SPELL = "spell" WoWMock.BOOKTYPE_PET = "pet" --[[---------------------------- FrameXML/TalentFrameBase --]]---------------------------- WoWMock.MAX_TALENT_TIERS = 7 WoWMock.NUM_TALENT_COLUMNS = 3 --[[-------------------------------------------------------------------- debugprofilestop() is a non-standard Lua function that returns the current time in milliseconds. This is a trivial implementation to just get the Profiler module working. --]]-------------------------------------------------------------------- WoWMock.debugprofilestop = ZeroFunction --[[-------------------------------------------------------------------- strsplit() is a non-standard Lua function that splits a string and returns multiple return values for each substring delimited by the named delimiter character. This implementation is taken verbatim from: http://lua-users.org/wiki/SplitJoin --]]-------------------------------------------------------------------- WoWMock.strsplit = function(delim, str, maxNb) -- Fix up '.' character class. delim = string.gsub(delim, "%.", "%%.") -- Eliminate bad cases... if string.find(str, delim) == nil then return str end if maxNb == nil or maxNb < 1 then maxNb = 0 -- No limit end local result = {} local pat = "(.-)" .. delim .. "()" local nb = 0 local lastPos for part, pos in string.gfind(str, pat) do nb = nb + 1 result[nb] = part lastPos = pos if nb == maxNb then break end end -- Handle the last field if nb ~= maxNb then result[nb + 1] = string.sub(str, lastPos) end return unpack(result) end --[[-------------------------------------------------------------------- tostringall() is a non-standard Lua function that returns a list of each argument converted to a string. --]]-------------------------------------------------------------------- WoWMock.tostringall = function(...) local array = { ... } local N = select("#", ...) for i = 1, N do array[N] = tostring(array[N]) end return unpack(array) end --[[-------------------------------------------------------------------- wipe() is a non-standard Lua function that clears the contents of a table and leaves the table pointer intact. --]]-------------------------------------------------------------------- WoWMock.wipe = function(t) for k in pairs(t) do t[k] = nil end end --[[------------------------------------------------- Fake Blizzard API functions for unit testing. --]]------------------------------------------------- WoWMock.mock = {} WoWMock.mock["CreateFrame"] = [[ do local function DoNothing() end local function ZeroFunction() return 0 end function CreateFrame(...) local frame = { CreateTexture = function(...) return CreateFrame() end, EnableMouse = DoNothing, Hide = DoNothing, IsVisible = DoNothing, NumLines = ZeroFunction, SetAllPoints = DoNothing, SetAlpha = DoNothing, SetFrameStrata = DoNothing, SetHeight = DoNothing, SetInventoryItem = DoNothing, SetMovable = DoNothing, SetOwner = DoNothing, SetPoint = DoNothing, SetScript = DoNothing, SetTexture = DoNothing, SetWidth = DoNothing, } return frame end end ]] WoWMock.mock["GetActiveSpecGroup"] = [[ function GetActiveSpecGroup() -- Always in the primary specialization. return 1 end ]] WoWMock.mock["GetActionInfo"] = [[ function GetActionInfo(slot) -- Action bar is always empty. return nil end ]] WoWMock.mock["GetAuctionItemSubClasses"] = [[ function GetAuctionItemSubClasses(classIndex) return "One-Handed Axes", "Two-Handed Axes", "Bows", "Guns", "One-Handed Maces", "Two-Handed Maces", "Polearms", "One-Handed Swords", "Two-Handed Swords", "Staves", "Fist Weapons", "Miscellaneous", "Daggers", "Thrown", "Crossbows", "Wands", "Fishing Poles" end ]] WoWMock.mock["GetBindingKey"] = [[ function GetBindingKey(name) -- No keybinds are assigned. return nil end ]] WoWMock.mock["GetBonusBarIndex"] = [[ function GetBonusBarIndex() return 8 end ]] WoWMock.mock["GetGlyphSocketInfo"] = [[ function GetGlyphSocketInfo(socket, talentGroup) -- No glyphs. return nil end ]] WoWMock.mock["GetInventoryItemGems"] = [[ function GetInventoryItemGems(slot) -- Player is always completely un-gemmed. return nil end ]] WoWMock.mock["GetInventoryItemID"] = [[ function GetInventoryItemID(unitId, slot) -- All units are naked. return nil end ]] WoWMock.mock["GetItemInfo"] = [[ function GetItemInfo(item) if type(item) == "number" then item = string.format("Item Name Of %d", item) end return item end ]] WoWMock.mock["GetLocale"] = [[ function GetLocale() return "enUS" end ]] WoWMock.mock["GetNumGlyphSockets"] = [[ function GetNumGlyphSockets() -- 3 x Major + 3 x Minor return 6 end ]] WoWMock.mock["GetNumShapeshiftForms"] = ZeroFunction WoWMock.mock["GetPowerRegen"] = [[ function GetPowerRegen() return 0, 0 end ]] WoWMock.mock["GetRuneCooldown"] = [[ function GetRuneCooldown(slot) -- The rune is always ready. return 0, 10, true end ]] WoWMock.mock["GetRuneType"] = [[ function GetRuneType(slot) -- Everything is a death rune. return 4 end ]] WoWMock.mock["GetShapeshiftForm"] = [[ function GetShapeshiftForm() -- Always in humanoid form. return 0 end ]] WoWMock.mock["GetSpecialization"] = [[ function GetSpecialization() local specialization = WOWMOCK_CONFIG.specialization or 1 return specialization end ]] WoWMock.mock["GetSpellInfo"] = [[ function GetSpellInfo(spell) if type(spell) == "number" then spell = string.format("Spell Name of %d", spell) end return spell end ]] WoWMock.mock["GetSpellTabInfo"] = [[ function GetSpellTabInfo(index) -- No spells in the spellbook. return nil end ]] WoWMock.mock["GetTalentInfo"] = [[ function GetTalentInfo(row, column, activeTalentGroup) -- No talents. return 123, "A Talent", nil, 0, nil end ]] WoWMock.mock["GetTime"] = [[ function GetTime() return 1234 end ]] WoWMock.mock["HasPetSpells"] = [[ function HasPetSpells() -- No pet spells. return false end ]] WoWMock.mock["RegisterAddonMessagePrefix"] = DoNothing WoWMock.mock["RegisterStateDriver"] = DoNothing WoWMock.UnitAura = function(unitId) -- No auras on any unit. return nil end WoWMock.mock["UnitClass"] = [[ function UnitClass() local class = WOWMOCK_CONFIG.class or "DEATHKNIGHT" return class, class end ]] WoWMock.mock["UnitGUID"] = [[ function UnitGUID(unitId) local guid = WOWMOCK_CONFIG.guid or 0 return guid end ]] WoWMock.mock["UnitLevel"] = [[ function UnitLevel() local level = WOWMOCK_CONFIG.level or 100 return level end ]] WoWMock.mock["UnitName"] = [[ function UnitName() local name = WOWMOCK_CONFIG.name or "AwesomePlayer" return name end ]] WoWMock.mock["UnitPower"] = [[ function UnitPower(unitId, powerType) -- Always no resources on any unit. return 0 end ]] WoWMock.mock["UnitPowerMax"] = [[ function UnitPowerMax(unitId, powerType) -- Resources are from 0 to 100. return 100 end ]] WoWMock.mock["UnitPowerType"] = [[ function UnitPowerType(unitId) -- Every unit is a mana user. return WoWMock.SPELL_POWER_MANA, "MANA" end ]] -- Unit stat functions for a naked toon. WoWMock.GetCombatRating = ZeroFunction WoWMock.GetCritChance = ZeroFunction WoWMock.GetMastery = ZeroFunction WoWMock.GetMasteryEffect = ZeroFunction WoWMock.GetMeleeHaste = ZeroFunction WoWMock.GetRangedCritChance = ZeroFunction WoWMock.GetRangedHaste = ZeroFunction WoWMock.GetSpellBonusDamage = ZeroFunction WoWMock.GetSpellBonusHealing = ZeroFunction WoWMock.GetSpellCritChance = ZeroFunction WoWMock.UnitAttackPower = function(unitId) return 0, 0, 0 end WoWMock.UnitAttackSpeed = function(unitId) return 0, 0 end WoWMock.UnitDamage = function(unitId) return 0, 0, 0, 0, 0, 0, 0 end WoWMock.UnitRangedAttackPower = WoWMock.UnitAttackPower WoWMock.UnitSpellHaste = ZeroFunction WoWMock.UnitStat = ZeroFunction WoWMock.bit = { band = DoNothing, bor = DoNothing, } WoWMock.LibStub = LibStub --</public-static-properties> --<private-static-methods> local function FileExists(filename, directory, verbose) if directory then filename = directory .. filename end local fh = io.open(filename, "r") if fh then fh:close() return true else if verbose then print(string.format("Warning: '%s' not found.", filename)) end return false end end --</private-static-methods> --<public-static-methods> -- Create a new sandbox environment. function WoWMock:NewSandbox(config, mock) mock = mock or {} local sandbox = DeepCopy(mock) -- Save configuration to sandbox as "WOWMOCK_CONFIG" property. config = config or {} local WOWMOCK_CONFIG = DeepCopy(config) sandbox.WOWMOCK_CONFIG = WOWMOCK_CONFIG -- Redirect all direct references into _G into the sandbox instead. sandbox._G = sandbox -- Any missing symbols in the sandbox are inherited from the global environment. setmetatable(sandbox, { __index = _G }) -- Export all of the WoWMock symbols into the sandbox, taking care not to -- overwrite explicitly defined mocks. for key, value in pairs(self) do if key == "NewSandbox" then -- skip elseif key == "mock" then for k, v in pairs(value) do if not rawget(sandbox, k) then if type(v) == "string" then --print("Loading symbol (loadstring)", k) local func = loadstring(v) setfenv(func, sandbox) func() elseif type(v) == "function" then --print("Loading symbol (function)", k) sandbox[k] = v end end end else --print("Loading symbol (direct)", key) if not rawget(sandbox, key) then sandbox[key] = DeepCopy(value) end end end -- Sandbox configuration defaults. if not WOWMOCK_CONFIG.addonName then sandbox:SetAddonName("Addon Name") end return sandbox end -- Set the name of the addon for all files. function WoWMock:SetAddonName(name) self.WOWMOCK_CONFIG.addonName = name end -- Execute the given function within the sandbox environment. function WoWMock:Execute(func) setfenv(func, self) return func() end -- Fire an event in the sandbox. function WoWMock:Fire(event) local lib = self.LibStub("AceAddon-3.0") if lib then lib.Fire(event) end end --[[-------------------------------------------------------------------- LoadAddOnFile() dispatches to the proper method to load the file based on the file extension. --]]-------------------------------------------------------------------- function WoWMock:LoadAddonFile(filename, directory, verbose) local s = directory and (directory .. filename) or filename directory, filename = string.match(s, "^(.+/)([^/]+[.][%w]+)$") if not directory then filename = s end if string.find(filename, "[.]lua$") then return self:LoadLua(filename, directory, verbose) elseif string.find(filename, "[.]toc$") then return self:LoadTOC(filename, directory, verbose) elseif string.find(filename, "[.]xml$") then return self:LoadXML(filename, directory, verbose) end end --[[-------------------------------------------------------------------- LoadAddonFile() does the equivalent of dofile(), but munges the WoW addon file line that uses ... to get the file arguments. --]]-------------------------------------------------------------------- function WoWMock:LoadLua(filename, directory, verbose) if directory then filename = directory .. filename end if verbose then print(string.format("Loading Lua: %s", filename)) end local ok = FileExists(filename, nil, verbose) if ok then local list = {} for line in io.lines(filename) do local varName = string.match(line, "^local%s+([%w_]+)%s*,[%w%s_,]*=%s*[.][.][.]%s*$") if varName then line = string.format("local %s = %q", varName, self.WOWMOCK_CONFIG.addonName) end table.insert(list, line) end local fileString = table.concat(list, "\n") local func = loadstring(fileString) if func then setfenv(func, self) func() else print(string.format("Error loading '%s'.", filename)) ok = false end end return ok end --[[-------------------------------------------------------------------- LoadTOC() loads all of the addon's files listed in the TOC file. --]]-------------------------------------------------------------------- function WoWMock:LoadTOC(filename, directory, verbose) local addonName = string.sub(filename, 1, -5) if directory then filename = directory .. filename end if verbose then print(string.format("Loading TOC: %s", filename)) end local ok = FileExists(filename, nil, verbose) if ok then -- Set the addon name from the name of the TOC file. self:SetAddonName(addonName) local list = {} for line in io.lines(filename) do line = string.gsub(line, "\\", "/") local t = {} t.directory, t.file = string.match(line, "^([^#]+/)([^/]+[.][%w]+)$") if t.directory then if directory then t.directory = directory .. t.directory end else t.directory = directory t.file = string.match(line, "^[%w_]+[.][%w]+$") end if t.file then table.insert(list, t) end end for _, t in ipairs(list) do if string.find(t.file, "[.]lua$") then ok = ok and self:LoadLua(t.file, t.directory, verbose) elseif string.find(t.file, "[.]xml$") then ok = ok and self:LoadXML(t.file, t.directory, verbose) end if not ok then break end end end return ok end --[[-------------------------------------------------------------------- LoadXML() loads all of the addon's Lua files listed in the XML file. --]]-------------------------------------------------------------------- function WoWMock:LoadXML(filename, directory, verbose) if directory then filename = directory .. filename end if verbose then print(string.format("Loading XML: %s", filename)) end local ok = FileExists(filename, nil, verbose) if ok then local list = {} for line in io.lines(filename) do local s = string.match(line, '<Script[%s]+file="([^"]+)"') if s then s = string.gsub(s, "\\", "/") local t = {} t.directory, t.file = string.match(s, "^(.+/)([^/]+[.][%w]+)$") if t.directory then if directory then t.directory = directory .. t.directory end else t.directory = directory t.file = s end if t.file then table.insert(list, t) end end end for _, t in ipairs(list) do if FileExists(t.file, t.directory, verbose) then if string.find(t.file, "[.]lua$") then ok = ok and self:LoadLua(t.file, t.directory, verbose) if not ok then break end end end end end return ok end --</public-static-methods>