MediaFileClass enum

This commit is contained in:
Brandon Thomas committed 2024-03-14 03:59:39 -04:00
1 parent 1cb420f5a3
commit ba0ad9a96f
2 files changed
+190

No files matched your search

@@ -0,0 +1,189 @@
use std::collections::BTreeSet;
#[cfg(test)]
use strum::EnumCount;
#[cfg(test)]
use strum::EnumIter;
use utoipa::ToSchema;
/// Used in the `media_files` table in a `VARCHAR(16)` field.
///
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
#[cfg_attr(test, derive(EnumIter, EnumCount))]
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Deserialize, Serialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum MediaFileClass {
/// Unknown (default value)
/// This will be present until we migrate all old files.
Unknown,
/// Audio files: wav, mp3, etc.
Audio,
/// Image files: png, jpeg, etc.
Image,
/// Video files: mp4, etc.
Video,
/// Engine "animations"
Animation,
/// Engine "characters"
Character,
/// Engine "prop" items
Prop,
/// Engine scenes (internal and external scenes)
Scene,
}
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
impl_enum_display_and_debug_using_to_str!(MediaFileClass);
impl_mysql_enum_coders!(MediaFileClass);
impl_mysql_from_row!(MediaFileClass);
/// NB: Legacy API for older code.
impl MediaFileClass {
pub fn to_str(&self) -> &'static str {
match self {
Self::Unknown => "unknown",
Self::Audio => "audio",
Self::Image => "image",
Self::Video => "video",
Self::Animation => "animation",
Self::Character => "character",
Self::Prop => "prop",
Self::Scene => "scene",
}
}
pub fn from_str(value: &str) -> Result<Self, String> {
match value {
"unknown" => Ok(Self::Unknown),
"audio" => Ok(Self::Audio),
"image" => Ok(Self::Image),
"video" => Ok(Self::Video),
"animation" => Ok(Self::Animation),
"character" => Ok(Self::Character),
"prop" => Ok(Self::Prop),
"scene" => Ok(Self::Scene),
_ => Err(format!("invalid value: {:?}", value)),
}
}
pub fn all_variants() -> BTreeSet<Self> {
// NB: BTreeSet is sorted
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
BTreeSet::from([
Self::Unknown,
Self::Audio,
Self::Image,
Self::Video,
Self::Animation,
Self::Character,
Self::Prop,
Self::Scene,
])
}
}
#[cfg(test)]
mod tests {
use crate::by_table::media_files::media_file_class::MediaFileClass;
use crate::test_helpers::assert_serialization;
mod serde {
use super::*;
#[test]
fn test_serialization() {
assert_serialization(MediaFileClass::Unknown, "unknown");
assert_serialization(MediaFileClass::Audio, "audio");
assert_serialization(MediaFileClass::Image, "image");
assert_serialization(MediaFileClass::Video, "video");
assert_serialization(MediaFileClass::Animation, "animation");
assert_serialization(MediaFileClass::Character, "character");
assert_serialization(MediaFileClass::Prop, "prop");
assert_serialization(MediaFileClass::Scene, "scene");
}
}
mod impl_methods {
use super::*;
#[test]
fn to_str() {
assert_eq!(MediaFileClass::Unknown.to_str(), "unknown");
assert_eq!(MediaFileClass::Audio.to_str(), "audio");
assert_eq!(MediaFileClass::Image.to_str(), "image");
assert_eq!(MediaFileClass::Video.to_str(), "video");
assert_eq!(MediaFileClass::Animation.to_str(), "animation");
assert_eq!(MediaFileClass::Character.to_str(), "character");
assert_eq!(MediaFileClass::Prop.to_str(), "prop");
assert_eq!(MediaFileClass::Scene.to_str(), "scene");
}
#[test]
fn from_str() {
assert_eq!(MediaFileClass::from_str("unknown").unwrap(), MediaFileClass::Unknown);
assert_eq!(MediaFileClass::from_str("audio").unwrap(), MediaFileClass::Audio);
assert_eq!(MediaFileClass::from_str("image").unwrap(), MediaFileClass::Image);
assert_eq!(MediaFileClass::from_str("video").unwrap(), MediaFileClass::Video);
assert_eq!(MediaFileClass::from_str("animation").unwrap(), MediaFileClass::Animation);
assert_eq!(MediaFileClass::from_str("character").unwrap(), MediaFileClass::Character);
assert_eq!(MediaFileClass::from_str("prop").unwrap(), MediaFileClass::Prop);
assert_eq!(MediaFileClass::from_str("scene").unwrap(), MediaFileClass::Scene);
assert!(MediaFileClass::from_str("foo").is_err());
}
}
mod manual_variant_checks {
use super::*;
#[test]
fn all_variants() {
let mut variants = MediaFileClass::all_variants();
assert_eq!(variants.len(), 8);
assert_eq!(variants.pop_first(), Some(MediaFileClass::Unknown));
assert_eq!(variants.pop_first(), Some(MediaFileClass::Audio));
assert_eq!(variants.pop_first(), Some(MediaFileClass::Image));
assert_eq!(variants.pop_first(), Some(MediaFileClass::Video));
assert_eq!(variants.pop_first(), Some(MediaFileClass::Animation));
assert_eq!(variants.pop_first(), Some(MediaFileClass::Character));
assert_eq!(variants.pop_first(), Some(MediaFileClass::Prop));
assert_eq!(variants.pop_first(), Some(MediaFileClass::Scene));
assert_eq!(variants.pop_first(), None);
}
}
mod mechanical_checks {
use super::*;
#[test]
fn variant_length() {
use strum::IntoEnumIterator;
assert_eq!(MediaFileClass::all_variants().len(), MediaFileClass::iter().len());
}
#[test]
fn round_trip() {
for variant in MediaFileClass::all_variants() {
assert_eq!(variant, MediaFileClass::from_str(variant.to_str()).unwrap());
assert_eq!(variant, MediaFileClass::from_str(&format!("{}", variant)).unwrap());
assert_eq!(variant, MediaFileClass::from_str(&format!("{:?}", variant)).unwrap());
}
}
#[test]
fn serialized_length_ok_for_database() {
const MAX_LENGTH : usize = 16;
for variant in MediaFileClass::all_variants() {
let serialized = variant.to_str();
assert!(serialized.len() > 0, "variant {:?} is too short", variant);
assert!(serialized.len() <= MAX_LENGTH, "variant {:?} is too long", variant);
}
}
}
}
@@ -1,3 +1,4 @@
pub mod media_file_class;
pub mod media_file_origin_category;
pub mod media_file_origin_model_type;
pub mod media_file_origin_product_category;