seedhammer-v1-companion/nonstandard/parse_test.go
mineracks 9261cf368a Lift composer substrate from upstream v1.3.0
Twelve packages lifted from seedhammer/seedhammer @ v1.3.0
(commit 2f071c1d8f23eb7fd39b15fc0acb8874113f801e):

  address/     — bitcoin address parsing
  backup/      — v1 plate dimensions + UR-coded multi-plate backup
  bc/          — Blockchain Commons: ur, fountain, bytewords, urtypes,
                 xoshiro256 (5 subpkgs)
  bip32/       — HD-key derivation
  bip39/       — mnemonic seed phrases + 2048-word wordlist
  engrave/     — text/QR → MoveTo/LineTo command stream conversion
  seedqr/      — SeedQR / CompactSeedQR encoders
  image/       — paletted, rgb565, alpha4, ninepatch image formats
  nonstandard/ — bitcoin descriptor + script parsing
  font/        — bitmap + vector font runtime
  font/{comfortaa,poppins,constant,bitmap,vector}/  — actual fonts
  driver/mjolnir/  — MarkingWay USB-serial engraver driver

Plus an earlier-aside backup_test.go restored (its deps are now lifted).

Import paths globally rewritten seedhammer.com → mineracks namespace
via single sed pass; verified no orphan refs remain. go.mod adopts
upstream's full dep set plus the replace-directive for the patched
kortschak/qr fork.

  go build ./...     clean (all 27 packages)
  go test ./...      clean (12 packages with tests, all passing)

NOT lifted in this commit:
  - driver/{wshat,drm,libcamera}  (hardware-specific GPIO/LCD/camera —
    will be platform-v1/-shaped abstractions instead)
  - gui/                (depends on the above; lifts in Phase 2)
  - cmd/{controller,...} (Pi binary entrypoints — not needed for the
    companion repo)
  - zbar/               (QR scanner — needs libcamera)

Next:
  - Write the SH1E reference encoder/decoder in engrave/wire/sh1e/
  - Lift Gangleri42's cmd/webnfc/ shell + retune to v1 plates
  - First buildable composer WASM with a working preview

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 18:36:40 +10:00

261 lines
14 KiB
Go

