#[cfg(test)]
mod tests {
use aex::connection::context::{BoxReader, TypeMapExt};
use aex::http::params::Params;
use aex::http::protocol::method::HttpMethod;
use aex::{
connection::context::LocalTypeMap,
http::{meta::HttpMetadata, req::Request},
};
use ahash::AHashMap;
use std::io::Cursor;
use std::sync::Arc;
use tokio::io::BufReader;
#[tokio::test]
async fn test_parse_to_local_success() {
let mut local = LocalTypeMap::new();
let input = b"GET /api/test?id=1 HTTP/1.1\r\n\
Host: localhost\r\n\
Content-Type: application/json\r\n\
Content-Length: 15\r\n\
Cookie: user=alice; session=123\r\n\
Transfer-Encoding: chunked\r\n\
\r\n";
let reader = BufReader::new(Cursor::new(input));
let mut reader: Option<BoxReader> = Some(Box::new(reader));
let mut req = Request::new(&mut reader, &mut local);
let result = req.parse_to_local().await;
assert!(result.is_ok());
let meta = local.get_value::<HttpMetadata>().unwrap();
assert_eq!(meta.method, HttpMethod::GET);
assert_eq!(meta.path, "/api/test?id=1");
assert!(meta.is_chunked);
assert_eq!(meta.cookies.get("user").unwrap(), "alice");
}
#[tokio::test]
async fn test_parse_multipart_boundary() {
let mut local = LocalTypeMap::new();
let input = b"POST /upload HTTP/1.1\r\n\
Content-Type: multipart/form-data; boundary=X-BOUNDARY\r\n\
\r\n";
let reader = BufReader::new(Cursor::new(input));
let mut reader: Option<BoxReader> = Some(Box::new(reader));
let mut req = Request::new(&mut reader, &mut local);
req.parse_to_local().await.unwrap();
let meta = local.get_value::<HttpMetadata>().unwrap();
assert_eq!(meta.multipart_boundary, Some("X-BOUNDARY".to_string()));
}
#[tokio::test]
async fn test_parse_errors() {
let mut local = LocalTypeMap::new();
let reader = BufReader::new(Cursor::new(b""));
let mut reader: Option<BoxReader> = Some(Box::new(reader));
let mut req = Request::new(&mut reader, &mut local);
assert!(req.parse_to_local().await.is_err());
let reader = BufReader::new(Cursor::new(b"INVALID_LINE\r\n\r\n"));
let mut reader: Option<BoxReader> = Some(Box::new(reader));
let mut req = Request::new(&mut reader, &mut local);
assert!(req.parse_to_local().await.is_err());
let reader = BufReader::new(Cursor::new(vec![0xff, 0xff, 0x0a]));
let mut reader: Option<BoxReader> = Some(Box::new(reader));
let mut req = Request::new(&mut reader, &mut local);
assert!(req.parse_to_local().await.is_err());
}
#[tokio::test]
async fn test_cookie_parsing_edge_cases() {
let mut local = LocalTypeMap::new();
let input = b"GET / HTTP/1.1\r\nCookie: ;; a=1 ; b=2 ; ;\r\n\r\n";
let reader = BufReader::new(Cursor::new(input));
let mut reader: Option<BoxReader> = Some(Box::new(reader));
let mut req = Request::new(&mut reader, &mut local);
req.parse_to_local().await.unwrap();
let meta = local.get_value::<HttpMetadata>().unwrap();
assert_eq!(meta.cookies.get("a").unwrap(), "1");
assert_eq!(meta.cookies.get("b").unwrap(), "2");
}
#[tokio::test]
async fn test_getters() {
let mut local = LocalTypeMap::new();
let mut meta = HttpMetadata::default();
meta.method = HttpMethod::POST;
let mut params = Params::new("/?q=rust".to_string());
let mut data = AHashMap::new();
data.insert("id".to_string(), "123".to_string());
params.data = Some(data);
params.set_form("name=bob");
meta.params = Some(params);
local.set_value(meta);
let reader = BufReader::new(Cursor::new(b""));
let mut reader: Option<BoxReader> = Some(Box::new(reader));
let req = Request::new(&mut reader, &mut local);
assert_eq!(req.method(), HttpMethod::POST);
assert_eq!(req.param("id").unwrap(), "123");
assert_eq!(req.query("q").unwrap(), "rust");
assert_eq!(req.form("name").unwrap(), "bob");
assert!(req.query("none").is_none());
}
#[tokio::test]
async fn test_read_line_limit_exceeded() {
let mut local = LocalTypeMap::new();
let long_line = vec![b'a'; 2048];
let reader = BufReader::new(Cursor::new(long_line));
let mut reader: Option<BoxReader> = Some(Box::new(reader));
let _req = Request::new(&mut reader, &mut local);
}
}