<filename>tests/test_repo/test_admin_sistema_repo.py
import pathlib
import unittest

from src.container import create_container
from src.enums import UserType
from src.models import AdminSistema
from src.classes import UserSession
from src.repo import AdminSistemaRepo
from src.services import Crypto
from tests.factories import set_session, AdminSistemaFactory
from tests.utils import make_general_db_setup, general_db_teardown, make_engine, make_savepoint


class TestAdminSistemaRepo(unittest.TestCase):
    @classmethod
    def setUpClass(cls) -> None:
        config_path = str(pathlib.Path(__file__).parents[2] / 'test.ini')
        cls.container = create_container(config_path)

        conn_string = str(cls.container.config.get('db')['conn_string'])
        cls.engine = make_engine(conn_string)

    @classmethod
    def tearDownClass(cls) -> None:
        cls.engine.dispose()

    def setUp(self) -> None:
        self.conn, self.outer_trans, self.session = make_general_db_setup(self.engine)
        set_session(self.session)  # Factories

        self.crypto = Crypto(is_testing=True, salt_rounds=12)
        senha = self.crypto.hash_password(b'<PASSWORD>')

        self.admin_sis = [AdminSistemaFactory.create(nome='Jorge', email='<EMAIL>', senha=senha),
                          AdminSistemaFactory.create(nome='Maria', email='<EMAIL>', senha=senha)]
        self.session.commit()

        make_savepoint(self.conn, self.session)

        self.valid_user_sess = UserSession(UserType.SISTEMA, self.admin_sis[0].id)

        self.repo = AdminSistemaRepo()

    def tearDown(self) -> None:
        general_db_teardown(self.conn, self.outer_trans, self.session)

    def test_setup(self):
        admin_sis = self.session.query(AdminSistema).all()
        self.assertEqual(self.admin_sis, admin_sis)

    def test_create_ok(self):
        requests = [
            ('Jorge', '<EMAIL>', 'matheus12'),
            ('Joaquim', '<EMAIL>', 'joaquim12'),
            ('Fernanda', '<EMAIL>', 'fernanda12'),
            ('Mariana', '<EMAIL>', 'mariana12'),
        ]

        for i in range(len(requests)):
            nome, email, senha = requests[i]

            success, error_or_admin = self.repo.create_admin(self.valid_user_sess, self.session, nome, email, senha)
            self.assertEqual(True, success, f'Success should be True on {i}. Error: {error_or_admin}')
            self.assertIsNotNone(error_or_admin, f'Admin should not be null on {i}')

            self.assertEqual(nome, error_or_admin.nome, f'Name does not match on {i}')
            self.assertEqual(email, error_or_admin.email, f'Email does not match on {i}')
            self.assertEqual(True, self.crypto.check_password(senha.encode('utf8'), error_or_admin.senha),
                             f'Senha does not match on {i}')

    def test_create_email_already_exists(self):
        requests = [
            ('Jorge', '<EMAIL>', 'senha123'),
            ('Maria', '<EMAIL>', 'maria123'),
        ]

        for i in range(len(requests)):
            nome, email, senha = requests[i]

            success, error = self.repo.create_admin(self.valid_user_sess, self.session, nome, email, senha)

            self.assertEqual('email_ja_cadastrado', error, f'Error should be "email_ja_cadastrado" on {i}')
            self.assertEqual(False, success, f'Success should be False on {i}')

    def test_create_invalid_permission(self):
        nome, email, senha = 'Jorge', '<EMAIL>', 'matheus12'

        sessions = [UserSession(UserType.ESTACIONAMENTO, 1), None]
        for i in range(len(sessions)):
            success, error = self.repo.create_admin(sessions[i], self.session, email, nome, senha)

            self.assertEqual('sem_permissao', error, f'Error should be "sem_permissao" on {i}')
            self.assertEqual(False, success, f'Success should be False on {i}')

    def _check_response(self, response, i):
        self.assertEqual(200, response.status_code, 'Should return a 200 OK code')
        self.assertIn('data', response.json, f'JSON should contain "data" on {i}')
        self.assertIn('login', response.json['data'], f'Base data should contain "login" on {i}')

        return response.json['data']['login']


if __name__ == '__main__':
    unittest.main()