package nonstandard
import (
"reflect"
"testing"
"github.com/btcsuite/btcd/btcutil/hdkeychain"
"github.com/btcsuite/btcd/chaincfg"
"github.com/mineracks/seedhammer-v1-companion/bc/urtypes"
)
func TestOutputDescriptors(t *testing.T) {
tests := []struct {
encoded string
desc urtypes.OutputDescriptor
}{
{
"wsh(sortedmulti(2,[dc567276/48h/0h/0h/2h]xpub6DiYrfRwNnjeX4vHsWMajJVFKrbEEnu8gAW9vDuQzgTWEsEHE16sGWeXXUV1LBWQE1yCTmeprSNcqZ3W74hqVdgDbtYHUv3eM4W2TEUhpan/0/*,[f245ae38/48h/0h/0h/2h]xpub6DnT4E1fT8VxuAZW29avMjr5i99aYTHBp9d7fiLnpL5t4JEprQqPMbTw7k7rh5tZZ2F5g8PJpssqrZoebzBChaiJrmEvWwUTEMAbHsY39Ge/0/*,[c5d87297/48h/0h/0h/2h]xpub6DjrnfAyuonMaboEb3ZQZzhQ2ZEgaKV2r64BFmqymZqJqviLTe1JzMr2X2RfQF892RH7MyYUbcy77R7pPu1P71xoj8cDUMNhAMGYzKR4noZ/0/*))#hfwurrvt",
urtypes.OutputDescriptor{
Script: urtypes.P2WSH,
Threshold: 2,
Type: urtypes.SortedMulti,
Keys: []urtypes.KeyDescriptor{
{
Network: &chaincfg.MainNetParams,
MasterFingerprint: 0xdc567276,
DerivationPath: []uint32{hdkeychain.HardenedKeyStart + 48, hdkeychain.HardenedKeyStart, hdkeychain.HardenedKeyStart, hdkeychain.HardenedKeyStart + 2},
Children: []urtypes.Derivation{{Index: 0}, {Type: urtypes.WildcardDerivation}},
KeyData: []uint8{0x2, 0x1c, 0xb, 0x47, 0x9e, 0xcf, 0x6e, 0x67, 0x71, 0x3d, 0xdf, 0xc, 0x43, 0xb6, 0x34, 0x59, 0x2f, 0x51, 0xc0, 0x37, 0xb6, 0xf9, 0x51, 0xfb, 0x1d, 0xc6, 0x36, 0x1a, 0x98, 0xb1, 0xe5, 0x73, 0x5e},
ChainCode: []uint8{0x6b, 0x3a, 0x4c, 0xfb, 0x6a, 0x45, 0xf6, 0x30, 0x5e, 0xfe, 0x6e, 0xe, 0x97, 0x6b, 0x5d, 0x26, 0xba, 0x27, 0xf7, 0xc3, 0x44, 0xd7, 0xfc, 0x7a, 0xbe, 0xf7, 0xbe, 0x2d, 0x6, 0xd5, 0x2d, 0xfd},
ParentFingerprint: 0x18f8c2e7,
},
{
Network: &chaincfg.MainNetParams,
MasterFingerprint: 0xf245ae38,
DerivationPath: []uint32{hdkeychain.HardenedKeyStart + 48, hdkeychain.HardenedKeyStart, hdkeychain.HardenedKeyStart, hdkeychain.HardenedKeyStart + 2},
Children: []urtypes.Derivation{{Index: 0}, {Type: urtypes.WildcardDerivation}},
KeyData: []uint8{0x3, 0x97, 0xfc, 0xf2, 0x27, 0x4a, 0xbd, 0x24, 0x3d, 0x42, 0xd4, 0x2d, 0x3c, 0x24, 0x86, 0x8, 0xc6, 0xd1, 0x93, 0x5e, 0xfc, 0xa4, 0x61, 0x38, 0xaf, 0xef, 0x43, 0xaf, 0x8, 0xe9, 0x71, 0x28, 0x96},
ChainCode: []uint8{0xc8, 0x87, 0xc7, 0x2d, 0x9d, 0x8a, 0xc2, 0x9c, 0xdd, 0xd5, 0xb2, 0xb0, 0x60, 0xe8, 0xb0, 0x23, 0x90, 0x39, 0xa1, 0x49, 0xc7, 0x84, 0xab, 0xe6, 0x7, 0x9e, 0x24, 0x44, 0x5d, 0xb4, 0xaa, 0x8a},
ParentFingerprint: 0x221eb5a0,
},
{
Network: &chaincfg.MainNetParams,
MasterFingerprint: 0xc5d87297,
DerivationPath: []uint32{hdkeychain.HardenedKeyStart + 48, hdkeychain.HardenedKeyStart, hdkeychain.HardenedKeyStart, hdkeychain.HardenedKeyStart + 2},
Children: []urtypes.Derivation{{Index: 0}, {Type: urtypes.WildcardDerivation}},
KeyData: []uint8{0x2, 0x83, 0x42, 0xf5, 0xf7, 0x77, 0x3f, 0x6f, 0xab, 0x37, 0x4e, 0x1c, 0x2d, 0x3c, 0xcd, 0xba, 0x26, 0xbc, 0x9, 0x33, 0xfc, 0x4f, 0x63, 0x82, 0x8b, 0x66, 0x2b, 0x43, 0x57, 0xe4, 0xcc, 0x37, 0x91},
ChainCode: []uint8{0x5a, 0xfe, 0xd5, 0x6d, 0x75, 0x5c, 0x8, 0x83, 0x20, 0xec, 0x9b, 0xc6, 0xac, 0xd8, 0x4d, 0x33, 0x73, 0x7b, 0x58, 0x0, 0x83, 0x75, 0x9e, 0xa, 0xf, 0xf8, 0xf2, 0x6e, 0x42, 0x9e, 0xb, 0x77},
ParentFingerprint: 0x1c0ae906,
},
},
},
},
{
`{
"label": "Test Multisig 2-of-3",
"blockheight": 481824,
"descriptor": "wsh(sortedmulti(2,[dc567276/48h/0h/0h/2h]xpub6DiYrfRwNnjeX4vHsWMajJVFKrbEEnu8gAW9vDuQzgTWEsEHE16sGWeXXUV1LBWQE1yCTmeprSNcqZ3W74hqVdgDbtYHUv3eM4W2TEUhpan/0/*,[f245ae38/48h/0h/0h/2h]xpub6DnT4E1fT8VxuAZW29avMjr5i99aYTHBp9d7fiLnpL5t4JEprQqPMbTw7k7rh5tZZ2F5g8PJpssqrZoebzBChaiJrmEvWwUTEMAbHsY39Ge/0/*,[c5d87297/48h/0h/0h/2h]xpub6DjrnfAyuonMaboEb3ZQZzhQ2ZEgaKV2r64BFmqymZqJqviLTe1JzMr2X2RfQF892RH7MyYUbcy77R7pPu1P71xoj8cDUMNhAMGYzKR4noZ/0/*))#hfwurrvt",
"devices": [{"type": "other", "label": "Test Multisig 2-of-3 Cosigner 1"}, {"type": "other", "label": "Test Multisig 2-of-3 Cosigner 2"}, {"type": "other", "label": "Test Multisig 2-of-3 Cosigner 3"}]
}`,
urtypes.OutputDescriptor{
Title: "Test Multisig 2-of-3",
Script: urtypes.P2WSH,
Threshold: 2,
Type: urtypes.SortedMulti,
Keys: []urtypes.KeyDescriptor{
{
Network: &chaincfg.MainNetParams,
MasterFingerprint: 0xdc567276,
DerivationPath: []uint32{hdkeychain.HardenedKeyStart + 48, hdkeychain.HardenedKeyStart, hdkeychain.HardenedKeyStart, hdkeychain.HardenedKeyStart + 2},
Children: []urtypes.Derivation{{Index: 0}, {Type: urtypes.WildcardDerivation}},
KeyData: []uint8{0x2, 0x1c, 0xb, 0x47, 0x9e, 0xcf, 0x6e, 0x67, 0x71, 0x3d, 0xdf, 0xc, 0x43, 0xb6, 0x34, 0x59, 0x2f, 0x51, 0xc0, 0x37, 0xb6, 0xf9, 0x51, 0xfb, 0x1d, 0xc6, 0x36, 0x1a, 0x98, 0xb1, 0xe5, 0x73, 0x5e},
ChainCode: []uint8{0x6b, 0x3a, 0x4c, 0xfb, 0x6a, 0x45, 0xf6, 0x30, 0x5e, 0xfe, 0x6e, 0xe, 0x97, 0x6b, 0x5d, 0x26, 0xba, 0x27, 0xf7, 0xc3, 0x44, 0xd7, 0xfc, 0x7a, 0xbe, 0xf7, 0xbe, 0x2d, 0x6, 0xd5, 0x2d, 0xfd},
ParentFingerprint: 0x18f8c2e7,
},
{
Network: &chaincfg.MainNetParams,
MasterFingerprint: 0xf245ae38,
DerivationPath: []uint32{hdkeychain.HardenedKeyStart + 48, hdkeychain.HardenedKeyStart, hdkeychain.HardenedKeyStart, hdkeychain.HardenedKeyStart + 2},
Children: []urtypes.Derivation{{Index: 0}, {Type: urtypes.WildcardDerivation}},
KeyData: []uint8{0x3, 0x97, 0xfc, 0xf2, 0x27, 0x4a, 0xbd, 0x24, 0x3d, 0x42, 0xd4, 0x2d, 0x3c, 0x24, 0x86, 0x8, 0xc6, 0xd1, 0x93, 0x5e, 0xfc, 0xa4, 0x61, 0x38, 0xaf, 0xef, 0x43, 0xaf, 0x8, 0xe9, 0x71, 0x28, 0x96},
ChainCode: []uint8{0xc8, 0x87, 0xc7, 0x2d, 0x9d, 0x8a, 0xc2, 0x9c, 0xdd, 0xd5, 0xb2, 0xb0, 0x60, 0xe8, 0xb0, 0x23, 0x90, 0x39, 0xa1, 0x49, 0xc7, 0x84, 0xab, 0xe6, 0x7, 0x9e, 0x24, 0x44, 0x5d, 0xb4, 0xaa, 0x8a},
ParentFingerprint: 0x221eb5a0,
},
{
Network: &chaincfg.MainNetParams,
MasterFingerprint: 0xc5d87297,
DerivationPath: []uint32{hdkeychain.HardenedKeyStart + 48, hdkeychain.HardenedKeyStart, hdkeychain.HardenedKeyStart, hdkeychain.HardenedKeyStart + 2},
Children: []urtypes.Derivation{{Index: 0}, {Type: urtypes.WildcardDerivation}},
KeyData: []uint8{0x2, 0x83, 0x42, 0xf5, 0xf7, 0x77, 0x3f, 0x6f, 0xab, 0x37, 0x4e, 0x1c, 0x2d, 0x3c, 0xcd, 0xba, 0x26, 0xbc, 0x9, 0x33, 0xfc, 0x4f, 0x63, 0x82, 0x8b, 0x66, 0x2b, 0x43, 0x57, 0xe4, 0xcc, 0x37, 0x91},
ChainCode: []uint8{0x5a, 0xfe, 0xd5, 0x6d, 0x75, 0x5c, 0x8, 0x83, 0x20, 0xec, 0x9b, 0xc6, 0xac, 0xd8, 0x4d, 0x33, 0x73, 0x7b, 0x58, 0x0, 0x83, 0x75, 0x9e, 0xa, 0xf, 0xf8, 0xf2, 0x6e, 0x42, 0x9e, 0xb, 0x77},
ParentFingerprint: 0x1c0ae906,
},
},
},
},
{
"sh(wpkh(xpub6DiYrfRwNnjeX4vHsWMajJVFKrbEEnu8gAW9vDuQzgTWEsEHE16sGWeXXUV1LBWQE1yCTmeprSNcqZ3W74hqVdgDbtYHUv3eM4W2TEUhpan))",
urtypes.OutputDescriptor{
Script: urtypes.P2SH_P2WPKH,
Type: urtypes.Singlesig,
Threshold: 1,
Keys: []urtypes.KeyDescriptor{
{
Network: &chaincfg.MainNetParams,
KeyData: []uint8{0x2, 0x1c, 0xb, 0x47, 0x9e, 0xcf, 0x6e, 0x67, 0x71, 0x3d, 0xdf, 0xc, 0x43, 0xb6, 0x34, 0x59, 0x2f, 0x51, 0xc0, 0x37, 0xb6, 0xf9, 0x51, 0xfb, 0x1d, 0xc6, 0x36, 0x1a, 0x98, 0xb1, 0xe5, 0x73, 0x5e},
ChainCode: []uint8{0x6b, 0x3a, 0x4c, 0xfb, 0x6a, 0x45, 0xf6, 0x30, 0x5e, 0xfe, 0x6e, 0xe, 0x97, 0x6b, 0x5d, 0x26, 0xba, 0x27, 0xf7, 0xc3, 0x44, 0xd7, 0xfc, 0x7a, 0xbe, 0xf7, 0xbe, 0x2d, 0x6, 0xd5, 0x2d, 0xfd},
ParentFingerprint: 0x18f8c2e7,
DerivationPath: urtypes.P2SH_P2WPKH.DerivationPath(),
},
},
},
},
{
"wpkh(tpubDE77mtPH9LnL5r2mFHjEXM2KZ6P2YyHcyCtjAXroj9jnQDbwtsRim3CoXTv2pQUaJinqoBFAhXguGhZcL4JDVD7JShCnV9MfAfSpke4Ja58)",
urtypes.OutputDescriptor{
Script: urtypes.P2WPKH,
Type: urtypes.Singlesig,
Threshold: 1,
Keys: []urtypes.KeyDescriptor{
{
Network: &chaincfg.TestNet3Params,
KeyData: []uint8{0x3, 0x46, 0x6d, 0xc4, 0xf, 0x23, 0x5c, 0x13, 0xa7, 0x3d, 0x2a, 0x65, 0x18, 0x16, 0x89, 0x62, 0x94, 0xd8, 0x75, 0x44, 0xdb, 0x71, 0x6c, 0x28, 0xde, 0x4a, 0x19, 0x58, 0xfb, 0xb8, 0xc5, 0xe9, 0x66},
ChainCode: []uint8{0x7a, 0xb6, 0x2, 0x11, 0xef, 0xd1, 0x25, 0x52, 0x1d, 0xdb, 0x57, 0x77, 0x57, 0xf0, 0xad, 0xb2, 0x94, 0xd7, 0x81, 0xd5, 0x58, 0x3d, 0x94, 0x31, 0xe6, 0x24, 0x35, 0x18, 0x1, 0x6c, 0x7b, 0x75},
ParentFingerprint: 0x1b2bf3a6,
DerivationPath: urtypes.P2WPKH.DerivationPath(),
},
},
},
},
}
for _, test := range tests {
got, err := OutputDescriptor([]byte(test.encoded))
if err != nil {
t.Fatalf("%q\nfailed with: %v", test.encoded, err)
}
if !reflect.DeepEqual(got, test.desc) {
t.Errorf("%q\ndecoded to\n%#v\nexpected\n%#v\n", test.encoded, got, test.desc)
}
}
}
func TestProprietaryDescriptors(t *testing.T) {
tests := []struct {
name string
encoded string
desc string
}{
{
"sh",
`# BlueWallet Multisig setup file
# this file contains only public keys and is safe to
# distribute among cosigners
#
Name: sh
Policy: 2 of 3
Derivation: m/48'/0'/0'/2'
Format: P2WSH
5A0804E3: xpub6F148LnjUhGrHfEN6Pa8VkwF8L6FJqYALxAkuHfacfVhMLVY4MRuUVMxr9pguAv67DHx1YFxqoKN8s4QfZtD9sR2xRCffTqi9E8FiFLAYk8
DD4FADEE: xpub6DnediUuY8Pcc6Fej8Yt2ZntPCyFdpbHBkNV7EawesRMbc6i9MKKMhKEv4JMMzwDJckaV4czBvNdc6ikwLiZqdUqMd5ZKQGYaQT4cXMeVjf
9BACD5C0: xpub6EefrCrMAduhNwnsHb3dAs8DYZSw4f63WyR6DaEByUHjwvPDdhczj15FyBBG4tbEJtf4vRKTv1ng5SPPnWv1Pve1f15EJfiBY5oYDN6VLEC
`,
"wsh(sortedmulti(2,[5A0804E3/48'/0'/0'/2']xpub6F148LnjUhGrHfEN6Pa8VkwF8L6FJqYALxAkuHfacfVhMLVY4MRuUVMxr9pguAv67DHx1YFxqoKN8s4QfZtD9sR2xRCffTqi9E8FiFLAYk8,[DD4FADEE/48'/0'/0'/2']xpub6DnediUuY8Pcc6Fej8Yt2ZntPCyFdpbHBkNV7EawesRMbc6i9MKKMhKEv4JMMzwDJckaV4czBvNdc6ikwLiZqdUqMd5ZKQGYaQT4cXMeVjf,[9BACD5C0/48'/0'/0'/2']xpub6EefrCrMAduhNwnsHb3dAs8DYZSw4f63WyR6DaEByUHjwvPDdhczj15FyBBG4tbEJtf4vRKTv1ng5SPPnWv1Pve1f15EJfiBY5oYDN6VLEC))",
},
{
// Wallet with Zpub keys.
"V2",
`# BlueWallet Multisig setup file
Name: V2
Policy: 2 of 3
Derivation: m/48'/0'/0'/2'
Format: P2WSH
79E1C26F: Zpub753vSk6B5CuYmJBvgBQYmBUghHoApQHtgJWthN7WmrJsaRaCGuQFguZTXdJxCL2rUbFdsVcLuT9ASoKGtRtug3A6SZmhfaMzYH5yc11Da3h
FC68BCE8: Zpub74vSYSU12tQqbxYb7YYwUSHq8bUVSe3iKxG8JHmuLjEu1K3ZjjgH1refsgdUhxR4WttV1NFQzJnZZtueannW6Mau9QXs58wLWvh3ftfkk97
347BCBE3: Zpub74bnCwDLdCa7ytzd2unjhLL842fv4RocsHbRBcpP8Nv2DGp6eCzZfJesd55YvYv1TkVrsyCNSV8HcoHcHpmm1GvmhuYmschCbYcTR1orqKB
`,
"wsh(sortedmulti(2,[79E1C26F/48'/0'/0'/2']Zpub753vSk6B5CuYmJBvgBQYmBUghHoApQHtgJWthN7WmrJsaRaCGuQFguZTXdJxCL2rUbFdsVcLuT9ASoKGtRtug3A6SZmhfaMzYH5yc11Da3h,[FC68BCE8/48'/0'/0'/2']Zpub74vSYSU12tQqbxYb7YYwUSHq8bUVSe3iKxG8JHmuLjEu1K3ZjjgH1refsgdUhxR4WttV1NFQzJnZZtueannW6Mau9QXs58wLWvh3ftfkk97,[347BCBE3/48'/0'/0'/2']Zpub74bnCwDLdCa7ytzd2unjhLL842fv4RocsHbRBcpP8Nv2DGp6eCzZfJesd55YvYv1TkVrsyCNSV8HcoHcHpmm1GvmhuYmschCbYcTR1orqKB))",
},
{
"test",
`Name: test
Policy: 2 of 3
Format: P2WSH
Derivation: m/48'/0'/0'/2'
dc567276: xpub6DiYrfRwNnjeX4vHsWMajJVFKrbEEnu8gAW9vDuQzgTWEsEHE16sGWeXXUV1LBWQE1yCTmeprSNcqZ3W74hqVdgDbtYHUv3eM4W2TEUhpan
Derivation: m/48'/0'/0'/2'
f245ae38: xpub6DnT4E1fT8VxuAZW29avMjr5i99aYTHBp9d7fiLnpL5t4JEprQqPMbTw7k7rh5tZZ2F5g8PJpssqrZoebzBChaiJrmEvWwUTEMAbHsY39Ge
Derivation: m/48'/0'/0'/2'
c5d87297: xpub6DjrnfAyuonMaboEb3ZQZzhQ2ZEgaKV2r64BFmqymZqJqviLTe1JzMr2X2RfQF892RH7MyYUbcy77R7pPu1P71xoj8cDUMNhAMGYzKR4noZ
`,
"wsh(sortedmulti(2,[dc567276/48'/0'/0'/2']xpub6DiYrfRwNnjeX4vHsWMajJVFKrbEEnu8gAW9vDuQzgTWEsEHE16sGWeXXUV1LBWQE1yCTmeprSNcqZ3W74hqVdgDbtYHUv3eM4W2TEUhpan,[f245ae38/48'/0'/0'/2']xpub6DnT4E1fT8VxuAZW29avMjr5i99aYTHBp9d7fiLnpL5t4JEprQqPMbTw7k7rh5tZZ2F5g8PJpssqrZoebzBChaiJrmEvWwUTEMAbHsY39Ge,[c5d87297/48'/0'/0'/2']xpub6DjrnfAyuonMaboEb3ZQZzhQ2ZEgaKV2r64BFmqymZqJqviLTe1JzMr2X2RfQF892RH7MyYUbcy77R7pPu1P71xoj8cDUMNhAMGYzKR4noZ))",
},
{
"",
"[4bbaa801/84'/0'/0']zpub6qpFgGWoG7bKmDDMvmwHBvg6inZAb2KF2Vg8h4fKJ2ickSZ71PsMmRg1FyRWAS6PqPCSzd5CB6PHixx64k6q5svZNZd9bEoCWJuMSkSRzJx",
"wpkh([4bbaa801/84'/0'/0']xpub6C9j4wAxxkWN4cq8G4N2mkV6NrGGhnLFCGdh8GsYY1xreEveW5YEXJMjDZWLAcnZ26xqVft5FmgBxPixdMGoVQZMdtEJRRADxrn4facoGnx)",
},
{
"",
"zpub6qpFgGWoG7bKmDDMvmwHBvg6inZAb2KF2Vg8h4fKJ2ickSZ71PsMmRg1FyRWAS6PqPCSzd5CB6PHixx64k6q5svZNZd9bEoCWJuMSkSRzJx",
"wpkh([00000000/84'/0'/0']xpub6C9j4wAxxkWN4cq8G4N2mkV6NrGGhnLFCGdh8GsYY1xreEveW5YEXJMjDZWLAcnZ26xqVft5FmgBxPixdMGoVQZMdtEJRRADxrn4facoGnx)",
},
{
"",
"xpub6C9j4wAxxkWN4cq8G4N2mkV6NrGGhnLFCGdh8GsYY1xreEveW5YEXJMjDZWLAcnZ26xqVft5FmgBxPixdMGoVQZMdtEJRRADxrn4facoGnx",
"pkh(xpub6C9j4wAxxkWN4cq8G4N2mkV6NrGGhnLFCGdh8GsYY1xreEveW5YEXJMjDZWLAcnZ26xqVft5FmgBxPixdMGoVQZMdtEJRRADxrn4facoGnx)",
},
}
for _, test := range tests {
got, err := OutputDescriptor([]byte(test.encoded))
if err != nil {
t.Fatalf("failed to parse:\n%q\nerror: %v", test.encoded, err)
}
want, err := parseTextOutputDescriptor(test.desc)
if err != nil {
t.Fatalf("failed to parse reference:\n%q\nerror: %v", test.desc, err)
}
want.Title = test.name
if !reflect.DeepEqual(got, want) {
t.Errorf("%q\ndecoded to\n%#v\nexpected\n%#v\n", test.encoded, got, want)
}
}
}
func TestDecoder(t *testing.T) {
parts := []string{
"p1of3 abc",
"p2of3 def",
"p3of3 g",
}
var d Decoder
for _, p := range parts {
if err := d.Add(p); err != nil {
t.Fatal(err)
}
}
if p := d.Progress(); p != 1. {
t.Errorf("decoder progress %f, want 1.", p)
}
got := string(d.Result())
if want := "abcdefg"; got != want {
t.Errorf("decoded %q, want %q", got, want)
}
}
func TestElectrumSeed(t *testing.T) {
phrase := "head orient raw shoulder size fancy front cycle lamp giant camera jacket"
if !ElectrumSeed(phrase) {
t.Fatal("failed to detect Electrum seed")
}
}