tmdb_api/tvshow/
aggregate_credits.rs1use std::borrow::Cow;
4
5#[derive(Clone, Debug, Default)]
25pub struct TVShowAggregateCredits {
26 pub id: u64,
27 pub language: Option<String>,
28}
29
30#[derive(Debug, Deserialize)]
31pub struct TVShowAggregateCreditsResult {
32 pub id: u64,
33 pub cast: Vec<CastPerson>,
34 pub crew: Vec<CrewPerson>,
35}
36
37#[derive(Debug, Deserialize)]
38pub struct CastPerson {
39 #[serde(flatten)]
40 pub inner: Person,
41 pub roles: Vec<Role>,
42 pub order: u64,
43}
44
45#[derive(Debug, Deserialize)]
46pub struct CrewPerson {
47 #[serde(flatten)]
48 pub inner: Person,
49 pub jobs: Vec<Job>,
50 pub department: String,
51}
52
53#[derive(Debug, Deserialize)]
54pub struct Person {
55 pub id: u64,
56 pub adult: bool,
57 pub gender: u64,
58 pub known_for_department: String,
59 pub name: String,
60 pub original_name: String,
61 pub popularity: f64,
62 pub profile_path: Option<String>,
63 pub total_episode_count: u64,
64}
65
66#[derive(Debug, Deserialize)]
67pub struct Role {
68 pub credit_id: String,
69 pub character: String,
70 pub episode_count: u64,
71}
72
73#[derive(Debug, Deserialize)]
74pub struct Job {
75 pub credit_id: String,
76 pub job: String,
77 pub episode_count: u64,
78}
79
80impl TVShowAggregateCredits {
81 pub fn new(tv_show_id: u64) -> Self {
82 Self {
83 id: tv_show_id,
84 language: None,
85 }
86 }
87
88 pub fn with_language(mut self, value: Option<String>) -> Self {
89 self.language = value;
90 self
91 }
92}
93
94impl crate::prelude::Command for TVShowAggregateCredits {
95 type Output = TVShowAggregateCreditsResult;
96
97 fn path(&self) -> Cow<'static, str> {
98 Cow::Owned(format!("/tv/{}/aggregate_credits", self.id))
99 }
100
101 fn params(&self) -> Vec<(&'static str, Cow<'_, str>)> {
102 if let Some(ref language) = self.language {
103 vec![("language", Cow::Borrowed(language))]
104 } else {
105 Vec::new()
106 }
107 }
108}
109
110#[cfg(test)]
111mod tests {
112 use mockito::Matcher;
113
114 use crate::Client;
115 use crate::client::reqwest::ReqwestExecutor;
116 use crate::prelude::Command;
117
118 use super::TVShowAggregateCredits;
119
120 #[tokio::test]
121 async fn it_works() {
122 let mut server = mockito::Server::new_async().await;
123 let client = Client::<ReqwestExecutor>::builder()
124 .with_api_key("secret".into())
125 .with_base_url(server.url())
126 .build()
127 .unwrap();
128
129 let _m = server
130 .mock("GET", "/tv/1399/aggregate_credits")
131 .match_query(Matcher::UrlEncoded("api_key".into(), "secret".into()))
132 .with_status(200)
133 .with_header("content-type", "application/json")
134 .with_body(include_str!("../../assets/tv-aggregate-credits.json"))
135 .create_async()
136 .await;
137
138 let result = TVShowAggregateCredits::new(1399)
139 .execute(&client)
140 .await
141 .unwrap();
142 assert_eq!(result.id, 1399);
143 assert!(!result.cast.is_empty());
144 assert!(!result.crew.is_empty());
145 }
146
147 #[tokio::test]
148 async fn invalid_api_key() {
149 let mut server = mockito::Server::new_async().await;
150 let client = Client::<ReqwestExecutor>::builder()
151 .with_api_key("secret".into())
152 .with_base_url(server.url())
153 .build()
154 .unwrap();
155
156 let _m = server
157 .mock("GET", "/tv/1399/aggregate_credits")
158 .match_query(Matcher::UrlEncoded("api_key".into(), "secret".into()))
159 .with_status(401)
160 .with_header("content-type", "application/json")
161 .with_body(include_str!("../../assets/invalid-api-key.json"))
162 .create_async()
163 .await;
164
165 let err = TVShowAggregateCredits::new(1399)
166 .execute(&client)
167 .await
168 .unwrap_err();
169 let server_err = err.as_server_error().unwrap();
170 assert_eq!(server_err.status_code, 7);
171 }
172
173 #[tokio::test]
174 async fn resource_not_found() {
175 let mut server = mockito::Server::new_async().await;
176 let client = Client::<ReqwestExecutor>::builder()
177 .with_api_key("secret".into())
178 .with_base_url(server.url())
179 .build()
180 .unwrap();
181
182 let _m = server
183 .mock("GET", "/tv/1399/aggregate_credits")
184 .match_query(Matcher::UrlEncoded("api_key".into(), "secret".into()))
185 .with_status(404)
186 .with_header("content-type", "application/json")
187 .with_body(include_str!("../../assets/resource-not-found.json"))
188 .create_async()
189 .await;
190
191 let err = TVShowAggregateCredits::new(1399)
192 .execute(&client)
193 .await
194 .unwrap_err();
195 let server_err = err.as_server_error().unwrap();
196 assert_eq!(server_err.status_code, 34);
197 }
198}
199
200#[cfg(all(test, feature = "integration"))]
201mod integration_tests {
202 use crate::Client;
203 use crate::client::reqwest::ReqwestExecutor;
204 use crate::prelude::Command;
205
206 use super::TVShowAggregateCredits;
207
208 #[tokio::test]
209 async fn execute() {
210 let secret = std::env::var("TMDB_TOKEN_V3").unwrap();
211 let client = Client::<ReqwestExecutor>::new(secret);
212
213 let result = TVShowAggregateCredits::new(1399)
214 .execute(&client)
215 .await
216 .unwrap();
217 assert_eq!(result.id, 1399);
218 assert!(!result.cast.is_empty());
219 assert!(!result.crew.is_empty());
220 }
221}