actix_http/test/
test_request.rs1use std::str::FromStr;
2
3use bytes::Bytes;
4use http::{header, Method, Uri, Version};
5
6use crate::{
7 header::{HeaderMap, TryIntoHeaderPair},
8 payload::Payload,
9 Request,
10};
11
12pub struct TestRequest(Option<Inner>);
14
15struct Inner {
16 version: Version,
17 method: Method,
18 uri: Uri,
19 headers: HeaderMap,
20 payload: Option<Payload>,
21}
22
23impl Default for TestRequest {
24 fn default() -> TestRequest {
25 TestRequest(Some(Inner {
26 method: Method::GET,
27 uri: Uri::from_str("/").unwrap(),
28 version: Version::HTTP_11,
29 headers: HeaderMap::new(),
30 payload: None,
31 }))
32 }
33}
34
35impl TestRequest {
36 pub fn with_uri(path: &str) -> TestRequest {
38 TestRequest::default().uri(path).take()
39 }
40
41 pub fn version(&mut self, ver: Version) -> &mut Self {
43 parts(&mut self.0).version = ver;
44 self
45 }
46
47 pub fn method(&mut self, meth: Method) -> &mut Self {
49 parts(&mut self.0).method = meth;
50 self
51 }
52
53 pub fn uri(&mut self, path: &str) -> &mut Self {
58 parts(&mut self.0).uri = Uri::from_str(path).unwrap();
59 self
60 }
61
62 pub fn insert_header(&mut self, header: impl TryIntoHeaderPair) -> &mut Self {
64 match header.try_into_pair() {
65 Ok((key, value)) => {
66 parts(&mut self.0).headers.insert(key, value);
67 }
68 Err(err) => {
69 panic!("Error inserting test header: {}.", err.into());
70 }
71 }
72
73 self
74 }
75
76 pub fn append_header(&mut self, header: impl TryIntoHeaderPair) -> &mut Self {
78 match header.try_into_pair() {
79 Ok((key, value)) => {
80 parts(&mut self.0).headers.append(key, value);
81 }
82 Err(err) => {
83 panic!("Error inserting test header: {}.", err.into());
84 }
85 }
86
87 self
88 }
89
90 pub fn set_payload(&mut self, data: impl Into<Bytes>) -> &mut Self {
94 let mut payload = crate::h1::Payload::empty();
95 let bytes = data.into();
96 self.insert_header((header::CONTENT_LENGTH, bytes.len()));
97 payload.unread_data(bytes);
98 parts(&mut self.0).payload = Some(payload.into());
99 self
100 }
101
102 pub fn take(&mut self) -> TestRequest {
103 TestRequest(self.0.take())
104 }
105
106 pub fn finish(&mut self) -> Request {
108 let inner = self.0.take().expect("cannot reuse test request builder");
109
110 let mut req = if let Some(pl) = inner.payload {
111 Request::with_payload(pl)
112 } else {
113 Request::with_payload(crate::h1::Payload::empty().into())
114 };
115
116 let head = req.head_mut();
117 head.uri = inner.uri;
118 head.method = inner.method;
119 head.version = inner.version;
120 head.headers = inner.headers;
121
122 req
123 }
124}
125
126#[inline]
127fn parts(parts: &mut Option<Inner>) -> &mut Inner {
128 parts.as_mut().expect("cannot reuse test request builder")
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134
135 #[test]
136 fn request_builder() {
137 let mut request = TestRequest::with_uri("/initial");
138 request
139 .version(Version::HTTP_10)
140 .method(Method::POST)
141 .uri("/final")
142 .insert_header(("x-test", "one"))
143 .append_header(("x-test", "two"));
144
145 let request = request.finish();
146 assert_eq!(request.head().uri, Uri::from_static("/final"));
147 assert_eq!(request.head().method, Method::POST);
148 assert_eq!(request.head().version, Version::HTTP_10);
149 assert_eq!(request.head().headers.get_all("x-test").count(), 2);
150
151 let mut request = TestRequest::default();
152 request.set_payload("body");
153 let request = request.finish();
154 assert_eq!(
155 request.head().headers.get(header::CONTENT_LENGTH).unwrap(),
156 "4"
157 );
158
159 let mut request = TestRequest::default();
160 let request = request.take();
161 let mut request = request;
162 assert_eq!(request.finish().head().uri, Uri::from_static("/"));
163 }
164
165 #[test]
166 #[should_panic(expected = "Error inserting test header")]
167 fn insert_header_rejects_invalid_header() {
168 TestRequest::default().insert_header(("invalid name", "value"));
169 }
170
171 #[test]
172 #[should_panic(expected = "Error inserting test header")]
173 fn append_header_rejects_invalid_header() {
174 TestRequest::default().append_header(("invalid name", "value"));
175 }
176}