tmdb_api/movie/
credits.rs

1use std::borrow::Cow;
2
3use crate::common::credits::{Cast, Crew};
4
5/// Command to get alternative titles for a movie
6///
7/// ```rust
8/// use tmdb_api::prelude::Command;
9/// use tmdb_api::client::Client;
10/// use tmdb_api::client::reqwest::ReqwestExecutor;
11/// use tmdb_api::movie::credits::MovieCredits;
12///
13/// #[tokio::main]
14/// async fn main() {
15///     let client = Client::<ReqwestExecutor>::new("this-is-my-secret-token".into());
16///     let cmd = MovieCredits::new(1);
17///     let result = cmd.execute(&client).await;
18///     match result {
19///         Ok(res) => println!("found: {:#?}", res),
20///         Err(err) => eprintln!("error: {:?}", err),
21///     };
22/// }
23/// ```
24#[derive(Clone, Debug, Default)]
25pub struct MovieCredits {
26    /// ID of the Movie
27    pub movie_id: u64,
28    /// ISO 639-1 value to display translated data for the fields that support it.
29    pub language: Option<String>,
30}
31
32impl MovieCredits {
33    pub fn new(movie_id: u64) -> Self {
34        Self {
35            movie_id,
36            language: None,
37        }
38    }
39
40    pub fn with_language(mut self, value: Option<String>) -> Self {
41        self.language = value;
42        self
43    }
44}
45
46#[derive(Debug, Deserialize, Serialize)]
47pub struct MovieCreditsResult {
48    pub id: u64,
49    pub cast: Vec<Cast>,
50    pub crew: Vec<Crew>,
51}
52
53impl crate::prelude::Command for MovieCredits {
54    type Output = MovieCreditsResult;
55
56    fn path(&self) -> Cow<'static, str> {
57        Cow::Owned(format!("/movie/{}/credits", self.movie_id))
58    }
59
60    fn params(&self) -> Vec<(&'static str, Cow<'_, str>)> {
61        if let Some(ref country) = self.language {
62            vec![("country", Cow::Borrowed(country))]
63        } else {
64            Vec::new()
65        }
66    }
67}
68
69#[cfg(test)]
70mod tests {
71    use mockito::Matcher;
72
73    use crate::client::Client;
74    use crate::client::reqwest::ReqwestExecutor;
75    use crate::prelude::Command;
76
77    use super::MovieCredits;
78
79    #[tokio::test]
80    async fn it_works() {
81        let mut server = mockito::Server::new_async().await;
82        let client = Client::<ReqwestExecutor>::builder()
83            .with_api_key("secret".into())
84            .with_base_url(server.url())
85            .build()
86            .unwrap();
87
88        let _m = server
89            .mock("GET", "/movie/3/credits")
90            .match_query(Matcher::UrlEncoded("api_key".into(), "secret".into()))
91            .with_status(200)
92            .with_header("content-type", "application/json")
93            .with_body(include_str!("../../assets/movie-credits.json"))
94            .create_async()
95            .await;
96
97        let result = MovieCredits::new(3).execute(&client).await.unwrap();
98        assert_eq!(result.id, 550);
99    }
100
101    #[tokio::test]
102    async fn invalid_api_key() {
103        let mut server = mockito::Server::new_async().await;
104        let client = Client::<ReqwestExecutor>::builder()
105            .with_api_key("secret".into())
106            .with_base_url(server.url())
107            .build()
108            .unwrap();
109
110        let _m = server
111            .mock("GET", "/movie/1/credits")
112            .match_query(Matcher::UrlEncoded("api_key".into(), "secret".into()))
113            .with_status(401)
114            .with_header("content-type", "application/json")
115            .with_body(include_str!("../../assets/invalid-api-key.json"))
116            .create_async()
117            .await;
118
119        let err = MovieCredits::new(1).execute(&client).await.unwrap_err();
120        let server_err = err.as_server_error().unwrap();
121        assert_eq!(server_err.status_code, 7);
122    }
123
124    #[tokio::test]
125    async fn resource_not_found() {
126        let mut server = mockito::Server::new_async().await;
127        let client = Client::<ReqwestExecutor>::builder()
128            .with_api_key("secret".into())
129            .with_base_url(server.url())
130            .build()
131            .unwrap();
132
133        let _m = server
134            .mock("GET", "/movie/1/credits")
135            .match_query(Matcher::UrlEncoded("api_key".into(), "secret".into()))
136            .with_status(404)
137            .with_header("content-type", "application/json")
138            .with_body(include_str!("../../assets/resource-not-found.json"))
139            .create_async()
140            .await;
141
142        let err = MovieCredits::new(1).execute(&client).await.unwrap_err();
143        let server_err = err.as_server_error().unwrap();
144        assert_eq!(server_err.status_code, 34);
145    }
146}
147
148#[cfg(all(test, feature = "integration"))]
149mod integration_tests {
150    use crate::client::Client;
151    use crate::client::reqwest::ReqwestExecutor;
152    use crate::prelude::Command;
153
154    use super::MovieCredits;
155
156    #[tokio::test]
157    async fn execute() {
158        let secret = std::env::var("TMDB_TOKEN_V3").unwrap();
159        let client = Client::<ReqwestExecutor>::new(secret);
160
161        for i in [550, 299641] {
162            let result = MovieCredits::new(i).execute(&client).await.unwrap();
163            assert_eq!(result.id, i);
164        }
165    }
166
167    #[tokio::test]
168    async fn execute_fr() {
169        let secret = std::env::var("TMDB_TOKEN_V3").unwrap();
170        let client = Client::<ReqwestExecutor>::new(secret);
171
172        let result = MovieCredits::new(550)
173            .with_language(Some("fr-FR".into()))
174            .execute(&client)
175            .await
176            .unwrap();
177        assert_eq!(result.id, 550);
178    }
179}