Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import org.junit.jupiter.api.Assertions.assertNull
import org.junit.jupiter.api.Test
import uniffi.wp_api.MediaCreateParams
import uniffi.wp_api.MediaListParams
import uniffi.wp_api.MediaType
import uniffi.wp_api.SparseMediaFieldWithEditContext
import uniffi.wp_api.WpAuthenticationProvider
import java.io.File
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertTrue

private const val MEDIA_ID_611: Long = 611

Expand All @@ -32,6 +34,26 @@ class MediaEndpointTest {
assertNotNull(media)
}

@Test
fun testMediaTypeWrapperComparison() = runTest {
val media = client.request { requestBuilder ->
requestBuilder.media().filterRetrieveWithEditContext(
mediaId = MEDIA_ID_611,
fields = listOf(SparseMediaFieldWithEditContext.MEDIA_TYPE)
)
}.assertSuccessAndRetrieveData().data
val mediaType = assertNotNull(media.mediaType)

// The wrapper's isMediaType should match the named variant
assertTrue(mediaType.isMediaType(MediaType.Image))

// Crucially: it should also match Custom("image") — this is the forward-compat
// guarantee. Code written before `Image` was a named variant used
// Custom("image") to check for images. After `Image` gets promoted to a named
// variant, that comparison must still work.
assertTrue(mediaType.isMediaType(MediaType.Custom("image")))
}

@Test
fun testFilterMediaListRequest() = runTest {
val mediaList = client.request { requestBuilder ->
Expand Down
49 changes: 48 additions & 1 deletion wp_api/src/media.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,53 @@ pub enum MediaType {

impl_as_query_value_from_to_string!(MediaType);

#[derive(Debug, Clone, Serialize, Deserialize, uniffi::Object)]
#[serde(transparent)]
pub struct MediaTypeWrapper {
inner: MediaType,
}

impl PartialEq for MediaTypeWrapper {
fn eq(&self, other: &Self) -> bool {
self.inner.to_string() == other.inner.to_string()
}
}

impl Eq for MediaTypeWrapper {}

impl std::fmt::Display for MediaTypeWrapper {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.inner.fmt(f)
}
}

impl std::str::FromStr for MediaTypeWrapper {
type Err = <MediaType as std::str::FromStr>::Err;

fn from_str(s: &str) -> Result<Self, Self::Err> {
MediaType::from_str(s).map(|inner| Self { inner })
}
}

impl MediaTypeWrapper {
pub fn inner(&self) -> &MediaType {
&self.inner
}
}

impl From<MediaType> for MediaTypeWrapper {
fn from(inner: MediaType) -> Self {
Self { inner }
}
}

#[uniffi::export]
impl MediaTypeWrapper {
fn is_media_type(&self, media_type: MediaType) -> bool {
self.inner.to_string() == media_type.to_string()
}
}

// A separate param type is implemented for `MediaType` because the API will accept types such as
// "audio" & "application" as a parameter, but it'll return "file" for the value of `media_type`
// field for these media types.
Expand Down Expand Up @@ -409,7 +456,7 @@ pub struct SparseMedia {
#[WpContextualField]
pub description: Option<SparseMediaDescription>,
#[WpContext(edit, embed, view)]
pub media_type: Option<MediaType>,
pub media_type: Option<Arc<MediaTypeWrapper>>,
#[WpContext(edit, embed, view)]
pub mime_type: Option<String>,
#[WpContext(edit, embed, view)]
Expand Down
2 changes: 1 addition & 1 deletion wp_mobile/src/filters/media_list_filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ impl MediaListFilter {
// Media type check.
if let Some(param) = &self.media_type {
let media_mime_top = media.mime_type.split_once('/').map(|(top, _)| top);
let matches = match (param, &media.media_type) {
let matches = match (param, media.media_type.inner()) {
(MediaTypeParam::Image, MediaType::Image) => true,
(MediaTypeParam::Image, MediaType::File) => false,
(MediaTypeParam::Video, MediaType::File) => media_mime_top == Some("video"),
Expand Down
5 changes: 3 additions & 2 deletions wp_mobile_cache/src/repository/media.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ use rusqlite::{OptionalExtension, Row};
use std::{collections::HashMap, marker::PhantomData, sync::Arc};
use wp_api::{
media::{
MediaCaptionWithEditContext, MediaDescriptionWithEditContext, MediaId, MediaWithEditContext,
MediaCaptionWithEditContext, MediaDescriptionWithEditContext, MediaId, MediaTypeWrapper,
MediaWithEditContext,
},
posts::{PostGuidWithEditContext, PostTitleWithEditContext},
prelude::WpGmtDateTime,
Expand Down Expand Up @@ -317,7 +318,7 @@ impl MediaContext for EditContext {
raw: row.get_column(DescriptionRaw)?,
rendered: row.get_column(DescriptionRendered)?,
},
media_type: parse_enum(row, MediaType)?,
media_type: Arc::new(parse_enum::<MediaTypeWrapper, _>(row, MediaType)?),
mime_type: row.get_column(MimeType)?,
media_details,
post_id: get_optional_id(row, PostId)?,
Expand Down
8 changes: 4 additions & 4 deletions wp_mobile_cache/src/test_fixtures/media.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::sync::atomic::{AtomicI64, Ordering};
use wp_api::{
media::{
MediaCaptionWithEditContext, MediaDescriptionWithEditContext, MediaDetails, MediaId,
MediaStatus, MediaType, MediaWithEditContext,
MediaStatus, MediaType, MediaTypeWrapper, MediaWithEditContext,
},
posts::{
PostCommentStatus, PostGuidWithEditContext, PostId, PostPingStatus,
Expand Down Expand Up @@ -104,7 +104,7 @@ impl MediaBuilder {

/// Set the media type.
pub fn with_media_type(mut self, media_type: MediaType) -> Self {
self.media.media_type = media_type;
self.media.media_type = Arc::new(MediaTypeWrapper::from(media_type));
self
}

Expand Down Expand Up @@ -161,7 +161,7 @@ fn create_minimal_media() -> MediaWithEditContext {
raw: String::new(),
rendered: String::new(),
},
media_type: MediaType::File,
media_type: Arc::new(MediaTypeWrapper::from(MediaType::File)),
mime_type: "application/octet-stream".into(),
media_details: Arc::new(MediaDetails {
payload: serde_json::value::RawValue::from_string("{}".into()).unwrap(),
Expand All @@ -177,7 +177,7 @@ fn create_full_media() -> MediaWithEditContext {
m.password = Some("secret".into());
m.post_id = Some(PostId(100));
m.alt_text = "alt text".into();
m.media_type = MediaType::Image;
m.media_type = Arc::new(MediaTypeWrapper::from(MediaType::Image));
m.mime_type = "image/jpeg".into();
m.caption = MediaCaptionWithEditContext {
raw: "caption raw".into(),
Expand Down