From 1311782bedaa31c28edf36bf1dfb0decd971b6e3 Mon Sep 17 00:00:00 2001 From: Chris Caron Date: Wed, 29 Nov 2017 22:24:01 -0500 Subject: [PATCH] Apprise and AppriseAsset unittesting + bugfixes --- apprise/Apprise.py | 28 +++--- apprise/AppriseAsset.py | 5 +- test/test_api.py | 184 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 199 insertions(+), 18 deletions(-) diff --git a/apprise/Apprise.py b/apprise/Apprise.py index d0efc6a2..40790ca7 100644 --- a/apprise/Apprise.py +++ b/apprise/Apprise.py @@ -36,7 +36,7 @@ logger = logging.getLogger(__name__) SCHEMA_MAP = {} # Used for attempting to acquire the schema if the URL can't be parsed. -GET_SCHEMA_RE = re.compile('\s*(?P[a-z0-9]+)://.*$', re.I) +GET_SCHEMA_RE = re.compile('\s*(?P[a-z0-9]{3,9})://.*$', re.I) # Load our Lookup Matrix @@ -181,15 +181,15 @@ class Apprise(object): # Add our initialized plugin to our server listings self.servers.append(plugin) - # Return our status - return return_status + # Return our status + return return_status - def clear(self, urls): + def clear(self): """ Empties our server list """ - self.servers.clear() + self.servers[:] = [] def notify(self, title, body, notify_type=NotifyType.SUCCESS, **kwargs): """ @@ -199,16 +199,8 @@ class Apprise(object): # Initialize our return result status = len(self.servers) > 0 - if notify_type and notify_type not in NOTIFY_TYPES: - logger.warning( - 'An invalid notification type (%s) was specified.' % ( - notify_type)) - - if not isinstance(body, basestring): - body = '' - - if not isinstance(title, basestring): - title = '' + if not (title or body): + return False # Iterate over our loaded plugins for server in self.servers: @@ -226,3 +218,9 @@ class Apprise(object): status = False return status + + def __len__(self): + """ + Returns the number of servers loaded + """ + return len(self.servers) diff --git a/apprise/AppriseAsset.py b/apprise/AppriseAsset.py index d6eaeecb..2bd32c81 100644 --- a/apprise/AppriseAsset.py +++ b/apprise/AppriseAsset.py @@ -42,6 +42,9 @@ class AppriseAsset(object): NotifyType.WARNING: '#CACF29', } + # The default color to return if a mapping isn't found in our table above + default_html_color = '#888888' + # The default theme theme = 'default' @@ -79,7 +82,7 @@ class AppriseAsset(object): """ # Attempt to get the type, otherwise return a default grey # if we couldn't look up the entry - return self.html_notify_map.get(notify_type, '#888888') + return self.html_notify_map.get(notify_type, self.default_html_color) def image_url(self, notify_type, image_size): """ diff --git a/test/test_api.py b/test/test_api.py index f694d21c..2b618840 100644 --- a/test/test_api.py +++ b/test/test_api.py @@ -5,8 +5,188 @@ from __future__ import print_function from __future__ import unicode_literals from apprise import Apprise +from apprise import AppriseAsset +from apprise.Apprise import SCHEMA_MAP +from apprise.plugins.NotifyBase import NotifyBase +from apprise import NotifyType +from apprise import NotifyImageSize -def test_initialization(): - "API: apprise() test initialization""" +def test_apprise(): + """ + API: Apprise() object + + """ a = Apprise() + + # no items + assert(len(a) == 0) + + # Create an Asset object + asset = AppriseAsset(theme='default') + + # We can load the device using our asset + a = Apprise(asset=asset) + + # We can load our servers up front as well + servers = [ + 'faast://abcdefghijklmnop-abcdefg', + 'kodi://kodi.server.local', + 'palot://1f418df7577e32b89ac6511f2eb9aa68', + ] + + a = Apprise(servers=servers) + + # 3 servers loaded + assert(len(a) == 3) + + # We can add another server + assert( + a.add('mmosts://mattermost.server.local/' + '3ccdd113474722377935511fc85d3dd4') is True) + assert(len(a) == 4) + + # We can empty our set + a.clear() + assert(len(a) == 0) + + # An invalid schema + assert( + a.add('this is not a parseable url at all') is False) + assert(len(a) == 0) + + # An unsupported schema + assert( + a.add('invalid://we.just.do.not.support.this.plugin.type') is False) + assert(len(a) == 0) + + # A poorly formatted URL + assert( + a.add('json://user:@@@:bad?no.good') is False) + assert(len(a) == 0) + + # Add a server with our asset we created earlier + assert( + a.add('mmosts://mattermost.server.local/' + '3ccdd113474722377935511fc85d3dd4', asset=asset) is True) + + # Clear our server listings again + a.clear() + + # No servers to notify + assert(a.notify(title="my title", body="my body") is False) + + class BadNotification(NotifyBase): + def __init__(self, **kwargs): + super(BadNotification, self).__init__() + + # We fail whenever we're initialized + raise TypeError() + + class GoodNotification(NotifyBase): + def __init__(self, **kwargs): + super(GoodNotification, self).__init__() + + def notify(self, **kwargs): + # Pretend everything is okay + return True + + # Store our bad notification in our schema map + SCHEMA_MAP['bad'] = BadNotification + + # Store our good notification in our schema map + SCHEMA_MAP['good'] = GoodNotification + + # Just to explain what is happening here, we would have parsed the + # url properly but failed when we went to go and create an instance + # of it. + assert(a.add('bad://localhost') is False) + assert(len(a) == 0) + + assert(a.add('good://localhost') is True) + assert(len(a) == 1) + + # Bad Notification Type is still allowed as it is presumed the user + # know's what their doing + assert(a.notify( + title="my title", body="my body", notify_type='bad') is True) + + # No Title/Body combo's + assert(a.notify(title=None, body=None) is False) + assert(a.notify(title='', body=None) is False) + assert(a.notify(title=None, body='') is False) + + # As long as one is present, we're good + assert(a.notify(title=None, body='present') is True) + assert(a.notify(title='present', body=None) is True) + assert(a.notify(title="present", body="present") is True) + + # Clear our server listings again + a.clear() + + class ThrowNotification(NotifyBase): + def notify(self, **kwargs): + # Pretend everything is okay + raise TypeError() + + class FailNotification(NotifyBase): + + def notify(self, **kwargs): + # Pretend everything is okay + return False + + # Store our bad notification in our schema map + SCHEMA_MAP['throw'] = ThrowNotification + + # Store our good notification in our schema map + SCHEMA_MAP['fail'] = FailNotification + + assert(a.add('throw://localhost') is True) + assert(a.add('fail://localhost') is True) + assert(len(a) == 2) + + # Test when our notify both throws an exception and or just + # simply returns False + assert(a.notify(title="present", body="present") is False) + + +def test_apprise_asset(): + """ + API: AppriseAsset() object + + """ + a = AppriseAsset( + theme='dark', + image_path_mask='/{THEME}/{TYPE}-{XY}.png', + image_url_mask='http://localhost/{THEME}/{TYPE}-{XY}.png', + ) + + a.default_html_color = '#abcabc' + a.html_notify_map[NotifyType.INFO] = '#aaaaaa' + + assert(a.html_color('invalid') == '#abcabc') + assert(a.html_color(NotifyType.INFO) == '#aaaaaa') + + assert(a.image_url(NotifyType.INFO, NotifyImageSize.XY_256) == + 'http://localhost/dark/info-256x256.png') + + assert(a.image_path( + NotifyType.INFO, + NotifyImageSize.XY_256, + must_exist=False) == '/dark/info-256x256.png') + + assert(a.image_path( + NotifyType.INFO, + NotifyImageSize.XY_256, + must_exist=True) is None) + + # Create a new object (with our default settings) + a = AppriseAsset() + + # Our default configuration can access our file + assert(a.image_path( + NotifyType.INFO, + NotifyImageSize.XY_256, + must_exist=True) is not None) + + assert(a.image_raw(NotifyType.INFO, NotifyImageSize.XY_256) is not None)