mediapulse 0.1.8

A self-contained native media player built around mpv
use std::sync::{Arc, Mutex};

use mediapulse_core::backend::{
    BackendError, BackendKind, PlaybackBackend, PlaybackCommand, PlaybackSnapshot, PropertyUpdate,
    PropertyValue,
};
use tauri::test::{INVOKE_KEY, get_ipc_response, mock_builder, mock_context, noop_assets};
use tauri::webview::InvokeRequest;
use tauri::{WebviewUrl, http::HeaderMap};

use crate::commands;
use crate::state::AppState;

#[derive(Default)]
struct StubBackend {
    loaded: Mutex<Vec<String>>,
}

impl PlaybackBackend for StubBackend {
    fn backend_kind(&self) -> BackendKind {
        BackendKind::Libmpv
    }

    fn load(&self, source: &str) -> Result<(), BackendError> {
        self.loaded
            .lock()
            .expect("loaded lock")
            .push(source.to_owned());
        Ok(())
    }

    fn command(&self, _command: PlaybackCommand) -> Result<(), BackendError> {
        Ok(())
    }

    fn set_property(&self, _update: PropertyUpdate) -> Result<(), BackendError> {
        Ok(())
    }

    fn get_property(&self, _name: &str) -> Result<PropertyValue, BackendError> {
        Ok(PropertyValue::Unit)
    }

    fn snapshot(&self) -> Result<PlaybackSnapshot, BackendError> {
        Ok(PlaybackSnapshot::default())
    }

    fn shutdown(&self) -> Result<(), BackendError> {
        Ok(())
    }
}

fn invoke<W: AsRef<tauri::Webview<tauri::test::MockRuntime>>>(
    webview: &W,
    cmd: &str,
    body: serde_json::Value,
) -> Result<tauri::ipc::InvokeResponseBody, serde_json::Value> {
    get_ipc_response(
        webview,
        InvokeRequest {
            cmd: cmd.into(),
            callback: tauri::ipc::CallbackFn(0),
            error: tauri::ipc::CallbackFn(1),
            url: "tauri://localhost".parse().expect("invoke url"),
            body: tauri::ipc::InvokeBody::Json(body),
            headers: HeaderMap::new(),
            invoke_key: INVOKE_KEY.to_string(),
        },
    )
}

#[test]
fn load_media_resolves_managed_state_and_dispatches_to_the_backend() {
    let backend = Arc::new(StubBackend::default());
    let app = mock_builder()
        .manage(Arc::new(AppState::with_backend(backend.clone())))
        .invoke_handler(tauri::generate_handler![commands::load_media])
        .build(mock_context(noop_assets()))
        .expect("mock app");

    let window = tauri::WebviewWindowBuilder::new(&app, "main", WebviewUrl::default())
        .build()
        .expect("mock window");

    let source = "/tmp/opencode/mediapulse-ipc-fixture.mp4";
    let response = invoke(
        &window,
        "load_media",
        serde_json::json!({ "source": source }),
    );

    assert!(
        response.is_ok(),
        "load_media must resolve the managed Arc<AppState>, got: {response:?}"
    );
    assert_eq!(
        backend.loaded.lock().expect("loaded lock").as_slice(),
        [source]
    );
}