use std::fmt;
use std::str::Utf8Error;
use std::string::FromUtf8Error;
use bytes::Bytes;
use http::HeaderMap;
use http::StatusCode;
use http_body_util::BodyExt;
use serde::de::DeserializeOwned;
use volter_core::BoxError;
#[derive(Debug)]
pub enum BodyError {
Stream(BoxError),
Utf8(Utf8Error),
Json(serde_json::Error),
}
impl fmt::Display for BodyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
BodyError::Stream(e) => write!(f, "body stream error: {e}"),
BodyError::Utf8(e) => write!(f, "body UTF-8 error: {e}"),
BodyError::Json(e) => write!(f, "body JSON error: {e}"),
}
}
}
impl std::error::Error for BodyError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
BodyError::Stream(e) => Some(e.as_ref()),
BodyError::Utf8(e) => Some(e),
BodyError::Json(e) => Some(e),
}
}
}
impl From<Utf8Error> for BodyError {
fn from(e: Utf8Error) -> Self {
BodyError::Utf8(e)
}
}
impl From<FromUtf8Error> for BodyError {
fn from(e: FromUtf8Error) -> Self {
BodyError::Utf8(e.utf8_error())
}
}
impl From<serde_json::Error> for BodyError {
fn from(e: serde_json::Error) -> Self {
BodyError::Json(e)
}
}
impl From<BoxError> for BodyError {
fn from(e: BoxError) -> Self {
BodyError::Stream(e)
}
}
pub struct TestResponse {
inner: volter_core::Response,
}
impl TestResponse {
pub(crate) fn new(inner: volter_core::Response) -> Self {
Self { inner }
}
pub fn status(&self) -> StatusCode {
self.inner.status()
}
pub fn headers(&self) -> &HeaderMap {
self.inner.headers()
}
pub async fn bytes(self) -> Result<Bytes, BodyError> {
let collected = self
.inner
.into_body()
.collect()
.await
.map_err(BodyError::Stream)?;
Ok(collected.to_bytes())
}
pub async fn text(self) -> Result<String, BodyError> {
let bytes = self.bytes().await?;
let text = String::from_utf8(bytes.to_vec())?;
Ok(text)
}
pub async fn json<T: DeserializeOwned>(self) -> Result<T, BodyError> {
let bytes = self.bytes().await?;
let value = serde_json::from_slice(&bytes)?;
Ok(value)
}
}