rustploy-gui 0.1.53

Rustploy — desktop client (glacier-ui) for the Rustploy PaaS daemon
--!nonstrict
local H = require("helpers")

--- apara as pontas e aceita nil e não-texto
function test_trim__apara_as_pontas_e_aceita_nil_e_nao_texto()
    assert_eq(H.trim("  oi  "), "oi")
    assert_eq(H.trim(nil), "")
    assert_eq(H.trim(42), "42")
    assert_eq(H.trim("a b"), "a b")
end

--- aceita <secret:x> e secret:x
function test_referencia_a_segredo__aceita_secret_x_e_secret_x()
    assert_eq(H.parse_secret_ref("<secret:DB_PASS>"), "DB_PASS")
    assert_eq(H.parse_secret_ref("  secret:TOKEN  "), "TOKEN")
    assert_eq(H.parse_secret_ref("<secret: espaço >"), "espaço")
end

--- o que não é referência devolve nil
function test_referencia_a_segredo__o_que_nao_e_referencia_devolve_nil()
    assert_nil(H.parse_secret_ref("valor comum"))
    assert_nil(H.parse_secret_ref("<secret:>"))
    assert_nil(H.parse_secret_ref("secret:   "))
    assert_nil(H.parse_secret_ref(nil))
end

--- separa chaves, valores e segredos
function test_env__separa_chaves_valores_e_segredos()
    local vars = H.parse_dotenv("A=1\nB = dois \nC=<secret:SEG>\n")
    assert_eq(#vars, 3)
    assert_eq(vars[1].key, "A")
    assert_eq(vars[1].value.Plain, "1")
    assert_eq(vars[2].key, "B")
    assert_eq(vars[2].value.Plain, "dois")
    assert_eq(vars[3].value.Secret, "SEG")
end

--- o valor pode conter =
function test_env__o_valor_pode_conter()
    local vars = H.parse_dotenv("URL=postgres://u:p@h/db?x=1")
    assert_eq(vars[1].value.Plain, "postgres://u:p@h/db?x=1")
end

--- comentários ficam ligados à chave que vem depois
function test_env__comentarios_ficam_ligados_a_chave_que_vem_depois()
    local vars, comments =
        H.parse_dotenv("# banco\n# principal\nDB=1\nOUTRA=2")
    assert_eq(#vars, 2)
    assert_eq(#comments, 2)
    assert_eq(comments[1].text, "# banco")
    assert_eq(comments[1].before_key, "DB")
    assert_eq(comments[2].before_key, "DB")
end

--- comentário no fim não tem chave seguinte
function test_env__comentario_no_fim_nao_tem_chave_seguinte()
    local _, comments = H.parse_dotenv("A=1\n# sobra")
    assert_eq(#comments, 1)
    assert_nil(comments[1].before_key)
end

--- linhas vazias e sem = são ignoradas
function test_env__linhas_vazias_e_sem_sao_ignoradas()
    local vars = H.parse_dotenv("\n\nsem igual\n=semchave\nOK=1")
    assert_eq(#vars, 1)
    assert_eq(vars[1].key, "OK")
end

--- o que não pôde ser lido vem em errors, com o número da linha
function test_env__linha_ruim_vira_erro_com_numero_da_linha()
    local vars, _, errors =
        H.parse_dotenv("OK=1\nsem igual\n=semchave\n1ABC=x\nA B=y")
    assert_eq(#vars, 1)
    assert_eq(#errors, 4)
    assert_eq(string.find(errors[1], "line 2", 1, true) ~= nil, true)
    assert_eq(string.find(errors[3], "invalid", 1, true) ~= nil, true)
end

--- chave repetida aponta a linha da primeira definição e não duplica a var
function test_env__chave_repetida_vira_erro()
    local vars, _, errors = H.parse_dotenv("A=1\nB=2\nA=3")
    assert_eq(#vars, 2)
    assert_eq(#errors, 1)
    assert_eq(string.find(errors[1], "line 3", 1, true) ~= nil, true)
    assert_eq(string.find(errors[1], "line 1", 1, true) ~= nil, true)
end

--- valor vazio é legítimo
function test_env__valor_vazio_nao_e_erro()
    local vars, _, errors = H.parse_dotenv("A=")
    assert_eq(#vars, 1)
    assert_eq(#errors, 0)
end

--- entrada vazia ou nil dá listas vazias que codificam como array
function test_env__entrada_vazia_ou_nil_da_listas_vazias_que_codificam_como()
    for _, entrada in { "", nil } do
        local vars, comments = H.parse_dotenv(entrada)
        assert_eq(#vars, 0)
        assert_eq(json.encode(vars), "[]")
        assert_eq(json.encode(comments), "[]")
    end
end

--- aceita final de linha sem \\n
function test_env__aceita_final_de_linha_sem_n()
    assert_eq(#H.parse_dotenv("A=1"), 1)
end

--- oauth_redirect_uri monta o callback do provedor
function test_urls__oauth_redirect_uri_monta_o_callback_do_provedor()
    assert_eq(
        H.oauth_redirect_uri("https://d.com", "github"),
        "https://d.com/oauth/github/callback"
    )
    assert_eq(
        H.oauth_redirect_uri("https://d.com///", "gitea"),
        "https://d.com/oauth/gitea/callback"
    )
end

--- provedor desconhecido cai em gitea, e base vazia avisa
function test_urls__provedor_desconhecido_cai_em_gitea_e_base_vazia_avisa()
    assert_eq(
        H.oauth_redirect_uri("https://d.com", "gitlab"),
        "https://d.com/oauth/gitea/callback"
    )
    assert_has(H.oauth_redirect_uri("", "github"), "indisponível")
    assert_has(H.oauth_redirect_uri(nil, "github"), "/oauth/github/callback")
end

--- looks_like_git_url reconhece os esquemas e o sufixo .git
function test_urls__looks_like_git_url_reconhece_os_esquemas_e_o_sufixo_git()
    for _, boa in
        {
            "https://x/r",
            "http://x/r",
            "git@github.com:a/b",
            "ssh://h/r",
            "file:///tmp/r",
            "foo/bar.git",
            "  https://x  ",
        }
    do
        assert_eq(H.looks_like_git_url(boa), true)
    end
    for _, ruim in { "", "ftp://x/r", "só texto", "github.com/a/b" } do
        assert_eq(H.looks_like_git_url(ruim), false)
    end
    assert_eq(H.looks_like_git_url(nil), false)
end

--- normalize_url fixa o esquema e descarta caminho, query e fragmento
function test_urls__normalize_url_fixa_o_esquema_e_descarta_caminho_query_e()
    assert_eq(H.normalize_url("https://a.com/x/y?z=1#f"), "https://a.com")
    assert_eq(H.normalize_url("a.com:8080/p"), "https://a.com:8080")
    assert_eq(H.normalize_url("  HTTP://B.com  "), "http://B.com")
end

--- normalize_url recusa vazio e esquema que não é http(s)
function test_urls__normalize_url_recusa_vazio_e_esquema_que_nao_e_http_s()
    assert_nil(H.normalize_url(""))
    assert_nil(H.normalize_url("   "))
    assert_nil(H.normalize_url("ftp://a.com"))
    assert_nil(H.normalize_url("https://"))
end

--- is_true aceita o boolean (checkbox/toggle) e o texto "true"; o resto é falso
function test_booleanos__is_true_aceita_boolean_e_texto()
    assert_true(H.is_true(true))
    assert_true(H.is_true("true"))
    assert_false(H.is_true(false))
    assert_false(H.is_true("false"))
    assert_false(H.is_true(nil))
    assert_false(H.is_true("1"))
end

--- is_false só é verdadeiro para o false explícito; ausente não é falso (padrão ligado)
function test_booleanos__is_false_nao_confunde_ausente_com_falso()
    assert_true(H.is_false(false))
    assert_true(H.is_false("false"))
    assert_false(H.is_false(nil))
    assert_false(H.is_false(true))
    assert_false(H.is_false("true"))
end

--- o valor digitado na edição no lugar vira Plain ou Secret
function test_env_value_from_draft__plain_secret_e_variavel_que_ja_era_secret()
    assert_eq(H.env_value_from_draft("abc", false).Plain, "abc")
    assert_eq(H.env_value_from_draft("", false).Plain, "")
    assert_eq(H.env_value_from_draft("secret:DB_PASS", false).Secret, "DB_PASS")
    assert_eq(H.env_value_from_draft("<secret:DB_PASS>", false).Secret, "DB_PASS")
    -- numa variável que já era secret, o texto é o NOME do secret
    assert_eq(H.env_value_from_draft("  OUTRO ", true).Secret, "OUTRO")
    assert_nil(H.env_value_from_draft("secret:X", true).Plain)
end