use crate::{
Body, Buffer, HttpConfig,
body::BodyType,
h3::H3Body,
received_body::{H3BodyFrameType, ReceivedBody, ReceivedBodyState},
};
use encoding_rs::UTF_8;
use futures_lite::{AsyncReadExt, io::Cursor};
use std::net::Shutdown;
use test_harness::test;
use trillium_testing::{TestTransport, harness};
async fn round_trip(body: BodyType, content_length: Option<u64>) -> String {
let (mut writer, reader) = TestTransport::new();
let rb = ReceivedBody::new_with_config(
content_length,
Buffer::with_capacity(HttpConfig::DEFAULT.response_header_initial_capacity),
reader,
ReceivedBodyState::new_h3(),
None,
UTF_8,
&HttpConfig::DEFAULT,
);
let ((), result) = futures_lite::future::zip(
async {
futures_lite::io::copy(H3Body::from(body), &mut writer)
.await
.unwrap();
writer.shutdown(Shutdown::Write);
},
rb.read_string(),
)
.await;
result.unwrap()
}
async fn round_trip_buf(body: BodyType, content_length: Option<u64>, buf_size: usize) -> String {
let (writer, reader) = TestTransport::new();
let rb = ReceivedBody::new_with_config(
content_length,
Buffer::from(Vec::with_capacity(
HttpConfig::DEFAULT.response_header_initial_capacity,
)),
reader,
ReceivedBodyState::H3Data {
remaining_in_frame: 0,
total: 0,
frame_type: H3BodyFrameType::Start,
partial_frame_header: false,
},
None,
UTF_8,
&HttpConfig::DEFAULT,
);
let ((), result) = futures_lite::future::zip(
async {
let mut src = H3Body::from(body);
let mut buf = vec![0u8; buf_size];
loop {
let n = src.read(&mut buf).await.unwrap();
if n == 0 {
break;
}
writer.write_all(&buf[..n]);
}
writer.shutdown(Shutdown::Write);
},
rb.read_string(),
)
.await;
result.unwrap()
}
#[test(harness)]
async fn empty_body() {
assert_eq!(round_trip(BodyType::Empty, None).await, "");
}
#[test(harness)]
async fn static_body() {
let body = "hello world";
let result = round_trip(
BodyType::Static {
content: body.as_bytes().into(),
cursor: 0,
},
Some(body.len() as u64),
)
.await;
assert_eq!(result, body);
}
#[test(harness)]
async fn streaming_known_length() {
let body = "hello streaming world";
let result = round_trip(
Body::new_streaming(
Cursor::new(body.as_bytes().to_vec()),
Some(body.len() as u64),
)
.0,
Some(body.len() as u64),
)
.await;
assert_eq!(result, body);
}
#[test(harness)]
async fn streaming_unknown_length() {
let body = "hello chunked world";
let result = round_trip(
Body::new_streaming(Cursor::new(body.as_bytes().to_vec()), None).0,
None,
)
.await;
assert_eq!(result, body);
}
#[test(harness)]
async fn static_body_various_buf_sizes() {
let body = "hello world";
for size in 3..=body.len() + 4 {
let result = round_trip_buf(
BodyType::Static {
content: body.as_bytes().into(),
cursor: 0,
},
Some(body.len() as u64),
size,
)
.await;
assert_eq!(result, body, "buf_size={size}");
}
}
#[test(harness)]
async fn streaming_known_length_various_buf_sizes() {
let body = "hello streaming world";
for size in 3..=body.len() + 4 {
let result = round_trip_buf(
Body::new_streaming(
Cursor::new(body.as_bytes().to_vec()),
Some(body.len() as u64),
)
.0,
Some(body.len() as u64),
size,
)
.await;
assert_eq!(result, body, "buf_size={size}");
}
}
#[test(harness)]
async fn streaming_unknown_length_various_buf_sizes() {
let body = "hello chunked world";
for size in 3..=body.len() + 4 {
let result = round_trip_buf(
Body::new_streaming(Cursor::new(body.as_bytes().to_vec()), None).0,
None,
size,
)
.await;
assert_eq!(result, body, "buf_size={size}");
}
}