From 4bc881da4bf51b3c4bb1d078a278f9127ef288e5 Mon Sep 17 00:00:00 2001 From: Chris Miles Date: Tue, 4 Mar 2025 17:15:27 -0600 Subject: [PATCH] [Tests] Cleanup Hand-in Tests (#4749) --- zone/cli/databuckets.cpp | 2 +- zone/cli/npc_handins.cpp | 251 ++++++++++++++++------------ zone/cli/npc_handins_multiquest.cpp | 98 +++-------- 3 files changed, 169 insertions(+), 182 deletions(-) diff --git a/zone/cli/databuckets.cpp b/zone/cli/databuckets.cpp index f90b981ca..e0656c5de 100644 --- a/zone/cli/databuckets.cpp +++ b/zone/cli/databuckets.cpp @@ -40,7 +40,7 @@ void ZoneCLI::DataBuckets(int argc, char **argv, argh::parser &cmd, std::string LogSys.EnableConsoleLogging(); std::cout << "===========================================\n"; - std::cout << "Running DataBuckets Tests...\n"; + std::cout << "⚙\uFE0F> Running DataBuckets Tests...\n"; std::cout << "===========================================\n\n"; Client *client = new Client(); diff --git a/zone/cli/npc_handins.cpp b/zone/cli/npc_handins.cpp index 0bab7076c..636d69484 100644 --- a/zone/cli/npc_handins.cpp +++ b/zone/cli/npc_handins.cpp @@ -4,8 +4,76 @@ #include "../zone.h" #include "../client.h" #include "../../common/net/eqstream.h" +#include "../../common/json/json.hpp" extern Zone *zone; +using json = nlohmann::json; + +struct HandinEntry { + std::string item_id = "0"; + uint32 count = 0; + const EQ::ItemInstance *item = nullptr; + bool is_multiquest_item = false; // state +}; + +struct HandinMoney { + uint32 platinum = 0; + uint32 gold = 0; + uint32 silver = 0; + uint32 copper = 0; +}; + +struct Handin { + std::vector items = {}; // items can be removed from this set as successful handins are made + HandinMoney money = {}; // money can be removed from this set as successful handins are made +}; + +struct TestCase { + std::string description; + Handin hand_in; + Handin required; + Handin returned; + bool handin_check_result; +}; + +void RunTest(const std::string &test_name, bool expected, bool actual) +{ + if (expected == actual) { + std::cout << "[✅] " << test_name << " PASSED\n"; + } + else { + std::cerr << "[❌] " << test_name << " FAILED\n"; + std::cerr << " 📌 Expected: " << (expected ? "true" : "false") << "\n"; + std::cerr << " ❌ Got: " << (actual ? "true" : "false") << "\n"; + std::exit(1); + } +} + +void RunSerializedTest(const std::string &test_name, const std::string &expected, const std::string &actual) +{ + if (expected == actual) { + std::cout << "[✅] " << test_name << " PASSED\n"; + } + else { + std::cerr << "[❌] " << test_name << " FAILED\n"; + std::cerr << " 📌 Expected: " << expected << "\n"; + std::cerr << " ❌ Got: " << actual << "\n"; + std::exit(1); + } +} + +std::string SerializeHandin(const std::map &items, const HandinMoney &money) +{ + json j; + j["items"] = items; + j["money"] = { + {"platinum", money.platinum}, + {"gold", money.gold}, + {"silver", money.silver}, + {"copper", money.copper} + }; + return j.dump(); +} void ZoneCLI::NpcHandins(int argc, char **argv, argh::parser &cmd, std::string &description) { @@ -13,15 +81,6 @@ void ZoneCLI::NpcHandins(int argc, char **argv, argh::parser &cmd, std::string & return; } - uint32 break_length = 50; - int failed_count = 0; - - RegisterExecutablePlatform(EQEmuExePlatform::ExePlatformZoneSidecar); - - LogInfo("{}", Strings::Repeat("-", break_length)); - LogInfo("Booting test zone for NPC handins"); - LogInfo("{}", Strings::Repeat("-", break_length)); - LogSys.SilenceConsoleLogging(); Zone::Bootup(ZoneID("qrg"), 0, false); @@ -30,9 +89,9 @@ void ZoneCLI::NpcHandins(int argc, char **argv, argh::parser &cmd, std::string & entity_list.Process(); entity_list.MobProcess(); - LogInfo("{}", Strings::Repeat("-", break_length)); - LogInfo("> Done booting test zone"); - LogInfo("{}", Strings::Repeat("-", break_length)); + std::cout << "===========================================\n"; + std::cout << "⚙\uFE0F> Running Hand-in Tests...\n"; + std::cout << "===========================================\n\n"; Client *c = new Client(); auto npc_type = content_db.LoadNPCTypesData(754008); @@ -46,36 +105,6 @@ void ZoneCLI::NpcHandins(int argc, char **argv, argh::parser &cmd, std::string & entity_list.AddNPC(npc); - LogInfo("> Spawned NPC [{}]", npc->GetCleanName()); - LogInfo("> Spawned client [{}]", c->GetCleanName()); - - struct HandinEntry { - std::string item_id = "0"; - uint32 count = 0; - const EQ::ItemInstance *item = nullptr; - bool is_multiquest_item = false; // state - }; - - struct HandinMoney { - uint32 platinum = 0; - uint32 gold = 0; - uint32 silver = 0; - uint32 copper = 0; - }; - - struct Handin { - std::vector items = {}; // items can be removed from this set as successful handins are made - HandinMoney money = {}; // money can be removed from this set as successful handins are made - }; - - struct TestCase { - std::string description = ""; - Handin hand_in; - Handin required; - Handin returned; - bool handin_check_result; - }; - std::vector test_cases = { TestCase{ .description = "Test basic cloth-cap hand-in", @@ -155,7 +184,10 @@ void ZoneCLI::NpcHandins(int argc, char **argv, argh::parser &cmd, std::string & .items = {}, .money = {.platinum = 100}, }, - .returned = {}, + .returned = { + .items = {}, + .money = {.platinum = 1}, + }, .handin_check_result = false, }, TestCase{ @@ -168,7 +200,10 @@ void ZoneCLI::NpcHandins(int argc, char **argv, argh::parser &cmd, std::string & .items = {}, .money = {.platinum = 100, .gold = 100, .silver = 100, .copper = 100}, }, - .returned = {}, + .returned = { + .items = {}, + .money = {.platinum = 1, .gold = 1, .silver = 1, .copper = 1}, + }, .handin_check_result = false, }, TestCase{ @@ -217,8 +252,11 @@ void ZoneCLI::NpcHandins(int argc, char **argv, argh::parser &cmd, std::string & }, .returned = { .items = { - HandinEntry{.item_id = "1001", .count = 1}, + HandinEntry{ + .item_id = "1001", .count = 0, + }, }, + .money = {.platinum = 1}, }, .handin_check_result = false, }, @@ -304,12 +342,7 @@ void ZoneCLI::NpcHandins(int argc, char **argv, argh::parser &cmd, std::string & HandinEntry{.item_id = "1007", .count = 1}, HandinEntry{.item_id = "1007", .count = 1}, }, - .money = { - .platinum = 1, - .gold = 666, - .silver = 234, - .copper = 444, - }, + .money = {}, }, .handin_check_result = true, }, @@ -402,8 +435,8 @@ void ZoneCLI::NpcHandins(int argc, char **argv, argh::parser &cmd, std::string & }, }; - std::map hand_ins; - std::map required; + std::map hand_ins; + std::map required; std::vector items; LogSys.EnableConsoleLogging(); @@ -411,14 +444,12 @@ void ZoneCLI::NpcHandins(int argc, char **argv, argh::parser &cmd, std::string & // turn this on to see debugging output LogSys.log_settings[Logs::NpcHandin].log_to_console = std::getenv("DEBUG") ? 3 : 0; - LogInfo("{}", Strings::Repeat("-", break_length)); - - for (auto &test_case: test_cases) { + for (auto &test: test_cases) { hand_ins.clear(); required.clear(); items.clear(); - for (auto &hand_in: test_case.hand_in.items) { + for (auto &hand_in: test.hand_in.items) { auto item_id = Strings::ToInt(hand_in.item_id); EQ::ItemInstance *inst = database.CreateItem(item_id); if (inst->IsStackable()) { @@ -434,72 +465,76 @@ void ZoneCLI::NpcHandins(int argc, char **argv, argh::parser &cmd, std::string & } // money - if (test_case.hand_in.money.platinum > 0) { - hand_ins["platinum"] = test_case.hand_in.money.platinum; + if (test.hand_in.money.platinum > 0) { + hand_ins["platinum"] = test.hand_in.money.platinum; } - if (test_case.hand_in.money.gold > 0) { - hand_ins["gold"] = test_case.hand_in.money.gold; + if (test.hand_in.money.gold > 0) { + hand_ins["gold"] = test.hand_in.money.gold; } - if (test_case.hand_in.money.silver > 0) { - hand_ins["silver"] = test_case.hand_in.money.silver; + if (test.hand_in.money.silver > 0) { + hand_ins["silver"] = test.hand_in.money.silver; } - if (test_case.hand_in.money.copper > 0) { - hand_ins["copper"] = test_case.hand_in.money.copper; + if (test.hand_in.money.copper > 0) { + hand_ins["copper"] = test.hand_in.money.copper; } - for (auto &req: test_case.required.items) { + for (auto &req: test.required.items) { required[req.item_id] = req.count; } // money - if (test_case.required.money.platinum > 0) { - required["platinum"] = test_case.required.money.platinum; + if (test.required.money.platinum > 0) { + required["platinum"] = test.required.money.platinum; } - if (test_case.required.money.gold > 0) { - required["gold"] = test_case.required.money.gold; + if (test.required.money.gold > 0) { + required["gold"] = test.required.money.gold; } - if (test_case.required.money.silver > 0) { - required["silver"] = test_case.required.money.silver; + if (test.required.money.silver > 0) { + required["silver"] = test.required.money.silver; } - if (test_case.required.money.copper > 0) { - required["copper"] = test_case.required.money.copper; + if (test.required.money.copper > 0) { + required["copper"] = test.required.money.copper; } auto result = npc->CheckHandin(c, hand_ins, required, items); - if (result != test_case.handin_check_result) { - failed_count++; - LogError("FAIL [{}]", test_case.description); - // print out the hand-ins - LogError("Hand-ins >"); - for (auto &hand_in: hand_ins) { - LogError(" > Item [{}] count [{}]", hand_in.first, hand_in.second); - } - LogError("Required >"); - for (auto &req: required) { - LogError(" > Item [{}] count [{}]", req.first, req.second); - } - LogError("Expected [{}] got [{}]", test_case.handin_check_result, result); - } - else { - LogInfo("PASS [{}]", test_case.description); - } + + RunTest(test.description, test.handin_check_result, result); auto returned = npc->ReturnHandinItems(c); - // assert that returned items are expected - for (auto &item: test_case.returned.items) { - auto found = false; - for (auto &ret: returned.items) { - if (ret.item_id == item.item_id) { - found = true; - break; - } - } - if (!found) { - LogError("Returned item [{}] not expected", item.item_id); - } + std::map returned_items; + HandinMoney returned_money{}; + + // Serialize returned items + for (const auto &ret: returned.items) { +// if (ret.item->IsStackable() && ret.item->GetCharges() != ret.count) { +// ret.item->SetCharges(ret.count); +// } + returned_items[ret.item_id] += ret.count; } + // Serialize returned money + returned_money.platinum = returned.money.platinum; + returned_money.gold = returned.money.gold; + returned_money.silver = returned.money.silver; + returned_money.copper = returned.money.copper; + + // Serialize expected and actual return values for comparison + std::map expected_returned_items; + for (const auto &entry: test.returned.items) { + expected_returned_items[entry.item_id] += entry.count; + } + + std::string expected_serialized = SerializeHandin( + expected_returned_items, + test.returned.money + ); + + std::string actual_serialized = SerializeHandin(returned_items, returned_money); + + // Run serialization check test + RunSerializedTest(test.description + " (Return Validation)", expected_serialized, actual_serialized); + npc->ResetHandin(); if (LogSys.log_settings[Logs::NpcHandin].log_to_console > 0) { @@ -508,11 +543,7 @@ void ZoneCLI::NpcHandins(int argc, char **argv, argh::parser &cmd, std::string & } } - if (failed_count > 0) { - LogError("Failed [{}] tests", failed_count); - std::exit(1); - } - else { - LogInfo("All tests passed"); - } + std::cout << "\n===========================================\n"; + std::cout << "✅ All NPC Hand-in Tests Completed!\n"; + std::cout << "===========================================\n"; } diff --git a/zone/cli/npc_handins_multiquest.cpp b/zone/cli/npc_handins_multiquest.cpp index f579cca7e..3ea526da1 100644 --- a/zone/cli/npc_handins_multiquest.cpp +++ b/zone/cli/npc_handins_multiquest.cpp @@ -16,12 +16,6 @@ void ZoneCLI::NpcHandinsMultiQuest(int argc, char **argv, argh::parser &cmd, std uint32 break_length = 50; int failed_count = 0; - RegisterExecutablePlatform(EQEmuExePlatform::ExePlatformZoneSidecar); - - LogInfo("{}", Strings::Repeat("-", break_length)); - LogInfo("Booting test zone for NPC handins (MultiQuest)"); - LogInfo("{}", Strings::Repeat("-", break_length)); - LogSys.SilenceConsoleLogging(); Zone::Bootup(ZoneID("qrg"), 0, false); @@ -30,9 +24,9 @@ void ZoneCLI::NpcHandinsMultiQuest(int argc, char **argv, argh::parser &cmd, std entity_list.Process(); entity_list.MobProcess(); - LogInfo("{}", Strings::Repeat("-", break_length)); - LogInfo("> Done booting test zone"); - LogInfo("{}", Strings::Repeat("-", break_length)); + std::cout << "===========================================\n"; + std::cout << "⚙\uFE0F> Running Hand-in Tests (Multi-Quest)...\n"; + std::cout << "===========================================\n\n"; Client *c = new Client(); auto npc_type = content_db.LoadNPCTypesData(754008); @@ -47,9 +41,6 @@ void ZoneCLI::NpcHandinsMultiQuest(int argc, char **argv, argh::parser &cmd, std entity_list.AddNPC(npc); npc->MultiQuestEnable(); - LogInfo("> Spawned NPC [{}]", npc->GetCleanName()); - LogInfo("> Spawned client [{}]", c->GetCleanName()); - struct HandinEntry { std::string item_id = "0"; uint32 count = 0; @@ -108,12 +99,10 @@ void ZoneCLI::NpcHandinsMultiQuest(int argc, char **argv, argh::parser &cmd, std // turn this on to see debugging output LogSys.log_settings[Logs::NpcHandin].log_to_console = std::getenv("DEBUG") ? 3 : 0; - LogInfo("{}", Strings::Repeat("-", break_length)); - - for (auto &test_case: test_cases) { + for (auto &test: test_cases) { required.clear(); - for (auto &hand_in: test_case.hand_in.items) { + for (auto &hand_in: test.hand_in.items) { hand_ins.clear(); items.clear(); @@ -135,72 +124,43 @@ void ZoneCLI::NpcHandinsMultiQuest(int argc, char **argv, argh::parser &cmd, std } // money - if (test_case.hand_in.money.platinum > 0) { - hand_ins["platinum"] = test_case.hand_in.money.platinum; + if (test.hand_in.money.platinum > 0) { + hand_ins["platinum"] = test.hand_in.money.platinum; } - if (test_case.hand_in.money.gold > 0) { - hand_ins["gold"] = test_case.hand_in.money.gold; + if (test.hand_in.money.gold > 0) { + hand_ins["gold"] = test.hand_in.money.gold; } - if (test_case.hand_in.money.silver > 0) { - hand_ins["silver"] = test_case.hand_in.money.silver; + if (test.hand_in.money.silver > 0) { + hand_ins["silver"] = test.hand_in.money.silver; } - if (test_case.hand_in.money.copper > 0) { - hand_ins["copper"] = test_case.hand_in.money.copper; + if (test.hand_in.money.copper > 0) { + hand_ins["copper"] = test.hand_in.money.copper; } - for (auto &req: test_case.required.items) { + for (auto &req: test.required.items) { required[req.item_id] = req.count; } // money - if (test_case.required.money.platinum > 0) { - required["platinum"] = test_case.required.money.platinum; + if (test.required.money.platinum > 0) { + required["platinum"] = test.required.money.platinum; } - if (test_case.required.money.gold > 0) { - required["gold"] = test_case.required.money.gold; + if (test.required.money.gold > 0) { + required["gold"] = test.required.money.gold; } - if (test_case.required.money.silver > 0) { - required["silver"] = test_case.required.money.silver; + if (test.required.money.silver > 0) { + required["silver"] = test.required.money.silver; } - if (test_case.required.money.copper > 0) { - required["copper"] = test_case.required.money.copper; + if (test.required.money.copper > 0) { + required["copper"] = test.required.money.copper; } auto result = npc->CheckHandin(c, hand_ins, required, items); - if (result != test_case.handin_check_result) { - failed_count++; - LogError("FAIL [{}]", test_case.description); - // print out the hand-ins - LogError("Hand-ins >"); - for (auto &item: npc->GetHandin().items) { - LogError(" > Item [{}] count [{}]", item.item_id, item.count); - } - LogError("Required >"); - for (auto &req: required) { - LogError(" > Item [{}] count [{}]", req.first, req.second); - } - LogError("Expected [{}] got [{}]", test_case.handin_check_result, result); - } - else { - LogInfo("PASS [{}]", test_case.description); - } + + RunTest(test.description, test.handin_check_result, result); auto returned = npc->ReturnHandinItems(c); - // assert that returned items are expected - for (auto &item: test_case.returned.items) { - auto found = false; - for (auto &ret: returned.items) { - if (ret.item_id == item.item_id) { - found = true; - break; - } - } - if (!found) { - LogError("Returned item [{}] not expected", item.item_id); - } - } - npc->ResetHandin(); if (LogSys.log_settings[Logs::NpcHandin].log_to_console > 0) { @@ -209,11 +169,7 @@ void ZoneCLI::NpcHandinsMultiQuest(int argc, char **argv, argh::parser &cmd, std } } - if (failed_count > 0) { - LogError("Failed [{}] tests", failed_count); - std::exit(1); - } - else { - LogInfo("All tests passed"); - } + std::cout << "\n===========================================\n"; + std::cout << "✅ All NPC Hand-in Tests Completed (Multi-Quest)!\n"; + std::cout << "===========================================\n"; }