NextMyDay/internal/core/routing/purity_test.go
Claus Lohmar e114a2be61 feat(routing): add the pure routing model (SPEC-002)
Turns a request path plus the two routing fields (`do`/`action`) into a single
Resolution for BOTH doors (D-039): the RESERVED level-1 switch first
(home/access/setup/api/static/media/ws/dev — D-004), then the GUID classifier,
then the registry. Identity and the module registry are injected interfaces, so
the package is PURE — no HTTP stack, no DB (asserted by purity_test.go). All 22
spec rows are covered.
2026-10-14 10:53:48 +00:00

59 lines
1.4 KiB
Go

package routing
import (
"go/parser"
"go/token"
"os"
"path/filepath"
"runtime"
"strings"
"testing"
)
// forbiddenImportPrefixes are the packages the pure routing model must never
// pull into its build OR test graph (SPEC-002 §5, the purity assertion).
var forbiddenImportPrefixes = []string{
"net/http",
"database/sql",
}
// TestPurityNoHTTPOrDB makes the purity assertion real: it parses every .go
// file in this package — implementation and tests — and fails if any of them
// imports an HTTP or DB package.
func TestPurityNoHTTPOrDB(t *testing.T) {
_, thisFile, _, ok := runtime.Caller(0)
if !ok {
t.Fatal("runtime.Caller failed")
}
dir := filepath.Dir(thisFile)
entries, err := os.ReadDir(dir)
if err != nil {
t.Fatalf("ReadDir(%s): %v", dir, err)
}
fset := token.NewFileSet()
checked := 0
for _, e := range entries {
if e.IsDir() || !strings.HasSuffix(e.Name(), ".go") {
continue
}
file, err := parser.ParseFile(fset, filepath.Join(dir, e.Name()), nil, parser.ImportsOnly)
if err != nil {
t.Fatalf("parse %s: %v", e.Name(), err)
}
checked++
for _, imp := range file.Imports {
pkg := strings.Trim(imp.Path.Value, `"`)
for _, bad := range forbiddenImportPrefixes {
if pkg == bad || strings.HasPrefix(pkg, bad+"/") {
t.Errorf("%s imports forbidden package %q (the routing model must be pure)", e.Name(), pkg)
}
}
}
}
if checked == 0 {
t.Fatal("purity check found no .go files to inspect")
}
}