Prepare Sandwich Hime v1 release candidate source
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sando
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/importer"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestV1PublicAPIContract(t *testing.T) {
|
||||
t.Parallel()
|
||||
entries, err := os.ReadDir(".")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fileSet := token.NewFileSet()
|
||||
var files []*ast.File
|
||||
for _, entry := range entries {
|
||||
if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".go") || strings.HasSuffix(entry.Name(), "_test.go") {
|
||||
continue
|
||||
}
|
||||
file, err := parser.ParseFile(fileSet, entry.Name(), nil, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("parse %s: %v", entry.Name(), err)
|
||||
}
|
||||
files = append(files, file)
|
||||
}
|
||||
configuration := types.Config{Importer: importer.Default()}
|
||||
checked, err := configuration.Check("gamertan.com/sandwich-hime/sando", fileSet, files, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
qualifier := func(pkg *types.Package) string {
|
||||
if pkg == nil || pkg.Path() == checked.Path() {
|
||||
return ""
|
||||
}
|
||||
return pkg.Name()
|
||||
}
|
||||
var actual []string
|
||||
for _, name := range checked.Scope().Names() {
|
||||
if !token.IsExported(name) {
|
||||
continue
|
||||
}
|
||||
object := checked.Scope().Lookup(name)
|
||||
switch object := object.(type) {
|
||||
case *types.Const:
|
||||
actual = append(actual, fmt.Sprintf("const %s = %s", object.Name(), object.Val().ExactString()))
|
||||
case *types.TypeName:
|
||||
named, ok := object.Type().(*types.Named)
|
||||
if !ok {
|
||||
actual = append(actual, types.ObjectString(object, qualifier))
|
||||
break
|
||||
}
|
||||
if structure, ok := named.Underlying().(*types.Struct); ok {
|
||||
var fields []string
|
||||
for index := 0; index < structure.NumFields(); index++ {
|
||||
field := structure.Field(index)
|
||||
if field.Exported() {
|
||||
fields = append(fields, field.Name()+" "+types.TypeString(field.Type(), qualifier))
|
||||
}
|
||||
}
|
||||
if len(fields) == 0 {
|
||||
actual = append(actual, "type "+object.Name()+" struct{ /* opaque */ }")
|
||||
} else {
|
||||
actual = append(actual, "type "+object.Name()+" struct{"+strings.Join(fields, "; ")+"}")
|
||||
}
|
||||
} else {
|
||||
actual = append(actual, types.ObjectString(object, qualifier))
|
||||
}
|
||||
default:
|
||||
actual = append(actual, types.ObjectString(object, qualifier))
|
||||
}
|
||||
typeName, ok := object.(*types.TypeName)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
named, ok := typeName.Type().(*types.Named)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
for index := 0; index < named.NumMethods(); index++ {
|
||||
method := named.Method(index)
|
||||
if method.Exported() {
|
||||
actual = append(actual, types.ObjectString(method, qualifier))
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Strings(actual)
|
||||
got := strings.Join(actual, "\n") + "\n"
|
||||
want, err := os.ReadFile("testdata/public-api-v1.txt")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
want = []byte(strings.TrimPrefix(string(want), "# SPDX-License-Identifier: Apache-2.0\n\n"))
|
||||
if string(want) != got {
|
||||
t.Fatalf("v1 public API drifted\n--- committed contract ---\n%s--- observed API ---\n%s", want, got)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user