package main import ( "go/ast" "go/importer" "go/parser" "go/token" "go/types" "strings" "testing" ) func TestExportedContractBoundaries(t *testing.T) { tests := []struct { name string source string wantError string }{ { name: "leaked implementation type", source: `package facade import "example.com/implementation" func New() *implementation.State { return nil } `, wantError: "exposes named type example.com/implementation.State", }, { name: "alias to implementation type", source: `package facade import "example.com/implementation" type Alias = implementation.State `, wantError: "exposes named type example.com/implementation.State", }, { name: "callback leaks implementation type", source: `package facade import "example.com/implementation" type Callback func() *implementation.State `, wantError: "exposes named type example.com/implementation.State", }, { name: "generic constraint leaks implementation type", source: `package facade import "example.com/implementation" type Box[T interface{ Value() *implementation.State }] struct { value T } `, wantError: "exposes named type example.com/implementation.State", }, { name: "generic instantiation leaks implementation type", source: `package facade import "example.com/implementation" type Box[T any] struct { value T } func New() Box[implementation.State] { return Box[implementation.State]{} } `, wantError: "exposes named type example.com/implementation.State", }, { name: "promoted implementation method", source: `package facade import "example.com/implementation" type state = implementation.State type Handle struct { state } `, wantError: "promotes method Promoted from example.com/implementation", }, { name: "promoted pointer implementation method", source: `package facade import "example.com/implementation" type state = implementation.State type Handle struct { state } `, wantError: "promotes method PointerPromoted from example.com/implementation", }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { violations := checkFixture(t, test.source) if !strings.Contains(strings.Join(violations, "\n"), test.wantError) { t.Fatalf("checkExports() = %v, want an error containing %q", violations, test.wantError) } }) } } func TestPrivateImplementationFieldAndSelectedStandardTypes(t *testing.T) { source := `package facade import ( "context" "example.com/implementation" ) type Handle struct { state *implementation.State } func Open(context.Context) *Handle { return nil } ` if violations := checkFixture(t, source); len(violations) != 0 { t.Fatalf("private implementation field and selected standard type were rejected: %v", violations) } } func TestActualRepositoryBoundaries(t *testing.T) { if err := checkRepository(t.Context(), "../.."); err != nil { t.Fatal(err) } } func TestInternalPackagesCannotImportPublicFacades(t *testing.T) { packages := []listedPackage{ {ImportPath: modulePath + "/internal/operations", Imports: []string{modulePath}}, {ImportPath: modulePath + "/cmd/releasekit/internal/cli", Imports: []string{modulePath + "/buildinfo"}}, {ImportPath: modulePath}, {ImportPath: modulePath + "/buildinfo"}, } err := checkImportDirections(packages) if err == nil || !strings.Contains(err.Error(), "internal package "+modulePath+"/internal/operations imports public or command package "+modulePath) || !strings.Contains(err.Error(), "internal package "+modulePath+"/cmd/releasekit/internal/cli imports public or command package "+modulePath+"/buildinfo") { t.Fatalf("checkImportDirections() error = %v, want internal-to-facade violation", err) } } func TestRuntimeFacadeCannotDependOnExternalPackages(t *testing.T) { packages := []listedPackage{ {ImportPath: modulePath + "/buildinfo", Imports: []string{"example.com/runtime"}}, {ImportPath: "example.com/runtime"}, } err := checkImportDirections(packages) if err == nil || !strings.Contains(err.Error(), "buildinfo depends on non-runtime package example.com/runtime") { t.Fatalf("checkImportDirections() error = %v, want runtime dependency violation", err) } } func checkFixture(t *testing.T, facadeSource string) []string { t.Helper() fset := token.NewFileSet() implementation := typecheck(t, fset, "example.com/implementation", `package implementation type State struct{} func (State) Promoted() {} func (*State) PointerPromoted() {} `) fixtureImporter := singlePackageImporter{path: "example.com/implementation", pkg: implementation} facade := typecheckWithImporter(t, fset, "example.com/facade", facadeSource, fixtureImporter) return checkExports(facade) } type singlePackageImporter struct { path string pkg *types.Package } func (i singlePackageImporter) Import(path string) (*types.Package, error) { if path == i.path { return i.pkg, nil } return importer.Default().Import(path) } func typecheck(t *testing.T, fset *token.FileSet, path, source string) *types.Package { t.Helper() return typecheckWithImporter(t, fset, path, source, importer.Default()) } func typecheckWithImporter(t *testing.T, fset *token.FileSet, path, source string, imports types.Importer) *types.Package { t.Helper() file, err := parser.ParseFile(fset, path+".go", source, 0) if err != nil { t.Fatal(err) } var errors []error config := types.Config{ Importer: imports, Error: func(err error) { errors = append(errors, err) }, } pkg, err := config.Check(path, fset, []*ast.File{file}, nil) if err != nil { t.Fatalf("typecheck %s: %v (%v)", path, err, errors) } return pkg }