Repository: lmmx/page-dewarp (language: python)

Issue:
Test CLI via hash of external image files created on default/modified params
I was wondering how to test and came up with a way:

- [x] Create outputs which will serve as the 'snapshot test'
- [x] Re-run same command and re-generate the artifact image
- [ ] If the diff of old (stored in `example_outputs` dir) and new is nil,
  the snapshot test passes. Don't even need to store the file(s) just
  hash, so is scaleable.

**Edit**: initially just use the stored files we ship anyway


Discussion / hints:

Fix patch:
diff --git a/pyproject.toml b/pyproject.toml
index 60d53e0..91f2901 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -111,5 +111,6 @@ showcontent = true
 [tool.uv]
 dev-dependencies = [
   "pysnooper>=1.2.0",
+  "pytest>=8.3.2",
   "towncrier>=24.8.0"
 ]
diff --git a/uv.lock b/uv.lock
index de3a0e4..b634715 100644
--- a/uv.lock
+++ b/uv.lock
@@ -120,6 +120,15 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321 },
 ]
 
+[[package]]
+name = "exceptiongroup"
+version = "1.2.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/09/35/2495c4ac46b980e4ca1f6ad6db102322ef3ad2410b79fdde159a4b0f3b92/exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc", size = 28883 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/02/cc/b7e31358aac6ed1ef2bb790a9746ac2c69bcb3c8588b41616914eb106eaf/exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", size = 16453 },
+]
+
 [[package]]
 name = "fonttools"
 version = "4.53.1"
@@ -185,6 +194,15 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/db/2a/728c8ae66011600fac5731a7db030d23c42f1321fd9547654f0c3b2b32d7/importlib_resources-6.4.4-py3-none-any.whl", hash = "sha256:dda242603d1c9cd836c3368b1174ed74cb4049ecd209e7a1a0104620c18c5c11", size = 35608 },
 ]
 
+[[package]]
+name = "iniconfig"
+version = "2.0.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 },
+]
+
 [[package]]
 name = "jinja2"
 version = "3.1.4"
@@ -538,13 +556,12 @@ dependencies = [
     { name = "opencv-python" },
     { name = "scipy" },
     { name = "sympy" },
-    { name = "toml" },
-    { name = "tomlkit" },
 ]
 
 [package.dev-dependencies]
 dev = [
     { name = "pysnooper" },
+    { name = "pytest" },
     { name = "towncrier" },
 ]
 
@@ -556,13 +573,12 @@ requires-dist = [
     { name = "opencv-python" },
     { name = "scipy" },
     { name = "sympy" },
-    { name = "toml" },
-    { name = "tomlkit" },
 ]
 
 [package.metadata.requires-dev]
 dev = [
     { name = "pysnooper", specifier = ">=1.2.0" },
+    { name = "pytest", specifier = ">=8.3.2" },
     { name = "towncrier", specifier = ">=24.8.0" },
 ]
 
@@ -643,6 +659,15 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/37/ae/2dbfc38cc4fd14aceea14bc440d5151b21f64c4c3ba3f6f4191610b7ee5d/pillow-10.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:cfdd747216947628af7b259d274771d84db2268ca062dd5faf373639d00113a3", size = 2554652 },
 ]
 
+[[package]]
+name = "pluggy"
+version = "1.5.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 },
+]
+
 [[package]]
 name = "pyparsing"
 version = "3.1.4"
@@ -661,6 +686,23 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/a7/b1/a5c75d691ac84a5503e69eac5de97523772c787ba84c3750f6ebb713a36f/PySnooper-1.2.0-py2.py3-none-any.whl", hash = "sha256:aa859aa9a746cffc1f35e4ee469d49c3cc5185b5fc0c571feb3af3c94d2eb625", size = 14818 },
 ]
 
+[[package]]
+name = "pytest"
+version = "8.3.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "colorama", marker = "sys_platform == 'win32'" },
+    { name = "exceptiongroup", marker = "python_full_version < '3.11'" },
+    { name = "iniconfig" },
+    { name = "packaging" },
+    { name = "pluggy" },
+    { name = "tomli", marker = "python_full_version < '3.11'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/b4/8c/9862305bdcd6020bc7b45b1b5e7397a6caf1a33d3025b9a003b39075ffb2/pytest-8.3.2.tar.gz", hash = "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce", size = 1439314 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/0f/f9/cf155cf32ca7d6fa3601bc4c5dd19086af4b320b706919d48a4c79081cf9/pytest-8.3.2-py3-none-any.whl", hash = "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5", size = 341802 },
+]
+
 [[package]]
 name = "python-dateutil"
 version = "2.9.0.post0"
@@ -729,15 +771,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/c1/f9/6845bf8fca0eaf847da21c5d5bc6cd92797364662824a11d3f836423a1a5/sympy-1.13.2-py3-none-any.whl", hash = "sha256:c51d75517712f1aed280d4ce58506a4a88d635d6b5dd48b39102a7ae1f3fcfe9", size = 6189289 },
 ]
 
-[[package]]
-name = "toml"
-version = "0.10.2"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/be/ba/1f744cdc819428fc6b5084ec34d9b30660f6f9daaf70eead706e3203ec3c/toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f", size = 22253 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588 },
-]
-
 [[package]]
 name = "tomli"
 version = "2.0.1"
@@ -747,15 +780,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/97/75/10a9ebee3fd790d20926a90a2547f0bf78f371b2f13aa822c759680ca7b9/tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", size = 12757 },
 ]
 
-[[package]]
-name = "tomlkit"
-version = "0.13.2"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/b1/09/a439bec5888f00a54b8b9f05fa94d7f901d6735ef4e55dcec9bc37b5d8fa/tomlkit-0.13.2.tar.gz", hash = "sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79", size = 192885 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/f9/b6/a447b5e4ec71e13871be01ba81f5dfc9d0af7e473da256ff46bc0e24026f/tomlkit-0.13.2-py3-none-any.whl", hash = "sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde", size = 37955 },
-]
-
 [[package]]
 name = "towncrier"
 version = "24.8.0"


Test patch:
diff --git a/tests/image_outputs_test.py b/tests/image_outputs_test.py
new file mode 100644
index 0000000..3095fb1
--- /dev/null
+++ b/tests/image_outputs_test.py
@@ -0,0 +1,27 @@
+import subprocess
+from pathlib import Path
+import filecmp
+import pytest
+
+repo_root = Path(__file__).parents[1]
+example_inputs_dir = repo_root / "example_input"
+example_outputs_dir = repo_root / "example_output"
+
+
+@pytest.fixture
+def temp_dir(tmp_path):
+    return tmp_path
+
+
+def test_page_dewarp_output(temp_dir):
+    input_file = example_inputs_dir / "boston_cooking_a.jpg"
+    expected_output = example_outputs_dir / "boston_cooking_a_thresh.png"
+    output_file = temp_dir / "boston_cooking_a_thresh.png"
+
+    subprocess.run(["page-dewarp", str(input_file)], cwd=temp_dir, check=True)
+
+    assert output_file.exists(), "Output file was not created"
+    assert filecmp.cmp(
+        output_file,
+        expected_output,
+    ), "Output file does not match expected output"