aboutsummaryrefslogtreecommitdiff
path: root/src/go/types/check_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/go/types/check_test.go')
-rw-r--r--src/go/types/check_test.go106
1 files changed, 72 insertions, 34 deletions
diff --git a/src/go/types/check_test.go b/src/go/types/check_test.go
index 51eae052f3..9812b3808b 100644
--- a/src/go/types/check_test.go
+++ b/src/go/types/check_test.go
@@ -44,10 +44,15 @@ import (
. "go/types"
)
+// parseTypeParams tells go/parser to parse type parameters. Must be kept in
+// sync with go/parser/interface.go.
+const parseTypeParams parser.Mode = 1 << 30
+
var (
haltOnError = flag.Bool("halt", false, "halt on error")
listErrors = flag.Bool("errlist", false, "list errors")
- testFiles = flag.String("files", "", "space-separated list of test files")
+ testFiles = flag.String("files", "", "comma-separated list of test files")
+ goVersion = flag.String("lang", "", "Go language version (e.g. \"go1.12\"")
)
var fset = token.NewFileSet()
@@ -68,11 +73,11 @@ func splitError(err error) (pos, msg string) {
return
}
-func parseFiles(t *testing.T, filenames []string, mode parser.Mode) ([]*ast.File, []error) {
+func parseFiles(t *testing.T, filenames []string, srcs [][]byte, mode parser.Mode) ([]*ast.File, []error) {
var files []*ast.File
var errlist []error
- for _, filename := range filenames {
- file, err := parser.ParseFile(fset, filename, nil, mode)
+ for i, filename := range filenames {
+ file, err := parser.ParseFile(fset, filename, srcs[i], mode)
if file == nil {
t.Fatalf("%s: %s", filename, err)
}
@@ -101,19 +106,17 @@ var errRx = regexp.MustCompile(`^ *ERROR *(HERE)? *"?([^"]*)"?`)
// errMap collects the regular expressions of ERROR comments found
// in files and returns them as a map of error positions to error messages.
//
-func errMap(t *testing.T, testname string, files []*ast.File) map[string][]string {
+// srcs must be a slice of the same length as files, containing the original
+// source for the parsed AST.
+func errMap(t *testing.T, files []*ast.File, srcs [][]byte) map[string][]string {
// map of position strings to lists of error message patterns
errmap := make(map[string][]string)
- for _, file := range files {
- filename := fset.Position(file.Package).Filename
- src, err := os.ReadFile(filename)
- if err != nil {
- t.Fatalf("%s: could not read %s", testname, filename)
- }
-
+ for i, file := range files {
+ tok := fset.File(file.Package)
+ src := srcs[i]
var s scanner.Scanner
- s.Init(fset.AddFile(filename, -1, len(src)), src, nil, scanner.ScanComments)
+ s.Init(tok, src, nil, scanner.ScanComments)
var prev token.Pos // position of last non-comment, non-semicolon token
var here token.Pos // position immediately after the token at position prev
@@ -190,24 +193,43 @@ func eliminate(t *testing.T, errmap map[string][]string, errlist []error) {
}
}
-func checkFiles(t *testing.T, sources []string) {
- if len(sources) == 0 {
+// goVersionRx matches a Go version string using '_', e.g. "go1_12".
+var goVersionRx = regexp.MustCompile(`^go[1-9][0-9]*_(0|[1-9][0-9]*)$`)
+
+// asGoVersion returns a regular Go language version string
+// if s is a Go version string using '_' rather than '.' to
+// separate the major and minor version numbers (e.g. "go1_12").
+// Otherwise it returns the empty string.
+func asGoVersion(s string) string {
+ if goVersionRx.MatchString(s) {
+ return strings.Replace(s, "_", ".", 1)
+ }
+ return ""
+}
+
+func checkFiles(t *testing.T, goVersion string, filenames []string, srcs [][]byte) {
+ if len(filenames) == 0 {
t.Fatal("no source files")
}
mode := parser.AllErrors
- if strings.HasSuffix(sources[0], ".go2") {
- mode |= parser.ParseTypeParams
+ if strings.HasSuffix(filenames[0], ".go2") {
+ mode |= parseTypeParams
}
// parse files and collect parser errors
- files, errlist := parseFiles(t, sources, mode)
+ files, errlist := parseFiles(t, filenames, srcs, mode)
pkgName := "<no package>"
if len(files) > 0 {
pkgName = files[0].Name.Name
}
+ // if no Go version is given, consider the package name
+ if goVersion == "" {
+ goVersion = asGoVersion(pkgName)
+ }
+
if *listErrors && len(errlist) > 0 {
t.Errorf("--- %s:", pkgName)
for _, err := range errlist {
@@ -217,13 +239,15 @@ func checkFiles(t *testing.T, sources []string) {
// typecheck and collect typechecker errors
var conf Config
+ conf.GoVersion = goVersion
// special case for importC.src
- if len(sources) == 1 && strings.HasSuffix(sources[0], "importC.src") {
- conf.FakeImportC = true
+ if len(filenames) == 1 {
+ if strings.HasSuffix(filenames[0], "importC.src") {
+ conf.FakeImportC = true
+ }
}
- // TODO(rFindley) we may need to use the source importer when adding generics
- // tests.
+
conf.Importer = importer.Default()
conf.Error = func(err error) {
if *haltOnError {
@@ -258,7 +282,7 @@ func checkFiles(t *testing.T, sources []string) {
// match and eliminate errors;
// we are expecting the following errors
- errmap := errMap(t, pkgName, files)
+ errmap := errMap(t, files, srcs)
eliminate(t, errmap, errlist)
// there should be no expected errors left
@@ -273,13 +297,20 @@ func checkFiles(t *testing.T, sources []string) {
}
// TestCheck is for manual testing of selected input files, provided with -files.
+// The accepted Go language version can be controlled with the -lang flag.
func TestCheck(t *testing.T) {
if *testFiles == "" {
return
}
testenv.MustHaveGoBuild(t)
DefPredeclaredTestFuncs()
- checkFiles(t, strings.Split(*testFiles, " "))
+ testPkg(t, strings.Split(*testFiles, ","), *goVersion)
+}
+
+func TestLongConstants(t *testing.T) {
+ format := "package longconst\n\nconst _ = %s\nconst _ = %s // ERROR excessively long constant"
+ src := fmt.Sprintf(format, strings.Repeat("1", 9999), strings.Repeat("1", 10001))
+ checkFiles(t, "", []string{"longconst.go"}, [][]byte{[]byte(src)})
}
func TestTestdata(t *testing.T) { DefPredeclaredTestFuncs(); testDir(t, "testdata") }
@@ -299,26 +330,33 @@ func testDir(t *testing.T, dir string) {
path := filepath.Join(dir, fi.Name())
// if fi is a directory, its files make up a single package
- var files []string
+ var filenames []string
if fi.IsDir() {
fis, err := ioutil.ReadDir(path)
if err != nil {
t.Error(err)
continue
}
- files = make([]string, len(fis))
- for i, fi := range fis {
- // if fi is a directory, checkFiles below will complain
- files[i] = filepath.Join(path, fi.Name())
- if testing.Verbose() {
- fmt.Printf("\t%s\n", files[i])
- }
+ for _, fi := range fis {
+ filenames = append(filenames, filepath.Join(path, fi.Name()))
}
} else {
- files = []string{path}
+ filenames = []string{path}
}
t.Run(filepath.Base(path), func(t *testing.T) {
- checkFiles(t, files)
+ testPkg(t, filenames, "")
})
}
}
+
+func testPkg(t *testing.T, filenames []string, goVersion string) {
+ srcs := make([][]byte, len(filenames))
+ for i, filename := range filenames {
+ src, err := os.ReadFile(filename)
+ if err != nil {
+ t.Fatalf("could not read %s: %v", filename, err)
+ }
+ srcs[i] = src
+ }
+ checkFiles(t, goVersion, filenames, srcs)
+}