uri_parsing_rs/parser/parsers/
query_parsers.rs

1use nom::branch::alt;
2use nom::character::complete;
3use nom::combinator::{map, opt};
4use nom::error::context;
5use nom::multi::many0;
6use nom::sequence::{preceded, tuple};
7
8use crate::ast::query::Query;
9use crate::parser::parsers::{Elms, UResult};
10use crate::parser::parsers::basic_parsers::pchar_without_eq_and;
11
12#[inline]
13fn code_point(i: Elms) -> UResult<Elms, String> {
14  map(
15    many0(alt((
16      pchar_without_eq_and,
17      map(complete::char('/'), |c| c.into()),
18      map(complete::char('?'), |c| c.into()),
19    ))),
20    |s| s.into_iter().collect(),
21  )(i)
22}
23
24// query = *( pchar / "/" / "?" )
25#[inline]
26pub fn query(i: Elms) -> UResult<Elms, Query> {
27  let key_values = || tuple((code_point, opt(preceded(complete::char('='), code_point))));
28  context(
29    "query",
30    map(
31      tuple((
32        key_values(),
33        many0(preceded(complete::char('&'), key_values())),
34      )),
35      |(head, tail)| {
36        let mut m = vec![head];
37        m.extend(tail);
38        Query::new(m)
39      },
40    ),
41  )(i)
42}
43
44#[cfg(test)]
45pub mod gens {
46  use itertools::Itertools;
47  use prop_check_rs::gen::{Gen, Gens};
48
49  use crate::parser::parsers::basic_parsers::gens::*;
50
51  fn sub_delims_without_char_gen() -> Gen<char> {
52    Gens::one_of_vec(vec!['!', '$', '\'', '(', ')', '*', '+', ',', ';'])
53  }
54
55  fn sub_delims_without_str_gen(len: u8) -> Gen<String> {
56    rep_char_gen(len, || sub_delims_without_char_gen())
57  }
58
59  pub fn pchar_without_eq_and_str_gen(min: u8, max: u8) -> Gen<String> {
60    rep_str_gen(min, max, || {
61      Gens::choose_u8(1, 4).bind(|n| match n {
62        1 => unreserved_char_gen().fmap(|c| c.into()),
63        2 => pct_encoded_str_gen(),
64        3 => sub_delims_without_char_gen().fmap(|c| c.into()),
65        4 => Gens::one_of_vec(vec![':', '@']).fmap(|c| c.into()),
66        x => panic!("x = {}", x),
67      })
68    })
69  }
70
71  pub fn query_gen() -> Gen<String> {
72    Gens::list_of_n(3, move || {
73      pchar_without_eq_and_str_gen(1, 10).bind(|key| {
74        Gens::list_of_n(2, || pchar_without_eq_and_str_gen(1, 10)).fmap(move |vl| {
75          let kvl = vl
76            .into_iter()
77            .map(|v| format!("{}={}", key, v))
78            .collect_vec();
79          kvl.join("&")
80        })
81      })
82    })
83    .fmap(|v| v.join("&"))
84  }
85}
86
87#[cfg(test)]
88mod tests {
89  use std::env;
90
91  use anyhow::Result;
92
93  use nom::multi::many1;
94
95  use prop_check_rs::prop;
96  use prop_check_rs::prop::TestCases;
97  use prop_check_rs::rng::RNG;
98
99  use crate::parser::parsers::Elms;
100
101  use super::*;
102  use super::gens::*;
103
104  const TEST_COUNT: TestCases = 100;
105
106  fn init() {
107    env::set_var("RUST_LOG", "debug");
108    let _ = env_logger::builder().is_test(true).try_init();
109  }
110
111  #[test]
112  fn test_pchar_without_eq_and() -> Result<()> {
113    init();
114    let mut counter = 0;
115    let prop = prop::for_all(
116      || pchar_without_eq_and_str_gen(1, u8::MAX - 1),
117      move |s| {
118        counter += 1;
119        log::debug!("{:>03}, value = {}", counter, s);
120        let (_, r) = many1(pchar_without_eq_and)(Elms::new(s.as_bytes()))
121          .ok()
122          .unwrap();
123        r.into_iter().collect::<String>() == s
124      },
125    );
126    prop::test_with_prop(prop, 5, TEST_COUNT, RNG::new())
127  }
128
129  #[test]
130  fn test_query() -> Result<()> {
131    init();
132    let mut counter = 0;
133    let prop = prop::for_all(
134      || query_gen(),
135      move |s| {
136        counter += 1;
137        log::debug!("{:>03}, query = {}", counter, s);
138        let (_, query) = query(Elms::new(s.as_bytes())).ok().unwrap();
139        log::debug!("as_string = {:?}", query.as_string());
140        let params = query.params();
141        log::debug!("params = {:?}", params);
142        true
143      },
144    );
145    prop::test_with_prop(prop, 5, TEST_COUNT, RNG::new())
146  }
147}