def test_plugin_telegram_formating_py2(mock_post):
    """
    NotifyTelegram() Python v2 Formatting Tests

    """

    # Disable Throttling to speed testing
    plugins.NotifyTelegram.request_rate_per_sec = 0

    # Prepare Mock
    mock_post.return_value = requests.Request()
    mock_post.return_value.status_code = requests.codes.ok
    mock_post.return_value.content = '{}'

    # Simple success response
    mock_post.return_value.content = dumps({
        "ok":
        True,
        "result": [
            {
                "update_id": 645421321,
                "message": {
                    "message_id":
                    2,
                    "from": {
                        "id": 532389719,
                        "is_bot": False,
                        "first_name": "Chris",
                        "language_code": "en-US"
                    },
                    "chat": {
                        "id": 532389719,
                        "first_name": "Chris",
                        "type": "private"
                    },
                    "date":
                    1519694394,
                    "text":
                    "/start",
                    "entities": [{
                        "offset": 0,
                        "length": 6,
                        "type": "bot_command",
                    }],
                }
            },
        ],
    })
    mock_post.return_value.status_code = requests.codes.ok

    results = plugins.NotifyTelegram.parse_url(
        'tgram://123456789:abcdefg_hijklmnop/')

    instance = plugins.NotifyTelegram(**results)
    assert isinstance(instance, plugins.NotifyTelegram)

    response = instance.send(title='title', body='body')
    assert response is True
    # 1 call to look up bot owner, and second for notification
    assert mock_post.call_count == 2

    assert mock_post.call_args_list[0][0][0] == \
        'https://api.telegram.org/bot123456789:abcdefg_hijklmnop/getUpdates'
    assert mock_post.call_args_list[1][0][0] == \
        'https://api.telegram.org/bot123456789:abcdefg_hijklmnop/sendMessage'

    # Reset our values
    mock_post.reset_mock()

    # Now test our HTML Conversion as TEXT)
    aobj = Apprise()
    aobj.add('tgram://123456789:abcdefg_hijklmnop/')
    assert len(aobj) == 1

    title = '馃毃 Change detected for <i>Apprise Test Title</i>'
    body = '<a href="http://localhost"><i>Apprise Body Title</i></a>' \
           ' had <a href="http://127.0.0.1">a change</a>'

    assert aobj.notify(title=title, body=body, body_format=NotifyFormat.TEXT)

    # Test our calls
    assert mock_post.call_count == 2

    assert mock_post.call_args_list[0][0][0] == \
        'https://api.telegram.org/bot123456789:abcdefg_hijklmnop/getUpdates'
    assert mock_post.call_args_list[1][0][0] == \
        'https://api.telegram.org/bot123456789:abcdefg_hijklmnop/sendMessage'

    payload = loads(mock_post.call_args_list[1][1]['data'])

    # Test that everything is escaped properly in a TEXT mode
    assert payload['text'].encode('utf-8') == \
        '<b>\xf0\x9f\x9a\xa8 Change detected for &lt;i&gt;' \
        'Apprise Test Title&lt;/i&gt;</b>\r\n&lt;' \
        'a href="http://localhost"&gt;&lt;i&gt;Apprise Body Title' \
        '&lt;/i&gt;&lt;/a&gt; had &lt;a href="http://127.0.0.1"' \
        '&gt;a change&lt;/a&gt;'

    # Reset our values
    mock_post.reset_mock()

    # Now test our HTML Conversion as TEXT)
    aobj = Apprise()
    aobj.add('tgram://123456789:abcdefg_hijklmnop/?format=html')
    assert len(aobj) == 1

    assert aobj.notify(title=title, body=body, body_format=NotifyFormat.HTML)

    # Test our calls
    assert mock_post.call_count == 2

    assert mock_post.call_args_list[0][0][0] == \
        'https://api.telegram.org/bot123456789:abcdefg_hijklmnop/getUpdates'
    assert mock_post.call_args_list[1][0][0] == \
        'https://api.telegram.org/bot123456789:abcdefg_hijklmnop/sendMessage'

    payload = loads(mock_post.call_args_list[1][1]['data'])

    # Test that everything is escaped properly in a HTML mode
    assert payload['text'].encode('utf-8') == \
        '<b>\xf0\x9f\x9a\xa8 Change detected for <i>Apprise Test Title</i>' \
        '</b>\r\n<a href="http://localhost"><i>Apprise Body Title</i></a> ' \
        'had <a href="http://127.0.0.1">a change</a>'

    # Reset our values
    mock_post.reset_mock()

    # Now test our MARKDOWN Handling
    title = '# 馃毃 Change detected for _Apprise Test Title_'
    body = '_[Apprise Body Title](http://localhost)_' \
           ' had [a change](http://127.0.0.1)'

    aobj = Apprise()
    aobj.add('tgram://123456789:abcdefg_hijklmnop/?format=markdown')
    assert len(aobj) == 1

    assert aobj.notify(title=title,
                       body=body,
                       body_format=NotifyFormat.MARKDOWN)

    # Test our calls
    assert mock_post.call_count == 2

    assert mock_post.call_args_list[0][0][0] == \
        'https://api.telegram.org/bot123456789:abcdefg_hijklmnop/getUpdates'
    assert mock_post.call_args_list[1][0][0] == \
        'https://api.telegram.org/bot123456789:abcdefg_hijklmnop/sendMessage'

    payload = loads(mock_post.call_args_list[1][1]['data'])

    # Test that everything is escaped properly in a HTML mode
    assert payload['text'].encode('utf-8') == \
        '# \xf0\x9f\x9a\xa8 Change detected for _Apprise Test Title_\r\n_' \
        '[Apprise Body Title](http://localhost)_ had ' \
        '[a change](http://127.0.0.1)'

    # Reset our values
    mock_post.reset_mock()

    # Upstream to use HTML but input specified as Markdown
    aobj = Apprise()
    aobj.add('tgram://987654321:abcdefg_hijklmnop/?format=html')
    assert len(aobj) == 1

    # HTML forced by the command line, but MARKDOWN specified as
    # upstream mode
    assert aobj.notify(title=title,
                       body=body,
                       body_format=NotifyFormat.MARKDOWN)

    # Test our calls
    assert mock_post.call_count == 2

    assert mock_post.call_args_list[0][0][0] == \
        'https://api.telegram.org/bot987654321:abcdefg_hijklmnop/getUpdates'
    assert mock_post.call_args_list[1][0][0] == \
        'https://api.telegram.org/bot987654321:abcdefg_hijklmnop/sendMessage'

    payload = loads(mock_post.call_args_list[1][1]['data'])

    # Test that everything is escaped properly in a HTML mode
    assert payload['text'].encode('utf-8') == \
        '<b>\r\n<b>\xf0\x9f\x9a\xa8 Change detected for ' \
        '<i>Apprise Test Title</i></b>\r\n</b>\r\n<i>' \
        '<a href="http://localhost">Apprise Body Title</a>' \
        '</i> had <a href="http://127.0.0.1">a change</a>\r\n'

    # Reset our values
    mock_post.reset_mock()

    # Now test hebrew types (outside of default utf-8)
    # 讻讜转专转 谞驻诇讗讛 translates to 'A wonderful title'
    # 讝讜 讛讜讚注讛 translates to 'This is a notification'
    title = '讻讜转专转 谞驻诇讗讛' \
            .decode('utf-8').encode('ISO-8859-8')
    body = '[_[讝讜 讛讜讚注讛](http://localhost)_' \
           .decode('utf-8').encode('ISO-8859-8')

    asset = AppriseAsset(encoding='utf-8')
    # Now test default entries
    aobj = Apprise(asset=asset)
    aobj.add('tgram://123456789:abcdefg_hijklmnop/')
    assert len(aobj) == 1

    # Our notification will fail because we'll have an encoding error
    assert not aobj.notify(title=title, body=body)
    # Nothing was even attempted to be notified
    assert mock_post.call_count == 0

    # Let's use the expected input
    asset = AppriseAsset(encoding='ISO-8859-8')

    # Now test default entries
    aobj = Apprise(asset=asset)

    aobj.add('tgram://123456789:abcdefg_hijklmnop/')
    assert len(aobj) == 1

    # Our notification will work now
    assert aobj.notify(title=title, body=body)

    # Test our calls
    assert mock_post.call_count == 2

    assert mock_post.call_args_list[0][0][0] == \
        'https://api.telegram.org/bot123456789:abcdefg_hijklmnop/getUpdates'
    assert mock_post.call_args_list[1][0][0] == \
        'https://api.telegram.org/bot123456789:abcdefg_hijklmnop/sendMessage'

    payload = loads(mock_post.call_args_list[1][1]['data'])

    # Test that everything is escaped properly in a HTML mode
    assert payload['text'].encode('utf-8') == \
        '<b>\xd7\x9b\xd7\x95\xd7\xaa\xd7\xa8\xd7\xaa '\
        '\xd7\xa0\xd7\xa4\xd7\x9c\xd7\x90\xd7\x94</b>\r\n[_[\xd7\x96\xd7\x95 '\
        '\xd7\x94\xd7\x95\xd7\x93\xd7\xa2\xd7\x94](http://localhost)_'

    # Now we'll test an edge case where a title was defined, but after
    # processing it, it was determiend there really wasn't anything there
    # at all at the end of the day.

    # Reset our values
    mock_post.reset_mock()

    # Upstream to use HTML but input specified as Markdown
    aobj = Apprise()
    aobj.add('tgram://987654321:abcdefg_hijklmnop/?format=markdown')
    assert len(aobj) == 1

    # Now test our MARKDOWN Handling (no title defined... not really anyway)
    title = '# '
    body = '_[Apprise Body Title](http://localhost)_' \
           ' had [a change](http://127.0.0.2)'

    # MARKDOWN forced by the command line, but TEXT specified as
    # upstream mode
    assert aobj.notify(title=title, body=body, body_format=NotifyFormat.TEXT)

    # Test our calls
    assert mock_post.call_count == 2

    assert mock_post.call_args_list[0][0][0] == \
        'https://api.telegram.org/bot987654321:abcdefg_hijklmnop/getUpdates'
    assert mock_post.call_args_list[1][0][0] == \
        'https://api.telegram.org/bot987654321:abcdefg_hijklmnop/sendMessage'

    payload = loads(mock_post.call_args_list[1][1]['data'])

    # Test that everything is escaped properly in a HTML mode
    assert payload['text'] == \
        '_[Apprise Body Title](http://localhost)_ had ' \
        '[a change](http://127.0.0.2)'

    # Reset our values
    mock_post.reset_mock()

    # Upstream to use HTML but input specified as Markdown
    aobj = Apprise()
    aobj.add('tgram://987654321:abcdefg_hijklmnop/?format=markdown')
    assert len(aobj) == 1

    # Set an actual title this time
    title = '# A Great Title'
    body = '_[Apprise Body Title](http://localhost)_' \
           ' had [a change](http://127.0.0.2)'

    # MARKDOWN forced by the command line, but TEXT specified as
    # upstream mode
    assert aobj.notify(title=title, body=body, body_format=NotifyFormat.TEXT)

    # Test our calls
    assert mock_post.call_count == 2

    assert mock_post.call_args_list[0][0][0] == \
        'https://api.telegram.org/bot987654321:abcdefg_hijklmnop/getUpdates'
    assert mock_post.call_args_list[1][0][0] == \
        'https://api.telegram.org/bot987654321:abcdefg_hijklmnop/sendMessage'

    payload = loads(mock_post.call_args_list[1][1]['data'])

    # Test that everything is escaped properly in a HTML mode
    assert payload['text'] == \
        '# A Great Title\r\n_[Apprise Body Title](http://localhost)_ had ' \
        '[a change](http://127.0.0.2)'
