From c9cce0a7f66e5abe6a94704eb478e0dc52a29f13 Mon Sep 17 00:00:00 2001 From: Will Ayd Date: Sun, 1 Apr 2018 22:45:41 -0700 Subject: [PATCH] Tests: Add Metaclass for BitcoinTestFramework BitcoinTestFramework instructs developers in its docstring to override `set_test_params` and `run_test` in subclasses while being sure NOT to override `__init__` and `main` . This change adds a metaclass to ensure that developers adhere to that protocol, raising a ``TypeError`` in instances where they have not. closes #12835 --- .../test_framework/test_framework.py | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 543643f273..96ce290ab1 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -41,7 +41,28 @@ TEST_EXIT_PASSED = 0 TEST_EXIT_FAILED = 1 TEST_EXIT_SKIPPED = 77 -class BitcoinTestFramework(): + +class BitcoinTestMetaClass(type): + """Metaclass for BitcoinTestFramework. + + Ensures that any attempt to register a subclass of `BitcoinTestFramework` + adheres to a standard whereby the subclass overrides `set_test_params` and + `run_test` but DOES NOT override either `__init__` or `main`. If any of + those standards are violated, a ``TypeError`` is raised.""" + + def __new__(cls, clsname, bases, dct): + if not clsname == 'BitcoinTestFramework': + if not ('run_test' in dct and 'set_test_params' in dct): + raise TypeError("BitcoinTestFramework subclasses must override " + "'run_test' and 'set_test_params'") + if '__init__' in dct or 'main' in dct: + raise TypeError("BitcoinTestFramework subclasses may not override " + "'__init__' or 'main'") + + return super().__new__(cls, clsname, bases, dct) + + +class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): """Base class for a bitcoin test script. Individual bitcoin test scripts should subclass this class and override the set_test_params() and run_test() methods. @@ -432,6 +453,7 @@ class BitcoinTestFramework(): for i in range(self.num_nodes): initialize_datadir(self.options.tmpdir, i) + class SkipTest(Exception): """This exception is raised to skip a test""" def __init__(self, message):