github.com/ader1990/go@v0.0.0-20140630135419-8c24447fa791/src/pkg/go/parser/parser_test.go (about) 1 // Copyright 2009 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 parser 6 7 import ( 8 "bytes" 9 "fmt" 10 "go/ast" 11 "go/token" 12 "os" 13 "strings" 14 "testing" 15 ) 16 17 var fset = token.NewFileSet() 18 19 var validFiles = []string{ 20 "parser.go", 21 "parser_test.go", 22 "error_test.go", 23 "short_test.go", 24 } 25 26 func TestParse(t *testing.T) { 27 for _, filename := range validFiles { 28 _, err := ParseFile(fset, filename, nil, DeclarationErrors) 29 if err != nil { 30 t.Fatalf("ParseFile(%s): %v", filename, err) 31 } 32 } 33 } 34 35 func nameFilter(filename string) bool { 36 switch filename { 37 case "parser.go", "interface.go", "parser_test.go": 38 return true 39 case "parser.go.orig": 40 return true // permit but should be ignored by ParseDir 41 } 42 return false 43 } 44 45 func dirFilter(f os.FileInfo) bool { return nameFilter(f.Name()) } 46 47 func TestParseDir(t *testing.T) { 48 path := "." 49 pkgs, err := ParseDir(fset, path, dirFilter, 0) 50 if err != nil { 51 t.Fatalf("ParseDir(%s): %v", path, err) 52 } 53 if n := len(pkgs); n != 1 { 54 t.Errorf("got %d packages; want 1", n) 55 } 56 pkg := pkgs["parser"] 57 if pkg == nil { 58 t.Errorf(`package "parser" not found`) 59 return 60 } 61 if n := len(pkg.Files); n != 3 { 62 t.Errorf("got %d package files; want 3", n) 63 } 64 for filename := range pkg.Files { 65 if !nameFilter(filename) { 66 t.Errorf("unexpected package file: %s", filename) 67 } 68 } 69 } 70 71 func TestParseExpr(t *testing.T) { 72 // just kicking the tires: 73 // a valid arithmetic expression 74 src := "a + b" 75 x, err := ParseExpr(src) 76 if err != nil { 77 t.Fatalf("ParseExpr(%s): %v", src, err) 78 } 79 // sanity check 80 if _, ok := x.(*ast.BinaryExpr); !ok { 81 t.Errorf("ParseExpr(%s): got %T, want *ast.BinaryExpr", src, x) 82 } 83 84 // a valid type expression 85 src = "struct{x *int}" 86 x, err = ParseExpr(src) 87 if err != nil { 88 t.Fatalf("ParseExpr(%s): %v", src, err) 89 } 90 // sanity check 91 if _, ok := x.(*ast.StructType); !ok { 92 t.Errorf("ParseExpr(%s): got %T, want *ast.StructType", src, x) 93 } 94 95 // an invalid expression 96 src = "a + *" 97 _, err = ParseExpr(src) 98 if err == nil { 99 t.Fatalf("ParseExpr(%s): got no error", src) 100 } 101 102 // a valid expression followed by extra tokens is invalid 103 src = "a[i] := x" 104 _, err = ParseExpr(src) 105 if err == nil { 106 t.Fatalf("ParseExpr(%s): got no error", src) 107 } 108 109 // ParseExpr must not crash 110 for _, src := range valids { 111 ParseExpr(src) 112 } 113 } 114 115 func TestColonEqualsScope(t *testing.T) { 116 f, err := ParseFile(fset, "", `package p; func f() { x, y, z := x, y, z }`, 0) 117 if err != nil { 118 t.Fatal(err) 119 } 120 121 // RHS refers to undefined globals; LHS does not. 122 as := f.Decls[0].(*ast.FuncDecl).Body.List[0].(*ast.AssignStmt) 123 for _, v := range as.Rhs { 124 id := v.(*ast.Ident) 125 if id.Obj != nil { 126 t.Errorf("rhs %s has Obj, should not", id.Name) 127 } 128 } 129 for _, v := range as.Lhs { 130 id := v.(*ast.Ident) 131 if id.Obj == nil { 132 t.Errorf("lhs %s does not have Obj, should", id.Name) 133 } 134 } 135 } 136 137 func TestVarScope(t *testing.T) { 138 f, err := ParseFile(fset, "", `package p; func f() { var x, y, z = x, y, z }`, 0) 139 if err != nil { 140 t.Fatal(err) 141 } 142 143 // RHS refers to undefined globals; LHS does not. 144 as := f.Decls[0].(*ast.FuncDecl).Body.List[0].(*ast.DeclStmt).Decl.(*ast.GenDecl).Specs[0].(*ast.ValueSpec) 145 for _, v := range as.Values { 146 id := v.(*ast.Ident) 147 if id.Obj != nil { 148 t.Errorf("rhs %s has Obj, should not", id.Name) 149 } 150 } 151 for _, id := range as.Names { 152 if id.Obj == nil { 153 t.Errorf("lhs %s does not have Obj, should", id.Name) 154 } 155 } 156 } 157 158 func TestObjects(t *testing.T) { 159 const src = ` 160 package p 161 import fmt "fmt" 162 const pi = 3.14 163 type T struct{} 164 var x int 165 func f() { L: } 166 ` 167 168 f, err := ParseFile(fset, "", src, 0) 169 if err != nil { 170 t.Fatal(err) 171 } 172 173 objects := map[string]ast.ObjKind{ 174 "p": ast.Bad, // not in a scope 175 "fmt": ast.Bad, // not resolved yet 176 "pi": ast.Con, 177 "T": ast.Typ, 178 "x": ast.Var, 179 "int": ast.Bad, // not resolved yet 180 "f": ast.Fun, 181 "L": ast.Lbl, 182 } 183 184 ast.Inspect(f, func(n ast.Node) bool { 185 if ident, ok := n.(*ast.Ident); ok { 186 obj := ident.Obj 187 if obj == nil { 188 if objects[ident.Name] != ast.Bad { 189 t.Errorf("no object for %s", ident.Name) 190 } 191 return true 192 } 193 if obj.Name != ident.Name { 194 t.Errorf("names don't match: obj.Name = %s, ident.Name = %s", obj.Name, ident.Name) 195 } 196 kind := objects[ident.Name] 197 if obj.Kind != kind { 198 t.Errorf("%s: obj.Kind = %s; want %s", ident.Name, obj.Kind, kind) 199 } 200 } 201 return true 202 }) 203 } 204 205 func TestUnresolved(t *testing.T) { 206 f, err := ParseFile(fset, "", ` 207 package p 208 // 209 func f1a(int) 210 func f2a(byte, int, float) 211 func f3a(a, b int, c float) 212 func f4a(...complex) 213 func f5a(a s1a, b ...complex) 214 // 215 func f1b(*int) 216 func f2b([]byte, (int), *float) 217 func f3b(a, b *int, c []float) 218 func f4b(...*complex) 219 func f5b(a s1a, b ...[]complex) 220 // 221 type s1a struct { int } 222 type s2a struct { byte; int; s1a } 223 type s3a struct { a, b int; c float } 224 // 225 type s1b struct { *int } 226 type s2b struct { byte; int; *float } 227 type s3b struct { a, b *s3b; c []float } 228 `, 0) 229 if err != nil { 230 t.Fatal(err) 231 } 232 233 want := "int " + // f1a 234 "byte int float " + // f2a 235 "int float " + // f3a 236 "complex " + // f4a 237 "complex " + // f5a 238 // 239 "int " + // f1b 240 "byte int float " + // f2b 241 "int float " + // f3b 242 "complex " + // f4b 243 "complex " + // f5b 244 // 245 "int " + // s1a 246 "byte int " + // s2a 247 "int float " + // s3a 248 // 249 "int " + // s1a 250 "byte int float " + // s2a 251 "float " // s3a 252 253 // collect unresolved identifiers 254 var buf bytes.Buffer 255 for _, u := range f.Unresolved { 256 buf.WriteString(u.Name) 257 buf.WriteByte(' ') 258 } 259 got := buf.String() 260 261 if got != want { 262 t.Errorf("\ngot: %s\nwant: %s", got, want) 263 } 264 } 265 266 var imports = map[string]bool{ 267 `"a"`: true, 268 "`a`": true, 269 `"a/b"`: true, 270 `"a.b"`: true, 271 `"m\x61th"`: true, 272 `"greek/αβ"`: true, 273 `""`: false, 274 275 // Each of these pairs tests both `` vs "" strings 276 // and also use of invalid characters spelled out as 277 // escape sequences and written directly. 278 // For example `"\x00"` tests import "\x00" 279 // while "`\x00`" tests import `<actual-NUL-byte>`. 280 `"\x00"`: false, 281 "`\x00`": false, 282 `"\x7f"`: false, 283 "`\x7f`": false, 284 `"a!"`: false, 285 "`a!`": false, 286 `"a b"`: false, 287 "`a b`": false, 288 `"a\\b"`: false, 289 "`a\\b`": false, 290 "\"`a`\"": false, 291 "`\"a\"`": false, 292 `"\x80\x80"`: false, 293 "`\x80\x80`": false, 294 `"\xFFFD"`: false, 295 "`\xFFFD`": false, 296 } 297 298 func TestImports(t *testing.T) { 299 for path, isValid := range imports { 300 src := fmt.Sprintf("package p; import %s", path) 301 _, err := ParseFile(fset, "", src, 0) 302 switch { 303 case err != nil && isValid: 304 t.Errorf("ParseFile(%s): got %v; expected no error", src, err) 305 case err == nil && !isValid: 306 t.Errorf("ParseFile(%s): got no error; expected one", src) 307 } 308 } 309 } 310 311 func TestCommentGroups(t *testing.T) { 312 f, err := ParseFile(fset, "", ` 313 package p /* 1a */ /* 1b */ /* 1c */ // 1d 314 /* 2a 315 */ 316 // 2b 317 const pi = 3.1415 318 /* 3a */ // 3b 319 /* 3c */ const e = 2.7182 320 321 // Example from issue 3139 322 func ExampleCount() { 323 fmt.Println(strings.Count("cheese", "e")) 324 fmt.Println(strings.Count("five", "")) // before & after each rune 325 // Output: 326 // 3 327 // 5 328 } 329 `, ParseComments) 330 if err != nil { 331 t.Fatal(err) 332 } 333 expected := [][]string{ 334 {"/* 1a */", "/* 1b */", "/* 1c */", "// 1d"}, 335 {"/* 2a\n*/", "// 2b"}, 336 {"/* 3a */", "// 3b", "/* 3c */"}, 337 {"// Example from issue 3139"}, 338 {"// before & after each rune"}, 339 {"// Output:", "// 3", "// 5"}, 340 } 341 if len(f.Comments) != len(expected) { 342 t.Fatalf("got %d comment groups; expected %d", len(f.Comments), len(expected)) 343 } 344 for i, exp := range expected { 345 got := f.Comments[i].List 346 if len(got) != len(exp) { 347 t.Errorf("got %d comments in group %d; expected %d", len(got), i, len(exp)) 348 continue 349 } 350 for j, exp := range exp { 351 got := got[j].Text 352 if got != exp { 353 t.Errorf("got %q in group %d; expected %q", got, i, exp) 354 } 355 } 356 } 357 } 358 359 func getField(file *ast.File, fieldname string) *ast.Field { 360 parts := strings.Split(fieldname, ".") 361 for _, d := range file.Decls { 362 if d, ok := d.(*ast.GenDecl); ok && d.Tok == token.TYPE { 363 for _, s := range d.Specs { 364 if s, ok := s.(*ast.TypeSpec); ok && s.Name.Name == parts[0] { 365 if s, ok := s.Type.(*ast.StructType); ok { 366 for _, f := range s.Fields.List { 367 for _, name := range f.Names { 368 if name.Name == parts[1] { 369 return f 370 } 371 } 372 } 373 } 374 } 375 } 376 } 377 } 378 return nil 379 } 380 381 // Don't use ast.CommentGroup.Text() - we want to see exact comment text. 382 func commentText(c *ast.CommentGroup) string { 383 var buf bytes.Buffer 384 if c != nil { 385 for _, c := range c.List { 386 buf.WriteString(c.Text) 387 } 388 } 389 return buf.String() 390 } 391 392 func checkFieldComments(t *testing.T, file *ast.File, fieldname, lead, line string) { 393 f := getField(file, fieldname) 394 if f == nil { 395 t.Fatalf("field not found: %s", fieldname) 396 } 397 if got := commentText(f.Doc); got != lead { 398 t.Errorf("got lead comment %q; expected %q", got, lead) 399 } 400 if got := commentText(f.Comment); got != line { 401 t.Errorf("got line comment %q; expected %q", got, line) 402 } 403 } 404 405 func TestLeadAndLineComments(t *testing.T) { 406 f, err := ParseFile(fset, "", ` 407 package p 408 type T struct { 409 /* F1 lead comment */ 410 // 411 F1 int /* F1 */ // line comment 412 // F2 lead 413 // comment 414 F2 int // F2 line comment 415 // f3 lead comment 416 f3 int // f3 line comment 417 } 418 `, ParseComments) 419 if err != nil { 420 t.Fatal(err) 421 } 422 checkFieldComments(t, f, "T.F1", "/* F1 lead comment *///", "/* F1 */// line comment") 423 checkFieldComments(t, f, "T.F2", "// F2 lead// comment", "// F2 line comment") 424 checkFieldComments(t, f, "T.f3", "// f3 lead comment", "// f3 line comment") 425 ast.FileExports(f) 426 checkFieldComments(t, f, "T.F1", "/* F1 lead comment *///", "/* F1 */// line comment") 427 checkFieldComments(t, f, "T.F2", "// F2 lead// comment", "// F2 line comment") 428 if getField(f, "T.f3") != nil { 429 t.Error("not expected to find T.f3") 430 } 431 }