From 974723226e94fb5d00f1308950473202e53fd6bf Mon Sep 17 00:00:00 2001 From: Andrew Toth Date: Sun, 22 Oct 2023 16:45:34 -0400 Subject: [PATCH] add more http types --- fake/examples/fakers.rs | 30 ++++++++ fake/src/impls/http/mod.rs | 149 ++++++++++++++++++++++++++++++------- 2 files changed, 152 insertions(+), 27 deletions(-) diff --git a/fake/examples/fakers.rs b/fake/examples/fakers.rs index bea1b1c..ad077f7 100644 --- a/fake/examples/fakers.rs +++ b/fake/examples/fakers.rs @@ -330,6 +330,36 @@ fn http_faker() { let val: http::Version = Faker.fake(); println!("{:?}", val); + + let val: http::Method = Faker.fake(); + println!("{:?}", val); + + let val: http::HeaderName = Faker.fake(); + println!("{:?}", val); + + let val: http::HeaderValue = Faker.fake(); + println!("{:?}", val); + + let val: http::HeaderMap = Faker.fake(); + println!("{:?}", val); + + let val: http::uri::Scheme = Faker.fake(); + println!("{:?}", val); + + let val: http::uri::Authority = Faker.fake(); + println!("{:?}", val); + + let val: http::uri::PathAndQuery = Faker.fake(); + println!("{:?}", val); + + let val: http::Uri = Faker.fake(); + println!("{:?}", val); + + let val: http::Request = Faker.fake(); + println!("{:?}", val); + + let val: http::Response = Faker.fake(); + println!("{:?}", val); } #[cfg(feature = "chrono")] diff --git a/fake/src/impls/http/mod.rs b/fake/src/impls/http/mod.rs index 5a05b91..f3474b2 100644 --- a/fake/src/impls/http/mod.rs +++ b/fake/src/impls/http/mod.rs @@ -2,6 +2,7 @@ use crate::{Dummy, Fake, Faker}; use http::uri; use rand::seq::SliceRandom; use rand::Rng; +use std::mem; use std::net::Ipv4Addr; use std::str::FromStr; @@ -19,6 +20,55 @@ const VALID_SCHEME_CHARACTERS: &[char] = &[ '5', '6', '7', '8', '9', '.', '-', '+', ]; +impl Dummy for http::Method { + fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { + let i: u8 = (0..9).fake_with_rng(rng); + match i { + 0 => http::Method::GET, + 1 => http::Method::POST, + 2 => http::Method::PUT, + 3 => http::Method::DELETE, + 4 => http::Method::HEAD, + 5 => http::Method::OPTIONS, + 6 => http::Method::CONNECT, + 7 => http::Method::PATCH, + _ => http::Method::TRACE, + } + } +} + +impl Dummy for http::HeaderValue { + fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { + let val = config.fake_with_rng::(rng); + http::HeaderValue::try_from(val).unwrap() + } +} + +impl Dummy for http::HeaderName { + fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { + let val = config.fake_with_rng::(rng); + http::HeaderName::try_from(val).unwrap() + } +} + +impl> Dummy for http::HeaderMap { + fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { + let len = rng.gen_range(1..10); + let mut map = http::HeaderMap::with_capacity(len); + for _ in 0..len { + let name: http::HeaderName = config.fake_with_rng(rng); + if rng.gen_bool(0.7) { + map.insert(name, config.fake_with_rng(rng)); + } else { + for _ in 0..rng.gen_range(1..5) { + map.append(&name, config.fake_with_rng(rng)); + } + } + } + map + } +} + impl Dummy for http::StatusCode { fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { let code = RFC_STATUS_CODES.choose(rng).unwrap(); @@ -52,33 +102,8 @@ impl Dummy for http::Version { } } -impl Dummy for http::Uri { +impl Dummy for http::uri::Authority { fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { - // Some common schemes or a random valid scheme - let scheme = match (0..7).fake_with_rng(rng) { - 0 => "http".to_string(), - 1 => "https".to_string(), - 2 => "ws".to_string(), - 3 => "wss".to_string(), - 4 => "ftp".to_string(), - 5 => "git".to_string(), - _ => { - // A valid scheme is any letter followed by any combination of letters, digits, '+', - // '.', '-'. Looking at a list of know schemes 28 seems to be the longest so I'll - // generate one a max of that long. - - let len = rng.gen_range(1..29); - let mut scheme = String::with_capacity(len); - scheme.push(rng.gen_range(b'a'..=b'z') as char); - if rng.gen_bool(0.5) { - scheme.make_ascii_uppercase(); - } - scheme.extend((1..len).map(|_| *VALID_SCHEME_CHARACTERS.choose(rng).unwrap())); - - scheme - } - }; - let mut authority = String::new(); if rng.gen_bool(0.5) { @@ -127,7 +152,42 @@ impl Dummy for http::Uri { } } } + uri::Authority::try_from(authority).unwrap() + } +} +impl Dummy for http::uri::Scheme { + fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { + // Some common schemes or a random valid scheme + let scheme = match (0..7).fake_with_rng(rng) { + 0 => "http".to_string(), + 1 => "https".to_string(), + 2 => "ws".to_string(), + 3 => "wss".to_string(), + 4 => "ftp".to_string(), + 5 => "git".to_string(), + _ => { + // A valid scheme is any letter followed by any combination of letters, digits, '+', + // '.', '-'. Looking at a list of know schemes 28 seems to be the longest so I'll + // generate one a max of that long. + + let len = rng.gen_range(1..29); + let mut scheme = String::with_capacity(len); + scheme.push(rng.gen_range(b'a'..=b'z') as char); + if rng.gen_bool(0.5) { + scheme.make_ascii_uppercase(); + } + scheme.extend((1..len).map(|_| *VALID_SCHEME_CHARACTERS.choose(rng).unwrap())); + + scheme + } + }; + uri::Scheme::from_str(&scheme).unwrap() + } +} + +impl Dummy for http::uri::PathAndQuery { + fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { let mut path = format!( "/{}", url_escape::encode_path(&config.fake_with_rng::(rng)) @@ -146,9 +206,18 @@ impl Dummy for http::Uri { } path.push_str(&query_parts.join("&")); } + uri::PathAndQuery::try_from(path).unwrap() + } +} + +impl Dummy for http::Uri { + fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { + let scheme = config.fake_with_rng::(rng); + let authority = config.fake_with_rng::(rng); + let path = config.fake_with_rng::(rng); uri::Builder::new() - .scheme(uri::Scheme::from_str(&scheme).unwrap()) + .scheme(scheme) .authority(authority) .path_and_query(path) .build() @@ -156,6 +225,32 @@ impl Dummy for http::Uri { } } +impl> Dummy for http::Request { + fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { + let method: http::Method = config.fake_with_rng(rng); + let uri: http::Uri = config.fake_with_rng(rng); + let mut req = http::Request::builder() + .method(method) + .uri(uri) + .version(config.fake_with_rng(rng)); + let mut headers: http::HeaderMap = config.fake_with_rng(rng); + mem::swap(req.headers_mut().unwrap(), &mut headers); + req.body(config.fake_with_rng(rng)).unwrap() + } +} + +impl> Dummy for http::Response { + fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { + let status: http::StatusCode = config.fake_with_rng(rng); + let mut res = http::Response::builder() + .status(status) + .version(config.fake_with_rng(rng)); + let mut headers: http::HeaderMap = config.fake_with_rng(rng); + mem::swap(res.headers_mut().unwrap(), &mut headers); + res.body(config.fake_with_rng(rng)).unwrap() + } +} + #[cfg(test)] mod tests { use super::*;