#![allow(dead_code)]
use proptest::prelude::*;
pub fn scheme_strategy() -> impl Strategy<Value = String> {
let first_char = prop::sample::select(('a'..='z').collect::<Vec<_>>());
let rest_chars = prop::collection::vec(
prop::sample::select(
('a'..='z').chain('0'..='9').chain(['+', '-', '.']).collect::<Vec<_>>(),
),
0..8,
);
(first_char, rest_chars).prop_map(|(first, rest)| {
let mut s = String::with_capacity(1 + rest.len());
s.push(first);
for c in rest {
s.push(c);
}
s
})
}
pub fn special_scheme_strategy() -> impl Strategy<Value = String> {
prop::sample::select(vec![
"http".to_string(),
"https".to_string(),
"ws".to_string(),
"wss".to_string(),
"ftp".to_string(),
])
}
pub fn host_strategy() -> impl Strategy<Value = String> {
let label = "[a-wyz][a-z0-9]{1,10}";
prop::string::string_regex(&format!("{}(\\.{})?(\\.{})?", label, label, label))
.expect("valid regex")
}
pub fn port_strategy() -> impl Strategy<Value = Option<u16>> { prop::option::of(any::<u16>()) }
pub fn path_strategy() -> impl Strategy<Value = String> {
prop::option::of(prop::string::string_regex("/[a-zA-Z0-9_~/-]{0,50}").expect("valid regex"))
.prop_map(|opt| opt.unwrap_or_default())
}
pub fn query_strategy() -> impl Strategy<Value = Option<String>> {
prop::option::of(prop::string::string_regex("[a-zA-Z0-9_.~=&-]{1,30}").expect("valid regex"))
}
pub fn fragment_strategy() -> impl Strategy<Value = Option<String>> {
prop::option::of(prop::string::string_regex("[a-zA-Z0-9_.~-]{1,20}").expect("valid regex"))
}
pub fn userinfo_strategy() -> impl Strategy<Value = (String, Option<String>)> {
let username =
prop::option::of(prop::string::string_regex("[a-zA-Z0-9_-]{1,10}").expect("valid regex"))
.prop_map(|opt| opt.unwrap_or_default());
let password =
prop::option::of(prop::string::string_regex("[a-zA-Z0-9_-]{1,10}").expect("valid regex"));
(username, password)
}
#[derive(Debug, Clone)]
pub struct ValidUrl {
pub url_string: String,
pub scheme: String,
pub host: String,
pub port: Option<u16>,
pub path: String,
pub query: Option<String>,
pub fragment: Option<String>,
}
fn is_known_scheme(scheme: &str) -> bool {
matches!(scheme, "http" | "https" | "ws" | "wss" | "ftp")
}
pub fn valid_url_strategy() -> impl Strategy<Value = ValidUrl> {
(
scheme_strategy(),
host_strategy(),
any::<u16>(), port_strategy(), path_strategy(),
query_strategy(),
fragment_strategy(),
)
.prop_map(|(scheme, host, port_value, optional_port, path, query, fragment)| {
let port = if is_known_scheme(&scheme) { optional_port } else { Some(port_value) };
let mut url_string = format!("{}://{}", scheme, host);
if let Some(p) = port {
url_string.push_str(&format!(":{}", p));
}
url_string.push_str(&path);
if let Some(ref q) = query {
url_string.push('?');
url_string.push_str(q);
}
if let Some(ref f) = fragment {
url_string.push('#');
url_string.push_str(f);
}
ValidUrl { url_string, scheme, host, port, path, query, fragment }
})
}
pub fn url_string_strategy() -> impl Strategy<Value = String> {
valid_url_strategy().prop_map(|v| v.url_string)
}
pub fn special_url_string_strategy() -> impl Strategy<Value = String> {
(
special_scheme_strategy(),
userinfo_strategy(),
host_strategy(),
port_strategy(),
path_strategy(),
query_strategy(),
fragment_strategy(),
)
.prop_map(|(scheme, (username, password), host, port, path, query, fragment)| {
let mut url_string = format!("{}://", scheme);
if !username.is_empty() {
url_string.push_str(&username);
if let Some(ref pw) = password {
url_string.push(':');
url_string.push_str(pw);
}
url_string.push('@');
}
url_string.push_str(&host);
if let Some(p) = port {
url_string.push_str(&format!(":{}", p));
}
url_string.push_str(&path);
if let Some(ref q) = query {
url_string.push('?');
url_string.push_str(q);
}
if let Some(ref f) = fragment {
url_string.push('#');
url_string.push_str(f);
}
url_string
})
}