github.com/ava-labs/subnet-evm@v0.6.4/accounts/abi/reflect_test.go (about) 1 // (c) 2019-2020, Ava Labs, Inc. 2 // 3 // This file is a derived work, based on the go-ethereum library whose original 4 // notices appear below. 5 // 6 // It is distributed under a license compatible with the licensing terms of the 7 // original code from which it is derived. 8 // 9 // Much love to the original authors for their work. 10 // ********** 11 // Copyright 2019 The go-ethereum Authors 12 // This file is part of the go-ethereum library. 13 // 14 // The go-ethereum library is free software: you can redistribute it and/or modify 15 // it under the terms of the GNU Lesser General Public License as published by 16 // the Free Software Foundation, either version 3 of the License, or 17 // (at your option) any later version. 18 // 19 // The go-ethereum library is distributed in the hope that it will be useful, 20 // but WITHOUT ANY WARRANTY; without even the implied warranty of 21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 // GNU Lesser General Public License for more details. 23 // 24 // You should have received a copy of the GNU Lesser General Public License 25 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 26 27 package abi 28 29 import ( 30 "math/big" 31 "reflect" 32 "testing" 33 ) 34 35 type reflectTest struct { 36 name string 37 args []string 38 struc interface{} 39 want map[string]string 40 err string 41 } 42 43 var reflectTests = []reflectTest{ 44 { 45 name: "OneToOneCorrespondence", 46 args: []string{"fieldA"}, 47 struc: struct { 48 FieldA int `abi:"fieldA"` 49 }{}, 50 want: map[string]string{ 51 "fieldA": "FieldA", 52 }, 53 }, 54 { 55 name: "MissingFieldsInStruct", 56 args: []string{"fieldA", "fieldB"}, 57 struc: struct { 58 FieldA int `abi:"fieldA"` 59 }{}, 60 want: map[string]string{ 61 "fieldA": "FieldA", 62 }, 63 }, 64 { 65 name: "MoreFieldsInStructThanArgs", 66 args: []string{"fieldA"}, 67 struc: struct { 68 FieldA int `abi:"fieldA"` 69 FieldB int 70 }{}, 71 want: map[string]string{ 72 "fieldA": "FieldA", 73 }, 74 }, 75 { 76 name: "MissingFieldInArgs", 77 args: []string{"fieldA"}, 78 struc: struct { 79 FieldA int `abi:"fieldA"` 80 FieldB int `abi:"fieldB"` 81 }{}, 82 err: "struct: abi tag 'fieldB' defined but not found in abi", 83 }, 84 { 85 name: "NoAbiDescriptor", 86 args: []string{"fieldA"}, 87 struc: struct { 88 FieldA int 89 }{}, 90 want: map[string]string{ 91 "fieldA": "FieldA", 92 }, 93 }, 94 { 95 name: "NoArgs", 96 args: []string{}, 97 struc: struct { 98 FieldA int `abi:"fieldA"` 99 }{}, 100 err: "struct: abi tag 'fieldA' defined but not found in abi", 101 }, 102 { 103 name: "DifferentName", 104 args: []string{"fieldB"}, 105 struc: struct { 106 FieldA int `abi:"fieldB"` 107 }{}, 108 want: map[string]string{ 109 "fieldB": "FieldA", 110 }, 111 }, 112 { 113 name: "DifferentName", 114 args: []string{"fieldB"}, 115 struc: struct { 116 FieldA int `abi:"fieldB"` 117 }{}, 118 want: map[string]string{ 119 "fieldB": "FieldA", 120 }, 121 }, 122 { 123 name: "MultipleFields", 124 args: []string{"fieldA", "fieldB"}, 125 struc: struct { 126 FieldA int `abi:"fieldA"` 127 FieldB int `abi:"fieldB"` 128 }{}, 129 want: map[string]string{ 130 "fieldA": "FieldA", 131 "fieldB": "FieldB", 132 }, 133 }, 134 { 135 name: "MultipleFieldsABIMissing", 136 args: []string{"fieldA", "fieldB"}, 137 struc: struct { 138 FieldA int `abi:"fieldA"` 139 FieldB int 140 }{}, 141 want: map[string]string{ 142 "fieldA": "FieldA", 143 "fieldB": "FieldB", 144 }, 145 }, 146 { 147 name: "NameConflict", 148 args: []string{"fieldB"}, 149 struc: struct { 150 FieldA int `abi:"fieldB"` 151 FieldB int 152 }{}, 153 err: "abi: multiple variables maps to the same abi field 'fieldB'", 154 }, 155 { 156 name: "Underscored", 157 args: []string{"_"}, 158 struc: struct { 159 FieldA int 160 }{}, 161 err: "abi: purely underscored output cannot unpack to struct", 162 }, 163 { 164 name: "DoubleMapping", 165 args: []string{"fieldB", "fieldC", "fieldA"}, 166 struc: struct { 167 FieldA int `abi:"fieldC"` 168 FieldB int 169 }{}, 170 err: "abi: multiple outputs mapping to the same struct field 'FieldA'", 171 }, 172 { 173 name: "AlreadyMapped", 174 args: []string{"fieldB", "fieldB"}, 175 struc: struct { 176 FieldB int `abi:"fieldB"` 177 }{}, 178 err: "struct: abi tag in 'FieldB' already mapped", 179 }, 180 } 181 182 func TestReflectNameToStruct(t *testing.T) { 183 for _, test := range reflectTests { 184 t.Run(test.name, func(t *testing.T) { 185 m, err := mapArgNamesToStructFields(test.args, reflect.ValueOf(test.struc)) 186 if len(test.err) > 0 { 187 if err == nil || err.Error() != test.err { 188 t.Fatalf("Invalid error: expected %v, got %v", test.err, err) 189 } 190 } else { 191 if err != nil { 192 t.Fatalf("Unexpected error: %v", err) 193 } 194 for fname := range test.want { 195 if m[fname] != test.want[fname] { 196 t.Fatalf("Incorrect value for field %s: expected %v, got %v", fname, test.want[fname], m[fname]) 197 } 198 } 199 } 200 }) 201 } 202 } 203 204 func TestConvertType(t *testing.T) { 205 // Test Basic Struct 206 type T struct { 207 X *big.Int 208 Y *big.Int 209 } 210 // Create on-the-fly structure 211 var fields []reflect.StructField 212 fields = append(fields, reflect.StructField{ 213 Name: "X", 214 Type: reflect.TypeOf(new(big.Int)), 215 Tag: "json:\"" + "x" + "\"", 216 }) 217 fields = append(fields, reflect.StructField{ 218 Name: "Y", 219 Type: reflect.TypeOf(new(big.Int)), 220 Tag: "json:\"" + "y" + "\"", 221 }) 222 val := reflect.New(reflect.StructOf(fields)) 223 val.Elem().Field(0).Set(reflect.ValueOf(big.NewInt(1))) 224 val.Elem().Field(1).Set(reflect.ValueOf(big.NewInt(2))) 225 // ConvertType 226 out := *ConvertType(val.Interface(), new(T)).(*T) 227 if out.X.Cmp(big.NewInt(1)) != 0 { 228 t.Errorf("ConvertType failed, got %v want %v", out.X, big.NewInt(1)) 229 } 230 if out.Y.Cmp(big.NewInt(2)) != 0 { 231 t.Errorf("ConvertType failed, got %v want %v", out.Y, big.NewInt(2)) 232 } 233 // Slice Type 234 val2 := reflect.MakeSlice(reflect.SliceOf(reflect.StructOf(fields)), 2, 2) 235 val2.Index(0).Field(0).Set(reflect.ValueOf(big.NewInt(1))) 236 val2.Index(0).Field(1).Set(reflect.ValueOf(big.NewInt(2))) 237 val2.Index(1).Field(0).Set(reflect.ValueOf(big.NewInt(3))) 238 val2.Index(1).Field(1).Set(reflect.ValueOf(big.NewInt(4))) 239 out2 := *ConvertType(val2.Interface(), new([]T)).(*[]T) 240 if out2[0].X.Cmp(big.NewInt(1)) != 0 { 241 t.Errorf("ConvertType failed, got %v want %v", out2[0].X, big.NewInt(1)) 242 } 243 if out2[0].Y.Cmp(big.NewInt(2)) != 0 { 244 t.Errorf("ConvertType failed, got %v want %v", out2[1].Y, big.NewInt(2)) 245 } 246 if out2[1].X.Cmp(big.NewInt(3)) != 0 { 247 t.Errorf("ConvertType failed, got %v want %v", out2[0].X, big.NewInt(1)) 248 } 249 if out2[1].Y.Cmp(big.NewInt(4)) != 0 { 250 t.Errorf("ConvertType failed, got %v want %v", out2[1].Y, big.NewInt(2)) 251 } 252 // Array Type 253 val3 := reflect.New(reflect.ArrayOf(2, reflect.StructOf(fields))) 254 val3.Elem().Index(0).Field(0).Set(reflect.ValueOf(big.NewInt(1))) 255 val3.Elem().Index(0).Field(1).Set(reflect.ValueOf(big.NewInt(2))) 256 val3.Elem().Index(1).Field(0).Set(reflect.ValueOf(big.NewInt(3))) 257 val3.Elem().Index(1).Field(1).Set(reflect.ValueOf(big.NewInt(4))) 258 out3 := *ConvertType(val3.Interface(), new([2]T)).(*[2]T) 259 if out3[0].X.Cmp(big.NewInt(1)) != 0 { 260 t.Errorf("ConvertType failed, got %v want %v", out3[0].X, big.NewInt(1)) 261 } 262 if out3[0].Y.Cmp(big.NewInt(2)) != 0 { 263 t.Errorf("ConvertType failed, got %v want %v", out3[1].Y, big.NewInt(2)) 264 } 265 if out3[1].X.Cmp(big.NewInt(3)) != 0 { 266 t.Errorf("ConvertType failed, got %v want %v", out3[0].X, big.NewInt(1)) 267 } 268 if out3[1].Y.Cmp(big.NewInt(4)) != 0 { 269 t.Errorf("ConvertType failed, got %v want %v", out3[1].Y, big.NewInt(2)) 270 } 271 }