#
#
#

from unittest import TestCase

from octodns.idna import IdnaDict, IdnaError, idna_decode, idna_encode


class TestIdna(TestCase):
    def assertIdna(self, value, expected):
        got = idna_encode(value)
        self.assertEqual(expected, got)
        # round tripped
        self.assertEqual(value, idna_decode(got))

    def test_noops(self):
        # empty
        self.assertIdna('', '')

        # noop
        self.assertIdna('unit.tests.', 'unit.tests.')

        # wildcard noop
        self.assertIdna('*.unit.tests.', '*.unit.tests.')

    def test_unicode(self):
        # encoded
        self.assertIdna('zajęzyk.pl.', 'xn--zajzyk-y4a.pl.')

        # encoded with wildcard
        self.assertIdna('*.zajęzyk.pl.', '*.xn--zajzyk-y4a.pl.')

        # encoded with simple name
        self.assertIdna('noop.zajęzyk.pl.', 'noop.xn--zajzyk-y4a.pl.')

        # encoded with encoded name
        self.assertIdna(
            'zajęzyk.zajęzyk.pl.', 'xn--zajzyk-y4a.xn--zajzyk-y4a.pl.'
        )

        self.assertIdna('déjàvu.com.', 'xn--djvu-1na6c.com.')
        self.assertIdna('déjà-vu.com.', 'xn--dj-vu-sqa5d.com.')

    def test_underscores(self):
        # underscores aren't valid in idna names, so these are all ascii

        self.assertIdna('foo_bar.pl.', 'foo_bar.pl.')
        self.assertIdna('bleep_bloop.foo_bar.pl.', 'bleep_bloop.foo_bar.pl.')

    def test_case_insensitivity(self):
        self.assertEqual('zajęzyk.pl.', idna_decode('XN--ZAJZYK-Y4A.PL.'))
        self.assertEqual('xn--zajzyk-y4a.pl.', idna_encode('ZajęzyK.Pl.'))

    def test_repeated_encode_decoded(self):
        self.assertEqual(
            'zajęzyk.pl.', idna_decode(idna_decode('xn--zajzyk-y4a.pl.'))
        )
        self.assertEqual(
            'xn--zajzyk-y4a.pl.', idna_encode(idna_encode('zajęzyk.pl.'))
        )

    def test_exception_translation(self):
        with self.assertRaises(IdnaError) as ctx:
            idna_decode('xn--djvu-1na6c.xn--djvu-1234-something.com.')
        self.assertEqual(
            "Codepoint U+0675 at position 6 of 'ٴdjٱvٵuٳ-123ٰٲ4ٴ' not allowed",
            str(ctx.exception),
        )


class TestIdnaDict(TestCase):
    plain = 'testing.tests.'
    almost = 'tésting.tests.'
    utf8 = 'déjà.vu.'

    normal = {plain: 42, almost: 43, utf8: 44}

    def test_basics(self):
        d = IdnaDict()

        # plain ascii
        d[self.plain] = 42
        self.assertEqual(42, d[self.plain])

        # almost the same, single utf-8 char
        d[self.almost] = 43
        # fetch as utf-8
        self.assertEqual(43, d[self.almost])
        # fetch as idna
        self.assertEqual(43, d[idna_encode(self.almost)])
        # plain is stil there, unchanged
        self.assertEqual(42, d[self.plain])

        # lots of utf8
        d[self.utf8] = 44
        self.assertEqual(44, d[self.utf8])
        self.assertEqual(44, d[idna_encode(self.utf8)])

        # setting with idna version replaces something set previously with utf8
        d[idna_encode(self.almost)] = 45
        self.assertEqual(45, d[self.almost])
        self.assertEqual(45, d[idna_encode(self.almost)])

        # contains
        self.assertTrue(self.plain in d)
        self.assertTrue(self.almost in d)
        self.assertTrue(idna_encode(self.almost) in d)
        self.assertTrue(self.utf8 in d)
        self.assertTrue(idna_encode(self.utf8) in d)

        # we can delete with either form
        del d[self.almost]
        self.assertFalse(self.almost in d)
        self.assertFalse(idna_encode(self.almost) in d)
        del d[idna_encode(self.utf8)]
        self.assertFalse(self.utf8 in d)
        self.assertFalse(idna_encode(self.utf8) in d)

        # smoke test of repr
        d.__repr__()

    def test_keys(self):
        d = IdnaDict(self.normal)

        # keys are idna versions by default
        self.assertEqual(
            (self.plain, idna_encode(self.almost), idna_encode(self.utf8)),
            tuple(d.keys()),
        )

        # decoded keys gives the utf8 version
        self.assertEqual(
            (self.plain, self.almost, self.utf8), tuple(d.decoded_keys())
        )

    def test_items(self):
        d = IdnaDict(self.normal)

        # idna keys in items
        self.assertEqual(
            (
                (self.plain, 42),
                (idna_encode(self.almost), 43),
                (idna_encode(self.utf8), 44),
            ),
            tuple(d.items()),
        )

        # utf8 keys in decoded_items
        self.assertEqual(
            ((self.plain, 42), (self.almost, 43), (self.utf8, 44)),
            tuple(d.decoded_items()),
        )
