import { describe, expect, it } from "vitest"; import { globMatch, isRefVisible, lineOwners, reachable, refKind, shortName } from "./filter"; import { chain } from "./test-helpers"; describe("ref names", () => { it("knows the kind and the short name", () => { expect(refKind("refs/heads/main")).toBe("local"); expect(refKind("refs/remotes/origin/main")).toBe("remote"); expect(refKind("refs/tags/v1")).toBe("tag"); expect(shortName("refs/heads/feat/x")).toBe("feat/x"); expect(shortName("refs/remotes/origin/main")).toBe("origin/main"); expect(shortName("refs/tags/v1")).toBe("v1"); }); }); describe("globMatch", () => { it("matches * across any characters, including /", () => { expect(globMatch("prototypes/*", "prototypes/a")).toBe(true); expect(globMatch("prototypes/*", "prototypes/a/b")).toBe(true); expect(globMatch("prototypes/*", "main")).toBe(false); expect(globMatch("*/main", "origin/main")).toBe(true); }); it("matches ? as one character and treats other characters literally", () => { expect(globMatch("v?.0", "v1.0")).toBe(true); expect(globMatch("v?.0", "v1x0")).toBe(false); expect(globMatch("a+b", "a+b")).toBe(true); }); it("matches the whole name only", () => { expect(globMatch("main", "origin/main")).toBe(false); }); }); describe("isRefVisible", () => { it("hides refs hidden with the eye toggle", () => { const s = { hidden: ["refs/heads/x"], rules: [] }; expect(isRefVisible("refs/heads/x", s)).toBe(false); expect(isRefVisible("refs/heads/y", s)).toBe(true); }); it("hides refs that match a hide rule", () => { const s = { hidden: [], rules: [{ pattern: "prototypes/*", mode: "hide" as const }] }; expect(isRefVisible("refs/heads/prototypes/a", s)).toBe(false); expect(isRefVisible("refs/heads/main", s)).toBe(true); }); it("with only rules, shows only refs that match one, and hide rules still win", () => { const s = { hidden: [], rules: [ { pattern: "origin/*", mode: "only" as const }, { pattern: "origin/old", mode: "hide" as const }, ], }; expect(isRefVisible("refs/remotes/origin/main", s)).toBe(true); expect(isRefVisible("refs/remotes/origin/old", s)).toBe(false); expect(isRefVisible("refs/heads/main", s)).toBe(false); }); }); describe("reachable", () => { it("keeps only ancestors of the start commits, in order", () => { // d is a side branch off b; e is an unrelated branch tip. const commits = chain("e:a", "d:b", "c:b", "b:a", "a"); expect(reachable(commits, ["c"]).map((c) => c.hash)).toEqual(["c", "b", "a"]); expect(reachable(commits, ["d", "e"]).map((c) => c.hash)).toEqual(["e", "d", "b", "a"]); }); }); describe("lineOwners", () => { it("gives each commit the ref whose first-parent line it is on, checked-out branch first", () => { const commits = chain("m:c,f", "f:b", "c:b", "b:a", "a"); const refs = [ { name: "refs/heads/feature", target: "f" }, { name: "refs/heads/main", target: "m" }, ]; const owners = lineOwners(commits, refs, "refs/heads/main"); expect(owners.get("m")).toBe("refs/heads/main"); expect(owners.get("c")).toBe("refs/heads/main"); expect(owners.get("a")).toBe("refs/heads/main"); expect(owners.get("f")).toBe("refs/heads/feature"); }); });