use crate::store_links::StoreLinks;
use std::cmp::{Ordering, PartialOrd};
use std::fmt;
#[derive(Serialize, Clone, Default, Debug, PartialEq, Eq)]
pub struct Game {
pub uid: u32,
pub name: String,
pub cover: Option<String>,
pub engine: Option<String>,
pub setup: Option<String>,
pub runtime: Option<String>,
pub stores: Option<StoreLinks>,
pub hints: Option<String>,
pub genres: Option<Vec<String>>,
pub tags: Option<Vec<String>>,
pub year: Option<String>,
pub dev: Option<String>,
#[serde(rename = "pub")]
pub publi: Option<String>,
pub version: Option<String>,
pub status: Option<String>,
pub added: Option<String>,
pub updated: Option<String>,
pub igdb_id: Option<String>,
}
impl<'a> Game {
#[allow(dead_code)]
pub fn new() -> Self {
Self::default()
}
fn get_ordering_name(&'a self) -> String {
if let Some(name) = self.name.to_lowercase().strip_prefix("the ") {
return name.to_string();
}
if let Some(name) = self.name.to_lowercase().strip_prefix("a ") {
return name.to_string();
}
self.name.to_lowercase()
}
}
impl PartialOrd for Game {
fn partial_cmp(&self, other: &Game) -> Option<Ordering> {
self.get_ordering_name()
.partial_cmp(&other.get_ordering_name())
}
fn lt(&self, other: &Game) -> bool {
self.get_ordering_name().lt(&other.get_ordering_name())
}
fn le(&self, other: &Game) -> bool {
self.get_ordering_name().le(&other.get_ordering_name())
}
fn gt(&self, other: &Game) -> bool {
self.get_ordering_name().gt(&other.get_ordering_name())
}
fn ge(&self, other: &Game) -> bool {
self.get_ordering_name().ge(&other.get_ordering_name())
}
}
impl Ord for Game {
fn cmp(&self, other: &Game) -> Ordering {
self.get_ordering_name().cmp(&other.get_ordering_name())
}
}
impl fmt::Display for Game {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let game = format!("Game\t{}", self.name);
let cover = match &self.cover {
Some(cover) => format!("Cover\t{}", cover),
None => "Cover".to_string(),
};
let engine = match &self.engine {
Some(engine) => format!("Engine\t{}", engine),
None => "Engine".to_string(),
};
let setup = match &self.setup {
Some(setup) => format!("Setup\t{}", setup),
None => "Setup".to_string(),
};
let runtime = match &self.runtime {
Some(runtime) => format!("Runtime\t{}", runtime),
None => "Runtime".to_string(),
};
let stores = match &self.stores {
Some(stores) => format!(
"Store\t{}",
stores
.inner_ref()
.into_iter()
.map(|a| a.url.to_string())
.collect::<Vec<String>>()
.join(" ")
),
None => "Store".to_string(),
};
let hints = match &self.hints {
Some(hints) => format!("Hints\t{}", hints),
None => "Hints".to_string(),
};
let genres = match &self.genres {
Some(genres) => format!("Genre\t{}", genres.join(", ")),
None => "Genre".to_string(),
};
let tags = match &self.tags {
Some(tags) => format!("Tags\t{}", tags.join(", ")),
None => "Tags".to_string(),
};
let year = match &self.year {
Some(year) => format!("Year\t{}", year),
None => "Year".to_string(),
};
let dev = match &self.dev {
Some(dev) => format!("Dev\t{}", dev),
None => "Dev".to_string(),
};
let publi = match &self.publi {
Some(publi) => format!("Pub\t{}", publi),
None => "Pub".to_string(),
};
let version = match &self.version {
Some(version) => format!("Version\t{}", version),
None => "Version".to_string(),
};
let status = match &self.status {
Some(status) => format!("Status\t{}", status),
None => "Status".to_string(),
};
let added = match &self.added {
Some(added) => format!("Added\t{}", added),
None => "Added".to_string(),
};
let updated = match &self.updated {
Some(updated) => format!("Updated\t{}", updated),
None => "Updated".to_string(),
};
let igdb_id = match &self.igdb_id {
Some(runtime) => format!("IgdbId\t{}", runtime),
None => "IgdbId".to_string(),
};
write!(
f,
"{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}",
game,
cover,
engine,
setup,
runtime,
stores,
hints,
genres,
tags,
year,
dev,
publi,
version,
status,
added,
updated,
igdb_id,
)
}
}
#[cfg(test)]
mod game_tests {
use crate::store_links::StoreLink;
use super::*;
fn create_game() -> Game {
let mut game = Game::default();
let tags: Vec<String> = vec!["tag1".to_string(), "tag2".to_string()];
let genres: Vec<String> = vec!["genre1".to_string(), "genre2".to_string()];
let stores: Vec<String> = vec!["store1".to_string(), "store2".to_string()];
let store_links: Vec<StoreLink> = stores.into_iter().map(|a| StoreLink::from(&a)).collect();
let stores = StoreLinks(store_links);
game.uid = 1221;
game.name = "game name".to_string();
game.cover = Some("cover.jpg".to_string());
game.engine = Some("game engine".to_string());
game.setup = Some("game setup".to_string());
game.runtime = Some("game runtime".to_string());
game.stores = Some(stores);
game.hints = Some("game hints".to_string());
game.genres = Some(genres);
game.tags = Some(tags);
game.year = Some("1980".to_string());
game.dev = Some("game dev".to_string());
game.publi = Some("game publi".to_string());
game.version = Some("game version".to_string());
game.status = Some("game status".to_string());
game.added = Some("2012-12-03".to_string());
game.updated = Some("2014-12-03".to_string());
game
}
#[test]
fn test_default_equivalent_to_new() {
let game = Game::default();
let game_bis = Game::new();
assert!(game == game_bis);
}
#[test]
fn test_get_ordering_name_with_a() {
let mut game = create_game();
game.name = "A champion".into();
assert_eq!(game.get_ordering_name(), "champion");
game.name = "a champion".into();
assert_eq!(game.get_ordering_name(), "champion");
}
#[test]
fn test_get_ordering_name_with_the() {
let mut game = create_game();
game.name = "The champion".into();
assert_eq!(game.get_ordering_name(), "champion");
game.name = "the champion".into();
assert_eq!(game.get_ordering_name(), "champion");
}
#[test]
fn test_ordering() {
let mut game1 = create_game();
let mut game2 = create_game();
game1.name = "Abc".into();
game2.name = "Def".into();
assert!(game2.gt(&game1));
assert!(game2.ge(&game1));
assert!(game1.le(&game2));
assert!(game1.lt(&game2));
game1.name = "The Abc".into();
game2.name = "def".into();
assert!(game2.gt(&game1));
assert!(game2.ge(&game1));
assert!(game1.le(&game2));
assert!(game1.lt(&game2));
game1.name = "The Abc".into();
game2.name = "A def".into();
assert!(game2.gt(&game1));
assert!(game2.ge(&game1));
assert!(game1.le(&game2));
assert!(game1.lt(&game2));
}
#[test]
fn test_display() {
let game_str = "Game\tAaaaaAAaaaAAAaaAAAAaAAAAA!!! for the Awesome
Cover\tAaaaaA_for_the_Awesome_Cover.jpg
Engine
Setup
Runtime\tHumblePlay
Store\thttps://www.humblebundle.com/store/aaaaaaaaaaaaaaaaaaaaaaaaa-for-the-awesome
Hints\tDemo on HumbleBundle store page
Genre
Tags
Year\t2011
Dev
Pub
Version
Status
Added
Updated
IgdbId";
let game = Game {
uid: 12,
name: "AaaaaAAaaaAAAaaAAAAaAAAAA!!! for the Awesome".to_string(),
cover: Some("AaaaaA_for_the_Awesome_Cover.jpg".to_string()),
engine: None,
setup: None,
runtime: Some("HumblePlay".to_string()),
stores: Some(StoreLinks(vec![StoreLink::from(
"https://www.humblebundle.com/store/aaaaaaaaaaaaaaaaaaaaaaaaa-for-the-awesome",
)])),
hints: Some("Demo on HumbleBundle store page".to_string()),
genres: None,
tags: None,
year: Some("2011".to_string()),
dev: None,
publi: None,
version: None,
status: None,
added: None,
updated: None,
igdb_id: None,
};
assert_eq!(format!("{}", game), game_str);
}
}