Source file src/internal/reflectlite/reflect_mirror_test.go

     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  	"uncommonType",
    23  	"arrayType",
    24  	"chanType",
    25  	"funcType",
    26  	"interfaceType",
    27  	"mapType",
    28  	"ptrType",
    29  	"sliceType",
    30  	"structType",
    31  }
    32  
    33  type visitor struct {
    34  	m map[string]map[string]bool
    35  }
    36  
    37  func newVisitor() visitor {
    38  	v := visitor{}
    39  	v.m = make(map[string]map[string]bool)
    40  
    41  	return v
    42  }
    43  func (v visitor) filter(name string) bool {
    44  	for _, typeName := range typeNames {
    45  		if typeName == name {
    46  			return true
    47  		}
    48  	}
    49  	return false
    50  }
    51  
    52  func (v visitor) Visit(n ast.Node) ast.Visitor {
    53  	switch x := n.(type) {
    54  	case *ast.TypeSpec:
    55  		if v.filter(x.Name.String()) {
    56  			if st, ok := x.Type.(*ast.StructType); ok {
    57  				v.m[x.Name.String()] = make(map[string]bool)
    58  				for _, field := range st.Fields.List {
    59  					k := fmt.Sprintf("%s", field.Type)
    60  					if len(field.Names) > 0 {
    61  						k = field.Names[0].Name
    62  					}
    63  					v.m[x.Name.String()][k] = true
    64  				}
    65  			}
    66  		}
    67  	}
    68  	return v
    69  }
    70  
    71  func loadTypes(path, pkgName string, v visitor) {
    72  	fset := token.NewFileSet()
    73  
    74  	filter := func(fi fs.FileInfo) bool {
    75  		return strings.HasSuffix(fi.Name(), ".go")
    76  	}
    77  	pkgs, err := parser.ParseDir(fset, path, filter, 0)
    78  	if err != nil {
    79  		panic(err)
    80  	}
    81  
    82  	pkg := pkgs[pkgName]
    83  
    84  	for _, f := range pkg.Files {
    85  		ast.Walk(v, f)
    86  	}
    87  }
    88  
    89  func TestMirrorWithReflect(t *testing.T) {
    90  	// TODO when the dust clears, figure out what this should actually test.
    91  	t.Skipf("reflect and reflectlite are out of sync for now")
    92  	reflectDir := filepath.Join(runtime.GOROOT(), "src", "reflect")
    93  	if _, err := os.Stat(reflectDir); os.IsNotExist(err) {
    94  		// On some mobile builders, the test binary executes on a machine without a
    95  		// complete GOROOT source tree.
    96  		t.Skipf("GOROOT source not present")
    97  	}
    98  
    99  	var wg sync.WaitGroup
   100  	rl, r := newVisitor(), newVisitor()
   101  
   102  	for _, tc := range []struct {
   103  		path, pkg string
   104  		v         visitor
   105  	}{
   106  		{".", "reflectlite", rl},
   107  		{reflectDir, "reflect", r},
   108  	} {
   109  		tc := tc
   110  		wg.Add(1)
   111  		go func() {
   112  			defer wg.Done()
   113  			loadTypes(tc.path, tc.pkg, tc.v)
   114  		}()
   115  	}
   116  	wg.Wait()
   117  
   118  	if len(rl.m) != len(r.m) {
   119  		t.Fatalf("number of types mismatch, reflect: %d, reflectlite: %d (%+v, %+v)", len(r.m), len(rl.m), r.m, rl.m)
   120  	}
   121  
   122  	for typName := range r.m {
   123  		if len(r.m[typName]) != len(rl.m[typName]) {
   124  			t.Errorf("type %s number of fields mismatch, reflect: %d, reflectlite: %d", typName, len(r.m[typName]), len(rl.m[typName]))
   125  			continue
   126  		}
   127  		for field := range r.m[typName] {
   128  			if _, ok := rl.m[typName][field]; !ok {
   129  				t.Errorf(`Field mismatch, reflect have "%s", relectlite does not.`, field)
   130  			}
   131  		}
   132  	}
   133  }
   134  

View as plain text