import { describe, expect, it } from "vitest";
import {
addPinned,
movePinned,
PINNED_LIMIT,
pinKeyOf,
pinnedWith,
removePinned
} from "#lib/api/pinning.ts";
import type { ProfileRecord } from "#lib/api/records.ts";
const profile = {
$type: "org.tangled.actor.profile",
description: "Hi.",
isOrganization: true,
pinnedRepositories: ["did:plc:a"]
} as ProfileRecord;
describe("pinnedWith", () => {
it("appends a pinned repository and keeps the rest of the profile", () => {
expect(pinnedWith(profile, "did:plc:b", true)).toEqual({
...profile,
pinnedRepositories: ["did:plc:a", "did:plc:b"]
});
});
it("does not pin the same repository twice", () => {
expect(pinnedWith(profile, "did:plc:a", true).pinnedRepositories).toEqual(["did:plc:a"]);
});
it("drops the field when the last repository is unpinned", () => {
expect(pinnedWith(profile, "did:plc:a", false)).not.toHaveProperty("pinnedRepositories");
});
it("starts a profile record when there is none", () => {
expect(pinnedWith(null, "did:plc:a", true)).toEqual({
$type: "org.tangled.actor.profile",
pinnedRepositories: ["did:plc:a"]
});
});
it("refuses to pin past the limit", () => {
const full = {
...profile,
pinnedRepositories: Array.from({ length: PINNED_LIMIT }, (_, i) => `did:plc:${i}`)
} as ProfileRecord;
expect(() => pinnedWith(full, "did:plc:new", true)).toThrow("Unpin a repository first.");
});
});
describe("addPinned", () => {
it("appends and moves an existing key to the end", () => {
expect(addPinned(["a", "b"], "c")).toEqual(["a", "b", "c"]);
expect(addPinned(["a", "b"], "a")).toEqual(["b", "a"]);
});
it("refuses past the limit but allows re-adding a pinned key", () => {
const full = Array.from({ length: PINNED_LIMIT }, (_, i) => `k${i}`);
expect(() => addPinned(full, "new")).toThrow("Unpin a repository first.");
expect(addPinned(full, "k0")).toHaveLength(PINNED_LIMIT);
});
});
describe("removePinned", () => {
it("removes the key and ignores unknown ones", () => {
expect(removePinned(["a", "b", "c"], "b")).toEqual(["a", "c"]);
expect(removePinned(["a"], "z")).toEqual(["a"]);
});
});
describe("movePinned", () => {
const keys = ["a", "b", "c", "d"];
it("moves an item forward and backward", () => {
expect(movePinned(keys, 0, 2)).toEqual(["b", "c", "a", "d"]);
expect(movePinned(keys, 3, 1)).toEqual(["a", "d", "b", "c"]);
});
it("clamps the target and ignores bad sources without mutating", () => {
expect(movePinned(keys, 1, 99)).toEqual(["a", "c", "d", "b"]);
expect(movePinned(keys, 1, -5)).toEqual(["b", "a", "c", "d"]);
expect(movePinned(keys, 9, 0)).toEqual(keys);
expect(movePinned(keys, 2, 2)).toEqual(keys);
expect(keys).toEqual(["a", "b", "c", "d"]);
});
});
describe("pinKeyOf", () => {
it("pins a repository by its did", () => {
const repoDid = "did:plc:repo";
expect(pinKeyOf({ repoDid, uri: `at://${repoDid}/org.tangled.repo.manifest/self` })).toBe(
repoDid
);
expect(pinKeyOf({ repoDid })).toBe(repoDid);
});
it("pins a legacy repository by its record uri, not its owner's did", () => {
const uri = "at://did:plc:alice/sh.tangled.repo/old";
expect(pinKeyOf({ repoDid: "did:plc:alice", uri })).toBe(uri);
});
});