test(coverage): close the coverage tail on shims, signing internals, decimal formatting - #76
Merged
Merged
Conversation
…decimal formatting Focused offline tests for the remaining uncovered lines: - transport/_polyfills.ts: native pass-throughs, plus the React Native fallbacks via a cache-busting re-import with the platform globals deleted. - transport/_redact.ts: a toJSON returning its own owner or an ancestor closes a cycle immediately. - signing/_abstractWallet.ts: signature length/recovery-value validation and the wrap-vs-rethrow error paths of signTypedData, signRawDigest, getWalletAddress, and getWalletChainId. - signing/_canonicalize.ts: the fast-path variant branch and the union structural matcher's required/optional key handling. - signing/_fastWallet.ts: the deriveAddress guard for a broken WASM module. - signing/_keccak.ts: a hasher throwing during the known-answer self-check, and the real loader's import-failure fallback (CJS entry hidden via require.cache drop + rename, restored afterwards). - utils/_decimal.ts / _format.ts: half-even edge branches (round-up-to-unit, all-nines carry-out) and the subnormal mantissa decomposition, forced through the exact path. _fastWallet.ts keeps 3 uncoverable lines (54-55, 58): the real ESM loader's failure internals cannot be exercised in a shared bun test process — an evaluated ESM module record is immutable, mock.module poisons the specifier process-wide, and a forced resolution failure poisons it permanently, all of which would break the differential suites.
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
Tests-only PR closing the remaining small coverage gaps in transport shims, signing internals, and the decimal/format machinery. Everything runs offline (
HL_OFFLINE=1), exactly like CI.src/transport/_polyfills.tssrc/transport/_redact.tssrc/signing/_abstractWallet.tssrc/signing/_canonicalize.tssrc/signing/_fastWallet.tssrc/signing/_keccak.tssrc/utils/_decimal.tssrc/utils/_format.ts(Before/after measured with
HL_OFFLINE=1 bun test tests/ --coverage --coverage-reporter=lcovon the base commit vs this branch; the_polyfills.tsDA total differs by one line between runs due to Bun's line attribution — both runs report 100% of the lines it attributes after this PR.)What was added
tests/transport/_polyfills.test.ts(new) — native pass-throughs (Promise_.withResolvers(), nativeDOMException_/CustomEvent_), plus the React Native fallbacks: platform globals are deleted and the module is re-imported through a cache-busting query (_polyfills.ts?react-native), so the selection IIFEs re-run and pick the bundled shims. Globals are restored infinally; the re-import never touches the instance the SDK already holds.tests/transport/_redact.test.ts— atoJSONthat returns its own owner (or an ancestor) closes a cycle immediately ("[Circular]") instead of descending forever.tests/signing/mod.test.ts— signature validation (wrong length, invalid recovery value) and the wrap-vs-rethrow error paths ofsignTypedData,signRawDigest,getWalletAddress,getWalletChainId: non-SDK wallet failures are wrapped with the cause kept;AbstractWalletErrors are rethrown unchanged.tests/signing/canonicalize_conformance.test.ts— theisCanonicalfast-path variant branch (canonical → by reference, non-canonical → rebuilt, unmatched →CanonicalizeError) and the union structural matcher's required-key handling (an option missing a required key is skipped; an option missing only an optional key still matches).tests/signing/fastWallet.test.ts—deriveAddressrejects when the WASM module returnsnullor a malformed point (_setEccLoaderForTestswith a stub module).tests/signing/keccak.test.ts— a hasher throwing during the known-answer self-check is never trusted; and the real loader's import-failure fallback: hash-wasm is CJS, so dropping itsrequire.cacherecord and hiding the entry file makesloadWasmKeccak's dynamic import really reject (restored infinally; verified that the real module re-loads afterwards). The test fails loudly (expect(served).toBe(false)) if a future runtime makes this simulation impossible.tests/utils/format.test.ts— the half-even edge branches in_decimal.ts(round-up-to-one-unit past half, tie-to-even below, all-nines carry-out for bothtoDecimalPlacesHalfEvenandtoSignificantDigitsHalfEven), the publicfloatToWireguard tripping at 5e-9, and the subnormal mantissa decomposition in_format.ts— subnormals never take the exact path naturally (toFixed(9)is all zeros), so the tie predicate is forced via a scopedNumber.prototype.toFixedpatch (restored infinally); the wire result is still"0", matching the fast path._fastWallet.ts: 3 lines remain (54–55, 58) — not coverable tests-onlyThese are the real
loadTinySecp256k1's shape-check return and catch. Reaching them requires the realimport("tiny-secp256k1")to fail or return a partial module inside the sharedbun test tests/process. Verified experimentally that every mechanism fails or destabilizes the suite:tiny-secp256k1loads as ESM; an evaluated ESM module record is immutable — hiding/swapping package files afterwards has no effect.mock.moduleis effectively one-shot per specifier and poisons it process-wide (mocks leak across test files; re-mocking the real namespace andmock.restore()do not undo it) — the repo's own module headers warn about this, and it would silently degrade the consensus-critical differential suites.import("tiny-secp256k1")in the process keeps failing (verified in a clean sandbox), breaking subsequent factory calls.require.cacheinjection doesn't apply: the ESM namespace is snapshotted at first import.The same lines in the CJS
hash-wasmloader were coverable (CJS recovers throughrequire.cachedeletion), which is why_keccak.tsreaches 100%.Verification
bun run check— all gates pass (format, lint, docs, types, ts7, jsdoc, export).HL_OFFLINE=1 bun test tests/— 1049 pass, 0 fail, 236 skip (skip count unchanged from base).