import unittest

from precis_i18n.codepointset import CodepointSet


class TestCodepointSet(unittest.TestCase):
    def test_contains(self):
        cps = CodepointSet('0000\n')
        actual = [cp in cps for cp in range(-1, 4)]
        self.assertEqual(actual, [False, True, False, False, False])

        self.assertFalse(0x010FFFF in cps)

        cps = CodepointSet('0000..0001\n')
        actual = [cp in cps for cp in range(-1, 4)]
        self.assertEqual(actual, [False, True, True, False, False])

        cps = CodepointSet('0000\n0001\n0002')
        actual = [cp in cps for cp in range(-1, 4)]
        self.assertEqual(actual, [False, True, True, True, False])

        cps = CodepointSet('0000\n0002')
        actual = [cp in cps for cp in range(-1, 4)]
        self.assertEqual(actual, [False, True, False, True, False])

        cps = CodepointSet('10000..10FFFF')
        self.assertTrue(0x10FFFF in cps)
        self.assertFalse(0x110000 in cps)

    def test_len(self):
        cps = CodepointSet('0000\n')
        self.assertEqual(len(cps), 1)

        cps = CodepointSet('0000..0001\n')
        self.assertEqual(len(cps), 2)

        cps = CodepointSet('0000\n0001\n0002')
        self.assertEqual(len(cps), 3)

        cps = CodepointSet('0000\n0002')
        self.assertEqual(len(cps), 2)

        cps = CodepointSet('10000..10FFFF')
        self.assertEqual(len(cps), 0x10FFFF - 0x10000 + 1)

    def test_equals(self):
        cps = CodepointSet('0000..00FF')
        self.assertEqual(cps, CodepointSet('0000..00FF'))
        self.assertNotEqual(cps, CodepointSet('0000..00FE'))

        # Non-CodepointSet always not-equal.
        self.assertFalse(cps == 'what?')

    def test_repr(self):
        cps = CodepointSet('')
        self.assertEqual(repr(cps), "CodepointSet('')")

        cps = CodepointSet('0000')
        self.assertEqual(repr(cps), "CodepointSet('0000')")

        cps = CodepointSet('0000..00FF')
        self.assertEqual(repr(cps), "CodepointSet('0000..00FF')")

        cps = CodepointSet('0001..FFFF\n100000..10FFFF')
        self.assertEqual(repr(cps),
                         r"CodepointSet('0001..FFFF\n100000..10FFFF')")

        cps = CodepointSet('FFFF..1FFFF')
        self.assertEqual(repr(cps), "CodepointSet('FFFF..1FFFF')")

        cps = CodepointSet('10000..1FFFF')
        self.assertEqual(repr(cps), "CodepointSet('10000..1FFFF')")

        cps = CodepointSet('FFFE\n10000..1FFFF')
        self.assertEqual(repr(cps), r"CodepointSet('FFFE\n10000..1FFFF')")

    def test_coalesce(self):
        cps = CodepointSet('0000\n0001\n0002')
        self.assertEqual(cps, CodepointSet('0000..0002'))

        cps = CodepointSet('0000\n0002\n0003..0004')
        self.assertEqual(cps, CodepointSet('0000\n0002..0004'))

    def test_malformed_range(self):
        with self.assertRaises(ValueError):
            CodepointSet('0002..0000\n0001')

        with self.assertRaises(ValueError):
            CodepointSet('0000..0001\n0000..0001\n0002')

        with self.assertRaises(ValueError):
            CodepointSet('0000\n0002\n0002..0004')

        with self.assertRaises(ValueError):
            CodepointSet('110000')

        with self.assertRaises(ValueError):
            CodepointSet('0000\n000G')

    def test_even_odd(self):
        data = '\n'.join("%04X" % cp for cp in range(0, 10000, 2))
        cps = CodepointSet(data)
        for cp in range(10000):
            if cp in cps:
                self.assertTrue((cp % 2) == 0)
            else:
                self.assertFalse((cp % 2) == 0)

    def test_parse(self):
        cps = CodepointSet('A\nBB\n')
        self.assertEqual(repr(cps), r"CodepointSet('000A\n00BB')")

        cps = CodepointSet('AAA\nBBB..CCC\n')
        self.assertEqual(repr(cps), r"CodepointSet('0AAA\n0BBB..0CCC')")

        cps = CodepointSet('\n  \n # comment  \n   \n')
        self.assertEqual(repr(cps), "CodepointSet('')")
