package luarunner import std.unittest.* import std.fs.* let scriptsDir = "./test/scripts" let generatedScriptsDir = "./test/generated_scripts" func scriptPath(name: String): String { scriptsDir + "/" + name } func generatedScriptPath(name: String): String { generatedScriptsDir + "/" + name } func ensureGeneratedScriptsDir(): Unit { let dir = Path(generatedScriptsDir) if (!exists(dir)) { Directory.create(dir, recursive: true) } } // ==================== // 1. 基础运行与参数测试 // ==================== @Test func testRunScript(): Unit { let runner = LuaRunner() let path = scriptPath("simple_return.lua") let res = runner.runScript(path, "") @Expect(res, "hello") } @Test func testRunScriptWithArg(): Unit { let runner = LuaRunner() let path = scriptPath("args_test.lua") let res = runner.runScript(path, "world") @Expect(res, "world") } // ==================== // 2. 异常处理测试 // ==================== @Test func testRunScriptSyntaxError(): Unit { let runner = LuaRunner() let path = scriptPath("syntax_error.lua") try { runner.runScript(path, "") fail("Should throw syntax error") } catch (e: LuaError) { @Expect(e.code, 5010) } } @Test func testRunScriptRuntimeError(): Unit { let runner = LuaRunner() let path = scriptPath("runtime_error.lua") try { runner.runScript(path, "") fail("Should throw runtime error") } catch (e: LuaError) { @Expect(e.code, 5010) } } // ==================== // 3. 库加载测试 // ==================== @Test func testLoadLib(): Unit { let runner = LuaRunner() let path = scriptPath("mylib.lua") runner.load(path, "mylib") } @Test func testLoadLibFileNotFound(): Unit { let runner = LuaRunner() try { runner.load("/no/such/file.lua", "badlib") fail("Should throw file not found error") } catch (e: LuaError) { @Expect(e.code, 5003) } } @Test func testUnloadLib(): Unit { let runner = LuaRunner() let path = scriptPath("mylib.lua") runner.load(path, "mylib") runner.unload("mylib") } @Test func testUnloadLibNotFound(): Unit { let runner = LuaRunner() try { runner.unload("nosuchlib") fail("Should throw exception") } catch (e: LuaError) { @Expect(e.code, 5012) } } // ==================== // 4. 状态管理与数据交互 // ==================== @Test func testCleanup(): Unit { let runner = LuaRunner() let setPath = scriptPath("set_global.lua") let getPath = scriptPath("get_global.lua") runner.runScript(setPath, "") runner.clear() let res = runner.runScript(getPath, "") @Expect(res, "nil") } @Test func testCrossCallDataPassing(): Unit { let runner = LuaRunner() let setPath = scriptPath("cross_call_set.lua") let getPath = scriptPath("cross_call_get.lua") runner.runScript(setPath, "") let res = runner.runScript(getPath, "") @Expect(res, "1,2,3") } @Test func testPipelineDocumentedFlow(): Unit { let runner = LuaRunner() runner.load(scriptPath("pipeline_add_suffix.lua"), "add_suffix") .load(scriptPath("pipeline_to_upper.lua"), "to_upper") .load(scriptPath("pipeline_add_prefix.lua"), "add_prefix") let initialData = runner.runScript(scriptPath("pipeline_generate_data.lua"), "hello") @Expect(initialData, "hello") let afterA = runner.runScript("", "") @Expect(afterA, "[PREFIX] hello") let afterB = runner.runScript("", "") @Expect(afterB, "[PREFIX] HELLO") let finalResult = runner.runScript("", "") @Expect(finalResult, "[PREFIX] HELLO [SUFFIX]") } @Test func testPipelineStepByStepResults(): Unit { let runner = LuaRunner() runner.load(scriptPath("pipeline_add_suffix.lua"), "add_suffix") .load(scriptPath("pipeline_to_upper.lua"), "to_upper") .load(scriptPath("pipeline_add_prefix.lua"), "add_prefix") let initialData = runner.runScript(scriptPath("pipeline_generate_data.lua"), "hello") @Expect(initialData, "hello") let afterPrefix = runner.runScript("", "") @Expect(afterPrefix, "[PREFIX] hello") let afterUpper = runner.runScript("", "") @Expect(afterUpper, "[PREFIX] HELLO") let afterSuffix = runner.runScript("", "") @Expect(afterSuffix, "[PREFIX] HELLO [SUFFIX]") } @Test func testLoadLibOverflow(): Unit { ensureGeneratedScriptsDir() let runner = LuaRunner() for (i in 0..20) { let name = "overflow_lib_${i}" let path = generatedScriptPath(name + ".lua") File.writeTo(path, ("return \"" + name + "\"").toArray()) runner.load(path, name) } let overflowName = "overflow_lib_20" let overflowPath = generatedScriptPath(overflowName + ".lua") File.writeTo(overflowPath, "return \"overflow\"".toArray()) try { runner.load(overflowPath, overflowName) fail("Should throw overflow error") } catch (e: LuaError) { @Expect(e.code, 5016) } } @Test func testPackagePathConfig(): Unit { let runner = LuaRunner(pkgpath: scriptsDir + "/pkgmods/?.lua") let res = runner.runScript(scriptPath("pkgpath_require_mylib.lua"), "") @Expect(res, "LoadedViaPkgPath") } @Test func testPackagePathInitLuaPattern(): Unit { let runner = LuaRunner(pkgpath: scriptsDir + "/pkgmods_init/?/init.lua") let res = runner.runScript(scriptPath("pkgpath_require_nested.lua"), "") @Expect(res, "LoadedViaInit") } // ==================== // 5. I/O 重定向测试 // ==================== @Test func testRedirectPrint(): Unit { let runner = LuaRunner(pathio: "/tmp") let path = scriptPath("print_test.lua") runner.runScript(path, "") } @Test func testRedirectIoWrite(): Unit { let runner = LuaRunner(pathio: "/tmp") let path = scriptPath("io_write_test.lua") runner.runScript(path, "") } @Test func testRedirectIoRead(): Unit { // 1. 准备输入文件 let inputFile = "/tmp/input" // [修正点]:移除了不存在的 option 参数。 // File.writeTo 默认行为即为 CreateOrTruncate: // 文件存在会截断(覆盖),不存在则创建。 File.writeTo(inputFile, "MockInputData".toArray()) // 2. 运行测试 let runner = LuaRunner(pathio: "/tmp") let path = scriptPath("io_read_test.lua") let res = runner.runScript(path, "") @Expect(res, "MockInputData") } // ==================== // 6. 错误码与回调 // ==================== @Test func testErrorCodesMapping(): Unit { @Expect(LuaError.getErrorMessage(5001), "JSON file load failed") @Expect(LuaError.getErrorMessage(5002), "Memory allocation failed") @Expect(LuaError.getErrorMessage(5010), "Script internal error, check result for details") @Expect(LuaError.getErrorMessage(9999), "Unknown error") } @Test func testDefaultIOCallback(): Unit { let result = unsafe { defaultIO() } @Expect(result, 0) }