Skip to content

Commit

Permalink
Add: Add a new testing module to pontos
Browse files Browse the repository at this point in the history
Provide utilities for writing unittests.
  • Loading branch information
bjoernricks committed Aug 31, 2022
1 parent 6ce552e commit 52951c4
Show file tree
Hide file tree
Showing 2 changed files with 237 additions and 11 deletions.
22 changes: 11 additions & 11 deletions pontos/git/git.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def __str__(self) -> str:
)


def _exec_git(
def exec_git(
*args: str, ignore_errors: Optional[bool] = False, cwd: Optional[str] = None
) -> str:
"""
Expand Down Expand Up @@ -89,7 +89,7 @@ def init(self, *, bare: Optional[bool] = False):
args = ["init"]
if bare:
args.append("--bare")
_exec_git(*args, cwd=self._cwd)
exec_git(*args, cwd=self._cwd)

def create_branch(self, branch: str, *, start_point: Optional[str] = None):
"""
Expand All @@ -104,7 +104,7 @@ def create_branch(self, branch: str, *, start_point: Optional[str] = None):
if start_point:
args.append(start_point)

_exec_git(*args, cwd=self._cwd)
exec_git(*args, cwd=self._cwd)

def rebase(
self,
Expand Down Expand Up @@ -132,7 +132,7 @@ def rebase(
if head:
args.append(head)

_exec_git(*args, cwd=self._cwd)
exec_git(*args, cwd=self._cwd)

def clone(
self,
Expand Down Expand Up @@ -161,7 +161,7 @@ def clone(
args.extend(["--depth", depth])
args.extend([repo_url, str(destination.absolute())])

_exec_git(
exec_git(
*args,
cwd=self._cwd,
)
Expand Down Expand Up @@ -191,13 +191,13 @@ def push(
if branch:
args.append(branch)

_exec_git(*args, cwd=self._cwd)
exec_git(*args, cwd=self._cwd)

def config(self, key: str, value: str):
"""
Set a (local) git config
"""
_exec_git("config", key, value, cwd=self._cwd)
exec_git("config", key, value, cwd=self._cwd)

def cherry_pick(self, commits: Union[str, List[str]]):
"""
Expand All @@ -213,13 +213,13 @@ def cherry_pick(self, commits: Union[str, List[str]]):
args = ["cherry-pick"]
args.extend(commits)

_exec_git(*args, cwd=self._cwd)
exec_git(*args, cwd=self._cwd)

def list_tags(self) -> List[str]:
"""
List all available tags
"""
return _exec_git("tag", "-l", cwd=self._cwd).splitlines()
return exec_git("tag", "-l", cwd=self._cwd).splitlines()

def add(self, files: Union[str, List[str]]):
"""
Expand All @@ -234,7 +234,7 @@ def add(self, files: Union[str, List[str]]):
args = ["add"]
args.extend(files)

_exec_git(*args, cwd=self._cwd)
exec_git(*args, cwd=self._cwd)

def commit(
self,
Expand All @@ -259,4 +259,4 @@ def commit(

args.extend(["-m", message])

_exec_git(*args, cwd=self._cwd)
exec_git(*args, cwd=self._cwd)
226 changes: 226 additions & 0 deletions pontos/testing/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
# Copyright (C) 2022 Greenbone Networks GmbH
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import os
import sys
import tempfile
from contextlib import contextmanager
from pathlib import Path
from typing import Generator, Optional

from pontos.git.git import exec_git


@contextmanager
def add_sys_path(directory: os.PathLike) -> Generator[None, None, None]:
"""
Context Manager to add a directory path to the module search path aka.
sys.path. The directory path is removed when the context manager is left.
Args:
directory: A os.PathLike directory to add to sys.path
Example:
.. code-block:: python
with add_sys_path("/tmp/test-modules"):
import mymodule
"""
directory = os.fspath(directory)

if sys.path[0] != directory:
sys.path.insert(0, directory)

yield

try:
sys.path.remove(directory)
except ValueError:
# directory was not in the path
pass


@contextmanager
def temp_directory(
*, change_into: bool = False, add_to_sys_path: bool = False
) -> Generator[Path, None, None]:
"""
Context Manager to create a temporary directory
Args:
change_into: Set the created temporary as the current working directory
add_to_sys_path: Add the created temporary directory to the directories
for searching for Python modules
Returns:
A path to the created temporary directory
Example:
.. code-block:: python
with temp_directory(change_into=True) as tmp:
new_file = tmp / "test.txt"
"""
temp_dir = tempfile.TemporaryDirectory()
dir_path = Path(temp_dir.name)

if change_into:
os.chdir(dir_path)

if add_to_sys_path:
with add_sys_path(dir_path):
yield Path(dir_path)
else:
yield Path(dir_path)

temp_dir.cleanup()


@contextmanager
def temp_git_repository(
*,
user_name: str = "Max Mustermann",
user_email: str = "[email protected]",
branch: str = "main",
) -> Generator[Path, None, None]:
"""
Context Manager to create a temporary git repository on the filesystem
Args:
user_name: User name to configure in the repository.
Default: Max Mustermann
user_email: Email address of the user to configure in the repository.
Default: [email protected]
branch: Branch name to create. Default: main
Returns:
A path to the created temporary git repository directory
Example:
.. code-block:: python
with temp_git_repository() as repo:
new_file = repo / "foo.txt"
new_file.write_text("Lorem Ipsum")
exec_git("add", "foo.txt")
"""
temp_dir = tempfile.TemporaryDirectory()
temp_path = Path(temp_dir.name)

os.chdir(str(temp_path))

exec_git("init", "-b", branch)
exec_git("config", "--local", "user.email", user_email)
exec_git("config", "--local", "user.name", user_name)

yield temp_path

temp_dir.cleanup()


@contextmanager
def temp_file(
content: str,
*,
name: Optional[str] = "test.toml",
change_into: bool = False,
) -> Generator[Path, None, None]:
"""
A Context Manager to create a temporary file within a new temporary
directory. The temporary file and directory are removed when the context is
exited.
Args:
content: Content to write into the temporary file.
name: Name of the temporary file. "test.toml" by default.
change_into: Adjust the current working directory to the temporary
directory.
Returns:
A path to the created temporary file
Example:
.. code-block:: python
with temp_file("Lorem Ipsum", name="foo.txt") as fpath:
"""
with temp_directory(change_into=change_into) as tmp_dir:
test_file = tmp_dir / name
test_file.write_text(content, encoding="utf8")
yield test_file


@contextmanager
def temp_python_module(
content: str, *, name: str = "foo"
) -> Generator[Path, None, None]:
"""
A Context Manager to create a new Python module in a temporary directory.
The temporary directory will be added to the module search path and removed
from the search path when the context is exited. Also it is ensured that
the module is unloaded if the context is exited.
Args:
content: Python code to write into the temporary module.
name: Name of the new Python module. By default: "foo".
Returns:
A path to the created temporary Python module file
Example:
.. code-block:: python
with temp_python_module("print()", name="bar") as python_module_path
"""
with temp_directory(
add_to_sys_path=True,
) as tmp_dir, ensure_unload_module(name):
test_file = tmp_dir / f"{name}.py"
test_file.write_text(content, encoding="utf8")
yield test_file


def unload_module(name: str) -> None:
"""
Unload a Python module
Args:
name: Name of the Python module to unload. For example: foo.bar
"""
if name in sys.modules:
del sys.modules[name]


@contextmanager
def ensure_unload_module(name: str) -> Generator[None, None, None]:
"""
A context manager to ensure that a module gets removed even if an error
occurs
Args:
name: Name of the Python module to unload. For example: foo.bar
Example:
.. code-block:: python
with ensure_unload_module("foo.bar"):
do_something()
"""
yield
unload_module(name)

0 comments on commit 52951c4

Please sign in to comment.