diff --git a/bob/io/base/test/test_utlilities.py b/bob/io/base/test/test_utlilities.py new file mode 100644 index 0000000000000000000000000000000000000000..d5f3da12e3441cb430eb97a213c17055c825aa97 --- /dev/null +++ b/bob/io/base/test/test_utlilities.py @@ -0,0 +1,38 @@ +import sys + +import click + +from click.testing import CliRunner + +from bob.io.base import test_utils + + +@click.command("dummy") +def dummy_command_0(): + sys.exit(0) + + +@click.command("dummy_exit_1") +def dummy_command_1(): + sys.exit(1) + + +@click.command("dummy_exit_raise") +def dummy_command_raise(): + raise RuntimeError("Expected exception") + + +def test_assert_dummy(): + result = CliRunner().invoke(dummy_command_0) + assert result.exit_code == 0 + test_utils.assert_click_runner_result(result) + + result = CliRunner().invoke(dummy_command_1) + assert result.exit_code == 1 + test_utils.assert_click_runner_result(result, exit_code=1) + + result = CliRunner().invoke(dummy_command_raise) + assert result.exit_code == 1 + test_utils.assert_click_runner_result( + result, exit_code=1, exception_type=RuntimeError + ) diff --git a/bob/io/base/test_utils.py b/bob/io/base/test_utils.py index 6156c4b459b6e10085b557471447daadadfb346b..193b3239c1d43b23a29fd189c55b201b1aa9ae2c 100644 --- a/bob/io/base/test_utils.py +++ b/bob/io/base/test_utils.py @@ -10,8 +10,13 @@ import functools import os +import traceback import unittest +from typing import Optional + +import click.testing + def datafile(f, module=None, path="data"): """datafile(f, [module], [data]) -> filename @@ -117,3 +122,38 @@ def extension_available(extension): return wrapper return test_wrapper + + +def assert_click_runner_result( + result: click.testing.Result, + exit_code: int = 0, + exception_type: Optional[Exception] = None, +): + """Helper for asserting click runner results. + + Parameters + ---------- + result + The return value on ``click.testing.CLIRunner.invoke()``. + exit_code + The expected command exit code (defaults to 0). + exception_type + If given, will ensure that the raised exception is of that type. + """ + + m = ( + "Click command exited with code '{}', instead of '{}'.\n" + "Exception:\n{}\n" + "Output:\n{}" + ) + exception = ( + "None" + if result.exc_info is None + else "".join(traceback.format_exception(*result.exc_info)) + ) + m = m.format(result.exit_code, exit_code, exception, result.output) + assert result.exit_code == exit_code, m + if exit_code == 0: + assert not result.exception, m + if exception_type is not None: + assert isinstance(result.exception, exception_type), m diff --git a/conda/meta.yaml b/conda/meta.yaml index 7f9bf577668dc920a97055fe5f0d5ac715b38f0c..a70a3cf70270a8c7579dbeb4556806719430b663 100644 --- a/conda/meta.yaml +++ b/conda/meta.yaml @@ -26,6 +26,7 @@ requirements: - numpy {{ numpy }} - pillow {{ pillow }} - imageio {{ imageio }} + - click {{ click }} run: - python - setuptools @@ -33,6 +34,7 @@ requirements: - {{ pin_compatible('pillow') }} - {{ pin_compatible('imageio') }} - {{ pin_compatible('h5py') }} + - {{ pin_compatible('click') }} test: imports: diff --git a/requirements.txt b/requirements.txt index 32506f993451e5f98c4342c48604b630ef0e59d3..ae1697a953f3f2dd3a8083aef515046b247fcffc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,3 +2,4 @@ bob.extension h5py imageio numpy +click