
This commit adds tests for CGo preprocessing. There are various errors that can be reported while preprocessing, and they should integrate well with the compiler (including accurate source location tracking). Also allow CGo preprocessing to continue after Clang encountered an error, for a better view of what happened.
131 строка
3,7 КиБ
Go
131 строка
3,7 КиБ
Go
package cgo
|
|
|
|
import (
|
|
"bytes"
|
|
"flag"
|
|
"fmt"
|
|
"go/ast"
|
|
"go/format"
|
|
"go/parser"
|
|
"go/token"
|
|
"go/types"
|
|
"io/ioutil"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// Pass -update to go test to update the output of the test files.
|
|
var flagUpdate = flag.Bool("update", false, "Update images based on test output.")
|
|
|
|
func TestCGo(t *testing.T) {
|
|
var cflags = []string{"--target=armv6m-none-eabi"}
|
|
|
|
for _, name := range []string{"basic", "errors", "types"} {
|
|
name := name // avoid a race condition
|
|
t.Run(name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// Read the AST in memory.
|
|
path := filepath.Join("testdata", name+".go")
|
|
fset := token.NewFileSet()
|
|
f, err := parser.ParseFile(fset, path, nil, parser.ParseComments)
|
|
if err != nil {
|
|
t.Fatal("could not parse Go source file:", err)
|
|
}
|
|
|
|
// Process the AST with CGo.
|
|
cgoAST, cgoErrors := Process([]*ast.File{f}, "testdata", fset, cflags)
|
|
|
|
// Check the AST for type errors.
|
|
var typecheckErrors []error
|
|
config := types.Config{
|
|
Error: func(err error) {
|
|
typecheckErrors = append(typecheckErrors, err)
|
|
},
|
|
Importer: simpleImporter{},
|
|
Sizes: types.SizesFor("gccgo", "arm"),
|
|
}
|
|
_, err = config.Check("", fset, []*ast.File{f, cgoAST}, nil)
|
|
if err != nil && len(typecheckErrors) == 0 {
|
|
// Only report errors when no type errors are found (an
|
|
// unexpected condition).
|
|
t.Error(err)
|
|
}
|
|
|
|
// Store the (formatted) output in a buffer. Format it, so it
|
|
// becomes easier to read (and will hopefully change less with CGo
|
|
// changes).
|
|
buf := &bytes.Buffer{}
|
|
if len(cgoErrors) != 0 {
|
|
buf.WriteString("// CGo errors:\n")
|
|
for _, err := range cgoErrors {
|
|
buf.WriteString(formatDiagnostic(err))
|
|
}
|
|
buf.WriteString("\n")
|
|
}
|
|
if len(typecheckErrors) != 0 {
|
|
buf.WriteString("// Type checking errors after CGo processing:\n")
|
|
for _, err := range typecheckErrors {
|
|
buf.WriteString(formatDiagnostic(err))
|
|
}
|
|
buf.WriteString("\n")
|
|
}
|
|
err = format.Node(buf, fset, cgoAST)
|
|
if err != nil {
|
|
t.Errorf("could not write out CGo AST: %v", err)
|
|
}
|
|
actual := strings.Replace(string(buf.Bytes()), "\r\n", "\n", -1)
|
|
|
|
// Read the file with the expected output, to compare against.
|
|
outfile := filepath.Join("testdata", name+".out.go")
|
|
expectedBytes, err := ioutil.ReadFile(outfile)
|
|
if err != nil {
|
|
t.Fatalf("could not read expected output: %v", err)
|
|
}
|
|
expected := strings.Replace(string(expectedBytes), "\r\n", "\n", -1)
|
|
|
|
// Check whether the output is as expected.
|
|
if expected != actual {
|
|
// It is not. Test failed.
|
|
if *flagUpdate {
|
|
// Update the file with the expected data.
|
|
err := ioutil.WriteFile(outfile, []byte(actual), 0666)
|
|
if err != nil {
|
|
t.Error("could not write updated output file:", err)
|
|
}
|
|
return
|
|
}
|
|
t.Errorf("output did not match:\n%s", string(actual))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// simpleImporter implements the types.Importer interface, but only allows
|
|
// importing the unsafe package.
|
|
type simpleImporter struct {
|
|
}
|
|
|
|
// Import implements the Importer interface. For testing usage only: it only
|
|
// supports importing the unsafe package.
|
|
func (i simpleImporter) Import(path string) (*types.Package, error) {
|
|
switch path {
|
|
case "unsafe":
|
|
return types.Unsafe, nil
|
|
default:
|
|
return nil, fmt.Errorf("importer not implemented for package %s", path)
|
|
}
|
|
}
|
|
|
|
// formatDiagnostics formats the error message to be an indented comment. It
|
|
// also fixes Windows path name issues (backward slashes).
|
|
func formatDiagnostic(err error) string {
|
|
msg := err.Error()
|
|
if runtime.GOOS == "windows" {
|
|
// Fix Windows path slashes.
|
|
msg = strings.Replace(msg, "testdata\\", "testdata/", -1)
|
|
}
|
|
return "// " + msg + "\n"
|
|
}
|