import crate_server/discogs_client.{ ArtistHit, DiscogsFormat, Release, ReleaseDetails, SearchPage, } import gleam/http/request import gleam/list import gleam/option.{None, Some} import gleam/result import gleam/set const collection_body = "{ \"pagination\": {\"page\": 1, \"pages\": 2}, \"releases\": [ {\"id\": 1, \"instance_id\": 1, \"basic_information\": { \"id\": 4577, \"title\": \"Selected Ambient Works 85-92\", \"year\": 1992, \"artists\": [{\"name\": \"Aphex Twin\"}], \"formats\": [{\"name\": \"Vinyl\"}, {\"name\": \"LP\"}], \"thumb\": \"https://i.discogs.com/t.jpg\", \"cover_image\": \"https://i.discogs.com/c.jpg\"}}, {\"id\": 2, \"instance_id\": 2, \"basic_information\": { \"id\": 9000, \"title\": \"Untitled\", \"year\": 0, \"artists\": [{\"name\": \"A\"}, {\"name\": \"B\"}], \"formats\": [], \"thumb\": \"\", \"cover_image\": \"\"}} ] }" pub fn collection_page_decodes_basic_information_test() { let send = fn(_req) { Ok(#(200, collection_body)) } let assert Ok(SearchPage(releases:, page: 1, pages: 2)) = discogs_client.collection_page(send, "OAuth ...", "someone", 1) let assert [first, second] = releases assert first == Release( discogs_id: 4577, title: "Selected Ambient Works 85-92", artist: "Aphex Twin", year: Some(1992), format: Some("Vinyl, LP"), thumb_url: Some("https://i.discogs.com/t.jpg"), cover_url: Some("https://i.discogs.com/c.jpg"), instance_id: Some(1), ) // Year 0 means unknown; empty images collapse to None; artists join. assert second.year == None assert second.artist == "A, B" assert second.thumb_url == None } pub fn collection_page_rate_limit_test() { let send = fn(_req) { Ok(#(429, "slow down")) } assert discogs_client.collection_page(send, "OAuth ...", "someone", 1) == Error("rate limited") } pub fn external_ids_includes_instance_when_known_test() { let send = fn(_req) { Ok(#(200, collection_body)) } let assert Ok(SearchPage(releases: [first, ..], ..)) = discogs_client.collection_page(send, "OAuth ...", "someone", 1) let ids = discogs_client.external_ids(first) assert list.any(ids, fn(x) { x.provider == "discogs" && x.id == "4577" }) assert list.any(ids, fn(x) { x.provider == "discogs-instance" && x.id == "1" }) } pub fn external_ids_omits_instance_when_unknown_test() { let ids = discogs_client.external_ids(release(42)) assert ids == [discogs_client.external_id(release(42))] } fn release(id: Int) -> discogs_client.Release { Release( discogs_id: id, title: "T", artist: "A", year: None, format: None, thumb_url: None, cover_url: None, instance_id: None, ) } pub fn plan_import_dedups_against_crate_and_within_run_test() { let items = [release(1), release(2), release(1), release(3)] // 2 is already in the crate with a cover. let plan = discogs_client.plan_import( items, set.from_list(["2"]), set.from_list(["2"]), 10, ) assert list.map(plan.new, fn(r) { r.discogs_id }) == [1, 3] // Skips the covered id AND the duplicate within the page. assert plan.skipped == 2 assert set.contains(plan.seen, "3") } pub fn plan_import_backfills_uncovered_entries_test() { let items = [release(1), release(2)] // 1 is in the crate but has no cover blob yet -> upsert bucket. let plan = discogs_client.plan_import(items, set.from_list(["1"]), set.new(), 10) assert list.map(plan.backfill, fn(r) { r.discogs_id }) == [1] assert list.map(plan.new, fn(r) { r.discogs_id }) == [2] assert plan.skipped == 0 } pub fn plan_import_respects_budget_across_buckets_test() { let items = [release(1), release(2), release(3)] // 1 needs a backfill; budget 2 covers it plus one new genesis. let plan = discogs_client.plan_import(items, set.from_list(["1"]), set.new(), 2) assert list.map(plan.backfill, fn(r) { r.discogs_id }) == [1] assert list.map(plan.new, fn(r) { r.discogs_id }) == [2] assert plan.skipped == 0 } const wantlist_body = "{ \"pagination\": {\"page\": 1, \"pages\": 1}, \"wants\": [ {\"id\": 4577, \"basic_information\": { \"id\": 4577, \"title\": \"Selected Ambient Works 85-92\", \"year\": 1992, \"artists\": [{\"name\": \"Aphex Twin\"}], \"formats\": [{\"name\": \"Vinyl\"}], \"thumb\": \"https://i.discogs.com/t.jpg\", \"cover_image\": \"https://i.discogs.com/c.jpg\"}} ] }" pub fn wantlist_page_decodes_wants_without_instance_test() { let send = fn(_req) { Ok(#(200, wantlist_body)) } let assert Ok(SearchPage(releases: [only], page: 1, pages: 1)) = discogs_client.wantlist_page(send, "OAuth ...", "someone", 1) assert only.discogs_id == 4577 assert only.artist == "Aphex Twin" assert only.instance_id == None } pub fn wantlist_page_rate_limit_test() { let send = fn(_req) { Ok(#(429, "slow down")) } assert discogs_client.wantlist_page(send, "OAuth ...", "someone", 1) == Error("rate limited") } const release_details_body = "{ \"id\": 4577, \"title\": \"Selected Ambient Works 85-92\", \"artists\": [{\"id\": 1, \"name\": \"Aphex Twin\"}], \"genres\": [\"Electronic\"], \"styles\": [\"Ambient\"], \"country\": \"UK\", \"released\": \"1992-02-01\", \"formats\": [ {\"name\": \"Vinyl\", \"qty\": \"2\", \"descriptions\": [\"LP\", \"Album\"]}, {\"name\": \"\", \"qty\": \"\", \"descriptions\": []} ], \"identifiers\": [{\"type\": \"Barcode\", \"value\": \"5012093219923\"}], \"images\": [{\"type\": \"primary\", \"uri\": \"https://i.discogs.com/p.jpg\"}], \"master_id\": 12526 }" pub fn release_details_decodes_formats_and_master_id_test() { let send = fn(_req) { Ok(#(200, release_details_body)) } let assert Ok(details) = discogs_client.release_details(send, None, 4577) assert details.formats == [ DiscogsFormat(name: "Vinyl", qty: Some(2), descriptions: ["LP", "Album"]), ] assert details.master_id == Some(12_526) } const release_details_body_without_formats_or_master = "{ \"id\": 4577, \"title\": \"Selected Ambient Works 85-92\", \"artists\": [{\"id\": 1, \"name\": \"Aphex Twin\"}] }" pub fn release_details_defaults_formats_and_master_id_when_absent_test() { let send = fn(_req) { Ok(#(200, release_details_body_without_formats_or_master)) } let assert Ok(ReleaseDetails(formats:, master_id:, ..)) = discogs_client.release_details(send, None, 4577) assert formats == [] assert master_id == None } pub fn release_details_rate_limit_test() { let send = fn(_req) { Ok(#(429, "slow down")) } assert discogs_client.release_details(send, None, 4577) == Error("rate limited") } pub fn release_details_other_status_is_error_test() { let send = fn(_req) { Ok(#(500, "boom")) } assert discogs_client.release_details(send, None, 4577) == Error("discogs returned status 500") } pub fn barcode_variants_despaces_and_excludes_original_test() { // 13-digit spaced barcode: de-spaced is the only useful variant; the // original (with spaces) is excluded, and a 13-digit code with no leading // zero has no UPC-A sibling. assert discogs_client.barcode_variants("5 099930 291623") == ["5099930291623"] } pub fn barcode_variants_upc_a_gains_ean_13_zero_test() { // 12-digit UPC-A: its EAN-13 sibling is the same digits with a leading zero. assert discogs_client.barcode_variants("825646350919") == ["0825646350919"] } pub fn barcode_variants_ean_13_with_leading_zero_strips_to_upc_a_test() { assert discogs_client.barcode_variants("0825646350919") == ["825646350919"] } pub fn barcode_variants_no_spaces_and_no_sibling_is_empty_test() { // 13 digits, no leading zero, no spaces: nothing to try that differs. assert discogs_client.barcode_variants("5099930291623") == [] } pub fn barcode_variants_dedupes_test() { // Spaces around a 12-digit UPC: de-spaced form plus its EAN-13 sibling, // each appearing once. assert discogs_client.barcode_variants("825 646 350919") == ["825646350919", "0825646350919"] } const artist_search_body = "{\"pagination\":{\"page\":1,\"pages\":1},\"results\":[{\"id\":123,\"title\":\"Aphex Twin\",\"thumb\":\"https://i.discogs.com/a.jpg\"}]}" pub fn search_artists_parses_discogs_artist_json_test() { let send = fn(_req) { Ok(#(200, artist_search_body)) } let assert Ok([hit]) = discogs_client.search_artists(send, None, "aphex", 1) assert hit == ArtistHit( id: "123", name: "Aphex Twin", thumb_url: Some("https://i.discogs.com/a.jpg"), ) } const empty_release_search_body = "{\"pagination\":{\"page\":1,\"pages\":1},\"results\":[]}" pub fn search_includes_artist_param_when_some_test() { let send = fn(req) { let query = request.get_query(req) |> result.unwrap([]) assert list.key_find(query, "artist") == Ok("Slint") Ok(#(200, empty_release_search_body)) } let assert Ok(_) = discogs_client.search(send, None, "spiderland", None, Some("Slint"), 1) } pub fn search_omits_artist_param_when_none_test() { let send = fn(req) { let query = request.get_query(req) |> result.unwrap([]) assert list.key_find(query, "artist") == Error(Nil) Ok(#(200, empty_release_search_body)) } let assert Ok(_) = discogs_client.search(send, None, "spiderland", None, None, 1) }