MacDive: decode ZRAWDATA profiles via libdivecomputer#264
Merged
Conversation
MacDiveDiveMapper now decodes ZRAWDATA via parseRawDiveData (same API ShearwaterDiveMapper uses for Shearwater Cloud). toPayload becomes async and threads warnings through. _vendorProductFromZComputer maps ZCOMPUTER strings to libdivecomputer (vendor, product) pairs. Sample projection matches ShearwaterDiveMapper.mergeWithParsedDive exactly (same keys, same conditional emission). Dives without ZRAWDATA or with unmapped computers emit profile:[] silently; decode failures emit profile:[] + ImportWarning. Closes the ZRAWDATA part of the MacDive SQLite profile gap from #256.
Mirrors ShearwaterDiveMapper's two-tier exception pattern: MissingPluginException and PlatformException(UNSUPPORTED|channel-error) propagate from _decodeProfile so toPayload can disable FFI for the remaining dives — avoids O(N) failing plugin round-trips on platforms where the native channel isn't registered. Also adds Shearwater Perdix 2 and NERD 2 to the ZCOMPUTER -> (vendor, product) mapping, updates a stale test comment, and adds a regression test covering the FFI-unavailable fallback path.
Replaces the now-stale 'profile always empty' assertion with four new tests that verify: - Shearwater dives (267 in the sample DB) get decoded profiles via libdivecomputer (>=95% success rate) - Decoded sample maps carry at least timestamp + depth - Non-Shearwater dives still emit profile:[] silently - Decode-failure warnings stay bounded (<5% of Shearwater dive count) All four tests guard against the FFI-unavailable unit-test environment (no native plugin registered) by detecting when all profiles are empty or all dives emit decode failures, and returning early rather than producing false failures on the build server.
Contributor
There was a problem hiding this comment.
Pull request overview
Adds libdivecomputer-backed decoding of MacDive SQLite ZDIVE.ZRAWDATA so Shearwater dives imported from MacDive gain full time-series profile samples (while preserving metadata-only behavior for dives without ZRAWDATA / unsupported computers and providing a one-time “FFI unavailable” fallback warning).
Changes:
- Make
MacDiveDiveMapper.toPayloadasync and decodeZRAWDATAinto canonicalprofilesample maps vialibdivecomputer_plugin.parseRawDiveData, emitting bounded warnings and short-circuiting repeated FFI failures. - Update
MacDiveSqliteParserto await the async mapper. - Extend/adjust tests (synthetic + gated real-sample) to cover decode success/failure, null
ZRAWDATA, and “MissingPluginException disables FFI” behavior.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| lib/features/universal_import/data/services/macdive_dive_mapper.dart | Adds async profile decoding from ZRAWDATA via libdivecomputer, warning aggregation, and vendor/product mapping for Shearwater models. |
| lib/features/universal_import/data/parsers/macdive_sqlite_parser.dart | Awaits the now-async mapper so mapping failures are caught within parser error handling. |
| test/features/universal_import/data/services/macdive_dive_mapper_test.dart | Updates existing tests to await async mapper and adds targeted profile-decoding unit tests. |
| test/features/universal_import/data/parsers/macdive_sqlite_real_sample_test.dart | Replaces “profile always empty” checks with gated real-sample assertions for Shearwater decode rate/shape and bounded warning behavior. |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
…ple fields Raises patch coverage toward the 85% target by exercising previously untested branches in MacDiveDiveMapper: - PlatformException(UNSUPPORTED) — disables FFI for remaining dives - PlatformException(channel-error) — same fatal-error path - PlatformException with non-fatal code — per-dive warning, FFI stays on - _defaultParse invoked via toPayload with no parseRawDiveData — exercises the real platform-channel code path that tests mock away by default - _projectSamples on samples with pressureBar + tankIndex, deco ceiling (decoType != 0), NDL (decoType == 0), heart rate, setpoint, ppO2, cns, rbt, tts — verifies the conditional emission branches
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes the profile-decoding gap from #256 (which landed metadata-only MacDive SQLite import) using the pivot documented in the Phase 1 spike (closed PR #260).
ZDIVE.ZRAWDATAvia the already-integratedlibdivecomputer_plugin.parseRawDiveData()API.ZRAWDATA(non-Shearwater computers, manual entries, older imports) continue to import metadata-only. Decoder failures emit oneImportWarning.warning; unmapped computers emitprofile: []silently.MissingPluginException/PlatformException(UNSUPPORTED|channel-error), emits oneinfowarning, and skips FFI for remaining dives — avoiding O(N) failing plugin round-trips.Why not
ZSAMPLESSee
docs/import-formats/macdive-zsamples.md— MacDive's proprietaryZSAMPLEScolumn is per-dive AES-encrypted. Phase 1 spike ruled it NO-GO; this PR is the pivot toZRAWDATA.Changes
lib/features/universal_import/data/services/macdive_dive_mapper.dart—toPayloadis nowasyncwith an optionalparseRawDiveDataparameter (for tests). New helpers:_decodeProfile,_projectSamples,_vendorProductFromZComputer. Projection intentionally duplicatesShearwaterDiveMapper.mergeWithParsedDive(same sample-map keys, same conditional emission).lib/features/universal_import/data/parsers/macdive_sqlite_parser.dart— addsawaitto the mapper call.test/features/universal_import/data/services/macdive_dive_mapper_test.dart— 10 existing callsites now useawait; 4 new tests: decode success, decode failure, null ZRAWDATA, MissingPluginException disables FFI.test/features/universal_import/data/parsers/macdive_sqlite_real_sample_test.dart— replaces the stale "profile always empty" assertion with 4 ZRAWDATA-specific tests (Shearwater decode rate ≥95%, expected sample-map keys, non-Shearwater stays empty, warning count bounded).Vendor / model mapping
_vendorProductFromZComputercovers:Shearwater Teric,Shearwater Tern,Shearwater Petrel,Shearwater Perdix,Shearwater Perdix 2,Shearwater Nerd,Shearwater NERD 2. Extend if a user provides a DB with other dive computers that libdivecomputer supports.Test plan
flutter analyzecleanflutter test test/features/universal_import/data/services/macdive_dive_mapper_test.dart— 14/14 passingflutter test test/features/universal_import/data/parsers/macdive_sqlite_parser_test.dart— 6/6 passingMACDIVE_SQLITE_REAL_SAMPLE_PATH=/path/to/MacDive.sqlite flutter test --run-skipped --tags=real-data test/features/universal_import/data/parsers/macdive_sqlite_real_sample_test.dartPrior work
docs/import-formats/macdive-zsamples.md.Known limitations (documented in the findings doc)
ZRAWDATAand no support in the shippedlibdivecomputerbuild. They remain profile-less; users wanting those profiles should continue to use MacDive UDDF export.ShearwaterDiveMapper's behavior.