tmdb_api/movie/
now_playing.rs1use std::borrow::Cow;
2
3use chrono::NaiveDate;
4
5use crate::common::PaginatedResult;
6
7#[derive(Clone, Debug, Default, serde::Serialize)]
8pub struct Params<'a> {
9 #[serde(skip_serializing_if = "Option::is_none")]
12 pub language: Option<Cow<'a, str>>,
13 #[serde(skip_serializing_if = "Option::is_none")]
15 pub page: Option<u32>,
16 #[serde(skip_serializing_if = "Option::is_none")]
18 pub region: Option<Cow<'a, str>>,
19}
20
21impl<'a> Params<'a> {
22 pub fn set_page(&mut self, value: u32) {
23 self.page = Some(value);
24 }
25
26 pub fn with_page(mut self, value: u32) -> Self {
27 self.set_page(value);
28 self
29 }
30
31 pub fn set_language(&mut self, value: impl Into<Cow<'a, str>>) {
32 self.language = Some(value.into());
33 }
34
35 pub fn with_language(mut self, value: impl Into<Cow<'a, str>>) -> Self {
36 self.set_language(value);
37 self
38 }
39
40 pub fn set_region(&mut self, value: impl Into<Cow<'a, str>>) {
41 self.region = Some(value.into());
42 }
43
44 pub fn with_region(mut self, value: impl Into<Cow<'a, str>>) -> Self {
45 self.set_region(value);
46 self
47 }
48}
49
50#[derive(Clone, Debug, Deserialize, Serialize)]
51pub struct DateRange {
52 #[serde(deserialize_with = "crate::util::empty_string::deserialize")]
53 pub maximum: Option<NaiveDate>,
54 #[serde(deserialize_with = "crate::util::empty_string::deserialize")]
55 pub minimum: Option<NaiveDate>,
56}
57
58#[derive(Clone, Debug, Deserialize, Serialize)]
59pub struct ListMoviesNowPlayingResponse {
60 #[serde(flatten)]
61 pub inner: PaginatedResult<super::MovieShort>,
62 pub dates: DateRange,
63}
64
65impl<E: crate::client::Executor> crate::Client<E> {
66 pub async fn list_movies_now_playing(
88 &self,
89 params: &Params<'_>,
90 ) -> crate::Result<ListMoviesNowPlayingResponse> {
91 self.execute("/movie/now_playing", params).await
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use mockito::Matcher;
98
99 use crate::client::Client;
100 use crate::client::reqwest::Client as ReqwestClient;
101
102 #[tokio::test]
103 async fn it_works() {
104 let mut server = mockito::Server::new_async().await;
105 let client = Client::<ReqwestClient>::builder()
106 .with_api_key("secret".into())
107 .with_base_url(server.url())
108 .build()
109 .unwrap();
110
111 let _m = server
112 .mock("GET", "/movie/now_playing")
113 .match_query(Matcher::UrlEncoded("api_key".into(), "secret".into()))
114 .with_status(200)
115 .with_header("content-type", "application/json")
116 .with_body(include_str!("../../assets/movie-now-playing.json"))
117 .create_async()
118 .await;
119
120 let result = client
121 .list_movies_now_playing(&Default::default())
122 .await
123 .unwrap();
124 assert_eq!(result.inner.page, 1);
125 }
126
127 #[tokio::test]
128 async fn invalid_api_key() {
129 let mut server = mockito::Server::new_async().await;
130 let client = Client::<ReqwestClient>::builder()
131 .with_api_key("secret".into())
132 .with_base_url(server.url())
133 .build()
134 .unwrap();
135
136 let _m = server
137 .mock("GET", "/movie/now_playing")
138 .match_query(Matcher::UrlEncoded("api_key".into(), "secret".into()))
139 .with_status(401)
140 .with_header("content-type", "application/json")
141 .with_body(include_str!("../../assets/invalid-api-key.json"))
142 .create_async()
143 .await;
144
145 let err = client
146 .list_movies_now_playing(&Default::default())
147 .await
148 .unwrap_err();
149 let server_err = err.as_server_error().unwrap();
150 assert_eq!(server_err.status_code, 7);
151 }
152
153 #[tokio::test]
154 async fn resource_not_found() {
155 let mut server = mockito::Server::new_async().await;
156 let client = Client::<ReqwestClient>::builder()
157 .with_api_key("secret".into())
158 .with_base_url(server.url())
159 .build()
160 .unwrap();
161
162 let _m = server
163 .mock("GET", "/movie/now_playing")
164 .match_query(Matcher::UrlEncoded("api_key".into(), "secret".into()))
165 .with_status(404)
166 .with_header("content-type", "application/json")
167 .with_body(include_str!("../../assets/resource-not-found.json"))
168 .create_async()
169 .await;
170
171 let err = client
172 .list_movies_now_playing(&Default::default())
173 .await
174 .unwrap_err();
175 let server_err = err.as_server_error().unwrap();
176 assert_eq!(server_err.status_code, 34);
177 }
178}
179
180#[cfg(all(test, feature = "integration"))]
181mod integration_tests {
182 use crate::client::Client;
183 use crate::client::reqwest::Client as ReqwestClient;
184
185 #[tokio::test]
186 async fn execute() {
187 let secret = std::env::var("TMDB_TOKEN_V3").unwrap();
188 let client = Client::<ReqwestClient>::new(secret);
189
190 let _result = client
191 .list_movies_now_playing(&Default::default())
192 .await
193 .unwrap();
194 }
195}