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 }