Skip to content

Add geotiff edge-case tests: IFD loops, header parsing, descending-y, non-georeferenced (#1482)#1492

Merged
brendancol merged 1 commit into
mainfrom
issue-1482
May 5, 2026
Merged

Add geotiff edge-case tests: IFD loops, header parsing, descending-y, non-georeferenced (#1482)#1492
brendancol merged 1 commit into
mainfrom
issue-1482

Conversation

@brendancol

Copy link
Copy Markdown
Contributor

Closes #1482.

Summary

21 new tests in the geotiff module, plus one small reader fix.

Tests cover:

  • IFD chain loop detection. parse_all_ifds already had a seen set; this adds a test that builds a malicious buffer where IFD2 points back at IFD1, so the guard can't regress silently.
  • _read_value edge cases: RATIONAL/SRATIONAL with denominator zero, RATIONAL count overflow, truncated IFD entry buffer.
  • BigTIFF malformations: magic 43 with offset_size != 8, truncated 8-byte BigTIFF header.
  • Classic TIFF with first-IFD offset past the buffer end.
  • Descending-y (south-up) write/read round-trip. Pixel data orientation survives. The y sign does not, because ModelPixelScale stores absolute scale, so the test documents that as a known limitation.
  • Non-georeferenced TIFF read returns a DataArray with integer pixel coords (0..N-1) and no crs attr, instead of fractional coords from the default unit transform.

Code change

_extract_transform now returns (transform, has_georef). GeoInfo carries a new has_georef flag. _geo_to_coords falls back to integer pixel coords when has_georef is False. Existing georeferenced reads behave identically.

Test plan

  • pytest xrspatial/geotiff/tests/test_header.py xrspatial/geotiff/tests/test_georef_edges.py
  • Full geotiff suite passes. Three pre-existing matplotlib-deepcopy failures in test_features.py::TestPalette are unrelated and present on main.

@github-actions github-actions Bot added the performance PR touches performance-sensitive code label May 5, 2026
brendancol added a commit that referenced this pull request May 5, 2026
…1495)

test_merge_dask_different_crs_matches_eager intermittently SIGABRTs
on macOS CI runners. The merge() dask graph creates a fresh
pyproj.Transformer per chunk, and PROJ's first-time CRS-database load
is not safe under concurrent threaded workers — multiple threads racing
to init the SQLite DB on macOS triggers an abort.

The test exercises dask graph correctness, not dask threading. Pin it
to the synchronous scheduler and pre-warm pyproj.CRS objects so the
parity assertion runs without the threading dimension. CRS
thread-safety in the production reproject path is its own concern and
is not regressed here.

Refs the same crash on PR #1492 macOS-3.13 and on main run e253900
(macOS-3.12).
Tests:
- IFD chain loop / cycle detection in parse_all_ifds
- RATIONAL/SRATIONAL with denominator=0 returning 0.0
- RATIONAL with count overflowing the buffer
- Truncated IFD entry buffer
- BigTIFF malformations (offset_size != 8, truncated header)
- Classic TIFF first-IFD offset past buffer
- Descending-y (south-up) write/read round-trip
- Non-georeferenced TIFF read produces integer pixel coords

Code:
- _extract_transform now returns (transform, has_georef) so callers
  can tell "no GeoTIFF tags" apart from "tags present with default
  values".  GeoInfo carries the new has_georef flag.
- _geo_to_coords falls back to integer pixel coords (0..N-1) when
  has_georef is False, instead of producing y values like
  -0.5, -1.5, ... from the default unit transform.
@brendancol brendancol merged commit 6ece00d into main May 5, 2026
11 checks passed
@brendancol brendancol deleted the issue-1482 branch May 15, 2026 04:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

performance PR touches performance-sensitive code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add geotiff edge-case tests: IFD chain loops, header parsing, descending-y, non-georeferenced

1 participant