def test_notify_telegram_plugin(mock_post, mock_get, tmpdir):
    """
    API: NotifyTelegram() Tests

    """
    # Disable Throttling to speed testing
    plugins.NotifyBase.request_rate_per_sec = 0

    # Bot Token
    bot_token = '123456789:abcdefg_hijklmnop'
    invalid_bot_token = 'abcd:123'

    # Chat ID
    chat_ids = 'l2g, lead2gold'

    # Prepare Mock
    mock_get.return_value = requests.Request()
    mock_post.return_value = requests.Request()
    mock_post.return_value.status_code = requests.codes.ok
    mock_get.return_value.status_code = requests.codes.ok
    mock_get.return_value.content = '{}'
    mock_post.return_value.content = '{}'

    # Exception should be thrown about the fact no bot token was specified
    with pytest.raises(TypeError):
        plugins.NotifyTelegram(bot_token=None, targets=chat_ids)

    # Invalid JSON while trying to detect bot owner
    mock_get.return_value.content = '{'
    mock_post.return_value.content = '}'
    with pytest.raises(TypeError):
        plugins.NotifyTelegram(bot_token=bot_token, targets=None)

    # Invalid JSON while trying to detect bot owner + 400 error
    mock_get.return_value.status_code = requests.codes.internal_server_error
    mock_post.return_value.status_code = requests.codes.internal_server_error
    with pytest.raises(TypeError):
        plugins.NotifyTelegram(bot_token=bot_token, targets=None)

    # Return status back to how they were
    mock_post.return_value.status_code = requests.codes.ok
    mock_get.return_value.status_code = requests.codes.ok

    # Exception should be thrown about the fact an invalid bot token was
    # specifed
    with pytest.raises(TypeError):
        plugins.NotifyTelegram(bot_token=invalid_bot_token, targets=chat_ids)

    obj = plugins.NotifyTelegram(bot_token=bot_token,
                                 targets=chat_ids,
                                 include_image=True)
    assert isinstance(obj, plugins.NotifyTelegram) is True
    assert len(obj.targets) == 2

    # Test Image Sending Exceptions
    mock_post.side_effect = IOError()
    assert not obj.send_media(obj.targets[0], NotifyType.INFO)

    # Test our other objects
    mock_post.side_effect = requests.HTTPError
    assert not obj.send_media(obj.targets[0], NotifyType.INFO)

    # Restore their entries
    mock_get.side_effect = None
    mock_post.side_effect = None
    mock_get.return_value.content = '{}'
    mock_post.return_value.content = '{}'

    # test url call
    assert isinstance(obj.url(), six.string_types) is True

    # test privacy version of url
    assert isinstance(obj.url(privacy=True), six.string_types) is True
    assert obj.url(privacy=True).startswith('tgram://1...p/') is True

    # Test that we can load the string we generate back:
    obj = plugins.NotifyTelegram(**plugins.NotifyTelegram.parse_url(obj.url()))
    assert isinstance(obj, plugins.NotifyTelegram) is True

    # Prepare Mock to fail
    response = mock.Mock()
    response.status_code = requests.codes.internal_server_error

    # a error response
    response.content = dumps({
        'description': 'test',
    })
    mock_get.return_value = response
    mock_post.return_value = response

    # No image asset
    nimg_obj = plugins.NotifyTelegram(bot_token=bot_token, targets=chat_ids)
    nimg_obj.asset = AppriseAsset(image_path_mask=False, image_url_mask=False)

    # Test that our default settings over-ride base settings since they are
    # not the same as the one specified in the base; this check merely
    # ensures our plugin inheritance is working properly
    assert obj.body_maxlen == plugins.NotifyTelegram.body_maxlen

    # We don't override the title maxlen so we should be set to the same
    # as our parent class in this case
    assert obj.title_maxlen == plugins.NotifyBase.title_maxlen

    # This tests erroneous messages involving multiple chat ids
    assert obj.notify(body='body', title='title',
                      notify_type=NotifyType.INFO) is False
    assert obj.notify(body='body', title='title',
                      notify_type=NotifyType.INFO) is False
    assert nimg_obj.notify(
        body='body', title='title', notify_type=NotifyType.INFO) is False

    # This tests erroneous messages involving a single chat id
    obj = plugins.NotifyTelegram(bot_token=bot_token, targets='l2g')
    nimg_obj = plugins.NotifyTelegram(bot_token=bot_token, targets='l2g')
    nimg_obj.asset = AppriseAsset(image_path_mask=False, image_url_mask=False)

    assert obj.notify(body='body', title='title',
                      notify_type=NotifyType.INFO) is False
    assert nimg_obj.notify(
        body='body', title='title', notify_type=NotifyType.INFO) is False

    # Bot Token Detection
    # Just to make it clear to people reading this code and trying to learn
    # what is going on.  Apprise tries to detect the bot owner if you don't
    # specify a user to message.  The idea is to just default to messaging
    # the bot owner himself (it makes it easier for people).  So we're testing
    # the creating of a Telegram Notification without providing a chat ID.
    # We're testing the error handling of this bot detection section of the
    # code
    mock_post.return_value.content = dumps({
        "ok":
        True,
        "result": [
            {
                "update_id": 645421321,
                "message": {
                    "message_id":
                    1,
                    "from": {
                        "id": 532389719,
                        "is_bot": False,
                        "first_name": "Chris",
                        "language_code": "en-US"
                    },
                    "chat": {
                        "id": 532389719,
                        "first_name": "Chris",
                        "type": "private"
                    },
                    "date":
                    1519694394,
                    "text":
                    "/start",
                    "entities": [{
                        "offset": 0,
                        "length": 6,
                        "type": "bot_command",
                    }],
                }
            },
        ],
    })
    mock_post.return_value.status_code = requests.codes.ok

    # Test sending attachments
    obj = plugins.NotifyTelegram(bot_token=bot_token, targets='12345')
    assert len(obj.targets) == 1
    assert obj.targets[0] == '12345'

    path = os.path.join(TEST_VAR_DIR, 'apprise-test.gif')
    attach = AppriseAttachment(path)
    assert obj.notify(
        body='body', title='title', notify_type=NotifyType.INFO,
        attach=attach) is True

    path = os.path.join(TEST_VAR_DIR, '/invalid/path/to/an/invalid/file.jpg')
    assert obj.notify(
        body='body', title='title', notify_type=NotifyType.INFO,
        attach=path) is False

    obj = plugins.NotifyTelegram(bot_token=bot_token, targets=None)
    assert len(obj.targets) == 1
    assert obj.targets[0] == '532389719'

    # Do the test again, but without the expected (parsed response)
    mock_post.return_value.content = dumps({
        "ok": True,
        "result": [],
    })

    # Exception should be thrown about the fact no bot token was specified
    with pytest.raises(TypeError):
        plugins.NotifyTelegram(bot_token=bot_token, targets=None)

    # Detect the bot with a bad response
    mock_post.return_value.content = dumps({})
    obj.detect_bot_owner()

    # Test our bot detection with a internal server error
    mock_post.return_value.status_code = requests.codes.internal_server_error

    # Exception should be thrown over internal server error caused
    with pytest.raises(TypeError):
        plugins.NotifyTelegram(bot_token=bot_token, targets=None)

    # Test our bot detection with an unmappable html error
    mock_post.return_value.status_code = 999
    # Exception should be thrown over invali internal error no
    with pytest.raises(TypeError):
        plugins.NotifyTelegram(bot_token=bot_token, targets=None)

    # Do it again but this time provide a failure message
    mock_post.return_value.content = dumps({'description': 'Failure Message'})

    # Exception should be thrown about the fact no bot token was specified
    with pytest.raises(TypeError):
        plugins.NotifyTelegram(bot_token=bot_token, targets=None)

    # Do it again but this time provide a failure message and perform a
    # notification without a bot detection by providing at least 1 chat id
    obj = plugins.NotifyTelegram(bot_token=bot_token, targets=['@abcd'])
    assert nimg_obj.notify(
        body='body', title='title', notify_type=NotifyType.INFO) is False

    # iterate over our exceptions and test them
    mock_post.side_effect = requests.HTTPError

    # No chat_ids specified
    with pytest.raises(TypeError):
        obj = plugins.NotifyTelegram(bot_token=bot_token, targets=None)
