#!/usr/bin/env python3
# Copyright 2021 The Pigweed Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
"""Tests encoding HDLC frames."""

import unittest
from unittest import mock

import pw_status

from pw_protobuf_compiler import python_protos
import pw_rpc
from pw_rpc import callback_client
from pw_rpc.console_tools import CommandHelper, Context, ClientInfo, Watchdog


class TestWatchdog(unittest.TestCase):
    """Tests the Watchdog class."""
    def setUp(self) -> None:
        self._reset = mock.Mock()
        self._expiration = mock.Mock()
        self._while_expired = mock.Mock()

        self._watchdog = Watchdog(self._reset, self._expiration,
                                  self._while_expired, 99999)

    def _trigger_timeout(self) -> None:
        # Don't wait for the timeout -- that's too flaky. Call the internal
        # timeout function instead.
        self._watchdog._timeout_expired()  # pylint: disable=protected-access

    def test_expiration_callbacks(self) -> None:
        self._watchdog.start()

        self._expiration.not_called()

        self._trigger_timeout()

        self._expiration.assert_called_once_with()
        self._while_expired.assert_not_called()

        self._trigger_timeout()

        self._expiration.assert_called_once_with()
        self._while_expired.assert_called_once_with()

        self._trigger_timeout()

        self._expiration.assert_called_once_with()
        self._while_expired.assert_called()

    def test_reset_not_called_unless_expires(self) -> None:
        self._watchdog.start()
        self._watchdog.reset()

        self._reset.assert_not_called()
        self._expiration.assert_not_called()
        self._while_expired.assert_not_called()

    def test_reset_called_if_expired(self) -> None:
        self._watchdog.start()
        self._trigger_timeout()

        self._watchdog.reset()

        self._trigger_timeout()

        self._reset.assert_called_once_with()
        self._expiration.assert_called()


class TestCommandHelper(unittest.TestCase):
    def setUp(self) -> None:
        self._commands = {'command_a': 'A', 'command_B': 'B'}
        self._variables = {'hello': 1, 'world': 2}
        self._helper = CommandHelper(self._commands, self._variables,
                                     'The header', 'The footer')

    def test_help_contents(self) -> None:
        help_contents = self._helper.help()

        self.assertTrue(help_contents.startswith('The header'))
        self.assertIn('The footer', help_contents)

        for var_name in self._variables:
            self.assertIn(var_name, help_contents)

        for cmd_name in self._commands:
            self.assertIn(cmd_name, help_contents)

    def test_repr_is_help(self):
        self.assertEqual(repr(self._helper), self._helper.help())


_PROTO = """\
syntax = "proto3";

package the.pkg;

message SomeMessage {
  uint32 magic_number = 1;

    message AnotherMessage {
      string payload = 1;
    }

}

service Service {
  rpc Unary(SomeMessage) returns (SomeMessage.AnotherMessage);
}
"""


class TestConsoleContext(unittest.TestCase):
    """Tests console_tools.console.Context."""
    def setUp(self) -> None:
        self._protos = python_protos.Library.from_strings(_PROTO)

        self._info = ClientInfo(
            'the_client', object(),
            pw_rpc.Client.from_modules(callback_client.Impl(), [
                pw_rpc.Channel(1, lambda _: None),
                pw_rpc.Channel(2, lambda _: None),
            ], self._protos.modules()))

    def test_sets_expected_variables(self) -> None:
        variables = Context([self._info],
                            default_client=self._info.client,
                            protos=self._protos).variables()

        self.assertIn('set_target', variables)

        self.assertIsInstance(variables['help'], CommandHelper)
        self.assertIs(variables['python_help'], help)
        self.assertIs(pw_status.Status, variables['Status'])
        self.assertIs(self._info.client, variables['the_client'])

    def test_set_target_switches_between_clients(self) -> None:
        client_1_channel = self._info.rpc_client.channel(1).channel

        client_2_channel = pw_rpc.Channel(99, lambda _: None)
        info_2 = ClientInfo(
            'other_client', object(),
            pw_rpc.Client.from_modules(callback_client.Impl(),
                                       [client_2_channel],
                                       self._protos.modules()))

        context = Context([self._info, info_2],
                          default_client=self._info.client,
                          protos=self._protos)

        # Make sure the RPC service switches from one client to the other.
        self.assertIs(context.variables()['the'].pkg.Service.Unary.channel,
                      client_1_channel)

        context.set_target(info_2.client)

        self.assertIs(context.variables()['the'].pkg.Service.Unary.channel,
                      client_2_channel)

    def test_default_client_must_be_in_clients(self) -> None:
        with self.assertRaises(ValueError):
            Context([self._info],
                    default_client='something else',
                    protos=self._protos)

    def test_set_target_invalid_channel(self) -> None:
        context = Context([self._info],
                          default_client=self._info.client,
                          protos=self._protos)

        with self.assertRaises(KeyError):
            context.set_target(self._info.client, 100)

    def test_set_target_non_default_channel(self) -> None:
        channel_1 = self._info.rpc_client.channel(1).channel
        channel_2 = self._info.rpc_client.channel(2).channel

        context = Context([self._info],
                          default_client=self._info.client,
                          protos=self._protos)
        variables = context.variables()

        self.assertIs(variables['the'].pkg.Service.Unary.channel, channel_1)

        context.set_target(self._info.client, 2)

        self.assertIs(variables['the'].pkg.Service.Unary.channel, channel_2)

        with self.assertRaises(KeyError):
            context.set_target(self._info.client, 100)

    def test_set_target_requires_client_object(self) -> None:
        context = Context([self._info],
                          default_client=self._info.client,
                          protos=self._protos)

        with self.assertRaises(ValueError):
            context.set_target(self._info.rpc_client)

        context.set_target(self._info.client)

    def test_derived_context(self) -> None:
        called_derived_set_target = False

        class DerivedContext(Context):
            def set_target(self,
                           unused_selected_client,
                           unused_channel_id: int = None) -> None:
                nonlocal called_derived_set_target
                called_derived_set_target = True

        variables = DerivedContext(client_info=[self._info],
                                   default_client=self._info.client,
                                   protos=self._protos).variables()
        variables['set_target'](self._info.client)
        self.assertTrue(called_derived_set_target)


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