github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/x/tools/go/gcimporter15/bexport_test.go (about)

     1  // Copyright 2016 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  // +build go1.6
     6  
     7  package gcimporter_test
     8  
     9  import (
    10  	"fmt"
    11  	"go/ast"
    12  	"go/build"
    13  	"go/constant"
    14  	"go/parser"
    15  	"go/token"
    16  	"go/types"
    17  	"reflect"
    18  	"runtime"
    19  	"strings"
    20  	"testing"
    21  
    22  	"github.com/insionng/yougam/libraries/x/tools/go/buildutil"
    23  	gcimporter "github.com/insionng/yougam/libraries/x/tools/go/gcimporter15"
    24  	"github.com/insionng/yougam/libraries/x/tools/go/loader"
    25  )
    26  
    27  func TestBExportData_stdlib(t *testing.T) {
    28  	if runtime.GOOS == "android" {
    29  		t.Skipf("incomplete std lib on %s", runtime.GOOS)
    30  	}
    31  
    32  	// Load, parse and type-check the program.
    33  	ctxt := build.Default // copy
    34  	ctxt.GOPATH = ""      // disable GOPATH
    35  	conf := loader.Config{
    36  		Build:       &ctxt,
    37  		AllowErrors: true,
    38  	}
    39  	for _, path := range buildutil.AllPackages(conf.Build) {
    40  		conf.Import(path)
    41  	}
    42  
    43  	// Create a package containing type and value errors to ensure
    44  	// they are properly encoded/decoded.
    45  	f, err := conf.ParseFile("haserrors/haserrors.go", `package haserrors
    46  const UnknownValue = "" + 0
    47  type UnknownType undefined
    48  `)
    49  	if err != nil {
    50  		t.Fatal(err)
    51  	}
    52  	conf.CreateFromFiles("haserrors", f)
    53  
    54  	prog, err := conf.Load()
    55  	if err != nil {
    56  		t.Fatalf("Load failed: %v", err)
    57  	}
    58  
    59  	numPkgs := len(prog.AllPackages)
    60  	if want := 248; numPkgs < want {
    61  		t.Errorf("Loaded only %d packages, want at least %d", numPkgs, want)
    62  	}
    63  
    64  	for pkg, info := range prog.AllPackages {
    65  		if info.Files == nil {
    66  			continue // empty directory
    67  		}
    68  		exportdata := gcimporter.BExportData(conf.Fset, pkg)
    69  
    70  		imports := make(map[string]*types.Package)
    71  		fset2 := token.NewFileSet()
    72  		n, pkg2, err := gcimporter.BImportData(fset2, imports, exportdata, pkg.Path())
    73  		if err != nil {
    74  			t.Errorf("BImportData(%s): %v", pkg.Path(), err)
    75  			continue
    76  		}
    77  		if n != len(exportdata) {
    78  			t.Errorf("BImportData(%s) decoded %d bytes, want %d",
    79  				pkg.Path(), n, len(exportdata))
    80  		}
    81  
    82  		// Compare the packages' corresponding members.
    83  		for _, name := range pkg.Scope().Names() {
    84  			if !ast.IsExported(name) {
    85  				continue
    86  			}
    87  			obj1 := pkg.Scope().Lookup(name)
    88  			obj2 := pkg2.Scope().Lookup(name)
    89  			if obj2 == nil {
    90  				t.Errorf("%s.%s not found, want %s", pkg.Path(), name, obj1)
    91  				continue
    92  			}
    93  
    94  			fl1 := fileLine(conf.Fset, obj1)
    95  			fl2 := fileLine(fset2, obj2)
    96  			if fl1 != fl2 {
    97  				t.Errorf("%s.%s: got posn %s, want %s",
    98  					pkg.Path(), name, fl2, fl1)
    99  			}
   100  
   101  			if err := equalObj(obj1, obj2); err != nil {
   102  				t.Errorf("%s.%s: %s\ngot:  %s\nwant: %s",
   103  					pkg.Path(), name, err, obj2, obj1)
   104  			}
   105  		}
   106  	}
   107  }
   108  
   109  func fileLine(fset *token.FileSet, obj types.Object) string {
   110  	posn := fset.Position(obj.Pos())
   111  	return fmt.Sprintf("%s:%d", posn.Filename, posn.Line)
   112  }
   113  
   114  // equalObj reports how x and y differ.  They are assumed to belong to
   115  // different universes so cannot be compared directly.
   116  func equalObj(x, y types.Object) error {
   117  	if reflect.TypeOf(x) != reflect.TypeOf(y) {
   118  		return fmt.Errorf("%T vs %T", x, y)
   119  	}
   120  	xt := x.Type()
   121  	yt := y.Type()
   122  	switch x.(type) {
   123  	case *types.Var, *types.Func:
   124  		// ok
   125  	case *types.Const:
   126  		xval := x.(*types.Const).Val()
   127  		yval := y.(*types.Const).Val()
   128  		// Use string comparison for floating-point values since rounding is permitted.
   129  		if constant.Compare(xval, token.NEQ, yval) &&
   130  			!(xval.Kind() == constant.Float && xval.String() == yval.String()) {
   131  			return fmt.Errorf("unequal constants %s vs %s", xval, yval)
   132  		}
   133  	case *types.TypeName:
   134  		xt = xt.Underlying()
   135  		yt = yt.Underlying()
   136  	default:
   137  		return fmt.Errorf("unexpected %T", x)
   138  	}
   139  	return equalType(xt, yt)
   140  }
   141  
   142  func equalType(x, y types.Type) error {
   143  	if reflect.TypeOf(x) != reflect.TypeOf(y) {
   144  		return fmt.Errorf("unequal kinds: %T vs %T", x, y)
   145  	}
   146  	switch x := x.(type) {
   147  	case *types.Interface:
   148  		y := y.(*types.Interface)
   149  		// TODO(gri): enable separate emission of Embedded interfaces
   150  		// and ExplicitMethods then use this logic.
   151  		// if x.NumEmbeddeds() != y.NumEmbeddeds() {
   152  		// 	return fmt.Errorf("unequal number of embedded interfaces: %d vs %d",
   153  		// 		x.NumEmbeddeds(), y.NumEmbeddeds())
   154  		// }
   155  		// for i := 0; i < x.NumEmbeddeds(); i++ {
   156  		// 	xi := x.Embedded(i)
   157  		// 	yi := y.Embedded(i)
   158  		// 	if xi.String() != yi.String() {
   159  		// 		return fmt.Errorf("mismatched %th embedded interface: %s vs %s",
   160  		// 			i, xi, yi)
   161  		// 	}
   162  		// }
   163  		// if x.NumExplicitMethods() != y.NumExplicitMethods() {
   164  		// 	return fmt.Errorf("unequal methods: %d vs %d",
   165  		// 		x.NumExplicitMethods(), y.NumExplicitMethods())
   166  		// }
   167  		// for i := 0; i < x.NumExplicitMethods(); i++ {
   168  		// 	xm := x.ExplicitMethod(i)
   169  		// 	ym := y.ExplicitMethod(i)
   170  		// 	if xm.Name() != ym.Name() {
   171  		// 		return fmt.Errorf("mismatched %th method: %s vs %s", i, xm, ym)
   172  		// 	}
   173  		// 	if err := equalType(xm.Type(), ym.Type()); err != nil {
   174  		// 		return fmt.Errorf("mismatched %s method: %s", xm.Name(), err)
   175  		// 	}
   176  		// }
   177  		if x.NumMethods() != y.NumMethods() {
   178  			return fmt.Errorf("unequal methods: %d vs %d",
   179  				x.NumMethods(), y.NumMethods())
   180  		}
   181  		for i := 0; i < x.NumMethods(); i++ {
   182  			xm := x.Method(i)
   183  			ym := y.Method(i)
   184  			if xm.Name() != ym.Name() {
   185  				return fmt.Errorf("mismatched %dth method: %s vs %s", i, xm, ym)
   186  			}
   187  			if err := equalType(xm.Type(), ym.Type()); err != nil {
   188  				return fmt.Errorf("mismatched %s method: %s", xm.Name(), err)
   189  			}
   190  		}
   191  	case *types.Array:
   192  		y := y.(*types.Array)
   193  		if x.Len() != y.Len() {
   194  			return fmt.Errorf("unequal array lengths: %d vs %d", x.Len(), y.Len())
   195  		}
   196  		if err := equalType(x.Elem(), y.Elem()); err != nil {
   197  			return fmt.Errorf("array elements: %s", err)
   198  		}
   199  	case *types.Basic:
   200  		y := y.(*types.Basic)
   201  		if x.Kind() != y.Kind() {
   202  			return fmt.Errorf("unequal basic types: %s vs %s", x, y)
   203  		}
   204  	case *types.Chan:
   205  		y := y.(*types.Chan)
   206  		if x.Dir() != y.Dir() {
   207  			return fmt.Errorf("unequal channel directions: %d vs %d", x.Dir(), y.Dir())
   208  		}
   209  		if err := equalType(x.Elem(), y.Elem()); err != nil {
   210  			return fmt.Errorf("channel elements: %s", err)
   211  		}
   212  	case *types.Map:
   213  		y := y.(*types.Map)
   214  		if err := equalType(x.Key(), y.Key()); err != nil {
   215  			return fmt.Errorf("map keys: %s", err)
   216  		}
   217  		if err := equalType(x.Elem(), y.Elem()); err != nil {
   218  			return fmt.Errorf("map values: %s", err)
   219  		}
   220  	case *types.Named:
   221  		y := y.(*types.Named)
   222  		if x.String() != y.String() {
   223  			return fmt.Errorf("unequal named types: %s vs %s", x, y)
   224  		}
   225  	case *types.Pointer:
   226  		y := y.(*types.Pointer)
   227  		if err := equalType(x.Elem(), y.Elem()); err != nil {
   228  			return fmt.Errorf("pointer elements: %s", err)
   229  		}
   230  	case *types.Signature:
   231  		y := y.(*types.Signature)
   232  		if err := equalType(x.Params(), y.Params()); err != nil {
   233  			return fmt.Errorf("parameters: %s", err)
   234  		}
   235  		if err := equalType(x.Results(), y.Results()); err != nil {
   236  			return fmt.Errorf("results: %s", err)
   237  		}
   238  		if x.Variadic() != y.Variadic() {
   239  			return fmt.Errorf("unequal varidicity: %t vs %t",
   240  				x.Variadic(), y.Variadic())
   241  		}
   242  		if (x.Recv() != nil) != (y.Recv() != nil) {
   243  			return fmt.Errorf("unequal receivers: %s vs %s", x.Recv(), y.Recv())
   244  		}
   245  		if x.Recv() != nil {
   246  			// TODO(adonovan): fix: this assertion fires for interface methods.
   247  			// The type of the receiver of an interface method is a named type
   248  			// if the Package was loaded from export data, or an unnamed (interface)
   249  			// type if the Package was produced by type-checking ASTs.
   250  			// if err := equalType(x.Recv().Type(), y.Recv().Type()); err != nil {
   251  			// 	return fmt.Errorf("receiver: %s", err)
   252  			// }
   253  		}
   254  	case *types.Slice:
   255  		y := y.(*types.Slice)
   256  		if err := equalType(x.Elem(), y.Elem()); err != nil {
   257  			return fmt.Errorf("slice elements: %s", err)
   258  		}
   259  	case *types.Struct:
   260  		y := y.(*types.Struct)
   261  		if x.NumFields() != y.NumFields() {
   262  			return fmt.Errorf("unequal struct fields: %d vs %d",
   263  				x.NumFields(), y.NumFields())
   264  		}
   265  		for i := 0; i < x.NumFields(); i++ {
   266  			xf := x.Field(i)
   267  			yf := y.Field(i)
   268  			if xf.Name() != yf.Name() {
   269  				return fmt.Errorf("mismatched fields: %s vs %s", xf, yf)
   270  			}
   271  			if err := equalType(xf.Type(), yf.Type()); err != nil {
   272  				return fmt.Errorf("struct field %s: %s", xf.Name(), err)
   273  			}
   274  			if x.Tag(i) != y.Tag(i) {
   275  				return fmt.Errorf("struct field %s has unequal tags: %q vs %q",
   276  					xf.Name(), x.Tag(i), y.Tag(i))
   277  			}
   278  		}
   279  	case *types.Tuple:
   280  		y := y.(*types.Tuple)
   281  		if x.Len() != y.Len() {
   282  			return fmt.Errorf("unequal tuple lengths: %d vs %d", x.Len(), y.Len())
   283  		}
   284  		for i := 0; i < x.Len(); i++ {
   285  			if err := equalType(x.At(i).Type(), y.At(i).Type()); err != nil {
   286  				return fmt.Errorf("tuple element %d: %s", i, err)
   287  			}
   288  		}
   289  	}
   290  	return nil
   291  }
   292  
   293  // TestVeryLongFile tests the position of an import object declared in
   294  // a very long input file.  Line numbers greater than maxlines are
   295  // reported as line 1, not garbage or token.NoPos.
   296  func TestVeryLongFile(t *testing.T) {
   297  	// parse and typecheck
   298  	longFile := "package foo" + strings.Repeat("\n", 123456) + "var X int"
   299  	fset1 := token.NewFileSet()
   300  	f, err := parser.ParseFile(fset1, "foo.go", longFile, 0)
   301  	if err != nil {
   302  		t.Fatal(err)
   303  	}
   304  	var conf types.Config
   305  	pkg, err := conf.Check("foo", fset1, []*ast.File{f}, nil)
   306  	if err != nil {
   307  		t.Fatal(err)
   308  	}
   309  
   310  	// export
   311  	exportdata := gcimporter.BExportData(fset1, pkg)
   312  
   313  	// import
   314  	imports := make(map[string]*types.Package)
   315  	fset2 := token.NewFileSet()
   316  	_, pkg2, err := gcimporter.BImportData(fset2, imports, exportdata, pkg.Path())
   317  	if err != nil {
   318  		t.Fatalf("BImportData(%s): %v", pkg.Path(), err)
   319  	}
   320  
   321  	// compare
   322  	posn1 := fset1.Position(pkg.Scope().Lookup("X").Pos())
   323  	posn2 := fset2.Position(pkg2.Scope().Lookup("X").Pos())
   324  	if want := "foo.go:1:1"; posn2.String() != want {
   325  		t.Errorf("X position = %s, want %s (orig was %s)",
   326  			posn2, want, posn1)
   327  	}
   328  }