use tokio::runtime::Runtime;
use crate::api::{
content::{
albums::search_albums,
artists::search_artists,
catalog::search_catalog,
playlists::search_playlists,
records::{Album, Artist, ItemSearchResult, Playlist, SearchResult, Track},
tracks::search_tracks,
},
service_state::QobuzApiService,
};
impl QobuzApiService {
delegate!(
pub fn search_catalog(query: &str, limit: Option<i32>, offset: Option<i32>) -> SearchResult = search_catalog
);
delegate!(
pub fn search_albums(query: &str, limit: Option<i32>, offset: Option<i32>) -> ItemSearchResult<Box<Album>> = search_albums
);
delegate!(
pub fn search_artists(query: &str, limit: Option<i32>, offset: Option<i32>) -> ItemSearchResult<Box<Artist>> = search_artists
);
delegate!(
pub fn search_tracks(query: &str, limit: Option<i32>, offset: Option<i32>) -> ItemSearchResult<Box<Track>> = search_tracks
);
delegate!(
pub fn search_playlists(query: &str, limit: Option<i32>, offset: Option<i32>) -> ItemSearchResult<Box<Playlist>> = search_playlists
);
}
#[cfg(test)]
mod tests {
use anyhow::{Result, anyhow, ensure};
use crate::api::dev_server::{MockServer, make_service};
#[test]
fn search_catalog_delegate_returns_all_groups() -> Result<()> {
let body = r#"{"albums":{"items":[{"id":"s1","title":"Blue"}],"total":1},"artists":{"items":[],"total":0},"tracks":{"items":[],"total":0},"playlists":{"items":[],"total":0}}"#;
let server = MockServer::start_with_max_requests(200, body, 16)?;
let service = make_service(&server.base_url())?;
let result = service.search_catalog("blue", Some(3), None)?;
let albums = result.albums.ok_or_else(|| anyhow!("no albums"))?;
ensure!(albums.total == Some(1), "expected total 1");
let items = albums.items.ok_or_else(|| anyhow!("no items"))?;
ensure!(items.first().and_then(|a| a.title.as_deref()) == Some("Blue"));
ensure!(
result.artists.is_some() && result.tracks.is_some() && result.playlists.is_some(),
"expected all result groups"
);
Ok(())
}
#[test]
fn search_albums_delegate_finds_matches() -> Result<()> {
let server = MockServer::start(
200,
r#"{"albums":{"items":[{"id":"x1","title":"Blue Train"}],"total":1}}"#,
)?;
let service = make_service(&server.base_url())?;
let result = service.search_albums("blue train", Some(5), None)?;
ensure!(result.total == Some(1), "expected total 1");
let items = result.items.ok_or_else(|| anyhow!("no items"))?;
ensure!(items.len() == 1, "expected one match");
ensure!(items.first().and_then(|a| a.title.as_deref()) == Some("Blue Train"));
Ok(())
}
#[test]
fn search_artists_delegate_finds_matches() -> Result<()> {
let server = MockServer::start(
200,
r#"{"artists":{"items":[{"id":7,"name":"Miles Davis"}],"total":1}}"#,
)?;
let service = make_service(&server.base_url())?;
let result = service.search_artists("miles", Some(10), None)?;
let items = result.items.ok_or_else(|| anyhow!("no items"))?;
ensure!(items.len() == 1, "expected one match");
ensure!(items.first().and_then(|a| a.name.as_deref()) == Some("Miles Davis"));
Ok(())
}
#[test]
fn search_tracks_delegate_finds_matches() -> Result<()> {
let server = MockServer::start(
200,
r#"{"tracks":{"items":[{"id":9,"title":"So What"}],"total":1}}"#,
)?;
let service = make_service(&server.base_url())?;
let result = service.search_tracks("so what", None, None)?;
ensure!(result.total == Some(1), "expected total 1");
let items = result.items.ok_or_else(|| anyhow!("no items"))?;
ensure!(items.first().and_then(|t| t.title.as_deref()) == Some("So What"));
Ok(())
}
#[test]
fn search_playlists_delegate_finds_matches() -> Result<()> {
let server = MockServer::start(
200,
r#"{"playlists":{"items":[{"id":"p9","name":"Late Night"}],"total":1}}"#,
)?;
let service = make_service(&server.base_url())?;
let result = service.search_playlists("late night", Some(5), Some(0))?;
let items = result.items.ok_or_else(|| anyhow!("no items"))?;
ensure!(!items.is_empty(), "expected matches");
ensure!(items.first().and_then(|p| p.name.as_deref()) == Some("Late Night"));
Ok(())
}
}