def test_plugin_telegram_general(mock_post):
    """
    NotifyTelegram() General Tests

    """

    # Disable Throttling to speed testing
    plugins.NotifyTelegram.request_rate_per_sec = 0

    # Bot Token
    bot_token = '123456789:abcdefg_hijklmnop'
    invalid_bot_token = 'abcd:123'

    # Chat ID
    chat_ids = 'l2g, lead2gold'

    # Prepare Mock
    mock_post.return_value = requests.Request()
    mock_post.return_value.status_code = requests.codes.ok
    mock_post.return_value.content = '{}'

    # Exception should be thrown about the fact no bot token was specified
    with pytest.raises(TypeError):
        plugins.NotifyTelegram(bot_token=None, targets=chat_ids)

    # Invalid JSON while trying to detect bot owner
    mock_post.return_value.content = '}'
    obj = plugins.NotifyTelegram(bot_token=bot_token, targets=None)
    obj.notify(title='hello', body='world')

    # Invalid JSON while trying to detect bot owner + 400 error
    mock_post.return_value.status_code = requests.codes.internal_server_error
    obj = plugins.NotifyTelegram(bot_token=bot_token, targets=None)
    obj.notify(title='hello', body='world')

    # Return status back to how they were
    mock_post.return_value.status_code = requests.codes.ok

    # Exception should be thrown about the fact an invalid bot token was
    # specifed
    with pytest.raises(TypeError):
        plugins.NotifyTelegram(bot_token=invalid_bot_token, targets=chat_ids)

    obj = plugins.NotifyTelegram(bot_token=bot_token,
                                 targets=chat_ids,
                                 include_image=True)
    assert isinstance(obj, plugins.NotifyTelegram) is True
    assert len(obj.targets) == 2

    # Test Image Sending Exceptions
    mock_post.side_effect = IOError()
    assert not obj.send_media(obj.targets[0], NotifyType.INFO)

    # Test our other objects
    mock_post.side_effect = requests.HTTPError
    assert not obj.send_media(obj.targets[0], NotifyType.INFO)

    # Restore their entries
    mock_post.side_effect = None
    mock_post.return_value.content = '{}'

    # test url call
    assert isinstance(obj.url(), six.string_types) is True

    # test privacy version of url
    assert isinstance(obj.url(privacy=True), six.string_types) is True
    assert obj.url(privacy=True).startswith('tgram://1...p/') is True

    # Test that we can load the string we generate back:
    obj = plugins.NotifyTelegram(**plugins.NotifyTelegram.parse_url(obj.url()))
    assert isinstance(obj, plugins.NotifyTelegram) is True

    # Prepare Mock to fail
    response = mock.Mock()
    response.status_code = requests.codes.internal_server_error

    # a error response
    response.content = dumps({
        'description': 'test',
    })
    mock_post.return_value = response

    # No image asset
    nimg_obj = plugins.NotifyTelegram(bot_token=bot_token, targets=chat_ids)
    nimg_obj.asset = AppriseAsset(image_path_mask=False, image_url_mask=False)

    # Test that our default settings over-ride base settings since they are
    # not the same as the one specified in the base; this check merely
    # ensures our plugin inheritance is working properly
    assert obj.body_maxlen == plugins.NotifyTelegram.body_maxlen

    # This tests erroneous messages involving multiple chat ids
    assert obj.notify(body='body', title='title',
                      notify_type=NotifyType.INFO) is False
    assert obj.notify(body='body', title='title',
                      notify_type=NotifyType.INFO) is False
    assert nimg_obj.notify(
        body='body', title='title', notify_type=NotifyType.INFO) is False

    # This tests erroneous messages involving a single chat id
    obj = plugins.NotifyTelegram(bot_token=bot_token, targets='l2g')
    nimg_obj = plugins.NotifyTelegram(bot_token=bot_token, targets='l2g')
    nimg_obj.asset = AppriseAsset(image_path_mask=False, image_url_mask=False)

    assert obj.notify(body='body', title='title',
                      notify_type=NotifyType.INFO) is False
    assert nimg_obj.notify(
        body='body', title='title', notify_type=NotifyType.INFO) is False

    # Bot Token Detection
    # Just to make it clear to people reading this code and trying to learn
    # what is going on.  Apprise tries to detect the bot owner if you don't
    # specify a user to message.  The idea is to just default to messaging
    # the bot owner himself (it makes it easier for people).  So we're testing
    # the creating of a Telegram Notification without providing a chat ID.
    # We're testing the error handling of this bot detection section of the
    # code
    mock_post.return_value.content = dumps({
        "ok":
        True,
        "result": [
            {
                "update_id": 645421319,
                # Entry without `message` in it
            },
            {
                # Entry without `from` in `message`
                "update_id": 645421320,
                "message": {
                    "message_id":
                    2,
                    "chat": {
                        "id": 532389719,
                        "first_name": "Chris",
                        "type": "private"
                    },
                    "date":
                    1519694394,
                    "text":
                    "/start",
                    "entities": [{
                        "offset": 0,
                        "length": 6,
                        "type": "bot_command",
                    }],
                }
            },
            {
                "update_id": 645421321,
                "message": {
                    "message_id":
                    2,
                    "from": {
                        "id": 532389719,
                        "is_bot": False,
                        "first_name": "Chris",
                        "language_code": "en-US"
                    },
                    "chat": {
                        "id": 532389719,
                        "first_name": "Chris",
                        "type": "private"
                    },
                    "date":
                    1519694394,
                    "text":
                    "/start",
                    "entities": [{
                        "offset": 0,
                        "length": 6,
                        "type": "bot_command",
                    }],
                }
            },
        ],
    })
    mock_post.return_value.status_code = requests.codes.ok

    obj = plugins.NotifyTelegram(bot_token=bot_token, targets='12345')
    assert len(obj.targets) == 1
    assert obj.targets[0] == '12345'

    # Test the escaping of characters since Telegram escapes stuff for us to
    # which we need to consider
    mock_post.reset_mock()
    body = "<p>\'\"This can't\t\r\nfail&nbsp;us\"\'</p>"
    assert obj.notify(body=body,
                      title='special characters',
                      notify_type=NotifyType.INFO) is True
    assert mock_post.call_count == 1
    payload = loads(mock_post.call_args_list[0][1]['data'])

    # Test our payload
    assert payload['text'] == \
        '<b>special characters</b>\r\n\'"This can\'t\t\r\nfail us"\'\r\n'

    # Test sending attachments
    attach = AppriseAttachment(os.path.join(TEST_VAR_DIR, 'apprise-test.gif'))
    assert obj.notify(
        body='body', title='title', notify_type=NotifyType.INFO,
        attach=attach) is True

    # An invalid attachment will cause a failure
    path = os.path.join(TEST_VAR_DIR, '/invalid/path/to/an/invalid/file.jpg')
    attach = AppriseAttachment(path)
    assert obj.notify(
        body='body', title='title', notify_type=NotifyType.INFO,
        attach=path) is False

    obj = plugins.NotifyTelegram(bot_token=bot_token, targets=None)
    # No user detected; this happens after our firsst notification
    assert len(obj.targets) == 0

    assert obj.notify(title='hello', body='world') is True
    assert len(obj.targets) == 1
    assert obj.targets[0] == '532389719'

    # Do the test again, but without the expected (parsed response)
    mock_post.return_value.content = dumps({
        "ok": True,
        "result": [],
    })

    # No user will be detected now
    obj = plugins.NotifyTelegram(bot_token=bot_token, targets=None)
    # No user detected; this happens after our firsst notification
    assert len(obj.targets) == 0
    assert obj.notify(title='hello', body='world') is False
    assert len(obj.targets) == 0

    # Do the test again, but with ok not set to True
    mock_post.return_value.content = dumps({
        "ok":
        False,
        "result": [
            {
                "update_id": 645421321,
                "message": {
                    "message_id":
                    2,
                    "from": {
                        "id": 532389719,
                        "is_bot": False,
                        "first_name": "Chris",
                        "language_code": "en-US"
                    },
                    "chat": {
                        "id": 532389719,
                        "first_name": "Chris",
                        "type": "private"
                    },
                    "date":
                    1519694394,
                    "text":
                    "/start",
                    "entities": [{
                        "offset": 0,
                        "length": 6,
                        "type": "bot_command",
                    }],
                }
            },
        ],
    })

    # No user will be detected now
    obj = plugins.NotifyTelegram(bot_token=bot_token, targets=None)
    # No user detected; this happens after our firsst notification
    assert len(obj.targets) == 0
    assert obj.notify(title='hello', body='world') is False
    assert len(obj.targets) == 0

    # An edge case where no results were provided; this will probably never
    # happen, but it helps with test coverage completeness
    mock_post.return_value.content = dumps({
        "ok": True,
    })

    # No user will be detected now
    obj = plugins.NotifyTelegram(bot_token=bot_token, targets=None)
    # No user detected; this happens after our firsst notification
    assert len(obj.targets) == 0
    assert obj.notify(title='hello', body='world') is False
    assert len(obj.targets) == 0
    # Detect the bot with a bad response
    mock_post.return_value.content = dumps({})
    obj.detect_bot_owner()

    # Test our bot detection with a internal server error
    mock_post.return_value.status_code = requests.codes.internal_server_error

    # internal server error prevents notification from being sent
    obj = plugins.NotifyTelegram(bot_token=bot_token, targets=None)
    assert len(obj.targets) == 0
    assert obj.notify(title='hello', body='world') is False
    assert len(obj.targets) == 0

    # Test our bot detection with an unmappable html error
    mock_post.return_value.status_code = 999
    plugins.NotifyTelegram(bot_token=bot_token, targets=None)
    assert len(obj.targets) == 0
    assert obj.notify(title='hello', body='world') is False
    assert len(obj.targets) == 0

    # Do it again but this time provide a failure message
    mock_post.return_value.content = dumps({'description': 'Failure Message'})
    plugins.NotifyTelegram(bot_token=bot_token, targets=None)
    assert len(obj.targets) == 0
    assert obj.notify(title='hello', body='world') is False
    assert len(obj.targets) == 0

    # Do it again but this time provide a failure message and perform a
    # notification without a bot detection by providing at least 1 chat id
    obj = plugins.NotifyTelegram(bot_token=bot_token, targets=['@abcd'])
    assert nimg_obj.notify(
        body='body', title='title', notify_type=NotifyType.INFO) is False

    # iterate over our exceptions and test them
    mock_post.side_effect = requests.HTTPError

    # No chat_ids specified
    obj = plugins.NotifyTelegram(bot_token=bot_token, targets=None)
    assert len(obj.targets) == 0
    assert obj.notify(title='hello', body='world') is False
    assert len(obj.targets) == 0

    # Test Telegram Group
    obj = Apprise.instantiate(
        'tgram://123456789:ABCdefghijkl123456789opqyz/-123456789525')
    assert isinstance(obj, plugins.NotifyTelegram)
    assert len(obj.targets) == 1
    assert '-123456789525' in obj.targets