use std::error;
use std::fmt;
pub trait HttpResponse: std::io::Read + fmt::Debug
where
Self: ::std::marker::Sized,
{
fn headers(&self) -> &reqwest::header::HeaderMap;
fn status(&self) -> reqwest::StatusCode;
fn error_for_status(self) -> Result<Self, Box<dyn error::Error>>;
}
impl HttpResponse for reqwest::blocking::Response {
fn headers(&self) -> &reqwest::header::HeaderMap {
self.headers()
}
fn status(&self) -> reqwest::StatusCode {
self.status()
}
fn error_for_status(self) -> Result<Self, Box<dyn error::Error>> {
Ok(self.error_for_status()?)
}
}
pub trait Client {
type Response: HttpResponse;
fn execute(
&self,
request: reqwest::blocking::Request,
) -> Result<Self::Response, Box<dyn error::Error>>;
}
impl Client for reqwest::blocking::Client {
type Response = reqwest::blocking::Response;
fn execute(
&self,
request: reqwest::blocking::Request,
) -> Result<Self::Response, Box<dyn error::Error>> {
Ok(self.execute(request)?)
}
}
#[cfg(test)]
pub mod tests {
use reqwest;
use std::cell;
use std::fmt;
use std::io;
use std::error::Error;
use std::io::Read;
#[derive(Debug, Eq, PartialEq, Hash)]
pub struct FakeError;
impl fmt::Display for FakeError {
fn fmt(
&self,
f: &mut ::std::fmt::Formatter,
) -> Result<(), ::std::fmt::Error> {
f.write_str("FakeError")?;
Ok(())
}
}
impl Error for FakeError {
fn description(&self) -> &str {
"Something Ooo occurred"
}
fn cause(&self) -> Option<&dyn Error> {
None
}
}
#[derive(Clone, Debug)]
pub struct FakeResponse {
pub status: reqwest::StatusCode,
pub headers: reqwest::header::HeaderMap,
pub body: io::Cursor<Vec<u8>>,
}
impl super::HttpResponse for FakeResponse {
fn headers(&self) -> &reqwest::header::HeaderMap {
&self.headers
}
fn status(&self) -> reqwest::StatusCode {
self.status
}
fn error_for_status(self) -> Result<Self, Box<dyn Error>> {
if !self.status.is_client_error() && !self.status.is_server_error()
{
Ok(self)
} else {
Err(Box::new(FakeError))
}
}
}
impl Read for FakeResponse {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.body.read(buf)
}
}
pub struct FakeClient {
pub expected_url: reqwest::Url,
pub expected_headers: reqwest::header::HeaderMap,
pub response: FakeResponse,
called: cell::Cell<bool>,
}
impl FakeClient {
pub fn new(
expected_url: reqwest::Url,
expected_headers: reqwest::header::HeaderMap,
response: FakeResponse,
) -> FakeClient {
let called = cell::Cell::new(false);
FakeClient {
expected_url,
expected_headers,
response,
called,
}
}
pub fn assert_called(self) {
assert!(self.called.get());
}
}
impl super::Client for FakeClient {
type Response = FakeResponse;
fn execute(
&self,
request: reqwest::blocking::Request,
) -> Result<Self::Response, Box<dyn Error>> {
assert_eq!(request.method(), &reqwest::Method::GET);
assert_eq!(request.url(), &self.expected_url);
assert_eq!(request.headers(), &self.expected_headers);
self.called.set(true);
Ok(self.response.clone())
}
}
pub struct BrokenClient<F>
where
F: Fn() -> Box<dyn Error>,
{
pub expected_url: reqwest::Url,
pub expected_headers: reqwest::header::HeaderMap,
pub make_error: F,
called: cell::Cell<bool>,
}
impl<F> BrokenClient<F>
where
F: Fn() -> Box<dyn Error>,
{
pub fn new(
expected_url: reqwest::Url,
expected_headers: reqwest::header::HeaderMap,
make_error: F,
) -> BrokenClient<F> {
let called = cell::Cell::new(false);
BrokenClient {
expected_url,
expected_headers,
make_error,
called,
}
}
pub fn assert_called(self) {
assert!(self.called.get());
}
}
impl<F> super::Client for BrokenClient<F>
where
F: Fn() -> Box<dyn Error>,
{
type Response = FakeResponse;
fn execute(
&self,
request: reqwest::blocking::Request,
) -> Result<Self::Response, Box<dyn Error>> {
assert_eq!(request.method(), &reqwest::Method::GET);
assert_eq!(request.url(), &self.expected_url);
assert_eq!(request.headers(), &self.expected_headers);
self.called.set(true);
Err((self.make_error)())
}
}
}