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

View as plain text