Back to examples

Real example 01 · Unit tests · merged PR #106

Restoring PROJ broke safe geodesy copies

The restored PROJ backend converted coordinates correctly in the simple case, but copied geodesy objects crashed and successful conversions left their stored coordinates at zero.

Real upstream PR PR #106 by HeroCC Merged July 23, 2026 · failing 00b2cf84 · corrected 68523edd

The upstream problem

A plausible solution was incomplete

The problem

PR #106 restored the PROJ implementation and made it selectable at build time. The first complete-looking version passed ordinary coordinate conversions, but it treated owned PROJ handles like ordinary copyable fields and returned projected values without updating MOOSGeodesy's stored state.

The incomplete solution

The implementation owned raw PROJ handles, freed them in the destructor, and relied on compiler-generated copy operations. A copy therefore shared the same handles, while repeated conversions returned good output arguments but left the object's getters stale.

Open the source at the failing revision

Corrections prompted by the failing tests

-  projPJ pj_utm_;
-  projPJ pj_latlong_;
+  typedef std::shared_ptr<void> ProjectionPtr;
+  ProjectionPtr m_utm_projection;
+  ProjectionPtr m_latlong_projection;

-  MetersNorth = tmpNorth - GetOriginNorthing();
-  MetersEast = tmpEast - GetOriginEasting();
+  SetMetersNorth(tmpNorth - GetOriginNorthing());
+  SetMetersEast(tmpEast - GetOriginEasting());
+  MetersNorth = GetMetersNorth();
+  MetersEast = GetMetersEast();

The test

Run the focused check

Command

cd tests/cpp
./ctests.sh --moosgeodesy --jobs=4

At the incomplete revision

The focused check fails

18/22 enabled geodesy tests passed

CopyConstructionPreservesProjection: SEGFAULT
CopyAssignmentOutlivesSource: SEGFAULT
ContainerCopiesRemainUsable: SEGFAULT

RepeatedProjectionIsIndependentOfCallHistory
  expected stored east/north ≈ -4.7174 / 6.7415
  actual 0 / 0

The correction

What changed before the final upstream result

What the test proved

The geodesy family deliberately copies initialized objects, lets source objects die, stores copies in containers, and compares returned coordinates with the object's stored east/north state. Those checks exercised ownership and state consistency that one successful conversion could not reveal.

Open the protecting test

Corrected solution

The PR replaced raw handles with shared ownership using the proper PROJ deleter, persisted successful conversion results through the normal setters, and added further transactional initialization and invalid-input safeguards.

Open the corrected source

Upstream result

All 22 enabled geodesy tests passed, and the corrected implementation merged in PR #106.

Open PR #106

Next example

A two-second failure lasted four seconds

Continue