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