Files
TrinityCore/tests/game/LuaEngine/LuaEngineIntegration.cpp

509 lines
20 KiB
C++

/*
* 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 "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);
}
}