"""Pruebas unitarias del dominio puro estequiometria_grader.

Formato SAQI-nivel unidad: cubren calificacion por tema sobre 100, normalizacion
de respuestas, descuento por incidentes y nota unificada.
"""

import unittest

import estequiometria_grader as g


N_2_INCIDENTES = 2


def respuestas_perfectas():
    return {
        "4.1.5": {"0": "B", "1": "A", "2": "C", "3": "D", "4": "B"},
        "4.1.6": {
            "0": "1,3,2", "1": "4,3,2", "2": "1,5,3,4", "3": "2,2,2,1",
            "4": "1,2,1,1", "5": "4,3,2", "6": "1,1,1", "7": "2,7,4,6",
            "8": "1,2,1,1", "9": "2,13,8,10",
        },
        "4.1.7": {
            "0": "4", "1": "4", "2": "117", "3": "324", "4": "5",
            "5": "10.8", "6": "34.6", "7": "0.5", "8": "302.2", "9": "7.45",
        },
        "ACT": {"0": "C", "1": "A", "2": "B", "3": "D", "4": "C"},
    }


class TestCalificacionTema(unittest.TestCase):

    def test_tema_415_perfecto(self):
        r = g.calificar_tema("4.1.5", {"0": "B", "1": "A", "2": "C",
                                        "3": "D", "4": "B"})
        self.assertEqual(r["puntos"], 5)
        self.assertEqual(r["nota_100"], 100)

    def test_tema_415_parcial(self):
        resp = {"0": "B", "1": "A", "2": "A", "3": "D", "4": "B"}
        r = g.calificar_tema("4.1.5", resp)
        self.assertEqual(r["puntos"], 4)
        self.assertEqual(r["nota_100"], 80)

    def test_tema_416_perfecto(self):
        resp = {
            "0": "1,3,2", "1": "4,3,2", "2": "1,5,3,4", "3": "2,2,2,1",
            "4": "1,2,1,1", "5": "4,3,2", "6": "1,1,1", "7": "2,7,4,6",
            "8": "1,2,1,1", "9": "2,13,8,10",
        }
        r = g.calificar_tema("4.1.6", resp)
        self.assertEqual(r["puntos"], 10)
        self.assertEqual(r["nota_100"], 100)

    def test_tema_416_acepta_espacios(self):
        resp = {"0": " 1 , 3 , 2 "}
        r = g.calificar_tema("4.1.6", resp)
        self.assertEqual(r["puntos"], 1)
        self.assertEqual(r["nota_100"], 10)

    def test_tema_417_perfecto(self):
        resp = {
            "0": "4", "1": "4", "2": "117", "3": "324", "4": "5",
            "5": "10.8", "6": "34.6", "7": "0.5", "8": "302.2", "9": "7.45",
        }
        r = g.calificar_tema("4.1.7", resp)
        self.assertEqual(r["puntos"], 10)
        self.assertEqual(r["nota_100"], 100)

    def test_tema_417_acepta_unidades(self):
        resp = {"0": "4 mol", "1": "4 mol", "2": "117 g"}
        r = g.calificar_tema("4.1.7", resp)
        self.assertEqual(r["puntos"], 3)

    def test_tema_act_perfecto(self):
        r = g.calificar_tema("ACT", {"0": "C", "1": "A", "2": "B",
                                     "3": "D", "4": "C"})
        self.assertEqual(r["puntos"], 5)
        self.assertEqual(r["nota_100"], 100)

    def test_tema_vacio_0(self):
        r = g.calificar_tema("4.1.5", {})
        self.assertEqual(r["puntos"], 0)
        self.assertEqual(r["nota_100"], 0)

    def test_tema_desconocido_levanta(self):
        with self.assertRaises(ValueError):
            g.calificar_tema("9.9.9", {})


class TestNormalizacion(unittest.TestCase):

    def test_acentos_y_espacios(self):
        self.assertEqual(g.normalizar("  Ley de conservacion "),
                         "leydeconservacion")
        self.assertEqual(g.normalizar("REACTIVOS"), "reactivos")

    def test_normalizar_coeficientes(self):
        self.assertEqual(g.normalizar_coeficientes("2, 1, 2"), "2,1,2")
        self.assertEqual(g.normalizar_coeficientes(" 4 - 3 - 2 "), "4,3,2")
        self.assertEqual(g.normalizar_coeficientes("(1, 2, 1, 2)"), "1,2,1,2")

    def test_normalizar_numero(self):
        self.assertEqual(g.normalizar_numero("80 g"), "80")
        self.assertEqual(g.normalizar_numero("2.5 mol"), "2.5")
        self.assertEqual(g.normalizar_numero("44 g/mol"), "44")
        self.assertEqual(g.normalizar_numero("36 mL"), "36")


class TestDescuentoIncidencias(unittest.TestCase):

    def test_descuento_por_incidencias(self):
        self.assertEqual(g.nota_final(100, 2), 90)

    def test_piso_en_cero(self):
        self.assertEqual(g.nota_final(100, 30), 0)
        self.assertEqual(g.nota_final(80, 20), 0)


class TestNotaModulo(unittest.TestCase):

    def test_nota_modulo_perfecta(self):
        nota = g.nota_modulo(respuestas_perfectas(), 0)
        self.assertEqual(nota, 100)

    def test_nota_modulo_con_incidentes(self):
        nota = g.nota_modulo(respuestas_perfectas(), 2)
        self.assertEqual(nota, 90)

    def test_nota_modulo_parcial(self):
        resp = {
            "4.1.5": {"0": "B", "1": "A", "2": "C", "3": "D", "4": "B"},
            "4.1.6": {}, "4.1.7": {}, "ACT": {}
        }
        nota = g.nota_modulo(resp, 0)
        # 5/30 = 16.67% -> 17
        self.assertEqual(nota, 17)

    def test_nota_modulo_vacia(self):
        nota = g.nota_modulo({}, 0)
        self.assertEqual(nota, 0)


class TestCalificarExamen(unittest.TestCase):

    def test_perfecto_sin_incidentes(self):
        res = g.calificar_examen(respuestas_perfectas(), 0)
        self.assertEqual(res["nota_final"], 100)
        self.assertEqual(res["descuento_total"], 0)

    def test_perfecto_con_incidentes(self):
        res = g.calificar_examen(respuestas_perfectas(), N_2_INCIDENTES)
        self.assertEqual(res["nota_final"], 90)
        self.assertEqual(res["descuento_total"], 10)


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