Tauri 2 + Vue app that draws the commit graph of the repository given on the command line. Branches can be hidden one by one or by patterns, runs of plain commits fold into a dotted line, and everything is reachable from the keyboard.
81 lines
3.3 KiB
TypeScript
81 lines
3.3 KiB
TypeScript
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");
|
|
});
|
|
});
|