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