1use crate::catcher::Catcher;
2use crate::route::{Route, Color};
3
4use crate::http::{MediaType, Status};
5use crate::request::Request;
6
7pub trait Collide<T = Self> {
8 fn collides_with(&self, other: &T) -> bool;
9}
10
11impl<'a, 'b, T: Collide> Collide<&T> for &T {
12 fn collides_with(&self, other: &&T) -> bool {
13 T::collides_with(*self, *other)
14 }
15}
16
17impl Collide for MediaType {
18 fn collides_with(&self, other: &Self) -> bool {
19 let collide = |a, b| a == "*" || b == "*" || a == b;
20 collide(self.top(), other.top()) && collide(self.sub(), other.sub())
21 }
22}
23
24fn paths_collide(route: &Route, other: &Route) -> bool {
25 let a_segments = &route.uri.metadata.path_segs;
26 let b_segments = &other.uri.metadata.path_segs;
27 for (seg_a, seg_b) in a_segments.iter().zip(b_segments.iter()) {
28 if seg_a.trailing || seg_b.trailing {
29 return true;
30 }
31
32 if seg_a.dynamic || seg_b.dynamic {
33 continue;
34 }
35
36 if seg_a.value != seg_b.value {
37 return false;
38 }
39 }
40
41 a_segments.get(b_segments.len()).map_or(false, |s| s.trailing)
42 || b_segments.get(a_segments.len()).map_or(false, |s| s.trailing)
43 || a_segments.len() == b_segments.len()
44}
45
46fn formats_collide(route: &Route, other: &Route) -> bool {
47 if !route.method.supports_payload() {
51 return true;
52 }
53
54 match (route.format.as_ref(), other.format.as_ref()) {
59 (Some(a), Some(b)) => a.collides_with(b),
60 _ => true
61 }
62}
63
64impl Collide for Route {
65 fn collides_with(&self, other: &Route) -> bool {
78 self.method == other.method
79 && self.rank == other.rank
80 && paths_collide(self, other)
81 && formats_collide(self, other)
82 }
83}
84
85impl Route {
86 pub(crate) fn matches(&self, req: &Request<'_>) -> bool {
100 self.method == req.method()
101 && paths_match(self, req)
102 && queries_match(self, req)
103 && formats_match(self, req)
104 }
105}
106
107fn paths_match(route: &Route, req: &Request<'_>) -> bool {
108 let route_segments = &route.uri.metadata.path_segs;
109 let req_segments = req.uri().path().segments();
110
111 if route.uri.metadata.trailing_path {
112 if req_segments.len() + 1 < route_segments.len() {
116 return false;
117 }
118 } else if route_segments.len() != req_segments.len() {
119 return false;
120 }
121
122 if route.uri.metadata.path_color == Color::Wild {
123 return true;
124 }
125
126 for (route_seg, req_seg) in route_segments.iter().zip(req_segments) {
127 if route_seg.trailing {
128 return true;
129 }
130
131 if !(route_seg.dynamic || route_seg.value == req_seg) {
132 return false;
133 }
134 }
135
136 true
137}
138
139fn queries_match(route: &Route, req: &Request<'_>) -> bool {
140 if matches!(route.uri.metadata.query_color, None | Some(Color::Wild)) {
141 return true;
142 }
143
144 let route_query_fields = route.uri.metadata.static_query_fields.iter()
145 .map(|(k, v)| (k.as_str(), v.as_str()));
146
147 for route_seg in route_query_fields {
148 if let Some(query) = req.uri().query() {
149 if !query.segments().any(|req_seg| req_seg == route_seg) {
150 trace_!("request {} missing static query {:?}", req, route_seg);
151 return false;
152 }
153 } else {
154 trace_!("query-less request {} missing static query {:?}", req, route_seg);
155 return false;
156 }
157 }
158
159 true
160}
161
162fn formats_match(route: &Route, request: &Request<'_>) -> bool {
163 if !route.method.supports_payload() {
164 route.format.as_ref()
165 .and_then(|a| request.format().map(|b| (a, b)))
166 .map(|(a, b)| a.collides_with(b))
167 .unwrap_or(true)
168 } else {
169 match route.format.as_ref() {
170 Some(a) => match request.format() {
171 Some(b) if b.specificity() == 2 => a.collides_with(b),
172 _ => false
173 }
174 None => true
175 }
176 }
177}
178
179
180impl Collide for Catcher {
181 fn collides_with(&self, other: &Self) -> bool {
188 self.code == other.code
189 && self.base.path().segments().eq(other.base.path().segments())
190 }
191}
192
193impl Catcher {
194 pub(crate) fn matches(&self, status: Status, req: &Request<'_>) -> bool {
200 self.code.map_or(true, |code| code == status.code)
201 && self.base.path().segments().prefix_of(req.uri().path().segments())
202 }
203}
204
205#[cfg(test)]
206mod tests {
207 use std::str::FromStr;
208
209 use super::*;
210 use crate::route::{Route, dummy_handler};
211 use crate::local::blocking::Client;
212 use crate::http::{Method, Method::*, MediaType, ContentType, Accept};
213 use crate::http::uri::Origin;
214
215 type SimpleRoute = (Method, &'static str);
216
217 fn m_collide(a: SimpleRoute, b: SimpleRoute) -> bool {
218 let route_a = Route::new(a.0, a.1, dummy_handler);
219 route_a.collides_with(&Route::new(b.0, b.1, dummy_handler))
220 }
221
222 fn unranked_collide(a: &'static str, b: &'static str) -> bool {
223 let route_a = Route::ranked(0, Get, a, dummy_handler);
224 let route_b = Route::ranked(0, Get, b, dummy_handler);
225 eprintln!("Checking {} against {}.", route_a, route_b);
226 route_a.collides_with(&route_b)
227 }
228
229 fn s_s_collide(a: &'static str, b: &'static str) -> bool {
230 let a = Route::new(Get, a, dummy_handler);
231 let b = Route::new(Get, b, dummy_handler);
232 paths_collide(&a, &b)
233 }
234
235 #[test]
236 fn simple_collisions() {
237 assert!(unranked_collide("/a", "/a"));
238 assert!(unranked_collide("/hello", "/hello"));
239 assert!(unranked_collide("/hello", "/hello/"));
240 assert!(unranked_collide("/hello/there/how/ar", "/hello/there/how/ar"));
241 assert!(unranked_collide("/hello/there", "/hello/there/"));
242 }
243
244 #[test]
245 fn simple_param_collisions() {
246 assert!(unranked_collide("/<a>", "/<b>"));
247 assert!(unranked_collide("/<a>", "/b"));
248 assert!(unranked_collide("/hello/<name>", "/hello/<person>"));
249 assert!(unranked_collide("/hello/<name>/hi", "/hello/<person>/hi"));
250 assert!(unranked_collide("/hello/<name>/hi/there", "/hello/<person>/hi/there"));
251 assert!(unranked_collide("/<name>/hi/there", "/<person>/hi/there"));
252 assert!(unranked_collide("/<name>/hi/there", "/dude/<name>/there"));
253 assert!(unranked_collide("/<name>/<a>/<b>", "/<a>/<b>/<c>"));
254 assert!(unranked_collide("/<name>/<a>/<b>/", "/<a>/<b>/<c>/"));
255 assert!(unranked_collide("/<a..>", "/hi"));
256 assert!(unranked_collide("/<a..>", "/hi/hey"));
257 assert!(unranked_collide("/<a..>", "/hi/hey/hayo"));
258 assert!(unranked_collide("/a/<a..>", "/a/hi/hey/hayo"));
259 assert!(unranked_collide("/a/<b>/<a..>", "/a/hi/hey/hayo"));
260 assert!(unranked_collide("/a/<b>/<c>/<a..>", "/a/hi/hey/hayo"));
261 assert!(unranked_collide("/<b>/<c>/<a..>", "/a/hi/hey/hayo"));
262 assert!(unranked_collide("/<b>/<c>/hey/hayo", "/a/hi/hey/hayo"));
263 assert!(unranked_collide("/<a..>", "/foo"));
264 }
265
266 #[test]
267 fn medium_param_collisions() {
268 assert!(unranked_collide("/<a>", "/b"));
269 assert!(unranked_collide("/hello/<name>", "/hello/bob"));
270 assert!(unranked_collide("/<name>", "//bob"));
271 }
272
273 #[test]
274 fn hard_param_collisions() {
275 assert!(unranked_collide("/<a..>", "///a///"));
276 assert!(unranked_collide("/<a..>", "//a/bcjdklfj//<c>"));
277 assert!(unranked_collide("/a/<a..>", "//a/bcjdklfj//<c>"));
278 assert!(unranked_collide("/a/<b>/<c..>", "//a/bcjdklfj//<c>"));
279 assert!(unranked_collide("/<a..>", "/"));
280 assert!(unranked_collide("/", "/<_..>"));
281 assert!(unranked_collide("/a/b/<a..>", "/a/<b..>"));
282 assert!(unranked_collide("/a/b/<a..>", "/a/<b>/<b..>"));
283 assert!(unranked_collide("/hi/<a..>", "/hi"));
284 assert!(unranked_collide("/hi/<a..>", "/hi/"));
285 assert!(unranked_collide("/<a..>", "//////"));
286 }
287
288 #[test]
289 fn query_collisions() {
290 assert!(unranked_collide("/?<a>", "/?<a>"));
291 assert!(unranked_collide("/a/?<a>", "/a/?<a>"));
292 assert!(unranked_collide("/a?<a>", "/a?<a>"));
293 assert!(unranked_collide("/<r>?<a>", "/<r>?<a>"));
294 assert!(unranked_collide("/a/b/c?<a>", "/a/b/c?<a>"));
295 assert!(unranked_collide("/<a>/b/c?<d>", "/a/b/<c>?<d>"));
296 assert!(unranked_collide("/?<a>", "/"));
297 assert!(unranked_collide("/a?<a>", "/a"));
298 assert!(unranked_collide("/a?<a>", "/a"));
299 assert!(unranked_collide("/a/b?<a>", "/a/b"));
300 assert!(unranked_collide("/a/b", "/a/b?<c>"));
301 }
302
303 #[test]
304 fn non_collisions() {
305 assert!(!unranked_collide("/<a>", "/"));
306 assert!(!unranked_collide("/a", "/b"));
307 assert!(!unranked_collide("/a/b", "/a"));
308 assert!(!unranked_collide("/a/b", "/a/c"));
309 assert!(!unranked_collide("/a/hello", "/a/c"));
310 assert!(!unranked_collide("/hello", "/a/c"));
311 assert!(!unranked_collide("/hello/there", "/hello/there/guy"));
312 assert!(!unranked_collide("/a/<b>", "/b/<b>"));
313 assert!(!unranked_collide("/t", "/test"));
314 assert!(!unranked_collide("/a", "/aa"));
315 assert!(!unranked_collide("/a", "/aaa"));
316 assert!(!unranked_collide("/", "/a"));
317 }
318
319 #[test]
320 fn query_non_collisions() {
321 assert!(!unranked_collide("/a?<b>", "/b"));
322 assert!(!unranked_collide("/a/b", "/a?<b>"));
323 assert!(!unranked_collide("/a/b/c?<d>", "/a/b/c/d"));
324 assert!(!unranked_collide("/a/hello", "/a/?<hello>"));
325 assert!(!unranked_collide("/?<a>", "/hi"));
326 }
327
328 #[test]
329 fn method_dependent_non_collisions() {
330 assert!(!m_collide((Get, "/"), (Post, "/")));
331 assert!(!m_collide((Post, "/"), (Put, "/")));
332 assert!(!m_collide((Put, "/a"), (Put, "/")));
333 assert!(!m_collide((Post, "/a"), (Put, "/")));
334 assert!(!m_collide((Get, "/a"), (Put, "/")));
335 assert!(!m_collide((Get, "/hello"), (Put, "/hello")));
336 assert!(!m_collide((Get, "/<foo..>"), (Post, "/")));
337 }
338
339 #[test]
340 fn query_dependent_non_collisions() {
341 assert!(!m_collide((Get, "/"), (Get, "/?a")));
342 assert!(!m_collide((Get, "/"), (Get, "/?<a>")));
343 assert!(!m_collide((Get, "/a/<b>"), (Get, "/a/<b>?d")));
344 }
345
346 #[test]
347 fn test_str_non_collisions() {
348 assert!(!s_s_collide("/a", "/b"));
349 assert!(!s_s_collide("/a/b", "/a"));
350 assert!(!s_s_collide("/a/b", "/a/c"));
351 assert!(!s_s_collide("/a/hello", "/a/c"));
352 assert!(!s_s_collide("/hello", "/a/c"));
353 assert!(!s_s_collide("/hello/there", "/hello/there/guy"));
354 assert!(!s_s_collide("/a/<b>", "/b/<b>"));
355 assert!(!s_s_collide("/a", "/b"));
356 assert!(!s_s_collide("/a/b", "/a"));
357 assert!(!s_s_collide("/a/b", "/a/c"));
358 assert!(!s_s_collide("/a/hello", "/a/c"));
359 assert!(!s_s_collide("/hello", "/a/c"));
360 assert!(!s_s_collide("/hello/there", "/hello/there/guy"));
361 assert!(!s_s_collide("/a/<b>", "/b/<b>"));
362 assert!(!s_s_collide("/a", "/b"));
363 assert!(!s_s_collide("/a/b", "/a"));
364 assert!(!s_s_collide("/a/b", "/a/c"));
365 assert!(!s_s_collide("/a/hello", "/a/c"));
366 assert!(!s_s_collide("/hello", "/a/c"));
367 assert!(!s_s_collide("/hello/there", "/hello/there/guy"));
368 assert!(!s_s_collide("/a/<b>", "/b/<b>"));
369 assert!(!s_s_collide("/t", "/test"));
370 assert!(!s_s_collide("/a", "/aa"));
371 assert!(!s_s_collide("/a", "/aaa"));
372 assert!(!s_s_collide("/", "/a"));
373
374 assert!(s_s_collide("/a/hi/<a..>", "/a/hi/"));
375 assert!(s_s_collide("/hi/<a..>", "/hi/"));
376 assert!(s_s_collide("/<a..>", "/"));
377 }
378
379 fn mt_mt_collide(mt1: &str, mt2: &str) -> bool {
380 let mt_a = MediaType::from_str(mt1).expect(mt1);
381 let mt_b = MediaType::from_str(mt2).expect(mt2);
382 mt_a.collides_with(&mt_b)
383 }
384
385 #[test]
386 fn test_content_type_collisions() {
387 assert!(mt_mt_collide("application/json", "application/json"));
388 assert!(mt_mt_collide("*/json", "application/json"));
389 assert!(mt_mt_collide("*/*", "application/json"));
390 assert!(mt_mt_collide("application/*", "application/json"));
391 assert!(mt_mt_collide("application/*", "*/json"));
392 assert!(mt_mt_collide("something/random", "something/random"));
393
394 assert!(!mt_mt_collide("text/*", "application/*"));
395 assert!(!mt_mt_collide("*/text", "*/json"));
396 assert!(!mt_mt_collide("*/text", "application/test"));
397 assert!(!mt_mt_collide("something/random", "something_else/random"));
398 assert!(!mt_mt_collide("something/random", "*/else"));
399 assert!(!mt_mt_collide("*/random", "*/else"));
400 assert!(!mt_mt_collide("something/*", "random/else"));
401 }
402
403 fn r_mt_mt_collide<S1, S2>(m: Method, mt1: S1, mt2: S2) -> bool
404 where S1: Into<Option<&'static str>>, S2: Into<Option<&'static str>>
405 {
406 let mut route_a = Route::new(m, "/", dummy_handler);
407 if let Some(mt_str) = mt1.into() {
408 route_a.format = Some(mt_str.parse::<MediaType>().unwrap());
409 }
410
411 let mut route_b = Route::new(m, "/", dummy_handler);
412 if let Some(mt_str) = mt2.into() {
413 route_b.format = Some(mt_str.parse::<MediaType>().unwrap());
414 }
415
416 route_a.collides_with(&route_b)
417 }
418
419 #[test]
420 fn test_route_content_type_collisions() {
421 assert!(r_mt_mt_collide(Get, "application/json", "application/json"));
423 assert!(r_mt_mt_collide(Get, "*/json", "application/json"));
424 assert!(r_mt_mt_collide(Get, "*/json", "application/*"));
425 assert!(r_mt_mt_collide(Get, "text/html", "text/*"));
426 assert!(r_mt_mt_collide(Get, "any/thing", "*/*"));
427
428 assert!(r_mt_mt_collide(Get, None, "text/*"));
429 assert!(r_mt_mt_collide(Get, None, "text/html"));
430 assert!(r_mt_mt_collide(Get, None, "*/*"));
431 assert!(r_mt_mt_collide(Get, "text/html", None));
432 assert!(r_mt_mt_collide(Get, "*/*", None));
433 assert!(r_mt_mt_collide(Get, "application/json", None));
434
435 assert!(r_mt_mt_collide(Get, "application/*", "text/*"));
436 assert!(r_mt_mt_collide(Get, "application/json", "text/*"));
437 assert!(r_mt_mt_collide(Get, "application/json", "text/html"));
438 assert!(r_mt_mt_collide(Get, "text/html", "text/html"));
439
440 assert!(r_mt_mt_collide(Post, "application/json", "application/json"));
442 assert!(r_mt_mt_collide(Post, "*/json", "application/json"));
443 assert!(r_mt_mt_collide(Post, "*/json", "application/*"));
444 assert!(r_mt_mt_collide(Post, "text/html", "text/*"));
445 assert!(r_mt_mt_collide(Post, "any/thing", "*/*"));
446
447 assert!(r_mt_mt_collide(Post, None, "text/*"));
448 assert!(r_mt_mt_collide(Post, None, "text/html"));
449 assert!(r_mt_mt_collide(Post, None, "*/*"));
450 assert!(r_mt_mt_collide(Post, "text/html", None));
451 assert!(r_mt_mt_collide(Post, "*/*", None));
452 assert!(r_mt_mt_collide(Post, "application/json", None));
453
454 assert!(!r_mt_mt_collide(Post, "text/html", "application/*"));
455 assert!(!r_mt_mt_collide(Post, "application/html", "text/*"));
456 assert!(!r_mt_mt_collide(Post, "*/json", "text/html"));
457 assert!(!r_mt_mt_collide(Post, "text/html", "text/css"));
458 assert!(!r_mt_mt_collide(Post, "other/html", "text/html"));
459 }
460
461 fn req_route_mt_collide<S1, S2>(m: Method, mt1: S1, mt2: S2) -> bool
462 where S1: Into<Option<&'static str>>, S2: Into<Option<&'static str>>
463 {
464 let client = Client::debug_with(vec![]).expect("client");
465 let mut req = client.req(m, "/");
466 if let Some(mt_str) = mt1.into() {
467 if m.supports_payload() {
468 req.replace_header(mt_str.parse::<ContentType>().unwrap());
469 } else {
470 req.replace_header(mt_str.parse::<Accept>().unwrap());
471 }
472 }
473
474 let mut route = Route::new(m, "/", dummy_handler);
475 if let Some(mt_str) = mt2.into() {
476 route.format = Some(mt_str.parse::<MediaType>().unwrap());
477 }
478
479 route.matches(&req)
480 }
481
482 #[test]
483 fn test_req_route_mt_collisions() {
484 assert!(req_route_mt_collide(Post, "application/json", "application/json"));
485 assert!(req_route_mt_collide(Post, "application/json", "application/*"));
486 assert!(req_route_mt_collide(Post, "application/json", "*/json"));
487 assert!(req_route_mt_collide(Post, "text/html", "*/*"));
488
489 assert!(req_route_mt_collide(Get, "application/json", "application/json"));
490 assert!(req_route_mt_collide(Get, "text/html", "text/html"));
491 assert!(req_route_mt_collide(Get, "text/html", "*/*"));
492 assert!(req_route_mt_collide(Get, None, "*/*"));
493 assert!(req_route_mt_collide(Get, None, "text/*"));
494 assert!(req_route_mt_collide(Get, None, "text/html"));
495 assert!(req_route_mt_collide(Get, None, "application/json"));
496
497 assert!(req_route_mt_collide(Post, "text/html", None));
498 assert!(req_route_mt_collide(Post, "application/json", None));
499 assert!(req_route_mt_collide(Post, "x-custom/anything", None));
500 assert!(req_route_mt_collide(Post, None, None));
501
502 assert!(req_route_mt_collide(Get, "text/html", None));
503 assert!(req_route_mt_collide(Get, "application/json", None));
504 assert!(req_route_mt_collide(Get, "x-custom/anything", None));
505 assert!(req_route_mt_collide(Get, None, None));
506 assert!(req_route_mt_collide(Get, None, "text/html"));
507 assert!(req_route_mt_collide(Get, None, "application/json"));
508
509 assert!(req_route_mt_collide(Get, "text/html, text/plain", "text/html"));
510 assert!(req_route_mt_collide(Get, "text/html; q=0.5, text/xml", "text/xml"));
511
512 assert!(!req_route_mt_collide(Post, None, "text/html"));
513 assert!(!req_route_mt_collide(Post, None, "text/*"));
514 assert!(!req_route_mt_collide(Post, None, "*/text"));
515 assert!(!req_route_mt_collide(Post, None, "*/*"));
516 assert!(!req_route_mt_collide(Post, None, "text/html"));
517 assert!(!req_route_mt_collide(Post, None, "application/json"));
518
519 assert!(!req_route_mt_collide(Post, "application/json", "text/html"));
520 assert!(!req_route_mt_collide(Post, "application/json", "text/*"));
521 assert!(!req_route_mt_collide(Post, "application/json", "*/xml"));
522 assert!(!req_route_mt_collide(Get, "application/json", "text/html"));
523 assert!(!req_route_mt_collide(Get, "application/json", "text/*"));
524 assert!(!req_route_mt_collide(Get, "application/json", "*/xml"));
525
526 assert!(!req_route_mt_collide(Post, None, "text/html"));
527 assert!(!req_route_mt_collide(Post, None, "application/json"));
528 }
529
530 fn req_route_path_match(a: &'static str, b: &'static str) -> bool {
531 let client = Client::debug_with(vec![]).expect("client");
532 let req = client.get(Origin::parse(a).expect("valid URI"));
533 let route = Route::ranked(0, Get, b, dummy_handler);
534 route.matches(&req)
535 }
536
537 #[test]
538 fn test_req_route_query_collisions() {
539 assert!(req_route_path_match("/a/b?a=b", "/a/b?<c>"));
540 assert!(req_route_path_match("/a/b?a=b", "/<a>/b?<c>"));
541 assert!(req_route_path_match("/a/b?a=b", "/<a>/<b>?<c>"));
542 assert!(req_route_path_match("/a/b?a=b", "/a/<b>?<c>"));
543 assert!(req_route_path_match("/?b=c", "/?<b>"));
544
545 assert!(req_route_path_match("/a/b?a=b", "/a/b"));
546 assert!(req_route_path_match("/a/b", "/a/b"));
547 assert!(req_route_path_match("/a/b/c/d?", "/a/b/c/d"));
548 assert!(req_route_path_match("/a/b/c/d?v=1&v=2", "/a/b/c/d"));
549
550 assert!(req_route_path_match("/a/b", "/a/b?<c>"));
551 assert!(req_route_path_match("/a/b", "/a/b?<c..>"));
552 assert!(req_route_path_match("/a/b?c", "/a/b?c"));
553 assert!(req_route_path_match("/a/b?c", "/a/b?<c>"));
554 assert!(req_route_path_match("/a/b?c=foo&d=z", "/a/b?<c>"));
555 assert!(req_route_path_match("/a/b?c=foo&d=z", "/a/b?<c..>"));
556
557 assert!(req_route_path_match("/a/b?c=foo&d=z", "/a/b?c=foo&<c..>"));
558 assert!(req_route_path_match("/a/b?c=foo&d=z", "/a/b?d=z&<c..>"));
559
560 assert!(!req_route_path_match("/a/b/c", "/a/b?<c>"));
561 assert!(!req_route_path_match("/a?b=c", "/a/b?<c>"));
562 assert!(!req_route_path_match("/?b=c", "/a/b?<c>"));
563 assert!(!req_route_path_match("/?b=c", "/a?<c>"));
564
565 assert!(!req_route_path_match("/a/b?c=foo&d=z", "/a/b?a=b&<c..>"));
566 assert!(!req_route_path_match("/a/b?c=foo&d=z", "/a/b?d=b&<c..>"));
567 assert!(!req_route_path_match("/a/b", "/a/b?c"));
568 assert!(!req_route_path_match("/a/b", "/a/b?foo"));
569 assert!(!req_route_path_match("/a/b", "/a/b?foo&<rest..>"));
570 assert!(!req_route_path_match("/a/b", "/a/b?<a>&b&<rest..>"));
571 }
572
573
574 fn catchers_collide<A, B>(a: A, ap: &str, b: B, bp: &str) -> bool
575 where A: Into<Option<u16>>, B: Into<Option<u16>>
576 {
577 use crate::catcher::dummy_handler as handler;
578
579 let a = Catcher::new(a, handler).map_base(|_| ap.into()).unwrap();
580 let b = Catcher::new(b, handler).map_base(|_| bp.into()).unwrap();
581 a.collides_with(&b)
582 }
583
584 #[test]
585 fn catcher_collisions() {
586 for path in &["/a", "/foo", "/a/b/c", "/a/b/c/d/e"] {
587 assert!(catchers_collide(404, path, 404, path));
588 assert!(catchers_collide(500, path, 500, path));
589 assert!(catchers_collide(None, path, None, path));
590 }
591 }
592
593 #[test]
594 fn catcher_non_collisions() {
595 assert!(!catchers_collide(404, "/foo", 405, "/foo"));
596 assert!(!catchers_collide(404, "/", None, "/foo"));
597 assert!(!catchers_collide(404, "/", None, "/"));
598 assert!(!catchers_collide(404, "/a/b", None, "/a/b"));
599 assert!(!catchers_collide(404, "/a/b", 404, "/a/b/c"));
600
601 assert!(!catchers_collide(None, "/a/b", None, "/a/b/c"));
602 assert!(!catchers_collide(None, "/b", None, "/a/b/c"));
603 assert!(!catchers_collide(None, "/", None, "/a/b/c"));
604 }
605}