diff --git a/.gitignore b/.gitignore index 12b8da9..82b17ad 100644 --- a/.gitignore +++ b/.gitignore @@ -132,9 +132,8 @@ dmypy.json *.tar.gz deb_dist .DS_Store +tests/test_docs/**/*-safe.pdf install/windows/Dangerzone.wxs -**/*-safe.pdf -test_docs/out/ share/container.tar share/container.tar.gz share/image-id.txt diff --git a/tests/__init__.py b/tests/__init__.py index e69de29..cad40ab 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -0,0 +1,22 @@ +import sys +from pathlib import Path + +import pytest + +sys.dangerzone_dev = True + +SAMPLE_DIRECTORY = "test_docs" +BASIC_SAMPLE = "sample.pdf" +test_docs_dir = Path(__file__).parent.joinpath(SAMPLE_DIRECTORY) +test_docs = [ + p + for p in test_docs_dir.rglob("*") + if p.is_file() and not p.name.endswith("-safe.pdf") +] + +# Pytest parameter decorators +for_each_doc = pytest.mark.parametrize("doc", test_docs) + + +class TestBase: + sample_doc = str(test_docs_dir.joinpath(BASIC_SAMPLE)) diff --git a/tests/test_cli.py b/tests/test_cli.py index 43691a6..b663f23 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,14 +1,13 @@ from __future__ import annotations -import os.path -import sys -from pathlib import Path -from unittest import TestCase +import tempfile +import pytest from click.testing import CliRunner, Result from dangerzone.cli import cli_main +from . import TestBase, for_each_doc # TODO --output-filename with spaces # TODO explore any symlink edge cases @@ -22,65 +21,50 @@ from dangerzone.cli import cli_main # FIXME "/" path separator is platform-dependent, use pathlib instead -class CliTestCase(TestCase): - SAMPLE_DIRECTORY = "test_docs" - BASIC_SAMPLE = f"{SAMPLE_DIRECTORY}/sample.pdf" - SAFE_SUFFIX = "-safe.pdf" - - def setUp(self): - sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) - sys.dangerzone_dev = True - self.runner = CliRunner() - # TODO Use pathlib or similar for safer file handling here - samples_dir = Path(self.SAMPLE_DIRECTORY) - self.samples: list[Path | str] = [ - p - for p in samples_dir.rglob("*") - if p.is_file() and not p.name.endswith(self.SAFE_SUFFIX) - ] - print(f"{self.BASIC_SAMPLE} --output-filename {self.SAMPLE_DIRECTORY}/out/my-output.pdf") - if len(self.samples) < 10: - raise RuntimeWarning(f"Only {len(self.samples)} samples found.") - - def invoke_runner(self, *args, **kwargs) -> Result: - return self.runner.invoke(cli_main, *args, **kwargs) +class TestCli(TestBase): + def run_cli(self, *args, **kwargs) -> Result: + return CliRunner().invoke(cli_main, *args, **kwargs) -class CliBasicTestCase(CliTestCase): +class TestCliBasic(TestCli): def test_no_args(self): """``$ dangerzone-cli``""" - result = self.invoke_runner() - self.assertNotEqual(result.exit_code, 0) + result = self.run_cli() + assert result.exit_code != 0 def test_help(self): """``$ dangerzone-cli --help``""" - result = self.invoke_runner("--help") - self.assertEqual(result.exit_code, 0) + result = self.run_cli("--help") + assert result.exit_code == 0 -class CliConversionTestCase(CliTestCase): + +class TestCliConversion(TestCliBasic): def test_invalid_lang(self): - result = self.invoke_runner(f"{self.BASIC_SAMPLE} --ocr-lang piglatin") - self.assertNotEqual(result.exit_code, 0) + result = self.run_cli(f"{self.sample_doc} --ocr-lang piglatin") + assert result.exit_code != 0 - def test_samples(self): - for sample in self.samples: - with self.subTest(f"Convert {sample}"): - result = self.invoke_runner(f'"{sample}"') - self.assertEqual(result.exit_code, 0) + @for_each_doc + def test_formats(self, doc): + result = self.run_cli(f'"{doc}"') + assert result.exit_code == 0 def test_output_filename(self): - result = self.invoke_runner(f"{self.BASIC_SAMPLE} --output-filename {self.SAMPLE_DIRECTORY}/out/my-output.pdf") - self.assertEqual(result.exit_code, 0) + temp_dir = tempfile.mkdtemp(prefix="dangerzone-") + result = self.run_cli( + f"{self.sample_doc} --output-filename {temp_dir}/safe.pdf" + ) + assert result.exit_code == 0 def test_output_filename_new_dir(self): - result = self.invoke_runner(f"{self.BASIC_SAMPLE} --output-filename fake-directory/my-output.pdf") - self.assertEqual(result.exit_code, 0) + result = self.run_cli( + f"{self.sample_doc} --output-filename fake-directory/my-output.pdf" + ) + assert result.exit_code != 0 def test_sample_not_found(self): - result = self.invoke_runner("fake-directory/fake-file.pdf") - self.assertEquals(result.exit_code, 1) + result = self.run_cli("fake-directory/fake-file.pdf") + assert result.exit_code != 0 def test_lang_eng(self): - # Rewrite this case if samples in other languages or scripts are added. - result = self.invoke_runner(f'"{self.BASIC_SAMPLE}" --ocr-lang eng') - self.assertEqual(result.exit_code, 0) \ No newline at end of file + result = self.run_cli(f'"{self.sample_doc}" --ocr-lang eng') + assert result.exit_code == 0 diff --git a/test_docs/sample.doc b/tests/test_docs/sample.doc similarity index 100% rename from test_docs/sample.doc rename to tests/test_docs/sample.doc diff --git a/test_docs/sample.docm b/tests/test_docs/sample.docm similarity index 100% rename from test_docs/sample.docm rename to tests/test_docs/sample.docm diff --git a/test_docs/sample.docx b/tests/test_docs/sample.docx similarity index 100% rename from test_docs/sample.docx rename to tests/test_docs/sample.docx diff --git a/test_docs/sample.gif b/tests/test_docs/sample.gif similarity index 100% rename from test_docs/sample.gif rename to tests/test_docs/sample.gif diff --git a/test_docs/sample.jpg b/tests/test_docs/sample.jpg similarity index 100% rename from test_docs/sample.jpg rename to tests/test_docs/sample.jpg diff --git a/test_docs/sample.odg b/tests/test_docs/sample.odg similarity index 100% rename from test_docs/sample.odg rename to tests/test_docs/sample.odg diff --git a/test_docs/sample.odp b/tests/test_docs/sample.odp similarity index 100% rename from test_docs/sample.odp rename to tests/test_docs/sample.odp diff --git a/test_docs/sample.ods b/tests/test_docs/sample.ods similarity index 100% rename from test_docs/sample.ods rename to tests/test_docs/sample.ods diff --git a/test_docs/sample.odt b/tests/test_docs/sample.odt similarity index 100% rename from test_docs/sample.odt rename to tests/test_docs/sample.odt diff --git a/test_docs/sample.pdf b/tests/test_docs/sample.pdf similarity index 100% rename from test_docs/sample.pdf rename to tests/test_docs/sample.pdf diff --git a/test_docs/sample.png b/tests/test_docs/sample.png similarity index 100% rename from test_docs/sample.png rename to tests/test_docs/sample.png diff --git a/test_docs/sample.ppt b/tests/test_docs/sample.ppt similarity index 100% rename from test_docs/sample.ppt rename to tests/test_docs/sample.ppt diff --git a/test_docs/sample.pptx b/tests/test_docs/sample.pptx similarity index 100% rename from test_docs/sample.pptx rename to tests/test_docs/sample.pptx diff --git a/test_docs/sample.xls b/tests/test_docs/sample.xls similarity index 100% rename from test_docs/sample.xls rename to tests/test_docs/sample.xls diff --git a/test_docs/sample.xlsx b/tests/test_docs/sample.xlsx similarity index 100% rename from test_docs/sample.xlsx rename to tests/test_docs/sample.xlsx diff --git a/tests/test_global_common.py b/tests/test_global_common.py index fe7c352..c1bc1af 100644 --- a/tests/test_global_common.py +++ b/tests/test_global_common.py @@ -1,58 +1,40 @@ -import io import os import platform -import subprocess -import sys -import unittest -from io import StringIO from pathlib import Path -from unittest import TestCase, mock +import pytest from strip_ansi import strip_ansi # type: ignore -import dangerzone.global_common as global_common +import dangerzone.global_common + +VERSION_FILE_NAME = "version.txt" -class TestGlobalCommon(TestCase): +@pytest.fixture +def global_common(): + return dangerzone.global_common.GlobalCommon() - VERSION_FILE_NAME = "version.txt" - def setUp(self): - self.global_common = global_common.GlobalCommon() - sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) - sys.dangerzone_dev = True - - def test_get_resource_path(self): +class TestGlobalCommon: + def test_get_resource_path(self, global_common): share_dir = Path("share").resolve() - resource_path = Path( - self.global_common.get_resource_path(self.VERSION_FILE_NAME) - ).parent - self.assertTrue( - share_dir.samefile(resource_path), - msg=f"{share_dir} is not the same file as {resource_path}", - ) + resource_path = Path(global_common.get_resource_path(VERSION_FILE_NAME)).parent + assert share_dir.samefile( + resource_path + ), f"{share_dir} is not the same file as {resource_path}" - @unittest.skipUnless(platform.system() == "Windows", "STARTUPINFO is for Windows") - def test_get_subprocess_startupinfo(self): - startupinfo = self.global_common.get_subprocess_startupinfo() + @pytest.mark.skipif(platform.system() != "Windows", reason="Windows-specific") + def test_get_subprocess_startupinfo(self, global_common): + startupinfo = global_common.get_subprocess_startupinfo() self.assertIsInstance(startupinfo, subprocess.STARTUPINFO) - @unittest.mock.patch("sys.stdout", new_callable=io.StringIO) - def test_display_banner(self, mock_stdout: StringIO): - self.global_common.display_banner() # call the test subject - banner = mock_stdout.getvalue() - plain_lines = [strip_ansi(line) for line in banner.splitlines()] - with self.subTest("banner top border"): - self.assertEqual("╭──────────────────────────╮", plain_lines[0]) - with self.subTest("banner bottom border"): - self.assertEqual("╰──────────────────────────╯", plain_lines[14]) - with self.subTest("banner consistent dimensions"): - width = len(plain_lines[0]) - for line in plain_lines: - self.assertEqual(len(line), width) + def test_display_banner(self, global_common, capfd): + global_common.display_banner() # call the test subject + (out, err) = capfd.readouterr() + plain_lines = [strip_ansi(line) for line in out.splitlines()] + assert "╭──────────────────────────╮" in plain_lines, "missing top border" + assert "╰──────────────────────────╯" in plain_lines, "missing bottom border" - @unittest.mock.patch("sys.stdout", new_callable=io.StringIO) - def test_display_banner_dims(self, mock_stdout: StringIO): - self.global_common.display_banner() # call the test subject - banner = mock_stdout.getvalue() - banner_lines = banner.splitlines() + banner_width = len(plain_lines[0]) + for line in plain_lines: + assert len(line) == banner_width, "banner has inconsistent width"