uri_rs/parser/parsers/
authority_parsers.rs1use nom::character::complete;
2use nom::combinator::{map, opt};
3use nom::error::context;
4use nom::sequence::{preceded, terminated, tuple};
5
6use crate::ast::authority::Authority;
7use crate::parser::parsers::{Elms, host_parsers, port_parsers, UResult, user_info_parsers};
8
9#[inline]
10pub(crate) fn authority(i: Elms) -> UResult<Elms, Authority> {
11 context(
12 "authority",
13 map(
14 tuple((
15 opt(terminated(
16 user_info_parsers::user_info,
17 complete::char('@'),
18 )),
19 host_parsers::host_name,
20 opt(preceded(complete::char(':'), port_parsers::port)),
21 )),
22 |(ui, h, p)| Authority::new(h, p, ui),
23 ),
24 )(i)
25}
26
27#[cfg(test)]
28pub mod gens {
29 use prop_check_rs::gen::Gen;
30
31 use crate::parser::parsers::basic_parsers::gens::to_option;
32 use crate::parser::parsers::host_parsers::gens::host_gen;
33 use crate::parser::parsers::port_parsers::gens::port_gen;
34 use crate::parser::parsers::user_info_parsers::gens::user_info_gen;
35
36 pub fn authority_gen() -> Gen<String> {
37 let user_info_opt_gen = || to_option(|| user_info_gen());
38 let port_opt_gen = || to_option(|| port_gen());
39
40 user_info_opt_gen().bind(move |ui| {
41 host_gen()
42 .bind(move |h| {
43 port_opt_gen().fmap(move |p| {
44 let p = p.map(|s| format!(":{}", s)).unwrap_or("".to_string());
45 format!("{}{}", h, p)
46 })
47 })
48 .fmap(move |hp| {
49 let ui = ui
50 .as_ref()
51 .map(|s| format!("{}@", s))
52 .unwrap_or("".to_string());
53 format!("{}{}", ui, hp)
54 })
55 })
56 }
57}
58
59#[cfg(test)]
60mod tests {
61 use std::env;
62
63 use anyhow::Result;
64 use prop_check_rs::prop;
65 use prop_check_rs::prop::TestCases;
66 use prop_check_rs::rng::RNG;
67
68 use super::*;
69 use super::gens::*;
70
71 const TEST_COUNT: TestCases = 100;
72
73 fn init() {
74 env::set_var("RUST_LOG", "debug");
75 let _ = env_logger::builder().is_test(true).try_init();
76 }
77
78 #[test]
79 fn test_authority() -> Result<()> {
80 init();
81 let mut counter = 0;
82 let prop = prop::for_all(
83 || authority_gen(),
84 move |s| {
85 counter += 1;
86 log::debug!("{:>03}, authority = {}", counter, s);
87 let (_, authority) = authority(Elms::new(s.as_bytes())).ok().unwrap();
88 assert_eq!(authority.to_string(), s);
89 true
90 },
91 );
92 prop::test_with_prop(prop, 5, TEST_COUNT, RNG::new())
93 }
94}