132 lines
2.6 KiB
Go
132 lines
2.6 KiB
Go
// Copyright 2019 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package reflectlite_test
|
|
|
|
import (
|
|
"fmt"
|
|
"go/ast"
|
|
"go/parser"
|
|
"go/token"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
"sync"
|
|
"testing"
|
|
)
|
|
|
|
var typeNames = []string{
|
|
"rtype",
|
|
"uncommonType",
|
|
"arrayType",
|
|
"chanType",
|
|
"funcType",
|
|
"interfaceType",
|
|
"mapType",
|
|
"ptrType",
|
|
"sliceType",
|
|
"structType",
|
|
}
|
|
|
|
type visitor struct {
|
|
m map[string]map[string]bool
|
|
}
|
|
|
|
func newVisitor() visitor {
|
|
v := visitor{}
|
|
v.m = make(map[string]map[string]bool)
|
|
|
|
return v
|
|
}
|
|
func (v visitor) filter(name string) bool {
|
|
for _, typeName := range typeNames {
|
|
if typeName == name {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (v visitor) Visit(n ast.Node) ast.Visitor {
|
|
switch x := n.(type) {
|
|
case *ast.TypeSpec:
|
|
if v.filter(x.Name.String()) {
|
|
if st, ok := x.Type.(*ast.StructType); ok {
|
|
v.m[x.Name.String()] = make(map[string]bool)
|
|
for _, field := range st.Fields.List {
|
|
k := fmt.Sprintf("%s", field.Type)
|
|
if len(field.Names) > 0 {
|
|
k = field.Names[0].Name
|
|
}
|
|
v.m[x.Name.String()][k] = true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return v
|
|
}
|
|
|
|
func loadTypes(path, pkgName string, v visitor) {
|
|
fset := token.NewFileSet()
|
|
|
|
filter := func(fi os.FileInfo) bool {
|
|
return strings.HasSuffix(fi.Name(), ".go")
|
|
}
|
|
pkgs, err := parser.ParseDir(fset, path, filter, 0)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
pkg := pkgs[pkgName]
|
|
|
|
for _, f := range pkg.Files {
|
|
ast.Walk(v, f)
|
|
}
|
|
}
|
|
|
|
func TestMirrorWithReflect(t *testing.T) {
|
|
reflectDir := filepath.Join(runtime.GOROOT(), "src", "reflect")
|
|
if _, err := os.Stat(reflectDir); os.IsNotExist(err) {
|
|
// On some mobile builders, the test binary executes on a machine without a
|
|
// complete GOROOT source tree.
|
|
t.Skipf("GOROOT source not present")
|
|
}
|
|
|
|
var wg sync.WaitGroup
|
|
rl, r := newVisitor(), newVisitor()
|
|
|
|
for _, tc := range []struct {
|
|
path, pkg string
|
|
v visitor
|
|
}{
|
|
{".", "reflectlite", rl},
|
|
{reflectDir, "reflect", r},
|
|
} {
|
|
tc := tc
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
loadTypes(tc.path, tc.pkg, tc.v)
|
|
}()
|
|
}
|
|
wg.Wait()
|
|
|
|
if len(rl.m) != len(r.m) {
|
|
t.Fatalf("number of types mismatch, reflect: %d, reflectlite: %d", len(r.m), len(rl.m))
|
|
}
|
|
|
|
for typName := range r.m {
|
|
if len(r.m[typName]) != len(rl.m[typName]) {
|
|
t.Errorf("type %s number of fields mismatch, reflect: %d, reflectlite: %d", typName, len(r.m[typName]), len(rl.m[typName]))
|
|
continue
|
|
}
|
|
for field := range r.m[typName] {
|
|
if _, ok := rl.m[typName][field]; !ok {
|
|
t.Errorf(`Field mismatch, reflect have "%s", relectlite does not.`, field)
|
|
}
|
|
}
|
|
}
|
|
}
|