use futures_util::{stream, Stream, StreamExt};
use headers::{ContentDisposition, ContentType, HeaderMapExt};
use http_body_util::{BodyExt, Full};
use serde::{Deserialize, Serialize};
use viz::{
header::{CONTENT_DISPOSITION, CONTENT_LOCATION, LOCATION},
Body, Error, HttpBody, Response, ResponseExt, Result, StatusCode,
};
#[derive(Debug, Deserialize, Serialize, PartialEq)]
struct Page {
p: u8,
}
#[tokio::test]
async fn response_ext() -> Result<()> {
let resp = Response::with(Full::new("<xml/>".into()), mime::TEXT_XML.as_ref());
assert!(resp.ok());
assert!(resp.content_length().is_none());
let content_type = resp.headers().typed_get::<ContentType>();
assert_eq!(
Into::<mime::Mime>::into(content_type.unwrap()),
mime::TEXT_XML
);
let body: Body = resp.into_body();
assert_eq!(
HttpBody::size_hint(&body).exact(),
Some(b"<xml/>".len() as u64)
);
assert_eq!(
BodyExt::collect(body).await.unwrap().to_bytes().to_vec(),
b"<xml/>"
);
let mut resp = Response::text("");
*resp.status_mut() = StatusCode::NOT_FOUND;
assert!(!resp.ok());
let content_type = resp.headers().typed_get::<ContentType>();
assert_eq!(
Into::<mime::Mime>::into(content_type.unwrap()),
mime::TEXT_PLAIN_UTF_8
);
let mut body: Body = resp.into_body();
assert_eq!(HttpBody::size_hint(&body).exact(), Some(0));
assert!(body.frame().await.is_none());
assert!(body.is_end_stream());
let resp = Response::html("<html/>");
assert!(resp.ok());
let content_type = resp.headers().typed_get::<ContentType>();
assert_eq!(
Into::<mime::Mime>::into(content_type.unwrap()),
mime::TEXT_HTML_UTF_8
);
let mut body: Body = resp.into_body();
assert_eq!(HttpBody::size_hint(&body).exact(), Some(7));
assert_eq!(
body.frame().await.unwrap().unwrap().into_data().unwrap(),
"<html/>"
);
assert!(body.is_end_stream());
let resp = Response::json(Page { p: 255 })?;
assert!(resp.ok());
let content_type = resp.headers().typed_get::<ContentType>();
assert_eq!(
Into::<mime::Mime>::into(content_type.unwrap()),
mime::APPLICATION_JSON
);
let resp = Response::stream(stream::repeat("viz").take(2).map(Result::<_, Error>::Ok));
assert!(resp.ok());
let body: Body = resp.into_body();
assert_eq!(Stream::size_hint(&body), (0, None));
let (item, stream) = body.into_future().await;
assert_eq!(item.unwrap().unwrap().to_vec(), b"viz");
let (item, stream) = stream.into_future().await;
assert_eq!(item.unwrap().unwrap().to_vec(), b"viz");
let (item, _) = stream.into_future().await;
assert!(item.is_none());
let resp = Response::attachment("inline");
let content_disposition = resp.headers().typed_get::<ContentDisposition>().unwrap();
assert!(content_disposition.is_inline());
let resp = Response::attachment("attachment");
let content_disposition = resp.headers().typed_get::<ContentDisposition>().unwrap();
assert!(content_disposition.is_attachment());
let resp = Response::attachment(r#"attachment; filename="filename.jpg""#);
let content_disposition = resp.headers().get(CONTENT_DISPOSITION).unwrap();
assert_eq!(
content_disposition,
r#"attachment; filename="filename.jpg""#
);
let resp = Response::location("/login");
let location = resp.headers().get(CONTENT_LOCATION).unwrap();
assert_eq!(location, "/login");
let resp = Response::redirect("/oauth");
let location = resp.headers().get(LOCATION).unwrap();
assert_eq!(location, "/oauth");
let resp = Response::redirect_with_status("/oauth", StatusCode::TEMPORARY_REDIRECT);
let location = resp.headers().get(LOCATION).unwrap();
assert_eq!(location, "/oauth");
assert_eq!(resp.status(), 307);
let resp = Response::see_other("/oauth");
assert_eq!(resp.status(), 303);
let resp = Response::temporary("/oauth");
assert_eq!(resp.status(), 307);
let resp = Response::permanent("/oauth");
assert_eq!(resp.status(), 308);
Ok(())
}
#[test]
#[should_panic(expected = "not a redirection status code")]
fn response_ext_panic() {
Response::redirect_with_status("/oauth", StatusCode::OK);
}
#[tokio::test]
async fn response_ext_with_server() -> Result<()> {
use viz::{Request, Router};
use viz_test::TestServer;
let router = Router::new()
.get("/", |_: Request| async move { Ok("") })
.post("/", |_: Request| async move {
Ok(Response::with(
Full::new("<xml/>".into()),
mime::TEXT_XML.as_ref(),
))
})
.get("/download", |_: Request| {
let dir = std::env::var("CARGO_MANIFEST_DIR")
.map(std::path::PathBuf::from)
.unwrap();
Response::download(dir.join("README.md"), Some("file.txt"))
});
let client = TestServer::new(router).await?;
let resp = client.get("/").send().await.map_err(Error::boxed)?;
assert_eq!(resp.content_length(), Some(0));
assert_eq!(resp.text().await.map_err(Error::boxed)?, "");
let resp = client.post("/").send().await.map_err(Error::boxed)?;
assert_eq!(resp.content_length(), Some(6));
assert_eq!(resp.text().await.map_err(Error::boxed)?, "<xml/>");
let resp = client.get("/download").send().await.map_err(Error::boxed)?;
assert_eq!(resp.content_length(), None);
assert_eq!(
resp.headers().get(http::header::CONTENT_DISPOSITION),
Some(http::header::HeaderValue::from_static(
"attachment; filename=\"file.txt\""
))
.as_ref()
);
assert!(resp
.text()
.await
.map_err(Error::boxed)?
.starts_with("<p align=\"center\">"));
Ok(())
}