File view with blame information shown in the left gutter beside each line.

barerepo / server / internal/httpd/routes_test.go
65 lines · 1.6kb · master
log files threads runs releases config jump to file t
133728e barerepo 1mo
1
package httpd
133728e barerepo 1mo
2
133728e barerepo 1mo
3
import (
133728e barerepo 1mo
4
"go/ast"
133728e barerepo 1mo
5
"go/parser"
133728e barerepo 1mo
6
"go/token"
133728e barerepo 1mo
7
"strconv"
133728e barerepo 1mo
8
"strings"
133728e barerepo 1mo
9
"testing"
133728e barerepo 1mo
10
133728e barerepo 1mo
11
"github.com/barerepo/server/internal/gitx"
133728e barerepo 1mo
12
)
133728e barerepo 1mo
13
133728e barerepo 1mo
14
// Chapter 42.5: a route with no reservation is one an account can shadow, and it says a test must catch it.
133728e barerepo 1mo
15
func TestEveryTopLevelRouteIsAReservedName(t *testing.T) {
133728e barerepo 1mo
16
fset := token.NewFileSet()
133728e barerepo 1mo
17
file, err := parser.ParseFile(fset, "web.go", nil, 0)
133728e barerepo 1mo
18
if err != nil {
133728e barerepo 1mo
19
t.Fatal(err)
133728e barerepo 1mo
20
}
133728e barerepo 1mo
21
133728e barerepo 1mo
22
seen := map[string]bool{}
133728e barerepo 1mo
23
ast.Inspect(file, func(n ast.Node) bool {
133728e barerepo 1mo
24
be, ok := n.(*ast.BinaryExpr)
133728e barerepo 1mo
25
if !ok || be.Op != token.EQL {
133728e barerepo 1mo
26
return true
133728e barerepo 1mo
27
}
133728e barerepo 1mo
28
lit, ok := be.Y.(*ast.BasicLit)
133728e barerepo 1mo
29
if !ok || lit.Kind != token.STRING || !isRequestPath(be.X) {
133728e barerepo 1mo
30
return true
133728e barerepo 1mo
31
}
133728e barerepo 1mo
32
path, err := strconv.Unquote(lit.Value)
133728e barerepo 1mo
33
if err != nil || !strings.HasPrefix(path, "/") {
133728e barerepo 1mo
34
return true
133728e barerepo 1mo
35
}
133728e barerepo 1mo
36
first, _, _ := strings.Cut(strings.TrimPrefix(path, "/"), "/")
133728e barerepo 1mo
37
if first != "" {
133728e barerepo 1mo
38
seen[first] = true
133728e barerepo 1mo
39
}
133728e barerepo 1mo
40
return true
133728e barerepo 1mo
41
})
133728e barerepo 1mo
42
133728e barerepo 1mo
43
if len(seen) < 8 {
133728e barerepo 1mo
44
t.Fatalf("only found %d top level routes, so this test is reading the wrong thing", len(seen))
133728e barerepo 1mo
45
}
133728e barerepo 1mo
46
for name := range seen {
133728e barerepo 1mo
47
// A name holding a dot is a file and not something an account could ever be called.
133728e barerepo 1mo
48
if strings.Contains(name, ".") {
133728e barerepo 1mo
49
continue
133728e barerepo 1mo
50
}
133728e barerepo 1mo
51
if !gitx.Reserved(name) {
133728e barerepo 1mo
52
t.Errorf("/%s is a route and not a reserved name, so an account can shadow it", name)
133728e barerepo 1mo
53
}
133728e barerepo 1mo
54
}
133728e barerepo 1mo
55
}
133728e barerepo 1mo
56
133728e barerepo 1mo
57
// isRequestPath reports whether an expression is r.URL.Path, which is what the route switch compares.
133728e barerepo 1mo
58
func isRequestPath(e ast.Expr) bool {
133728e barerepo 1mo
59
sel, ok := e.(*ast.SelectorExpr)
133728e barerepo 1mo
60
if !ok || sel.Sel.Name != "Path" {
133728e barerepo 1mo
61
return false
133728e barerepo 1mo
62
}
133728e barerepo 1mo
63
inner, ok := sel.X.(*ast.SelectorExpr)
133728e barerepo 1mo
64
return ok && inner.Sel.Name == "URL"
133728e barerepo 1mo
65
}
history · rawbarerepo 0.1.0