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.
 
 
 
 
 
 

120 lines
3.0 KiB

#include <gtest/gtest.h>
#include <random>
#include "engine/random.hpp"
#include "items.h"
#include "player.h"
#include "spells.h"
#include "utils/str_cat.hpp"
namespace devilution {
namespace {
class ItemsTest : public ::testing::Test {
public:
void SetUp() override
{
Players.resize(1);
MyPlayer = &Players[0];
for (auto &flag : UniqueItemFlags)
flag = false;
}
static void SetUpTestSuite()
{
LoadItemData();
LoadSpellData();
gbIsSpawn = false;
gbIsMultiplayer = false; // to also test UniqueItemFlags
}
};
void GenerateAllUniques(bool hellfire, const size_t expectedUniques)
{
gbIsHellfire = hellfire;
std::mt19937 betterRng;
std::uniform_int_distribution<uint32_t> dist(0, std::numeric_limits<uint32_t>::max());
// Get seed for test run from time. If a test run fails, remember the seed and hardcode it here.
uint32_t testRunSeed = static_cast<uint32_t>(time(nullptr));
betterRng.seed(testRunSeed);
std::set<int> foundUniques;
constexpr int max_iterations = 1000000;
int iteration = 0;
for (int uniqueIndex = 0, n = static_cast<int>(UniqueItems.size()); uniqueIndex < n; ++uniqueIndex) {
if (!IsUniqueAvailable(uniqueIndex))
continue;
if (foundUniques.contains(uniqueIndex))
continue;
auto &uniqueItem = UniqueItems[uniqueIndex];
_item_indexes uniqueBaseIndex = IDI_GOLD;
for (std::underlying_type_t<_item_indexes> j = IDI_GOLD; j <= IDI_LAST; j++) {
if (!IsItemAvailable(j))
continue;
if (AllItemsList[j].iItemId != uniqueItem.UIItemId)
continue;
if (AllItemsList[j].dropRate > 0)
uniqueBaseIndex = static_cast<_item_indexes>(j);
break;
}
if (uniqueBaseIndex == IDI_GOLD)
continue; // Unique not dropable (Quest-Unique)
auto &baseItemData = AllItemsList[static_cast<size_t>(uniqueBaseIndex)];
while (true) {
iteration += 1;
if (iteration > max_iterations)
FAIL() << StrCat("Item ", uniqueItem.UIName, " not found in ", max_iterations, " tries with test run seed ", testRunSeed);
Item testItem = {};
testItem._iMiscId = baseItemData.iMiscId;
std::uniform_int_distribution<int32_t> dist(0, INT_MAX);
SetRndSeed(dist(betterRng));
int targetLvl = uniqueItem.UIMinLvl;
int uper = 1;
if (uniqueItem.UIMinLvl - 4 > 0) {
uper = 15;
targetLvl = uniqueItem.UIMinLvl - 4;
}
SetupAllItems(*MyPlayer, testItem, uniqueBaseIndex, AdvanceRndSeed(), targetLvl, uper, true, false);
TryRandomUniqueItem(testItem, uniqueBaseIndex, targetLvl, uper, true, false);
SetupItem(testItem);
if (testItem._iMagical != ITEM_QUALITY_UNIQUE)
continue;
foundUniques.insert(testItem._iUid);
if (testItem._iUid == uniqueIndex)
break;
}
}
EXPECT_EQ(foundUniques.size(), expectedUniques) << StrCat("test run seed ", testRunSeed);
}
TEST_F(ItemsTest, AllDiabloUniquesCanDrop)
{
GenerateAllUniques(false, 79);
}
TEST_F(ItemsTest, AllHellfireUniquesCanDrop)
{
GenerateAllUniques(true, 99);
}
} // namespace
} // namespace devilution