/* * 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 . */ #include "tc_catch2.h" #include "LuaEngineTestFixture.h" /** * @brief Phase 3 Tests: Complex Integration and Game Scenarios * * These tests verify complex multi-component scenarios */ TEST_CASE("Game Event Hooks - Event Handler Patterns", "[LuaEngine][LuaEngineIntegration]") { LuaEngineTestFixture fixture; Eluna* eluna = fixture.CreateGlobalElunaInstance(); REQUIRE(eluna != nullptr); SECTION("World update event pattern") { std::string script = R"( world_state = {tick = 0, updates = 0} function on_world_update(diff) world_state.tick = world_state.tick + diff world_state.updates = world_state.updates + 1 end on_world_update(100) on_world_update(100) on_world_update(100) )"; REQUIRE(fixture.ExecuteScript(eluna, script)); REQUIRE(fixture.GetGlobalAsInt(eluna, "world_state.tick") == 300); REQUIRE(fixture.GetGlobalAsInt(eluna, "world_state.updates") == 3); } SECTION("Player event pattern") { std::string script = R"( player_events = {} function on_player_login(player_id, player_name) table.insert(player_events, {event = 'login', id = player_id, name = player_name}) end on_player_login(1, 'Alice') on_player_login(2, 'Bob') event_count = #player_events )"; REQUIRE(fixture.ExecuteScript(eluna, script)); REQUIRE(fixture.GetGlobalAsInt(eluna, "event_count") == 2); } SECTION("Creature event pattern") { std::string script = R"( creature_events = {} function on_creature_spawn(creature_id, creature_name) table.insert(creature_events, {event = 'spawn', id = creature_id, name = creature_name}) end on_creature_spawn(100, 'Goblin') on_creature_spawn(101, 'Orc') event_count = #creature_events )"; REQUIRE(fixture.ExecuteScript(eluna, script)); REQUIRE(fixture.GetGlobalAsInt(eluna, "event_count") == 2); } } TEST_CASE("Query Processing - Query Pattern Simulation", "[LuaEngine][LuaEngineIntegration]") { LuaEngineTestFixture fixture; Eluna* eluna = fixture.CreateGlobalElunaInstance(); REQUIRE(eluna != nullptr); SECTION("Async query callback pattern") { std::string script = R"( query_results = {} function on_query_complete(query_id, result_data) table.insert(query_results, {id = query_id, data = result_data}) end function execute_query(query_id, query_string) local result = {rows = 5, status = 'success'} on_query_complete(query_id, result) end execute_query(1, 'SELECT * FROM players') execute_query(2, 'SELECT * FROM creatures') result_count = #query_results )"; REQUIRE(fixture.ExecuteScript(eluna, script)); REQUIRE(fixture.GetGlobalAsInt(eluna, "result_count") == 2); } SECTION("Query result processing") { std::string script = R"( processed_data = {} function process_query_result(query_result) local processed = {row_count = query_result.rows, success = query_result.status == 'success'} table.insert(processed_data, processed) end process_query_result({rows = 10, status = 'success'}) process_query_result({rows = 0, status = 'error'}) process_query_result({rows = 25, status = 'success'}) success_count = 0 for i, data in ipairs(processed_data) do if data.success then success_count = success_count + 1 end end )"; REQUIRE(fixture.ExecuteScript(eluna, script)); REQUIRE(fixture.GetGlobalAsInt(eluna, "success_count") == 2); } } TEST_CASE("Complex Scenarios - Multi-System Game World", "[LuaEngine][LuaEngineIntegration]") { LuaEngineTestFixture fixture; Eluna* eluna = fixture.CreateGlobalElunaInstance(); REQUIRE(eluna != nullptr); SECTION("Complete game world simulation") { std::string script = R"( world = {players = {}, creatures = {}, items = {}, events = {}} function add_player(id, name, level) table.insert(world.players, {id = id, name = name, level = level}) end function spawn_creature(id, name, health) table.insert(world.creatures, {id = id, name = name, health = health}) end function create_item(id, name, rarity) table.insert(world.items, {id = id, name = name, rarity = rarity}) end function log_event(event_type, data) table.insert(world.events, {type = event_type, data = data}) end add_player(1, 'Hero', 50) add_player(2, 'Mage', 48) spawn_creature(100, 'Goblin', 30) spawn_creature(101, 'Orc', 50) create_item(1000, 'Sword', 'rare') create_item(1001, 'Shield', 'common') log_event('combat', {attacker = 1, target = 100}) log_event('loot', {player = 1, item = 1000}) player_count = #world.players creature_count = #world.creatures item_count = #world.items event_count = #world.events )"; REQUIRE(fixture.ExecuteScript(eluna, script)); REQUIRE(fixture.GetGlobalAsInt(eluna, "player_count") == 2); REQUIRE(fixture.GetGlobalAsInt(eluna, "creature_count") == 2); REQUIRE(fixture.GetGlobalAsInt(eluna, "item_count") == 2); REQUIRE(fixture.GetGlobalAsInt(eluna, "event_count") == 2); } SECTION("Dynamic world state management") { std::string script = R"( state = {day_cycle = 0, weather = 'clear', active_events = {}} function update_world(delta_time) state.day_cycle = state.day_cycle + delta_time if state.day_cycle > 1440 then state.day_cycle = 0 end end function trigger_event(event_name) table.insert(state.active_events, event_name) end update_world(100) update_world(200) update_world(300) trigger_event('dragon_spawn') trigger_event('meteor_shower') total_time = state.day_cycle event_count = #state.active_events )"; REQUIRE(fixture.ExecuteScript(eluna, script)); REQUIRE(fixture.GetGlobalAsInt(eluna, "total_time") == 600); REQUIRE(fixture.GetGlobalAsInt(eluna, "event_count") == 2); } } TEST_CASE("Complex Scenarios - Dungeon Instance Management", "[LuaEngine][LuaEngineIntegration]") { LuaEngineTestFixture fixture; Eluna* eluna = fixture.CreateGlobalElunaInstance(); REQUIRE(eluna != nullptr); SECTION("Instance lifecycle management") { std::string script = R"( instances = {} function create_instance(instance_id, map_id, difficulty) local instance = {id = instance_id, map = map_id, difficulty = difficulty, players = {}, bosses = {}} instances[instance_id] = instance end function add_player_to_instance(instance_id, player_id) if instances[instance_id] then table.insert(instances[instance_id].players, player_id) end end function spawn_boss(instance_id, boss_id, boss_name) if instances[instance_id] then table.insert(instances[instance_id].bosses, {id = boss_id, name = boss_name, health = 100}) end end create_instance(1, 100, 'normal') add_player_to_instance(1, 1) add_player_to_instance(1, 2) add_player_to_instance(1, 3) spawn_boss(1, 1000, 'Boss1') spawn_boss(1, 1001, 'Boss2') instance_players = #instances[1].players instance_bosses = #instances[1].bosses )"; REQUIRE(fixture.ExecuteScript(eluna, script)); REQUIRE(fixture.GetGlobalAsInt(eluna, "instance_players") == 3); REQUIRE(fixture.GetGlobalAsInt(eluna, "instance_bosses") == 2); } SECTION("Boss encounter progression") { std::string script = R"( encounter = {bosses = {}, phase = 1, progress = 0} function add_boss(boss_id, boss_name, health) table.insert(encounter.bosses, {id = boss_id, name = boss_name, health = health, defeated = false}) end function damage_boss(boss_index, damage) if encounter.bosses[boss_index] then encounter.bosses[boss_index].health = encounter.bosses[boss_index].health - damage if encounter.bosses[boss_index].health <= 0 then encounter.bosses[boss_index].defeated = true encounter.progress = encounter.progress + 1 end end end add_boss(1, 'Boss1', 100) add_boss(2, 'Boss2', 100) damage_boss(1, 150) damage_boss(2, 150) if encounter.progress >= 2 then encounter.phase = 2 end phase = encounter.phase progress = encounter.progress )"; REQUIRE(fixture.ExecuteScript(eluna, script)); REQUIRE(fixture.GetGlobalAsInt(eluna, "phase") == 2); REQUIRE(fixture.GetGlobalAsInt(eluna, "progress") == 2); } } TEST_CASE("Complex Scenarios - Guild and Group Systems", "[LuaEngine][LuaEngineIntegration]") { LuaEngineTestFixture fixture; Eluna* eluna = fixture.CreateGlobalElunaInstance(); REQUIRE(eluna != nullptr); SECTION("Guild management system") { std::string script = R"( guilds = {} function create_guild(guild_id, guild_name, leader_id) local guild = {id = guild_id, name = guild_name, leader = leader_id, members = {leader_id}, treasury = 0} guilds[guild_id] = guild end function add_member(guild_id, player_id) if guilds[guild_id] then table.insert(guilds[guild_id].members, player_id) end end function deposit_gold(guild_id, amount) if guilds[guild_id] then guilds[guild_id].treasury = guilds[guild_id].treasury + amount end end create_guild(1, 'Legends', 1) add_member(1, 2) add_member(1, 3) add_member(1, 4) deposit_gold(1, 1000) deposit_gold(1, 500) member_count = #guilds[1].members treasury = guilds[1].treasury )"; REQUIRE(fixture.ExecuteScript(eluna, script)); REQUIRE(fixture.GetGlobalAsInt(eluna, "member_count") == 4); REQUIRE(fixture.GetGlobalAsInt(eluna, "treasury") == 1500); } SECTION("Group management") { std::string script = R"( groups = {} function create_group(group_id, leader_id) local group = {id = group_id, leader = leader_id, members = {leader_id}, max_members = 5} groups[group_id] = group end function add_to_group(group_id, player_id) if groups[group_id] and #groups[group_id].members < groups[group_id].max_members then table.insert(groups[group_id].members, player_id) return true end return false end create_group(1, 1) add_to_group(1, 2) add_to_group(1, 3) add_to_group(1, 4) add_to_group(1, 5) member_count = #groups[1].members )"; REQUIRE(fixture.ExecuteScript(eluna, script)); REQUIRE(fixture.GetGlobalAsInt(eluna, "member_count") == 5); } } TEST_CASE("Complex Scenarios - Quest and Achievement Systems", "[LuaEngine][LuaEngineIntegration]") { LuaEngineTestFixture fixture; Eluna* eluna = fixture.CreateGlobalElunaInstance(); REQUIRE(eluna != nullptr); SECTION("Quest progression system") { std::string script = R"( quests = {} function create_quest(quest_id, title, objectives_count) local quest = {id = quest_id, title = title, objectives = {}, completed = false} for i = 1, objectives_count do table.insert(quest.objectives, {id = i, completed = false}) end quests[quest_id] = quest end function complete_objective(quest_id, objective_id) if quests[quest_id] and quests[quest_id].objectives[objective_id] then quests[quest_id].objectives[objective_id].completed = true end end function check_quest_completion(quest_id) if quests[quest_id] then local all_complete = true for i, obj in ipairs(quests[quest_id].objectives) do if not obj.completed then all_complete = false break end end quests[quest_id].completed = all_complete return all_complete end return false end create_quest(1, 'Defeat Goblins', 3) complete_objective(1, 1) complete_objective(1, 2) complete_objective(1, 3) check_quest_completion(1) is_completed = quests[1].completed )"; REQUIRE(fixture.ExecuteScript(eluna, script)); REQUIRE(fixture.GetGlobalAsBoolean(eluna, "is_completed") == true); } SECTION("Achievement tracking system") { std::string script = R"( achievements = {} player_achievements = {} function register_achievement(achievement_id, name, points) achievements[achievement_id] = {id = achievement_id, name = name, points = points} end function unlock_achievement(player_id, achievement_id) if not player_achievements[player_id] then player_achievements[player_id] = {} end if achievements[achievement_id] then table.insert(player_achievements[player_id], achievement_id) return true end return false end function get_player_points(player_id) local points = 0 if player_achievements[player_id] then for i, ach_id in ipairs(player_achievements[player_id]) do if achievements[ach_id] then points = points + achievements[ach_id].points end end end return points end register_achievement(1, 'First Blood', 10) register_achievement(2, 'Monster Slayer', 25) register_achievement(3, 'Legend', 50) unlock_achievement(1, 1) unlock_achievement(1, 2) unlock_achievement(1, 3) total_points = get_player_points(1) )"; REQUIRE(fixture.ExecuteScript(eluna, script)); REQUIRE(fixture.GetGlobalAsInt(eluna, "total_points") == 85); } } TEST_CASE("Complex Scenarios - Economy and Trading", "[LuaEngine][LuaEngineIntegration]") { LuaEngineTestFixture fixture; Eluna* eluna = fixture.CreateGlobalElunaInstance(); REQUIRE(eluna != nullptr); SECTION("Player economy system") { std::string script = R"( players = {} function create_player(player_id, name, gold) players[player_id] = {id = player_id, name = name, gold = gold} end function transfer_gold(from_id, to_id, amount) if players[from_id] and players[to_id] then if players[from_id].gold >= amount then players[from_id].gold = players[from_id].gold - amount players[to_id].gold = players[to_id].gold + amount return true end end return false end create_player(1, 'Alice', 1000) create_player(2, 'Bob', 500) transfer_gold(1, 2, 200) transfer_gold(2, 1, 100) alice_gold = players[1].gold bob_gold = players[2].gold )"; REQUIRE(fixture.ExecuteScript(eluna, script)); REQUIRE(fixture.GetGlobalAsInt(eluna, "alice_gold") == 900); REQUIRE(fixture.GetGlobalAsInt(eluna, "bob_gold") == 600); } SECTION("Auction house system") { std::string script = R"( auctions = {} auction_counter = 0 function post_auction(seller_id, item_name, starting_bid, duration) auction_counter = auction_counter + 1 local auction = {id = auction_counter, seller = seller_id, item = item_name, bid = starting_bid} table.insert(auctions, auction) return auction.id end function place_bid(auction_id, bidder_id, bid_amount) for i, auction in ipairs(auctions) do if auction.id == auction_id then if bid_amount > auction.bid then auction.bid = bid_amount auction.bidder = bidder_id return true end end end return false end post_auction(1, 'Sword', 100, 24) post_auction(1, 'Shield', 50, 24) place_bid(1, 2, 150) place_bid(1, 3, 200) place_bid(2, 2, 75) auction_count = #auctions )"; REQUIRE(fixture.ExecuteScript(eluna, script)); REQUIRE(fixture.GetGlobalAsInt(eluna, "auction_count") == 2); } } TEST_CASE("Complex Scenarios - Error Recovery and Resilience", "[LuaEngine][LuaEngineIntegration]") { LuaEngineTestFixture fixture; Eluna* eluna = fixture.CreateGlobalElunaInstance(); REQUIRE(eluna != nullptr); SECTION("Graceful degradation on errors") { std::string script = R"( system_state = {errors = 0, warnings = 0, operations = 0} function safe_operation(operation_func) system_state.operations = system_state.operations + 1 if operation_func then return true else system_state.errors = system_state.errors + 1 return false end end safe_operation(true) safe_operation(true) safe_operation(false) safe_operation(true) error_count = system_state.errors operation_count = system_state.operations )"; REQUIRE(fixture.ExecuteScript(eluna, script)); REQUIRE(fixture.GetGlobalAsInt(eluna, "error_count") == 1); REQUIRE(fixture.GetGlobalAsInt(eluna, "operation_count") == 4); } SECTION("State preservation after errors") { REQUIRE(fixture.ExecuteScript(eluna, "game_state = {level = 1, exp = 0}")); REQUIRE(!fixture.ExecuteScript(eluna, "undefined_function()")); REQUIRE(fixture.ExecuteScript(eluna, "result = game_state.level")); REQUIRE(fixture.GetGlobalAsInt(eluna, "result") == 1); } }