Source code for tests.test_utils

"""Module for test utility functions."""
import contextlib
import os
import tempfile
import typing as tp
from copy import deepcopy
from functools import wraps
from pathlib import Path

import benchbuild.utils.settings
import plumbum as pb
from benchbuild.source import Git, base

import varats.utils.settings as settings

TEST_INPUTS_DIR = Path(os.path.dirname(__file__)) / 'TEST_INPUTS'


[docs]def get_test_config(tmp_path: Path) -> benchbuild.utils.settings.Configuration: """ Get a vara config suitable for testing. Configs returned by this function are meant to be passed to :func:`replace_config()`. Args: tmp_path: path to put files that may be written during test execution Returns: a (deep)copy of the current vara config suitable for testing """ test_config = deepcopy(settings._CFG) # pylint: disable=protected-access # setup test input dir test_config["config_file"] = str(tmp_path / ".varats.yml") test_config["result_dir"] = str(TEST_INPUTS_DIR / "results") test_config["paper_config"]["folder"] = str( TEST_INPUTS_DIR / "paper_configs" ) test_config["paper_config"]["current_config"] = None # let output config options point to test env. test_config["data_cache"] = str(tmp_path / "data_cache") test_config["plots"]["plot_dir"] = str(tmp_path / "plots") test_config["tables"]["table_dir"] = str(tmp_path / "tables") test_config["artefacts"]["artefacts_dir"] = str(tmp_path / "artefacts") return test_config
[docs]def get_bb_test_config() -> benchbuild.utils.settings.Configuration: return deepcopy(settings.bb_cfg())
class _ReplaceConfig(): def __init__( self, replace_bb_config: bool = False, tmp_path: tp.Optional[Path] = None, vara_config: tp.Optional[benchbuild.utils.settings.Configuration ] = None, bb_config: tp.Optional[benchbuild.utils.settings.Configuration] = None, ) -> None: self.replace_bb_config = replace_bb_config if self.replace_bb_config: # pylint: disable=protected-access self.old_bb_config = settings.bb_cfg() if bb_config: self.new_bb_config = bb_config else: self.new_bb_config = deepcopy(self.old_bb_config) if tmp_path: self.tmp_path: tp.Optional[tempfile.TemporaryDirectory] = None else: self.tmp_path = tempfile.TemporaryDirectory() tmp_path = Path(self.tmp_path.name) # pylint: disable=protected-access self.old_config = settings.vara_cfg() if vara_config: self.new_config = vara_config else: self.new_config = get_test_config(tmp_path) @contextlib.contextmanager def _decoration_helper(self, args: tp.Any, kwargs: tp.Any) -> tp.Any: # pylint: disable=protected-access settings._CFG = self.new_config settings.create_missing_folders() args += (self.new_config,) if self.replace_bb_config: # pylint: disable=protected-access settings._BB_CFG = self.new_bb_config args += (self.new_bb_config,) try: yield args, kwargs finally: # pylint: disable=protected-access settings._CFG = self.old_config if self.replace_bb_config: # pylint: disable=protected-access settings._BB_CFG = self.old_bb_config if self.tmp_path: self.tmp_path.cleanup() def __call__(self, func) -> tp.Any: @wraps(func) def wrapper(*args: tp.Any, **kwargs: tp.Any) -> tp.Any: with self._decoration_helper(args, kwargs) as (newargs, newkwargs): return func(*newargs, **newkwargs) return wrapper def __enter__(self): # pylint: disable=protected-access settings._CFG = self.new_config settings.create_missing_folders() if self.replace_bb_config: # pylint: disable=protected-access settings._BB_CFG = self.new_bb_config return self.new_config, self.new_bb_config return self.new_config def __exit__(self, exc_type, exc_val, exc_tb): # pylint: disable=protected-access settings._CFG = self.old_config if self.replace_bb_config: # pylint: disable=protected-access settings._BB_CFG = self.old_bb_config if self.tmp_path: self.tmp_path.cleanup()
[docs]def replace_config( replace_bb_config: bool = False, tmp_path: tp.Optional[Path] = None, vara_config: tp.Optional[benchbuild.utils.settings.Configuration] = None, bb_config: tp.Optional[benchbuild.utils.settings.Configuration] = None ) -> tp.Any: """ Replace the vara and benchbuild config while executing a (test) function. This function can be used as a decorator or a context manager. It replaces the current vara or benchbuild configuration with a :func:`test config<get_test_config()>` or a given config. If used as a decorator, the replaced config is passed as an additional argument to the function. If used as a context manager, it binds the replaced config to the name given after the `as`. Args: replace_bb_config: whether to also replace the benchbuild config tmp_path: path to put files that may be written during test execution. If absent, the wrapper will create a temporary directory that is deleted after restoring the config. vara_config: if given, use this as the new vara config instead of a copy of the current one bb_config: if given, use this as the new benchbuild config instead of a copy of the current one Returns: the wrapped function """ return _ReplaceConfig(replace_bb_config, tmp_path, vara_config, bb_config)
[docs]class DummyGit(Git): """A dummy git source that does nothing."""
[docs] def fetch(self) -> pb.LocalPath: return pb.LocalPath("/dev/null")
[docs] def version(self, target_dir: str, version: str = 'HEAD') -> pb.LocalPath: return pb.LocalPath("/dev/null")
[docs] def versions(self) -> tp.List[base.Variant]: return []