diff --git a/evennia/utils/containers.py b/evennia/utils/containers.py index d3392b1a14..a94a92454b 100644 --- a/evennia/utils/containers.py +++ b/evennia/utils/containers.py @@ -106,6 +106,7 @@ class GlobalScriptContainer(Container): callables from settings but a custom dict of tuples. """ + __BASE_SCRIPT_TYPECLASS = class_from_module(settings.BASE_SCRIPT_TYPECLASS) def __init__(self): """ @@ -205,7 +206,9 @@ class GlobalScriptContainer(Container): for key, data in list(self.loaded_data.items()): try: typeclass = data.get("typeclass", settings.BASE_SCRIPT_TYPECLASS) - self.typeclass_storage[key] = class_from_module(typeclass) + script_typeclass = class_from_module(typeclass) + assert issubclass(script_typeclass, self.__BASE_SCRIPT_TYPECLASS) + self.typeclass_storage[key] = script_typeclass except Exception: logger.log_trace( f"GlobalScriptContainer could not start import global script {key}. " diff --git a/evennia/utils/tests/test_containers.py b/evennia/utils/tests/test_containers.py new file mode 100644 index 0000000000..6967cd725e --- /dev/null +++ b/evennia/utils/tests/test_containers.py @@ -0,0 +1,86 @@ +import unittest + +from evennia.utils import containers +from django.conf import settings +from evennia.utils.utils import class_from_module + +_BASE_SCRIPT_TYPECLASS = class_from_module(settings.BASE_SCRIPT_TYPECLASS) + +class GoodScript(_BASE_SCRIPT_TYPECLASS): + pass + +class BadScript: + """Not subclass of _BASE_SCRIPT_TYPECLASS,""" + pass + +class WorseScript(_BASE_SCRIPT_TYPECLASS): + """objects will fail upon call""" + @property + def objects(self): + from evennia import module_that_doesnt_exist + +class TestGlobalScriptContainer(unittest.TestCase): + + def setUp(self): + settings.GLOBAL_SCRIPTS = {} + + def patch_global_scripts(self, adict): + settings.GLOBAL_SCRIPTS.update(adict) + + def test_init_with_no_scripts(self): + gsc = containers.GlobalScriptContainer() + + self.assertEqual(len(gsc.loaded_data), 0) + + def test_init_with_typeclassless_script(self): + self.patch_global_scripts({'script_name': {}}) + + gsc = containers.GlobalScriptContainer() + + self.assertEqual(len(gsc.loaded_data), 1) + self.assertIn('script_name', gsc.loaded_data) + + def test_start_with_no_scripts(self): + gsc = containers.GlobalScriptContainer() + + gsc.start() + + self.assertEqual(len(gsc.typeclass_storage), 0) + + def test_start_with_typeclassless_script_defaults_to_base(self): + self.patch_global_scripts({'script_name': {}}) + gsc = containers.GlobalScriptContainer() + + gsc.start() + + self.assertEqual(len(gsc.typeclass_storage), 1) + self.assertIn('script_name', gsc.typeclass_storage) + self.assertEqual(gsc.typeclass_storage['script_name'], _BASE_SCRIPT_TYPECLASS) + + def test_start_with_typeclassed_script_loads_it(self): + self.patch_global_scripts({'script_name': {'typeclass': 'evennia.utils.tests.test_containers.GoodScript'}}) + gsc = containers.GlobalScriptContainer() + + gsc.start() + + self.assertEqual(len(gsc.typeclass_storage), 1) + self.assertIn('script_name', gsc.typeclass_storage) + self.assertEqual(gsc.typeclass_storage['script_name'], GoodScript) + + def test_start_with_bad_typeclassed_script_skips_it(self): + self.patch_global_scripts({'script_name': {'typeclass': 'evennia.utils.tests.test_containers.BadScript'}}) + gsc = containers.GlobalScriptContainer() + + gsc.start() + + self.assertEqual(len(gsc.typeclass_storage), 0) + self.assertNotIn('script_name', gsc.typeclass_storage) + + def test_start_with_worst_typeclassed_script_skips_it(self): + self.patch_global_scripts({'script_name': {'typeclass': 'evennia.utils.tests.test_containers.WorstScript'}}) + gsc = containers.GlobalScriptContainer() + + gsc.start() + + self.assertEqual(len(gsc.typeclass_storage), 0) + self.assertNotIn('script_name', gsc.typeclass_storage)