github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/core/transaction/attribute_test.go (about) 1 package transaction 2 3 import ( 4 "encoding/base64" 5 "encoding/json" 6 "testing" 7 8 "github.com/nspcc-dev/neo-go/internal/random" 9 "github.com/nspcc-dev/neo-go/internal/testserdes" 10 "github.com/nspcc-dev/neo-go/pkg/io" 11 "github.com/nspcc-dev/neo-go/pkg/util" 12 "github.com/stretchr/testify/assert" 13 "github.com/stretchr/testify/require" 14 ) 15 16 func TestAttribute_EncodeBinary(t *testing.T) { 17 t.Run("HighPriority", func(t *testing.T) { 18 attr := &Attribute{ 19 Type: HighPriority, 20 } 21 testserdes.EncodeDecodeBinary(t, attr, new(Attribute)) 22 }) 23 t.Run("OracleResponse", func(t *testing.T) { 24 attr := &Attribute{ 25 Type: OracleResponseT, 26 Value: &OracleResponse{ 27 ID: 0x1122334455, 28 Code: Success, 29 Result: []byte{1, 2, 3}, 30 }, 31 } 32 testserdes.EncodeDecodeBinary(t, attr, new(Attribute)) 33 for _, code := range []OracleResponseCode{ProtocolNotSupported, ConsensusUnreachable, 34 NotFound, Timeout, Forbidden, ResponseTooLarge, InsufficientFunds, Error} { 35 attr = &Attribute{ 36 Type: OracleResponseT, 37 Value: &OracleResponse{ 38 ID: 42, 39 Code: code, 40 Result: []byte{}, 41 }, 42 } 43 testserdes.EncodeDecodeBinary(t, attr, new(Attribute)) 44 } 45 }) 46 t.Run("NotValidBefore", func(t *testing.T) { 47 t.Run("positive", func(t *testing.T) { 48 attr := &Attribute{ 49 Type: NotValidBeforeT, 50 Value: &NotValidBefore{ 51 Height: 123, 52 }, 53 } 54 testserdes.EncodeDecodeBinary(t, attr, new(Attribute)) 55 }) 56 t.Run("bad format: too short", func(t *testing.T) { 57 bw := io.NewBufBinWriter() 58 bw.WriteBytes([]byte{1, 2, 3}) 59 require.Error(t, testserdes.DecodeBinary(bw.Bytes(), new(NotValidBefore))) 60 }) 61 }) 62 t.Run("Reserved", func(t *testing.T) { 63 getReservedAttribute := func(t AttrType) *Attribute { 64 return &Attribute{ 65 Type: t, 66 Value: &Reserved{ 67 Value: []byte{1, 2, 3, 4, 5}, 68 }, 69 } 70 } 71 t.Run("lower bound", func(t *testing.T) { 72 testserdes.EncodeDecodeBinary(t, getReservedAttribute(ReservedLowerBound+3), new(Attribute)) 73 }) 74 t.Run("upper bound", func(t *testing.T) { 75 testserdes.EncodeDecodeBinary(t, getReservedAttribute(ReservedUpperBound), new(Attribute)) 76 }) 77 t.Run("inside bounds", func(t *testing.T) { 78 testserdes.EncodeDecodeBinary(t, getReservedAttribute(ReservedLowerBound+5), new(Attribute)) 79 }) 80 t.Run("not reserved", func(t *testing.T) { 81 _, err := testserdes.EncodeBinary(getReservedAttribute(ReservedLowerBound - 1)) 82 require.Error(t, err) 83 }) 84 }) 85 t.Run("Conflicts", func(t *testing.T) { 86 t.Run("positive", func(t *testing.T) { 87 attr := &Attribute{ 88 Type: ConflictsT, 89 Value: &Conflicts{ 90 Hash: random.Uint256(), 91 }, 92 } 93 testserdes.EncodeDecodeBinary(t, attr, new(Attribute)) 94 }) 95 t.Run("negative: bad uint256", func(t *testing.T) { 96 bw := io.NewBufBinWriter() 97 bw.WriteBytes(make([]byte, util.Uint256Size-1)) 98 require.Error(t, testserdes.DecodeBinary(bw.Bytes(), new(Conflicts))) 99 }) 100 }) 101 t.Run("NotaryAssisted", func(t *testing.T) { 102 t.Run("positive", func(t *testing.T) { 103 attr := &Attribute{ 104 Type: NotaryAssistedT, 105 Value: &NotaryAssisted{ 106 NKeys: 3, 107 }, 108 } 109 testserdes.EncodeDecodeBinary(t, attr, new(Attribute)) 110 }) 111 t.Run("bad format: too short", func(t *testing.T) { 112 bw := io.NewBufBinWriter() 113 bw.WriteBytes([]byte{}) 114 require.Error(t, testserdes.DecodeBinary(bw.Bytes(), new(NotaryAssisted))) 115 }) 116 }) 117 } 118 119 func TestAttribute_MarshalJSON(t *testing.T) { 120 t.Run("HighPriority", func(t *testing.T) { 121 attr := &Attribute{Type: HighPriority} 122 data, err := json.Marshal(attr) 123 require.NoError(t, err) 124 require.JSONEq(t, `{"type":"HighPriority"}`, string(data)) 125 126 actual := new(Attribute) 127 require.NoError(t, json.Unmarshal(data, actual)) 128 require.Equal(t, attr, actual) 129 }) 130 t.Run("OracleResponse", func(t *testing.T) { 131 res := []byte{1, 2, 3} 132 attr := &Attribute{ 133 Type: OracleResponseT, 134 Value: &OracleResponse{ 135 ID: 123, 136 Code: Success, 137 Result: res, 138 }, 139 } 140 data, err := json.Marshal(attr) 141 require.NoError(t, err) 142 require.JSONEq(t, `{ 143 "type":"OracleResponse", 144 "id": 123, 145 "code": "Success", 146 "result": "`+base64.StdEncoding.EncodeToString(res)+`"}`, string(data)) 147 148 actual := new(Attribute) 149 require.NoError(t, json.Unmarshal(data, actual)) 150 require.Equal(t, attr, actual) 151 testserdes.EncodeDecodeBinary(t, attr, new(Attribute)) 152 }) 153 t.Run("NotValidBefore", func(t *testing.T) { 154 attr := &Attribute{ 155 Type: NotValidBeforeT, 156 Value: &NotValidBefore{ 157 Height: 123, 158 }, 159 } 160 testserdes.MarshalUnmarshalJSON(t, attr, new(Attribute)) 161 }) 162 t.Run("Conflicts", func(t *testing.T) { 163 attr := &Attribute{ 164 Type: ConflictsT, 165 Value: &Conflicts{ 166 Hash: random.Uint256(), 167 }, 168 } 169 testserdes.MarshalUnmarshalJSON(t, attr, new(Attribute)) 170 }) 171 t.Run("NotaryAssisted", func(t *testing.T) { 172 attr := &Attribute{ 173 Type: NotaryAssistedT, 174 Value: &NotaryAssisted{ 175 NKeys: 3, 176 }, 177 } 178 testserdes.MarshalUnmarshalJSON(t, attr, new(Attribute)) 179 }) 180 } 181 182 func TestAttribute_Copy(t *testing.T) { 183 originals := []*Attribute{ 184 {Type: HighPriority}, 185 {Type: OracleResponseT, Value: &OracleResponse{ID: 123, Code: Success, Result: []byte{1, 2, 3}}}, 186 {Type: NotValidBeforeT, Value: &NotValidBefore{Height: 123}}, 187 {Type: ConflictsT, Value: &Conflicts{Hash: random.Uint256()}}, 188 {Type: NotaryAssistedT, Value: &NotaryAssisted{NKeys: 3}}, 189 {Type: ReservedLowerBound, Value: &Reserved{Value: []byte{1, 2, 3, 4, 5}}}, 190 {Type: ReservedUpperBound, Value: &Reserved{Value: []byte{1, 2, 3, 4, 5}}}, 191 {Type: ReservedLowerBound + 5, Value: &Reserved{Value: []byte{1, 2, 3, 4, 5}}}, 192 } 193 require.Nil(t, (*Attribute)(nil).Copy()) 194 195 for _, original := range originals { 196 cp := original.Copy() 197 require.NotNil(t, cp) 198 assert.Equal(t, original.Type, cp.Type) 199 assert.Equal(t, original.Value, cp.Value) 200 if original.Value != nil { 201 originalValueCopy := original.Value.Copy() 202 switch originalVal := originalValueCopy.(type) { 203 case *OracleResponse: 204 originalVal.Result = append(originalVal.Result, 0xFF) 205 assert.NotEqual(t, len(original.Value.(*OracleResponse).Result), len(originalVal.Result)) 206 case *Conflicts: 207 originalVal.Hash = random.Uint256() 208 assert.NotEqual(t, original.Value.(*Conflicts).Hash, originalVal.Hash) 209 case *NotaryAssisted: 210 originalVal.NKeys++ 211 assert.NotEqual(t, original.Value.(*NotaryAssisted).NKeys, originalVal.NKeys) 212 } 213 assert.Equal(t, cp.Value, original.Value) 214 } 215 } 216 }