Rebase.
[official-gcc.git] / libgo / go / go / parser / parser_test.go
blob2797ea518bd0e23c23aaf021444d242286da6865
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.
5 package parser
7 import (
8 "bytes"
9 "fmt"
10 "go/ast"
11 "go/token"
12 "os"
13 "strings"
14 "testing"
17 var fset = token.NewFileSet()
19 var validFiles = []string{
20 "parser.go",
21 "parser_test.go",
22 "error_test.go",
23 "short_test.go",
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)
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
42 return false
45 func dirFilter(f os.FileInfo) bool { return nameFilter(f.Name()) }
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)
53 if n := len(pkgs); n != 1 {
54 t.Errorf("got %d packages; want 1", n)
56 pkg := pkgs["parser"]
57 if pkg == nil {
58 t.Errorf(`package "parser" not found`)
59 return
61 if n := len(pkg.Files); n != 3 {
62 t.Errorf("got %d package files; want 3", n)
64 for filename := range pkg.Files {
65 if !nameFilter(filename) {
66 t.Errorf("unexpected package file: %s", filename)
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)
79 // sanity check
80 if _, ok := x.(*ast.BinaryExpr); !ok {
81 t.Errorf("ParseExpr(%s): got %T, want *ast.BinaryExpr", src, x)
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)
90 // sanity check
91 if _, ok := x.(*ast.StructType); !ok {
92 t.Errorf("ParseExpr(%s): got %T, want *ast.StructType", src, x)
95 // an invalid expression
96 src = "a + *"
97 _, err = ParseExpr(src)
98 if err == nil {
99 t.Fatalf("ParseExpr(%s): got no error", src)
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)
109 // ParseExpr must not crash
110 for _, src := range valids {
111 ParseExpr(src)
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)
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)
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)
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)
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)
151 for _, id := range as.Names {
152 if id.Obj == nil {
153 t.Errorf("lhs %s does not have Obj, should", id.Name)
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: }
168 f, err := ParseFile(fset, "", src, 0)
169 if err != nil {
170 t.Fatal(err)
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,
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)
191 return true
193 if obj.Name != ident.Name {
194 t.Errorf("names don't match: obj.Name = %s, ident.Name = %s", obj.Name, ident.Name)
196 kind := objects[ident.Name]
197 if obj.Kind != kind {
198 t.Errorf("%s: obj.Kind = %s; want %s", ident.Name, obj.Kind, kind)
201 return true
205 func TestUnresolved(t *testing.T) {
206 f, err := ParseFile(fset, "", `
207 package p
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)
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)
221 type s1a struct { int }
222 type s2a struct { byte; int; s1a }
223 type s3a struct { a, b int; c float }
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)
233 want := "int " + // f1a
234 "byte int float " + // f2a
235 "int float " + // f3a
236 "complex " + // f4a
237 "complex " + // f5a
239 "int " + // f1b
240 "byte int float " + // f2b
241 "int float " + // f3b
242 "complex " + // f4b
243 "complex " + // f5b
245 "int " + // s1a
246 "byte int " + // s2a
247 "int float " + // s3a
249 "int " + // s1a
250 "byte int float " + // s2a
251 "float " // s3a
253 // collect unresolved identifiers
254 var buf bytes.Buffer
255 for _, u := range f.Unresolved {
256 buf.WriteString(u.Name)
257 buf.WriteByte(' ')
259 got := buf.String()
261 if got != want {
262 t.Errorf("\ngot: %s\nwant: %s", got, want)
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,
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,
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)
311 func TestCommentGroups(t *testing.T) {
312 f, err := ParseFile(fset, "", `
313 package p /* 1a */ /* 1b */ /* 1c */ // 1d
314 /* 2a
316 // 2b
317 const pi = 3.1415
318 /* 3a */ // 3b
319 /* 3c */ const e = 2.7182
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
329 `, ParseComments)
330 if err != nil {
331 t.Fatal(err)
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"},
341 if len(f.Comments) != len(expected) {
342 t.Fatalf("got %d comment groups; expected %d", len(f.Comments), len(expected))
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
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)
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
378 return nil
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)
389 return buf.String()
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)
397 if got := commentText(f.Doc); got != lead {
398 t.Errorf("got lead comment %q; expected %q", got, lead)
400 if got := commentText(f.Comment); got != line {
401 t.Errorf("got line comment %q; expected %q", got, line)
405 func TestLeadAndLineComments(t *testing.T) {
406 f, err := ParseFile(fset, "", `
407 package p
408 type T struct {
409 /* F1 lead comment */
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
418 `, ParseComments)
419 if err != nil {
420 t.Fatal(err)
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")