github.com/SandwichDev/go-internals@v0.0.0-20210605002614-12311ac6b2c5/reflectlite/reflect_mirror_test.go (about) 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 5 package reflectlite_test 6 7 import ( 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 21 var typeNames = []string{ 22 "rtype", 23 "uncommonType", 24 "arrayType", 25 "chanType", 26 "funcType", 27 "interfaceType", 28 "mapType", 29 "ptrType", 30 "sliceType", 31 "structType", 32 } 33 34 type visitor struct { 35 m map[string]map[string]bool 36 } 37 38 func newVisitor() visitor { 39 v := visitor{} 40 v.m = make(map[string]map[string]bool) 41 42 return v 43 } 44 func (v visitor) filter(name string) bool { 45 for _, typeName := range typeNames { 46 if typeName == name { 47 return true 48 } 49 } 50 return false 51 } 52 53 func (v visitor) Visit(n ast.Node) ast.Visitor { 54 switch x := n.(type) { 55 case *ast.TypeSpec: 56 if v.filter(x.Name.String()) { 57 if st, ok := x.Type.(*ast.StructType); ok { 58 v.m[x.Name.String()] = make(map[string]bool) 59 for _, field := range st.Fields.List { 60 k := fmt.Sprintf("%s", field.Type) 61 if len(field.Names) > 0 { 62 k = field.Names[0].Name 63 } 64 v.m[x.Name.String()][k] = true 65 } 66 } 67 } 68 } 69 return v 70 } 71 72 func loadTypes(path, pkgName string, v visitor) { 73 fset := token.NewFileSet() 74 75 filter := func(fi fs.FileInfo) bool { 76 return strings.HasSuffix(fi.Name(), ".go") 77 } 78 pkgs, err := parser.ParseDir(fset, path, filter, 0) 79 if err != nil { 80 panic(err) 81 } 82 83 pkg := pkgs[pkgName] 84 85 for _, f := range pkg.Files { 86 ast.Walk(v, f) 87 } 88 } 89 90 func TestMirrorWithReflect(t *testing.T) { 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", len(r.m), len(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 }