|
@@ -1127,6 +1127,50 @@ def list_templates():
|
|
|
_templates = ()
|
|
|
return _templates
|
|
|
|
|
|
+def create_testcases_for_templates(name, *bases, globals, **kwds):
|
|
|
+ '''Do-it-all helper for generating per-template tests via load_tests proto
|
|
|
+
|
|
|
+ This does several things:
|
|
|
+ - creates per-template classes
|
|
|
+ - adds them to module's :py:func:`globals`
|
|
|
+ - returns an iterable suitable for passing to loader.loadTestsFromNames
|
|
|
+
|
|
|
+ TestCase classes created by this function have implicit `.template`
|
|
|
+ attribute, which contains name of the respective template. They are also
|
|
|
+ named with given prefix, underscore and template name. If template name
|
|
|
+ contains characters not valid as part of Python identifier, they are
|
|
|
+ impossible to get via standard ``.`` operator, though :py:func:`getattr` is
|
|
|
+ still usable.
|
|
|
+
|
|
|
+ >>> class MyTestsMixIn:
|
|
|
+ ... def test_000_my_test(self):
|
|
|
+ ... assert self.template.startswith('debian')
|
|
|
+ >>> def load_tests(loader, tests, pattern):
|
|
|
+ ... tests.addTests(loader.loadTestsFromNames(
|
|
|
+ ... qubes.tests.create_testcases_for_templates(
|
|
|
+ ... 'TC_00_MyTests', MyTestsMixIn, qubes.tests.SystemTestCase,
|
|
|
+ ... globals=globals())))
|
|
|
+
|
|
|
+ *NOTE* adding ``globals=globals()`` is *mandatory*, and to allow enforcing
|
|
|
+ this, it uses keyword-only argument syntax, which is Python 3 only.
|
|
|
+ '''
|
|
|
+
|
|
|
+ # NOTE globals is passed from calling function, and has slightly different
|
|
|
+ # semantics (no ``()``).
|
|
|
+ #
|
|
|
+ # Do not attempt to grab from traceback, since we are actually a generator
|
|
|
+ # and loadTestsFromNames may also be a generator, so it's not possible to
|
|
|
+ # correctly guess frame from stack. Explicit is better than implicit!
|
|
|
+
|
|
|
+ module = globals['__name__']
|
|
|
+ for template in list_templates():
|
|
|
+ clsname = name + '_' + template
|
|
|
+ cls = type(clsname, bases, {'template': template, **kwds})
|
|
|
+ cls.__module__ = module
|
|
|
+ # XXX I wonder what other __dunder__ attrs did I miss
|
|
|
+ globals[clsname] = cls
|
|
|
+ yield '.'.join((module, clsname))
|
|
|
+
|
|
|
def extra_info(obj):
|
|
|
'''Return short info identifying object.
|
|
|
|