import unittest
import collections


class TestGroups(unittest.TestCase):
    def getGroups_generic(self):
        groups, _ = self.objectGenerator("groups")
        groups.update(
            {
                "group 1": ("A", "B", "C"),
                "group 2": ("x", "y", "z"),
                "group 3": (),
                "group 4": ("A",),
            }
        )
        return groups

    # ----
    # repr
    # ----

    def test_reprContents(self):
        font, _ = self.objectGenerator("font")
        groups = font.groups
        value = groups._reprContents()
        self.assertIsInstance(value, list)
        found = False
        for i in value:
            self.assertIsInstance(i, str)
            if "for font" in value:
                found = True
        self.assertTrue(found)

    def test_reprContents_noFont(self):
        groups, _ = self.objectGenerator("groups")
        value = groups._reprContents()
        self.assertIsInstance(value, list)
        self.assertEqual(value, [])

    # -------
    # Parents
    # -------

    def test_get_parent_font(self):
        font, _ = self.objectGenerator("font")
        groups = font.groups
        self.assertIsNotNone(groups.font)
        self.assertEqual(groups.font, font)

    def test_get_parent_font_none(self):
        groups, _ = self.objectGenerator("groups")
        self.assertIsNone(groups.font)

    def test_set_parent_font(self):
        font, _ = self.objectGenerator("font")
        groups, _ = self.objectGenerator("groups")
        groups.font = font
        self.assertIsNotNone(groups.font)
        self.assertEqual(groups.font, font)

    def test_set_parent_font_none(self):
        groups, _ = self.objectGenerator("groups")
        groups.font = None
        self.assertIsNone(groups.font)

    def test_set_parent_differentFont(self):
        font, _ = self.objectGenerator("font")
        fontB, _ = self.objectGenerator("font")
        groups, _ = self.objectGenerator("groups")
        groups.font = font
        self.assertIsNotNone(groups.font)

        with self.assertRaises(AssertionError):
            groups.font = fontB

    # ---
    # len
    # ---

    def test_len_initial(self):
        groups = self.getGroups_generic()
        self.assertEqual(len(groups), 4)

    def test_len_clear(self):
        groups = self.getGroups_generic()
        groups.clear()
        self.assertEqual(len(groups), 0)

    def test_len_add(self):
        groups = self.getGroups_generic()
        groups["group 5"] = ["D", "E", "F"]
        self.assertEqual(len(groups), 5)

    def test_len_subtract(self):
        groups = self.getGroups_generic()
        groups.pop("group 4")
        self.assertEqual(len(groups), 3)

    # ---
    # Get
    # ---

    def test_get_fallback_default(self):
        groups = self.getGroups_generic()
        self.assertEqual(groups.get("test"), None)

    # -------
    # Queries
    # -------

    def test_find_found(self):
        groups = self.getGroups_generic()
        found = groups.findGlyph("A")
        found.sort()
        self.assertEqual(found, ["group 1", "group 4"])

    def test_find_not_found(self):
        groups = self.getGroups_generic()
        self.assertEqual(groups.findGlyph("five"), [])

    def test_find_invalid_key(self):
        groups = self.getGroups_generic()
        with self.assertRaises(TypeError):
            groups.findGlyph(5)

    def test_contains_found(self):
        groups = self.getGroups_generic()
        self.assertTrue("group 4" in groups)

    def test_contains_not_found(self):
        groups = self.getGroups_generic()
        self.assertFalse("group five" in groups)

    def test_get_found(self):
        groups = self.getGroups_generic()
        self.assertEqual(groups["group 1"], ("A", "B", "C"))

    def test_get_not_found(self):
        groups = self.getGroups_generic()
        with self.assertRaises(KeyError):
            groups["group two"]

    # --------------
    # Kerning Groups
    # --------------

    def getGroups_kerning(self):
        groups = self.getGroups_generic()
        kerningGroups = {
            "public.kern1.A": ("A", "Aacute"),
            "public.kern1.O": ("O", "D"),
            "public.kern2.A": ("A", "Aacute"),
            "public.kern2.O": ("O", "C"),
        }
        groups.update(kerningGroups)
        return groups

    def test_side1KerningGroups(self):
        groups = self.getGroups_kerning()
        expected = {"public.kern1.A": ("A", "Aacute"), "public.kern1.O": ("O", "D")}
        self.assertEqual(groups.side1KerningGroups, expected)
        # self.assertEqual(super(groups, self)._get_side1KerningGroups(), expected)

    def test_get_side1KerningGroups(self):
        groups = self.getGroups_kerning()
        expected = {"public.kern1.A": ("A", "Aacute"), "public.kern1.O": ("O", "D")}
        self.assertEqual(groups._get_side1KerningGroups(), expected)

    def test_side2KerningGroups(self):
        groups = self.getGroups_kerning()
        expected = {"public.kern2.A": ("A", "Aacute"), "public.kern2.O": ("O", "C")}
        self.assertEqual(groups.side2KerningGroups, expected)

    def test_get_side2KerningGroups(self):
        groups = self.getGroups_kerning()
        expected = {"public.kern1.A": ("A", "Aacute"), "public.kern1.O": ("O", "D")}
        self.assertEqual(groups._get_side1KerningGroups(), expected)

    # ----
    # Hash
    # ----

    def test_hash(self):
        groups = self.getGroups_generic()
        self.assertEqual(isinstance(groups, collections.abc.Hashable), True)

    # --------
    # Equality
    # --------

    def test_object_equal_self(self):
        groups_one = self.getGroups_generic()
        self.assertEqual(groups_one, groups_one)

    def test_object_not_equal_other(self):
        groups_one = self.getGroups_generic()
        groups_two = self.getGroups_generic()
        self.assertNotEqual(groups_one, groups_two)

    def test_object_equal_self_variable_assignment(self):
        groups_one = self.getGroups_generic()
        a = groups_one
        self.assertEqual(groups_one, a)

    def test_object_not_equal_other_variable_assignment(self):
        groups_one = self.getGroups_generic()
        groups_two = self.getGroups_generic()
        a = groups_one
        self.assertNotEqual(groups_two, a)

    # ---------------------
    # RoboFab Compatibility
    # ---------------------

    def test_remove(self):
        groups = self.getGroups_generic()
        groups.remove("group 2")
        expected = {"group 1": ("A", "B", "C"), "group 3": (), "group 4": ("A",)}
        self.assertEqual(groups.asDict(), expected)

    def test_remove_twice(self):
        groups = self.getGroups_generic()
        groups.remove("group 1")
        with self.assertRaises(KeyError):
            groups.remove("group 1")

    def test_remove_nonexistant_group(self):
        groups = self.getGroups_generic()
        with self.assertRaises(KeyError):
            groups.remove("group 7")

    def test_asDict(self):
        groups = self.getGroups_generic()
        expected = {
            "group 1": ("A", "B", "C"),
            "group 2": ("x", "y", "z"),
            "group 3": (),
            "group 4": ("A",),
        }
        self.assertEqual(groups.asDict(), expected)

    # -------------------
    # Inherited Functions
    # -------------------

    def test_iter(self):
        groups = self.getGroups_generic()
        expected = ["group 1", "group 2", "group 3", "group 4"]

        listOfGroups = []
        for groupName in groups:
            listOfGroups.append(groupName)

        self.assertEqual(listOfGroups.sort(), expected.sort())

    def test_iter_remove(self):
        groups = self.getGroups_generic()

        for groupName in groups:
            groups.remove(groupName)
            self.assertNotIn(groupName, groups)

        self.assertFalse(groups)

    def test_values(self):
        groups = self.getGroups_generic()
        expected = [("A", "B", "C"), ("x", "y", "z"), (), ("A",)]
        self.assertEqual(sorted(groups.values()), sorted(expected))
