1use crate::store_links::StoreLinks;
3use std::cmp::{Ordering, PartialOrd};
4use std::fmt;
5
6#[derive(Serialize, Clone, Default, Debug, PartialEq, Eq)]
35pub struct Game {
36 pub uid: u32,
38 pub name: String,
40 pub cover: Option<String>,
42 pub engine: Option<String>,
44 pub setup: Option<String>,
46 pub runtime: Option<String>,
48 pub stores: Option<StoreLinks>,
50 pub hints: Option<String>,
52 pub genres: Option<Vec<String>>,
54 pub tags: Option<Vec<String>>,
56 pub year: Option<String>,
58 pub dev: Option<String>,
60 #[serde(rename = "pub")]
62 pub publi: Option<String>,
63 pub version: Option<String>,
65 pub status: Option<String>,
67 pub added: Option<String>,
69 pub updated: Option<String>,
71 pub igdb_id: Option<String>,
73}
74
75impl<'a> Game {
76 #[allow(dead_code)]
77 pub fn new() -> Self {
78 Self::default()
79 }
80 fn get_ordering_name(&'a self) -> String {
81 if let Some(name) = self.name.to_lowercase().strip_prefix("the ") {
82 return name.to_string();
83 }
84 if let Some(name) = self.name.to_lowercase().strip_prefix("a ") {
85 return name.to_string();
86 }
87 self.name.to_lowercase()
88 }
89}
90
91impl PartialOrd for Game {
92 fn partial_cmp(&self, other: &Game) -> Option<Ordering> {
93 self.get_ordering_name()
94 .partial_cmp(&other.get_ordering_name())
95 }
96 fn lt(&self, other: &Game) -> bool {
97 self.get_ordering_name().lt(&other.get_ordering_name())
98 }
99 fn le(&self, other: &Game) -> bool {
100 self.get_ordering_name().le(&other.get_ordering_name())
101 }
102 fn gt(&self, other: &Game) -> bool {
103 self.get_ordering_name().gt(&other.get_ordering_name())
104 }
105 fn ge(&self, other: &Game) -> bool {
106 self.get_ordering_name().ge(&other.get_ordering_name())
107 }
108}
109
110impl Ord for Game {
111 fn cmp(&self, other: &Game) -> Ordering {
112 self.get_ordering_name().cmp(&other.get_ordering_name())
113 }
114}
115
116impl fmt::Display for Game {
120 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
121 let game = format!("Game\t{}", self.name);
122 let cover = match &self.cover {
123 Some(cover) => format!("Cover\t{}", cover),
124 None => "Cover".to_string(),
125 };
126 let engine = match &self.engine {
127 Some(engine) => format!("Engine\t{}", engine),
128 None => "Engine".to_string(),
129 };
130 let setup = match &self.setup {
131 Some(setup) => format!("Setup\t{}", setup),
132 None => "Setup".to_string(),
133 };
134 let runtime = match &self.runtime {
135 Some(runtime) => format!("Runtime\t{}", runtime),
136 None => "Runtime".to_string(),
137 };
138 let stores = match &self.stores {
139 Some(stores) => format!(
140 "Store\t{}",
141 stores
142 .inner_ref()
143 .into_iter()
144 .map(|a| a.url.to_string())
145 .collect::<Vec<String>>()
146 .join(" ")
147 ),
148 None => "Store".to_string(),
149 };
150 let hints = match &self.hints {
151 Some(hints) => format!("Hints\t{}", hints),
152 None => "Hints".to_string(),
153 };
154 let genres = match &self.genres {
155 Some(genres) => format!("Genre\t{}", genres.join(", ")),
156 None => "Genre".to_string(),
157 };
158 let tags = match &self.tags {
159 Some(tags) => format!("Tags\t{}", tags.join(", ")),
160 None => "Tags".to_string(),
161 };
162 let year = match &self.year {
163 Some(year) => format!("Year\t{}", year),
164 None => "Year".to_string(),
165 };
166 let dev = match &self.dev {
167 Some(dev) => format!("Dev\t{}", dev),
168 None => "Dev".to_string(),
169 };
170 let publi = match &self.publi {
171 Some(publi) => format!("Pub\t{}", publi),
172 None => "Pub".to_string(),
173 };
174 let version = match &self.version {
175 Some(version) => format!("Version\t{}", version),
176 None => "Version".to_string(),
177 };
178 let status = match &self.status {
179 Some(status) => format!("Status\t{}", status),
180 None => "Status".to_string(),
181 };
182 let added = match &self.added {
183 Some(added) => format!("Added\t{}", added),
184 None => "Added".to_string(),
185 };
186 let updated = match &self.updated {
187 Some(updated) => format!("Updated\t{}", updated),
188 None => "Updated".to_string(),
189 };
190 let igdb_id = match &self.igdb_id {
191 Some(runtime) => format!("IgdbId\t{}", runtime),
192 None => "IgdbId".to_string(),
193 };
194 write!(
195 f,
196 "{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}",
197 game,
198 cover,
199 engine,
200 setup,
201 runtime,
202 stores,
203 hints,
204 genres,
205 tags,
206 year,
207 dev,
208 publi,
209 version,
210 status,
211 added,
212 updated,
213 igdb_id,
214 )
215 }
216}
217
218#[cfg(test)]
221mod game_tests {
222 use crate::store_links::StoreLink;
223
224 use super::*;
225 fn create_game() -> Game {
226 let mut game = Game::default();
227 let tags: Vec<String> = vec!["tag1".to_string(), "tag2".to_string()];
228 let genres: Vec<String> = vec!["genre1".to_string(), "genre2".to_string()];
229 let stores: Vec<String> = vec!["store1".to_string(), "store2".to_string()];
230 let store_links: Vec<StoreLink> = stores.into_iter().map(|a| StoreLink::from(&a)).collect();
231 let stores = StoreLinks(store_links);
232 game.uid = 1221;
233 game.name = "game name".to_string();
234 game.cover = Some("cover.jpg".to_string());
235 game.engine = Some("game engine".to_string());
236 game.setup = Some("game setup".to_string());
237 game.runtime = Some("game runtime".to_string());
238 game.stores = Some(stores);
239 game.hints = Some("game hints".to_string());
240 game.genres = Some(genres);
241 game.tags = Some(tags);
242 game.year = Some("1980".to_string());
243 game.dev = Some("game dev".to_string());
244 game.publi = Some("game publi".to_string());
245 game.version = Some("game version".to_string());
246 game.status = Some("game status".to_string());
247 game.added = Some("2012-12-03".to_string());
248 game.updated = Some("2014-12-03".to_string());
249 game
250 }
251 #[test]
252 fn test_default_equivalent_to_new() {
253 let game = Game::default();
254 let game_bis = Game::new();
255 assert!(game == game_bis);
256 }
257 #[test]
258 fn test_get_ordering_name_with_a() {
259 let mut game = create_game();
260 game.name = "A champion".into();
261 assert_eq!(game.get_ordering_name(), "champion");
262 game.name = "a champion".into();
263 assert_eq!(game.get_ordering_name(), "champion");
264 }
265 #[test]
266 fn test_get_ordering_name_with_the() {
267 let mut game = create_game();
268 game.name = "The champion".into();
269 assert_eq!(game.get_ordering_name(), "champion");
270 game.name = "the champion".into();
271 assert_eq!(game.get_ordering_name(), "champion");
272 }
273 #[test]
274 fn test_ordering() {
275 let mut game1 = create_game();
276 let mut game2 = create_game();
277 game1.name = "Abc".into();
278 game2.name = "Def".into();
279 assert!(game2.gt(&game1));
280 assert!(game2.ge(&game1));
281 assert!(game1.le(&game2));
282 assert!(game1.lt(&game2));
283 game1.name = "The Abc".into();
284 game2.name = "def".into();
285 assert!(game2.gt(&game1));
286 assert!(game2.ge(&game1));
287 assert!(game1.le(&game2));
288 assert!(game1.lt(&game2));
289 game1.name = "The Abc".into();
290 game2.name = "A def".into();
291 assert!(game2.gt(&game1));
292 assert!(game2.ge(&game1));
293 assert!(game1.le(&game2));
294 assert!(game1.lt(&game2));
295 }
296 #[test]
297 fn test_display() {
298 let game_str = "Game\tAaaaaAAaaaAAAaaAAAAaAAAAA!!! for the Awesome
299Cover\tAaaaaA_for_the_Awesome_Cover.jpg
300Engine
301Setup
302Runtime\tHumblePlay
303Store\thttps://www.humblebundle.com/store/aaaaaaaaaaaaaaaaaaaaaaaaa-for-the-awesome
304Hints\tDemo on HumbleBundle store page
305Genre
306Tags
307Year\t2011
308Dev
309Pub
310Version
311Status
312Added
313Updated
314IgdbId";
315 let game = Game {
316 uid: 12,
317 name: "AaaaaAAaaaAAAaaAAAAaAAAAA!!! for the Awesome".to_string(),
318 cover: Some("AaaaaA_for_the_Awesome_Cover.jpg".to_string()),
319 engine: None,
320 setup: None,
321 runtime: Some("HumblePlay".to_string()),
322 stores: Some(StoreLinks(vec![StoreLink::from(
323 "https://www.humblebundle.com/store/aaaaaaaaaaaaaaaaaaaaaaaaa-for-the-awesome",
324 )])),
325 hints: Some("Demo on HumbleBundle store page".to_string()),
326 genres: None,
327 tags: None,
328 year: Some("2011".to_string()),
329 dev: None,
330 publi: None,
331 version: None,
332 status: None,
333 added: None,
334 updated: None,
335 igdb_id: None,
336 };
337 assert_eq!(format!("{}", game), game_str);
338 }
339}