-- Regression test for (tarantool.lua_package) file option. -- -- The option lives on FileOptions as extension field 60001 and overrides -- the default `._pb` Lua require path. The plugin parses the -- extension via protoreflect/protoregistry, so this test guards against -- the option silently becoming a no-op when the extension is not -- registered in the global type registry (the failure mode is that -- proto.GetExtension returns "" and the override is lost). -- -- Coverage: -- * The on-disk output path follows `lua_package`, not `/_pb`. -- * Cross-file `import "other.proto"` rewrites to `require("")`. local t = require('luatest') local fio = require('fio') local g = t.group('codegen_lua_package') local REPO_ROOT = fio.abspath(fio.pathjoin( fio.dirname(debug.getinfo(1, 'S').source:sub(2)), '..')) local OPTIONS_DIR = fio.pathjoin(REPO_ROOT, 'options') local PLUGIN = fio.pathjoin(REPO_ROOT, 'protoc-gen-tarantool') local function spit(path, content) local f = assert(io.open(path, 'wb')) f:write(content) f:close() end local function slurp(path) local f = assert(io.open(path, 'rb')) local s = f:read('*a') f:close() return s end local function ensure_plugin() if fio.path.exists(PLUGIN) then return end local cmd = string.format('cd %q && go build -o %s ./cmd/protoc-gen-tarantool', REPO_ROOT, fio.basename(PLUGIN)) assert(os.execute(cmd) == 0 or os.execute(cmd) == true, 'failed to build plugin: ' .. cmd) end local SAMPLE_PROTO = [[ syntax = "proto3"; package sample; import "tarantool/tarantool.proto"; option (tarantool.lua_package) = "myapp.proto.sample"; message Foo { int32 x = 1; } ]] local OTHER_PROTO = [[ syntax = "proto3"; package other; import "tarantool/tarantool.proto"; import "sample.proto"; option (tarantool.lua_package) = "myapp.proto.other"; message Bar { sample.Foo foo = 1; } ]] local function run_plugin(mode) local tmp = fio.tempdir() local proto_dir = fio.pathjoin(tmp, 'proto') local out_dir = fio.pathjoin(tmp, 'out') assert(fio.mkdir(proto_dir)) assert(fio.mkdir(out_dir)) spit(fio.pathjoin(proto_dir, 'sample.proto'), SAMPLE_PROTO) spit(fio.pathjoin(proto_dir, 'other.proto'), OTHER_PROTO) local cmd = string.format( 'protoc --plugin=%q --tarantool_out=%q --tarantool_opt=mode=%s ' ..'-I %q -I %q %q %q', PLUGIN, out_dir, mode, proto_dir, OPTIONS_DIR, fio.pathjoin(proto_dir, 'sample.proto'), fio.pathjoin(proto_dir, 'other.proto')) local ok = os.execute(cmd) assert(ok == 0 or ok == true, 'plugin failed: ' .. cmd) return out_dir end g.before_all(function() ensure_plugin() end) for _, mode in ipairs({'full', 'runtime'}) do g['test_output_path_honors_lua_package_'..mode] = function() local out = run_plugin(mode) t.assert(fio.path.exists(fio.pathjoin(out, 'myapp', 'proto', 'sample.lua')), 'expected sample.lua under lua_package path, got: ' .. table.concat(fio.glob(fio.pathjoin(out, '**', '*.lua')) or {}, ', ')) t.assert(fio.path.exists(fio.pathjoin(out, 'myapp', 'proto', 'other.lua')), 'expected other.lua under lua_package path') -- Default `/_pb.lua` layout must NOT be present — -- that's the regression signature (extension dropped, fallback used). t.assert_not(fio.path.exists(fio.pathjoin(out, 'sample', 'sample_pb.lua')), 'fallback path was emitted — lua_package option was ignored') end g['test_cross_file_require_honors_lua_package_'..mode] = function() local out = run_plugin(mode) local body = slurp(fio.pathjoin(out, 'myapp', 'proto', 'other.lua')) t.assert_str_contains(body, 'require("myapp.proto.sample")', false, 'cross-file import should resolve via lua_package, not the default path') t.assert_not(string.find(body, 'require("sample.sample_pb")', 1, true), 'default require path leaked into cross-file import') end end