Skip to content

feat(health): parse WorkoutStatistics from Apple Health export - #29

Merged
johnnyhuy merged 2 commits into
mainfrom
agent/issue-28-workout-statistics
Nov 7, 2026
Merged

johnnyhuy merged 2 commits into
mainfrom
agent/issue-28-workout-statistics

Conversation

@johnnyhuy

Copy link
Copy Markdown
Contributor

Adds WorkoutStatistics parsing for Apple Health exports. A new Foundation-only parser reads Workout elements and their nested WorkoutStatistics from export.xml, and ParsedWorkout exposes per-workout active and basal energy, distance, step count, and heart-rate summaries (average, minimum, maximum) with unit normalisation to kilocalories and metres.

Part of #7. Closes #28.

How it was verified:

  • mise run lint - no new violations in the added files. The repo total stays at the pre-existing baseline (504 warnings, 11 serious across 122 files, all in existing app files).
  • mise run build - passed.
  • mise run test - passed, 110 tests with 0 failures. The 15 new WorkoutStatisticsTests are listed below.
  • mise run ios:build:dev and mise run ios:test:ui were not run. Nothing user-facing changed; this slice is core parsing logic only.

Proof, terminal capture from swift test --filter WorkoutStatisticsTests:

Test Case '-[BetterFitTests.WorkoutStatisticsTests testCodableRoundTrip]' passed (0.006 seconds).
Test Case '-[BetterFitTests.WorkoutStatisticsTests testDistanceNormalisationFromMilesAndKilojoules]' passed (0.000 seconds).
Test Case '-[BetterFitTests.WorkoutStatisticsTests testDistanceSummaryPrefersStatisticOverTotal]' passed (0.001 seconds).
Test Case '-[BetterFitTests.WorkoutStatisticsTests testEmptyExportReturnsNoWorkouts]' passed (0.000 seconds).
Test Case '-[BetterFitTests.WorkoutStatisticsTests testEnergySummariesFromStatistics]' passed (0.001 seconds).
Test Case '-[BetterFitTests.WorkoutStatisticsTests testFallsBackToWorkoutTotalsWhenStatisticsAbsent]' passed (0.000 seconds).
Test Case '-[BetterFitTests.WorkoutStatisticsTests testHeartRateStatisticKeepsUnitAndDates]' passed (0.001 seconds).
Test Case '-[BetterFitTests.WorkoutStatisticsTests testHeartRateSummary]' passed (0.001 seconds).
Test Case '-[BetterFitTests.WorkoutStatisticsTests testMalformedXMLThrows]' passed (0.002 seconds).
Test Case '-[BetterFitTests.WorkoutStatisticsTests testParsesChildStatisticsCountAndTypes]' passed (0.001 seconds).
Test Case '-[BetterFitTests.WorkoutStatisticsTests testParsesWorkoutMetadataAndDuration]' passed (0.001 seconds).
Test Case '-[BetterFitTests.WorkoutStatisticsTests testParsesWorkoutsAndSkipsRecords]' passed (0.001 seconds).
Test Case '-[BetterFitTests.WorkoutStatisticsTests testPreservesUnknownStatisticType]' passed (0.000 seconds).
Test Case '-[BetterFitTests.WorkoutStatisticsTests testStepCountSummary]' passed (0.001 seconds).
Test Case '-[BetterFitTests.WorkoutStatisticsTests testWorkoutWithoutStatisticsHasNilSummaries]' passed (0.000 seconds).
Executed 15 tests, with 0 failures (0 unexpected) in 0.017 (0.018) seconds

Each test name states what it shows. Together they cover parsing two workouts from a mixed export, skipping top-level Record elements, preferring child statistics over workout totals, falling back to workout totals when statistics are absent, preserving unknown statistic types, handling an empty export, throwing on malformed XML, normalising miles and kilojoules, and a Codable round-trip.

Reviewer notes:

Co-authored-by: Muse Code <muse-code@meta.com>
@johnnyhuy
johnnyhuy force-pushed the agent/issue-28-workout-statistics branch from d0bc6c3 to 25a0037 Compare November 7, 2026 11:27
@johnnyhuy
johnnyhuy merged commit 59eb95b into main Nov 7, 2026
10 checks passed
@johnnyhuy
johnnyhuy deleted the agent/issue-28-workout-statistics branch November 7, 2026 15:23
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.

Add WorkoutStatistics parsing with per-workout energy and heart-rate summaries

1 participant