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