Skip to content

Commit

Permalink
internal/reflectlite: add type mirror with reflect test
Browse files Browse the repository at this point in the history
Add test to check that struct type in reflectlite is mirror of reflect.
Note that the test does not check the field types, only check for number
of fields and field name are the same.

Updates #34486

Change-Id: Id5f9b26d35faec97863dd1fe7e5eab37d4913181
Reviewed-on: https://go-review.googlesource.com/c/go/+/199280
Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
  • Loading branch information
cuonglm authored and mvdan committed Oct 7, 2019
1 parent c7d81bc commit 8b39106
Showing 1 changed file with 120 additions and 0 deletions.
120 changes: 120 additions & 0 deletions src/internal/reflectlite/reflect_mirror_test.go
@@ -0,0 +1,120 @@
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) {
var wg sync.WaitGroup
rl, r := newVisitor(), newVisitor()

for _, tc := range []struct {
path, pkg string
v visitor
}{
{".", "reflectlite", rl},
{filepath.Join(runtime.GOROOT(), "src", "reflect"), "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)
}
}
}
}

0 comments on commit 8b39106

Please sign in to comment.