mirror of
https://github.com/araxiaonline/TrinityCore.git
synced 2026-06-13 11:43:18 -04:00
591 lines
17 KiB
C++
591 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"
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
extern "C"
|
|
{
|
|
#include "lua.h"
|
|
#include "lauxlib.h"
|
|
#include "lualib.h"
|
|
}
|
|
|
|
/**
|
|
* @brief Mock ChatHandler for testing console commands
|
|
*
|
|
* Captures all messages sent through the handler for verification
|
|
*/
|
|
class MockChatHandler
|
|
{
|
|
private:
|
|
std::vector<std::string> messages;
|
|
bool lastCommandResult = false;
|
|
|
|
public:
|
|
MockChatHandler() = default;
|
|
~MockChatHandler() = default;
|
|
|
|
/**
|
|
* @brief Send a system message (mimics ChatHandler::SendSysMessage)
|
|
*/
|
|
void SendSysMessage(const char* msg)
|
|
{
|
|
if (msg)
|
|
messages.push_back(msg);
|
|
}
|
|
|
|
/**
|
|
* @brief Send a formatted message (mimics ChatHandler::PSendSysMessage)
|
|
*/
|
|
void PSendSysMessage(const char* format, ...)
|
|
{
|
|
char buffer[1024];
|
|
va_list args;
|
|
va_start(args, format);
|
|
vsnprintf(buffer, sizeof(buffer), format, args);
|
|
va_end(args);
|
|
messages.push_back(buffer);
|
|
}
|
|
|
|
/**
|
|
* @brief Get all captured messages
|
|
*/
|
|
const std::vector<std::string>& GetMessages() const { return messages; }
|
|
|
|
/**
|
|
* @brief Get the last message
|
|
*/
|
|
std::string GetLastMessage() const
|
|
{
|
|
return messages.empty() ? "" : messages.back();
|
|
}
|
|
|
|
/**
|
|
* @brief Clear all captured messages
|
|
*/
|
|
void ClearMessages() { messages.clear(); }
|
|
|
|
/**
|
|
* @brief Check if a specific message was sent
|
|
*/
|
|
bool HasMessage(const std::string& msg) const
|
|
{
|
|
for (const auto& m : messages)
|
|
{
|
|
if (m.find(msg) != std::string::npos)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @brief Get message count
|
|
*/
|
|
size_t GetMessageCount() const { return messages.size(); }
|
|
};
|
|
|
|
/**
|
|
* @brief Helper function to simulate the Lua command handler
|
|
*
|
|
* This mimics the HandleLuaCommand function from cs_lua.cpp
|
|
* Works with lua_State pointers cast as Eluna* for testing
|
|
*/
|
|
bool SimulateLuaCommand(MockChatHandler& handler, Eluna* eluna, const char* args)
|
|
{
|
|
if (!args || !*args)
|
|
{
|
|
handler.SendSysMessage("Usage: .lua <code>");
|
|
return false;
|
|
}
|
|
|
|
if (!eluna)
|
|
{
|
|
handler.SendSysMessage("Eluna is not initialized.");
|
|
return false;
|
|
}
|
|
|
|
// In tests, eluna is actually a lua_State* cast to Eluna*
|
|
lua_State* L = reinterpret_cast<lua_State*>(eluna);
|
|
if (!L)
|
|
{
|
|
handler.SendSysMessage("Eluna is not initialized.");
|
|
return false;
|
|
}
|
|
|
|
int err = luaL_dostring(L, args);
|
|
|
|
if (err)
|
|
{
|
|
const char* errMsg = lua_tostring(L, -1);
|
|
handler.SendSysMessage(errMsg ? errMsg : "Unknown error");
|
|
lua_pop(L, 1);
|
|
return false;
|
|
}
|
|
|
|
// Check if there's a return value
|
|
if (lua_gettop(L) > 0)
|
|
{
|
|
if (lua_isstring(L, -1))
|
|
{
|
|
handler.SendSysMessage(lua_tostring(L, -1));
|
|
}
|
|
else if (lua_isnumber(L, -1))
|
|
{
|
|
char buffer[64];
|
|
snprintf(buffer, sizeof(buffer), "%g", lua_tonumber(L, -1));
|
|
handler.SendSysMessage(buffer);
|
|
}
|
|
else if (lua_isboolean(L, -1))
|
|
{
|
|
handler.SendSysMessage(lua_toboolean(L, -1) ? "true" : "false");
|
|
}
|
|
else if (lua_isnil(L, -1))
|
|
{
|
|
handler.SendSysMessage("nil");
|
|
}
|
|
else
|
|
{
|
|
handler.SendSysMessage("Executed successfully");
|
|
}
|
|
lua_pop(L, 1);
|
|
}
|
|
else
|
|
{
|
|
handler.SendSysMessage("Executed successfully");
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// ============================================================================
|
|
// TEST CASES
|
|
// ============================================================================
|
|
|
|
TEST_CASE("Lua Command - Basic String Output", "[LuaEngine][LuaCommand]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("Simple print statement")
|
|
{
|
|
MockChatHandler handler;
|
|
// Note: print() writes to stdout, not captured by handler
|
|
// Instead test with return value
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "return 'Hello, Eluna!'"));
|
|
REQUIRE(handler.HasMessage("Hello, Eluna!"));
|
|
}
|
|
|
|
SECTION("Return string value")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "return 'test string'"));
|
|
REQUIRE(handler.HasMessage("test string"));
|
|
}
|
|
|
|
SECTION("Concatenated string")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "return 'Hello' .. ' ' .. 'World'"));
|
|
REQUIRE(handler.HasMessage("Hello World"));
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Lua Command - Numeric Output", "[LuaEngine][LuaCommand]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("Simple integer return")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "return 42"));
|
|
REQUIRE(handler.HasMessage("42"));
|
|
}
|
|
|
|
SECTION("Arithmetic operation")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "return 2 + 2"));
|
|
REQUIRE(handler.HasMessage("4"));
|
|
}
|
|
|
|
SECTION("Float calculation")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "return 3.14 * 2"));
|
|
REQUIRE(handler.HasMessage("6.28"));
|
|
}
|
|
|
|
SECTION("Complex arithmetic")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "return (10 + 5) * 2 - 3"));
|
|
REQUIRE(handler.HasMessage("27"));
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Lua Command - Boolean Output", "[LuaEngine][LuaCommand]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("Return true")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "return true"));
|
|
REQUIRE(handler.HasMessage("true"));
|
|
}
|
|
|
|
SECTION("Return false")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "return false"));
|
|
REQUIRE(handler.HasMessage("false"));
|
|
}
|
|
|
|
SECTION("Boolean comparison")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "return 5 > 3"));
|
|
REQUIRE(handler.HasMessage("true"));
|
|
}
|
|
|
|
SECTION("Boolean comparison false")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "return 5 < 3"));
|
|
REQUIRE(handler.HasMessage("false"));
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Lua Command - Nil Output", "[LuaEngine][LuaCommand]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("Return nil")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "return nil"));
|
|
REQUIRE(handler.HasMessage("nil"));
|
|
}
|
|
|
|
SECTION("No return value")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "x = 5"));
|
|
REQUIRE(handler.HasMessage("Executed successfully"));
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Lua Command - Variable Assignment", "[LuaEngine][LuaCommand]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("Assign and retrieve integer")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "myvar = 100"));
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "return myvar"));
|
|
REQUIRE(handler.HasMessage("100"));
|
|
}
|
|
|
|
SECTION("Assign and retrieve string")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "mystring = 'stored value'"));
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "return mystring"));
|
|
REQUIRE(handler.HasMessage("stored value"));
|
|
}
|
|
|
|
SECTION("Multiple assignments")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "a = 10; b = 20; return a + b"));
|
|
REQUIRE(handler.HasMessage("30"));
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Lua Command - Function Definition and Calling", "[LuaEngine][LuaCommand]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("Define and call simple function")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "function add(a, b) return a + b end"));
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "return add(5, 3)"));
|
|
REQUIRE(handler.HasMessage("8"));
|
|
}
|
|
|
|
SECTION("Define function with string return")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "function greet(name) return 'Hello, ' .. name end"));
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "return greet('World')"));
|
|
REQUIRE(handler.HasMessage("Hello, World"));
|
|
}
|
|
|
|
SECTION("Recursive function")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "function factorial(n) if n <= 1 then return 1 else return n * factorial(n-1) end end"));
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "return factorial(5)"));
|
|
REQUIRE(handler.HasMessage("120"));
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Lua Command - Table Operations", "[LuaEngine][LuaCommand]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("Create and access table")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "t = {1, 2, 3}; return t[1]"));
|
|
REQUIRE(handler.HasMessage("1"));
|
|
}
|
|
|
|
SECTION("Table with named fields")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "t = {name='test', value=42}; return t.name"));
|
|
REQUIRE(handler.HasMessage("test"));
|
|
}
|
|
|
|
SECTION("Table length")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "t = {10, 20, 30}; return #t"));
|
|
REQUIRE(handler.HasMessage("3"));
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Lua Command - Control Flow", "[LuaEngine][LuaCommand]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("If statement true branch")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "if 5 > 3 then return 'yes' else return 'no' end"));
|
|
REQUIRE(handler.HasMessage("yes"));
|
|
}
|
|
|
|
SECTION("If statement false branch")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "if 5 < 3 then return 'yes' else return 'no' end"));
|
|
REQUIRE(handler.HasMessage("no"));
|
|
}
|
|
|
|
SECTION("For loop")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "sum = 0; for i=1,5 do sum = sum + i end; return sum"));
|
|
REQUIRE(handler.HasMessage("15"));
|
|
}
|
|
|
|
SECTION("While loop")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "i = 0; while i < 5 do i = i + 1 end; return i"));
|
|
REQUIRE(handler.HasMessage("5"));
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Lua Command - Error Handling", "[LuaEngine][LuaCommand]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("Syntax error")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(!SimulateLuaCommand(handler, eluna, "return 5 +"));
|
|
REQUIRE((handler.HasMessage("syntax error") || handler.HasMessage("unexpected")));
|
|
}
|
|
|
|
SECTION("Undefined variable returns nil")
|
|
{
|
|
MockChatHandler handler;
|
|
// In Lua, undefined variables return nil, not an error
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "return undefined_var"));
|
|
REQUIRE(handler.HasMessage("nil"));
|
|
}
|
|
|
|
SECTION("Type mismatch in operation")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(!SimulateLuaCommand(handler, eluna, "return 'string' + 5"));
|
|
REQUIRE((handler.HasMessage("attempt") || handler.HasMessage("error")));
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Lua Command - Empty and Invalid Input", "[LuaEngine][LuaCommand]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("Empty command")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(!SimulateLuaCommand(handler, eluna, ""));
|
|
REQUIRE(handler.HasMessage("Usage"));
|
|
}
|
|
|
|
SECTION("Null command")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(!SimulateLuaCommand(handler, eluna, nullptr));
|
|
REQUIRE(handler.HasMessage("Usage"));
|
|
}
|
|
|
|
SECTION("Whitespace only")
|
|
{
|
|
MockChatHandler handler;
|
|
// Whitespace-only is valid Lua (empty statement), so it should succeed
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, " "));
|
|
REQUIRE(handler.HasMessage("Executed successfully"));
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Lua Command - Complex Expressions", "[LuaEngine][LuaCommand]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("String manipulation")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "return string.upper('hello')"));
|
|
REQUIRE(handler.HasMessage("HELLO"));
|
|
}
|
|
|
|
SECTION("Table iteration")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "t = {1,2,3}; sum = 0; for _,v in ipairs(t) do sum = sum + v end; return sum"));
|
|
REQUIRE(handler.HasMessage("6"));
|
|
}
|
|
|
|
SECTION("Nested function calls")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "function f(x) return x * 2 end; function g(x) return f(x) + 1 end; return g(5)"));
|
|
REQUIRE(handler.HasMessage("11"));
|
|
}
|
|
|
|
SECTION("Ternary-like operation")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "x = 10; return x > 5 and 'big' or 'small'"));
|
|
REQUIRE(handler.HasMessage("big"));
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Lua Command - State Persistence", "[LuaEngine][LuaCommand]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("Variable persists across commands")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "global_var = 'persistent'"));
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "return global_var"));
|
|
REQUIRE(handler.HasMessage("persistent"));
|
|
}
|
|
|
|
SECTION("Function persists across commands")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "function my_func() return 'stored' end"));
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "return my_func()"));
|
|
REQUIRE(handler.HasMessage("stored"));
|
|
}
|
|
|
|
SECTION("Table persists across commands")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "my_table = {a=1, b=2}"));
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "return my_table.a + my_table.b"));
|
|
REQUIRE(handler.HasMessage("3"));
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Lua Command - Edge Cases", "[LuaEngine][LuaCommand]")
|
|
{
|
|
LuaEngineTestFixture fixture;
|
|
Eluna* eluna = fixture.CreateGlobalElunaInstance();
|
|
REQUIRE(eluna != nullptr);
|
|
|
|
SECTION("Very large number")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "return 999999999999"));
|
|
REQUIRE((handler.HasMessage("999999999999") || handler.HasMessage("1e+12")));
|
|
}
|
|
|
|
SECTION("Negative number")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "return -42"));
|
|
REQUIRE(handler.HasMessage("-42"));
|
|
}
|
|
|
|
SECTION("Zero")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "return 0"));
|
|
REQUIRE(handler.HasMessage("0"));
|
|
}
|
|
|
|
SECTION("Empty string")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "return ''"));
|
|
REQUIRE(handler.GetLastMessage() == "");
|
|
}
|
|
|
|
SECTION("Special characters in string")
|
|
{
|
|
MockChatHandler handler;
|
|
REQUIRE(SimulateLuaCommand(handler, eluna, "return 'Hello\\nWorld'"));
|
|
REQUIRE((handler.HasMessage("Hello") || handler.HasMessage("World")));
|
|
}
|
|
}
|