1 #![deny(warnings)]
2 #[macro_use]
3 extern crate warp;
4
5 use futures::future;
6 use warp::Filter;
7
8 #[tokio::test]
path()9 async fn path() {
10 let _ = pretty_env_logger::try_init();
11
12 let foo = warp::path("foo");
13 let bar = warp::path(String::from("bar"));
14 let foo_bar = foo.and(bar.clone());
15
16 // /foo
17 let foo_req = || warp::test::request().path("/foo");
18
19 assert!(foo_req().matches(&foo).await);
20 assert!(!foo_req().matches(&bar).await);
21 assert!(!foo_req().matches(&foo_bar).await);
22
23 // /foo/bar
24 let foo_bar_req = || warp::test::request().path("/foo/bar");
25
26 assert!(foo_bar_req().matches(&foo).await);
27 assert!(!foo_bar_req().matches(&bar).await);
28 assert!(foo_bar_req().matches(&foo_bar).await);
29 }
30
31 #[tokio::test]
param()32 async fn param() {
33 let _ = pretty_env_logger::try_init();
34
35 let num = warp::path::param::<u32>();
36
37 let req = warp::test::request().path("/321");
38 assert_eq!(req.filter(&num).await.unwrap(), 321);
39
40 let s = warp::path::param::<String>();
41
42 let req = warp::test::request().path("/warp");
43 assert_eq!(req.filter(&s).await.unwrap(), "warp");
44
45 // u32 doesn't extract a non-int
46 let req = warp::test::request().path("/warp");
47 assert!(!req.matches(&num).await);
48
49 let combo = num.map(|n| n + 5).and(s);
50
51 let req = warp::test::request().path("/42/vroom");
52 assert_eq!(req.filter(&combo).await.unwrap(), (47, "vroom".to_string()));
53
54 // empty segments never match
55 let req = warp::test::request();
56 assert!(
57 !req.matches(&s).await,
58 "param should never match an empty segment"
59 );
60 }
61
62 #[tokio::test]
end()63 async fn end() {
64 let _ = pretty_env_logger::try_init();
65
66 let foo = warp::path("foo");
67 let end = warp::path::end();
68 let foo_end = foo.and(end);
69
70 assert!(
71 warp::test::request().path("/").matches(&end).await,
72 "end() matches /"
73 );
74
75 assert!(
76 warp::test::request()
77 .path("http://localhost:1234")
78 .matches(&end)
79 .await,
80 "end() matches /"
81 );
82
83 assert!(
84 warp::test::request()
85 .path("http://localhost:1234?q=2")
86 .matches(&end)
87 .await,
88 "end() matches empty path"
89 );
90
91 assert!(
92 warp::test::request()
93 .path("localhost:1234")
94 .matches(&end)
95 .await,
96 "end() matches authority-form"
97 );
98
99 assert!(
100 !warp::test::request().path("/foo").matches(&end).await,
101 "end() doesn't match /foo"
102 );
103
104 assert!(
105 warp::test::request().path("/foo").matches(&foo_end).await,
106 "path().and(end()) matches /foo"
107 );
108
109 assert!(
110 warp::test::request().path("/foo/").matches(&foo_end).await,
111 "path().and(end()) matches /foo/"
112 );
113 }
114
115 #[tokio::test]
tail()116 async fn tail() {
117 let tail = warp::path::tail();
118
119 // matches full path
120 let ex = warp::test::request()
121 .path("/42/vroom")
122 .filter(&tail)
123 .await
124 .unwrap();
125 assert_eq!(ex.as_str(), "42/vroom");
126
127 // matches index
128 let ex = warp::test::request().path("/").filter(&tail).await.unwrap();
129 assert_eq!(ex.as_str(), "");
130
131 // doesn't include query
132 let ex = warp::test::request()
133 .path("/foo/bar?baz=quux")
134 .filter(&tail)
135 .await
136 .unwrap();
137 assert_eq!(ex.as_str(), "foo/bar");
138
139 // doesn't include previously matched prefix
140 let and = warp::path("foo").and(tail);
141 let ex = warp::test::request()
142 .path("/foo/bar")
143 .filter(&and)
144 .await
145 .unwrap();
146 assert_eq!(ex.as_str(), "bar");
147
148 // sets unmatched path index to end
149 let m = tail.and(warp::path("foo"));
150 assert!(!warp::test::request().path("/foo/bar").matches(&m).await);
151
152 let m = tail.and(warp::path::end());
153 assert!(warp::test::request().path("/foo/bar").matches(&m).await);
154
155 let ex = warp::test::request()
156 .path("localhost")
157 .filter(&tail)
158 .await
159 .unwrap();
160 assert_eq!(ex.as_str(), "/");
161 }
162
163 #[tokio::test]
or()164 async fn or() {
165 let _ = pretty_env_logger::try_init();
166
167 // /foo/bar OR /foo/baz
168 let foo = warp::path("foo");
169 let bar = warp::path("bar");
170 let baz = warp::path("baz");
171 let p = foo.and(bar.or(baz));
172
173 // /foo/bar
174 let req = warp::test::request().path("/foo/bar");
175
176 assert!(req.matches(&p).await);
177
178 // /foo/baz
179 let req = warp::test::request().path("/foo/baz");
180
181 assert!(req.matches(&p).await);
182
183 // deeper nested ORs
184 // /foo/bar/baz OR /foo/baz/bar OR /foo/bar/bar
185 let p = foo
186 .and(bar.and(baz).map(|| panic!("shouldn't match")))
187 .or(foo.and(baz.and(bar)).map(|| panic!("shouldn't match")))
188 .or(foo.and(bar.and(bar)));
189
190 // /foo/baz
191 let req = warp::test::request().path("/foo/baz/baz");
192 assert!(!req.matches(&p).await);
193
194 // /foo/bar/bar
195 let req = warp::test::request().path("/foo/bar/bar");
196 assert!(req.matches(&p).await);
197 }
198
199 #[tokio::test]
or_else()200 async fn or_else() {
201 let _ = pretty_env_logger::try_init();
202
203 let foo = warp::path("foo");
204 let bar = warp::path("bar");
205
206 let p = foo.and(bar.or_else(|_| future::ok::<_, std::convert::Infallible>(())));
207
208 // /foo/bar
209 let req = warp::test::request().path("/foo/nope");
210
211 assert!(req.matches(&p).await);
212 }
213
214 #[tokio::test]
path_macro()215 async fn path_macro() {
216 let _ = pretty_env_logger::try_init();
217
218 let req = warp::test::request().path("/foo/bar");
219 let p = path!("foo" / "bar");
220 assert!(req.matches(&p).await);
221
222 let req = warp::test::request().path("/foo/bar");
223 let p = path!(String / "bar");
224 assert_eq!(req.filter(&p).await.unwrap(), "foo");
225
226 let req = warp::test::request().path("/foo/bar");
227 let p = path!("foo" / String);
228 assert_eq!(req.filter(&p).await.unwrap(), "bar");
229
230 // Requires path end
231
232 let req = warp::test::request().path("/foo/bar/baz");
233 let p = path!("foo" / "bar");
234 assert!(!req.matches(&p).await);
235
236 let req = warp::test::request().path("/foo/bar/baz");
237 let p = path!("foo" / "bar").and(warp::path("baz"));
238 assert!(!req.matches(&p).await);
239
240 // Prefix syntax
241
242 let req = warp::test::request().path("/foo/bar/baz");
243 let p = path!("foo" / "bar" / ..);
244 assert!(req.matches(&p).await);
245
246 let req = warp::test::request().path("/foo/bar/baz");
247 let p = path!("foo" / "bar" / ..).and(warp::path!("baz"));
248 assert!(req.matches(&p).await);
249 }
250
251 #[tokio::test]
full_path()252 async fn full_path() {
253 let full_path = warp::path::full();
254
255 let foo = warp::path("foo");
256 let bar = warp::path("bar");
257 let param = warp::path::param::<u32>();
258
259 // matches full request path
260 let ex = warp::test::request()
261 .path("/42/vroom")
262 .filter(&full_path)
263 .await
264 .unwrap();
265 assert_eq!(ex.as_str(), "/42/vroom");
266
267 // matches index
268 let ex = warp::test::request()
269 .path("/")
270 .filter(&full_path)
271 .await
272 .unwrap();
273 assert_eq!(ex.as_str(), "/");
274
275 // does not include query
276 let ex = warp::test::request()
277 .path("/foo/bar?baz=quux")
278 .filter(&full_path)
279 .await
280 .unwrap();
281 assert_eq!(ex.as_str(), "/foo/bar");
282
283 // includes previously matched prefix
284 let and = foo.and(full_path);
285 let ex = warp::test::request()
286 .path("/foo/bar")
287 .filter(&and)
288 .await
289 .unwrap();
290 assert_eq!(ex.as_str(), "/foo/bar");
291
292 // includes following matches
293 let and = full_path.and(foo);
294 let ex = warp::test::request()
295 .path("/foo/bar")
296 .filter(&and)
297 .await
298 .unwrap();
299 assert_eq!(ex.as_str(), "/foo/bar");
300
301 // includes previously matched param
302 let and = foo.and(param).and(full_path);
303 let (_, ex) = warp::test::request()
304 .path("/foo/123")
305 .filter(&and)
306 .await
307 .unwrap();
308 assert_eq!(ex.as_str(), "/foo/123");
309
310 // does not modify matching
311 let m = full_path.and(foo).and(bar);
312 assert!(warp::test::request().path("/foo/bar").matches(&m).await);
313
314 // doesn't panic on authority-form
315 let ex = warp::test::request()
316 .path("localhost:1234")
317 .filter(&full_path)
318 .await
319 .unwrap();
320 assert_eq!(ex.as_str(), "/");
321 }
322
323 #[tokio::test]
peek()324 async fn peek() {
325 let peek = warp::path::peek();
326
327 let foo = warp::path("foo");
328 let bar = warp::path("bar");
329 let param = warp::path::param::<u32>();
330
331 // matches full request path
332 let ex = warp::test::request()
333 .path("/42/vroom")
334 .filter(&peek)
335 .await
336 .unwrap();
337 assert_eq!(ex.as_str(), "42/vroom");
338
339 // matches index
340 let ex = warp::test::request().path("/").filter(&peek).await.unwrap();
341 assert_eq!(ex.as_str(), "");
342
343 // does not include query
344 let ex = warp::test::request()
345 .path("/foo/bar?baz=quux")
346 .filter(&peek)
347 .await
348 .unwrap();
349 assert_eq!(ex.as_str(), "foo/bar");
350
351 // does not include previously matched prefix
352 let and = foo.and(peek);
353 let ex = warp::test::request()
354 .path("/foo/bar")
355 .filter(&and)
356 .await
357 .unwrap();
358 assert_eq!(ex.as_str(), "bar");
359
360 // includes following matches
361 let and = peek.and(foo);
362 let ex = warp::test::request()
363 .path("/foo/bar")
364 .filter(&and)
365 .await
366 .unwrap();
367 assert_eq!(ex.as_str(), "foo/bar");
368
369 // does not include previously matched param
370 let and = foo.and(param).and(peek);
371 let (_, ex) = warp::test::request()
372 .path("/foo/123")
373 .filter(&and)
374 .await
375 .unwrap();
376 assert_eq!(ex.as_str(), "");
377
378 // does not modify matching
379 let and = peek.and(foo).and(bar);
380 assert!(warp::test::request().path("/foo/bar").matches(&and).await);
381 }
382
383 #[tokio::test]
peek_segments()384 async fn peek_segments() {
385 let peek = warp::path::peek();
386
387 // matches full request path
388 let ex = warp::test::request()
389 .path("/42/vroom")
390 .filter(&peek)
391 .await
392 .unwrap();
393
394 assert_eq!(ex.segments().collect::<Vec<_>>(), &["42", "vroom"]);
395
396 // matches index
397 let ex = warp::test::request().path("/").filter(&peek).await.unwrap();
398
399 let segs = ex.segments().collect::<Vec<_>>();
400 assert_eq!(segs, Vec::<&str>::new());
401 }
402