diff options
Diffstat (limited to 'src/pkg/exp/types/check_test.go')
-rw-r--r-- | src/pkg/exp/types/check_test.go | 217 |
1 files changed, 0 insertions, 217 deletions
diff --git a/src/pkg/exp/types/check_test.go b/src/pkg/exp/types/check_test.go deleted file mode 100644 index 03cc7438e2..0000000000 --- a/src/pkg/exp/types/check_test.go +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// This file implements a typechecker test harness. The packages specified -// in tests are typechecked. Error messages reported by the typechecker are -// compared against the error messages expected in the test files. -// -// Expected errors are indicated in the test files by putting a comment -// of the form /* ERROR "rx" */ immediately following an offending token. -// The harness will verify that an error matching the regular expression -// rx is reported at that source position. Consecutive comments may be -// used to indicate multiple errors for the same token position. -// -// For instance, the following test file indicates that a "not declared" -// error should be reported for the undeclared variable x: -// -// package p -// func f() { -// _ = x /* ERROR "not declared" */ + 1 -// } - -package types - -import ( - "fmt" - "go/ast" - "go/parser" - "go/scanner" - "go/token" - "io/ioutil" - "os" - "regexp" - "testing" -) - -// The test filenames do not end in .go so that they are invisible -// to gofmt since they contain comments that must not change their -// positions relative to surrounding tokens. - -var tests = []struct { - name string - files []string -}{ - {"test0", []string{"testdata/test0.src"}}, -} - -var fset = token.NewFileSet() - -func getFile(filename string) (file *token.File) { - fset.Iterate(func(f *token.File) bool { - if f.Name() == filename { - file = f - return false // end iteration - } - return true - }) - return file -} - -func getPos(filename string, offset int) token.Pos { - if f := getFile(filename); f != nil { - return f.Pos(offset) - } - return token.NoPos -} - -func parseFiles(t *testing.T, testname string, filenames []string) (map[string]*ast.File, error) { - files := make(map[string]*ast.File) - var errors scanner.ErrorList - for _, filename := range filenames { - if _, exists := files[filename]; exists { - t.Fatalf("%s: duplicate file %s", testname, filename) - } - file, err := parser.ParseFile(fset, filename, nil, parser.DeclarationErrors) - if file == nil { - t.Fatalf("%s: could not parse file %s", testname, filename) - } - files[filename] = file - if err != nil { - // if the parser returns a non-scanner.ErrorList error - // the file couldn't be read in the first place and - // file == nil; in that case we shouldn't reach here - errors = append(errors, err.(scanner.ErrorList)...) - } - - } - return files, errors -} - -// ERROR comments must be of the form /* ERROR "rx" */ and rx is -// a regular expression that matches the expected error message. -// -var errRx = regexp.MustCompile(`^/\* *ERROR *"([^"]*)" *\*/$`) - -// expectedErrors collects the regular expressions of ERROR comments found -// in files and returns them as a map of error positions to error messages. -// -func expectedErrors(t *testing.T, testname string, files map[string]*ast.File) map[token.Pos]string { - errors := make(map[token.Pos]string) - for filename := range files { - src, err := ioutil.ReadFile(filename) - if err != nil { - t.Fatalf("%s: could not read %s", testname, filename) - } - - var s scanner.Scanner - // file was parsed already - do not add it again to the file - // set otherwise the position information returned here will - // not match the position information collected by the parser - s.Init(getFile(filename), src, nil, scanner.ScanComments) - var prev token.Pos // position of last non-comment, non-semicolon token - - scanFile: - for { - pos, tok, lit := s.Scan() - switch tok { - case token.EOF: - break scanFile - case token.COMMENT: - s := errRx.FindStringSubmatch(lit) - if len(s) == 2 { - errors[prev] = string(s[1]) - } - case token.SEMICOLON: - // ignore automatically inserted semicolon - if lit == "\n" { - break - } - fallthrough - default: - prev = pos - } - } - } - return errors -} - -func eliminate(t *testing.T, expected map[token.Pos]string, errors error) { - if errors == nil { - return - } - for _, error := range errors.(scanner.ErrorList) { - // error.Pos is a token.Position, but we want - // a token.Pos so we can do a map lookup - pos := getPos(error.Pos.Filename, error.Pos.Offset) - if msg, found := expected[pos]; found { - // we expect a message at pos; check if it matches - rx, err := regexp.Compile(msg) - if err != nil { - t.Errorf("%s: %v", error.Pos, err) - continue - } - if match := rx.MatchString(error.Msg); !match { - t.Errorf("%s: %q does not match %q", error.Pos, error.Msg, msg) - continue - } - // we have a match - eliminate this error - delete(expected, pos) - } else { - // To keep in mind when analyzing failed test output: - // If the same error position occurs multiple times in errors, - // this message will be triggered (because the first error at - // the position removes this position from the expected errors). - t.Errorf("%s: no (multiple?) error expected, but found: %s", error.Pos, error.Msg) - } - } -} - -func check(t *testing.T, testname string, testfiles []string) { - // TODO(gri) Eventually all these different phases should be - // subsumed into a single function call that takes - // a set of files and creates a fully resolved and - // type-checked AST. - - files, err := parseFiles(t, testname, testfiles) - - // we are expecting the following errors - // (collect these after parsing the files so that - // they are found in the file set) - errors := expectedErrors(t, testname, files) - - // verify errors returned by the parser - eliminate(t, errors, err) - - // verify errors returned after resolving identifiers - pkg, err := ast.NewPackage(fset, files, GcImport, Universe) - eliminate(t, errors, err) - - // verify errors returned by the typechecker - _, err = Check(fset, pkg) - eliminate(t, errors, err) - - // there should be no expected errors left - if len(errors) > 0 { - t.Errorf("%s: %d errors not reported:", testname, len(errors)) - for pos, msg := range errors { - t.Errorf("%s: %s\n", fset.Position(pos), msg) - } - } -} - -func TestCheck(t *testing.T) { - // For easy debugging w/o changing the testing code, - // if there is a local test file, only test that file. - const testfile = "testdata/test.go" - if fi, err := os.Stat(testfile); err == nil && !fi.IsDir() { - fmt.Printf("WARNING: Testing only %s (remove it to run all tests)\n", testfile) - check(t, testfile, []string{testfile}) - return - } - - // Otherwise, run all the tests. - for _, test := range tests { - check(t, test.name, test.files) - } -} |