blob: 9b28b13550e0c779c284a80fcec9e8d89f3f32a8 [file] [log] [blame]
// 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"
"io/fs"
"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 fs.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)
}
}
}
}