class TestSecretCodeDecodingService(object):
    
    SAMPLE_ISLAND_COLOR_SERVER_RESPONSE = """{"couleur": "jaune"}"""
    SAMPLE_ISLAND_TYPE_SERVER_RESPONSE = """{"forme": "cercle"}"""
    SAMPLE_SECRET_CODE = "G"
    VERIFICATION_TIMEOUT = 10
    VERIFICATION_INTERVAL = 0.1

    @mock.patch('drivers.microcontroller_driver.MicrocontrollerDriver.MicrocontrollerDriver', autospec = False)
    @mock.patch('services.secret_code_decoding.SecretCodeDecodingService.urllib.request', autospec = False)
    def setup(self, request_mock, microcontroller_driver_mock):
        self._microcontroller_driver_mock_instance = microcontroller_driver_mock.return_value
        self._microcontroller_driver_mock_instance.get_secret_code.return_value = None
        
        self._request_mock = request_mock
        self._secret_code_decoding_service = SecretCodeDecodingService(self._microcontroller_driver_mock_instance)

    def test_when_no_secret_code_present_then_no_secret_code_is_returned(self):
        self._verify_decoding(None, None)

    def test_when_secret_code_present_then_island_color_is_decoded_from_server(self):
        self._request_mock.urlopen.return_value.read.return_value.decode.return_value = self.SAMPLE_ISLAND_COLOR_SERVER_RESPONSE
        self._microcontroller_driver_mock_instance.get_secret_code.return_value = self.SAMPLE_SECRET_CODE
        
        self._verify_decoding(self.SAMPLE_SECRET_CODE, IslandDescriptor(IslandType.ANY, IslandColor.YELLOW))

    def test_when_secret_code_present_then_island_type_is_decoded_from_server(self):
        self._request_mock.urlopen.return_value.read.return_value.decode.return_value = self.SAMPLE_ISLAND_TYPE_SERVER_RESPONSE
        self._microcontroller_driver_mock_instance.get_secret_code.return_value = self.SAMPLE_SECRET_CODE
        
        self._verify_decoding(self.SAMPLE_SECRET_CODE, IslandDescriptor(IslandType.CIRCLE, IslandColor.ANY))

    def _verify_decoding(self, expected_secret_code, expected_island_descriptor):
        self._thread = Thread(target = self._decoding_verification_thread, daemon = True, args = (expected_secret_code, expected_island_descriptor))
        self._thread.start()
        self._thread.join(self.VERIFICATION_TIMEOUT)
        if self._thread.is_alive():
            assert False, "Decoding verification timeout reached."

    def _decoding_verification_thread(self, expected_secret_code, expected_island_descriptor):
        while (self._secret_code_decoding_service.get_secret_code() != expected_secret_code
               or self._secret_code_decoding_service.get_target_island() != expected_island_descriptor):
            time.sleep(self.VERIFICATION_INTERVAL)
 def setup(self, request_mock, microcontroller_driver_mock):
     self._microcontroller_driver_mock_instance = microcontroller_driver_mock.return_value
     self._microcontroller_driver_mock_instance.get_secret_code.return_value = None
     
     self._request_mock = request_mock
     self._secret_code_decoding_service = SecretCodeDecodingService(self._microcontroller_driver_mock_instance)