mirror of
https://github.com/araxiaonline/TrinityCore.git
synced 2026-06-13 11:43:18 -04:00
837 lines
26 KiB
C++
837 lines
26 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 2 Tests: Advanced Lua Engine Functionality
|
|
*
|
|
* These tests verify:
|
|
* 1. Instance data lifecycle management
|
|
* 2. Hook registration and management
|
|
* 3. Advanced stack operations
|
|
* 4. AI integration patterns
|
|
*/
|
|
|
|
TEST_CASE("Instance Data - Data Storage and Retrieval", "[LuaEngine][LuaEngineAdvanced]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("Instance data can be stored as tables")
|
|
{
|
|
std::string script = R"(
|
|
instance_data = {
|
|
boss_defeated = false,
|
|
treasure_found = 0,
|
|
players_count = 0
|
|
}
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.GetGlobalAsBoolean(eluna, "instance_data.boss_defeated") == false);
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "instance_data.treasure_found") == 0);
|
|
}
|
|
|
|
SECTION("Instance data can be updated")
|
|
{
|
|
std::string script = R"(
|
|
data = {value = 10}
|
|
data.value = 20
|
|
data.new_field = 'added'
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "data.value") == 20);
|
|
REQUIRE(fixture.GetGlobalAsString(eluna, "data.new_field") == "added");
|
|
}
|
|
|
|
SECTION("Instance data persists across function calls")
|
|
{
|
|
std::string script = R"(
|
|
state = {counter = 0}
|
|
|
|
function increment()
|
|
state.counter = state.counter + 1
|
|
end
|
|
|
|
function get_counter()
|
|
return state.counter
|
|
end
|
|
|
|
increment()
|
|
increment()
|
|
result = get_counter()
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "result") == 2);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Instance Data - Complex Data Structures", "[LuaEngine][LuaEngineAdvanced]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("Nested data structures are supported")
|
|
{
|
|
std::string script = R"(
|
|
instance = {
|
|
bosses = {
|
|
boss1 = {name = 'Lich King', health = 1000},
|
|
boss2 = {name = 'Ragnaros', health = 2000}
|
|
},
|
|
players = {
|
|
{name = 'Alice', level = 50},
|
|
{name = 'Bob', level = 45}
|
|
}
|
|
}
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.GetGlobalAsString(eluna, "instance.bosses.boss1.name") == "Lich King");
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "instance.bosses.boss1.health") == 1000);
|
|
}
|
|
|
|
SECTION("Array data structures work correctly")
|
|
{
|
|
std::string script = R"(
|
|
items = {
|
|
{id = 1, name = 'Sword'},
|
|
{id = 2, name = 'Shield'},
|
|
{id = 3, name = 'Armor'}
|
|
}
|
|
count = #items
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.GetTableSize(eluna, "items") == 3);
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "count") == 3);
|
|
}
|
|
|
|
SECTION("Mixed array and key-value tables work")
|
|
{
|
|
std::string script = R"(
|
|
mixed = {
|
|
1, 2, 3,
|
|
name = 'mixed',
|
|
value = 100
|
|
}
|
|
array_size = #mixed
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "array_size") == 3);
|
|
REQUIRE(fixture.GetGlobalAsString(eluna, "mixed.name") == "mixed");
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Instance Data - Data Persistence", "[LuaEngine][LuaEngineAdvanced]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("Data persists across multiple script executions")
|
|
{
|
|
// First execution
|
|
REQUIRE(fixture.ExecuteScript(eluna, "persistent_data = {value = 42}"));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "persistent_data.value") == 42);
|
|
|
|
// Second execution - data should still exist
|
|
REQUIRE(fixture.ExecuteScript(eluna, "result = persistent_data.value + 8"));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "result") == 50);
|
|
}
|
|
|
|
SECTION("Functions can access persistent data")
|
|
{
|
|
std::string script = R"(
|
|
shared_data = {count = 0}
|
|
|
|
function add_to_count()
|
|
shared_data.count = shared_data.count + 1
|
|
end
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.CallFunction(eluna, "add_to_count"));
|
|
|
|
// Verify data was modified
|
|
REQUIRE(fixture.ExecuteScript(eluna, "result = shared_data.count"));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "result") >= 1);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Hook Registration - Event Handler Registration", "[LuaEngine][LuaEngineAdvanced]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("Event handlers can be registered")
|
|
{
|
|
std::string script = R"(
|
|
handlers = {}
|
|
|
|
function register_handler(event_id, handler)
|
|
if not handlers[event_id] then
|
|
handlers[event_id] = {}
|
|
end
|
|
table.insert(handlers[event_id], handler)
|
|
end
|
|
|
|
function on_event_1()
|
|
return 'event1'
|
|
end
|
|
|
|
register_handler(1, on_event_1)
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.FunctionExists(eluna, "register_handler"));
|
|
REQUIRE(fixture.FunctionExists(eluna, "on_event_1"));
|
|
}
|
|
|
|
SECTION("Multiple handlers can be registered for same event")
|
|
{
|
|
std::string script = R"(
|
|
event_handlers = {}
|
|
|
|
function add_handler(event_id, handler_name)
|
|
if not event_handlers[event_id] then
|
|
event_handlers[event_id] = {}
|
|
end
|
|
table.insert(event_handlers[event_id], handler_name)
|
|
end
|
|
|
|
add_handler(1, 'handler_a')
|
|
add_handler(1, 'handler_b')
|
|
add_handler(1, 'handler_c')
|
|
|
|
handler_count = #event_handlers[1]
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "handler_count") == 3);
|
|
}
|
|
|
|
SECTION("Handlers can be organized by type")
|
|
{
|
|
std::string script = R"(
|
|
handlers = {
|
|
server = {},
|
|
player = {},
|
|
creature = {}
|
|
}
|
|
|
|
function register_server_handler(name)
|
|
table.insert(handlers.server, name)
|
|
end
|
|
|
|
function register_player_handler(name)
|
|
table.insert(handlers.player, name)
|
|
end
|
|
|
|
register_server_handler('on_start')
|
|
register_player_handler('on_login')
|
|
|
|
server_count = #handlers.server
|
|
player_count = #handlers.player
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "server_count") == 1);
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "player_count") == 1);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Hook Registration - Event Execution", "[LuaEngine][LuaEngineAdvanced]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("Registered handlers can be executed")
|
|
{
|
|
std::string script = R"(
|
|
event_result = nil
|
|
|
|
function on_event()
|
|
event_result = 'executed'
|
|
end
|
|
|
|
function trigger_event()
|
|
on_event()
|
|
end
|
|
|
|
trigger_event()
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.GetGlobalAsString(eluna, "event_result") == "executed");
|
|
}
|
|
|
|
SECTION("Handlers can pass and return values")
|
|
{
|
|
std::string script = R"(
|
|
function handler_with_params(a, b)
|
|
return a + b
|
|
end
|
|
|
|
function call_handler()
|
|
result = handler_with_params(10, 20)
|
|
end
|
|
|
|
call_handler()
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "result") == 30);
|
|
}
|
|
|
|
SECTION("Multiple handlers can be executed in sequence")
|
|
{
|
|
std::string script = R"(
|
|
execution_log = {}
|
|
|
|
function handler_1()
|
|
table.insert(execution_log, 'h1')
|
|
end
|
|
|
|
function handler_2()
|
|
table.insert(execution_log, 'h2')
|
|
end
|
|
|
|
function handler_3()
|
|
table.insert(execution_log, 'h3')
|
|
end
|
|
|
|
function execute_all()
|
|
handler_1()
|
|
handler_2()
|
|
handler_3()
|
|
end
|
|
|
|
execute_all()
|
|
count = #execution_log
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "count") == 3);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Advanced Stack Operations - Type Conversions", "[LuaEngine][LuaEngineAdvanced]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("Numbers are converted correctly")
|
|
{
|
|
REQUIRE(fixture.ExecuteScript(eluna, "x = 42; y = tostring(x)"));
|
|
REQUIRE(fixture.GetGlobalAsString(eluna, "y") == "42");
|
|
}
|
|
|
|
SECTION("Strings are converted to numbers")
|
|
{
|
|
REQUIRE(fixture.ExecuteScript(eluna, "x = '123'; y = tonumber(x)"));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "y") == 123);
|
|
}
|
|
|
|
SECTION("Booleans are converted to strings")
|
|
{
|
|
REQUIRE(fixture.ExecuteScript(eluna, "x = true; y = tostring(x)"));
|
|
REQUIRE(fixture.GetGlobalAsString(eluna, "y") == "true");
|
|
}
|
|
|
|
SECTION("Type checking with type()")
|
|
{
|
|
REQUIRE(fixture.ExecuteScript(eluna, "types = {type(1), type('s'), type(true), type({}), type(function() end)}"));
|
|
REQUIRE(fixture.GetTableSize(eluna, "types") == 5);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Advanced Stack Operations - Table Manipulation", "[LuaEngine][LuaEngineAdvanced]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("Table insertion works")
|
|
{
|
|
std::string script = R"(
|
|
t = {1, 2, 3}
|
|
table.insert(t, 4)
|
|
table.insert(t, 5)
|
|
size = #t
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "size") == 5);
|
|
}
|
|
|
|
SECTION("Table removal works")
|
|
{
|
|
std::string script = R"(
|
|
t = {1, 2, 3, 4, 5}
|
|
table.remove(t, 2)
|
|
size = #t
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "size") == 4);
|
|
}
|
|
|
|
SECTION("Table concatenation works")
|
|
{
|
|
std::string script = R"(
|
|
t = {1, 2, 3}
|
|
result = table.concat(t, ',')
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.GetGlobalAsString(eluna, "result") == "1,2,3");
|
|
}
|
|
|
|
SECTION("Table sorting works")
|
|
{
|
|
std::string script = R"(
|
|
t = {3, 1, 4, 1, 5}
|
|
table.sort(t)
|
|
first = t[1]
|
|
last = t[#t]
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "first") == 1);
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "last") == 5);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Advanced Stack Operations - String Manipulation", "[LuaEngine][LuaEngineAdvanced]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("String length works")
|
|
{
|
|
REQUIRE(fixture.ExecuteScript(eluna, "x = 'hello'; len = #x"));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "len") == 5);
|
|
}
|
|
|
|
SECTION("String concatenation works")
|
|
{
|
|
REQUIRE(fixture.ExecuteScript(eluna, "x = 'hello' .. ' ' .. 'world'"));
|
|
REQUIRE(fixture.GetGlobalAsString(eluna, "x") == "hello world");
|
|
}
|
|
|
|
SECTION("String substring works")
|
|
{
|
|
REQUIRE(fixture.ExecuteScript(eluna, "x = string.sub('hello', 2, 4)"));
|
|
REQUIRE(fixture.GetGlobalAsString(eluna, "x") == "ell");
|
|
}
|
|
|
|
SECTION("String formatting works")
|
|
{
|
|
REQUIRE(fixture.ExecuteScript(eluna, "x = string.format('Value: %d', 42)"));
|
|
REQUIRE(fixture.GetGlobalAsString(eluna, "x") == "Value: 42");
|
|
}
|
|
|
|
SECTION("String case conversion works")
|
|
{
|
|
REQUIRE(fixture.ExecuteScript(eluna, "upper = string.upper('hello'); lower = string.lower('WORLD')"));
|
|
REQUIRE(fixture.GetGlobalAsString(eluna, "upper") == "HELLO");
|
|
REQUIRE(fixture.GetGlobalAsString(eluna, "lower") == "world");
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Advanced Stack Operations - Math Operations", "[LuaEngine][LuaEngineAdvanced]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("Math floor and ceil work")
|
|
{
|
|
REQUIRE(fixture.ExecuteScript(eluna, "x = math.floor(3.7); y = math.ceil(3.2)"));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "x") == 3);
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "y") == 4);
|
|
}
|
|
|
|
SECTION("Math min and max work")
|
|
{
|
|
REQUIRE(fixture.ExecuteScript(eluna, "x = math.min(5, 2, 8); y = math.max(5, 2, 8)"));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "x") == 2);
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "y") == 8);
|
|
}
|
|
|
|
SECTION("Math absolute value works")
|
|
{
|
|
REQUIRE(fixture.ExecuteScript(eluna, "x = math.abs(-42)"));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "x") == 42);
|
|
}
|
|
|
|
SECTION("Math power works")
|
|
{
|
|
REQUIRE(fixture.ExecuteScript(eluna, "x = math.pow(2, 3)"));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "x") == 8);
|
|
}
|
|
|
|
SECTION("Math square root works")
|
|
{
|
|
REQUIRE(fixture.ExecuteScript(eluna, "x = math.sqrt(16)"));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "x") == 4);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("AI Integration - State Management", "[LuaEngine][LuaEngineAdvanced]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("AI state can be initialized")
|
|
{
|
|
std::string script = R"(
|
|
ai_state = {
|
|
current_state = 'idle',
|
|
health = 100,
|
|
mana = 50,
|
|
in_combat = false
|
|
}
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.GetGlobalAsString(eluna, "ai_state.current_state") == "idle");
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "ai_state.health") == 100);
|
|
}
|
|
|
|
SECTION("AI state can be updated")
|
|
{
|
|
std::string script = R"(
|
|
state = {status = 'idle'}
|
|
|
|
function enter_combat()
|
|
state.status = 'combat'
|
|
end
|
|
|
|
function exit_combat()
|
|
state.status = 'idle'
|
|
end
|
|
|
|
enter_combat()
|
|
current = state.status
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.GetGlobalAsString(eluna, "current") == "combat");
|
|
}
|
|
|
|
SECTION("AI can track multiple entities")
|
|
{
|
|
std::string script = R"(
|
|
ai = {
|
|
creatures = {},
|
|
players = {}
|
|
}
|
|
|
|
function add_creature(id, name)
|
|
table.insert(ai.creatures, {id = id, name = name})
|
|
end
|
|
|
|
function add_player(id, name)
|
|
table.insert(ai.players, {id = id, name = name})
|
|
end
|
|
|
|
add_creature(1, 'Goblin')
|
|
add_creature(2, 'Orc')
|
|
add_player(100, 'Hero')
|
|
|
|
creature_count = #ai.creatures
|
|
player_count = #ai.players
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "creature_count") == 2);
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "player_count") == 1);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("AI Integration - Behavior Implementation", "[LuaEngine][LuaEngineAdvanced]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("AI behavior functions can be defined")
|
|
{
|
|
std::string script = R"(
|
|
function on_spawn()
|
|
return 'spawned'
|
|
end
|
|
|
|
function on_combat()
|
|
return 'fighting'
|
|
end
|
|
|
|
function on_death()
|
|
return 'dead'
|
|
end
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.FunctionExists(eluna, "on_spawn"));
|
|
REQUIRE(fixture.FunctionExists(eluna, "on_combat"));
|
|
REQUIRE(fixture.FunctionExists(eluna, "on_death"));
|
|
}
|
|
|
|
SECTION("AI behavior can be triggered")
|
|
{
|
|
std::string script = R"(
|
|
behavior_log = {}
|
|
|
|
function trigger_behavior(behavior_name)
|
|
table.insert(behavior_log, behavior_name)
|
|
end
|
|
|
|
function execute_behaviors()
|
|
trigger_behavior('spawn')
|
|
trigger_behavior('idle')
|
|
trigger_behavior('patrol')
|
|
end
|
|
|
|
execute_behaviors()
|
|
count = #behavior_log
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "count") == 3);
|
|
}
|
|
|
|
SECTION("AI can make decisions based on conditions")
|
|
{
|
|
std::string script = R"(
|
|
function decide_action(health, threat_level)
|
|
if health < 30 then
|
|
return 'flee'
|
|
elseif threat_level > 50 then
|
|
return 'attack'
|
|
else
|
|
return 'patrol'
|
|
end
|
|
end
|
|
|
|
action1 = decide_action(20, 30)
|
|
action2 = decide_action(80, 60)
|
|
action3 = decide_action(50, 20)
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.GetGlobalAsString(eluna, "action1") == "flee");
|
|
REQUIRE(fixture.GetGlobalAsString(eluna, "action2") == "attack");
|
|
REQUIRE(fixture.GetGlobalAsString(eluna, "action3") == "patrol");
|
|
}
|
|
}
|
|
|
|
TEST_CASE("AI Integration - Event Handling", "[LuaEngine][LuaEngineAdvanced]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("AI can handle multiple event types")
|
|
{
|
|
std::string script = R"(
|
|
events = {}
|
|
|
|
function on_event(event_type, data)
|
|
table.insert(events, {type = event_type, data = data})
|
|
end
|
|
|
|
on_event('spawn', {x = 100, y = 200})
|
|
on_event('combat', {target = 'player1'})
|
|
on_event('death', {killer = 'player1'})
|
|
|
|
event_count = #events
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "event_count") == 3);
|
|
}
|
|
|
|
SECTION("AI can respond to events with state changes")
|
|
{
|
|
std::string script = R"(
|
|
ai = {state = 'idle', target = nil}
|
|
|
|
function on_aggro(target_id)
|
|
ai.state = 'combat'
|
|
ai.target = target_id
|
|
end
|
|
|
|
function on_disengage()
|
|
ai.state = 'idle'
|
|
ai.target = nil
|
|
end
|
|
|
|
on_aggro(123)
|
|
state_after_aggro = ai.state
|
|
|
|
on_disengage()
|
|
state_after_disengage = ai.state
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.GetGlobalAsString(eluna, "state_after_aggro") == "combat");
|
|
REQUIRE(fixture.GetGlobalAsString(eluna, "state_after_disengage") == "idle");
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Advanced Integration - Complex Workflows", "[LuaEngine][LuaEngineAdvanced]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("Complex game scenario with multiple systems")
|
|
{
|
|
std::string script = R"(
|
|
-- Game world state
|
|
world = {
|
|
creatures = {},
|
|
players = {},
|
|
events = {}
|
|
}
|
|
|
|
-- Creature AI
|
|
function spawn_creature(id, name, health)
|
|
local creature = {
|
|
id = id,
|
|
name = name,
|
|
health = health,
|
|
state = 'idle'
|
|
}
|
|
table.insert(world.creatures, creature)
|
|
return creature
|
|
end
|
|
|
|
-- Player management
|
|
function add_player(id, name, level)
|
|
local player = {
|
|
id = id,
|
|
name = name,
|
|
level = level
|
|
}
|
|
table.insert(world.players, player)
|
|
return player
|
|
end
|
|
|
|
-- Event system
|
|
function trigger_event(event_type, data)
|
|
table.insert(world.events, {type = event_type, data = data})
|
|
end
|
|
|
|
-- Execute scenario
|
|
spawn_creature(1, 'Goblin', 50)
|
|
spawn_creature(2, 'Orc', 100)
|
|
add_player(100, 'Hero', 50)
|
|
trigger_event('combat', {creature = 1, player = 100})
|
|
|
|
creature_count = #world.creatures
|
|
player_count = #world.players
|
|
event_count = #world.events
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "creature_count") == 2);
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "player_count") == 1);
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "event_count") == 1);
|
|
}
|
|
|
|
SECTION("Data persistence across function calls")
|
|
{
|
|
std::string script = R"(
|
|
-- Persistent game state
|
|
game = {
|
|
level = 1,
|
|
experience = 0,
|
|
gold = 0
|
|
}
|
|
|
|
function gain_experience(amount)
|
|
game.experience = game.experience + amount
|
|
if game.experience >= 100 then
|
|
game.level = game.level + 1
|
|
game.experience = game.experience - 100
|
|
end
|
|
end
|
|
|
|
function gain_gold(amount)
|
|
game.gold = game.gold + amount
|
|
end
|
|
|
|
-- Simulate gameplay
|
|
gain_experience(50)
|
|
gain_experience(60)
|
|
gain_gold(100)
|
|
|
|
final_level = game.level
|
|
final_exp = game.experience
|
|
final_gold = game.gold
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "final_level") == 2);
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "final_exp") == 10);
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "final_gold") == 100);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Advanced Integration - Error Handling and Recovery", "[LuaEngine][LuaEngineAdvanced]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("Errors in one function don't affect others")
|
|
{
|
|
std::string script = R"(
|
|
function safe_function()
|
|
return 'success'
|
|
end
|
|
|
|
result1 = safe_function()
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.GetGlobalAsString(eluna, "result1") == "success");
|
|
|
|
// Error script - calling undefined function
|
|
REQUIRE(!fixture.ExecuteScript(eluna, "undefined_function()"));
|
|
|
|
// Safe function still works
|
|
REQUIRE(fixture.ExecuteScript(eluna, "result2 = safe_function()"));
|
|
REQUIRE(fixture.GetGlobalAsString(eluna, "result2") == "success");
|
|
}
|
|
|
|
SECTION("State is preserved after errors")
|
|
{
|
|
REQUIRE(fixture.ExecuteScript(eluna, "state = {value = 42}"));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "state.value") == 42);
|
|
|
|
// Trigger error
|
|
REQUIRE(!fixture.ExecuteScript(eluna, "error('test error')"));
|
|
|
|
// State should still be there
|
|
REQUIRE(fixture.ExecuteScript(eluna, "result = state.value"));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "result") == 42);
|
|
}
|
|
|
|
SECTION("Conditional execution prevents errors")
|
|
{
|
|
std::string script = R"(
|
|
data = {value = 10}
|
|
|
|
if data and data.value then
|
|
result = data.value * 2
|
|
else
|
|
result = 0
|
|
end
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "result") == 20);
|
|
}
|
|
}
|