← Files Biological Sequence & Alignment ViewerARCHIVED FILE
src/msa/guide-tree.test.ts
1.55 KB · Sep 30, 2026 · 23:01 UTC
import { describe, expect, it } from "vitest";
import {
buildUpgmaGuideTree,
calculatePDistance,
MAX_GUIDE_TREE_COLUMNS,
MAX_GUIDE_TREE_ROWS,
} from "./guide-tree";
import type { MsaSequenceRow } from "./types";
describe("alignment guide tree", () => {
it("calculates p-distance while ignoring all-gap columns", () => {
expect(calculatePDistance("AC-G", "AT-G")).toBeCloseTo(1 / 3);
});
it("builds a deterministic UPGMA Newick tree", () => {
const rows = [
row("a", "AAAA"),
row("b", "AAAT"),
row("c", "TTTT"),
];
const tree = buildUpgmaGuideTree(rows);
expect(tree).toContain("'a':0.125");
expect(tree).toContain("'b':0.125");
expect(tree.endsWith(";")).toBe(true);
});
it("escapes Newick labels and enforces interactive calculation limits", () => {
expect(buildUpgmaGuideTree([row("patient's-sequence", "AAAA")])).toBe(
"'patient''s-sequence';",
);
expect(() =>
buildUpgmaGuideTree(
Array.from({ length: MAX_GUIDE_TREE_ROWS + 1 }, (_, index) =>
row(`row-${index}`, "AAAA"),
),
),
).toThrow(`${MAX_GUIDE_TREE_ROWS} rows`);
expect(() =>
buildUpgmaGuideTree([
row("too-wide", "A".repeat(MAX_GUIDE_TREE_COLUMNS + 1)),
]),
).toThrow("10,000 alignment columns");
});
});
function row(label: string, alignedSequence: string): MsaSequenceRow {
return {
alignedSequence,
description: undefined,
hidden: false,
id: label,
label,
metadata: {},
ungappedLength: alignedSequence.replaceAll("-", "").length,
};
}
SHA-256: 21ba0409b9261d0c9d791bee4c8d6203236b1a4011667c5f0884078c6c830347