use {
anyhow::{Result, anyhow, ensure},
tokio::runtime::Runtime,
};
use crate::api::{
dev_server::{MockServer, make_service, make_service_without_auth},
favorites::{
add_user_favorites, delete_user_favorites, get_user_favorite_ids, get_user_favorites,
},
};
macro_rules! assert_favorites_success {
($fn:expr, $ids:expr, $item_type:expr) => {{
let body = r#"{"status":"success"}"#;
let server = MockServer::start(200, body)?;
let service = make_service(&server.base_url())?;
let rt = Runtime::new()?;
rt.block_on($fn(&service, $ids, $item_type))?;
Ok(())
}};
}
#[test]
fn add_user_favorites_success() -> Result<()> {
assert_favorites_success!(add_user_favorites, &[123, 456], "track")
}
#[test]
fn add_user_favorites_not_authenticated() -> Result<()> {
let server = MockServer::start(200, "{}")?;
let service = make_service_without_auth(&server.base_url())?;
let rt = Runtime::new()?;
let result = rt.block_on(add_user_favorites(&service, &[1], "track"));
ensure!(result.is_err());
let err = result.err().ok_or_else(|| anyhow!("expected error"))?;
ensure!(format!("{err}").contains("Not authenticated"));
Ok(())
}
#[test]
fn delete_user_favorites_success() -> Result<()> {
assert_favorites_success!(delete_user_favorites, &[123], "album")
}
#[test]
fn delete_user_favorites_not_authenticated() -> Result<()> {
let server = MockServer::start(200, "{}")?;
let service = make_service_without_auth(&server.base_url())?;
let rt = Runtime::new()?;
let result = rt.block_on(delete_user_favorites(&service, &[1], "track"));
ensure!(result.is_err());
Ok(())
}
#[test]
fn get_user_favorites_success() -> Result<()> {
let body = r#"{"albums":{"items":[{"id":"123","title":"Fav Album"}],"total":1},"artists":null,"tracks":null}"#;
let server = MockServer::start(200, body)?;
let service = make_service(&server.base_url())?;
let rt = Runtime::new()?;
let result = rt.block_on(get_user_favorites(&service, "album", Some(10), None))?;
let albums = result.albums.ok_or_else(|| anyhow!("no albums"))?;
let items = albums.items.ok_or_else(|| anyhow!("no items"))?;
ensure!(items.len() == 1);
ensure!(items.first().and_then(|i| i.title.as_deref()) == Some("Fav Album"));
Ok(())
}
#[test]
fn get_user_favorites_empty() -> Result<()> {
let body = r#"{"albums":{"items":[],"total":0},"artists":null,"tracks":null}"#;
let server = MockServer::start(200, body)?;
let service = make_service(&server.base_url())?;
let rt = Runtime::new()?;
let result = rt.block_on(get_user_favorites(&service, "album", None, None))?;
let albums = result.albums.ok_or_else(|| anyhow!("no albums"))?;
let items = albums.items.ok_or_else(|| anyhow!("no items"))?;
ensure!(items.is_empty());
Ok(())
}
#[test]
fn get_user_favorites_not_authenticated() -> Result<()> {
let server = MockServer::start(200, "{}")?;
let service = make_service_without_auth(&server.base_url())?;
let rt = Runtime::new()?;
let result = rt.block_on(get_user_favorites(&service, "track", None, None));
ensure!(result.is_err());
Ok(())
}
#[test]
fn get_user_favorite_ids_success() -> Result<()> {
let body = r#"{"album_ids":[1,2,3],"artist_ids":[4,5],"track_ids":[6,7,8,9],"albums":null,"artists":null,"tracks":null}"#;
let server = MockServer::start(200, body)?;
let service = make_service(&server.base_url())?;
let rt = Runtime::new()?;
let result = rt.block_on(get_user_favorite_ids(&service))?;
let album_ids = result.album_ids.ok_or_else(|| anyhow!("no album_ids"))?;
ensure!(album_ids == vec![1, 2, 3]);
let track_ids = result.track_ids.ok_or_else(|| anyhow!("no track_ids"))?;
ensure!(track_ids == vec![6, 7, 8, 9]);
Ok(())
}
#[test]
fn get_user_favorite_ids_not_authenticated() -> Result<()> {
let server = MockServer::start(200, "{}")?;
let service = make_service_without_auth(&server.base_url())?;
let rt = Runtime::new()?;
let result = rt.block_on(get_user_favorite_ids(&service));
ensure!(result.is_err());
Ok(())
}
#[test]
fn add_favorites_api_error() -> Result<()> {
let body = r#"{"status":"error","code":400,"message":"Invalid item type"}"#;
let server = MockServer::start(400, body)?;
let service = make_service(&server.base_url())?;
let rt = Runtime::new()?;
let result = rt.block_on(add_user_favorites(&service, &[1], "invalid_type"));
ensure!(result.is_err());
let err = result.err().ok_or_else(|| anyhow!("expected error"))?;
ensure!(format!("{err}").contains("Invalid item type"));
Ok(())
}
#[test]
fn get_favorites_with_pagination() -> Result<()> {
let body = r#"{"tracks":{"items":[{"id":1,"title":"Song"}],"total":100,"limit":1,"offset":0},"albums":null,"artists":null}"#;
let server = MockServer::start(200, body)?;
let service = make_service(&server.base_url())?;
let rt = Runtime::new()?;
let result = rt.block_on(get_user_favorites(&service, "track", Some(1), Some(0)))?;
let tracks = result.tracks.ok_or_else(|| anyhow!("no tracks"))?;
ensure!(tracks.total == Some(100));
ensure!(tracks.limit == Some(1));
ensure!(tracks.offset == Some(0));
Ok(())
}