tmdb_api/movie/
reviews.rs

1use std::borrow::Cow;
2
3use crate::common::PaginatedResult;
4
5/// Get the release date along with the certification 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::reviews::MovieReviews;
12///
13/// #[tokio::main]
14/// async fn main() {
15///     let client = Client::<ReqwestExecutor>::new("this-is-my-secret-token".into());
16///     let cmd = MovieReviews::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 MovieReviews {
26    /// ID of the movie.
27    pub movie_id: u64,
28}
29
30impl MovieReviews {
31    pub fn new(movie_id: u64) -> Self {
32        Self { movie_id }
33    }
34}
35
36#[derive(Debug, Deserialize, Serialize)]
37pub struct AuthorDetails {
38    pub name: String,
39    pub username: String,
40    pub avatar_path: Option<String>,
41    pub rating: Option<f32>,
42}
43
44#[derive(Debug, Deserialize, Serialize)]
45pub struct MovieReview {
46    pub id: String,
47    pub author: String,
48    pub author_details: AuthorDetails,
49    pub content: String,
50    pub url: String,
51    pub created_at: chrono::DateTime<chrono::Utc>,
52    pub updated_at: chrono::DateTime<chrono::Utc>,
53}
54
55impl crate::prelude::Command for MovieReviews {
56    type Output = PaginatedResult<MovieReview>;
57
58    fn path(&self) -> Cow<'static, str> {
59        Cow::Owned(format!("/movie/{}/reviews", self.movie_id))
60    }
61
62    fn params(&self) -> Vec<(&'static str, Cow<'_, str>)> {
63        Vec::new()
64    }
65}
66
67#[cfg(test)]
68mod tests {
69    use super::MovieReviews;
70    use crate::client::Client;
71    use crate::client::reqwest::ReqwestExecutor;
72    use crate::prelude::Command;
73    use mockito::Matcher;
74
75    #[tokio::test]
76    async fn it_works() {
77        let mut server = mockito::Server::new_async().await;
78        let client = Client::<ReqwestExecutor>::builder()
79            .with_api_key("secret".into())
80            .with_base_url(server.url())
81            .build()
82            .unwrap();
83
84        let _m = server
85            .mock("GET", "/movie/550/reviews")
86            .match_query(Matcher::UrlEncoded("api_key".into(), "secret".into()))
87            .with_status(200)
88            .with_header("content-type", "application/json")
89            .with_body(include_str!("../../assets/movie-reviews.json"))
90            .create_async()
91            .await;
92
93        let result = MovieReviews::new(550).execute(&client).await.unwrap();
94        assert_eq!(result.page, 1);
95        assert!(!result.results.is_empty());
96    }
97
98    #[tokio::test]
99    async fn invalid_api_key() {
100        let mut server = mockito::Server::new_async().await;
101        let client = Client::<ReqwestExecutor>::builder()
102            .with_api_key("secret".into())
103            .with_base_url(server.url())
104            .build()
105            .unwrap();
106
107        let _m = server
108            .mock("GET", "/movie/550/reviews")
109            .match_query(Matcher::UrlEncoded("api_key".into(), "secret".into()))
110            .with_status(401)
111            .with_header("content-type", "application/json")
112            .with_body(include_str!("../../assets/invalid-api-key.json"))
113            .create_async()
114            .await;
115
116        let err = MovieReviews::new(550).execute(&client).await.unwrap_err();
117        let server_err = err.as_server_error().unwrap();
118        assert_eq!(server_err.status_code, 7);
119    }
120
121    #[tokio::test]
122    async fn resource_not_found() {
123        let mut server = mockito::Server::new_async().await;
124        let client = Client::<ReqwestExecutor>::builder()
125            .with_api_key("secret".into())
126            .with_base_url(server.url())
127            .build()
128            .unwrap();
129
130        let _m = server
131            .mock("GET", "/movie/550/reviews")
132            .match_query(Matcher::UrlEncoded("api_key".into(), "secret".into()))
133            .with_status(404)
134            .with_header("content-type", "application/json")
135            .with_body(include_str!("../../assets/resource-not-found.json"))
136            .create_async()
137            .await;
138
139        let err = MovieReviews::new(550).execute(&client).await.unwrap_err();
140        let server_err = err.as_server_error().unwrap();
141        assert_eq!(server_err.status_code, 34);
142    }
143}
144
145#[cfg(all(test, feature = "integration"))]
146mod integration_tests {
147    use super::MovieReviews;
148    use crate::client::Client;
149    use crate::client::reqwest::ReqwestExecutor;
150    use crate::prelude::Command;
151
152    #[tokio::test]
153    async fn execute() {
154        let secret = std::env::var("TMDB_TOKEN_V3").unwrap();
155        let client = Client::<ReqwestExecutor>::new(secret);
156
157        let result = MovieReviews::new(550).execute(&client).await.unwrap();
158        assert_eq!(result.page, 1);
159    }
160}