tmdb_api/movie/
reviews.rs1use std::borrow::Cow;
2
3use crate::common::PaginatedResult;
4
5#[derive(Clone, Debug, Default)]
25pub struct MovieReviews {
26 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}