Source file
src/goji.io/router_test.go
Documentation: goji.io
1 package goji
2
3 import (
4 "context"
5 "net/http"
6 "reflect"
7 "testing"
8
9 "goji.io/internal"
10 "goji.io/pattern"
11 )
12
13 func TestNoMatch(t *testing.T) {
14 t.Parallel()
15
16 var rt router
17 rt.add(boolPattern(false), http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
18 t.Fatal("did not expect handler to be called")
19 }))
20 _, r := wr()
21 ctx := context.Background()
22 ctx = context.WithValue(ctx, internal.Pattern, boolPattern(true))
23 ctx = context.WithValue(ctx, internal.Pattern, boolPattern(true))
24 ctx = context.WithValue(ctx, pattern.Variable("answer"), 42)
25 ctx = context.WithValue(ctx, internal.Path, "/")
26
27 r = r.WithContext(ctx)
28 r = rt.route(r)
29 ctx = r.Context()
30
31 if p := ctx.Value(internal.Pattern); p != nil {
32 t.Errorf("unexpected pattern %v", p)
33 }
34 if h := ctx.Value(internal.Handler); h != nil {
35 t.Errorf("unexpected handler %v", h)
36 }
37 if h := ctx.Value(pattern.Variable("answer")); h != 42 {
38 t.Errorf("context didn't work: got %v, wanted %v", h, 42)
39 }
40 }
41
42
50
51 var TestRoutes = []testPattern{
52 testPattern{methods: nil, prefix: "/"},
53 testPattern{methods: nil, prefix: "/a"},
54 testPattern{methods: []string{"POST", "PUT"}, prefix: "/a"},
55 testPattern{methods: []string{"GET", "POST"}, prefix: "/a"},
56 testPattern{methods: []string{"GET"}, prefix: "/b"},
57 testPattern{methods: nil, prefix: "/ab"},
58 testPattern{methods: []string{"POST", "PUT"}, prefix: "/"},
59 testPattern{methods: nil, prefix: "/ba"},
60 testPattern{methods: nil, prefix: "/"},
61 testPattern{methods: []string{}, prefix: "/"},
62 testPattern{methods: nil, prefix: "/carl"},
63 testPattern{methods: []string{"PUT"}, prefix: "/car"},
64 testPattern{methods: nil, prefix: "/cake"},
65 testPattern{methods: nil, prefix: "/car"},
66 testPattern{methods: []string{"GET"}, prefix: "/c"},
67 testPattern{methods: []string{"POST"}, prefix: "/"},
68 testPattern{methods: []string{"PUT"}, prefix: "/"},
69 }
70
71 var RouterTests = []struct {
72 method, path string
73 results []int
74 }{
75 {"GET", "/", []int{0, 8, 8, 8, 8, 8, 8, 8, 8, -1, -1, -1, -1, -1, -1, -1, -1}},
76 {"POST", "/", []int{0, 6, 6, 6, 6, 6, 6, 8, 8, 15, 15, 15, 15, 15, 15, 15, -1}},
77 {"PUT", "/", []int{0, 6, 6, 6, 6, 6, 6, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16}},
78 {"HEAD", "/", []int{0, 8, 8, 8, 8, 8, 8, 8, 8, -1, -1, -1, -1, -1, -1, -1, -1}},
79 {"GET", "/a", []int{0, 1, 3, 3, 8, 8, 8, 8, 8, -1, -1, -1, -1, -1, -1, -1, -1}},
80 {"POST", "/a", []int{0, 1, 2, 3, 6, 6, 6, 8, 8, 15, 15, 15, 15, 15, 15, 15, -1}},
81 {"PUT", "/a", []int{0, 1, 2, 6, 6, 6, 6, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16}},
82 {"HEAD", "/a", []int{0, 1, 8, 8, 8, 8, 8, 8, 8, -1, -1, -1, -1, -1, -1, -1, -1}},
83 {"GET", "/b", []int{0, 4, 4, 4, 4, 8, 8, 8, 8, -1, -1, -1, -1, -1, -1, -1, -1}},
84 {"POST", "/b", []int{0, 6, 6, 6, 6, 6, 6, 8, 8, 15, 15, 15, 15, 15, 15, 15, -1}},
85 {"GET", "/ba", []int{0, 4, 4, 4, 4, 7, 7, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1}},
86 {"GET", "/c", []int{0, 8, 8, 8, 8, 8, 8, 8, 8, 14, 14, 14, 14, 14, 14, -1, -1}},
87 {"POST", "/c", []int{0, 6, 6, 6, 6, 6, 6, 8, 8, 15, 15, 15, 15, 15, 15, 15, -1}},
88 {"GET", "/ab", []int{0, 1, 3, 3, 5, 5, 8, 8, 8, -1, -1, -1, -1, -1, -1, -1, -1}},
89 {"POST", "/ab", []int{0, 1, 2, 3, 5, 5, 6, 8, 8, 15, 15, 15, 15, 15, 15, 15, -1}},
90 {"GET", "/carl", []int{0, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 13, 13, 13, 14, -1, -1}},
91 {"POST", "/carl", []int{0, 6, 6, 6, 6, 6, 6, 8, 8, 10, 10, 13, 13, 13, 15, 15, -1}},
92 {"HEAD", "/carl", []int{0, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 13, 13, 13, -1, -1, -1}},
93 {"PUT", "/carl", []int{0, 6, 6, 6, 6, 6, 6, 8, 8, 10, 10, 11, 13, 13, 16, 16, 16}},
94 {"GET", "/cake", []int{0, 8, 8, 8, 8, 8, 8, 8, 8, 12, 12, 12, 12, 14, 14, -1, -1}},
95 {"PUT", "/cake", []int{0, 6, 6, 6, 6, 6, 6, 8, 8, 12, 12, 12, 12, 16, 16, 16, 16}},
96 {"OHAI", "/carl", []int{0, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 13, 13, 13, -1, -1, -1}},
97 }
98
99 func TestRouter(t *testing.T) {
100 t.Parallel()
101
102 var rt router
103 mark := new(int)
104 for i, p := range TestRoutes {
105 i := i
106 p.index = i
107 p.mark = mark
108 rt.add(p, intHandler(i))
109 }
110
111 for i, test := range RouterTests {
112 r, err := http.NewRequest(test.method, test.path, nil)
113 if err != nil {
114 panic(err)
115 }
116 ctx := context.WithValue(context.Background(), internal.Path, test.path)
117 r = r.WithContext(ctx)
118
119 var out []int
120 for *mark = 0; *mark < len(TestRoutes); *mark++ {
121 r := rt.route(r)
122 ctx := r.Context()
123 if h := ctx.Value(internal.Handler); h != nil {
124 out = append(out, int(h.(intHandler)))
125 } else {
126 out = append(out, -1)
127 }
128 }
129 if !reflect.DeepEqual(out, test.results) {
130 t.Errorf("[%d] expected %v got %v", i, test.results, out)
131 }
132 }
133 }
134
135 type contextPattern struct{}
136
137 func (contextPattern) Match(r *http.Request) *http.Request {
138 return r.WithContext(context.WithValue(r.Context(), pattern.Variable("hello"), "world"))
139 }
140
141 func TestRouterContextPropagation(t *testing.T) {
142 t.Parallel()
143
144 var rt router
145 rt.add(contextPattern{}, intHandler(0))
146 _, r := wr()
147 r = r.WithContext(context.WithValue(r.Context(), internal.Path, "/"))
148 r2 := rt.route(r)
149 ctx := r2.Context()
150 if hello := ctx.Value(pattern.Variable("hello")).(string); hello != "world" {
151 t.Fatalf("routed request didn't include correct key from pattern: %q", hello)
152 }
153 }
154
View as plain text