
daptest has type assertion functions that panic if the read response/event message is not the expected type. This is not only against the recommended style guideline (Don't Panic, Useful Test Failures, ...), but also it prevents from quickly diagnosing test failures occurred in remote CIs. This PR changes the type assertion to the two return value type assertion, and t.Fatal with details if the type is not expected. service/dap/daptest/main.go is a program that auto generates those assertion functions in resp.go. Run `go generate` from the service/dap directory to update resp.go.
100 lines
2.2 KiB
Go
100 lines
2.2 KiB
Go
// Binary gen generates service/dap/daptest/responses.go.
|
|
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"flag"
|
|
"fmt"
|
|
"go/format"
|
|
"go/types"
|
|
"io/ioutil"
|
|
"os"
|
|
"text/template"
|
|
|
|
"golang.org/x/tools/go/packages"
|
|
|
|
_ "github.com/google/go-dap"
|
|
)
|
|
|
|
var oFlag = flag.String("o", "", "output file name")
|
|
|
|
var tmpl = template.Must(template.New("assert").Parse(`package daptest
|
|
|
|
// Code generated by go generate; DO NOT EDIT.
|
|
// The code generator program is in ./gen directory.
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/google/go-dap"
|
|
)
|
|
{{range .}}
|
|
// Expect{{.}} reads a protocol message from the connection
|
|
// and fails the test if the read message is not *{{.}}.
|
|
func (c *Client) Expect{{.}}(t *testing.T) *dap.{{.}} {
|
|
t.Helper()
|
|
m := c.ExpectMessage(t)
|
|
r, ok := m.(*dap.{{.}})
|
|
if !ok {
|
|
t.Fatalf("got %q, want *dap.{{.}}", m)
|
|
}
|
|
return r
|
|
}{{end}}
|
|
`))
|
|
|
|
func main() {
|
|
flag.Parse()
|
|
|
|
if *oFlag == "" {
|
|
fmt.Fprintf(os.Stderr, "-o must be provided\n")
|
|
}
|
|
|
|
pkgs, err := packages.Load(&packages.Config{
|
|
Mode: packages.NeedTypes,
|
|
}, "github.com/google/go-dap")
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "load: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
if len(pkgs) != 1 || pkgs[0].Types == nil {
|
|
fmt.Fprintf(os.Stderr, "invalid package was loaded: %#v\n", pkgs)
|
|
os.Exit(1)
|
|
}
|
|
|
|
messages := []string{}
|
|
scope := pkgs[0].Types.Scope()
|
|
for _, name := range scope.Names() {
|
|
// Find only types that are embedding go-dap.Respose message.
|
|
obj := scope.Lookup(name)
|
|
if !obj.Exported() {
|
|
continue // skip unexported
|
|
}
|
|
u, ok := obj.Type().Underlying().(*types.Struct)
|
|
if !ok {
|
|
continue
|
|
}
|
|
for i := 0; i < u.NumFields(); i++ {
|
|
if f := u.Field(i); f.Embedded() && (f.Type().String() == "github.com/google/go-dap.Response" ||
|
|
f.Type().String() == "github.com/google/go-dap.Event") {
|
|
messages = append(messages, obj.Name())
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
buf := &bytes.Buffer{}
|
|
if err := tmpl.Execute(buf, messages); err != nil {
|
|
fmt.Fprintf(os.Stderr, "Failed to generate: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
formatted, err := format.Source(buf.Bytes())
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "Generated invalid go code: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
if err := ioutil.WriteFile(*oFlag, formatted, 0644); err != nil {
|
|
fmt.Fprintf(os.Stderr, "Failed to write: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
}
|