# Path: responsebot/responsebot_stream.py
# class ResponseBotStream(object):
#     """
#     Connect to Twitter's streaming API and handle any error that occurs.
#     """
#     def __init__(self, client, listener):
#         """
#         :param client: Some Twitter API client for authentication. E.g. :class:`~responsebot.tweet_client.TweetClient`
#         :param listener: A central listener that will receive tweets from the stream and forward them to user's
#         handlers. E.g. :class:`~responsebot.listeners.responsebot_listener.ResponseBotListener`
#         """
#         self.client = client
#         self.listener = listener
#         self.filter = listener.get_merged_filter()
# 
#     def start(self, retry_limit=None):
#         """
#         Try to connect to Twitter's streaming API.
# 
#         :param retry_limit: The maximum number of retries in case of failures. Default is None (unlimited)
#         :raises :class:`~tweepy.error.TweepyError`: If there's some critical API error
#         """
#         # Run tweepy stream
#         wrapper_listener = TweepyWrapperListener(listener=self.listener)
#         stream = tweepy.Stream(auth=self.client.tweepy_api.auth, listener=wrapper_listener)
# 
#         retry_counter = 0
#         while retry_limit is None or retry_counter <= retry_limit:
#             try:
#                 retry_counter += 1
#                 if not self.client.config.get('user_stream'):
#                     logging.info('Listening to public stream')
#                     stream.filter(follow=self.filter.follow, track=self.filter.track)
#                 else:
#                     if self.filter.follow:
#                         logging.warning('Follow filters won\'t be used in user stream')
# 
#                     logging.info('Listening to user stream')
#                     stream.userstream(track=self.filter.track)
#             except AttributeError as e:
#                 # Known Tweepy's issue https://github.com/tweepy/tweepy/issues/576
#                 if "'NoneType' object has no attribute 'strip'" in str(e):
#                     pass
#                 else:
#                     raise


from unittest.case import TestCase
from tweepy.error import TweepError
from responsebot.responsebot_stream import ResponseBotStream
    from mock import patch, MagicMock
    from unittest.mock import patch, MagicMock
    def test_filter_using_merged_filter(self):
        merged_filter = MagicMock(track=['track'], follow=['follow'])
        mock_client = MagicMock(config=MagicMock(get=MagicMock(return_value=False)))
        stream = ResponseBotStream(client=mock_client, listener=MagicMock(
                get_merged_filter=MagicMock(return_value=merged_filter)))

        with patch('responsebot.responsebot_stream.tweepy.Stream.filter') as mock_filter_call:
            stream.start(retry_limit=0)

            mock_filter_call.assert_called_once_with(track=merged_filter.track, follow=merged_filter.follow)

    @patch('responsebot.responsebot_stream.tweepy.Stream.filter',
           side_effect=AttributeError('\'NoneType\' object has no attribute \'strip\''))
    def test_ignore_tweepy_attribute_error(self, mock_stream):
        mock_client = MagicMock(config=MagicMock(get=MagicMock(return_value=False)))
        stream = ResponseBotStream(client=mock_client, listener=MagicMock())
        stream.start(retry_limit=1)

        self.assertEqual(mock_stream.call_count, 2)

    @patch('responsebot.responsebot_stream.tweepy.Stream.filter',
           side_effect=AttributeError('Some error that is not NoneType'))
    def test_raise_attribute_error(self, mock_stream):
        mock_client = MagicMock(config=MagicMock(get=MagicMock(return_value=False)))
        stream = ResponseBotStream(client=mock_client, listener=MagicMock())
        self.assertRaises(AttributeError, stream.start)

    def test_use_user_stream(self):
        mock_client = MagicMock(config=MagicMock(get=MagicMock(return_value=True)))
        merged_filter = MagicMock(track=['track'])

# Path: responsebot/responsebot_stream.py
# class ResponseBotStream(object):
#     """
#     Connect to Twitter's streaming API and handle any error that occurs.
#     """
#     def __init__(self, client, listener):
#         """
#         :param client: Some Twitter API client for authentication. E.g. :class:`~responsebot.tweet_client.TweetClient`
#         :param listener: A central listener that will receive tweets from the stream and forward them to user's
#         handlers. E.g. :class:`~responsebot.listeners.responsebot_listener.ResponseBotListener`
#         """
#         self.client = client
#         self.listener = listener
#         self.filter = listener.get_merged_filter()
# 
#     def start(self, retry_limit=None):
#         """
#         Try to connect to Twitter's streaming API.
# 
#         :param retry_limit: The maximum number of retries in case of failures. Default is None (unlimited)
#         :raises :class:`~tweepy.error.TweepyError`: If there's some critical API error
#         """
#         # Run tweepy stream
#         wrapper_listener = TweepyWrapperListener(listener=self.listener)
#         stream = tweepy.Stream(auth=self.client.tweepy_api.auth, listener=wrapper_listener)
# 
#         retry_counter = 0
#         while retry_limit is None or retry_counter <= retry_limit:
#             try:
#                 retry_counter += 1
#                 if not self.client.config.get('user_stream'):
#                     logging.info('Listening to public stream')
#                     stream.filter(follow=self.filter.follow, track=self.filter.track)
#                 else:
#                     if self.filter.follow:
#                         logging.warning('Follow filters won\'t be used in user stream')
# 
#                     logging.info('Listening to user stream')
#                     stream.userstream(track=self.filter.track)
#             except AttributeError as e:
#                 # Known Tweepy's issue https://github.com/tweepy/tweepy/issues/576
#                 if "'NoneType' object has no attribute 'strip'" in str(e):
#                     pass
#                 else:
#                     raise


# Path: tests/unit_tests/test_tweet_stream.py
from unittest.case import TestCase
from tweepy.error import TweepError
from responsebot.responsebot_stream import ResponseBotStream
    from mock import patch, MagicMock
    from unittest.mock import patch, MagicMock

    def test_filter_using_merged_filter(self):
        merged_filter = MagicMock(track=['track'], follow=['follow'])
        mock_client = MagicMock(config=MagicMock(get=MagicMock(return_value=False)))
        stream = ResponseBotStream(client=mock_client, listener=MagicMock(
                get_merged_filter=MagicMock(return_value=merged_filter)))

        with patch('responsebot.responsebot_stream.tweepy.Stream.filter') as mock_filter_call:
            stream.start(retry_limit=0)

            mock_filter_call.assert_called_once_with(track=merged_filter.track, follow=merged_filter.follow)

    @patch('responsebot.responsebot_stream.tweepy.Stream.filter',
           side_effect=AttributeError('\'NoneType\' object has no attribute \'strip\''))
    def test_ignore_tweepy_attribute_error(self, mock_stream):
        mock_client = MagicMock(config=MagicMock(get=MagicMock(return_value=False)))
        stream = ResponseBotStream(client=mock_client, listener=MagicMock())
        stream.start(retry_limit=1)

        self.assertEqual(mock_stream.call_count, 2)

    @patch('responsebot.responsebot_stream.tweepy.Stream.filter',
           side_effect=AttributeError('Some error that is not NoneType'))
    def test_raise_attribute_error(self, mock_stream):
        mock_client = MagicMock(config=MagicMock(get=MagicMock(return_value=False)))
        stream = ResponseBotStream(client=mock_client, listener=MagicMock())
        self.assertRaises(AttributeError, stream.start)

    def test_use_user_stream(self):
        mock_client = MagicMock(config=MagicMock(get=MagicMock(return_value=True)))
        merged_filter = MagicMock(track=['track'])

        stream = ResponseBotStream(client=mock_client, listener=MagicMock(