1// Copyright 2019 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package reflectlite_test 6 7import ( 8 "fmt" 9 "go/ast" 10 "go/parser" 11 "go/token" 12 "io/fs" 13 "os" 14 "path/filepath" 15 "runtime" 16 "strings" 17 "sync" 18 "testing" 19) 20 21var typeNames = []string{ 22 "uncommonType", 23 "arrayType", 24 "chanType", 25 "funcType", 26 "interfaceType", 27 "ptrType", 28 "sliceType", 29 "structType", 30} 31 32type visitor struct { 33 m map[string]map[string]bool 34} 35 36func newVisitor() visitor { 37 v := visitor{} 38 v.m = make(map[string]map[string]bool) 39 40 return v 41} 42func (v visitor) filter(name string) bool { 43 for _, typeName := range typeNames { 44 if typeName == name { 45 return true 46 } 47 } 48 return false 49} 50 51func (v visitor) Visit(n ast.Node) ast.Visitor { 52 switch x := n.(type) { 53 case *ast.TypeSpec: 54 if v.filter(x.Name.String()) { 55 if st, ok := x.Type.(*ast.StructType); ok { 56 v.m[x.Name.String()] = make(map[string]bool) 57 for _, field := range st.Fields.List { 58 k := fmt.Sprintf("%s", field.Type) 59 if len(field.Names) > 0 { 60 k = field.Names[0].Name 61 } 62 v.m[x.Name.String()][k] = true 63 } 64 } 65 } 66 } 67 return v 68} 69 70func loadTypes(path, pkgName string, v visitor) { 71 fset := token.NewFileSet() 72 73 filter := func(fi fs.FileInfo) bool { 74 return strings.HasSuffix(fi.Name(), ".go") 75 } 76 pkgs, err := parser.ParseDir(fset, path, filter, 0) 77 if err != nil { 78 panic(err) 79 } 80 81 pkg := pkgs[pkgName] 82 83 for _, f := range pkg.Files { 84 ast.Walk(v, f) 85 } 86} 87 88func TestMirrorWithReflect(t *testing.T) { 89 // TODO when the dust clears, figure out what this should actually test. 90 t.Skipf("reflect and reflectlite are out of sync for now") 91 reflectDir := filepath.Join(runtime.GOROOT(), "src", "reflect") 92 if _, err := os.Stat(reflectDir); os.IsNotExist(err) { 93 // On some mobile builders, the test binary executes on a machine without a 94 // complete GOROOT source tree. 95 t.Skipf("GOROOT source not present") 96 } 97 98 var wg sync.WaitGroup 99 rl, r := newVisitor(), newVisitor() 100 101 for _, tc := range []struct { 102 path, pkg string 103 v visitor 104 }{ 105 {".", "reflectlite", rl}, 106 {reflectDir, "reflect", r}, 107 } { 108 tc := tc 109 wg.Add(1) 110 go func() { 111 defer wg.Done() 112 loadTypes(tc.path, tc.pkg, tc.v) 113 }() 114 } 115 wg.Wait() 116 117 if len(rl.m) != len(r.m) { 118 t.Fatalf("number of types mismatch, reflect: %d, reflectlite: %d (%+v, %+v)", len(r.m), len(rl.m), r.m, rl.m) 119 } 120 121 for typName := range r.m { 122 if len(r.m[typName]) != len(rl.m[typName]) { 123 t.Errorf("type %s number of fields mismatch, reflect: %d, reflectlite: %d", typName, len(r.m[typName]), len(rl.m[typName])) 124 continue 125 } 126 for field := range r.m[typName] { 127 if _, ok := rl.m[typName][field]; !ok { 128 t.Errorf(`Field mismatch, reflect have "%s", relectlite does not.`, field) 129 } 130 } 131 } 132} 133