189 lines
5.8 KiB
Rust
189 lines
5.8 KiB
Rust
use shanty_db::Database;
|
|
use shanty_search::cache;
|
|
use shanty_search::error::SearchResult;
|
|
use shanty_search::provider::*;
|
|
|
|
/// Mock search provider for testing.
|
|
struct MockSearch;
|
|
|
|
impl SearchProvider for MockSearch {
|
|
async fn search_artist(&self, query: &str, _limit: u32) -> SearchResult<Vec<ArtistResult>> {
|
|
if query.contains("Pink Floyd") {
|
|
Ok(vec![ArtistResult {
|
|
id: "83d91898-7763-47d7-b03b-b92132375c47".into(),
|
|
name: "Pink Floyd".into(),
|
|
disambiguation: Some("English rock band".into()),
|
|
country: Some("GB".into()),
|
|
artist_type: Some("Group".into()),
|
|
score: 100,
|
|
}])
|
|
} else {
|
|
Ok(vec![])
|
|
}
|
|
}
|
|
|
|
async fn search_album(
|
|
&self,
|
|
query: &str,
|
|
_artist_hint: Option<&str>,
|
|
_limit: u32,
|
|
) -> SearchResult<Vec<AlbumResult>> {
|
|
if query.contains("Dark Side") {
|
|
Ok(vec![AlbumResult {
|
|
id: "release-123".into(),
|
|
title: "The Dark Side of the Moon".into(),
|
|
artist: "Pink Floyd".into(),
|
|
artist_id: Some("83d91898".into()),
|
|
year: Some("1973".into()),
|
|
track_count: Some(10),
|
|
score: 100,
|
|
}])
|
|
} else {
|
|
Ok(vec![])
|
|
}
|
|
}
|
|
|
|
async fn search_track(
|
|
&self,
|
|
query: &str,
|
|
_artist_hint: Option<&str>,
|
|
_limit: u32,
|
|
) -> SearchResult<Vec<TrackResult>> {
|
|
if query.contains("Time") {
|
|
Ok(vec![TrackResult {
|
|
id: "rec-456".into(),
|
|
title: "Time".into(),
|
|
artist: "Pink Floyd".into(),
|
|
artist_id: Some("83d91898".into()),
|
|
album: Some("The Dark Side of the Moon".into()),
|
|
duration_ms: Some(413_000),
|
|
score: 100,
|
|
}])
|
|
} else {
|
|
Ok(vec![])
|
|
}
|
|
}
|
|
|
|
async fn get_discography(&self, _artist_id: &str) -> SearchResult<Discography> {
|
|
Ok(Discography {
|
|
artist_name: "Pink Floyd".into(),
|
|
artist_id: "83d91898".into(),
|
|
releases: vec![
|
|
DiscographyEntry {
|
|
id: "r1".into(),
|
|
title: "The Dark Side of the Moon".into(),
|
|
date: Some("1973-03-01".into()),
|
|
release_type: Some("Album".into()),
|
|
track_count: Some(10),
|
|
},
|
|
DiscographyEntry {
|
|
id: "r2".into(),
|
|
title: "Wish You Were Here".into(),
|
|
date: Some("1975-09-12".into()),
|
|
release_type: Some("Album".into()),
|
|
track_count: Some(5),
|
|
},
|
|
],
|
|
})
|
|
}
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_search_artist() {
|
|
let provider = MockSearch;
|
|
let results = provider.search_artist("Pink Floyd", 10).await.unwrap();
|
|
assert_eq!(results.len(), 1);
|
|
assert_eq!(results[0].name, "Pink Floyd");
|
|
assert_eq!(results[0].country.as_deref(), Some("GB"));
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_search_artist_no_results() {
|
|
let provider = MockSearch;
|
|
let results = provider.search_artist("Nonexistent Band", 10).await.unwrap();
|
|
assert!(results.is_empty());
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_search_album() {
|
|
let provider = MockSearch;
|
|
let results = provider.search_album("Dark Side", Some("Pink Floyd"), 10).await.unwrap();
|
|
assert_eq!(results.len(), 1);
|
|
assert_eq!(results[0].title, "The Dark Side of the Moon");
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_search_track() {
|
|
let provider = MockSearch;
|
|
let results = provider.search_track("Time", Some("Pink Floyd"), 10).await.unwrap();
|
|
assert_eq!(results.len(), 1);
|
|
assert_eq!(results[0].title, "Time");
|
|
assert_eq!(results[0].album.as_deref(), Some("The Dark Side of the Moon"));
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_discography() {
|
|
let provider = MockSearch;
|
|
let disco = provider.get_discography("83d91898").await.unwrap();
|
|
assert_eq!(disco.artist_name, "Pink Floyd");
|
|
assert_eq!(disco.releases.len(), 2);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_result_serialization() {
|
|
let result = ArtistResult {
|
|
id: "test-id".into(),
|
|
name: "Test Artist".into(),
|
|
disambiguation: None,
|
|
country: Some("US".into()),
|
|
artist_type: Some("Person".into()),
|
|
score: 95,
|
|
};
|
|
let json = serde_json::to_string(&result).unwrap();
|
|
let back: ArtistResult = serde_json::from_str(&json).unwrap();
|
|
assert_eq!(back.name, "Test Artist");
|
|
assert_eq!(back.score, 95);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_cache_roundtrip() {
|
|
let db = Database::new("sqlite::memory:").await.unwrap();
|
|
let results = vec![ArtistResult {
|
|
id: "123".into(),
|
|
name: "Cached Artist".into(),
|
|
disambiguation: None,
|
|
country: None,
|
|
artist_type: None,
|
|
score: 90,
|
|
}];
|
|
|
|
// Cache miss
|
|
let cached: Option<Vec<ArtistResult>> =
|
|
cache::get_cached(Some(db.conn()), "test:artist:query").await.unwrap();
|
|
assert!(cached.is_none());
|
|
|
|
// Store
|
|
cache::set_cached(Some(db.conn()), "test:artist:query", "musicbrainz", &results)
|
|
.await
|
|
.unwrap();
|
|
|
|
// Cache hit
|
|
let cached: Option<Vec<ArtistResult>> =
|
|
cache::get_cached(Some(db.conn()), "test:artist:query").await.unwrap();
|
|
assert!(cached.is_some());
|
|
assert_eq!(cached.unwrap()[0].name, "Cached Artist");
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_cache_none_conn() {
|
|
// With no DB connection, caching is a no-op
|
|
let cached: Option<Vec<ArtistResult>> =
|
|
cache::get_cached(None, "anything").await.unwrap();
|
|
assert!(cached.is_none());
|
|
|
|
// set_cached with None conn should not error
|
|
cache::set_cached::<Vec<ArtistResult>>(None, "key", "provider", &vec![])
|
|
.await
|
|
.unwrap();
|
|
}
|