package httpd import ( "go/ast" "go/parser" "go/token" "strconv" "strings" "testing" "github.com/barerepo/server/internal/gitx" ) // Chapter 42.5: a route with no reservation is one an account can shadow, and it says a test must catch it. func TestEveryTopLevelRouteIsAReservedName(t *testing.T) { fset := token.NewFileSet() file, err := parser.ParseFile(fset, "web.go", nil, 0) if err != nil { t.Fatal(err) } seen := map[string]bool{} ast.Inspect(file, func(n ast.Node) bool { be, ok := n.(*ast.BinaryExpr) if !ok || be.Op != token.EQL { return true } lit, ok := be.Y.(*ast.BasicLit) if !ok || lit.Kind != token.STRING || !isRequestPath(be.X) { return true } path, err := strconv.Unquote(lit.Value) if err != nil || !strings.HasPrefix(path, "/") { return true } first, _, _ := strings.Cut(strings.TrimPrefix(path, "/"), "/") if first != "" { seen[first] = true } return true }) if len(seen) < 8 { t.Fatalf("only found %d top level routes, so this test is reading the wrong thing", len(seen)) } for name := range seen { // A name holding a dot is a file and not something an account could ever be called. if strings.Contains(name, ".") { continue } if !gitx.Reserved(name) { t.Errorf("/%s is a route and not a reserved name, so an account can shadow it", name) } } } // isRequestPath reports whether an expression is r.URL.Path, which is what the route switch compares. func isRequestPath(e ast.Expr) bool { sel, ok := e.(*ast.SelectorExpr) if !ok || sel.Sel.Name != "Path" { return false } inner, ok := sel.X.(*ast.SelectorExpr) return ok && inner.Sel.Name == "URL" }