import pytest from fastapi import FastAPI from fastapi.testclient import TestClient from app.auth import UsuarioLogado, exigir_login from app.routers import funcionarios as router_funcionarios app_teste = FastAPI() app_teste.include_router(router_funcionarios.router) app_teste.dependency_overrides[exigir_login] = lambda: UsuarioLogado(login="admin", nome="Admin", perfil="ADMIN") client = TestClient(app_teste, follow_redirects=False) CSRF_TESTE = "teste-csrf-token" client.cookies.set("csrf_token", CSRF_TESTE) @pytest.fixture(autouse=True) def _sem_log_real(monkeypatch): monkeypatch.setattr(router_funcionarios.db_log, "registrar", lambda *args, **kwargs: None) @pytest.fixture(autouse=True) def _admin_como_padrao(monkeypatch): """Todo teste roda como admin por padrão (override acima). Testes que querem simular usuário padrão sobrescrevem de novo dentro do próprio teste e restauram no fim via yield.""" yield app_teste.dependency_overrides[exigir_login] = lambda: UsuarioLogado(login="admin", nome="Admin", perfil="ADMIN") def test_usuario_padrao_toma_403_em_qualquer_rota(): app_teste.dependency_overrides[exigir_login] = lambda: UsuarioLogado(login="fulano", nome="Fulano", perfil="PADRAO") resposta = client.get("/funcionarios") assert resposta.status_code == 403 def test_listar_funcionarios(monkeypatch): monkeypatch.setattr( router_funcionarios.db_funcionarios, "listar_funcionarios", lambda: [{"ID": 1, "NOME": "Fulano", "LOGIN": "fulano", "PERFIL": "PADRAO", "ATIVO": 1, "CRIADO_EM": "2026-01-01"}], ) resposta = client.get("/funcionarios") assert resposta.status_code == 200 assert "Fulano" in resposta.text def test_criar_funcionario_com_sucesso(monkeypatch): monkeypatch.setattr(router_funcionarios.db_funcionarios, "login_em_uso", lambda login, ignorar_id=None: False) criado = {} monkeypatch.setattr( router_funcionarios.db_funcionarios, "criar_funcionario", lambda nome, login, senha, perfil: criado.setdefault("dados", (nome, login, senha, perfil)) and 1, ) resposta = client.post( "/funcionarios/novo", data={ "nome": "Fulano", "login": "fulano", "senha": "senhaForte123", "confirmar_senha": "senhaForte123", "perfil": "PADRAO", "csrf_token": CSRF_TESTE, }, ) assert resposta.status_code == 303 assert criado["dados"] == ("Fulano", "fulano", "senhaForte123", "PADRAO") def test_criar_funcionario_senhas_diferentes_bloqueia(monkeypatch): monkeypatch.setattr(router_funcionarios.db_funcionarios, "login_em_uso", lambda login, ignorar_id=None: False) chamou = {} monkeypatch.setattr( router_funcionarios.db_funcionarios, "criar_funcionario", lambda nome, login, senha, perfil: chamou.setdefault("ok", True), ) resposta = client.post( "/funcionarios/novo", data={ "nome": "Fulano", "login": "fulano", "senha": "senhaForte123", "confirmar_senha": "outraCoisa", "perfil": "PADRAO", "csrf_token": CSRF_TESTE, }, ) assert resposta.status_code == 200 assert "não coincidem" in resposta.text assert "ok" not in chamou def test_criar_funcionario_login_duplicado_bloqueia(monkeypatch): monkeypatch.setattr(router_funcionarios.db_funcionarios, "login_em_uso", lambda login, ignorar_id=None: True) chamou = {} monkeypatch.setattr( router_funcionarios.db_funcionarios, "criar_funcionario", lambda nome, login, senha, perfil: chamou.setdefault("ok", True), ) resposta = client.post( "/funcionarios/novo", data={ "nome": "Fulano", "login": "fulano", "senha": "senhaForte123", "confirmar_senha": "senhaForte123", "perfil": "PADRAO", "csrf_token": CSRF_TESTE, }, ) assert resposta.status_code == 200 assert "já está em uso" in resposta.text assert "ok" not in chamou def test_criar_funcionario_perfil_invalido_bloqueia(monkeypatch): monkeypatch.setattr(router_funcionarios.db_funcionarios, "login_em_uso", lambda login, ignorar_id=None: False) chamou = {} monkeypatch.setattr( router_funcionarios.db_funcionarios, "criar_funcionario", lambda nome, login, senha, perfil: chamou.setdefault("ok", True), ) resposta = client.post( "/funcionarios/novo", data={ "nome": "Fulano", "login": "fulano", "senha": "senhaForte123", "confirmar_senha": "senhaForte123", "perfil": "SUPERUSUARIO", "csrf_token": CSRF_TESTE, }, ) assert resposta.status_code == 200 assert "ok" not in chamou def test_editar_funcionario_com_sucesso(monkeypatch): monkeypatch.setattr(router_funcionarios.db_funcionarios, "login_em_uso", lambda login, ignorar_id=None: False) monkeypatch.setattr( router_funcionarios.db_funcionarios, "obter_funcionario", lambda fid: {"ID": fid, "NOME": "Fulano", "LOGIN": "fulano", "PERFIL": "PADRAO", "ATIVO": 1}, ) capturado = {} monkeypatch.setattr( router_funcionarios.db_funcionarios, "atualizar_funcionario", lambda fid, nome, login, perfil: capturado.setdefault("dados", (fid, nome, login, perfil)), ) resposta = client.post( "/funcionarios/1/editar", data={"nome": "Fulano Editado", "login": "fulano.editado", "perfil": "PADRAO", "csrf_token": CSRF_TESTE}, ) assert resposta.status_code == 303 assert capturado["dados"] == (1, "Fulano Editado", "fulano.editado", "PADRAO") def test_editar_ultimo_admin_para_padrao_bloqueia(monkeypatch): monkeypatch.setattr(router_funcionarios.db_funcionarios, "login_em_uso", lambda login, ignorar_id=None: False) monkeypatch.setattr( router_funcionarios.db_funcionarios, "obter_funcionario", lambda fid: {"ID": fid, "NOME": "Admin", "LOGIN": "admin.db", "PERFIL": "ADMIN", "ATIVO": 1}, ) monkeypatch.setattr(router_funcionarios.db_funcionarios, "contar_admins_ativos", lambda: 1) chamou = {} monkeypatch.setattr( router_funcionarios.db_funcionarios, "atualizar_funcionario", lambda fid, nome, login, perfil: chamou.setdefault("ok", True), ) resposta = client.post( "/funcionarios/1/editar", data={"nome": "Admin", "login": "admin.db", "perfil": "PADRAO", "csrf_token": CSRF_TESTE}, ) assert resposta.status_code == 200 assert "único administrador" in resposta.text assert "ok" not in chamou def test_editar_admin_para_padrao_com_outros_admins_permite(monkeypatch): monkeypatch.setattr(router_funcionarios.db_funcionarios, "login_em_uso", lambda login, ignorar_id=None: False) monkeypatch.setattr( router_funcionarios.db_funcionarios, "obter_funcionario", lambda fid: {"ID": fid, "NOME": "Admin", "LOGIN": "admin.db", "PERFIL": "ADMIN", "ATIVO": 1}, ) monkeypatch.setattr(router_funcionarios.db_funcionarios, "contar_admins_ativos", lambda: 2) capturado = {} monkeypatch.setattr( router_funcionarios.db_funcionarios, "atualizar_funcionario", lambda fid, nome, login, perfil: capturado.setdefault("dados", (fid, nome, login, perfil)), ) resposta = client.post( "/funcionarios/1/editar", data={"nome": "Admin", "login": "admin.db", "perfil": "PADRAO", "csrf_token": CSRF_TESTE}, ) assert resposta.status_code == 303 assert capturado["dados"] == (1, "Admin", "admin.db", "PADRAO") def test_editar_funcionario_inexistente_nao_finge_sucesso(monkeypatch): monkeypatch.setattr(router_funcionarios.db_funcionarios, "login_em_uso", lambda login, ignorar_id=None: False) monkeypatch.setattr(router_funcionarios.db_funcionarios, "obter_funcionario", lambda fid: None) chamou = {} monkeypatch.setattr( router_funcionarios.db_funcionarios, "atualizar_funcionario", lambda fid, nome, login, perfil: chamou.setdefault("ok", True), ) resposta = client.post( "/funcionarios/999/editar", data={"nome": "Fulano", "login": "fulano", "perfil": "PADRAO", "csrf_token": CSRF_TESTE}, ) assert resposta.status_code == 200 assert "não encontrado" in resposta.text assert "ok" not in chamou def test_redefinir_senha_com_sucesso(monkeypatch): capturado = {} monkeypatch.setattr( router_funcionarios.db_funcionarios, "redefinir_senha", lambda fid, senha: capturado.setdefault("dados", (fid, senha)), ) resposta = client.post( "/funcionarios/1/redefinir-senha", data={"nova_senha": "novaSenha123", "confirmar_nova_senha": "novaSenha123", "csrf_token": CSRF_TESTE}, ) assert resposta.status_code == 303 assert capturado["dados"] == (1, "novaSenha123") def test_redefinir_senha_nao_coincide_bloqueia(monkeypatch): chamou = {} monkeypatch.setattr( router_funcionarios.db_funcionarios, "redefinir_senha", lambda fid, senha: chamou.setdefault("ok", True) ) resposta = client.post( "/funcionarios/1/redefinir-senha", data={"nova_senha": "a", "confirmar_nova_senha": "b", "csrf_token": CSRF_TESTE}, follow_redirects=True, ) assert "não coincidem" in resposta.text assert "ok" not in chamou def test_redefinir_senha_funcionario_inexistente_nao_finge_sucesso(monkeypatch): monkeypatch.setattr(router_funcionarios.db_funcionarios, "redefinir_senha", lambda fid, senha: False) resposta = client.post( "/funcionarios/999/redefinir-senha", data={"nova_senha": "novaSenha123", "confirmar_nova_senha": "novaSenha123", "csrf_token": CSRF_TESTE}, follow_redirects=True, ) assert "não encontrado" in resposta.text def test_alternar_ativo_funcionario_inexistente_nao_finge_sucesso(monkeypatch): monkeypatch.setattr(router_funcionarios.db_funcionarios, "obter_funcionario", lambda fid: None) chamou = {} monkeypatch.setattr( router_funcionarios.db_funcionarios, "alternar_ativo", lambda fid: chamou.setdefault("ok", True) ) resposta = client.post( "/funcionarios/999/alternar-ativo", data={"csrf_token": CSRF_TESTE}, follow_redirects=True ) assert "não encontrado" in resposta.text assert "ok" not in chamou def test_alternar_ativo(monkeypatch): monkeypatch.setattr( router_funcionarios.db_funcionarios, "obter_funcionario", lambda fid: {"ID": fid, "NOME": "Fulano", "LOGIN": "fulano", "PERFIL": "PADRAO", "ATIVO": 1}, ) capturado = {} monkeypatch.setattr( router_funcionarios.db_funcionarios, "alternar_ativo", lambda fid: capturado.setdefault("id", fid) ) resposta = client.post("/funcionarios/1/alternar-ativo", data={"csrf_token": CSRF_TESTE}) assert resposta.status_code == 303 assert capturado["id"] == 1 def test_desativar_ultimo_admin_ativo_bloqueia(monkeypatch): monkeypatch.setattr( router_funcionarios.db_funcionarios, "obter_funcionario", lambda fid: {"ID": fid, "NOME": "Admin", "LOGIN": "admin.db", "PERFIL": "ADMIN", "ATIVO": 1}, ) monkeypatch.setattr(router_funcionarios.db_funcionarios, "contar_admins_ativos", lambda: 1) chamou = {} monkeypatch.setattr( router_funcionarios.db_funcionarios, "alternar_ativo", lambda fid: chamou.setdefault("ok", True) ) resposta = client.post( "/funcionarios/1/alternar-ativo", data={"csrf_token": CSRF_TESTE}, follow_redirects=True ) assert "único administrador" in resposta.text assert "ok" not in chamou def test_reativar_funcionario_nao_passa_pela_checagem_de_ultimo_admin(monkeypatch): # ATIVO indo de 0 para 1 (reativação) nunca reduz a contagem de admins # ativos — não precisa nem chamar contar_admins_ativos(). monkeypatch.setattr( router_funcionarios.db_funcionarios, "obter_funcionario", lambda fid: {"ID": fid, "NOME": "Admin", "LOGIN": "admin.db", "PERFIL": "ADMIN", "ATIVO": 0}, ) def _falha_se_chamado(): raise AssertionError("contar_admins_ativos não deveria ser chamado ao reativar") monkeypatch.setattr(router_funcionarios.db_funcionarios, "contar_admins_ativos", _falha_se_chamado) capturado = {} monkeypatch.setattr( router_funcionarios.db_funcionarios, "alternar_ativo", lambda fid: capturado.setdefault("id", fid) ) resposta = client.post("/funcionarios/1/alternar-ativo", data={"csrf_token": CSRF_TESTE}) assert resposta.status_code == 303 assert capturado["id"] == 1