use std::{convert::Infallible, fmt::Debug, marker::PhantomData};
use http::method::Method;
use motore::{layer::Layer, service::Service};
use super::{
IntoResponse,
handler::{Handler, HandlerService},
route::method_router::MethodRouter,
};
use crate::{
body::Body, context::ServerContext, request::Request, response::Response, server::Server,
utils::test_helpers::mock_address,
};
pub struct DefaultService<R = Response, E = Infallible> {
_marker: PhantomData<fn(R, E)>,
}
impl<R, E> DefaultService<R, E> {
pub const fn new() -> Self {
Self {
_marker: PhantomData,
}
}
}
impl<R, E> Default for DefaultService<R, E> {
fn default() -> Self {
Self::new()
}
}
impl<Cx, Req, Resp, E> Service<Cx, Req> for DefaultService<Resp, E>
where
Cx: Send,
Req: Send,
Resp: Default + Send,
{
type Response = Resp;
type Error = E;
async fn call(&self, _: &mut Cx, _: Req) -> Result<Self::Response, Self::Error> {
Ok(Resp::default())
}
}
pub fn to_service<H, T, B, E>(handler: H) -> HandlerService<H, T, B, E>
where
H: Handler<T, B, E>,
{
Handler::into_service(handler)
}
pub struct TestServer<S, B = Body> {
inner: S,
_marker: PhantomData<fn(B)>,
}
pub fn empty_cx() -> ServerContext {
ServerContext::new(mock_address())
}
impl<B, E> MethodRouter<B, E>
where
B: Send,
E: IntoResponse,
{
pub async fn call_without_cx(&self, req: Request<B>) -> Result<Response, E> {
self.call(&mut ServerContext::new(mock_address()), req)
.await
}
pub async fn call_route<D>(&self, method: Method, data: D) -> Response
where
B: TryFrom<D>,
B::Error: Debug,
{
self.call_without_cx(
Request::builder()
.method(method)
.uri("/")
.body(B::try_from(data).expect("Failed to convert data to body"))
.expect("Failed to build request"),
)
.await
.into_response()
}
}
impl<S, B> TestServer<S, B>
where
S: Service<ServerContext, Request<B>>,
S::Response: IntoResponse,
S::Error: IntoResponse,
{
pub async fn call(
&self,
cx: &mut ServerContext,
req: Request<B>,
) -> Result<S::Response, S::Error> {
self.inner.call(cx, req).await
}
pub async fn call_without_cx(&self, req: Request<B>) -> Result<S::Response, S::Error> {
self.call(&mut ServerContext::new(mock_address()), req)
.await
}
pub async fn call_route<U, D>(&self, method: Method, uri: U, data: D) -> Response
where
U: AsRef<str>,
B: TryFrom<D>,
B::Error: Debug,
{
self.call_without_cx(
Request::builder()
.method(method)
.uri(uri.as_ref().to_owned())
.body(B::try_from(data).expect("Failed to convert data to body"))
.expect("Failed to build request"),
)
.await
.into_response()
}
}
impl<S, L, SP> Server<S, L, SP> {
pub fn into_test_server<B>(self) -> TestServer<L::Service, B>
where
S: Service<ServerContext, Request<B>>,
L: Layer<S>,
{
TestServer {
inner: self.layer.layer(self.service),
_marker: PhantomData,
}
}
}