mirror of
https://github.com/kmc7468/arkvault.git
synced 2026-11-04 00:00:28 +09:00
102 lines
3.4 KiB
TypeScript
102 lines
3.4 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import {
|
|
CHUNK_SIZE,
|
|
ENCRYPTED_CHUNK_SIZE,
|
|
ENCRYPTION_OVERHEAD,
|
|
getDecryptedSize,
|
|
getEncryptedRange,
|
|
getEncryptedSize,
|
|
} from "#lib/shared/format/index.ts";
|
|
import { getContentRangeHeader, parseRangeHeader, resolveRange } from "#lib/shared/http.ts";
|
|
|
|
describe("parseRangeHeader", () => {
|
|
it("parses byte ranges", () => {
|
|
expect(parseRangeHeader(null)).toBeUndefined();
|
|
expect(parseRangeHeader("bytes=0-")).toEqual({ start: 0, end: undefined });
|
|
expect(parseRangeHeader("bytes=10-20")).toEqual({ start: 10, end: 20 });
|
|
expect(parseRangeHeader("bytes=10-20, 30-40")).toEqual({ start: 10, end: 20 });
|
|
expect(parseRangeHeader("bytes=-500")).toEqual({ suffixLength: 500 });
|
|
});
|
|
|
|
it("ignores invalid ranges", () => {
|
|
expect(parseRangeHeader("bytes=-")).toBeUndefined();
|
|
expect(parseRangeHeader("items=0-1")).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
describe("resolveRange", () => {
|
|
it("resolves the whole content without a range", () => {
|
|
expect(resolveRange(undefined, 100)).toEqual({ start: 0, end: 99, total: 100 });
|
|
});
|
|
|
|
it("clamps the end to the content size", () => {
|
|
expect(resolveRange({ start: 10, end: 1000 }, 100)).toEqual({ start: 10, end: 99, total: 100 });
|
|
expect(resolveRange({ start: 10 }, 100)).toEqual({ start: 10, end: 99, total: 100 });
|
|
});
|
|
|
|
it("resolves suffix ranges", () => {
|
|
expect(resolveRange({ suffixLength: 10 }, 100)).toEqual({ start: 90, end: 99, total: 100 });
|
|
expect(resolveRange({ suffixLength: 1000 }, 100)).toEqual({ start: 0, end: 99, total: 100 });
|
|
});
|
|
|
|
it("rejects unsatisfiable ranges", () => {
|
|
expect(resolveRange({ start: 100 }, 100)).toBeNull();
|
|
expect(resolveRange({ start: 20, end: 10 }, 100)).toBeNull();
|
|
});
|
|
|
|
it("formats Content-Range", () => {
|
|
expect(getContentRangeHeader({ start: 1, end: 2, total: 3 })).toEqual({
|
|
"Content-Range": "bytes 1-2/3",
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("encrypted chunk layout", () => {
|
|
it.each([1, CHUNK_SIZE - 1, CHUNK_SIZE, CHUNK_SIZE + 1, 3 * CHUNK_SIZE + 12345])(
|
|
"computes the decrypted size of %i bytes",
|
|
(size) => {
|
|
expect(getEncryptedSize(size)).toBe(
|
|
size + Math.ceil(size / CHUNK_SIZE) * ENCRYPTION_OVERHEAD,
|
|
);
|
|
expect(getDecryptedSize(getEncryptedSize(size), false)).toBe(size);
|
|
},
|
|
);
|
|
|
|
it("computes the decrypted size of legacy files", () => {
|
|
expect(getDecryptedSize(100 + ENCRYPTION_OVERHEAD, true)).toBe(100);
|
|
});
|
|
|
|
it("maps a plaintext range to whole encrypted chunks", () => {
|
|
const totalSize = 3 * CHUNK_SIZE + 100;
|
|
const totalEncryptedSize = getEncryptedSize(totalSize);
|
|
|
|
expect(getEncryptedRange(0, 10, totalEncryptedSize, false)).toEqual({
|
|
firstChunkIndex: 0,
|
|
lastChunkIndex: 0,
|
|
start: 0,
|
|
end: ENCRYPTED_CHUNK_SIZE - 1,
|
|
});
|
|
expect(getEncryptedRange(CHUNK_SIZE - 1, CHUNK_SIZE, totalEncryptedSize, false)).toEqual({
|
|
firstChunkIndex: 0,
|
|
lastChunkIndex: 1,
|
|
start: 0,
|
|
end: 2 * ENCRYPTED_CHUNK_SIZE - 1,
|
|
});
|
|
expect(getEncryptedRange(totalSize - 1, totalSize - 1, totalEncryptedSize, false)).toEqual({
|
|
firstChunkIndex: 3,
|
|
lastChunkIndex: 3,
|
|
start: 3 * ENCRYPTED_CHUNK_SIZE,
|
|
end: totalEncryptedSize - 1,
|
|
});
|
|
});
|
|
|
|
it("maps any range of legacy files to the whole file", () => {
|
|
expect(getEncryptedRange(5, 10, 1000, true)).toEqual({
|
|
firstChunkIndex: 0,
|
|
lastChunkIndex: 0,
|
|
start: 0,
|
|
end: 999,
|
|
});
|
|
});
|
|
});
|