← Files Biological Sequence & Alignment ViewerARCHIVED FILE

src/cram-decoder.test.ts

3.59 KB · Sep 30, 2026 · 23:01 UTC

↓ Download file

import { describe, expect, it } from "vitest";

import {
  cramReadFeaturesToCigar,
  decodeCramWindowToSam,
} from "./cram-decoder";
import { parseSequenceTrack } from "./sequence/tracks";

const CRAM = "Q1JBTQMALQAAAAAAAAAAAAAAAAAAAAAAAADPAAAAAAAAAAAAAgIAgIQlD7gGAQAAeoC6H4sIAAAAAAAAE9vGwMDgEBzIGexnVVHB6eNnZWTA6WtqlZSUZpKSapZiYWJpnmhoaJmSkmiWamBuYmpkaGZinJLMGRpkpR9anFpUrF+UVJqaU6yfklqmn1FSnJOZpF+SWlyiX1Ghl5bIBTW6spL6RgMAKob8NboAAAAQG+fNAAAAQkIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7OO9sxAEAAAABFAMAHgoBgKBWntNVAAEAgJWAlRIEVEQBAFNNGxsbGxtSTgFBUAF/EkJGAQEPQ0YDBAEDAQBSTAMEAQoBAEFQAQERUkcDCAH/////DwEATUYBARVOUwMEAQABAE5QAQEXVFMBARZUTAMEAQABAEZOAwQBAAEASU4FAgANQkIEBgEBKgEBJU1RAwQBAQEAUk4FAgALUVMBAQxSSQMEAQABAFNDBQIADgEA5supAgACACMjAAEUAwAIBwsMDxEVFhf/////D7v03m2El6EZ3abgdFIWQ9zWxUHpAAUAAAAvB/zxAQQLHQkfiwgAAAAAAAATSzRkSDRkSDRkAADGOdc0CQAAALzPmRgBBAwWHh+LCAAAAAAABBPjxAsA+TQVfx4AAAAwdMfMAQQPGAQfiwgAAAAAAAQTc1ZumAwAw4prwAQAAAC9oy/4AQQRFwMfiwgAAAAAAAQTY2BlBQDY2VzyAwAAAJ/oBIIBBBUXAx+LCAAAAAAABBNjYGQAAFPoWuYDAAAA8I9LzAEEFiALH4sIAAAAAAAEExP5////P57/////4wEAay8YkQsAAABJvxTdAQQXFwMfiwgAAAAAAAQTY+NmBAD9TD9vAwAAAP0uM3dgAQAAAQEPAgMUCAGAjstk99AAAQCAg4CDEgRURAEAU00bGxsbG1JOAUFQAW0PQkYBAQ9DRgEBEFJMAwQBCgEAQVABARFSRwMIAf////8PAQBORgMEAQABAFRMAwQBAAEARk4DBAEAAQBJTgUCAA1CQgQGAQEqAQElTVEDBAEBAQBSTgUCAAtRUwEBDFJJAwQBAQEAU0MFAgAOAQBAQ8SQAAIAISEBAQ8CAwYFCwwPEBH/////DxsxEk7y96F0BZLwkNjFEeFW/wKIAAUAAAAvB/zxAQQLGgYfiwgAAAAAAAATSzRkSDRkAADPSmNhBgAAAAGvzsoBBAwWFB+LCAAAAAAABBPjxAIAoRgI/hQAAACtHFAPAQQPFgIfiwgAAAAAAAQTc2YGAINfhAMCAAAA9xl7jAEEEBYCH4sIAAAAAAAEE2NlBAAs1qlLAgAAACdVahoBBBEWAh+LCAAAAAAABBNjYAUAcOazMQIAAAAdmLGaDwAAAP////8P4EVPRgAAAAABAAW92U8AAQAGBgEAAQABAO5jAUs=";
const CRAI = "H4sIAAAAAAAAEzLgNOQ0MuA0MjXiNDQD0pZGXIZAIUNTTnMjoJCJEaeRoQEXQIABAHb9ClkmAAAA";
const REFERENCE = ">xx\nAAAAAAAAAATTTTTTTTTT\n>yy\nAAAAAAAAAATTTTTTTTTT\n\n";

describe("CRAM evidence decoding", () => {
  it("decodes an indexed regional CRAM window into a bounded read track", async () => {
    const result = await decodeCramWindowToSam({
      cramBytes: bytes(CRAM),
      end: 20,
      indexBytes: bytes(CRAI),
      reference: "xx",
      referenceContents: REFERENCE,
      referenceFileName: "xx.fa",
      start: 1,
    });
    expect(result).toMatchObject({
      end: 20,
      reference: "xx",
      start: 1,
      truncated: false,
    });
    expect(result.sam).toContain("@SQ\tSN:xx\tLN:20");

    const track = parseSequenceTrack({
      content: result.sam,
      displayName: "triplet.cram",
      format: "cram",
      id: "track",
      requestedReference: "xx",
    });
    expect(track.format).toBe("cram");
    expect(track.kind).toBe("reads");
    expect(track.reads?.length).toBeGreaterThan(0);
    expect(track.mapping.status).toBe("matched");
  });

  it("requires a bounded coordinate window and a matching reference", async () => {
    await expect(
      decodeCramWindowToSam({
        cramBytes: bytes(CRAM),
        end: 200_000,
        indexBytes: bytes(CRAI),
        reference: "missing",
        referenceContents: REFERENCE,
        start: 1,
      }),
    ).rejects.toThrow("No CRAM reference matched");
  });

  it("preserves insertion, deletion, clipping, and splice semantics in CIGAR", () => {
    expect(
      cramReadFeaturesToCigar(
        [
          { code: "S", data: "AA", pos: 1 },
          { code: "I", data: "G", pos: 5 },
          { code: "D", data: 3, pos: 7 },
          { code: "N", data: 20, pos: 8 },
        ],
        10,
      ),
    ).toBe("2S2M1I1M3D1M20N3M");
  });
});

function bytes(value: string): Uint8Array {
  return Uint8Array.from(Buffer.from(value, "base64"));
}

SHA-256: daa6440c154a13b6e7c313d4a7746425271d1262f43eae127ee5974592ccbe5c