uri_parsing_rs/parser/parsers/
user_info_parsers.rs

1use nom::branch::alt;
2use nom::character::complete;
3use nom::combinator::{map, opt};
4use nom::error::context;
5use nom::multi::many1;
6use nom::sequence::{preceded, tuple};
7
8use crate::ast::user_info::UserInfo;
9use crate::parser::parsers::{Elms, UResult};
10use crate::parser::parsers::basic_parsers::{pct_encoded, sub_delims, unreserved};
11
12#[inline]
13fn code_point(i: Elms) -> UResult<Elms, String> {
14  map(
15    many1(alt((
16      map(unreserved, |c| c.into()),
17      pct_encoded,
18      map(sub_delims, |c| c.into()),
19    ))),
20    |sl| sl.into_iter().collect(),
21  )(i)
22}
23
24// *( unreserved / pct-encoded / sub-delims / ":" )
25#[inline]
26pub(crate) fn user_info(i: Elms) -> UResult<Elms, UserInfo> {
27  context(
28    "user_info",
29    map(
30      tuple((code_point, opt(preceded(complete::char(':'), code_point)))),
31      |(user_name, password)| (user_name.as_str(), password.as_ref().map(|s| s.as_str())).into(),
32    ),
33  )(i)
34}
35
36#[cfg(test)]
37pub mod gens {
38  use prop_check_rs::gen::{Gen, Gens};
39
40  use crate::parser::parsers::basic_parsers::gens::*;
41
42  pub fn user_info_gen() -> Gen<String> {
43    let gen = || {
44      rep_str_gen(1, 5, || {
45        Gens::choose_u8(1, 3).bind(|n| match n {
46          1 => unreserved_str_gen(1),
47          2 => pct_encoded_str_gen(),
48          3 => sub_delims_str_gen(1),
49          x => panic!("x = {}", x),
50        })
51      })
52    };
53    Gens::one_bool().bind(move |b| {
54      if b {
55        gen().bind(move |s1| gen().fmap(move |s2| format!("{}:{}", s1, s2)))
56      } else {
57        gen().fmap(|s| format!("{}", s))
58      }
59    })
60  }
61}
62
63#[cfg(test)]
64mod tests {
65  use std::env;
66
67  use anyhow::Result;
68  use prop_check_rs::prop;
69  use prop_check_rs::prop::TestCases;
70  use prop_check_rs::rng::RNG;
71
72  use super::*;
73  use super::gens::*;
74
75  const TEST_COUNT: TestCases = 100;
76
77  fn init() {
78    env::set_var("RUST_LOG", "debug");
79    let _ = env_logger::builder().is_test(true).try_init();
80  }
81
82  #[test]
83  fn test_user_info() -> Result<()> {
84    init();
85    let mut counter = 0;
86    let prop = prop::for_all(
87      || user_info_gen(),
88      move |s| {
89        counter += 1;
90        log::debug!("{:>03}, user_info = {}", counter, s);
91        let (_, r) = user_info(Elms::new(s.as_bytes())).ok().unwrap();
92        assert_eq!(r.to_string(), s);
93        true
94      },
95    );
96    prop::test_with_prop(prop, 5, TEST_COUNT, RNG::new())
97  }
98}