Skip to content

test(geofence): unit tests for the waypoint geofence alert engine#2083

Merged
garthvh merged 2 commits into
meshtastic:mainfrom
bruschill:test/geofence-alert-engine
Jul 16, 2026
Merged

test(geofence): unit tests for the waypoint geofence alert engine#2083
garthvh merged 2 commits into
meshtastic:mainfrom
bruschill:test/geofence-alert-engine

Conversation

@bruschill

@bruschill bruschill commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

What changed?

Adds a unit-test suite (MeshtasticTests/GeofenceTests.swift, 18 tests in 3 suites) for the waypoint-geofence alert engine (MeshPackets+Geofence), which previously had no test coverage. It exercises the deterministic core:

  • GeofenceCrossingStore — the in-memory crossing-state store that drives enter/exit alerts:
    • First observation of a (waypoint, node) pair establishes a baseline (returns nil, never alerts) — so an app relaunch can't produce spurious alerts.
    • Correct enter/exit/enter transition reporting and per-key independence.
    • Using the production key format, that changing the geofence geometry (radius or bounding box) re-establishes a fresh baseline instead of firing a spurious enter/exit from stale inside/outside state.
    • A concurrency hammer test (DispatchQueue.concurrentPerform) for the serial-queue thread safety.
  • WaypointEntity.contains(location:) — circle inside/outside, bounding-box containment (interior / exterior / near-edge), circle+box union semantics, the no-geofence nil case, and boundingBoxCoordinates.
  • WaypointEntity.applyGeofence(from:) — proto→entity mapping, including the branch that clears a stale bounding box when the incoming proto has none.

Why did it change?

The geofence feature (#2005 / #2001) shipped without unit tests. The baseline/relaunch spurious-alert avoidance and geometry-key rotation are exactly the kind of subtle, easy-to-regress logic that benefits from deterministic coverage. This adds that safety net without touching any production code.

How is this tested?

xcodebuild test — the 3 new suites (GeofenceCrossingStoreTests, WaypointGeofenceGeometryTests, WaypointApplyGeofenceTests), 18 tests, all passing. No production code changed. The full evaluateGeofences path (MeshPackets actor + LocalNotificationManager) is glue over these units and is intentionally left out to keep the suite deterministic.

Screenshots/Videos (when applicable)

N/A — test-only change.

Checklist

  • My code adheres to the project's coding and style guidelines.
  • I have conducted a self-review of my code.
  • I have commented my code, particularly in complex areas.
  • I have verified whether these changes require updates to the in-app documentation under docs/user/ or docs/developer/, and updated accordingly — test-only change, no user- or developer-facing docs affected. skip-docs-check applies.
  • I have tested the change to ensure that it works as intended.

Summary by CodeRabbit

  • Tests
    • Added comprehensive automated coverage for geofence transition semantics, including baseline establishment, repeated-state behavior, and correct enter/exit sequencing.
    • Validated independent tracking per geofence key and thread-safety under concurrent updates.
    • Covered waypoint containment for circular and bounding-box geofences (including combined behavior and missing configurations).
    • Confirmed geofence settings are applied correctly and that stale bounding-box data is cleared when no bounding box is provided.

Covers the deterministic core of MeshPackets+Geofence (previously untested):

- GeofenceCrossingStore: first observation establishes a baseline (returns nil,
  never alerts — so an app relaunch can't produce spurious alerts); enter/exit/
  enter transition reporting; per-key independence; and — using the production
  key format — that changing the geofence geometry (radius or bounding box)
  re-establishes a fresh baseline instead of firing a spurious enter/exit from
  stale state. Plus a concurrency hammer test for the serial-queue thread safety.
- WaypointEntity.contains(location:): circle inside/outside, bounding-box
  containment (interior/exterior/near-edge), circle+box union semantics, the
  no-geofence nil case, and boundingBoxCoordinates.
- WaypointEntity.applyGeofence(from:): proto→entity mapping including the
  branch that clears a stale bounding box when the incoming proto has none.

The full evaluateGeofences path (actor + LocalNotificationManager) is glue over
these units and isn't exercised here to keep the suite deterministic.

18 tests, all passing.
@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6ca22c5d-6a9c-4f55-96e7-357dba13286f

📥 Commits

Reviewing files that changed from the base of the PR and between 564ac5f and be225b7.

📒 Files selected for processing (1)
  • Meshtastic.xcodeproj/project.pbxproj

📝 Walkthrough

Walkthrough

Adds geofence unit tests for crossing transitions, waypoint geometry, and proto application, then registers GeofenceTests.swift in the Xcode test target.

Changes

Geofence validation

Layer / File(s) Summary
Geofence behavior test suites
MeshtasticTests/GeofenceTests.swift
Tests crossing-state transitions, circle and bounding-box containment, geometry unions, coordinate access, geofence field mapping, and stale bounding-box clearing.
Test target registration
Meshtastic.xcodeproj/project.pbxproj
Adds GeofenceTests.swift to project references, the test group, build files, and the MeshtasticTests sources phase.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

Poem

A bunny hops through circles bright,
Then bounds the box just right.
Enter, exit, enter too—
Tests keep every state in view!
GeofenceTests.swift goes thump,
Into the test target’s burrowed rump.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change: new geofence unit tests.
Description check ✅ Passed The description follows the template and covers what changed, why, how it was tested, screenshots, and the checklist.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…ngine

# Conflicts:
#	Meshtastic.xcodeproj/project.pbxproj
@garthvh
garthvh merged commit eaa6f13 into meshtastic:main Jul 16, 2026
2 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants