github.com/influx6/npkg@v0.8.8/nreflect/reflection_test.go (about) 1 package nreflect_test 2 3 import ( 4 "errors" 5 "fmt" 6 "reflect" 7 "testing" 8 "time" 9 10 nreflect "github.com/influx6/npkg/nreflect" 11 ) 12 13 type bull string 14 15 type speaker interface { 16 Speak() string 17 } 18 19 // mosnter provides a basic struct test case type. 20 type monster struct { 21 Name string 22 Items []bull 23 } 24 25 // Speak returns the sound the monster makes. 26 func (m *monster) Speak() string { 27 return "Raaaaaaarggg!" 28 } 29 30 func get(t *testing.T, sm speaker) { 31 name, embedded, err := nreflect.ExternalTypeNames(sm) 32 if err != nil { 33 t.Fatalf("Should be able to retrieve field names arguments lists\n") 34 } 35 t.Logf("PageName: %s", name) 36 t.Logf("Fields: %+q", embedded) 37 t.Logf("Should be able to retrieve function arguments lists") 38 } 39 40 type Addrs struct { 41 Addr string 42 } 43 44 type addrFunc func(Addrs) error 45 46 var errorType = reflect.TypeOf((*error)(nil)).Elem() 47 48 func TestIsSettableType(t *testing.T) { 49 m2 := errors.New("invalid error") 50 if !nreflect.IsSettableType(errorType, reflect.TypeOf(m2)) { 51 t.Fatalf("Should have error matching type") 52 } 53 } 54 55 func TestIsSettable(t *testing.T) { 56 m2 := errors.New("invalid error") 57 if !nreflect.IsSettable(errorType, reflect.ValueOf(m2)) { 58 t.Fatalf("Should have error matching type") 59 } 60 61 m1 := mo("invalid error") 62 if !nreflect.IsSettable(errorType, reflect.ValueOf(m1)) { 63 t.Fatalf("Should have error matching type") 64 } 65 } 66 67 type mo string 68 69 func (m mo) Error() string { 70 return string(m) 71 } 72 73 func TestValidateFunc_Bad(t *testing.T) { 74 var testFunc = func(v string) string { 75 return "Hello " + v 76 } 77 78 err := nreflect.ValidateFunc(testFunc, []nreflect.TypeValidation{ 79 func(types []reflect.Type) error { 80 if len(types) == 1 { 81 return nil 82 } 83 return errors.New("bad") 84 }, 85 }, []nreflect.TypeValidation{ 86 func(types []reflect.Type) error { 87 if len(types) == 0 { 88 return nil 89 } 90 return errors.New("bad") 91 }, 92 }) 93 94 if err == nil { 95 t.Fatalf("Should have function invalid to conditions") 96 } 97 } 98 99 func TestValidateFunc(t *testing.T) { 100 var testFunc = func(v string) string { 101 return "Hello " + v 102 } 103 104 err := nreflect.ValidateFunc(testFunc, []nreflect.TypeValidation{ 105 func(types []reflect.Type) error { 106 if len(types) == 1 { 107 return nil 108 } 109 return errors.New("bad") 110 }, 111 }, []nreflect.TypeValidation{ 112 func(types []reflect.Type) error { 113 if len(types) == 1 { 114 return nil 115 } 116 return errors.New("bad") 117 }, 118 }) 119 120 if err != nil { 121 t.Fatalf("Should have function valid to conditions") 122 } 123 } 124 125 func TestFunctionApply_OneArgument(t *testing.T) { 126 var testFunc = func(v string) string { 127 return "Hello " + v 128 } 129 130 res, err := nreflect.CallFunc(testFunc, "Alex") 131 if err != nil { 132 t.Fatalf("Should have executed function") 133 } 134 t.Logf("Should have executed function") 135 136 if !reflect.DeepEqual(res, []interface{}{"Hello Alex"}) { 137 t.Logf("Received: %q", res) 138 t.Fatalf("Expected value unmatched") 139 } 140 } 141 142 func TestFunctionApply_ThreeArgumentWithError(t *testing.T) { 143 bad := errors.New("bad") 144 var testFunc = func(v string, i int, d bool) ([]interface{}, error) { 145 return []interface{}{v, i, d}, bad 146 } 147 148 res, err := nreflect.CallFunc(testFunc, "Alex", 1, false) 149 if err != nil { 150 t.Fatalf("Should have executed function") 151 } 152 t.Logf("Should have executed function") 153 154 if !reflect.DeepEqual(res, []interface{}{[]interface{}{"Alex", 1, false}, bad}) { 155 t.Logf("Expected: %q", []interface{}{[]interface{}{"Alex", 1, false}, bad}) 156 t.Logf("Received: %q", res) 157 t.Fatalf("Expected value unmatched") 158 } 159 } 160 161 func TestFunctionApply_ThreeArgumentWithVariadic(t *testing.T) { 162 var testFunc = func(v string, i int, d ...bool) []interface{} { 163 return []interface{}{v, i, d} 164 } 165 166 res, err := nreflect.CallFunc(testFunc, "Alex", 1, []bool{false}) 167 if err != nil { 168 t.Fatalf("Should have executed function") 169 } 170 t.Logf("Should have executed function") 171 172 if !reflect.DeepEqual(res, []interface{}{[]interface{}{"Alex", 1, []bool{false}}}) { 173 t.Logf("Expected: %q", []interface{}{[]interface{}{"Alex", 1, []bool{false}}}) 174 t.Logf("Received: %q", res) 175 t.Fatalf("Expected value unmatched") 176 } 177 } 178 179 func TestFunctionApply_ThreeArgument(t *testing.T) { 180 var testFunc = func(v string, i int, d bool) string { 181 return "Hello " + v 182 } 183 184 res, err := nreflect.CallFunc(testFunc, "Alex", 1, false) 185 if err != nil { 186 t.Fatalf("Should have executed function") 187 } 188 t.Logf("Should have executed function") 189 190 if !reflect.DeepEqual(res, []interface{}{"Hello Alex"}) { 191 t.Logf("Received: %q", res) 192 t.Fatalf("Expected value unmatched") 193 } 194 } 195 196 func TestMatchFunction(t *testing.T) { 197 var addr1 = func(_ Addrs) error { return nil } 198 var addr2 = func(_ Addrs) error { return nil } 199 200 if !nreflect.MatchFunction(addr1, addr2) { 201 t.Fatalf("Should have matched argument types successfully") 202 } 203 t.Logf("Should have matched argument types successfully") 204 205 if !nreflect.MatchFunction(&addr1, &addr2) { 206 t.Fatalf("Should have matched argument types successfully") 207 } 208 t.Logf("Should have matched argument types successfully") 209 210 if nreflect.MatchFunction(&addr1, addr2) { 211 t.Fatalf("Should have failed matched argument types successfully") 212 } 213 t.Logf("Should have failed matched argument types successfully") 214 } 215 216 func TestMatchElement(t *testing.T) { 217 if !nreflect.MatchElement(Addrs{}, Addrs{}, false) { 218 t.Fatalf("Should have matched argument types successfully") 219 } 220 t.Logf("Should have matched argument types successfully") 221 222 if !nreflect.MatchElement(new(Addrs), new(Addrs), false) { 223 t.Fatalf("Should have matched argument types successfully") 224 } 225 t.Logf("Should have matched argument types successfully") 226 227 if nreflect.MatchElement(new(Addrs), Addrs{}, false) { 228 t.Fatalf("Should have failed matched argument types successfully") 229 } 230 t.Logf("Should have failed matched argument types successfully") 231 } 232 233 func TestStructMapperWithSlice(t *testing.T) { 234 mapper := nreflect.NewStructMapper() 235 236 profile := struct { 237 List []Addrs 238 }{ 239 List: []Addrs{{Addr: "Tokura 20"}}, 240 } 241 242 mapped, err := mapper.MapFrom("json", profile) 243 if err != nil { 244 t.Fatalf("Should have successfully converted struct") 245 } 246 t.Logf("Should have successfully converted struct") 247 248 t.Logf("Map of Struct: %+q", mapped) 249 250 profile2 := struct { 251 List []Addrs 252 }{} 253 254 if err := mapper.MapTo("json", &profile2, mapped); err != nil { 255 t.Fatalf("Should have successfully mapped data back to struct") 256 } 257 t.Logf("Should have successfully mapped data back to struct") 258 259 if len(profile.List) != len(profile2.List) { 260 t.Fatalf("Mapped struct should have same length: %d - %d ", len(profile.List), len(profile2.List)) 261 } 262 t.Logf("Mapped struct should have same length: %d - %d ", len(profile.List), len(profile2.List)) 263 264 for ind, item := range profile.List { 265 nxItem := profile2.List[ind] 266 if item.Addr != nxItem.Addr { 267 t.Fatalf("Item at %d should have equal value %+q -> %+q", ind, item.Addr, nxItem.Addr) 268 } 269 } 270 271 t.Logf("All items should be exactly the same") 272 } 273 274 func TestStructMapperWthFieldStruct(t *testing.T) { 275 layout := "Mon Jan 2 2006 15:04:05 -0700 MST" 276 timeType := reflect.TypeOf((*time.Time)(nil)) 277 278 mapper := nreflect.NewStructMapper() 279 mapper.AddAdapter(timeType, nreflect.TimeMapper(layout)) 280 mapper.AddInverseAdapter(timeType, nreflect.TimeInverseMapper(layout)) 281 282 profile := struct { 283 Addr Addrs 284 Name string `json:"name"` 285 Date time.Time `json:"date"` 286 }{ 287 Addr: Addrs{Addr: "Tokura 20"}, 288 Name: "Johnson", 289 Date: time.Now(), 290 } 291 292 mapped, err := mapper.MapFrom("json", profile) 293 if err != nil { 294 t.Fatalf("Should have successfully converted struct") 295 } 296 t.Logf("Should have successfully converted struct") 297 298 t.Logf("Map of Struct: %+q", mapped) 299 300 profile2 := struct { 301 Addr Addrs 302 Name string `json:"name"` 303 Date time.Time `json:"date"` 304 }{} 305 306 if err := mapper.MapTo("json", &profile2, mapped); err != nil { 307 t.Fatalf("Should have successfully mapped data back to struct") 308 } 309 t.Logf("Should have successfully mapped data back to struct") 310 311 if profile2.Addr.Addr != profile.Addr.Addr { 312 t.Fatalf("Mapped struct should have same %q value", "Addr.Addr") 313 } 314 t.Logf("Mapped struct should have same %q value", "Addr.Addr") 315 } 316 317 func TestGetFieldByTagAndValue(t *testing.T) { 318 profile := struct { 319 Addrs 320 Name string `json:"name"` 321 Date time.Time `json:"date"` 322 }{ 323 Addrs: Addrs{Addr: "Tokura 20"}, 324 Name: "Johnson", 325 Date: time.Now(), 326 } 327 328 _, err := nreflect.GetFieldByTagAndValue(profile, "json", "name") 329 if err != nil { 330 t.Fatalf("Should have successfully converted struct") 331 } 332 } 333 334 func TestStructMapperWthEmbeddedStruct(t *testing.T) { 335 layout := "Mon Jan 2 2006 15:04:05 -0700 MST" 336 timeType := reflect.TypeOf((*time.Time)(nil)) 337 338 mapper := nreflect.NewStructMapper() 339 mapper.AddAdapter(timeType, nreflect.TimeMapper(layout)) 340 mapper.AddInverseAdapter(timeType, nreflect.TimeInverseMapper(layout)) 341 342 profile := struct { 343 Addrs 344 Name string `json:"name"` 345 Date time.Time `json:"date"` 346 }{ 347 Addrs: Addrs{Addr: "Tokura 20"}, 348 Name: "Johnson", 349 Date: time.Now(), 350 } 351 352 mapped, err := mapper.MapFrom("json", profile) 353 if err != nil { 354 t.Fatalf("Should have successfully converted struct") 355 } 356 t.Logf("Should have successfully converted struct") 357 358 t.Logf("Map of Struct: %+q", mapped) 359 360 profile2 := struct { 361 Addrs 362 Name string `json:"name"` 363 Date time.Time `json:"date"` 364 }{} 365 366 if err := mapper.MapTo("json", &profile2, mapped); err != nil { 367 t.Fatalf("Should have successfully mapped data back to struct") 368 } 369 t.Logf("Should have successfully mapped data back to struct") 370 371 if profile2.Addr != profile.Addr { 372 t.Fatalf("Mapped struct should have same %q value", "Addr.Addr") 373 } 374 t.Logf("Mapped struct should have same %q value", "Addr.Addr") 375 } 376 377 func TestStructMapper(t *testing.T) { 378 layout := "Mon Jan 2 2006 15:04:05 -0700 MST" 379 timeType := reflect.TypeOf((*time.Time)(nil)) 380 381 mapper := nreflect.NewStructMapper() 382 mapper.AddAdapter(timeType, nreflect.TimeMapper(layout)) 383 mapper.AddInverseAdapter(timeType, nreflect.TimeInverseMapper(layout)) 384 385 profile := struct { 386 Addr string 387 CountryName string 388 Name string `json:"name"` 389 Date time.Time `json:"date"` 390 }{ 391 Addr: "Tokura 20", 392 Name: "Johnson", 393 CountryName: "Nigeria", 394 Date: time.Now(), 395 } 396 397 mapped, err := mapper.MapFrom("json", profile) 398 if err != nil { 399 t.Fatalf("Should have successfully converted struct") 400 } 401 t.Logf("Should have successfully converted struct") 402 403 t.Logf("Map of Struct: %+q", mapped) 404 405 if _, ok := mapped["name"]; !ok { 406 t.Fatalf("Map should have %q field", "name") 407 } 408 t.Logf("Map should have %q field", "name") 409 410 if _, ok := mapped["date"]; !ok { 411 t.Fatalf("Map should have %q field", "date") 412 } 413 t.Logf("Map should have %q field", "date") 414 415 if _, ok := mapped["addr"]; !ok { 416 t.Fatalf("Map should have %q field", "addr") 417 } 418 t.Logf("Map should have %q field", "addr") 419 420 if _, ok := mapped["data"].(string); ok { 421 t.Fatalf("Map should have field %q be a string", "date") 422 } 423 t.Logf("Map should have field %q be a string", "date") 424 425 profile2 := struct { 426 Addr string 427 CountryName string 428 Name string `json:"name"` 429 Date time.Time `json:"date"` 430 }{} 431 432 if err := mapper.MapTo("json", &profile2, mapped); err != nil { 433 t.Fatalf("Should have successfully mapped data back to struct") 434 } 435 t.Logf("Should have successfully mapped data back to struct") 436 437 t.Logf("Mapped Struct: %+q", profile2) 438 439 if profile2.Name != profile.Name { 440 t.Fatalf("Mapped struct should have same %q value", "PageName") 441 } 442 t.Logf("Mapped struct should have same %q value", "PageName") 443 444 if profile2.Date.Format(layout) != profile.Date.Format(layout) { 445 t.Fatalf("Mapped struct should have same %q value", "Date") 446 } 447 t.Logf("Mapped struct should have same %q value", "Date") 448 449 if profile2.CountryName != profile.CountryName { 450 t.Fatalf("Mapped struct should have same %q value", "CountryName") 451 } 452 t.Logf("Mapped struct should have same %q value", "CountryName") 453 454 if profile2.Addr != profile.Addr { 455 t.Fatalf("Mapped struct should have same %q value", "Addr") 456 } 457 t.Logf("Mapped struct should have same %q value", "Addr") 458 } 459 460 // TestGetArgumentsType validates nreflect API GetArgumentsType functions 461 // results. 462 func TestGetArgumentsType(t *testing.T) { 463 f := func(m monster) string { 464 return fmt.Sprintf("Monster[%s] is ready!", m.Name) 465 } 466 467 args, err := nreflect.GetFuncArgumentsType(f) 468 if err != nil { 469 t.Fatalf("Should be able to retrieve function arguments lists") 470 } 471 t.Logf("Should be able to retrieve function arguments lists") 472 473 name, embedded, err := nreflect.ExternalTypeNames(monster{Name: "Bob"}) 474 if err != nil { 475 t.Fatalf("Should be able to retrieve field names arguments lists") 476 } 477 t.Logf("PageName: %s", name) 478 t.Logf("Fields: %+q", embedded) 479 t.Logf("Should be able to retrieve function arguments lists") 480 481 get(t, &monster{Name: "Bob"}) 482 483 newVals := nreflect.MakeArgumentsValues(args) 484 if nlen, alen := len(newVals), len(args); nlen != alen { 485 t.Fatalf("Should have matching new values lists for arguments") 486 } 487 t.Logf("Should have matching new values lists for arguments") 488 489 mstring := reflect.TypeOf((*monster)(nil)).Elem() 490 491 if mstring.Kind() != newVals[0].Kind() { 492 t.Fatalf("Should be able to match argument kind") 493 } 494 t.Logf("Should be able to match argument kind") 495 496 } 497 498 func TestMatchFUncArgumentTypeWithValues(t *testing.T) { 499 f := func(m monster) string { 500 return fmt.Sprintf("Monster[%s] is ready!", m.Name) 501 } 502 503 var vals []reflect.Value 504 vals = append(vals, reflect.ValueOf(monster{Name: "FireHouse"})) 505 506 if index := nreflect.MatchFuncArgumentTypeWithValues(f, vals); index != -1 { 507 t.Fatalf("Should have matching new values lists for arguments: %d", index) 508 } 509 t.Logf("Should have matching new values lists for arguments") 510 }