use crate::Request;
use http::status::StatusCode;
use std::convert::TryInto;
use std::str::FromStr;
#[derive(Debug, Clone)]
pub struct Response {
pub(super) headers: Vec<(String, String)>,
pub(super) body: Vec<u8>,
pub(super) status: StatusCode,
}
impl Default for Response {
fn default() -> Self {
Self {
body: Vec::new(),
headers: Vec::new(),
status: http::StatusCode::default(),
}
}
}
#[derive(Debug, Clone)]
pub struct Mock {
pub(super) path: String,
pub(super) method: String,
pub(super) response: Response,
pub(super) host: Option<String>,
}
impl Mock {
pub fn new(method: &str, path: &str) -> Self {
let fake_base = url::Url::from_str("https://fake_base.com").unwrap();
let url = url::Url::options()
.base_url(Some(&fake_base))
.parse(path)
.expect("failed to parse");
let mut qs = &url::form_urlencoded::Serializer::new(String::new())
.extend_pairs(url.query_pairs())
.finish();
let bit;
if !qs.is_empty() {
bit = "?".to_owned() + &qs.to_owned();
qs = &bit;
}
Self {
method: method.to_string(),
path: url.path().to_string() + qs,
host: if url.host() == fake_base.host() {
None
} else {
url.host().map(|f| f.to_string())
},
response: Response::default(),
}
}
pub fn with_body_from_file(
&mut self,
filename: &str,
) -> Result<&mut Self, Box<dyn std::error::Error>> {
self.response.body = std::fs::read(filename)?;
Ok(self)
}
pub fn with_body_from_json<T>(
&mut self,
value: T,
) -> Result<&mut Self, Box<dyn std::error::Error>>
where
T: Into<json::JsonValue>,
{
self.response.body = json::stringify_pretty(value, 2).as_bytes().to_vec();
Ok(self)
}
pub fn with_header<K, V>(&mut self, name: K, value: V) -> &mut Self
where
K: ToString,
V: ToString,
{
self.response
.headers
.push((name.to_string(), value.to_string()));
self
}
pub fn with_status<T>(&mut self, status: T) -> &mut Self
where
T: TryInto<http::StatusCode>,
{
self.response.status = match status.try_into() {
Ok(status) => status,
Err(_) => panic!("Bad status"),
};
self
}
pub fn create(&self) -> Self {
self.clone()
}
pub(super) fn matches(&self, request: &Request) -> bool {
let host_match = match &self.host {
Some(host) => {
host == request
.host
.as_ref()
.expect("Expected request to have a host")
}
None => true,
};
host_match
&& &self.path == request.path.as_ref().unwrap()
&& &self.method == request.method.as_ref().unwrap()
}
}