# Copyright (c) 2022 <NAME>. All rights reserved.
from unittest import TestCase, mock
import os
import contextlib
from typing import Iterator

from click import testing

from remoteweb import crypto, server
from remoteweb.cli import (
    root,
    server as cliserver
)


CLIRUNNER = testing.CliRunner()


@mock.patch("remoteweb.server.RemoteWebServer", spec_set=server.RemoteWebServer)
class Test_run_client(TestCase):

    def _test(self, args: list[str]) -> None:
        result = CLIRUNNER.invoke(root.main, args)
        self.assertEqual(result.exit_code, 0)

    def test_host(self, server_mock: mock.Mock) -> None:
        hosts = [f"127.0.0.{i}" for i in range(3)]
        port = 6171
        endpoint = "/remoteweb/ws"
        for host in hosts:
            with self.subTest(host=host):
                args = [str(cliserver.run_server.name), "--host", host]
                self._test(args)
                server_mock.assert_called_once_with(
                    host=host,
                    port=port,
                    authorized_keys=[],
                    websocket_endpoint=endpoint
                )
                server_mock.return_value.run.assert_called_once_with()
            server_mock.reset_mock()

    def test_port(self, server_mock: mock.Mock) -> None:
        host = "127.0.0.1"
        ports = [6171 + i for i in range(3)]
        endpoint = "/remoteweb/ws"
        for port in ports:
            with self.subTest(port=port):
                args = [str(cliserver.run_server.name), "--port", str(port)]
                self._test(args)
                server_mock.assert_called_once_with(
                    host=host,
                    port=port,
                    authorized_keys=[],
                    websocket_endpoint=endpoint
                )
                server_mock.return_value.run.assert_called_once_with()
            server_mock.reset_mock()

    def test_key(self, server_mock: mock.Mock) -> None:
        host = "127.0.0.1"
        port = 6171
        keys = [f"tests/test_cli/remoteweb_key{i}.pub" for i in range(3)]
        endpoint = "/remoteweb/ws"

        @contextlib.contextmanager
        def key_test(key: str) -> Iterator[None]:
            crypto.create_key(
                publickey_path=key
            )
            try:
                yield
            finally:
                os.unlink("remoteweb_key")
                os.unlink(key)

        for key in keys:
            with key_test(key):
                with self.subTest(key=key):
                    args = [str(cliserver.run_server.name), "--key", key]
                    self._test(args)
                    server_mock.assert_called_once_with(
                        host=host,
                        port=port,
                        authorized_keys=[crypto.import_key(key)],
                        websocket_endpoint=endpoint
                    )
                    server_mock.return_value.run.assert_called_once_with()
            server_mock.reset_mock()

    def test_endpoint(self, server_mock: mock.Mock) -> None:
        host = "127.0.0.1"
        port = 6171
        endpoints = [f"/remoteweb/ws{i}" for i in range(3)]
        for endpoint in endpoints:
            with self.subTest(endpoint=endpoint):
                args = [str(cliserver.run_server.name), "--endpoint", endpoint]
                self._test(args)
                server_mock.assert_called_once_with(
                    host=host,
                    port=port,
                    authorized_keys=[],
                    websocket_endpoint=endpoint
                )
                server_mock.return_value.run.assert_called_once_with()
            server_mock.reset_mock()

# Copyright (c) 2022 <NAME>. All rights reserved.
from unittest import TestCase, mock
import os
import contextlib
from typing import Iterator

from click import testing

from remoteweb import crypto, server
from remoteweb.cli import (
    root,
    server as cliserver
)


CLIRUNNER = testing.CliRunner()


@mock.patch("remoteweb.server.RemoteWebServer", spec_set=server.RemoteWebServer)
class Test_run_client(TestCase):

    def _test(self, args: list[str]) -> None:
        result = CLIRUNNER.invoke(root.main, args)
        self.assertEqual(result.exit_code, 0)

    def test_host(self, server_mock: mock.Mock) -> None:
        hosts = [f"127.0.0.{i}" for i in range(3)]
        port = 6171
        endpoint = "/remoteweb/ws"
        for host in hosts:
            with self.subTest(host=host):
                args = [str(cliserver.run_server.name), "--host", host]
                self._test(args)
                server_mock.assert_called_once_with(
                    host=host,
                    port=port,
                    authorized_keys=[],
                    websocket_endpoint=endpoint
                )
                server_mock.return_value.run.assert_called_once_with()
            server_mock.reset_mock()

    def test_port(self, server_mock: mock.Mock) -> None:
        host = "127.0.0.1"
        ports = [6171 + i for i in range(3)]
        endpoint = "/remoteweb/ws"
        for port in ports:
            with self.subTest(port=port):
                args = [str(cliserver.run_server.name), "--port", str(port)]
                self._test(args)
                server_mock.assert_called_once_with(
                    host=host,
                    port=port,
                    authorized_keys=[],
                    websocket_endpoint=endpoint
                )
                server_mock.return_value.run.assert_called_once_with()
            server_mock.reset_mock()

    def test_key(self, server_mock: mock.Mock) -> None:
        host = "127.0.0.1"
        port = 6171
        keys = [f"tests/test_cli/remoteweb_key{i}.pub" for i in range(3)]
        endpoint = "/remoteweb/ws"

        @contextlib.contextmanager
        def key_test(key: str) -> Iterator[None]:
            crypto.create_key(
                publickey_path=key
            )
            try:
                yield
            finally:
                os.unlink("remoteweb_key")
                os.unlink(key)

        for key in keys:
            with key_test(key):
                with self.subTest(key=key):
                    args = [str(cliserver.run_server.name), "--key", key]
                    self._test(args)
                    server_mock.assert_called_once_with(
                        host=host,
                        port=port,
                        authorized_keys=[crypto.import_key(key)],
                        websocket_endpoint=endpoint
                    )
                    server_mock.return_value.run.assert_called_once_with()
            server_mock.reset_mock()

    def test_endpoint(self, server_mock: mock.Mock) -> None:
        host = "127.0.0.1"
        port = 6171
        endpoints = [f"/remoteweb/ws{i}" for i in range(3)]
        for endpoint in endpoints:
            with self.subTest(endpoint=endpoint):
                args = [str(cliserver.run_server.name), "--endpoint", endpoint]
                self._test(args)
                server_mock.assert_called_once_with(
                    host=host,
                    port=port,
                    authorized_keys=[],
                    websocket_endpoint=endpoint
                )
                server_mock.return_value.run.assert_called_once_with()
            server_mock.reset_mock()

# Copyright (c) 2022 <NAME>. All rights reserved.