Files
search/tests/integration.rs
Connor Johnstone d358b79a6b Formatting
2026-03-18 15:37:21 -04:00

214 lines
6.1 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),
},
],
})
}
async fn get_release_groups(
&self,
_artist_id: &str,
) -> SearchResult<Vec<shanty_search::ReleaseGroupResult>> {
Ok(vec![])
}
}
#[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();
}