# Copyright (C) 2015 Red Hat, Inc.
# Author: Petr Spacek <pspacek@redhat.com>
#
# Permission to use, copy, modify, and distribute this software and its
# documentation for any purpose with or without fee is hereby granted,
# provided that the above copyright notice and this permission notice
# appear in all copies.
#
# THE SOFTWARE IS PROVIDED 'AS IS' AND RED HAT DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

import unittest
from io import BytesIO

import dns.rrset
import dns.rdtypes.ANY.EUI48
import dns.rdtypes.ANY.EUI64
import dns.exception


class RdtypeAnyEUI48TestCase(unittest.TestCase):
    def testInstOk(self):
        '''Valid binary input.'''
        eui = b'\x01\x23\x45\x67\x89\xab'
        inst = dns.rdtypes.ANY.EUI48.EUI48(dns.rdataclass.IN,
                                           dns.rdatatype.EUI48,
                                           eui)
        self.assertEqual(inst.eui, eui)

    def testInstLength(self):
        '''Incorrect input length.'''
        eui = b'\x01\x23\x45\x67\x89\xab\xcd'
        with self.assertRaises(dns.exception.FormError):
            dns.rdtypes.ANY.EUI48.EUI48(dns.rdataclass.IN,
                                        dns.rdatatype.EUI48,
                                        eui)

    def testFromTextOk(self):
        '''Valid text input.'''
        r1 = dns.rrset.from_text('foo', 300, 'IN', 'EUI48',
                                 '01-23-45-67-89-ab')
        eui = b'\x01\x23\x45\x67\x89\xab'
        self.assertEqual(r1[0].eui, eui)

    def testFromTextLength(self):
        '''Invalid input length.'''
        with self.assertRaises(dns.exception.SyntaxError):
            dns.rrset.from_text('foo', 300, 'IN', 'EUI48',
                                '00-01-23-45-67-89-ab')

    def testFromTextDelim(self):
        '''Invalid delimiter.'''
        with self.assertRaises(dns.exception.SyntaxError):
            dns.rrset.from_text('foo', 300, 'IN', 'EUI48', '01_23-45-67-89-ab')

    def testFromTextExtraDash(self):
        '''Extra dash instead of hex digit.'''
        with self.assertRaises(dns.exception.SyntaxError):
            dns.rrset.from_text('foo', 300, 'IN', 'EUI48', '0--23-45-67-89-ab')

    def testFromTextMultipleTokens(self):
        '''Invalid input divided to multiple tokens.'''
        with self.assertRaises(dns.exception.SyntaxError):
            dns.rrset.from_text('foo', 300, 'IN', 'EUI48', '01 23-45-67-89-ab')

    def testFromTextInvalidHex(self):
        '''Invalid hexadecimal input.'''
        with self.assertRaises(dns.exception.SyntaxError):
            dns.rrset.from_text('foo', 300, 'IN', 'EUI48', 'g0-23-45-67-89-ab')

    def testToTextOk(self):
        '''Valid text output.'''
        eui = b'\x01\x23\x45\x67\x89\xab'
        exp_text = '01-23-45-67-89-ab'
        inst = dns.rdtypes.ANY.EUI48.EUI48(dns.rdataclass.IN,
                                           dns.rdatatype.EUI48,
                                           eui)
        text = inst.to_text()
        self.assertEqual(exp_text, text)

    def testToWire(self):
        '''Valid wire format.'''
        eui = b'\x01\x23\x45\x67\x89\xab'
        inst = dns.rdtypes.ANY.EUI48.EUI48(dns.rdataclass.IN,
                                           dns.rdatatype.EUI48,
                                           eui)
        buff = BytesIO()
        inst.to_wire(buff)
        self.assertEqual(buff.getvalue(), eui)

    def testFromWireOk(self):
        '''Valid wire format.'''
        eui = b'\x01\x23\x45\x67\x89\xab'
        pad_len = 100
        wire = dns.wiredata.WireData(b'x' * pad_len + eui + b'y' * pad_len * 2)
        inst = dns.rdtypes.ANY.EUI48.EUI48.from_wire(dns.rdataclass.IN,
                                                     dns.rdatatype.EUI48,
                                                     wire,
                                                     pad_len,
                                                     len(eui))
        self.assertEqual(inst.eui, eui)

    def testFromWireLength(self):
        '''Valid wire format.'''
        eui = b'\x01\x23\x45\x67\x89'
        pad_len = 100
        wire = dns.wiredata.WireData(b'x' * pad_len + eui + b'y' * pad_len * 2)
        with self.assertRaises(dns.exception.FormError):
            dns.rdtypes.ANY.EUI48.EUI48.from_wire(dns.rdataclass.IN,
                                                  dns.rdatatype.EUI48,
                                                  wire,
                                                  pad_len,
                                                  len(eui))


