diff --git a/src/database/key_value/media.rs b/src/database/key_value/media.rs index 713c8b05..1e7866d5 100644 --- a/src/database/key_value/media.rs +++ b/src/database/key_value/media.rs @@ -9,6 +9,7 @@ use crate::{ utils, Error, Result, }; +#[derive(Debug, Eq, PartialEq)] struct MediaFileKeyParts { mxc: OwnedMxcUri, width: u32, @@ -218,3 +219,142 @@ impl service::media::Data for KeyValueDatabase { ) } } + +#[cfg(test)] +mod test { + use super::{FileMeta, MediaFileKey, MediaFileKeyParts}; + + #[test] + fn parse_key_basic() { + let mut key = b"mxc://example.com/someid".to_vec(); + key.push(0xFF); + key.extend_from_slice(&640_u32.to_be_bytes()); + key.extend_from_slice(&480_u32.to_be_bytes()); + key.push(0xFF); + key.extend_from_slice(b"inline"); + key.push(0xFF); + key.extend_from_slice(b"image/png"); + let key = MediaFileKey::new(key); + + assert_eq!( + MediaFileKeyParts::try_from(&key).unwrap(), + MediaFileKeyParts { + mxc: "mxc://example.com/someid".into(), + width: 640, + height: 480, + meta: FileMeta { + content_disposition: Some("inline".to_owned()), + content_type: Some("image/png".to_owned()), + } + } + ); + } + + #[test] + fn parse_key_no_content_type() { + let mut key = b"mxc://example.com/someid".to_vec(); + key.push(0xFF); + key.extend_from_slice(&640_u32.to_be_bytes()); + key.extend_from_slice(&480_u32.to_be_bytes()); + key.push(0xFF); + key.extend_from_slice(b"inline"); + key.push(0xFF); + // No content type + let key = MediaFileKey::new(key); + + assert_eq!( + MediaFileKeyParts::try_from(&key).unwrap(), + MediaFileKeyParts { + mxc: "mxc://example.com/someid".into(), + width: 640, + height: 480, + meta: FileMeta { + content_disposition: Some("inline".to_owned()), + content_type: None, + } + } + ); + } + + #[test] + fn parse_key_no_content_disposition() { + let mut key = b"mxc://example.com/someid".to_vec(); + key.push(0xFF); + key.extend_from_slice(&640_u32.to_be_bytes()); + key.extend_from_slice(&480_u32.to_be_bytes()); + key.push(0xFF); + // No content disposition + key.push(0xFF); + key.extend_from_slice(b"image/png"); + let key = MediaFileKey::new(key); + + assert_eq!( + MediaFileKeyParts::try_from(&key).unwrap(), + MediaFileKeyParts { + mxc: "mxc://example.com/someid".into(), + width: 640, + height: 480, + meta: FileMeta { + content_disposition: None, + content_type: Some("image/png".to_owned()), + } + } + ); + } + + #[test] + fn parse_key_no_content_disposition_or_type() { + let mut key = b"mxc://example.com/someid".to_vec(); + key.push(0xFF); + key.extend_from_slice(&640_u32.to_be_bytes()); + key.extend_from_slice(&480_u32.to_be_bytes()); + key.push(0xFF); + // No content disposition + key.push(0xFF); + // No content type + let key = MediaFileKey::new(key); + + assert_eq!( + MediaFileKeyParts::try_from(&key).unwrap(), + MediaFileKeyParts { + mxc: "mxc://example.com/someid".into(), + width: 640, + height: 480, + meta: FileMeta { + content_disposition: None, + content_type: None, + } + } + ); + } + + // Our current media service code has an allowlist of thumbnail dimensions, + // and so we don't expect to create new thumbnails with dimensions + // containing a 0xFF byte. Thumbnails with a 0xFF in the dimensions may + // have been created previously, so we need to be able to read them. + #[test] + fn parse_key_separator_in_thumbnail_dims() { + let mut key = b"mxc://example.com/someid".to_vec(); + key.push(0xFF); + key.extend_from_slice(&[0x0, 0x0, 0xFF, 0xFF]); + key.extend_from_slice(&[0x0, 0x0, 0x10, 0xFF]); + key.push(0xFF); + key.extend_from_slice(b"inline"); + key.push(0xFF); + key.extend_from_slice(b"image/png"); + let key = MediaFileKey::new(key); + + assert_eq!( + MediaFileKeyParts::try_from(&key).unwrap(), + MediaFileKeyParts { + mxc: "mxc://example.com/someid".into(), + width: 0xFFFF, + height: 0x10FF, + meta: FileMeta { + content_disposition: Some("inline".to_owned()), + content_type: Some("image/png".to_owned()), + } + } + ); + } +} diff --git a/src/service/media.rs b/src/service/media.rs index 03109004..399dc1dd 100644 --- a/src/service/media.rs +++ b/src/service/media.rs @@ -14,6 +14,7 @@ mod data; pub(crate) use data::Data; +#[derive(Debug, Eq, PartialEq)] pub(crate) struct FileMeta { // This gets written to the database but we no longer read it //