Skip to content

Refactor unit tests: hoist imports, add EXIF read/write coverage, split exiftool tests#821

Merged
ptpt merged 14 commits into
mainfrom
refactor-test-imports
Jun 24, 2026
Merged

Refactor unit tests: hoist imports, add EXIF read/write coverage, split exiftool tests#821
ptpt merged 14 commits into
mainfrom
refactor-test-imports

Conversation

@ptpt

@ptpt ptpt commented Jun 5, 2026

Copy link
Copy Markdown
Member

Refactor and expand the unit-test suite around EXIF reading/writing and
import hygiene. No production code changes — mapillary_tools/ is untouched.

Import hygiene

  • Hoist imports nested inside test functions/methods up to module scope and
    let usort normalize the import blocks across the unit-test suite.
  • test_exifread: alias the two clashing EXIFTOOL_NAMESPACES as
    EXIFTOOL_READ_NAMESPACES / EXIFTOOL_READ_VIDEO_NAMESPACES.
  • test_exifread: drop the geo import in favor of an inlined
    as_unix_time helper; test _parse_coord via the public extract_lon_lat.

Coverage for exif_read / exif_write

Raises coverage of exif_read.py 64%→84% and exif_write.py 71%→87%.

  • test_exifread: ExifReadFromXMP metadata extractors (altitude, lon/lat
    incl. Adobe format, make/model, width/height incl. GPano fallbacks,
    orientation, direction, EXIF/GPS datetime, capture_time); the JPEG
    APP1/XMP segment scanner; the ExifRead EXIF→XMP fallback path.
  • test_exifedit: add_make/add_model round-trip and empty-string
    ValueError; add_orientation out-of-range ValueError; write() on a
    bytes-backed edit without filename raises.

_safe_dump recovery via committed fixtures

Cover the _safe_dump recovery branches with real JPEG fixtures (under
tests/unit/data/) instead of reaching into the private ExifEdit._ef
dict:

  • corrupt_exif_wrong_type.jpg: untrusted tag with wrong type → stripped
    and retried.
  • corrupt_exif_trusted_wrong_type.jpg: trusted tag with wrong type →
    re-raised.
  • corrupt_exif_large_thumbnail.jpg: oversized thumbnail → dropped on
    dump and retried.

Test-file organization

Split the exiftool reader tests out of test_exifread.py so it only
covers exif_read:

  • test_exiftool_read.py — ExifToolRead tests
  • test_exiftool_read_video.py — ExifToolReadVideo camera-uuid tests

Move imports that were nested inside test functions/methods up to the
top of their modules, and let usort normalize the import blocks.

- test_camm_parser: lift mp4_sample_parser into the mapillary_tools.mp4 import
- test_exifread: hoist ExifReadFromEXIF/ExifReadFromXMP/XMP_NAMESPACES,
  ExifToolRead, ExifToolReadVideo and xml.etree; alias the two clashing
  EXIFTOOL_NAMESPACES as EXIFTOOL_READ_NAMESPACES / EXIFTOOL_READ_VIDEO_NAMESPACES
- test_geo: hoist math and telemetry CAMMGPSPoint/GPSFix/GPSPoint
- test_gpmf_parser: hoist struct
- remaining files: usort import-block normalization only
@meta-cla meta-cla Bot added the cla signed label Jun 5, 2026
ptpt added 13 commits June 5, 2026 17:06
Raises coverage of exif_read.py 64%->84% and exif_write.py 71%->87%.

test_exifread.py:
- TestExifReadFromXMPMetadata: the ExifReadFromXMP metadata extractors
  (altitude, lon/lat incl. Adobe format, make/model, width/height incl.
  GPano fallbacks, orientation, direction, EXIF/GPS datetime, capture_time)
- TestExtractXmpEfficiently: the JPEG APP1/XMP segment scanner, incl.
  no-SOI, no-XMP, and non-XMP-segment-skipped cases
- TestExifReadXmpFallback: the ExifRead EXIF->XMP fallback path driven
  through a real BytesIO stream

test_exifedit.py:
- add_make/add_model round-trip and empty-string ValueError
- add_orientation out-of-range ValueError
- write() on bytes-backed edit without filename raises
- _safe_dump recovery: untrusted wrong-type tag stripped, trusted
  wrong-type tag re-raised, AsShotNeutral workaround (issue #662)
The three _safe_dump recovery tests injected malformed tags via the
private ExifEdit._ef dict. There is no public API to trigger those
branches, so remove the tests rather than depend on internals.
Replace the two ExifEdit._safe_dump tests that injected malformed tags
through the private _ef dict with file-based equivalents driven by real
JPEG fixtures whose EXIF piexif can load but cannot re-dump.

- tests/unit/generate_corrupt_exif_image.py: hand-assembles the EXIF
  (PIL + raw TIFF bytes), since neither PIL nor piexif.dump can emit a
  malformed-but-loadable tag.
- tests/data/corrupt_exif_wrong_type.jpg: Software (non-trusted) stored
  as SHORT -> _safe_dump strips it and retries.
- tests/data/corrupt_exif_trusted_wrong_type.jpg: ImageDescription
  (trusted) stored as SHORT -> _safe_dump re-raises.

The AsShotNeutral workaround branch is dropped: it can't be reproduced
from a file (piexif decodes it to a dumpable value) without _ef access.
Relocate the undumpable-EXIF fixtures alongside the other unit-test
fixtures and reference them via the test's data_dir.
Point test_exifedit.py at the fixtures via data_dir and update the
generator's output path accordingly.
Replace the last ExifEdit._ef access in test_exifedit.py. The large
thumbnail is no longer injected into the private _ef dict; instead a
committed fixture carries a thumbnail above piexif's 64000-byte dump
limit (yet within a JPEG APP1 segment), so ExifEdit loads it and
_safe_dump drops the thumbnail/1st IFD on dump and retries.

tests/unit/data/corrupt_exif_large_thumbnail.jpg added; generator
extended to build it.
Reword test docstrings/comments and rename tests so they describe
observable behavior (unsavable tags, oversized thumbnails) rather than
implementation details (private helpers, library specifics, IFD layout).
The fixtures are committed binaries under tests/unit/data; the
generator is no longer needed.
Move ExifToolRead tests to tests/unit/test_exiftool_read.py and
ExifToolReadVideo camera-uuid tests to tests/unit/test_exiftool_read_video.py
so that test_exifread.py only covers exif_read.
@ptpt ptpt changed the title Hoist function-level imports to module scope in unit tests Refactor unit tests: hoist imports, add EXIF read/write coverage, split exiftool tests Jun 24, 2026
@ptpt ptpt merged commit a880c7d into main Jun 24, 2026
33 of 34 checks passed
@ptpt ptpt deleted the refactor-test-imports branch June 24, 2026 18:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant