rustploy-gui 0.1.13

Rustploy — desktop client (glacier-ui) for the Rustploy PaaS daemon
--!nonstrict
-- busy.luau envolve handlers globais numa trava: enquanto um roda, a chave
-- `busy_<nome>` do ctx fica "true" e um segundo disparo é descartado. Mexe em
-- `_G` e no global `ctx`, então cada teste usa nomes de handler próprios.

local Busy = require("busy")

local env = _G :: any

local function ambiente()
    env.ctx = {}
    env.toast = function() end
    env.init = nil
end

describe("busy", function()
    test("key monta o nome da chave", function()
        expect(Busy.key("salvar")):toBe("busy_salvar")
    end)

    test("a chave fica true durante o handler e false depois", function()
        ambiente()
        local durante
        env.h_um = function()
            durante = env.ctx.busy_h_um
        end
        Busy.install({ "h_um" })
        env.h_um()
        expect(durante):toBe("true")
        expect(env.ctx.busy_h_um):toBe("false")
    end)

    test("repassa argumentos e valores de retorno", function()
        ambiente()
        env.h_soma = function(a, b)
            return a + b, "ok"
        end
        Busy.install({ "h_soma" })
        local soma, estado = env.h_soma(2, 3)
        expect(soma):toBe(5)
        expect(estado):toBe("ok")
    end)

    test("um segundo disparo durante a execução é descartado", function()
        ambiente()
        local rodadas = 0
        env.h_reentrante = function()
            rodadas += 1
            env.h_reentrante() -- o clique duplo
        end
        Busy.install({ "h_reentrante" })
        env.h_reentrante()
        expect(rodadas):toBe(1)
    end)

    test("depois de terminar, o handler pode rodar de novo", function()
        ambiente()
        local rodadas = 0
        env.h_repete = function()
            rodadas += 1
        end
        Busy.install({ "h_repete" })
        env.h_repete()
        env.h_repete()
        expect(rodadas):toBe(2)
    end)

    test("erro no handler se propaga e mesmo assim solta a trava", function()
        ambiente()
        env.h_quebra = function()
            error("boom", 0)
        end
        Busy.install({ "h_quebra" })
        expect(function()
            env.h_quebra()
        end):toThrow("boom")
        expect(env.ctx.busy_h_quebra):toBe("false")
        -- e não ficou travado: um novo disparo chega a rodar (e quebrar de novo)
        expect(function()
            env.h_quebra()
        end):toThrow("boom")
    end)

    test("toast solta a trava de quem o chamou (a ação já deu o retorno)", function()
        ambiente()
        local depois
        env.h_avisa = function()
            env.toast({ message = "pronto" })
            depois = env.ctx.busy_h_avisa
        end
        Busy.install({ "h_avisa" })
        env.h_avisa()
        expect(depois):toBe("false")
    end)

    test("o toast original continua sendo chamado com as opções", function()
        ambiente()
        local recebido
        env.toast = function(opcoes)
            recebido = opcoes
        end
        env.h_toast = function()
            env.toast({ message = "oi" })
        end
        Busy.install({ "h_toast" })
        env.h_toast()
        expect(recebido.message):toBe("oi")
    end)

    test("init semeia false em todas as chaves e chama o init original", function()
        ambiente()
        local chamado = false
        env.init = function()
            chamado = true
        end
        env.h_a = function() end
        env.h_b = function() end
        Busy.install({ "h_a", "h_b" })
        env.init()
        expect(chamado):toBe(true)
        expect(env.ctx.busy_h_a):toBe("false")
        expect(env.ctx.busy_h_b):toBe("false")
    end)

    test("init funciona mesmo sem um init original", function()
        ambiente()
        env.h_c = function() end
        Busy.install({ "h_c" })
        env.init()
        expect(env.ctx.busy_h_c):toBe("false")
    end)

    test("nome sem função global não ganha trava nem semente", function()
        ambiente()
        env.h_existe = function() end
        env.h_nao_funcao = 42
        Busy.install({ "h_existe", "h_fantasma", "h_nao_funcao" })
        env.init()
        expect(env.ctx.busy_h_existe):toBe("false")
        expect(env.ctx.busy_h_fantasma):toBeNil()
        expect(env.ctx.busy_h_nao_funcao):toBeNil()
        expect(env.h_nao_funcao):toBe(42)
    end)
end)