use churust_core::{Churust, TestClient};
use churust_json::Json;
use http::StatusCode;
use serde::Deserialize;
#[derive(Deserialize)]
struct Transfer {
amount: u64,
}
fn app() -> churust_core::App {
Churust::server()
.routing(|r| {
r.post("/transfer", |Json(t): Json<Transfer>| async move {
format!("moved {}", t.amount)
});
})
.build()
}
async fn post_with(content_type: Option<&str>, body: &'static str) -> (StatusCode, String) {
let client = TestClient::new(app());
let mut req = client.post("/transfer");
if let Some(ct) = content_type {
req = req.header("content-type", ct);
}
let res = req.body(body).send().await;
(res.status(), res.text())
}
#[tokio::test]
async fn a_cross_origin_text_plain_form_post_is_refused() {
let (status, body) = post_with(Some("text/plain"), r#"{"amount":1000}"#).await;
assert_eq!(
status,
StatusCode::UNSUPPORTED_MEDIA_TYPE,
"a text/plain body was deserialised as JSON: {body}"
);
}
#[tokio::test]
async fn the_other_two_simple_request_types_are_refused_as_well() {
for ct in [
"application/x-www-form-urlencoded",
"multipart/form-data; boundary=x",
] {
let (status, _) = post_with(Some(ct), r#"{"amount":1000}"#).await;
assert_eq!(status, StatusCode::UNSUPPORTED_MEDIA_TYPE, "accepted {ct}");
}
}
#[tokio::test]
async fn application_json_is_accepted() {
let (status, body) = post_with(Some("application/json"), r#"{"amount":7}"#).await;
assert_eq!(status, StatusCode::OK, "{body}");
assert_eq!(body, "moved 7");
}
#[tokio::test]
async fn a_charset_parameter_is_fine() {
let (status, body) =
post_with(Some("application/json; charset=utf-8"), r#"{"amount":7}"#).await;
assert_eq!(status, StatusCode::OK, "{body}");
assert_eq!(body, "moved 7");
}
#[tokio::test]
async fn a_structured_suffix_is_accepted() {
for ct in [
"application/problem+json",
"application/vnd.api+json",
"application/merge-patch+json",
] {
let (status, body) = post_with(Some(ct), r#"{"amount":7}"#).await;
assert_eq!(status, StatusCode::OK, "rejected {ct}: {body}");
}
}
#[tokio::test]
async fn a_missing_content_type_is_refused() {
let (status, _) = post_with(None, r#"{"amount":1000}"#).await;
assert_eq!(status, StatusCode::UNSUPPORTED_MEDIA_TYPE);
}
#[tokio::test]
async fn malformed_json_is_still_a_400_not_a_415() {
let (status, _) = post_with(Some("application/json"), "{not json").await;
assert_eq!(status, StatusCode::BAD_REQUEST);
}