import { test } from "node:test"; import assert from "node:assert/strict"; import { rankPeople, reasonText, reasonParts, WEIGHTS, CAPS } from "../../src/lib/discover.js"; const overlapOf = (username, albums, gaps = 0, artists = 0) => ({ username, albums_in_common_count: albums, gaps_count: gaps, artists_in_common_count: artists, }); test("one list across the shelves, every card naming where it came from", () => { const ranked = rankPeople({ me: "zoocone", rooms: { ambient: { users: [{ username: "aphex" }, { username: "zoocone" }, { username: "boc" }] }, idm: { users: [{ username: "boc" }] }, }, activeRoom: "ambient", downloads: [{ username: "aphex" }, { username: "aphex" }], uploads: [{ username: "autechre" }], similar: [{ username: "boc", rating: 3 }, { username: "aphex", rating: 1 }], overlap: [overlapOf("autechre", 4, 2), overlapOf("aphex", 0, 0, 0)], space: { name: "Late Night Ambient", members: [{ username: "boc" }, { username: null }, { username: "zoocone", is_me: true }] }, }); assert.deepEqual( ranked.map((p) => p.username), ["autechre", "boc", "aphex"], ); const [autechre, boc, aphex] = ranked; // autechre: 4 albums in common + 2 gaps, one upload assert.equal(autechre.score, 4 * WEIGHTS.albumInCommon + 2 * WEIGHTS.gap + WEIGHTS.transfer); assert.deepEqual(autechre.reasons.map(reasonText), ["shares 4 albums you own · 2 you lack", "you sent them 1"]); // boc: 3 likes, in the active room and one other, a seat in the Space assert.equal(boc.score, 3 * WEIGHTS.like + WEIGHTS.activeRoom + WEIGHTS.room + WEIGHTS.spaceMember); assert.deepEqual(boc.reasons.map(reasonText), [ "shares 3 of your declared likes", "in #ambient now · also in #idm", "with you in Late Night Ambient", ]); // aphex: a browse with nothing in common scores nothing and is not a // reason; the three that remain tie at two points each and keep the // signal order (likes, rooms, transfers) assert.equal(aphex.score, WEIGHTS.activeRoom + 2 * WEIGHTS.transfer + WEIGHTS.like); assert.deepEqual(aphex.reasons.map(reasonText), ["shares 1 of your declared likes", "in #ambient now", "sent you 2 files"]); // we never list ourselves, and a member without a Soulseek name has no card assert.ok(!ranked.some((p) => p.username === "zoocone")); }); test("contacts and friends are someone else's shelf, and a cap keeps one browse honest", () => { const ranked = rankPeople({ me: "zoocone", skip: (u) => u === "buddy", overlap: [overlapOf("buddy", 40, 40), overlapOf("hoarder", 40, 40, 40), overlapOf("thin", 0, 3, 2)], similar: [{ username: "buddy", rating: 9 }], }); assert.deepEqual(ranked.map((p) => p.username), ["hoarder", "thin"]); assert.equal(ranked[0].score, CAPS.albums * WEIGHTS.albumInCommon + CAPS.gaps * WEIGHTS.gap); // artists only count when no album is in common assert.equal(ranked[1].score, 3 * WEIGHTS.gap + 2 * WEIGHTS.artistInCommon); assert.equal(reasonText(ranked[1].reasons[0]), "2 artists in common · 3 albums you lack"); }); test("ties break toward fewer, stronger reasons, then by name; the limit holds", () => { const ranked = rankPeople({ me: "", similar: [{ username: "b", rating: 2 }, { username: "a", rating: 2 }], downloads: [{ username: "c" }, { username: "c" }, { username: "c" }, { username: "c" }], limit: 2, }); // c: 4 transfers = 4 points; a and b: 2 likes = 4 points each, one reason each assert.deepEqual(ranked.map((p) => p.username), ["a", "b"]); assert.deepEqual(rankPeople({ me: "", similar: [] }), []); assert.equal(reasonText({ kind: "rooms", active: null, others: ["x", "y"] }), "in 2 rooms with you"); // the numbers and names are what the card bolds assert.deepEqual( reasonParts({ kind: "transfers", from: 2, to: 1 }).filter((s) => s.b).map((s) => s.t), ["2", "1"], ); assert.deepEqual(reasonParts({ kind: "rooms", active: "idm", others: [] }), [ { t: "in ", b: false }, { t: "#idm", b: true }, { t: " now", b: false }, ]); });