proptest_http_message/request_line/target/
origin_form.rs1use std::{num::NonZero, ops::RangeInclusive};
4
5use proptest::prelude::Strategy;
6
7use super::components::{
8 path::{Path, path_absolute},
9 query::{QueryParam, query},
10};
11
12#[derive(Debug)]
14pub struct OriginForm {
15 pub path: Path,
16 pub query: Option<Vec<QueryParam>>,
17}
18
19pub fn origin(
23 max_segments: NonZero<usize>,
24 query_count_range: RangeInclusive<usize>,
25) -> impl Strategy<Value = (OriginForm, String)> {
26 (path_absolute(max_segments), query(*query_count_range.start(), *query_count_range.end()))
27 .prop_map(|((path, path_repr), (query, query_repr))| {
28 if query.is_empty() {
29 (OriginForm { path, query: None }, path_repr)
30 } else {
31 let repr = format!("{path_repr}?{query_repr}");
32 (OriginForm { path, query: Some(query) }, repr)
33 }
34 })
35}
36
37#[cfg(test)]
38pub(super) mod tests {
39 use std::sync::LazyLock;
40
41 use claims::assert_ok;
42 use proptest::proptest;
43 use url::Url;
44
45 use super::*;
46
47 const DUMMY_BASE_URL: &str = "https://example.com";
48 static BASE_URL: LazyLock<Url> = LazyLock::new(|| {
49 Url::parse(DUMMY_BASE_URL).unwrap_or_else(|_| panic!("{DUMMY_BASE_URL:?} is a valid base URL"))
50 });
51
52 pub(in super::super) fn origin_asserts(origin: &OriginForm, repr: &str) {
53 let url = assert_ok!(BASE_URL.join(repr));
54
55 assert_eq!(
56 origin.path.normalized,
57 url.path(),
58 "expected path {:?} but parsed {}",
59 origin.path.normalized,
60 url.path()
61 );
62
63 match (origin.query.as_deref(), url.query()) {
64 (None, None) => {}
65 (Some(query), Some(query2)) => {
66 let query = query
67 .iter()
68 .map(|query| format!("{}={}", query.key, query.value.as_deref().unwrap_or_default()))
69 .collect::<Vec<_>>()
70 .join("&");
71 assert_eq!(query, query2, "expected query {query:?} but parsed {query2:?}");
72 }
73 (query, query2) => panic!("expected query {query:?} but got {query2:?}"),
74 }
75 }
76
77 proptest! {
78 #[test]
79 fn origin_works((origin, repr) in origin(50.try_into().unwrap(), 0..=20)) {
80 origin_asserts(&origin, &repr);
81 }
82 }
83}