1 package pat
2
3 import (
4 "context"
5 "net/http"
6 "reflect"
7 "testing"
8
9 "goji.io/pattern"
10 )
11
12 func mustReq(method, path string) *http.Request {
13 req, err := http.NewRequest(method, path, nil)
14 if err != nil {
15 panic(err)
16 }
17 ctx := pattern.SetPath(context.Background(), req.URL.EscapedPath())
18 return req.WithContext(ctx)
19 }
20
21 type PatTest struct {
22 pat string
23 req string
24 match bool
25 vars map[pattern.Variable]interface{}
26 path string
27 }
28
29 type pv map[pattern.Variable]interface{}
30
31 var PatTests = []PatTest{
32 {"/", "/", true, nil, ""},
33 {"/", "/hello", false, nil, ""},
34 {"/hello", "/hello", true, nil, ""},
35
36 {"/:name", "/carl", true, pv{"name": "carl"}, ""},
37 {"/:name", "/carl/", false, nil, ""},
38 {"/:name", "/", false, nil, ""},
39 {"/:name/", "/carl/", true, pv{"name": "carl"}, ""},
40 {"/:name/", "/carl/no", false, nil, ""},
41 {"/:name/hi", "/carl/hi", true, pv{"name": "carl"}, ""},
42 {"/:name/:color", "/carl/red", true, pv{"name": "carl", "color": "red"}, ""},
43 {"/:name/:color", "/carl/", false, nil, ""},
44 {"/:name/:color", "/carl.red", false, nil, ""},
45
46 {"/:file.:ext", "/data.json", true, pv{"file": "data", "ext": "json"}, ""},
47 {"/:file.:ext", "/data.tar.gz", true, pv{"file": "data", "ext": "tar.gz"}, ""},
48 {"/:file.:ext", "/data", false, nil, ""},
49 {"/:file.:ext", "/data.", false, nil, ""},
50 {"/:file.:ext", "/.gitconfig", false, nil, ""},
51 {"/:file.:ext", "/data.json/", false, nil, ""},
52 {"/:file.:ext", "/data/json", false, nil, ""},
53 {"/:file.:ext", "/data;json", false, nil, ""},
54 {"/hello.:ext", "/hello.json", true, pv{"ext": "json"}, ""},
55 {"/:file.json", "/hello.json", true, pv{"file": "hello"}, ""},
56 {"/:file.json", "/hello.world.json", false, nil, ""},
57 {"/file;:version", "/file;1", true, pv{"version": "1"}, ""},
58 {"/file;:version", "/file,1", false, nil, ""},
59 {"/file,:version", "/file,1", true, pv{"version": "1"}, ""},
60 {"/file,:version", "/file;1", false, nil, ""},
61
62 {"/*", "/", true, nil, "/"},
63 {"/*", "/hello", true, nil, "/hello"},
64 {"/users/*", "/", false, nil, ""},
65 {"/users/*", "/users", false, nil, ""},
66 {"/users/*", "/users/", true, nil, "/"},
67 {"/users/*", "/users/carl", true, nil, "/carl"},
68 {"/users/*", "/profile/carl", false, nil, ""},
69 {"/:name/*", "/carl", false, nil, ""},
70 {"/:name/*", "/carl/", true, pv{"name": "carl"}, "/"},
71 {"/:name/*", "/carl/photos", true, pv{"name": "carl"}, "/photos"},
72 {"/:name/*", "/carl/photos%2f2015", true, pv{"name": "carl"}, "/photos%2f2015"},
73 }
74
75 func TestPat(t *testing.T) {
76 t.Parallel()
77
78 for _, test := range PatTests {
79 pat := New(test.pat)
80
81 if str := pat.String(); str != test.pat {
82 t.Errorf("[%q %q] String()=%q, expected=%q", test.pat, test.req, str, test.pat)
83 }
84
85 req := pat.Match(mustReq("GET", test.req))
86 if (req != nil) != test.match {
87 t.Errorf("[%q %q] match=%v, expected=%v", test.pat, test.req, req != nil, test.match)
88 }
89 if req == nil {
90 continue
91 }
92
93 ctx := req.Context()
94 if path := pattern.Path(ctx); path != test.path {
95 t.Errorf("[%q %q] path=%q, expected=%q", test.pat, test.req, path, test.path)
96 }
97
98 vars := ctx.Value(pattern.AllVariables)
99 if (vars != nil) != (test.vars != nil) {
100 t.Errorf("[%q %q] vars=%#v, expected=%#v", test.pat, test.req, vars, test.vars)
101 }
102 if vars == nil {
103 continue
104 }
105 if tvars := vars.(map[pattern.Variable]interface{}); !reflect.DeepEqual(tvars, test.vars) {
106 t.Errorf("[%q %q] vars=%v, expected=%v", test.pat, test.req, tvars, test.vars)
107 }
108 }
109 }
110
111 func TestBadPathEncoding(t *testing.T) {
112 t.Parallel()
113
114
115
116 ctx := pattern.SetPath(context.Background(), "/%nope")
117 r, _ := http.NewRequest("GET", "/", nil)
118 if New("/:name").Match(r.WithContext(ctx)) != nil {
119 t.Error("unexpected match")
120 }
121 }
122
123 var PathPrefixTests = []struct {
124 pat string
125 prefix string
126 }{
127 {"/", "/"},
128 {"/hello/:world", "/hello/"},
129 {"/users/:name/profile", "/users/"},
130 {"/users/*", "/users/"},
131 }
132
133 func TestPathPrefix(t *testing.T) {
134 t.Parallel()
135
136 for _, test := range PathPrefixTests {
137 pat := New(test.pat)
138 if prefix := pat.PathPrefix(); prefix != test.prefix {
139 t.Errorf("%q.PathPrefix() = %q, expected %q", test.pat, prefix, test.prefix)
140 }
141 }
142 }
143
144 func TestHTTPMethods(t *testing.T) {
145 t.Parallel()
146
147 pat := New("/foo")
148 if methods := pat.HTTPMethods(); methods != nil {
149 t.Errorf("expected nil with no methods, got %v", methods)
150 }
151
152 pat = Get("/boo")
153 expect := map[string]struct{}{"GET": {}, "HEAD": {}}
154 if methods := pat.HTTPMethods(); !reflect.DeepEqual(expect, methods) {
155 t.Errorf("methods=%v, expected %v", methods, expect)
156 }
157 }
158
159 func TestParam(t *testing.T) {
160 t.Parallel()
161
162 pat := New("/hello/:name")
163 req := pat.Match(mustReq("GET", "/hello/carl"))
164 if req == nil {
165 t.Fatal("expected a match")
166 }
167 if name := Param(req, "name"); name != "carl" {
168 t.Errorf("name=%q, expected %q", name, "carl")
169 }
170 }
171
View as plain text