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.
17 var validFiles
= []string{
24 func TestParse(t
*testing
.T
) {
25 for _
, filename
:= range validFiles
{
26 _
, err
:= ParseFile(token
.NewFileSet(), filename
, nil, DeclarationErrors
)
28 t
.Fatalf("ParseFile(%s): %v", filename
, err
)
33 func nameFilter(filename
string) bool {
35 case "parser.go", "interface.go", "parser_test.go":
37 case "parser.go.orig":
38 return true // permit but should be ignored by ParseDir
43 func dirFilter(f os
.FileInfo
) bool { return nameFilter(f
.Name()) }
45 func TestParseDir(t
*testing
.T
) {
47 pkgs
, err
:= ParseDir(token
.NewFileSet(), path
, dirFilter
, 0)
49 t
.Fatalf("ParseDir(%s): %v", path
, err
)
51 if n
:= len(pkgs
); n
!= 1 {
52 t
.Errorf("got %d packages; want 1", n
)
56 t
.Errorf(`package "parser" not found`)
59 if n
:= len(pkg
.Files
); n
!= 3 {
60 t
.Errorf("got %d package files; want 3", n
)
62 for filename
:= range pkg
.Files
{
63 if !nameFilter(filename
) {
64 t
.Errorf("unexpected package file: %s", filename
)
69 func TestParseExpr(t
*testing
.T
) {
70 // just kicking the tires:
71 // a valid arithmetic expression
73 x
, err
:= ParseExpr(src
)
75 t
.Errorf("ParseExpr(%q): %v", src
, err
)
78 if _
, ok
:= x
.(*ast
.BinaryExpr
); !ok
{
79 t
.Errorf("ParseExpr(%q): got %T, want *ast.BinaryExpr", src
, x
)
82 // a valid type expression
83 src
= "struct{x *int}"
84 x
, err
= ParseExpr(src
)
86 t
.Errorf("ParseExpr(%q): %v", src
, err
)
89 if _
, ok
:= x
.(*ast
.StructType
); !ok
{
90 t
.Errorf("ParseExpr(%q): got %T, want *ast.StructType", src
, x
)
93 // an invalid expression
95 if _
, err
:= ParseExpr(src
); err
== nil {
96 t
.Errorf("ParseExpr(%q): got no error", src
)
99 // a valid expression followed by extra tokens is invalid
101 if _
, err
:= ParseExpr(src
); err
== nil {
102 t
.Errorf("ParseExpr(%q): got no error", src
)
105 // a semicolon is not permitted unless automatically inserted
107 if _
, err
:= ParseExpr(src
); err
!= nil {
108 t
.Errorf("ParseExpr(%q): got error %s", src
, err
)
111 if _
, err
:= ParseExpr(src
); err
== nil {
112 t
.Errorf("ParseExpr(%q): got no error", src
)
115 // various other stuff following a valid expression
116 const validExpr
= "a + b"
117 const anything
= "dh3*#D)#_"
118 for _
, c
:= range "!)]};," {
119 src
:= validExpr
+ string(c
) + anything
120 if _
, err
:= ParseExpr(src
); err
== nil {
121 t
.Errorf("ParseExpr(%q): got no error", src
)
125 // ParseExpr must not crash
126 for _
, src
:= range valids
{
131 func TestColonEqualsScope(t
*testing
.T
) {
132 f
, err
:= ParseFile(token
.NewFileSet(), "", `package p; func f() { x, y, z := x, y, z }`, 0)
137 // RHS refers to undefined globals; LHS does not.
138 as
:= f
.Decls
[0].(*ast
.FuncDecl
).Body
.List
[0].(*ast
.AssignStmt
)
139 for _
, v
:= range as
.Rhs
{
142 t
.Errorf("rhs %s has Obj, should not", id
.Name
)
145 for _
, v
:= range as
.Lhs
{
148 t
.Errorf("lhs %s does not have Obj, should", id
.Name
)
153 func TestVarScope(t
*testing
.T
) {
154 f
, err
:= ParseFile(token
.NewFileSet(), "", `package p; func f() { var x, y, z = x, y, z }`, 0)
159 // RHS refers to undefined globals; LHS does not.
160 as
:= f
.Decls
[0].(*ast
.FuncDecl
).Body
.List
[0].(*ast
.DeclStmt
).Decl
.(*ast
.GenDecl
).Specs
[0].(*ast
.ValueSpec
)
161 for _
, v
:= range as
.Values
{
164 t
.Errorf("rhs %s has Obj, should not", id
.Name
)
167 for _
, id
:= range as
.Names
{
169 t
.Errorf("lhs %s does not have Obj, should", id
.Name
)
174 func TestObjects(t
*testing
.T
) {
184 f
, err
:= ParseFile(token
.NewFileSet(), "", src
, 0)
189 objects
:= map[string]ast
.ObjKind
{
190 "p": ast
.Bad
, // not in a scope
191 "fmt": ast
.Bad
, // not resolved yet
195 "int": ast
.Bad
, // not resolved yet
200 ast
.Inspect(f
, func(n ast
.Node
) bool {
201 if ident
, ok
:= n
.(*ast
.Ident
); ok
{
204 if objects
[ident
.Name
] != ast
.Bad
{
205 t
.Errorf("no object for %s", ident
.Name
)
209 if obj
.Name
!= ident
.Name
{
210 t
.Errorf("names don't match: obj.Name = %s, ident.Name = %s", obj
.Name
, ident
.Name
)
212 kind
:= objects
[ident
.Name
]
213 if obj
.Kind
!= kind
{
214 t
.Errorf("%s: obj.Kind = %s; want %s", ident
.Name
, obj
.Kind
, kind
)
221 func TestUnresolved(t
*testing
.T
) {
222 f
, err
:= ParseFile(token
.NewFileSet(), "", `
226 func f2a(byte, int, float)
227 func f3a(a, b int, c float)
229 func f5a(a s1a, b ...complex)
232 func f2b([]byte, (int), *float)
233 func f3b(a, b *int, c []float)
234 func f4b(...*complex)
235 func f5b(a s1a, b ...[]complex)
237 type s1a struct { int }
238 type s2a struct { byte; int; s1a }
239 type s3a struct { a, b int; c float }
241 type s1b struct { *int }
242 type s2b struct { byte; int; *float }
243 type s3b struct { a, b *s3b; c []float }
249 want
:= "int " + // f1a
250 "byte int float " + // f2a
251 "int float " + // f3a
256 "byte int float " + // f2b
257 "int float " + // f3b
263 "int float " + // s3a
266 "byte int float " + // s2a
269 // collect unresolved identifiers
271 for _
, u
:= range f
.Unresolved
{
272 buf
.WriteString(u
.Name
)
278 t
.Errorf("\ngot: %s\nwant: %s", got
, want
)
282 var imports
= map[string]bool{
288 `"greek/αβ"`: true,
291 // Each of these pairs tests both `` vs "" strings
292 // and also use of invalid characters spelled out as
293 // escape sequences and written directly.
294 // For example `"\x00"` tests import "\x00"
295 // while "`\x00`" tests import `<actual-NUL-byte>`.
314 func TestImports(t
*testing
.T
) {
315 for path
, isValid
:= range imports
{
316 src
:= fmt
.Sprintf("package p; import %s", path
)
317 _
, err
:= ParseFile(token
.NewFileSet(), "", src
, 0)
319 case err
!= nil && isValid
:
320 t
.Errorf("ParseFile(%s): got %v; expected no error", src
, err
)
321 case err
== nil && !isValid
:
322 t
.Errorf("ParseFile(%s): got no error; expected one", src
)
327 func TestCommentGroups(t
*testing
.T
) {
328 f
, err
:= ParseFile(token
.NewFileSet(), "", `
329 package p /* 1a */ /* 1b */ /* 1c */ // 1d
335 /* 3c */ const e = 2.7182
337 // Example from issue 3139
338 func ExampleCount() {
339 fmt.Println(strings.Count("cheese", "e"))
340 fmt.Println(strings.Count("five", "")) // before & after each rune
349 expected
:= [][]string{
350 {"/* 1a */", "/* 1b */", "/* 1c */", "// 1d"},
351 {"/* 2a\n*/", "// 2b"},
352 {"/* 3a */", "// 3b", "/* 3c */"},
353 {"// Example from issue 3139"},
354 {"// before & after each rune"},
355 {"// Output:", "// 3", "// 5"},
357 if len(f
.Comments
) != len(expected
) {
358 t
.Fatalf("got %d comment groups; expected %d", len(f
.Comments
), len(expected
))
360 for i
, exp
:= range expected
{
361 got
:= f
.Comments
[i
].List
362 if len(got
) != len(exp
) {
363 t
.Errorf("got %d comments in group %d; expected %d", len(got
), i
, len(exp
))
366 for j
, exp
:= range exp
{
369 t
.Errorf("got %q in group %d; expected %q", got
, i
, exp
)
375 func getField(file
*ast
.File
, fieldname
string) *ast
.Field
{
376 parts
:= strings
.Split(fieldname
, ".")
377 for _
, d
:= range file
.Decls
{
378 if d
, ok
:= d
.(*ast
.GenDecl
); ok
&& d
.Tok
== token
.TYPE
{
379 for _
, s
:= range d
.Specs
{
380 if s
, ok
:= s
.(*ast
.TypeSpec
); ok
&& s
.Name
.Name
== parts
[0] {
381 if s
, ok
:= s
.Type
.(*ast
.StructType
); ok
{
382 for _
, f
:= range s
.Fields
.List
{
383 for _
, name
:= range f
.Names
{
384 if name
.Name
== parts
[1] {
397 // Don't use ast.CommentGroup.Text() - we want to see exact comment text.
398 func commentText(c
*ast
.CommentGroup
) string {
401 for _
, c
:= range c
.List
{
402 buf
.WriteString(c
.Text
)
408 func checkFieldComments(t
*testing
.T
, file
*ast
.File
, fieldname
, lead
, line
string) {
409 f
:= getField(file
, fieldname
)
411 t
.Fatalf("field not found: %s", fieldname
)
413 if got
:= commentText(f
.Doc
); got
!= lead
{
414 t
.Errorf("got lead comment %q; expected %q", got
, lead
)
416 if got
:= commentText(f
.Comment
); got
!= line
{
417 t
.Errorf("got line comment %q; expected %q", got
, line
)
421 func TestLeadAndLineComments(t
*testing
.T
) {
422 f
, err
:= ParseFile(token
.NewFileSet(), "", `
425 /* F1 lead comment */
427 F1 int /* F1 */ // line comment
430 F2 int // F2 line comment
432 f3 int // f3 line comment
438 checkFieldComments(t
, f
, "T.F1", "/* F1 lead comment *///", "/* F1 */// line comment")
439 checkFieldComments(t
, f
, "T.F2", "// F2 lead// comment", "// F2 line comment")
440 checkFieldComments(t
, f
, "T.f3", "// f3 lead comment", "// f3 line comment")
442 checkFieldComments(t
, f
, "T.F1", "/* F1 lead comment *///", "/* F1 */// line comment")
443 checkFieldComments(t
, f
, "T.F2", "// F2 lead// comment", "// F2 line comment")
444 if getField(f
, "T.f3") != nil {
445 t
.Error("not expected to find T.f3")
449 // TestIssue9979 verifies that empty statements are contained within their enclosing blocks.
450 func TestIssue9979(t
*testing
.T
) {
451 for _
, src
:= range []string{
452 "package p; func f() {;}",
453 "package p; func f() {L:}",
454 "package p; func f() {L:;}",
455 "package p; func f() {L:\n}",
456 "package p; func f() {L:\n;}",
457 "package p; func f() { ; }",
458 "package p; func f() { L: }",
459 "package p; func f() { L: ; }",
460 "package p; func f() { L: \n}",
461 "package p; func f() { L: \n; }",
463 fset
:= token
.NewFileSet()
464 f
, err
:= ParseFile(fset
, "", src
, 0)
469 var pos
, end token
.Pos
470 ast
.Inspect(f
, func(x ast
.Node
) bool {
471 switch s
:= x
.(type) {
473 pos
, end
= s
.Pos()+1, s
.End()-1 // exclude "{", "}"
474 case *ast
.LabeledStmt
:
475 pos
, end
= s
.Pos()+2, s
.End() // exclude "L:"
478 if s
.Pos() < pos || s
.End() > end
{
479 t
.Errorf("%s: %T[%d, %d] not inside [%d, %d]", src
, s
, s
.Pos(), s
.End(), pos
, end
)
482 offs
:= fset
.Position(s
.Pos()).Offset
483 if ch
:= src
[offs
]; ch
!= ';' != s
.Implicit
{
486 want
= "but ';' is implicit"
488 t
.Errorf("%s: found %q at offset %d; %s", src
, ch
, offs
, want
)
496 // TestIncompleteSelection ensures that an incomplete selector
497 // expression is parsed as a (blank) *ast.SelectorExpr, not a
499 func TestIncompleteSelection(t
*testing
.T
) {
500 for _
, src
:= range []string{
501 "package p; var _ = fmt.", // at EOF
502 "package p; var _ = fmt.\ntype X int", // not at EOF
504 fset
:= token
.NewFileSet()
505 f
, err
:= ParseFile(fset
, "", src
, 0)
507 t
.Errorf("ParseFile(%s) succeeded unexpectedly", src
)
511 const wantErr
= "expected selector or type assertion"
512 if !strings
.Contains(err
.Error(), wantErr
) {
513 t
.Errorf("ParseFile returned wrong error %q, want %q", err
, wantErr
)
516 var sel
*ast
.SelectorExpr
517 ast
.Inspect(f
, func(n ast
.Node
) bool {
518 if n
, ok
:= n
.(*ast
.SelectorExpr
); ok
{
524 t
.Error("found no *ast.SelectorExpr")
527 const wantSel
= "&{fmt _}"
528 if fmt
.Sprint(sel
) != wantSel
{
529 t
.Errorf("found selector %s, want %s", sel
, wantSel
)
535 func TestLastLineComment(t
*testing
.T
) {
536 const src
= `package main
537 type x int // comment
539 fset
:= token
.NewFileSet()
540 f
, err
:= ParseFile(fset
, "", src
, ParseComments
)
544 comment
:= f
.Decls
[0].(*ast
.GenDecl
).Specs
[0].(*ast
.TypeSpec
).Comment
.List
[0].Text
545 if comment
!= "// comment" {
546 t
.Errorf("got %q, want %q", comment
, "// comment")