#include #include #include #include #include #include #include #include #include #include extern "C" { #include "lua_cj_api.h" #include "errors.h" } static std::string create_temp_dir() { char tmpl[] = "/tmp/lua_cj_test_XXXXXX"; char *dir = mkdtemp(tmpl); if (dir == nullptr) { perror("mkdtemp failed"); throw std::runtime_error("Failed to create temp directory"); } return std::string(dir); } static int callback_invoke_count = 0; static int mock_callback() { callback_invoke_count++; return 0; } static std::string get_script_path(const std::string& script_name) { return std::string(SCRIPT_DIR) + "/" + script_name; } class LuaCjApiTest : public ::testing::Test { protected: void* runner; std::string temp_dir; void SetUp() override { temp_dir = create_temp_dir(); callback_invoke_count = 0; runner = init_lua_runner(temp_dir.c_str(), NULL, mock_callback, mock_callback); ASSERT_NE(runner, nullptr) << "init_lua_runner failed, errno=" << get_errno(); } void TearDown() override { if (runner) { free_lua(runner); runner = nullptr; } std::string cmd = "rm -rf " + temp_dir; system(cmd.c_str()); } std::string read_file(const std::string& filename) { std::string path = temp_dir + "/" + filename; std::ifstream t(path); std::string str((std::istreambuf_iterator(t)), std::istreambuf_iterator()); return str; } }; // 基础生命周期测试 TEST_F(LuaCjApiTest, InitFree) { SUCCEED(); } // 测试加载库 TEST_F(LuaCjApiTest, LoadLib) { int ret = load_lib(runner, get_script_path("mylib.lua").c_str(), "mylib"); EXPECT_EQ(ret, 0); } // 测试加载不存在的文件 TEST_F(LuaCjApiTest, LoadLibFileNotFound) { int ret = load_lib(runner, "/no/such/file.lua", "bad"); EXPECT_EQ(ret, -1); EXPECT_EQ(get_errno(), LUAERR_LOAD_FILE); } // 测试超过最大库数量限制 TEST_F(LuaCjApiTest, LoadLibOverflow) { for (int i = 0; i < MAX_LUA_LIB; ++i) { char name[20]; snprintf(name, sizeof(name), "lib%d", i); std::string content = "return " + std::to_string(i); std::string path = temp_dir + "/" + std::string(name) + ".lua"; FILE* f = fopen(path.c_str(), "w"); ASSERT_NE(f, nullptr); fprintf(f, "%s", content.c_str()); fclose(f); int ret = load_lib(runner, path.c_str(), name); EXPECT_EQ(ret, 0); } std::string path = temp_dir + "/extra.lua"; FILE* f = fopen(path.c_str(), "w"); ASSERT_NE(f, nullptr); fprintf(f, "return {}"); fclose(f); int ret = load_lib(runner, path.c_str(), "extra"); EXPECT_EQ(ret, -1); EXPECT_EQ(get_errno(), LUAERR_LIB_OVERFLOW); } // 测试卸载库 TEST_F(LuaCjApiTest, UnloadLib) { ASSERT_EQ(load_lib(runner, get_script_path("mylib.lua").c_str(), "mylib"), 0); int ret = unload_lib(runner, "mylib"); EXPECT_EQ(ret, 0); } // 测试卸载未加载的库 TEST_F(LuaCjApiTest, UnloadLibNotFound) { int ret = unload_lib(runner, "nosuch"); EXPECT_EQ(ret, -1); EXPECT_EQ(get_errno(), LUAERR_UNLOADLIB_FAIL); } // 测试运行脚本 TEST_F(LuaCjApiTest, RunScript) { int ret = run(runner, get_script_path("simple_return.lua").c_str(), nullptr); EXPECT_EQ(ret, 0); char* res = getresult(runner); EXPECT_STREQ(res, "hello"); } // 测试带参数的脚本 TEST_F(LuaCjApiTest, RunScriptWithArg) { int ret = run(runner, get_script_path("args_test.lua").c_str(), "world"); EXPECT_EQ(ret, 0); char* res = getresult(runner); EXPECT_STREQ(res, "world"); } // 测试脚本编译期语法错误按加载错误上报 TEST_F(LuaCjApiTest, RunScriptSyntaxError) { int ret = run(runner, get_script_path("syntax_error.lua").c_str(), NULL); EXPECT_EQ(ret, -1); EXPECT_EQ(get_errno(), LUAERR_LOAD_FILE); char* res = getresult(runner); EXPECT_NE(strstr(res, "'do' expected"), nullptr); } // 测试脚本运行时错误 TEST_F(LuaCjApiTest, RunScriptRuntimeError) { int ret = run(runner, get_script_path("runtime_error.lua").c_str(), nullptr); EXPECT_EQ(ret, -1); EXPECT_EQ(get_errno(), LUAERR_SCRIPT_ERROR); char* res = getresult(runner); EXPECT_NE(strstr(res, "oops"), nullptr); } // 测试 cleanup 重置状态 TEST_F(LuaCjApiTest, Cleanup) { ASSERT_EQ(run(runner, get_script_path("set_global.lua").c_str(), nullptr), 0); int ret = cleanup(runner); EXPECT_EQ(ret, 0); ret = run(runner, get_script_path("get_global.lua").c_str(), nullptr); EXPECT_EQ(ret, 0); char* res = getresult(runner); EXPECT_STREQ(res, "nil"); } // 测试跨调用数据传递 TEST_F(LuaCjApiTest, CrossCallDataPassing) { ASSERT_EQ(run(runner, get_script_path("cross_call_set.lua").c_str(), nullptr), 0); ASSERT_EQ(run(runner, get_script_path("cross_call_get.lua").c_str(), nullptr), 0); char* res = getresult(runner); EXPECT_STREQ(res, "1,2,3"); } // 测试多次加载卸载后栈索引正确 TEST_F(LuaCjApiTest, MultipleLoadUnload) { for (int i = 0; i < 5; ++i) { char name[20]; snprintf(name, sizeof(name), "L%d", i); std::string path = temp_dir + "/" + std::string(name) + ".lua"; FILE* f = fopen(path.c_str(), "w"); ASSERT_NE(f, nullptr); fprintf(f, "return %d", i); fclose(f); ASSERT_EQ(load_lib(runner, path.c_str(), name), 0); } for (int i = 4; i >= 0; --i) { char name[20]; snprintf(name, sizeof(name), "L%d", i); ASSERT_EQ(unload_lib(runner, name), 0); for (int j = 0; j < i; ++j) { char libname[20]; snprintf(libname, sizeof(libname), "L%d", j); std::string script = "return require '" + std::string(libname) + "'"; std::string scriptname = temp_dir + "/check" + std::to_string(j) + ".lua"; FILE* f = fopen(scriptname.c_str(), "w"); ASSERT_NE(f, nullptr); fprintf(f, "%s", script.c_str()); fclose(f); int ret = run(runner, scriptname.c_str(), nullptr); EXPECT_EQ(ret, -1) << "Failed for lib " << libname << " after unloading " << name; if (ret == 0) { char expected[10]; snprintf(expected, sizeof(expected), "%d", j); EXPECT_STREQ(getresult(runner), expected); } } } } // ==================== 新增测试:针对仓颉封装覆盖的功能 ==================== // 测试 I/O 重定向:Print TEST_F(LuaCjApiTest, RedirectPrint) { int ret = run(runner, get_script_path("print_test.lua").c_str(), nullptr); EXPECT_EQ(ret, 0); EXPECT_GT(callback_invoke_count, 0) << "Output callback should be invoked by print"; std::string content = read_file("output"); EXPECT_NE(content.find("Hello Cangjie"), std::string::npos); } // 测试 I/O 重定向:io.write TEST_F(LuaCjApiTest, RedirectIoWrite) { int ret = run(runner, get_script_path("io_write_test.lua").c_str(), nullptr); EXPECT_EQ(ret, 0); EXPECT_GT(callback_invoke_count, 0) << "Output callback should be invoked by io.write"; std::string content = read_file("output"); EXPECT_NE(content.find("Data from lua"), std::string::npos); } // 测试 I/O 重定向:io.read TEST_F(LuaCjApiTest, RedirectIoRead) { std::string input_file = temp_dir + "/input"; FILE* f = fopen(input_file.c_str(), "w"); ASSERT_NE(f, nullptr); fprintf(f, "MockInputData"); fclose(f); int ret = run(runner, get_script_path("io_read_test.lua").c_str(), nullptr); EXPECT_EQ(ret, 0); EXPECT_GT(callback_invoke_count, 0) << "Input callback should be invoked by io.read"; char* res = getresult(runner); EXPECT_STREQ(res, "MockInputData"); } // 测试 pkgpath 配置是否生效,并验证当前实现返回栈顶路径字符串 TEST_F(LuaCjApiTest, PackagePathConfig) { std::string lib_dir = temp_dir + "/mypkgs"; mkdir(lib_dir.c_str(), 0755); std::string lib_path = lib_dir + "/mylib.lua"; FILE* f = fopen(lib_path.c_str(), "w"); fprintf(f, "return 'LoadedViaPkgPath'"); fclose(f); free_lua(runner); runner = nullptr; std::string pkg_path_pattern = lib_dir + "/?.lua"; runner = init_lua_runner(temp_dir.c_str(), pkg_path_pattern.c_str(), mock_callback, mock_callback); ASSERT_NE(runner, nullptr); std::string main_script = temp_dir + "/main.lua"; f = fopen(main_script.c_str(), "w"); fprintf(f, "return require 'mylib'"); fclose(f); int ret = run(runner, main_script.c_str(), nullptr); EXPECT_EQ(ret, 0) << "Require failed, maybe pkgpath not set correctly. Errno: " << get_errno(); char* res = getresult(runner); // 跨版本语义适配: // - Lua 5.3 的 require 返回 1 个值(模块本身),run() 读栈顶得模块返回值 "LoadedViaPkgPath" // - Lua 5.4+ 的 require 返回 2 个值(模块 + loader data),run() 读栈顶得 loader data(文件路径) // 两者都表明 require 经 pkgpath 成功定位并加载了模块 EXPECT_TRUE(strcmp(res, lib_path.c_str()) == 0 || strcmp(res, "LoadedViaPkgPath") == 0) << "unexpected require result: " << (res ? res : "(null)"); } // ==================== 新增测试:doString 功能 ==================== // 测试简单表达式 TEST_F(LuaCjApiTest, DoStringSimple) { int ret = dostring(runner, "return 1 + 1"); EXPECT_EQ(ret, 0); char* res = getresult(runner); EXPECT_STREQ(res, "2"); } // 测试全局变量设置与读取 TEST_F(LuaCjApiTest, DoStringWithGlobal) { int ret = dostring(runner, "g = 42; return g"); EXPECT_EQ(ret, 0); char* res = getresult(runner); EXPECT_STREQ(res, "42"); } // 测试语法错误 TEST_F(LuaCjApiTest, DoStringSyntaxError) { int ret = dostring(runner, "if true then"); EXPECT_EQ(ret, -1); EXPECT_EQ(get_errno(), LUAERR_CALLBACK); char* res = getresult(runner); EXPECT_NE(strstr(res, "'end' expected"), nullptr); } // 测试无返回值 TEST_F(LuaCjApiTest, DoStringNoReturn) { int ret = dostring(runner, "x = 10"); EXPECT_EQ(ret, -1); EXPECT_EQ(get_errno(), LUAERR_SCRIPT_BAD_RET); } // 测试返回 nil TEST_F(LuaCjApiTest, DoStringNilReturn) { int ret = dostring(runner, "return nil"); EXPECT_EQ(ret, -1); EXPECT_EQ(get_errno(), LUAERR_SCRIPT_BAD_RET); } // ==================== loadfunction / callfunction 预加载测试 ==================== // 基础预加载 + 调用 TEST_F(LuaCjApiTest, LoadFunctionAndCall) { int ret = loadfunction(runner, get_script_path("func_add.lua").c_str(), "add"); EXPECT_EQ(ret, 0); ret = callfunction(runner, "add", "hello"); EXPECT_EQ(ret, 0); EXPECT_STREQ(getresult(runner), "result: hello (call #1)"); } // 同一函数多次调用:顶层只执行一次,计数器持续累加 TEST_F(LuaCjApiTest, CallFunctionMultipleTimes) { ASSERT_EQ(loadfunction(runner, get_script_path("func_add.lua").c_str(), "add"), 0); EXPECT_EQ(callfunction(runner, "add", "a"), 0); EXPECT_STREQ(getresult(runner), "result: a (call #1)"); EXPECT_EQ(callfunction(runner, "add", "b"), 0); EXPECT_STREQ(getresult(runner), "result: b (call #2)"); EXPECT_EQ(callfunction(runner, "add", "c"), 0); EXPECT_STREQ(getresult(runner), "result: c (call #3)"); } // 无参函数多次调用 TEST_F(LuaCjApiTest, CallFunctionNoArgMultipleTimes) { ASSERT_EQ(loadfunction(runner, get_script_path("func_multi_call.lua").c_str(), "multi"), 0); for (int i = 0; i < 5; i++) { EXPECT_EQ(callfunction(runner, "multi", NULL), 0); EXPECT_STREQ(getresult(runner), "multi:init-done"); } } // 调用未预加载的函数 TEST_F(LuaCjApiTest, CallFunctionNotFound) { int ret = callfunction(runner, "nonexistent", NULL); EXPECT_EQ(ret, -1); EXPECT_EQ(get_errno(), LUAERR_FUNCTION_NOT_FOUND); } // 预加载不存在的文件 TEST_F(LuaCjApiTest, LoadFunctionFileNotFound) { int ret = loadfunction(runner, "/no/such/file.lua", "bad"); EXPECT_EQ(ret, -1); EXPECT_EQ(get_errno(), LUAERR_LOAD_FILE); } // 预加载顶层未返回函数的文件 TEST_F(LuaCjApiTest, LoadFunctionNotAFunction) { int ret = loadfunction(runner, get_script_path("func_not_a_function.lua").c_str(), "bad"); EXPECT_EQ(ret, -1); EXPECT_EQ(get_errno(), LUAERR_FUNCTION_INVALID); } // 预加载同名函数 TEST_F(LuaCjApiTest, LoadFunctionDuplicate) { ASSERT_EQ(loadfunction(runner, get_script_path("func_add.lua").c_str(), "dup"), 0); int ret = loadfunction(runner, get_script_path("func_add.lua").c_str(), "dup"); EXPECT_EQ(ret, -1); EXPECT_EQ(get_errno(), LUAERR_FUNCTION_NOT_FOUND); } // 运行时错误 TEST_F(LuaCjApiTest, CallFunctionRuntimeError) { ASSERT_EQ(loadfunction(runner, get_script_path("func_runtime_error.lua").c_str(), "bad"), 0); int ret = callfunction(runner, "bad", NULL); EXPECT_EQ(ret, -1); EXPECT_EQ(get_errno(), LUAERR_SCRIPT_ERROR); } // unloadfunction 后再调用应报 5023,且可重新加载 TEST_F(LuaCjApiTest, CallFunctionWithUnloadFunction) { ASSERT_EQ(loadfunction(runner, get_script_path("func_add.lua").c_str(), "add"), 0); EXPECT_EQ(callfunction(runner, "add", "before"), 0); EXPECT_STREQ(getresult(runner), "result: before (call #1)"); EXPECT_EQ(unloadfunction(runner, "add"), 0); int ret = callfunction(runner, "add", NULL); EXPECT_EQ(ret, -1); EXPECT_EQ(get_errno(), LUAERR_FUNCTION_NOT_FOUND); // 卸载后可重新预加载,计数器重置 EXPECT_EQ(loadfunction(runner, get_script_path("func_add.lua").c_str(), "add"), 0); EXPECT_EQ(callfunction(runner, "add", "after"), 0); EXPECT_STREQ(getresult(runner), "result: after (call #1)"); } // 预加载与管道模式共存,互不干扰: // 预加载函数走独立的 funcs[]+Registry,管道走 pkgs[] 栈 TEST_F(LuaCjApiTest, LoadFunctionAndPipelineNoInterference) { // 预加载一个函数(独立于管道栈) ASSERT_EQ(loadfunction(runner, get_script_path("func_add.lua").c_str(), "add"), 0); EXPECT_EQ(callfunction(runner, "add", "x"), 0); EXPECT_STREQ(getresult(runner), "result: x (call #1)"); // 管道模式照常(pkgs 栈) ASSERT_EQ(load_lib(runner, get_script_path("pipeline_add_suffix.lua").c_str(), "add_suffix"), 0); ASSERT_EQ(load_lib(runner, get_script_path("pipeline_to_upper.lua").c_str(), "to_upper"), 0); ASSERT_EQ(load_lib(runner, get_script_path("pipeline_add_prefix.lua").c_str(), "add_prefix"), 0); int ret = run(runner, get_script_path("pipeline_generate_data.lua").c_str(), "hello"); EXPECT_EQ(ret, 0); EXPECT_STREQ(getresult(runner), "hello"); ret = run(runner, nullptr, nullptr); EXPECT_EQ(ret, 0); EXPECT_STREQ(getresult(runner), "[PREFIX] hello"); ret = run(runner, nullptr, nullptr); EXPECT_EQ(ret, 0); EXPECT_STREQ(getresult(runner), "[PREFIX] HELLO"); ret = run(runner, nullptr, nullptr); EXPECT_EQ(ret, 0); EXPECT_STREQ(getresult(runner), "[PREFIX] HELLO [SUFFIX]"); // 管道跑完后,预加载函数仍可调用,计数器继续 EXPECT_EQ(callfunction(runner, "add", "y"), 0); EXPECT_STREQ(getresult(runner), "result: y (call #2)"); } // 预加载数量上限:默认 MAX_LUA_FUNC=20 TEST_F(LuaCjApiTest, LoadFunctionOverflow) { for (int i = 0; i < MAX_LUA_FUNC; i++) { char name[20]; snprintf(name, sizeof(name), "func%d", i); std::string content = "return function() return '" + std::to_string(i) + "' end"; std::string path = temp_dir + "/func" + std::to_string(i) + ".lua"; FILE* f = fopen(path.c_str(), "w"); ASSERT_NE(f, nullptr); fprintf(f, "%s", content.c_str()); fclose(f); int ret = loadfunction(runner, path.c_str(), name); EXPECT_EQ(ret, 0); } // 第 21 个应报 5024 std::string path = temp_dir + "/overflow.lua"; FILE* f = fopen(path.c_str(), "w"); ASSERT_NE(f, nullptr); fprintf(f, "return function() return 'overflow' end"); fclose(f); int ret = loadfunction(runner, path.c_str(), "overflow"); EXPECT_EQ(ret, -1); EXPECT_EQ(get_errno(), LUAERR_FUNC_OVERFLOW); } // cleanup 后预加载函数应失效 TEST_F(LuaCjApiTest, CallFunctionAfterCleanup) { ASSERT_EQ(loadfunction(runner, get_script_path("func_add.lua").c_str(), "add"), 0); EXPECT_EQ(callfunction(runner, "add", "x"), 0); EXPECT_EQ(cleanup(runner), 0); int ret = callfunction(runner, "add", NULL); EXPECT_EQ(ret, -1); EXPECT_EQ(get_errno(), LUAERR_FUNCTION_NOT_FOUND); } // ==================== typed interop 测试(v0.2.2)==================== // 整型参数直通:Lua 收到 integer,返回 integer+1,仓颉侧读回 Int64 TEST_F(LuaCjApiTest, TypedCallInt) { ASSERT_EQ(loadfunction(runner, get_script_path("func_typed_add.lua").c_str(), "inc"), 0); EXPECT_EQ(callfunction_int(runner, "inc", 41), 0); EXPECT_EQ(result_type(runner), CJT_INT); EXPECT_EQ(result_int(runner), 42); // 字符串形式同步可用(向后兼容) EXPECT_STREQ(getresult(runner), "42"); } // 浮点参数直通:返回 number*2.5,读回 Float64 TEST_F(LuaCjApiTest, TypedCallNum) { ASSERT_EQ(loadfunction(runner, get_script_path("func_typed_mul.lua").c_str(), "mul"), 0); EXPECT_EQ(callfunction_num(runner, "mul", 4.0), 0); EXPECT_EQ(result_type(runner), CJT_NUM); EXPECT_DOUBLE_EQ(result_num(runner), 10.0); EXPECT_STREQ(getresult(runner), "10.0"); } // 布尔参数直通:返回逻辑非,读回 Bool TEST_F(LuaCjApiTest, TypedCallBool) { ASSERT_EQ(loadfunction(runner, get_script_path("func_typed_not.lua").c_str(), "lnot"), 0); EXPECT_EQ(callfunction_bool(runner, "lnot", 1), 0); EXPECT_EQ(result_type(runner), CJT_BOOL); EXPECT_EQ(result_bool(runner), 0); EXPECT_STREQ(getresult(runner), "false"); EXPECT_EQ(callfunction_bool(runner, "lnot", 0), 0); EXPECT_EQ(result_type(runner), CJT_BOOL); EXPECT_EQ(result_bool(runner), 1); EXPECT_STREQ(getresult(runner), "true"); } // 无参调用 + 整数返回 TEST_F(LuaCjApiTest, TypedCallVoid) { ASSERT_EQ(loadfunction(runner, get_script_path("func_typed_void.lua").c_str(), "forty_two"), 0); EXPECT_EQ(callfunction_void(runner, "forty_two"), 0); EXPECT_EQ(result_type(runner), CJT_INT); EXPECT_EQ(result_int(runner), 42); } // 回声函数:验证各类型往返保真(类型不丢失) TEST_F(LuaCjApiTest, TypedEchoRoundTrip) { ASSERT_EQ(loadfunction(runner, get_script_path("func_typed_echo.lua").c_str(), "echo"), 0); // int 往返 EXPECT_EQ(callfunction_int(runner, "echo", -123456789LL), 0); EXPECT_EQ(result_type(runner), CJT_INT); EXPECT_EQ(result_int(runner), -123456789LL); // 大整数(超过 double 精确表示范围)往返 EXPECT_EQ(callfunction_int(runner, "echo", 9007199254740993LL), 0); EXPECT_EQ(result_type(runner), CJT_INT); EXPECT_EQ(result_int(runner), 9007199254740993LL); // num 往返 EXPECT_EQ(callfunction_num(runner, "echo", 3.14159), 0); EXPECT_EQ(result_type(runner), CJT_NUM); EXPECT_DOUBLE_EQ(result_num(runner), 3.14159); // bool 往返 EXPECT_EQ(callfunction_bool(runner, "echo", 1), 0); EXPECT_EQ(result_type(runner), CJT_BOOL); EXPECT_EQ(result_bool(runner), 1); // string 往返(走原 callfunction) EXPECT_EQ(callfunction(runner, "echo", "hello typed"), 0); EXPECT_EQ(result_type(runner), CJT_STR); EXPECT_STREQ(getresult(runner), "hello typed"); } // nil 返回值识别 TEST_F(LuaCjApiTest, TypedNilResult) { ASSERT_EQ(loadfunction(runner, get_script_path("func_typed_nil.lua").c_str(), "nilret"), 0); EXPECT_EQ(callfunction_void(runner, "nilret"), 0); EXPECT_EQ(result_type(runner), CJT_NIL); EXPECT_EQ(result_int(runner), 0); EXPECT_EQ(result_bool(runner), 0); } // typed 调用不存在的函数仍报 5023 TEST_F(LuaCjApiTest, TypedCallNotFound) { EXPECT_EQ(callfunction_int(runner, "nonexistent", 1), -1); EXPECT_EQ(get_errno(), LUAERR_FUNCTION_NOT_FOUND); EXPECT_EQ(callfunction_void(runner, "nonexistent"), -1); EXPECT_EQ(get_errno(), LUAERR_FUNCTION_NOT_FOUND); } // runScript 的 typed 变体:args_echo.lua 直接返回入参 TEST_F(LuaCjApiTest, TypedRunVariants) { std::string path = temp_dir + "/args_echo.lua"; FILE* f = fopen(path.c_str(), "w"); ASSERT_NE(f, nullptr); fprintf(f, "return (...)"); fclose(f); // int EXPECT_EQ(run_int(runner, path.c_str(), 777), 0); EXPECT_EQ(result_type(runner), CJT_INT); EXPECT_EQ(result_int(runner), 777); // num EXPECT_EQ(run_num(runner, path.c_str(), 2.5), 0); EXPECT_EQ(result_type(runner), CJT_NUM); EXPECT_DOUBLE_EQ(result_num(runner), 2.5); // bool EXPECT_EQ(run_bool(runner, path.c_str(), 1), 0); EXPECT_EQ(result_type(runner), CJT_BOOL); EXPECT_EQ(result_bool(runner), 1); // 无参(无返回时栈顶为空,reslt 应为 "nil") std::string void_path = temp_dir + "/no_return.lua"; f = fopen(void_path.c_str(), "w"); ASSERT_NE(f, nullptr); fprintf(f, "local x = 1"); fclose(f); EXPECT_EQ(run_void(runner, void_path.c_str()), 0); EXPECT_EQ(result_type(runner), CJT_NIL); } // typed 与字符串 API 混用互不干扰;typed 结果同步到字符串缓冲区 TEST_F(LuaCjApiTest, TypedAndStringCoexist) { ASSERT_EQ(loadfunction(runner, get_script_path("func_add.lua").c_str(), "add"), 0); ASSERT_EQ(loadfunction(runner, get_script_path("func_typed_add.lua").c_str(), "inc"), 0); // 字符串 API EXPECT_EQ(callfunction(runner, "add", "a"), 0); EXPECT_STREQ(getresult(runner), "result: a (call #1)"); EXPECT_EQ(result_type(runner), CJT_STR); // typed API EXPECT_EQ(callfunction_int(runner, "inc", 100), 0); EXPECT_EQ(result_int(runner), 101); // 字符串函数的计数器不受影响 EXPECT_EQ(callfunction(runner, "add", "b"), 0); EXPECT_STREQ(getresult(runner), "result: b (call #2)"); } // cleanup 后 typed 状态重置为 NIL TEST_F(LuaCjApiTest, TypedStateAfterCleanup) { ASSERT_EQ(loadfunction(runner, get_script_path("func_typed_void.lua").c_str(), "v"), 0); EXPECT_EQ(callfunction_void(runner, "v"), 0); EXPECT_EQ(result_type(runner), CJT_INT); EXPECT_EQ(cleanup(runner), 0); int ret = callfunction_void(runner, "v"); EXPECT_EQ(ret, -1); EXPECT_EQ(get_errno(), LUAERR_FUNCTION_NOT_FOUND); } int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }