125 lines
3.7 KiB
TypeScript
125 lines
3.7 KiB
TypeScript
import { expect, test } from "@rstest/core";
|
|
|
|
import {
|
|
MACOS_APP_BUNDLE_UPLOAD_MESSAGE,
|
|
formatUploadSize,
|
|
isLikelyMacOSAppBundle,
|
|
splitUnsupportedUploadFiles,
|
|
validateUploadLimits,
|
|
} from "@/core/uploads/file-validation";
|
|
|
|
const limits = {
|
|
max_files: 2,
|
|
max_file_size: 5,
|
|
max_total_size: 7,
|
|
};
|
|
|
|
test("identifies Finder-style .app bundle uploads as unsupported", () => {
|
|
expect(
|
|
isLikelyMacOSAppBundle({
|
|
name: "Vibe Island.app",
|
|
type: "application/octet-stream",
|
|
}),
|
|
).toBe(true);
|
|
});
|
|
|
|
test("keeps normal files and reports rejected app bundles", () => {
|
|
const files = [
|
|
new File(["demo"], "Vibe Island.app", {
|
|
type: "application/octet-stream",
|
|
}),
|
|
new File(["notes"], "notes.txt", { type: "text/plain" }),
|
|
];
|
|
|
|
const result = splitUnsupportedUploadFiles(files);
|
|
|
|
expect(result.accepted.length).toBe(1);
|
|
expect(result.accepted[0]?.name).toBe("notes.txt");
|
|
expect(result.rejected.length).toBe(1);
|
|
expect(result.rejected[0]?.name).toBe("Vibe Island.app");
|
|
expect(result.message).toBe(MACOS_APP_BUNDLE_UPLOAD_MESSAGE);
|
|
});
|
|
|
|
test("treats empty MIME .app uploads as unsupported", () => {
|
|
const result = splitUnsupportedUploadFiles([
|
|
new File(["demo"], "Another.app", { type: "" }),
|
|
]);
|
|
|
|
expect(result.accepted.length).toBe(0);
|
|
expect(result.rejected.length).toBe(1);
|
|
expect(result.message).toBe(MACOS_APP_BUNDLE_UPLOAD_MESSAGE);
|
|
});
|
|
|
|
test("returns no message when every file is supported", () => {
|
|
const result = splitUnsupportedUploadFiles([
|
|
new File(["notes"], "notes.txt", { type: "text/plain" }),
|
|
]);
|
|
|
|
expect(result.accepted.length).toBe(1);
|
|
expect(result.rejected.length).toBe(0);
|
|
expect(result.message).toBeUndefined();
|
|
});
|
|
|
|
test("accepts a file at the per-file limit and rejects one byte over", () => {
|
|
const atLimit = new File(["12345"], "at-limit.txt");
|
|
const overLimit = new File(["123456"], "over-limit.txt");
|
|
|
|
const result = validateUploadLimits([], [atLimit, overLimit], limits);
|
|
|
|
expect(result.accepted).toEqual([atLimit]);
|
|
expect(result.rejected).toEqual([overLimit]);
|
|
expect(result.violations).toEqual([
|
|
{ code: "max_file_size", files: [overLimit], limit: 5 },
|
|
]);
|
|
});
|
|
|
|
test("counts existing files and their size before incoming files", () => {
|
|
const existing = new File(["12"], "existing.txt");
|
|
const accepted = new File(["12345"], "accepted.txt");
|
|
const overCount = new File(["1"], "over-count.txt");
|
|
|
|
const result = validateUploadLimits(
|
|
[existing],
|
|
[accepted, overCount],
|
|
limits,
|
|
);
|
|
|
|
expect(result.accepted).toEqual([accepted]);
|
|
expect(result.rejected).toEqual([overCount]);
|
|
expect(result.violations[0]?.code).toBe("max_files");
|
|
});
|
|
|
|
test("keeps selection order and aggregates each violation category", () => {
|
|
const first = new File(["1234"], "first.txt");
|
|
const overSize = new File(["123456"], "over-size.txt");
|
|
const overTotal = new File(["1234"], "over-total.txt");
|
|
const second = new File(["1"], "second.txt");
|
|
|
|
const result = validateUploadLimits(
|
|
[],
|
|
[first, overSize, overTotal, second],
|
|
limits,
|
|
);
|
|
|
|
expect(result.accepted).toEqual([first, second]);
|
|
expect(result.violations).toEqual([
|
|
{ code: "max_file_size", files: [overSize], limit: 5 },
|
|
{ code: "max_total_size", files: [overTotal], limit: 7 },
|
|
]);
|
|
});
|
|
|
|
test("does not block files when upload limits are unavailable", () => {
|
|
const file = new File(["123456"], "fallback.txt");
|
|
|
|
const result = validateUploadLimits([], [file]);
|
|
|
|
expect(result.accepted).toEqual([file]);
|
|
expect(result.rejected).toEqual([]);
|
|
expect(result.violations).toEqual([]);
|
|
});
|
|
|
|
test("formats binary upload limits for display", () => {
|
|
expect(formatUploadSize(50 * 1024 * 1024)).toBe("50 MiB");
|
|
expect(formatUploadSize(1536)).toBe("1.5 KiB");
|
|
});
|