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

View as plain text