1#[cfg(feature = "cookie")]
3use coo_kie::{Cookie, CookieJar};
4
5use crate::http::error::HttpError;
6use crate::http::header::{HeaderName, HeaderValue};
7use crate::http::{Payload, ResponseHead, StatusCode, Version};
8use crate::{Cfg, channel::bstream, util::Bytes};
9
10use super::ClientResponse;
11
12#[derive(Debug)]
13pub struct TestResponse {
15 head: ResponseHead,
16 payload: Option<Payload>,
17 #[cfg(feature = "cookie")]
18 cookies: CookieJar,
19}
20
21impl TestResponse {
22 pub fn builder() -> TestResponse {
24 TestResponse {
25 head: ResponseHead::new(StatusCode::OK, Version::default()),
26 payload: None,
27 #[cfg(feature = "cookie")]
28 cookies: CookieJar::new(),
29 }
30 }
31
32 #[must_use]
33 pub fn with_header<K, V>(key: K, value: V) -> Self
35 where
36 HeaderName: TryFrom<K>,
37 HeaderValue: TryFrom<V>,
38 <HeaderName as TryFrom<K>>::Error: Into<HttpError>,
39 {
40 Self::builder().header(key, value)
41 }
42
43 #[must_use]
44 pub fn version(mut self, ver: Version) -> Self {
46 self.head.version = ver;
47 self
48 }
49
50 #[must_use]
51 pub fn header<K, V>(mut self, key: K, value: V) -> Self
53 where
54 HeaderName: TryFrom<K>,
55 HeaderValue: TryFrom<V>,
56 <HeaderName as TryFrom<K>>::Error: Into<HttpError>,
57 {
58 if let Ok(key) = HeaderName::try_from(key)
59 && let Ok(value) = HeaderValue::try_from(value)
60 {
61 self.head.headers.append(key, value);
62 return self;
63 }
64 panic!("Cannot create header");
65 }
66
67 #[must_use]
68 #[cfg(feature = "cookie")]
69 pub fn cookie<C>(mut self, cookie: C) -> Self
71 where
72 C: Into<Cookie<'static>>,
73 {
74 self.cookies.add(cookie.into());
75 self
76 }
77
78 #[must_use]
79 pub fn set_payload<B: Into<Bytes>>(mut self, data: B) -> Self {
81 self.payload = Some(bstream::empty(Some(data.into())).into());
82 self
83 }
84
85 #[must_use]
86 pub fn build(self) -> ClientResponse {
88 #[allow(unused_mut)]
89 let mut head = self.head;
90
91 #[cfg(feature = "cookie")]
93 for c in self.cookies.delta() {
94 let value = HeaderValue::from_str(&c.encoded().to_string()).unwrap();
95 head.headers.append(crate::http::header::SET_COOKIE, value);
96 }
97
98 if let Some(pl) = self.payload {
99 ClientResponse::new(head, pl, Cfg::default())
100 } else {
101 ClientResponse::new(head, bstream::empty(None).into(), Cfg::default())
102 }
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109 use crate::http::header;
110
111 #[crate::rt_test]
112 async fn test_basics() {
113 let res = {
114 #[cfg(feature = "cookie")]
115 {
116 TestResponse::builder()
117 .version(Version::HTTP_2)
118 .header(header::DATE, "data")
119 .cookie(coo_kie::Cookie::build(("name", "value")))
120 .build()
121 }
122 #[cfg(not(feature = "cookie"))]
123 {
124 TestResponse::builder()
125 .version(Version::HTTP_2)
126 .header(header::DATE, "data")
127 .build()
128 }
129 };
130 #[cfg(feature = "cookie")]
131 assert!(res.headers().contains_key(header::SET_COOKIE));
132 assert!(res.headers().contains_key(header::DATE));
133 assert_eq!(res.version(), Version::HTTP_2);
134 }
135
136 #[cfg(feature = "cookie")]
137 #[crate::rt_test]
138 async fn test_cookies() {
139 use crate::http::HttpMessage;
140 use coo_kie::Cookie;
141
142 let res = TestResponse::builder()
143 .cookie(Cookie::build(("c1", "v 1")).path("/p"))
144 .cookie(Cookie::build(("c2", "v2")))
145 .build();
146 assert_eq!(res.headers().get_all(header::SET_COOKIE).count(), 2);
147
148 let mut cookies: Vec<_> = res
149 .cookies()
150 .unwrap()
151 .iter()
152 .map(|c| (c.name().to_string(), c.value().to_string()))
153 .collect();
154 cookies.sort_unstable();
155 assert_eq!(
156 cookies,
157 [
158 ("c1".to_string(), "v 1".to_string()),
159 ("c2".to_string(), "v2".to_string())
160 ]
161 );
162 assert_eq!(res.cookie("c1").unwrap().path(), Some("/p"));
163 }
164}