mirror of
https://github.com/araxiaonline/TrinityCore.git
synced 2026-06-13 11:43:18 -04:00
555 lines
17 KiB
C++
555 lines
17 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 1 Tests: Core Lua Engine Functionality
|
|
*
|
|
* These tests verify:
|
|
* 1. Lua state management (creation, cleanup)
|
|
* 2. Script execution and loading
|
|
* 3. Binding store management
|
|
* 4. Event manager functionality
|
|
*/
|
|
|
|
TEST_CASE("Lua State Management - State Creation", "[LuaEngine][LuaEngineCore]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("Eluna instance has valid Lua state")
|
|
{
|
|
lua_State* L = fixture.GetLuaState(eluna);
|
|
REQUIRE(L != nullptr);
|
|
}
|
|
|
|
SECTION("HasLuaState returns true for valid instance")
|
|
{
|
|
REQUIRE(eluna != nullptr);
|
|
// If we got here, Eluna was created successfully with Lua state
|
|
REQUIRE(true);
|
|
}
|
|
|
|
SECTION("Multiple Eluna instances have independent Lua states")
|
|
{
|
|
Eluna* eluna2 = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna2 != nullptr);
|
|
|
|
lua_State* L1 = fixture.GetLuaState(eluna);
|
|
lua_State* L2 = fixture.GetLuaState(eluna2);
|
|
|
|
// States should be different
|
|
REQUIRE(L1 != L2);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Lua State Management - Lua Libraries", "[LuaEngine][LuaEngineCore]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("Standard Lua libraries are available")
|
|
{
|
|
// Test that standard library functions work
|
|
REQUIRE(fixture.ExecuteScript(eluna, "x = math.floor(3.7)"));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "x") == 3);
|
|
}
|
|
|
|
SECTION("String library is available")
|
|
{
|
|
REQUIRE(fixture.ExecuteScript(eluna, "x = string.upper('hello')"));
|
|
REQUIRE(fixture.GetGlobalAsString(eluna, "x") == "HELLO");
|
|
}
|
|
|
|
SECTION("Table library is available")
|
|
{
|
|
REQUIRE(fixture.ExecuteScript(eluna, "t = {1, 2, 3}; x = #t"));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "x") == 3);
|
|
}
|
|
|
|
SECTION("Math library functions work")
|
|
{
|
|
REQUIRE(fixture.ExecuteScript(eluna, "x = math.max(5, 10, 3)"));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "x") == 10);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Script Execution - Basic Script Loading", "[LuaEngine][LuaEngineCore]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("Simple script executes successfully")
|
|
{
|
|
REQUIRE(fixture.ExecuteScript(eluna, "x = 42"));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "x") == 42);
|
|
}
|
|
|
|
SECTION("Multi-line scripts execute successfully")
|
|
{
|
|
std::string script = R"(
|
|
x = 10
|
|
y = 20
|
|
z = x + y
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "z") == 30);
|
|
}
|
|
|
|
SECTION("Scripts with functions execute successfully")
|
|
{
|
|
std::string script = R"(
|
|
function add(a, b)
|
|
return a + b
|
|
end
|
|
result = add(5, 3)
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "result") == 8);
|
|
}
|
|
|
|
SECTION("Scripts with tables execute successfully")
|
|
{
|
|
std::string script = R"(
|
|
data = {
|
|
name = 'test',
|
|
value = 100,
|
|
items = {1, 2, 3}
|
|
}
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.GetGlobalAsString(eluna, "data.name") == "test");
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "data.value") == 100);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Script Execution - Error Handling", "[LuaEngine][LuaEngineCore]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("Syntax errors are caught")
|
|
{
|
|
REQUIRE(!fixture.ExecuteScript(eluna, "this is not valid lua syntax"));
|
|
}
|
|
|
|
SECTION("Runtime errors are caught")
|
|
{
|
|
REQUIRE(!fixture.ExecuteScript(eluna, "x = nil; y = x.foo()"));
|
|
}
|
|
|
|
SECTION("Undefined function calls are caught")
|
|
{
|
|
REQUIRE(!fixture.ExecuteScript(eluna, "nonexistent_function()"));
|
|
}
|
|
|
|
SECTION("Type errors are caught")
|
|
{
|
|
REQUIRE(!fixture.ExecuteScript(eluna, "x = 'string'; y = x + 5"));
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Script Execution - Script Isolation", "[LuaEngine][LuaEngineCore]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna1 = fixture.CreateGlobalElunaInstance();
|
|
Eluna* eluna2 = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna1 != nullptr);
|
|
REQUIRE(eluna2 != nullptr);
|
|
|
|
SECTION("Scripts in different Eluna instances don't share state")
|
|
{
|
|
REQUIRE(fixture.ExecuteScript(eluna1, "shared_var = 100"));
|
|
REQUIRE(fixture.ExecuteScript(eluna2, "shared_var = 200"));
|
|
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna1, "shared_var") == 100);
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna2, "shared_var") == 200);
|
|
}
|
|
|
|
SECTION("Functions defined in one instance are not available in another")
|
|
{
|
|
REQUIRE(fixture.ExecuteScript(eluna1, "function test_func() return 42 end"));
|
|
REQUIRE(!fixture.FunctionExists(eluna2, "test_func"));
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Binding Management - Binding Store Creation", "[LuaEngine][LuaEngineCore]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("Eluna instance has binding stores")
|
|
{
|
|
// Verify by checking that we can access global functions
|
|
REQUIRE(fixture.ExecuteScript(eluna, "x = 1"));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "x") == 1);
|
|
}
|
|
|
|
SECTION("Multiple Eluna instances have independent bindings")
|
|
{
|
|
Eluna* eluna2 = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna2 != nullptr);
|
|
|
|
// Both should have independent binding stores
|
|
REQUIRE(fixture.ExecuteScript(eluna, "x = 1"));
|
|
REQUIRE(fixture.ExecuteScript(eluna2, "x = 2"));
|
|
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "x") == 1);
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna2, "x") == 2);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Binding Management - Standard Library Bindings", "[LuaEngine][LuaEngineCore]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("Math library bindings are available")
|
|
{
|
|
REQUIRE(fixture.ExecuteScript(eluna, "x = math.floor(3.9)"));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "x") == 3);
|
|
}
|
|
|
|
SECTION("String library bindings are available")
|
|
{
|
|
REQUIRE(fixture.ExecuteScript(eluna, "x = string.len('hello')"));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "x") == 5);
|
|
}
|
|
|
|
SECTION("Table library bindings are available")
|
|
{
|
|
REQUIRE(fixture.ExecuteScript(eluna, "t = {3, 1, 2}; table.sort(t); x = t[1]"));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "x") == 1);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Event Management - Event Registration", "[LuaEngine][LuaEngineCore]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("Global table can be accessed")
|
|
{
|
|
// Verify that we can access and manipulate the global table
|
|
REQUIRE(fixture.ExecuteScript(eluna, "x = type(_G)"));
|
|
REQUIRE(fixture.GetGlobalAsString(eluna, "x") == "table");
|
|
}
|
|
|
|
SECTION("Global functions are accessible")
|
|
{
|
|
// Test that standard global functions exist
|
|
REQUIRE(fixture.ExecuteScript(eluna, "x = type(print)"));
|
|
REQUIRE(fixture.GetGlobalAsString(eluna, "x") == "function");
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Event Management - Timed Events", "[LuaEngine][LuaEngineCore]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("Timed event counter can be incremented")
|
|
{
|
|
std::string script = R"(
|
|
counter = 0
|
|
function increment_counter()
|
|
counter = counter + 1
|
|
end
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.FunctionExists(eluna, "increment_counter"));
|
|
}
|
|
|
|
SECTION("Event handlers can be defined")
|
|
{
|
|
std::string script = R"(
|
|
event_called = false
|
|
function on_event()
|
|
event_called = true
|
|
end
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.FunctionExists(eluna, "on_event"));
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Event Management - Event Handler Execution", "[LuaEngine][LuaEngineCore]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("Event handler can be called and modify state")
|
|
{
|
|
std::string script = R"(
|
|
state_value = 0
|
|
function update_state(new_value)
|
|
state_value = new_value
|
|
end
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.CallFunction(eluna, "update_state"));
|
|
// Function was called successfully
|
|
REQUIRE(true);
|
|
}
|
|
|
|
SECTION("Multiple event handlers can coexist")
|
|
{
|
|
std::string script = R"(
|
|
function handler1()
|
|
return 1
|
|
end
|
|
function handler2()
|
|
return 2
|
|
end
|
|
function handler3()
|
|
return 3
|
|
end
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.FunctionExists(eluna, "handler1"));
|
|
REQUIRE(fixture.FunctionExists(eluna, "handler2"));
|
|
REQUIRE(fixture.FunctionExists(eluna, "handler3"));
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Lua Stack Operations - Push Operations", "[LuaEngine][LuaEngineCore]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("Integer values are correctly pushed and retrieved")
|
|
{
|
|
REQUIRE(fixture.ExecuteScript(eluna, "x = 42"));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "x") == 42);
|
|
}
|
|
|
|
SECTION("Float values are correctly pushed and retrieved")
|
|
{
|
|
REQUIRE(fixture.ExecuteScript(eluna, "x = 3.14"));
|
|
int value = fixture.GetGlobalAsInt(eluna, "x");
|
|
REQUIRE(value == 3); // Truncated to int
|
|
}
|
|
|
|
SECTION("String values are correctly pushed and retrieved")
|
|
{
|
|
REQUIRE(fixture.ExecuteScript(eluna, "x = 'hello world'"));
|
|
REQUIRE(fixture.GetGlobalAsString(eluna, "x") == "hello world");
|
|
}
|
|
|
|
SECTION("Boolean values are correctly pushed and retrieved")
|
|
{
|
|
REQUIRE(fixture.ExecuteScript(eluna, "x = true"));
|
|
REQUIRE(fixture.GetGlobalAsBoolean(eluna, "x") == true);
|
|
|
|
REQUIRE(fixture.ExecuteScript(eluna, "y = false"));
|
|
REQUIRE(fixture.GetGlobalAsBoolean(eluna, "y") == false);
|
|
}
|
|
|
|
SECTION("Nil values are correctly handled")
|
|
{
|
|
REQUIRE(fixture.ExecuteScript(eluna, "x = nil"));
|
|
REQUIRE(fixture.GetGlobalAsString(eluna, "x") == "");
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Lua Stack Operations - Type Checking", "[LuaEngine][LuaEngineCore]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("Integer type is correctly identified")
|
|
{
|
|
REQUIRE(fixture.ExecuteScript(eluna, "x = 42; t = type(x)"));
|
|
REQUIRE(fixture.GetGlobalAsString(eluna, "t") == "number");
|
|
}
|
|
|
|
SECTION("String type is correctly identified")
|
|
{
|
|
REQUIRE(fixture.ExecuteScript(eluna, "x = 'hello'; t = type(x)"));
|
|
REQUIRE(fixture.GetGlobalAsString(eluna, "t") == "string");
|
|
}
|
|
|
|
SECTION("Boolean type is correctly identified")
|
|
{
|
|
REQUIRE(fixture.ExecuteScript(eluna, "x = true; t = type(x)"));
|
|
REQUIRE(fixture.GetGlobalAsString(eluna, "t") == "boolean");
|
|
}
|
|
|
|
SECTION("Table type is correctly identified")
|
|
{
|
|
REQUIRE(fixture.ExecuteScript(eluna, "x = {}; t = type(x)"));
|
|
REQUIRE(fixture.GetGlobalAsString(eluna, "t") == "table");
|
|
}
|
|
|
|
SECTION("Function type is correctly identified")
|
|
{
|
|
REQUIRE(fixture.ExecuteScript(eluna, "function f() end; t = type(f)"));
|
|
REQUIRE(fixture.GetGlobalAsString(eluna, "t") == "function");
|
|
}
|
|
|
|
SECTION("Nil type is correctly identified")
|
|
{
|
|
REQUIRE(fixture.ExecuteScript(eluna, "x = nil; t = type(x)"));
|
|
REQUIRE(fixture.GetGlobalAsString(eluna, "t") == "nil");
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Lua Stack Operations - Complex Types", "[LuaEngine][LuaEngineCore]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("Nested tables are correctly handled")
|
|
{
|
|
std::string script = R"(
|
|
data = {
|
|
level1 = {
|
|
level2 = {
|
|
value = 42
|
|
}
|
|
}
|
|
}
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "data.level1.level2.value") == 42);
|
|
}
|
|
|
|
SECTION("Mixed type tables are correctly handled")
|
|
{
|
|
std::string script = R"(
|
|
mixed = {
|
|
int_val = 42,
|
|
str_val = 'hello',
|
|
bool_val = true
|
|
}
|
|
table_val = {1, 2, 3}
|
|
)";
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "mixed.int_val") == 42);
|
|
REQUIRE(fixture.GetGlobalAsString(eluna, "mixed.str_val") == "hello");
|
|
// Verify the separate array table has correct size
|
|
REQUIRE(fixture.GetTableSize(eluna, "table_val") == 3);
|
|
}
|
|
|
|
SECTION("Array tables are correctly sized")
|
|
{
|
|
REQUIRE(fixture.ExecuteScript(eluna, "arr = {10, 20, 30, 40, 50}"));
|
|
REQUIRE(fixture.GetTableSize(eluna, "arr") == 5);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Lua State Cleanup - State Destruction", "[LuaEngine][LuaEngineCore]")
|
|
{
|
|
SECTION("Eluna instances can be created and destroyed")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
// Scope ends, fixture is destroyed
|
|
}
|
|
|
|
SECTION("Multiple Eluna instances can be created and destroyed")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna1 = fixture.CreateGlobalElunaInstance();
|
|
Eluna* eluna2 = fixture.CreateGlobalElunaInstance();
|
|
Eluna* eluna3 = fixture.CreateGlobalElunaInstance();
|
|
|
|
REQUIRE(eluna1 != nullptr);
|
|
REQUIRE(eluna2 != nullptr);
|
|
REQUIRE(eluna3 != nullptr);
|
|
|
|
// All should be different
|
|
REQUIRE(eluna1 != eluna2);
|
|
REQUIRE(eluna2 != eluna3);
|
|
REQUIRE(eluna1 != eluna3);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Integration - Complete Workflow", "[LuaEngine][LuaEngineCore]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("Complex script with multiple features")
|
|
{
|
|
std::string script = R"(
|
|
-- Define data
|
|
game_state = {
|
|
players = {},
|
|
npcs = {},
|
|
events = {}
|
|
}
|
|
|
|
-- Define functions
|
|
function add_player(name, level)
|
|
table.insert(game_state.players, {name = name, level = level})
|
|
return #game_state.players
|
|
end
|
|
|
|
function get_player_count()
|
|
return #game_state.players
|
|
end
|
|
|
|
-- Execute logic
|
|
add_player('Alice', 50)
|
|
add_player('Bob', 45)
|
|
add_player('Charlie', 55)
|
|
|
|
player_count = get_player_count()
|
|
)";
|
|
|
|
REQUIRE(fixture.ExecuteScript(eluna, script));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "player_count") == 3);
|
|
REQUIRE(fixture.FunctionExists(eluna, "add_player"));
|
|
REQUIRE(fixture.FunctionExists(eluna, "get_player_count"));
|
|
}
|
|
|
|
SECTION("Script with error recovery")
|
|
{
|
|
// First script succeeds
|
|
REQUIRE(fixture.ExecuteScript(eluna, "x = 10"));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "x") == 10);
|
|
|
|
// Second script fails
|
|
REQUIRE(!fixture.ExecuteScript(eluna, "this is invalid"));
|
|
|
|
// Third script succeeds (state is still valid)
|
|
REQUIRE(fixture.ExecuteScript(eluna, "y = 20"));
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "y") == 20);
|
|
|
|
// Original value still exists
|
|
REQUIRE(fixture.GetGlobalAsInt(eluna, "x") == 10);
|
|
}
|
|
}
|