diff options
author | Treeston <treeston.mmoc@gmail.com> | 2020-08-31 16:56:56 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-08-31 16:56:56 +0200 |
commit | 5394b2ef0f1c7b48e8886257b93698358abb575f (patch) | |
tree | fa864bdefed2097131158b6dd548a9c809c21f62 | |
parent | 1e8cb1ed1f374e5aaaafad7b6c283000bce8aaee (diff) |
UnitTests: Add a first set of item hyperlink tests
-rw-r--r-- | src/server/game/Chat/Hyperlinks.cpp | 14 | ||||
-rw-r--r-- | src/server/game/Chat/Hyperlinks.h | 2 | ||||
-rw-r--r-- | src/server/game/Entities/Item/ItemTemplate.h | 38 | ||||
-rw-r--r-- | src/server/game/Globals/ObjectMgr.h | 14 | ||||
-rw-r--r-- | tests/DummyData.cpp | 129 | ||||
-rw-r--r-- | tests/DummyData.h | 38 | ||||
-rw-r--r-- | tests/game/Hyperlinks.cpp | 59 |
7 files changed, 253 insertions, 41 deletions
diff --git a/src/server/game/Chat/Hyperlinks.cpp b/src/server/game/Chat/Hyperlinks.cpp index 6bc47c8416f..308ec33d46d 100644 --- a/src/server/game/Chat/Hyperlinks.cpp +++ b/src/server/game/Chat/Hyperlinks.cpp @@ -152,7 +152,7 @@ struct LinkValidator<LinkTags::item> { if (!locale && i != DEFAULT_LOCALE) continue; - std::string const& name = (i == DEFAULT_LOCALE) ? data.Item->Name1 : locale->Name[i]; + std::string_view name = (i == DEFAULT_LOCALE) ? data.Item->Name1 : ObjectMgr::GetLocaleString(locale->Name, i); if (name.empty()) continue; if (randomSuffixes) @@ -184,15 +184,17 @@ struct LinkValidator<LinkTags::quest> static bool IsTextValid(QuestLinkData const& data, std::string_view text) { QuestLocale const* locale = sObjectMgr->GetQuestLocale(data.Quest->GetQuestId()); - if (!locale) - return text == data.Quest->GetTitle(); + + if (text == data.Quest->GetTitle()) + return true; for (uint8 i = 0; i < TOTAL_LOCALES; ++i) { - std::string const& name = (i == DEFAULT_LOCALE) ? data.Quest->GetTitle() : locale->Title[i]; - if (name.empty()) + if (i == DEFAULT_LOCALE) continue; - if (text == name) + + std::string_view name = ObjectMgr::GetLocaleString(locale->Title, i); + if (!name.empty() && (text == name)) return true; } diff --git a/src/server/game/Chat/Hyperlinks.h b/src/server/game/Chat/Hyperlinks.h index 5b39cfc7906..69bfdb28ff0 100644 --- a/src/server/game/Chat/Hyperlinks.h +++ b/src/server/game/Chat/Hyperlinks.h @@ -95,7 +95,7 @@ namespace Trinity::Hyperlinks |* - this method SHOULD be constexpr *| |* - returns identifier string for the link ("creature", "creature_entry", "item") *| |* - MUST expose static ::StoreTo method, (storage&, std::string_view) *| - |* - assign value_type& based on content of std::string_view *| + |* - assign storage& based on content of std::string_view *| |* - return value indicates success/failure *| |* - for integral/string types this can be achieved by extending base_tag *| \****************************************************************************************/ diff --git a/src/server/game/Entities/Item/ItemTemplate.h b/src/server/game/Entities/Item/ItemTemplate.h index e08a04d0063..cba6604fe6a 100644 --- a/src/server/game/Entities/Item/ItemTemplate.h +++ b/src/server/game/Entities/Item/ItemTemplate.h @@ -563,31 +563,31 @@ const uint32 MaxItemSubclassValues[MAX_ITEM_CLASS] = struct _Damage { - float DamageMin; - float DamageMax; - uint32 DamageType; // id from Resistances.dbc + float DamageMin = 0.0f; + float DamageMax = 0.0f; + uint32 DamageType = 0; // id from Resistances.dbc }; struct _ItemStat { - uint32 ItemStatType; - int32 ItemStatValue; + uint32 ItemStatType = 0; + int32 ItemStatValue = 0; }; struct _Spell { - int32 SpellId; // id from Spell.dbc - uint32 SpellTrigger; - int32 SpellCharges; - float SpellPPMRate; - int32 SpellCooldown; - uint32 SpellCategory; // id from SpellCategory.dbc - int32 SpellCategoryCooldown; + int32 SpellId = 0; // id from Spell.dbc + uint32 SpellTrigger = 0; + int32 SpellCharges = 0; + float SpellPPMRate = 0.0f; + int32 SpellCooldown = -1; + uint32 SpellCategory = 0; // id from SpellCategory.dbc + int32 SpellCategoryCooldown = -1; }; struct _Socket { - uint32 Color; - uint32 Content; + uint32 Color = 0; + uint32 Content = 0; }; #pragma pack(pop) @@ -629,10 +629,10 @@ struct ItemTemplate int32 Stackable; // 0: not allowed, -1: put in player coin info tab and don't limit stacking (so 1 slot) uint32 ContainerSlots; uint32 StatsCount; - _ItemStat ItemStat[MAX_ITEM_PROTO_STATS]; + std::array<_ItemStat, MAX_ITEM_PROTO_STATS> ItemStat; uint32 ScalingStatDistribution; // id from ScalingStatDistribution.dbc uint32 ScalingStatValue; // mask for selecting column in ScalingStatValues.dbc - _Damage Damage[MAX_ITEM_PROTO_DAMAGES]; + std::array<_Damage, MAX_ITEM_PROTO_DAMAGES> Damage; uint32 Armor; uint32 HolyRes; uint32 FireRes; @@ -643,7 +643,7 @@ struct ItemTemplate uint32 Delay; uint32 AmmoType; float RangedModRange; - _Spell Spells[MAX_ITEM_PROTO_SPELLS]; + std::array<_Spell, MAX_ITEM_PROTO_SPELLS> Spells; uint32 Bonding; std::string Description; uint32 PageText; @@ -662,7 +662,7 @@ struct ItemTemplate uint32 Map; // id from Map.dbc uint32 BagFamily; // bit mask (1 << id from ItemBagFamily.dbc) uint32 TotemCategory; // id from TotemCategory.dbc - _Socket Socket[MAX_ITEM_PROTO_SOCKETS]; + std::array<_Socket, MAX_ITEM_PROTO_SOCKETS> Socket; uint32 socketBonus; // id from SpellItemEnchantment.dbc uint32 GemProperties; // id from GemProperties.dbc uint32 RequiredDisenchantSkill; @@ -676,7 +676,7 @@ struct ItemTemplate uint32 MinMoneyLoot; uint32 MaxMoneyLoot; uint32 FlagsCu; - WorldPacket QueryData[TOTAL_LOCALES]; + std::array<WorldPacket, TOTAL_LOCALES> QueryData; // helpers bool CanChangeEquipStateInCombat() const; diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index ca3fa6eab32..43eb008f2f2 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -940,6 +940,7 @@ class PlayerDumpReader; class TC_GAME_API ObjectMgr { friend class PlayerDumpReader; + friend class UnitTestDataLoader; private: ObjectMgr(); @@ -1535,10 +1536,17 @@ class TC_GAME_API ObjectMgr GraveyardContainer GraveyardStore; static void AddLocaleString(std::string&& value, LocaleConstant localeConstant, std::vector<std::string>& data); - static inline void GetLocaleString(std::vector<std::string> const& data, LocaleConstant localeConstant, std::string& value) + static std::string_view GetLocaleString(std::vector<std::string> const& data, size_t locale) { - if (data.size() > size_t(localeConstant) && !data[localeConstant].empty()) - value = data[localeConstant]; + if (locale < data.size()) + return data[locale]; + else + return {}; + } + static void GetLocaleString(std::vector<std::string> const& data, LocaleConstant localeConstant, std::string& value) + { + if (std::string_view str = GetLocaleString(data, static_cast<size_t>(localeConstant)); !str.empty()) + value.assign(str); } CharacterConversionMap FactionChangeAchievements; diff --git a/tests/DummyData.cpp b/tests/DummyData.cpp new file mode 100644 index 00000000000..916edb0accd --- /dev/null +++ b/tests/DummyData.cpp @@ -0,0 +1,129 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "DummyData.h" + +#include "ItemDefines.h" +#include "ItemTemplate.h" +#include "ObjectMgr.h" + +/*static*/ ItemTemplate& UnitTestDataLoader::GetItemTemplate(uint32 itemId, std::string_view name) +{ + ItemTemplate& t = sObjectMgr->_itemTemplateStore[itemId]; + t.ItemId = itemId; + t.Class = ItemClass::ITEM_CLASS_MISC; + t.SubClass = 0; + t.SoundOverrideSubclass = 0; + t.Name1 = name; + t.DisplayInfoID = 0; + t.Quality = ItemQualities::ITEM_QUALITY_ARTIFACT; + t.Flags = 0; + t.Flags2 = 0; + t.BuyCount = 1; + t.BuyPrice = 0; + t.SellPrice = 0; + t.InventoryType = InventoryType::INVTYPE_NON_EQUIP; + t.AllowableClass = static_cast<uint32>(-1); + t.AllowableRace = static_cast<uint32>(-1); + t.ItemLevel = 1; + t.RequiredLevel = 0; + t.RequiredSkill = 0; + t.RequiredSkillRank = 0; + t.RequiredSpell = 0; + t.RequiredHonorRank = 0; + t.RequiredCityRank = 0; + t.RequiredReputationFaction = 0; + t.RequiredReputationRank = 0; + t.MaxCount = 0; + t.Stackable = 1; + t.ContainerSlots = 0; + t.StatsCount = 0; + t.ItemStat = {}; + t.ScalingStatDistribution = 0; + t.ScalingStatValue = 0; + t.Damage = {}; + t.Armor = 0; + t.HolyRes = 0; + t.FireRes = 0; + t.NatureRes = 0; + t.FrostRes = 0; + t.ShadowRes = 0; + t.ArcaneRes = 0; + t.Delay = 0; + t.AmmoType = 0; + t.RangedModRange = 0.0f; + t.Spells = {}; + t.Bonding = ItemBondingType::NO_BIND; + t.Description = ""; + t.PageText = 0; + t.LanguageID = 0; + t.PageMaterial = 0; + t.StartQuest = 0; + t.LockID = 0; + t.Material = static_cast<uint32>(-1); + t.Sheath = 0; + t.RandomProperty = 0; + t.RandomSuffix = 0; + t.Block = 0; + t.ItemSet = 0; + t.MaxDurability = 0; + t.Area = 0; + t.Map = 0; + t.BagFamily = 0; + t.TotemCategory = 0; + t.Socket = {}; + t.socketBonus = 0; + t.GemProperties = 0; + t.RequiredDisenchantSkill = static_cast<uint32>(-1); + t.ArmorDamageModifier = 0.0; + t.Duration = 0; + t.ItemLevel = 0; + t.HolidayId = 0; + t.ScriptId = 0; + t.DisenchantID = 0; + t.FoodType = 0; + t.MinMoneyLoot = 0; + t.MaxMoneyLoot = 0; + + return t; +} + +/*static*/ void UnitTestDataLoader::SetItemLocale(uint32 id, LocaleConstant locale, std::string_view name) +{ + size_t const i = static_cast<size_t>(locale); + ItemLocale& localeData = sObjectMgr->_itemLocaleStore[id]; + if (localeData.Name.size() <= i) + localeData.Name.resize(i + 1); + localeData.Name[i] = name; +} + +/*static*/ void UnitTestDataLoader::LoadItemTemplates() +{ + if (!sObjectMgr->_itemTemplateStore.empty()) + return; + + ItemTemplate& hearthstone = GetItemTemplate(6948, "Hearthstone"); + hearthstone.SoundOverrideSubclass = -1; + hearthstone.DisplayInfoID = 6418; + hearthstone.Quality = ItemQualities::ITEM_QUALITY_NORMAL; + hearthstone.Flags = ItemFlags::ITEM_FLAG_PLAYERCAST; + hearthstone.MaxCount = 1; + hearthstone.Spells[0].SpellId = 8690; + hearthstone.Bonding = ItemBondingType::BIND_WHEN_PICKED_UP; + + SetItemLocale(6948, LocaleConstant::LOCALE_esMX, "Piedra de hogar"); +} diff --git a/tests/DummyData.h b/tests/DummyData.h new file mode 100644 index 00000000000..98812d3b6b8 --- /dev/null +++ b/tests/DummyData.h @@ -0,0 +1,38 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef TRINITY_DUMMYDATA_H +#define TRINITY_DUMMYDATA_H + +#include "Common.h" +#include "Define.h" + +#include <string_view> + +struct ItemTemplate; + +class UnitTestDataLoader +{ + public: + static void LoadItemTemplates(); + + private: + static ItemTemplate& GetItemTemplate(uint32 id, std::string_view name); + static void SetItemLocale(uint32 id, LocaleConstant locale, std::string_view name); +}; + +#endif diff --git a/tests/game/Hyperlinks.cpp b/tests/game/Hyperlinks.cpp index ff9062af905..e7ac5287f74 100644 --- a/tests/game/Hyperlinks.cpp +++ b/tests/game/Hyperlinks.cpp @@ -17,23 +17,58 @@ #include "tc_catch2.h" +#include "DummyData.h" #include "Hyperlinks.h" -#include "ChatCommand.h" +#include "World.h" using namespace std::string_view_literals; using namespace Trinity::Hyperlinks; TEST_CASE("Basic link structure", "[Hyperlinks]") { - HyperlinkInfo info = ParseSingleHyperlink("|c12345678|Htag:data1:data2:data3:data4:data5|h[Text]|h|rtail"); - REQUIRE(info.ok); - REQUIRE(info.color == 0x12345678); - REQUIRE(info.color.a == 0x12); - REQUIRE(info.color.r == 0x34); - REQUIRE(info.color.g == 0x56); - REQUIRE(info.color.b == 0x78); - REQUIRE(info.tag == "tag"); - REQUIRE(info.data == "data1:data2:data3:data4:data5"); - REQUIRE(info.text == "Text"); - REQUIRE(info.tail == "tail"); + SECTION("Link without data") + { + HyperlinkInfo info = ParseSingleHyperlink("|cabcdef01|HTag|h[text]|h|r"); + REQUIRE(info.ok); + REQUIRE(info.color == 0xabcdef01); + REQUIRE(info.color.a == 0xab); + REQUIRE(info.color.r == 0xcd); + REQUIRE(info.color.g == 0xef); + REQUIRE(info.color.b == 0x01); + REQUIRE(info.tag == "Tag"); + REQUIRE(info.data == ""); + REQUIRE(info.text == "text"); + REQUIRE(info.tail == ""); + } + SECTION("Link with data") + { + HyperlinkInfo info = ParseSingleHyperlink("|c12345678|Htag:data1:data2:data3:data4:data5|h[Text]|h|rtail"); + REQUIRE(info.ok); + REQUIRE(info.color == 0x12345678); + REQUIRE(info.color.a == 0x12); + REQUIRE(info.color.r == 0x34); + REQUIRE(info.color.g == 0x56); + REQUIRE(info.color.b == 0x78); + REQUIRE(info.tag == "tag"); + REQUIRE(info.data == "data1:data2:data3:data4:data5"); + REQUIRE(info.text == "Text"); + REQUIRE(info.tail == "tail"); + } +} + +TEST_CASE("|Hitem validation", "[Hyperlinks]") +{ + UnitTestDataLoader::LoadItemTemplates(); + sWorld->setIntConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_SEVERITY, 1); + + SECTION("Basic item link") + { + REQUIRE(true == CheckAllLinks("This is my |cffffffff|Hitem:6948:0:0:0:0:0:0:0:80|h[Hearthstone]|h|r. There are many like it, but this one is mine.")); + REQUIRE(true == CheckAllLinks("Some might call it their |cffffffff|Hitem:6948:0:0:0:0:0:0:0:80|h[Piedra de hogar]|h|r. They all still take you home.")); + REQUIRE(false == CheckAllLinks("However, if you call it a |cffffffff|Hitem:6948:0:0:0:0:0:0:0:80|h[Doormat]|h|r, that's a step too far. Get it? Step?")); + REQUIRE(false == CheckAllLinks("Or if you try to pronounce |cffffffff|Hitem:0:0:0:0:0:0:0:0:80|h[Cthulhu fhtagn]|h|r. Also too far.")); + REQUIRE(false == CheckAllLinks("I'm out of witty one-liners. |cffffffff|Hitem|h[This]|h|r is just lacking data.")); + REQUIRE(false == CheckAllLinks("This is a mis-colored |cffa335ee|Hitem:6948:0:0:0:0:0:0:0:80|h[Hearthstone]|h|r.")); + REQUIRE(false == CheckAllLinks("This is a |cffffffff|Hitem:6948:-1:0:0:0:0:0:0:-1|h[Hearthstone]|h|r that is quite negative.")); + } } |