Both the snapshot helper and the multi-touch helper drive 'am instrument -w'
and parse the same INSTRUMENTATION_STATUS/INSTRUMENTATION_RESULT key/value
records, and both validate a bundled JSON manifest with the same integer and
literal field rules.
Extract the genuinely-identical parts into a shared
src/platforms/android/instrumentation-helper.ts:
- parseInstrumentationRecords (status + result record parsing) and the
shared key/value reader
- readInstrumentationResultNumber / readInstrumentationResultBoolean
- readAndroidHelperManifestInteger / readAndroidHelperManifestLiteral
(label-parameterized so each helper's exact error message is preserved)
multitouch-helper now consumes the shared record parser (was its own
~25-line copy) and the shared numeric reader; snapshot-helper-capture
re-exports the shared metadata readers under their existing public names so
snapshot-helper-session keeps importing them unchanged.
Behaviorless: the divergent, behavior-bearing parts are intentionally left
in each consumer (install caches Set vs Map + install-policy/forget/retry,
installed-versionCode regex + timeout, sha256File stream-vs-read,
readString trim semantics and the sha256 validator that depends on it,
artifact resolution + per-helper manifest schemas).
What
The Android snapshot helper and multi-touch helper both drive
am instrument -wand independently re-implement the same low-level glue:INSTRUMENTATION_STATUS/INSTRUMENTATION_RESULTkey/value recordsThis PR extracts the genuinely-identical parts into a new single-source module
src/platforms/android/instrumentation-helper.tsand has both helpers consume it:parseInstrumentationRecords(output)— status + result record parsing (+ the shared=key/value reader)readInstrumentationResultNumber/readInstrumentationResultBooleanreadAndroidHelperManifestInteger/readAndroidHelperManifestLiteral— label-parameterized ("snapshot helper"/"multi-touch helper") so each helper's exact error message is preserved byte-for-bytemultitouch-helper.tspreviously carried its own ~25-line copy of the result parser; it now callsparseInstrumentationRecords(...).results.snapshot-helper-capture.tsre-exports the shared metadata readers under their existing public names (readAndroidSnapshotHelperMetadataNumber/Boolean) sosnapshot-helper-session.tskeeps importing them unchanged.LOC
Consumers shed 173 lines of duplicated/relocated parsing+validation logic, now single-sourced in the new 134-line shared module (
+177 / -173across 4 files; net ~flat, duplication eliminated). The genuine duplicate that was deleted outright is multi-touch's parallel INSTRUMENTATION parser plus the per-helper manifest integer/literal validators.Validation
tsc -p tsconfig.json --noEmit— cleanoxfmt --write+oxlint --deny-warnings— cleanvitest run android snapshot-helper multitouch— 284 passed (25 files), including the manifest message tests (... outputFormat must be "uiautomator-xml".,... sha256 must be a 64-character hex string.) and the result-number parsing tests (injectedEvents/elapsedMs).behaviorless
No behavior change for any valid input. The shared manifest validators preserve each helper's exact
INVALID_ARGSmessages via a label parameter; the sharedreadInstrumentationResultNumber/Booleanare byte-identical to the prior local copies; multitouch'sparseInstrumentationResults(output)is exactlyparseInstrumentationRecords(output).results(the extra status records are collected but discarded by multitouch, which only reads.results).Partial by design — the behavior-bearing differences were intentionally left in each consumer and NOT force-unified:
Set<string>(multi-touch, no policy) vsMap<string,number>(snapshot, with install-policy / forget-on-failure / retry-on-INSTALL_FAILED_UPDATE_INCOMPATIBLE)sha256File: whole-filereadFile(multi-touch) vs streaming (snapshot)readString:value.length === 0(multi-touch) vsvalue.trim().length === 0(snapshot) — and thereforereadSha256, which depends on it