Files
gen1recomp/tests/engine/shaderfx_ffi_c_fallback.lua
T
bryanthaboi d622e83a8e shaderfix
2026-08-25 09:16:59 -04:00

86 lines
3.1 KiB
Lua

package.path = "./?.lua;./?/init.lua;" .. package.path
local T = require("tests.harness")
love = love or require("tests.love_stub")
local NAME = "src.render.ShaderFX"
local function withFfi(fakeFfi, os, fn)
local oldModule = package.loaded[NAME]
local oldFfi = package.loaded.ffi
local oldPreload = package.preload.ffi
local oldGetOS = love.system.getOS
if os then love.system.getOS = function() return os end end
package.loaded[NAME] = nil
package.loaded.ffi = nil
package.preload.ffi = function() return fakeFfi end
local ShaderFX = require(NAME)
local can, err = ShaderFX.canConvert(), ShaderFX.bridgeError()
if fn then fn(ShaderFX) end
package.loaded[NAME] = oldModule
package.loaded.ffi = oldFfi
package.preload.ffi = oldPreload
love.system.getOS = oldGetOS
return can, err, ShaderFX
end
local function baseFfi()
return {
cdef = function() end,
load = function() error("no such library") end,
string = function(value) return value end,
}
end
local staticFfi = baseFfi()
staticFfi.C = {
librashader_translate_preset = function() return "{}" end,
librashader_free_string = function() end,
}
local can, err = withFfi(staticFfi)
T.eq(can, true, "a statically linked bridge is found through ffi.C")
T.eq(err, nil, "the ffi.C fallback leaves no bridge error behind")
local emptyFfi = baseFfi()
emptyFfi.C = setmetatable({}, {
__index = function() error("undefined symbol") end,
})
local missing, missingErr = withFfi(emptyFfi)
T.eq(missing, false, "no library and no ffi.C symbol means no conversion")
T.check(missingErr and missingErr:find("ffi.C has no librashader_translate_preset", 1, true) ~= nil,
"libError says ffi.C was probed too (got " .. tostring(missingErr) .. ")")
T.check(missingErr and missingErr:find("looked in", 1, true) ~= nil,
"libError still lists the paths that were tried")
local iosMissing, iosErr = withFfi(baseFfi(), "iOS")
T.eq(iosMissing, false, "iOS with no static symbol cannot convert")
T.check(iosErr and iosErr:find("ffi.C has no librashader_translate_preset", 1, true) ~= nil,
"iOS libError names the ffi.C probe")
T.check(iosErr and iosErr:find("looked in", 1, true) == nil,
"iOS lists no file candidates (got " .. tostring(iosErr) .. ")")
local iosCan = withFfi(staticFfi, "iOS")
T.eq(iosCan, true, "iOS resolves the bridge through ffi.C alone")
local freed = false
local translateFfi = baseFfi()
translateFfi.C = {
librashader_translate_preset = function(path, es)
return ('{"pass_count":1,"passes":[{"name":"%s","es":%d}]}'):format(path, es)
end,
librashader_free_string = function() freed = true end,
}
withFfi(translateFfi, "iOS", function(ShaderFX)
local preset, terr = ShaderFX.translate("/presets/a.slangp", true)
T.check(preset ~= nil, "translate works with lib == ffi.C (" .. tostring(terr) .. ")")
T.eq(preset and preset.passes[1].name, "/presets/a.slangp",
"the ffi.C symbol receives the preset path")
T.eq(preset and preset.passes[1].es, 1, "the es flag reaches the ffi.C symbol")
T.eq(freed, true, "the returned string is freed through ffi.C")
end)
T.finish("shaderfx ffi.C fallback")