Add legacy-cgi dev dep and expand erdr2pml tests

erdr2pml imports the stdlib `cgi` module, removed in Python 3.13, so its
tests were skipped on modern interpreters. Add the `legacy-cgi` backport
as a dev dependency so the module imports, and flesh out its tests:
deXOR involution, fixKey known vector / length, cleanPML high-ASCII
escaping, and sanitizeFileName separator/colon/control-char/angle-bracket
handling. The skip guard is kept as a safety net for environments without
the backport.

Suite is now 44 passing, 0 skipped.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-22 20:13:26 -05:00
co-authored by Claude Opus 4.8
parent ba96df081f
commit 9b93b5b789
3 changed files with 50 additions and 9 deletions
+34 -8
View File
@@ -1,8 +1,9 @@
"""Tests for erdr2pml helpers.
"""Tests for erdr2pml (eReader) helpers.
erdr2pml imports the stdlib ``cgi`` module, which was removed in Python 3.13.
On such interpreters the whole module is unimportable, so these tests are
skipped (calibre currently ships Python 3.8-3.11, where they run).
The ``legacy-cgi`` backport is a dev dependency so the module imports on modern
interpreters; the skip guard below keeps the suite green if it is ever run
without that backport (e.g. a bare Python 3.13+ with no dev extras).
"""
import pytest
@@ -12,7 +13,7 @@ import dedrm_test_utils as U
try:
erdr2pml = U.load("erdr2pml", package="dedrm")
_skip_reason = None
except Exception as exc: # pragma: no cover - depends on interpreter version
except Exception as exc: # pragma: no cover - depends on interpreter / deps
erdr2pml = None
_skip_reason = "erdr2pml not importable: {0}".format(exc)
@@ -27,7 +28,32 @@ def test_dexor_is_involutive():
assert erdr2pml.deXOR(once, 0, table) == text
def test_sanitize_filename_strips_separators():
name = erdr2pml.sanitizeFileName("a/b\\c")
assert "/" not in name
assert "\\" not in name
def test_fix_key_known_vector():
assert erdr2pml.fixKey(bytes([0, 1, 2, 3, 255, 128, 64])) == bytes(
[0x80, 0x01, 0x02, 0x83, 0x7F, 0x80, 0x40]
)
def test_fix_key_preserves_length():
assert len(erdr2pml.fixKey(b"\x00" * 16)) == 16
def test_clean_pml_escapes_high_ascii():
# bytes 128..255 become \aNNN PML codes; bytes < 128 are left untouched.
assert erdr2pml.cleanPML(b"abc\x80\xff\x7f") == b"abc\\a128\\a255\x7f"
def test_sanitize_filename_replaces_separators():
assert erdr2pml.sanitizeFileName("a/b\\c|d") == "a_b_c_d"
def test_sanitize_filename_removes_colon():
assert ":" not in erdr2pml.sanitizeFileName("foo: bar")
def test_sanitize_filename_strips_control_chars_and_dots():
assert erdr2pml.sanitizeFileName("...\x01na\tme.") == "name"
def test_sanitize_filename_replaces_angle_brackets():
assert erdr2pml.sanitizeFileName("<tag>") == "[tag]"