"""Functional authentication tests with fake MRP Apple TV."""

import inspect

from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop

import pyatv
from pyatv import exceptions
from pyatv.const import Protocol
from pyatv.conf import MrpService, AppleTV
from pyatv.mrp.server_auth import PIN_CODE, CLIENT_IDENTIFIER, CLIENT_CREDENTIALS
from tests.fake_device import FakeAppleTV


class MrpAuthFunctionalTest(AioHTTPTestCase):
    def setUp(self):
        AioHTTPTestCase.setUp(self)

        self.service = MrpService(
            CLIENT_IDENTIFIER, self.fake_atv.get_port(Protocol.MRP)
        )
        self.conf = AppleTV("127.0.0.1", "Apple TV")
        self.conf.add_service(self.service)

    async def tearDownAsync(self):
        if inspect.iscoroutinefunction(self.handle.close):
            await self.handle.close()
        else:
            self.handle.close()
        await super().tearDownAsync()

    async def get_application(self, loop=None):
        self.fake_atv = FakeAppleTV(self.loop)
        self.state, self.usecase = self.fake_atv.add_service(Protocol.MRP)
        return self.fake_atv.app

    @unittest_run_loop
    async def test_pairing_with_device(self):
        self.handle = await pyatv.pair(self.conf, Protocol.MRP, self.loop)

        self.assertIsNone(self.service.credentials)
        self.assertTrue(self.handle.device_provides_pin)

        await self.handle.begin()
        self.handle.pin(PIN_CODE)

        await self.handle.finish()

        self.assertTrue(self.handle.has_paired)
        self.assertTrue(self.state.has_paired)
        self.assertIsNotNone(self.service.credentials)

    @unittest_run_loop
    async def test_pairing_with_existing_credentials(self):
        self.service.credentials = CLIENT_CREDENTIALS

        self.handle = await pyatv.pair(self.conf, Protocol.MRP, self.loop)

        self.assertFalse(self.handle.has_paired)
        self.assertIsNotNone(self.service.credentials)
        self.assertTrue(self.handle.device_provides_pin)

        await self.handle.begin()
        self.handle.pin(PIN_CODE)

        await self.handle.finish()

        self.assertTrue(self.handle.has_paired)
        self.assertTrue(self.state.has_paired)
        self.assertIsNotNone(self.service.credentials)

    @unittest_run_loop
    async def test_pairing_with_bad_pin(self):
        self.handle = await pyatv.pair(self.conf, Protocol.MRP, self.loop)

        self.assertIsNone(self.service.credentials)
        self.assertTrue(self.handle.device_provides_pin)

        await self.handle.begin()
        self.handle.pin(PIN_CODE + 1)

        with self.assertRaises(exceptions.PairingError):
            await self.handle.finish()

        self.assertFalse(self.handle.has_paired)
        self.assertFalse(self.state.has_paired)
        self.assertIsNone(self.service.credentials)

    @unittest_run_loop
    async def test_authentication(self):
        self.service.credentials = CLIENT_CREDENTIALS

        self.handle = await pyatv.connect(self.conf, self.loop)

        self.assertTrue(self.state.has_authenticated)

[((17, 8, 17, 35), 'aiohttp.test_utils.AioHTTPTestCase.setUp', 'AioHTTPTestCase.setUp', ({(17, 30, 17, 34): 'self'}, {}), '(self)', False, 'from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop\n'), ((22, 20, 22, 52), 'pyatv.conf.AppleTV', 'AppleTV', ({(22, 28, 22, 39): '"""127.0.0.1"""', (22, 41, 22, 51): '"""Apple TV"""'}, {}), "('127.0.0.1', 'Apple TV')", False, 'from pyatv.conf import MrpService, AppleTV\n'), ((26, 11, 26, 57), 'inspect.iscoroutinefunction', 'inspect.iscoroutinefunction', ({(26, 39, 26, 56): 'self.handle.close'}, {}), '(self.handle.close)', False, 'import inspect\n'), ((33, 24, 33, 46), 'tests.fake_device.FakeAppleTV', 'FakeAppleTV', ({(33, 36, 33, 45): 'self.loop'}, {}), '(self.loop)', False, 'from tests.fake_device import FakeAppleTV\n'), ((39, 28, 39, 74), 'pyatv.pair', 'pyatv.pair', ({(39, 39, 39, 48): 'self.conf', (39, 50, 39, 62): 'Protocol.MRP', (39, 64, 39, 73): 'self.loop'}, {}), '(self.conf, Protocol.MRP, self.loop)', False, 'import pyatv\n'), ((57, 28, 57, 74), 'pyatv.pair', 'pyatv.pair', ({(57, 39, 57, 48): 'self.conf', (57, 50, 57, 62): 'Protocol.MRP', (57, 64, 57, 73): 'self.loop'}, {}), '(self.conf, Protocol.MRP, self.loop)', False, 'import pyatv\n'), ((74, 28, 74, 74), 'pyatv.pair', 'pyatv.pair', ({(74, 39, 74, 48): 'self.conf', (74, 50, 74, 62): 'Protocol.MRP', (74, 64, 74, 73): 'self.loop'}, {}), '(self.conf, Protocol.MRP, self.loop)', False, 'import pyatv\n'), ((93, 28, 93, 63), 'pyatv.connect', 'pyatv.connect', ({(93, 42, 93, 51): 'self.conf', (93, 53, 93, 62): 'self.loop'}, {}), '(self.conf, self.loop)', False, 'import pyatv\n')]