# -*- coding: UTF-8 -*

"""Unit tests for auth (users/roles/permission management)

Usage: python -m unittest tests.test_users
"""

import unittest

from flask import current_app

from app import app, db
from app.auth.models import User, Role, Permission
from app.scodoc.sco_roles_default import SCO_ROLES_DEFAULTS


DEPT = "XX"


class UserModelCase(unittest.TestCase):
    """Test user, roles and permissions"""

    def setUp(self):
        app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite://"
        app.app_context().push()
        db.create_all()
        Role.insert_roles()

    def tearDown(self):
        db.session.remove()
        db.drop_all()

    def test_password_hashing(self):
        u = User(user_name="susan")
        db.session.add(u)
        db.session.commit()
        # nota: default attributes values, like active,
        # are not set before the first commit() (?)
        self.assertTrue(u.active)
        u.set_password("cat")
        self.assertFalse(u.check_password("dog"))
        self.assertTrue(u.check_password("cat"))

    def test_roles_permissions(self):
        perm = Permission.ScoAbsChange  # une permission au hasard
        role = Role(name="test")
        self.assertFalse(role.has_permission(perm))
        role.add_permission(perm)
        self.assertTrue(role.has_permission(perm))
        role.remove_permission(perm)
        self.assertFalse(role.has_permission(perm))
        # Default roles:
        Role.insert_roles()
        # Bien présents ?
        role_names = [r.name for r in Role.query.filter_by().all()]
        self.assertTrue(len(role_names) == len(SCO_ROLES_DEFAULTS))
        self.assertTrue("Ens" in role_names)
        self.assertTrue("Secr" in role_names)
        self.assertTrue("Admin" in role_names)
        # Les permissions de "Ens":
        role = Role.query.filter_by(name="Ens").first()
        self.assertTrue(role)
        self.assertTrue(role.has_permission(Permission.ScoView))
        self.assertTrue(role.has_permission(Permission.ScoAbsChange))
        # Permissions de Admin
        role = Role.query.filter_by(name="Admin").first()
        self.assertTrue(role.has_permission(Permission.ScoEtudChangeAdr))
        # Permissions de Secr
        role = Role.query.filter_by(name="Secr").first()
        self.assertTrue(role.has_permission(Permission.ScoEtudChangeAdr))
        self.assertFalse(role.has_permission(Permission.ScoEditAllNotes))

    def test_users_roles(self):
        dept = "XX"
        perm = Permission.ScoAbsChange
        perm2 = Permission.ScoView
        u = User(user_name="un enseignant")
        db.session.add(u)
        self.assertFalse(u.has_permission(perm, dept))
        r = Role.get_named_role("Ens")
        if not r:
            r = Role(name="Ens", permissions=perm)
        u.add_role(r, dept)
        self.assertTrue(u.has_permission(perm, dept))
        u = User(user_name="un autre")
        u.add_role(r, dept)
        db.session.add(u)
        db.session.commit()
        self.assertTrue(u.has_permission(perm, dept))
        r2 = Role.get_named_role("Secr")
        if not r2:
            r2 = Role(name="Secr", dept=dept, permissions=perm2)
        u.add_roles([r, r2], dept)
        self.assertTrue(len(u.roles) == 2)
        u = User(user_name="encore un")
        db.session.add(u)
        db.session.commit()
        u.set_roles([r, r2], dept)
        print(u.roles)
        self.assertTrue(len(u.roles) == 2)
        self.assertTrue(u.has_permission(perm, dept))
        self.assertTrue(u.has_permission(perm2, dept))
        # et pas accès aux autres dept:
        self.assertFalse(u.has_permission(perm, dept + "X"))
        self.assertFalse(u.has_permission(perm, None))

    def test_user_admin(self):
        dept = "XX"
        perm = 0x1234  # a random perm
        u = User(user_name="un admin", email=current_app.config["SCODOC_ADMIN_MAIL"])
        db.session.add(u)
        self.assertTrue(len(u.roles) == 1)
        self.assertTrue(u.has_permission(perm, dept))
        # Le grand admin a accès à tous les départements:
        self.assertTrue(u.has_permission(perm, dept + "XX"))
        self.assertTrue(u.roles[0].name == "SuperAdmin")

    def test_create_delete(self):
        u = User(user_name="dupont", nom="Dupont", prenom="Pierre")
        db.session.add(u)
        db.session.commit()
        u = User(user_name="dupond", nom="Dupond", prenom="Pierre")
        db.session.add(u)
        db.session.commit()
        ul = User.query.filter_by(prenom="Pierre").all()
        self.assertTrue(len(ul) == 2)
        ul = User.query.filter_by(user_name="dupont").all()
        self.assertTrue(len(ul) == 1)
        db.session.delete(ul[0])
        db.session.commit()
        ul = User.query.filter_by(prenom="Pierre").all()
        self.assertTrue(len(ul) == 1)


if __name__ == "__main__":
    app.app_context().push()
    unittest.main(verbosity=2)
