Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
internal/reflectlite: add type mirror with reflect test
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
Showing
1 changed file
with
120 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
} | ||
} | ||
} | ||
} |