import unittest
from mock import patch, Mock
import SocketServer
import serial
import socket
from pymodbus3.device import ModbusDeviceIdentification
from pymodbus3.server.sync import ModbusBaseRequestHandler
from pymodbus3.server.sync import ModbusSingleRequestHandler
from pymodbus3.server.sync import ModbusConnectedRequestHandler
from pymodbus3.server.sync import ModbusDisconnectedRequestHandler
from pymodbus3.server.sync import ModbusTcpServer, ModbusUdpServer, ModbusSerialServer
from pymodbus3.server.sync import StartTcpServer, StartUdpServer, StartSerialServer
from pymodbus3.bit_read_message import ReadCoilsRequest, ReadCoilsResponse

#---------------------------------------------------------------------------#
# Mock Classes
#---------------------------------------------------------------------------#


class MockServer(object):
    def __init__(self):
        self.framer = lambda _: "framer"
        self.decoder = "decoder"
        self.threads = []
        self.context = {}

#---------------------------------------------------------------------------#
# Fixture
#---------------------------------------------------------------------------#


class SynchronousServerTest(unittest.TestCase):
    """
    This is the unittest for the pymodbus3.server.sync module
    """

    #-----------------------------------------------------------------------#
    # Test Base Request Handler
    #-----------------------------------------------------------------------#

    def test_base_handler_undefined_methods(self):
        """ Test the base handler undefined methods"""
        handler = SocketServer.BaseRequestHandler(None, None, None)
        handler.__class__ = ModbusBaseRequestHandler
        self.assertRaises(NotImplementedError, lambda: handler.send(None))
        self.assertRaises(NotImplementedError, lambda: handler.handle())

    def test_base_handler_methods(self):
        """ Test the base class for all the clients """
        request = ReadCoilsRequest(1, 1)
        address = ('server', 12345)
        server = MockServer()
        with patch.object(ModbusBaseRequestHandler, 'handle') as mock_handle:
            with patch.object(ModbusBaseRequestHandler, 'send') as mock_send:
                mock_handle.return_value = True
                mock_send.return_value = True
                handler = ModbusBaseRequestHandler(request, address, server)
                self.assertEqual(handler.running, True)
                self.assertEqual(handler.framer, 'framer')

                handler.execute(request)
                self.assertEqual(mock_send.call_count, 1)

                server.context[0x00] = object()
                handler.execute(request)
                self.assertEqual(mock_send.call_count, 2)

    #-----------------------------------------------------------------------#
    # Test Single Request Handler
    #-----------------------------------------------------------------------#
    def test_modbus_single_request_handler_send(self):
        handler = SocketServer.BaseRequestHandler(None, None, None)
        handler.__class__ = ModbusSingleRequestHandler
        handler.framer = Mock()
        handler.framer.buildPacket.return_value = "message"
        handler.request = Mock()
        request = ReadCoilsResponse([1])
        handler.send(request)
        self.assertEqual(handler.request.send.call_count, 1)

        request.should_respond = False
        handler.send(request)
        self.assertEqual(handler.request.send.call_count, 1)