Repository: bitcoin/bitcoin
File: test/functional/test_framework/test_framework.py (Python)

Code before:
        bin_path: An optional string containing a directory path to look for
            binaries, which takes precedence over the paths above, if specified.
            This is used by tests calling binaries from previous releases.
    """
    def __init__(self, paths, bin_path=None):
        self.paths = paths
        self.bin_path = bin_path

    def daemon_args(self):
        "Return argv array that should be used to invoke bitcoind"
        return self.args("daemon", "bitcoind")

    def rpc_args(self):
        "Return argv array that should be used to invoke bitcoin-cli"
        # Add -nonamed because "bitcoin rpc" enables -named by default, but bitcoin-cli doesn't
        return self.args("rpc", "bitcoincli") + ["-nonamed"]

    def util_args(self):
        "Return argv array that should be used to invoke bitcoin-util"
        return self.args("util", "bitcoinutil")

    def wallet_args(self):
        "Return argv array that should be used to invoke bitcoin-wallet"
        return self.args("wallet", "bitcoinwallet")

    def args(self, command, path_attr):
        if self.bin_path is not None:
            return [os.path.join(self.bin_path, os.path.basename(getattr(self.paths, path_attr)))]
        elif self.paths.bitcoin_cmd is not None:
            return self.paths.bitcoin_cmd + [command]
        else:
            return [getattr(self.paths, path_attr)]


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'")


Review comment (suggestion):
a1d960e03be53517e80d36c257941ff407a6f61f: it took me a while to wrap my head around this. Suggested doc:

> Return argv array that should be used to invoke the command. It either uses the bitcoin wrapper executable (if BITCOIN_CMD is set), or the direct binary path (bitcoind, etc). When bin_path is set (by tests calling binaries from previous releases) it always uses the direct path.

(in the future some of the previous releases will have the `bitcoin` binary, but I don't expect we'll need to use it in tests)

Code after:
        bin_dir: An optional string containing a directory path to look for
            binaries, which takes precedence over the paths above, if specified.
            This is used by tests calling binaries from previous releases.
    """
    def __init__(self, paths, bin_dir):
        self.paths = paths
        self.bin_dir = bin_dir

    def node_argv(self):
        "Return argv array that should be used to invoke bitcoind"
        return self._argv("node", self.paths.bitcoind)

    def rpc_argv(self):
        "Return argv array that should be used to invoke bitcoin-cli"
        # Add -nonamed because "bitcoin rpc" enables -named by default, but bitcoin-cli doesn't
        return self._argv("rpc", self.paths.bitcoincli) + ["-nonamed"]

    def util_argv(self):
        "Return argv array that should be used to invoke bitcoin-util"
        return self._argv("util", self.paths.bitcoinutil)

    def wallet_argv(self):
        "Return argv array that should be used to invoke bitcoin-wallet"
        return self._argv("wallet", self.paths.bitcoinwallet)

    def chainstate_argv(self):
        "Return argv array that should be used to invoke bitcoin-chainstate"
        return self._argv("chainstate", self.paths.bitcoinchainstate)

    def _argv(self, command, bin_path):
        """Return argv array that should be used to invoke the command. It
        either uses the bitcoin wrapper executable (if BITCOIN_CMD is set), or
        the direct binary path (bitcoind, etc). When bin_dir is set (by tests
        calling binaries from previous releases) it always uses the direct
        path."""
        if self.bin_dir is not None:
            return [os.path.join(self.bin_dir, os.path.basename(bin_path))]
        elif self.paths.bitcoin_cmd is not None:
            return self.paths.bitcoin_cmd + [command]
        else:
            return [bin_path]


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."""