class RdtypeAnyEUI64TestCase(unittest.TestCase):
    def testInstOk(self):
        '''Valid binary input.'''
        eui = b'\x01\x23\x45\x67\x89\xab\xcd\xef'
        inst = dns.rdtypes.ANY.EUI64.EUI64(dns.rdataclass.IN,
                                           dns.rdatatype.EUI64,
                                           eui)
        self.assertEqual(inst.eui, eui)

    def testInstLength(self):
        '''Incorrect input length.'''
        eui = b'\x01\x23\x45\x67\x89\xab'
        with self.assertRaises(dns.exception.FormError):
            dns.rdtypes.ANY.EUI64.EUI64(dns.rdataclass.IN,
                                        dns.rdatatype.EUI64,
                                        eui)

    def testFromTextOk(self):
        '''Valid text input.'''
        r1 = dns.rrset.from_text('foo', 300, 'IN', 'EUI64',
                                 '01-23-45-67-89-ab-cd-ef')
        eui = b'\x01\x23\x45\x67\x89\xab\xcd\xef'
        self.assertEqual(r1[0].eui, eui)

    def testFromTextLength(self):
        '''Invalid input length.'''
        with self.assertRaises(dns.exception.SyntaxError):
            dns.rrset.from_text('foo', 300, 'IN', 'EUI64',
                                '01-23-45-67-89-ab')

    def testFromTextDelim(self):
        '''Invalid delimiter.'''
        with self.assertRaises(dns.exception.SyntaxError):
            dns.rrset.from_text('foo', 300, 'IN', 'EUI64',
                                '01_23-45-67-89-ab-cd-ef')

    def testFromTextExtraDash(self):
        '''Extra dash instead of hex digit.'''
        with self.assertRaises(dns.exception.SyntaxError):
            dns.rrset.from_text('foo', 300, 'IN', 'EUI64',
                                '0--23-45-67-89-ab-cd-ef')

    def testFromTextMultipleTokens(self):
        '''Invalid input divided to multiple tokens.'''
        with self.assertRaises(dns.exception.SyntaxError):
            dns.rrset.from_text('foo', 300, 'IN', 'EUI64',
                                '01 23-45-67-89-ab-cd-ef')

    def testFromTextInvalidHex(self):
        '''Invalid hexadecimal input.'''
        with self.assertRaises(dns.exception.SyntaxError):
            dns.rrset.from_text('foo', 300, 'IN', 'EUI64',
                                'g0-23-45-67-89-ab-cd-ef')

    def testToTextOk(self):
        '''Valid text output.'''
        eui = b'\x01\x23\x45\x67\x89\xab\xcd\xef'
        exp_text = '01-23-45-67-89-ab-cd-ef'
        inst = dns.rdtypes.ANY.EUI64.EUI64(dns.rdataclass.IN,
                                           dns.rdatatype.EUI64,
                                           eui)
        text = inst.to_text()
        self.assertEqual(exp_text, text)

    def testToWire(self):
        '''Valid wire format.'''
        eui = b'\x01\x23\x45\x67\x89\xab\xcd\xef'
        inst = dns.rdtypes.ANY.EUI64.EUI64(dns.rdataclass.IN,
                                           dns.rdatatype.EUI64,
                                           eui)
        buff = BytesIO()
        inst.to_wire(buff)
        self.assertEqual(buff.getvalue(), eui)

    def testFromWireOk(self):
        '''Valid wire format.'''
        eui = b'\x01\x23\x45\x67\x89\xab\xcd\xef'
        pad_len = 100
        wire = dns.wiredata.WireData(b'x' * pad_len + eui + b'y' * pad_len * 2)
        inst = dns.rdtypes.ANY.EUI64.EUI64.from_wire(dns.rdataclass.IN,
                                                     dns.rdatatype.EUI64,
                                                     wire,
                                                     pad_len,
                                                     len(eui))
        self.assertEqual(inst.eui, eui)

    def testFromWireLength(self):
        '''Valid wire format.'''
        eui = b'\x01\x23\x45\x67\x89'
        pad_len = 100
        wire = dns.wiredata.WireData(b'x' * pad_len + eui + b'y' * pad_len * 2)
        with self.assertRaises(dns.exception.FormError):
            dns.rdtypes.ANY.EUI64.EUI64.from_wire(dns.rdataclass.IN,
                                                  dns.rdatatype.EUI64,
                                                  wire,
                                                  pad_len,
                                                  len(eui))


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