From a033ecfceafb0e3469d99f20ae603a9b2f3ab38d Mon Sep 17 00:00:00 2001 From: Teodor Calin Date: Wed, 27 May 2026 20:29:14 -0700 Subject: [PATCH] tests: tighten coverage by retiring unreachable defensive code (wave 2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Source changes: - saveEVMSigner (pkg/evm/key.go): identityFile struct is all strings — drop the json.MarshalIndent error branch with a comment. - saveLocalSigner (pkg/wallet/signer.go): identical to above for the Ed25519 identityFile. Test additions: - TestEVMAccessors_WithBinding (pkg/wallet/zz_helpers_test.go): drives the non-nil-evm branch of EVMAddress / EVMChainID / EVMToken so the accessors are covered beyond the nil-binding shortcut. - TestHexHelpers_ErrorPaths (pkg/evm/rpc_test.go): covers every rejection branch of hexToUint64 / hexToBigInt (missing 0x prefix, non-hex chars, value too large for uint64, empty-after-prefix). Coverage: 84.4% → 85.3%. The remaining gap is largely input-validation in crypto/financial code that fires on bad operator input — left as-is. --- pkg/evm/key.go | 6 ++---- pkg/evm/rpc_test.go | 30 ++++++++++++++++++++++++++++++ pkg/wallet/signer.go | 6 ++---- pkg/wallet/zz_helpers_test.go | 22 ++++++++++++++++++++++ 4 files changed, 56 insertions(+), 8 deletions(-) diff --git a/pkg/evm/key.go b/pkg/evm/key.go index d6adad1..da5398c 100644 --- a/pkg/evm/key.go +++ b/pkg/evm/key.go @@ -327,10 +327,8 @@ func saveEVMSigner(path string, s *EVMSigner) error { Address: s.addr.String(), CreatedAt: time.Now().UTC().Format(time.RFC3339), } - body, err := json.MarshalIndent(&f, "", " ") - if err != nil { - return err - } + // identityFile is all strings — json.MarshalIndent cannot fail. + body, _ := json.MarshalIndent(&f, "", " ") tmp := path + ".tmp" if err := os.WriteFile(tmp, body, 0o600); err != nil { return err diff --git a/pkg/evm/rpc_test.go b/pkg/evm/rpc_test.go index 9406345..ebb652c 100644 --- a/pkg/evm/rpc_test.go +++ b/pkg/evm/rpc_test.go @@ -182,3 +182,33 @@ func TestHexHelpersRoundtrip(t *testing.T) { } } } + +// TestHexHelpers_ErrorPaths covers each rejection branch of hexToUint64 +// and hexToBigInt: missing 0x prefix, non-hex characters, value too +// large for uint64. +func TestHexHelpers_ErrorPaths(t *testing.T) { + t.Parallel() + if _, err := hexToUint64("no-prefix"); err == nil { + t.Error("hexToUint64 should reject input without 0x prefix") + } + if _, err := hexToUint64("0xZZZZ"); err == nil { + t.Error("hexToUint64 should reject non-hex characters") + } + // 17-digit hex value overflows uint64. + if _, err := hexToUint64("0x10000000000000000"); err == nil { + t.Error("hexToUint64 should reject value too large for uint64") + } + if _, err := hexToBigInt("no-prefix"); err == nil { + t.Error("hexToBigInt should reject input without 0x prefix") + } + if _, err := hexToBigInt("0xZZZZ"); err == nil { + t.Error("hexToBigInt should reject non-hex characters") + } + // Empty-after-prefix returns 0 cleanly for both. + if got, err := hexToUint64("0x"); err != nil || got != 0 { + t.Errorf("hexToUint64(0x) = (%d, %v), want (0, nil)", got, err) + } + if got, err := hexToBigInt("0x"); err != nil || got == nil || got.Sign() != 0 { + t.Errorf("hexToBigInt(0x) = (%v, %v), want (0, nil)", got, err) + } +} diff --git a/pkg/wallet/signer.go b/pkg/wallet/signer.go index db2135c..13ab2b1 100644 --- a/pkg/wallet/signer.go +++ b/pkg/wallet/signer.go @@ -139,10 +139,8 @@ func saveLocalSigner(path string, s *LocalSigner) error { Pubkey: hex.EncodeToString(s.pub), CreatedAt: time.Now().UTC().Format(time.RFC3339), } - body, err := json.MarshalIndent(&f, "", " ") - if err != nil { - return fmt.Errorf("marshal: %w", err) - } + // identityFile is all strings — json.MarshalIndent cannot fail. + body, _ := json.MarshalIndent(&f, "", " ") // Write to a tmp then rename — never leave a half-written identity file. tmp := path + ".tmp" if err := os.WriteFile(tmp, body, 0o600); err != nil { diff --git a/pkg/wallet/zz_helpers_test.go b/pkg/wallet/zz_helpers_test.go index 30f50ea..6f3d717 100644 --- a/pkg/wallet/zz_helpers_test.go +++ b/pkg/wallet/zz_helpers_test.go @@ -172,3 +172,25 @@ func TestMemoryStore_IsSettled_DefaultFalse(t *testing.T) { t.Error("IsSettled fresh: want false") } } + +// TestEVMAccessors_WithBinding drives the non-nil-evm branch of +// EVMAddress / EVMChainID / EVMToken so coverage isn't pinned at the +// nil-binding shortcut path alone. +func TestEVMAccessors_WithBinding(t *testing.T) { + w := newDualWallet(t) // binds an EVM signer + chain id + defer w.Close() + addr := w.EVMAddress() + zero := [20]byte{} + if addr == zero { + t.Errorf("EVMAddress with binding should be non-zero, got zero") + } + if got := w.EVMChainID(); got == 0 { + t.Errorf("EVMChainID with binding should be non-zero, got 0") + } + // EVMToken on a dual wallet may legitimately be zero (mock method), + // just confirm the call doesn't panic and returns 20 bytes. + tok := w.EVMToken() + if len(tok) != 20 { + t.Errorf("EVMToken: got %d bytes, want 20", len(tok)) + } +}