use std::path::PathBuf;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Platform {
Nes,
Gb,
Gbc,
}
impl Platform {
pub fn label(self) -> &'static str {
match self {
Platform::Nes => "NES",
Platform::Gb => "GB",
Platform::Gbc => "GBC",
}
}
pub fn thegamesdb_id(self) -> i64 {
match self {
Platform::Nes => 7,
Platform::Gb | Platform::Gbc => 4,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RomEntry {
pub path: PathBuf,
pub display_name: String,
pub search_key: String,
pub mapper_label: String,
pub mapper: Option<u16>,
pub hardware: Option<String>,
pub crc: Option<String>,
pub recording_duration: Option<std::time::Duration>,
pub metadata_game_id: Option<i64>,
pub genres: Vec<String>,
pub overview: Option<String>,
pub release_date: Option<String>,
pub players: Option<u32>,
pub rating: Option<String>,
pub boxart_path: Option<PathBuf>,
pub screenshot_paths: Vec<PathBuf>,
pub is_favorite: bool,
pub platform: Platform,
}
impl RomEntry {
pub fn hardware_label(&self) -> &str {
self.hardware.as_deref().unwrap_or("-")
}
pub fn crc_label(&self) -> &str {
self.crc.as_deref().unwrap_or("-")
}
}
#[cfg(test)]
mod tests {
use super::*;
fn make_entry(mapper: Option<u16>, hardware: Option<&str>, crc: Option<&str>) -> RomEntry {
let display_name = "Test ROM".to_string();
let search_key = display_name.to_lowercase();
let mapper_label = mapper.map_or_else(|| "-".to_string(), |m| m.to_string());
RomEntry {
path: PathBuf::from("/roms/test.nes"),
display_name,
search_key,
mapper_label,
mapper,
hardware: hardware.map(str::to_string),
crc: crc.map(str::to_string),
recording_duration: None,
metadata_game_id: None,
genres: Vec::new(),
overview: None,
release_date: None,
players: None,
rating: None,
boxart_path: None,
screenshot_paths: Vec::new(),
is_favorite: false,
platform: Platform::Nes,
}
}
#[test]
fn test_hardware_label_present() {
let entry = make_entry(None, Some("NES NTSC"), None);
assert_eq!(entry.hardware_label(), "NES NTSC");
}
#[test]
fn test_hardware_label_absent() {
let entry = make_entry(None, None, None);
assert_eq!(entry.hardware_label(), "-");
}
#[test]
fn test_mapper_label_present() {
let entry = make_entry(Some(4), None, None);
assert_eq!(entry.mapper_label, "4");
}
#[test]
fn test_mapper_label_absent() {
let entry = make_entry(None, None, None);
assert_eq!(entry.mapper_label, "-");
}
#[test]
fn test_crc_label_present() {
let entry = make_entry(None, None, Some("DEADBEEF"));
assert_eq!(entry.crc_label(), "DEADBEEF");
}
#[test]
fn test_crc_label_absent() {
let entry = make_entry(None, None, None);
assert_eq!(entry.crc_label(), "-");
}
#[test]
fn test_recording_duration_none_by_default() {
let entry = make_entry(None, None, None);
assert!(entry.recording_duration.is_none());
}
#[test]
fn test_search_key_is_lowercase_display_name() {
let entry = make_entry(None, None, None);
assert_eq!(entry.search_key, "test rom");
}
#[test]
fn test_metadata_fields_default_to_none_or_empty() {
let entry = make_entry(None, None, None);
assert!(entry.metadata_game_id.is_none());
assert!(entry.genres.is_empty());
assert!(entry.overview.is_none());
assert!(entry.release_date.is_none());
assert!(entry.players.is_none());
assert!(entry.rating.is_none());
assert!(entry.boxart_path.is_none());
assert!(entry.screenshot_paths.is_empty());
assert!(!entry.is_favorite);
}
}