class TestVideoStreamDispatcher(object):
    
    SAMPLE_DEFAULT_IMAGE = object()
    SAMPLE_IMAGE = object()
    SAMPLE_FPS = 5

    @mock.patch('services.video_streaming.stream_writers.InMemoryBufferedStreamWriter.InMemoryBufferedStreamWriter', autospec = False)
    @mock.patch('services.video_streaming.stream_readers.CameraStreamReader.CameraStreamReader', autospec = False)
    def setup(self, stream_reader_mock, stream_writer_mock):
        self._stream_reader_mock = stream_reader_mock
        self._stream_writer_mock = stream_writer_mock

        self._stream_reader_mock.read_next.side_effect = self._read_next_mock

        self._video_stream_dispatcher = VideoStreamDispatcher(self.SAMPLE_DEFAULT_IMAGE)
        self._video_stream_dispatcher.stream_reader = stream_reader_mock
        self._video_stream_dispatcher.add_stream_writer(stream_writer_mock)

    def _read_next_mock(self):
        time.sleep(1 / self.SAMPLE_FPS)
        return self.SAMPLE_IMAGE
        
    def test_when_dispatching_then_image_is_dispatched_to_stream_writer(self):
        self._dispatch()
        self._stream_writer_mock.write.assert_called_with(self.SAMPLE_IMAGE)
        
    def test_given_read_error_when_dispatching_then_last_image_is_dispatched_to_stream_writer(self):
        self._stream_reader_mock.read_next.side_effect = [self.SAMPLE_IMAGE, IOError]
        self._dispatch()
        self._stream_writer_mock.write.assert_called_with(self.SAMPLE_IMAGE)

    def test_given_read_error_and_no_last_image_when_dispatching_then_default_image_is_dispatched_to_stream_writer(self):
        self._stream_reader_mock.read_next.side_effect = IOError
        self._dispatch()
        self._stream_writer_mock.write.assert_called_with(self.SAMPLE_DEFAULT_IMAGE)

    def _dispatch(self):
        self._video_stream_dispatcher.start_dispatching_async()
        time.sleep(0.25)
        self._video_stream_dispatcher.stop_dispatching()