// Copyright 2010 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 simple typechecker test harness. Packages found
// in the testDir directory are typechecked. Error messages reported by
// the typechecker are compared against the error messages expected for
// 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 P0
//	func f() {
//		_ = x /* ERROR "not declared" */ + 1
//	}
// 
// If the -pkg flag is set, only packages with package names matching
// the regular expression provided via the flag value are tested.

package typechecker

import (
	"flag"
	"fmt"
	"go/ast"
	"go/parser"
	"go/scanner"
	"go/token"
	"io/ioutil"
	"os"
	"regexp"
	"sort"
	"strings"
	"testing"
)

const testDir = "./testdata" // location of test packages

var fset = token.NewFileSet()

var (
	pkgPat = flag.String("pkg", ".*", "regular expression to select test packages by package name")
	trace  = flag.Bool("trace", false, "print package names")
)

// 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 the package files of pkg and returns them in sorted order
// (by filename and position).
func expectedErrors(t *testing.T, pkg *ast.Package) (list scanner.ErrorList) {
	// scan all package files
	for filename := range pkg.Files {
		src, err := ioutil.ReadFile(filename)
		if err != nil {
			t.Fatalf("expectedErrors(%s): %v", pkg.Name, err)
		}

		var s scanner.Scanner
		file := fset.AddFile(filename, fset.Base(), len(src))
		s.Init(file, src, nil, scanner.ScanComments)
		var prev token.Pos // position of last non-comment token
	loop:
		for {
			pos, tok, lit := s.Scan()
			switch tok {
			case token.EOF:
				break loop
			case token.COMMENT:
				s := errRx.FindStringSubmatch(lit)
				if len(s) == 2 {
					list = append(list, &scanner.Error{fset.Position(prev), string(s[1])})
				}
			default:
				prev = pos
			}
		}
	}
	sort.Sort(list) // multiple files may not be sorted
	return
}

func testFilter(f *os.FileInfo) bool {
	return strings.HasSuffix(f.Name, ".src") && f.Name[0] != '.'
}

func checkError(t *testing.T, expected, found *scanner.Error) {
	rx, err := regexp.Compile(expected.Msg)
	if err != nil {
		t.Errorf("%s: %v", expected.Pos, err)
		return
	}

	match := rx.MatchString(found.Msg)

	if expected.Pos.Offset != found.Pos.Offset {
		if match {
			t.Errorf("%s: expected error should have been at %s", expected.Pos, found.Pos)
		} else {
			t.Errorf("%s: error matching %q expected", expected.Pos, expected.Msg)
			return
		}
	}

	if !match {
		t.Errorf("%s: %q does not match %q", expected.Pos, expected.Msg, found.Msg)
	}
}

func TestTypeCheck(t *testing.T) {
	flag.Parse()
	pkgRx, err := regexp.Compile(*pkgPat)
	if err != nil {
		t.Fatalf("illegal flag value %q: %s", *pkgPat, err)
	}

	pkgs, err := parser.ParseDir(fset, testDir, testFilter, 0)
	if err != nil {
		scanner.PrintError(os.Stderr, err)
		t.Fatalf("packages in %s contain syntax errors", testDir)
	}

	for _, pkg := range pkgs {
		if !pkgRx.MatchString(pkg.Name) {
			continue // only test selected packages
		}

		if *trace {
			fmt.Println(pkg.Name)
		}

		xlist := expectedErrors(t, pkg)
		err := CheckPackage(fset, pkg, nil)
		if err != nil {
			if elist, ok := err.(scanner.ErrorList); ok {
				// verify that errors match
				for i := 0; i < len(xlist) && i < len(elist); i++ {
					checkError(t, xlist[i], elist[i])
				}
				// the correct number or errors must have been found
				if len(xlist) != len(elist) {
					fmt.Fprintf(os.Stderr, "%s\n", pkg.Name)
					scanner.PrintError(os.Stderr, elist)
					fmt.Fprintln(os.Stderr)
					t.Errorf("TypeCheck(%s): %d errors expected but %d reported", pkg.Name, len(xlist), len(elist))
				}
			} else {
				t.Errorf("TypeCheck(%s): %v", pkg.Name, err)
			}
		} else if len(xlist) > 0 {
			t.Errorf("TypeCheck(%s): %d errors expected but 0 reported", pkg.Name, len(xlist))
		}
	}
}
