Skip to main content

Add a basic test harness

ID
ce05b0d
date
2024-06-06 06:39:51+00:00
author
Alex Chan <alex@alexwlchan.net>
parent
c2cdfab
message
Add a basic test harness
changed files
6 files, 129 additions, 14 deletions

Changed files

get_live_text.swift (2766) → get_live_text.swift (2834)

diff --git a/get_live_text.swift b/get_live_text.swift
index d796656..18a91c2 100755
--- a/get_live_text.swift
+++ b/get_live_text.swift
@@ -34,6 +34,8 @@
 
 import Vision
 
+let SCRIPT_VERSION = "1.0.0"
+
 // Process the results of the text-recognition request.
 //
 // This is based on the code in Apple's documentation, and prints the
@@ -52,21 +54,16 @@ func recognizeTextHandler(request: VNRequest, error: Error?) {
     return observation.topCandidates(1).first?.string
   }
 
-  // Serialise to JSON
-  do {
-    let jsonData = try JSONSerialization.data(withJSONObject: recognizedStrings)
-
-    if let JSONString = String(data: jsonData, encoding: String.Encoding.utf8) {
-      print(JSONString)
-    }
-  } catch {
-    fputs("Unable to serialise the result as JSON: \(error).\n", stderr)
-    exit(1)
-  }
+  print(recognizedStrings.joined(separator: " "))
 }
 
 // Given the path to an image, print a JSON array of text it contains.
 func printTextInImage(imagePath: String) {
+  if !FileManager.default.fileExists(atPath: imagePath) {
+    fputs("Cannot find file at path: \(imagePath)\n", stderr)
+    exit(1)
+  }
+
   let requestHandler = VNImageRequestHandler(
     url: URL(fileURLWithPath: imagePath),
     options: [:]
@@ -85,8 +82,14 @@ func printTextInImage(imagePath: String) {
 
 let arguments = CommandLine.arguments
 
+if arguments.count == 2 && arguments[1] == "--version" {
+  let filename = (arguments[0] as NSString).lastPathComponent
+  print("\(filename) \(SCRIPT_VERSION)")
+  exit(0)
+}
+
 if arguments.count != 2 {
-  fputs("Usage: \(arguments[0]) PATH\n", stderr)
+  fputs("Usage: \(arguments[0]) <PATH>\n", stderr)
   exit(1)
 }
 

tests/fixtures/checkerboard.png (0) → tests/fixtures/checkerboard.png (1040)

diff --git a/tests/fixtures/checkerboard.png b/tests/fixtures/checkerboard.png
new file mode 100644
index 0000000..76a7412
Binary files /dev/null and b/tests/fixtures/checkerboard.png differ

tests/fixtures/with_text.png (0) → tests/fixtures/with_text.png (3222)

diff --git a/tests/fixtures/with_text.png b/tests/fixtures/with_text.png
new file mode 100644
index 0000000..e6c6832
Binary files /dev/null and b/tests/fixtures/with_text.png differ

tests/test_get_live_text.py (0) → tests/test_get_live_text.py (1979)

diff --git a/tests/test_get_live_text.py b/tests/test_get_live_text.py
new file mode 100755
index 0000000..62719ed
--- /dev/null
+++ b/tests/test_get_live_text.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python3
+
+import os
+import pathlib
+import plistlib
+import re
+
+import pytest
+
+from utils import get_live_text
+
+
+def test_gets_empty_result_if_no_text() -> None:
+    result = get_live_text(["tests/fixtures/checkerboard.png"])
+
+    assert result == {
+        "returncode": 0,
+        "stdout": "\n",
+        "stderr": None,
+    }
+
+
+def test_gets_text_from_image() -> None:
+    result = get_live_text(["tests/fixtures/with_text.png"])
+
+    assert result == {
+        "returncode": 0,
+        "stdout": "This is an image with more than one block of text\n",
+        "stderr": None,
+    }
+
+
+def test_gives_useful_error_if_no_such_file() -> None:
+    result = get_live_text(["tests/fixtures/doesnotexist.gif"])
+
+    assert result == {
+        "returncode": 1,
+        "stdout": None,
+        "stderr": "Cannot find file at path: tests/fixtures/doesnotexist.gif\n",
+    }
+
+
+def test_gives_useful_error_if_cannot_recognize_image(tmp_path: pathlib.Path) -> None:
+    with open(tmp_path / "broken.tif", "wb") as outfile:
+        outfile.write(b"helloworld")
+
+    result = get_live_text([str(tmp_path / "broken.tif")])
+
+    assert result["returncode"] == 1
+    assert result["stdout"] is None
+    assert result["stderr"].startswith("Unable to recognise text:")
+
+
+@pytest.mark.parametrize(
+    "argv",
+    [
+        pytest.param([], id="no_arguments"),
+        pytest.param(["example.png", "example.gif", "--debug"], id="too_many_arguments"),
+    ],
+)
+def test_it_fails_if_you_supply_the_wrong_arguments(argv: list[str]) -> None:
+    result = get_live_text(argv)
+
+    assert result == {
+        "returncode": 1,
+        "stdout": None,
+        "stderr": "Usage: get_live_text.swift <PATH>\n",
+    }
+
+
+
+def test_prints_the_version() -> None:
+    result = get_live_text(["--version"])
+
+    assert result["returncode"] == 0
+    assert result["stderr"] is None
+    assert re.match(
+        r"^get_live_text.swift [0-9]+\.[0-9]+\.[0-9]+\n$", result["stdout"]
+    ), result["stdout"]

tests/test_truth.py (34) → tests/test_truth.py (0)

diff --git a/tests/test_truth.py b/tests/test_truth.py
deleted file mode 100644
index 29c6b40..0000000
--- a/tests/test_truth.py
+++ /dev/null
@@ -1,2 +0,0 @@
-def test_truth():
-    assert True

tests/utils.py (0) → tests/utils.py (794)

diff --git a/tests/utils.py b/tests/utils.py
new file mode 100644
index 0000000..3b10776
--- /dev/null
+++ b/tests/utils.py
@@ -0,0 +1,35 @@
+import pathlib
+import subprocess
+import typing
+
+
+class CommandOutput(typing.TypedDict):
+    returncode: int
+    stdout: str | None
+    stderr: str | None
+
+
+def get_live_text(argv: list[str | pathlib.Path]) -> CommandOutput:
+    """
+    Run the ``get_live_text.swift`` script and return the result.
+    """
+    cmd = ["swift", "get_live_text.swift"] + [str(av) for av in argv]
+
+    proc = subprocess.Popen(
+        cmd,
+        stdout=subprocess.PIPE,
+        stderr=subprocess.PIPE,
+    )
+    stdout, stderr = proc.communicate()
+
+    if stdout is not None:
+        stdout = stdout.decode("utf8")
+
+    if stderr is not None:
+        stderr = stderr.decode("utf8")
+
+    return CommandOutput(
+        returncode=proc.returncode,
+        stdout=stdout or None,
+        stderr=stderr or None,
+    )