1use std::borrow::Cow;
2use std::io::{Cursor, Read};
3use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
4
5use conduit::{
6 header::{HeaderValue, IntoHeaderName},
7 Body, Extensions, HeaderMap, Host, Method, Response, Scheme, StartInstant, Version,
8};
9
10pub trait ResponseExt {
11 fn into_cow(self) -> Cow<'static, [u8]>;
12}
13
14impl ResponseExt for Response<Body> {
15 fn into_cow(self) -> Cow<'static, [u8]> {
25 use conduit::Body::*;
26
27 match self.into_body() {
28 Static(slice) => slice.into(),
29 Owned(vec) => vec.into(),
30 File(mut file) => {
31 let mut vec = Vec::new();
32 std::io::copy(&mut file, &mut vec).unwrap();
33 vec.into()
34 }
35 }
36 }
37}
38
39pub struct MockRequest {
40 path: String,
41 method: Method,
42 query_string: Option<String>,
43 body: Option<Vec<u8>>,
44 headers: HeaderMap,
45 extensions: Extensions,
46 reader: Option<Cursor<Vec<u8>>>,
47}
48
49impl MockRequest {
50 pub fn new(method: Method, path: &str) -> MockRequest {
51 let headers = HeaderMap::new();
52 let mut extensions = Extensions::new();
53 extensions.insert(StartInstant::now());
54
55 MockRequest {
56 path: path.to_string(),
57 extensions,
58 query_string: None,
59 body: None,
60 headers,
61 method,
62 reader: None,
63 }
64 }
65
66 pub fn with_method(&mut self, method: Method) -> &mut MockRequest {
67 self.method = method;
68 self
69 }
70
71 pub fn with_path(&mut self, path: &str) -> &mut MockRequest {
72 self.path = path.to_string();
73 self
74 }
75
76 pub fn with_query(&mut self, string: &str) -> &mut MockRequest {
77 self.query_string = Some(string.to_string());
78 self
79 }
80
81 pub fn with_body(&mut self, bytes: &[u8]) -> &mut MockRequest {
82 self.body = Some(bytes.to_vec());
83 self.reader = None;
84 self
85 }
86
87 pub fn header<K>(&mut self, name: K, value: &str) -> &mut MockRequest
88 where
89 K: IntoHeaderName,
90 {
91 self.headers
92 .insert(name, HeaderValue::from_str(value).unwrap());
93 self
94 }
95}
96
97impl conduit::RequestExt for MockRequest {
98 fn http_version(&self) -> Version {
99 Version::HTTP_11
100 }
101
102 fn method(&self) -> &Method {
103 &self.method
104 }
105 fn scheme(&self) -> Scheme {
106 Scheme::Http
107 }
108 fn host(&self) -> Host<'_> {
109 Host::Name("example.com")
110 }
111 fn virtual_root(&self) -> Option<&str> {
112 None
113 }
114
115 fn path(&self) -> &str {
116 &self.path
117 }
118
119 fn path_mut(&mut self) -> &mut String {
120 &mut self.path
121 }
122
123 fn query_string(&self) -> Option<&str> {
124 self.query_string.as_ref().map(|s| &s[..])
125 }
126
127 fn remote_addr(&self) -> SocketAddr {
128 SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 80))
129 }
130
131 fn content_length(&self) -> Option<u64> {
132 self.body.as_ref().map(|b| b.len() as u64)
133 }
134
135 fn headers(&self) -> &HeaderMap {
136 &self.headers
137 }
138
139 fn body(&mut self) -> &mut dyn Read {
140 if self.reader.is_none() {
141 let body = self.body.clone().unwrap_or_default();
142 self.reader = Some(Cursor::new(body));
143 }
144 self.reader.as_mut().unwrap()
145 }
146
147 fn extensions(&self) -> &Extensions {
148 &self.extensions
149 }
150 fn mut_extensions(&mut self) -> &mut Extensions {
151 &mut self.extensions
152 }
153}
154
155#[cfg(test)]
156mod tests {
157 use super::MockRequest;
158
159 use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
160
161 use conduit::{header, Host, Method, RequestExt, Scheme, Version};
162
163 #[test]
164 fn simple_request_test() {
165 let mut req = MockRequest::new(Method::GET, "/");
166
167 assert_eq!(req.http_version(), Version::HTTP_11);
168 assert_eq!(req.method(), Method::GET);
169 assert_eq!(req.scheme(), Scheme::Http);
170 assert_eq!(req.host(), Host::Name("example.com"));
171 assert_eq!(req.virtual_root(), None);
172 assert_eq!(req.path(), "/");
173 assert_eq!(req.query_string(), None);
174 assert_eq!(
175 req.remote_addr(),
176 SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 80))
177 );
178 assert_eq!(req.content_length(), None);
179 assert_eq!(req.headers().len(), 0);
180 let mut s = String::new();
181 req.body().read_to_string(&mut s).expect("No body");
182 assert_eq!(s, "".to_string());
183 }
184
185 #[test]
186 fn request_body_test() {
187 let mut req = MockRequest::new(Method::POST, "/articles");
188 req.with_body(b"Hello world");
189
190 assert_eq!(req.method(), Method::POST);
191 assert_eq!(req.path(), "/articles");
192 let mut s = String::new();
193 req.body().read_to_string(&mut s).expect("No body");
194 assert_eq!(s, "Hello world".to_string());
195 assert_eq!(req.content_length(), Some(11));
196 }
197
198 #[test]
199 fn request_query_test() {
200 let mut req = MockRequest::new(Method::POST, "/articles");
201 req.with_query("foo=bar");
202
203 assert_eq!(req.query_string().expect("No query string"), "foo=bar");
204 }
205
206 #[test]
207 fn request_headers() {
208 let mut req = MockRequest::new(Method::POST, "/articles");
209 req.header(header::USER_AGENT, "lulz");
210 req.header(header::DNT, "1");
211
212 assert_eq!(req.headers().len(), 2);
213 assert_eq!(req.headers().get(header::USER_AGENT).unwrap(), "lulz");
214 assert_eq!(req.headers().get(header::DNT).unwrap(), "1");
215 }
216}