From 84e90e01d188aaf94e9581c4e04e7d716a659be2 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Fri, 13 Dec 2013 18:42:26 +0000 Subject: [PATCH] new files --- openlp/core/common/registry.py | 167 ++++++++++++++++++ .../openlp_core_common/test_registry.py | 112 ++++++++++++ 2 files changed, 279 insertions(+) create mode 100644 openlp/core/common/registry.py create mode 100644 tests/functional/openlp_core_common/test_registry.py diff --git a/openlp/core/common/registry.py b/openlp/core/common/registry.py new file mode 100644 index 000000000..7a5f224cb --- /dev/null +++ b/openlp/core/common/registry.py @@ -0,0 +1,167 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2013 Raoul Snyman # +# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan # +# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, # +# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. # +# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, # +# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, # +# Frode Woldsund, Martin Zibricky, Patrick Zimmermann # +# --------------------------------------------------------------------------- # +# This program is free software; you can redistribute it and/or modify it # +# under the terms of the GNU General Public License as published by the Free # +# Software Foundation; version 2 of the License. # +# # +# This program is distributed in the hope that it will be useful, but WITHOUT # +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # +# more details. # +# # +# You should have received a copy of the GNU General Public License along # +# with this program; if not, write to the Free Software Foundation, Inc., 59 # +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # +############################################################################### +""" +Provide Registry Services +""" +import logging +import sys + +log = logging.getLogger(__name__) + + +class Registry(object): + """ + This is the Component Registry. It is a singleton object and is used to provide a look up service for common + objects. + """ + log.info('Registry loaded') + __instance__ = None + + def __new__(cls): + """ + Re-implement the __new__ method to make sure we create a true singleton. + """ + if not cls.__instance__: + cls.__instance__ = object.__new__(cls) + return cls.__instance__ + + @classmethod + def create(cls): + """ + The constructor for the component registry providing a single registry of objects. + """ + log.info('Registry Initialising') + registry = cls() + registry.service_list = {} + registry.functions_list = {} + registry.running_under_test = False + # Allow the tests to remove Registry entries but not the live system + if 'nose' in sys.argv[0]: + registry.running_under_test = True + return registry + + def get(self, key): + """ + Extracts the registry value from the list based on the key passed in + + ``key`` + The service to be retrieved. + """ + if key in self.service_list: + return self.service_list[key] + else: + log.error('Service %s not found in list' % key) + raise KeyError('Service %s not found in list' % key) + + def register(self, key, reference): + """ + Registers a component against a key. + + ``key`` + The service to be created this is usually a major class like "renderer" or "main_window" . + + ``reference`` + The service address to be saved. + """ + if key in self.service_list: + log.error('Duplicate service exception %s' % key) + raise KeyError('Duplicate service exception %s' % key) + else: + self.service_list[key] = reference + + def remove(self, key): + """ + Removes the registry value from the list based on the key passed in (Only valid and active for testing + framework). + + ``key`` + The service to be deleted. + """ + if key in self.service_list: + del self.service_list[key] + + def register_function(self, event, function): + """ + Register an event and associated function to be called + + ``event`` + The function description like "live_display_hide" where a number of places in the code + will/may need to respond to a single action and the caller does not need to understand or know about the + recipients. + + ``function`` + The function to be called when the event happens. + """ + if event in self.functions_list: + self.functions_list[event].append(function) + else: + self.functions_list[event] = [function] + + def remove_function(self, event, function): + """ + Remove an event and associated handler + + ``event`` + The function description.. + + ``function`` + The function to be called when the event happens. + """ + if self.running_under_test is False: + log.error('Invalid Method call for key %s' % event) + raise KeyError('Invalid Method call for key %s' % event) + if event in self.functions_list: + self.functions_list[event].remove(function) + + def execute(self, event, *args, **kwargs): + """ + Execute all the handlers associated with the event and return an array of results. + + ``event`` + The function to be processed + + ``*args`` + Parameters to be passed to the function. + + ``*kwargs`` + Parameters to be passed to the function. + """ + results = [] + if event in self.functions_list: + for function in self.functions_list[event]: + try: + result = function(*args, **kwargs) + if result: + results.append(result) + except TypeError: + # Who has called me can help in debugging + import inspect + log.debug(inspect.currentframe().f_back.f_locals) + log.exception('Exception for function %s', function) + return results diff --git a/tests/functional/openlp_core_common/test_registry.py b/tests/functional/openlp_core_common/test_registry.py new file mode 100644 index 000000000..17dd05b49 --- /dev/null +++ b/tests/functional/openlp_core_common/test_registry.py @@ -0,0 +1,112 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2013 Raoul Snyman # +# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan # +# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, # +# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. # +# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, # +# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, # +# Frode Woldsund, Martin Zibricky, Patrick Zimmermann # +# --------------------------------------------------------------------------- # +# This program is free software; you can redistribute it and/or modify it # +# under the terms of the GNU General Public License as published by the Free # +# Software Foundation; version 2 of the License. # +# # +# This program is distributed in the hope that it will be useful, but WITHOUT # +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # +# more details. # +# # +# You should have received a copy of the GNU General Public License along # +# with this program; if not, write to the Free Software Foundation, Inc., 59 # +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # +############################################################################### +""" +Package to test the openlp.core.lib package. +""" +import os +from unittest import TestCase + +from openlp.core.common import Registry +from tests.functional import MagicMock + +TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '../', '..', 'resources')) + + +class TestRegistry(TestCase): + + def registry_service_test(self): + """ + Test the registry creation and its usage + """ + # GIVEN: A new registry + Registry.create() + + # WHEN: I add a component it should save it + mock_1 = MagicMock() + Registry().register('test1', mock_1) + + # THEN: we should be able retrieve the saved component + assert Registry().get('test1') == mock_1, 'The saved service can be retrieved and matches' + + # WHEN: I add a component for the second time I am mad. + # THEN and I will get an exception + with self.assertRaises(KeyError) as context: + Registry().register('test1', mock_1) + self.assertEqual(context.exception.args[0], 'Duplicate service exception test1', + 'KeyError exception should have been thrown for duplicate service') + + # WHEN I try to get back a non existent component + # THEN I will get an exception + with self.assertRaises(KeyError) as context: + temp = Registry().get('test2') + self.assertEqual(context.exception.args[0], 'Service test2 not found in list', + 'KeyError exception should have been thrown for missing service') + + # WHEN I try to replace a component I should be allowed (testing only) + Registry().remove('test1') + # THEN I will get an exception + with self.assertRaises(KeyError) as context: + temp = Registry().get('test1') + self.assertEqual(context.exception.args[0], 'Service test1 not found in list', + 'KeyError exception should have been thrown for deleted service') + + def registry_function_test(self): + """ + Test the registry function creation and their usages + """ + # GIVEN: An existing registry register a function + Registry.create() + Registry().register_function('test1', self.dummy_function_1) + + # WHEN: I execute the function + return_value = Registry().execute('test1') + + # THEN: I expect then function to have been called and a return given + self.assertEqual(return_value[0], 'function_1', 'A return value is provided and matches') + + # WHEN: I execute the a function with the same reference and execute the function + Registry().register_function('test1', self.dummy_function_1) + return_value = Registry().execute('test1') + + # THEN: I expect then function to have been called and a return given + self.assertEqual(return_value, ['function_1', 'function_1'], 'A return value list is provided and matches') + + # WHEN: I execute the a 2nd function with the different reference and execute the function + Registry().register_function('test2', self.dummy_function_2) + return_value = Registry().execute('test2') + + # THEN: I expect then function to have been called and a return given + self.assertEqual(return_value[0], 'function_2', 'A return value is provided and matches') + + def dummy_function_1(self): + return "function_1" + + def dummy_function_2(self): + return "function_2" +