a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
118 lines
4.6 KiB
Go
118 lines
4.6 KiB
Go
package contracts
|
|
|
|
import (
|
|
"slices"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
type fakeRoutePass struct {
|
|
name string
|
|
langs []string
|
|
detect func(string, []byte) bool
|
|
extract func(*RouteExtractCtx) []Contract
|
|
}
|
|
|
|
func (p fakeRoutePass) Name() string { return p.name }
|
|
func (p fakeRoutePass) Languages() []string { return p.langs }
|
|
func (p fakeRoutePass) Detect(fp string, src []byte) bool { return p.detect(fp, src) }
|
|
func (p fakeRoutePass) Extract(ctx *RouteExtractCtx) []Contract { return p.extract(ctx) }
|
|
|
|
// saveRegistry snapshots and restores the global registry around a test that
|
|
// mutates it.
|
|
func saveRegistry(t *testing.T) {
|
|
t.Helper()
|
|
saved := append([]FrameworkRoutePass(nil), frameworkRoutePasses...)
|
|
t.Cleanup(func() { frameworkRoutePasses = saved })
|
|
}
|
|
|
|
func TestApplicableFrameworkRoutePasses_LanguageFilter(t *testing.T) {
|
|
got := ApplicableFrameworkRoutePasses("go")
|
|
for _, p := range got {
|
|
if langs := p.Languages(); len(langs) > 0 && !slices.Contains(langs, "go") {
|
|
t.Errorf("pass %q (langs %v) wrongly applicable to go", p.Name(), langs)
|
|
}
|
|
if p.Name() == "django" {
|
|
t.Errorf("python-only django pass must not apply to go")
|
|
}
|
|
}
|
|
// file-based has no language filter → applies to every language.
|
|
if !slices.ContainsFunc(got, func(p FrameworkRoutePass) bool { return p.Name() == "file-based" }) {
|
|
t.Errorf("file-based pass (all languages) should apply to go")
|
|
}
|
|
}
|
|
|
|
func TestRegisterFrameworkRoutePass_CustomExtension(t *testing.T) {
|
|
saveRegistry(t)
|
|
RegisterFrameworkRoutePass(fakeRoutePass{
|
|
name: "custom", langs: []string{"go"},
|
|
detect: func(fp string, _ []byte) bool { return strings.HasSuffix(fp, ".custom") },
|
|
extract: func(*RouteExtractCtx) []Contract {
|
|
return []Contract{{ID: "http::GET::/custom", Type: ContractHTTP, Role: RoleProvider}}
|
|
},
|
|
})
|
|
out := runFrameworkRoutePasses(&RouteExtractCtx{FilePath: "x.custom", Lang: "go", Src: []byte("anything")})
|
|
if !slices.ContainsFunc(out, func(c Contract) bool { return c.ID == "http::GET::/custom" }) {
|
|
t.Errorf("a custom registered pass should emit its route contract; got %+v", out)
|
|
}
|
|
// A non-matching file path: Detect returns false, no contract.
|
|
none := runFrameworkRoutePasses(&RouteExtractCtx{FilePath: "x.go", Lang: "go", Src: []byte("anything")})
|
|
if slices.ContainsFunc(none, func(c Contract) bool { return c.ID == "http::GET::/custom" }) {
|
|
t.Errorf("custom pass must not fire when Detect is false")
|
|
}
|
|
}
|
|
|
|
func TestRunFrameworkRoutePasses_PanicIsolation(t *testing.T) {
|
|
saveRegistry(t)
|
|
frameworkRoutePasses = nil
|
|
RegisterFrameworkRoutePass(fakeRoutePass{
|
|
name: "boom", langs: nil,
|
|
detect: func(string, []byte) bool { panic("detect boom") },
|
|
extract: func(*RouteExtractCtx) []Contract { return nil },
|
|
})
|
|
RegisterFrameworkRoutePass(fakeRoutePass{
|
|
name: "ok", langs: nil,
|
|
detect: func(string, []byte) bool { return true },
|
|
extract: func(*RouteExtractCtx) []Contract { return []Contract{{ID: "http::GET::/ok", Type: ContractHTTP}} },
|
|
})
|
|
|
|
out := runFrameworkRoutePasses(&RouteExtractCtx{FilePath: "f", Lang: "go", Src: []byte("x")})
|
|
if !slices.ContainsFunc(out, func(c Contract) bool { return c.ID == "http::GET::/ok" }) {
|
|
t.Errorf("a panicking Detect must not prevent other passes from running; got %+v", out)
|
|
}
|
|
if names := DetectFrameworks("f", []byte("x")); !slices.Contains(names, "ok") {
|
|
t.Errorf("DetectFrameworks should still list ok despite the boom panic; got %v", names)
|
|
}
|
|
}
|
|
|
|
func TestRunFrameworkRoutePasses_ExtractPanicIsolation(t *testing.T) {
|
|
saveRegistry(t)
|
|
frameworkRoutePasses = nil
|
|
RegisterFrameworkRoutePass(fakeRoutePass{
|
|
name: "boom-extract", langs: nil,
|
|
detect: func(string, []byte) bool { return true },
|
|
extract: func(*RouteExtractCtx) []Contract { panic("extract boom") },
|
|
})
|
|
RegisterFrameworkRoutePass(fakeRoutePass{
|
|
name: "ok", langs: nil,
|
|
detect: func(string, []byte) bool { return true },
|
|
extract: func(*RouteExtractCtx) []Contract { return []Contract{{ID: "http::GET::/ok", Type: ContractHTTP}} },
|
|
})
|
|
out := runFrameworkRoutePasses(&RouteExtractCtx{FilePath: "f", Lang: "go", Src: []byte("x")})
|
|
if !slices.ContainsFunc(out, func(c Contract) bool { return c.ID == "http::GET::/ok" }) {
|
|
t.Errorf("a panicking Extract must not prevent other passes from running; got %+v", out)
|
|
}
|
|
}
|
|
|
|
func TestRegisteredFrameworkRoutePasses_CoversStructuralPasses(t *testing.T) {
|
|
names := map[string]bool{}
|
|
for _, p := range RegisteredFrameworkRoutePasses() {
|
|
names[p.Name()] = true
|
|
}
|
|
for _, want := range []string{"file-based", "django", "drf", "rails-resources", "express-objects", "flask-decorator"} {
|
|
if !names[want] {
|
|
t.Errorf("registry missing structural pass %q", want)
|
|
}
|
|
}
|
|
}
|