1717package types_test
1818
1919import (
20+ "encoding/json"
2021 "errors"
22+ "fmt"
2123 "io"
2224 "testing"
2325
@@ -31,19 +33,33 @@ import (
3133)
3234
3335type stubHeaderHooks struct {
34- rlpSuffix []byte
35- gotRawRLPToDecode []byte
36- setHeaderToOnDecode Header
36+ suffix []byte
37+ gotRawJSONToUnmarshal , gotRawRLPToDecode []byte
38+ setHeaderToOnUnmarshalOrDecode Header
3739
38- errEncode , errDecode error
40+ errMarshal , errUnmarshal , errEncode , errDecode error
41+ }
42+
43+ func fakeHeaderJSON (h * Header , suffix []byte ) []byte {
44+ return []byte (fmt .Sprintf (`"%#x:%#x"` , h .ParentHash , suffix ))
3945}
4046
4147func fakeHeaderRLP (h * Header , suffix []byte ) []byte {
4248 return append (crypto .Keccak256 (h .ParentHash [:]), suffix ... )
4349}
4450
51+ func (hh * stubHeaderHooks ) MarshalJSON (h * Header ) ([]byte , error ) { //nolint:govet
52+ return fakeHeaderJSON (h , hh .suffix ), hh .errMarshal
53+ }
54+
55+ func (hh * stubHeaderHooks ) UnmarshalJSON (h * Header , b []byte ) error { //nolint:govet
56+ hh .gotRawJSONToUnmarshal = b
57+ * h = hh .setHeaderToOnUnmarshalOrDecode
58+ return hh .errUnmarshal
59+ }
60+
4561func (hh * stubHeaderHooks ) EncodeRLP (h * Header , w io.Writer ) error {
46- if _ , err := w .Write (fakeHeaderRLP (h , hh .rlpSuffix )); err != nil {
62+ if _ , err := w .Write (fakeHeaderRLP (h , hh .suffix )); err != nil {
4763 return err
4864 }
4965 return hh .errEncode
@@ -55,7 +71,7 @@ func (hh *stubHeaderHooks) DecodeRLP(h *Header, s *rlp.Stream) error {
5571 return err
5672 }
5773 hh .gotRawRLPToDecode = r
58- * h = hh .setHeaderToOnDecode
74+ * h = hh .setHeaderToOnUnmarshalOrDecode
5975 return hh .errDecode
6076}
6177
@@ -66,14 +82,36 @@ func TestHeaderHooks(t *testing.T) {
6682 extras := RegisterExtras [stubHeaderHooks , * stubHeaderHooks , struct {}]()
6783 rng := ethtest .NewPseudoRand (13579 )
6884
69- t .Run ("EncodeRLP" , func (t * testing.T ) {
70- suffix := rng .Bytes (8 )
85+ suffix := rng .Bytes (8 )
86+ hdr := & Header {
87+ ParentHash : rng .Hash (),
88+ }
89+ extras .Header .Get (hdr ).suffix = append ([]byte {}, suffix ... )
90+
91+ t .Run ("MarshalJSON" , func (t * testing.T ) {
92+ got , err := json .Marshal (hdr )
93+ require .NoError (t , err , "json.Marshal(%T)" , hdr )
94+ assert .Equal (t , fakeHeaderJSON (hdr , suffix ), got )
95+ })
7196
72- hdr := & Header {
73- ParentHash : rng .Hash (),
97+ t .Run ("UnmarshalJSON" , func (t * testing.T ) {
98+ hdr := new (Header )
99+ stub := & stubHeaderHooks {
100+ setHeaderToOnUnmarshalOrDecode : Header {
101+ Extra : []byte ("can you solve this puzzle? 0xbda01b6cf56c303bd3f581599c0d5c0b" ),
102+ },
74103 }
75- extras .Header .Get (hdr ).rlpSuffix = append ([]byte {}, suffix ... )
104+ extras .Header .Set (hdr , stub )
105+
106+ input := fmt .Sprintf ("%q" , "hello, JSON world" )
107+ err := json .Unmarshal ([]byte (input ), hdr )
108+ require .NoErrorf (t , err , "json.Unmarshal()" )
76109
110+ assert .Equal (t , input , string (stub .gotRawJSONToUnmarshal ), "raw JSON received by hook" )
111+ assert .Equal (t , & stub .setHeaderToOnUnmarshalOrDecode , hdr , "%T after JSON unmarshalling with hook" , hdr )
112+ })
113+
114+ t .Run ("EncodeRLP" , func (t * testing.T ) {
77115 got , err := rlp .EncodeToBytes (hdr )
78116 require .NoError (t , err , "rlp.EncodeToBytes(%T)" , hdr )
79117 assert .Equal (t , fakeHeaderRLP (hdr , suffix ), got )
@@ -85,7 +123,7 @@ func TestHeaderHooks(t *testing.T) {
85123
86124 hdr := new (Header )
87125 stub := & stubHeaderHooks {
88- setHeaderToOnDecode : Header {
126+ setHeaderToOnUnmarshalOrDecode : Header {
89127 Extra : []byte ("arr4n was here" ),
90128 },
91129 }
@@ -94,20 +132,46 @@ func TestHeaderHooks(t *testing.T) {
94132 require .NoErrorf (t , err , "rlp.DecodeBytes(%#x)" , input )
95133
96134 assert .Equal (t , input , stub .gotRawRLPToDecode , "raw RLP received by hooks" )
97- assert .Equalf (t , & stub .setHeaderToOnDecode , hdr , "%T after RLP decoding with hook" , hdr )
135+ assert .Equalf (t , & stub .setHeaderToOnUnmarshalOrDecode , hdr , "%T after RLP decoding with hook" , hdr )
98136 })
99137
100138 t .Run ("error_propagation" , func (t * testing.T ) {
139+ errMarshal := errors .New ("whoops" )
140+ errUnmarshal := errors .New ("is it broken?" )
101141 errEncode := errors .New ("uh oh" )
102142 errDecode := errors .New ("something bad happened" )
103143
104144 hdr := new (Header )
105- extras .Header .Set (hdr , & stubHeaderHooks {
106- errEncode : errEncode ,
107- errDecode : errDecode ,
108- })
145+ setStub := func () {
146+ extras .Header .Set (hdr , & stubHeaderHooks {
147+ errMarshal : errMarshal ,
148+ errUnmarshal : errUnmarshal ,
149+ errEncode : errEncode ,
150+ errDecode : errDecode ,
151+ })
152+ }
153+
154+ setStub ()
155+ // The { } blocks are defensive, avoiding accidentally having the wrong
156+ // error checked in a future refactor. The verbosity is acceptable for
157+ // clarity in tests.
158+ {
159+ _ , err := json .Marshal (hdr )
160+ assert .ErrorIs (t , err , errMarshal , "via json.Marshal()" ) //nolint:testifylint // require is inappropriate here as we wish to keep going
161+ }
162+ {
163+ err := json .Unmarshal ([]byte ("{}" ), hdr )
164+ assert .Equal (t , errUnmarshal , err , "via json.Unmarshal()" )
165+ }
109166
110- assert .Equal (t , errEncode , rlp .Encode (io .Discard , hdr ), "via rlp.Encode()" )
111- assert .Equal (t , errDecode , rlp .DecodeBytes ([]byte {0 }, hdr ), "via rlp.DecodeBytes()" )
167+ setStub () // [stubHeaderHooks] completely overrides the Header
168+ {
169+ err := rlp .Encode (io .Discard , hdr )
170+ assert .Equal (t , errEncode , err , "via rlp.Encode()" )
171+ }
172+ {
173+ err := rlp .DecodeBytes ([]byte {0 }, hdr )
174+ assert .Equal (t , errDecode , err , "via rlp.DecodeBytes()" )
175+ }
112176 })
113177}
0 commit comments