224 lines
7.6 KiB
TypeScript
224 lines
7.6 KiB
TypeScript
import { expect } from "vitest";
|
|
import type { SpacePrimitives } from "./space_primitives.ts";
|
|
import type { FileMeta } from "@silverbulletmd/silverbullet/type/index";
|
|
import { notFoundError } from "@silverbulletmd/silverbullet/constants";
|
|
|
|
export async function testSpacePrimitives(spacePrimitives: SpacePrimitives) {
|
|
await testBasicOperations(spacePrimitives);
|
|
await testFileOverwriting(spacePrimitives);
|
|
await testEmptyFiles(spacePrimitives);
|
|
await testUnicodeContent(spacePrimitives);
|
|
await testSpecialFileNames(spacePrimitives);
|
|
await testErrorHandling(spacePrimitives);
|
|
await testLargeFiles(spacePrimitives);
|
|
await testMetadataPreservation(spacePrimitives);
|
|
|
|
// Ensure clean state at the end
|
|
const finalFiles = await spacePrimitives.fetchFileList();
|
|
expect(finalFiles).toEqual([]);
|
|
}
|
|
|
|
async function testBasicOperations(spacePrimitives: SpacePrimitives) {
|
|
const files = await spacePrimitives.fetchFileList();
|
|
expect(files).toEqual([]);
|
|
|
|
// Write text file
|
|
const fileMeta = await spacePrimitives.writeFile(
|
|
"test.txt",
|
|
stringToBytes("Hello World"),
|
|
{
|
|
name: "test.txt",
|
|
perm: "rw",
|
|
created: 10,
|
|
contentType: "text/plain",
|
|
lastModified: 20,
|
|
size: 11,
|
|
},
|
|
);
|
|
|
|
const { data: retrievedData, meta: retrievedMeta } =
|
|
await spacePrimitives.readFile("test.txt");
|
|
|
|
expect(retrievedData).toEqual(stringToBytes("Hello World"));
|
|
// Check that the meta data is persisted
|
|
expect(retrievedMeta.lastModified).toEqual(20);
|
|
|
|
const fbContent = (await spacePrimitives.readFile("test.txt")).data;
|
|
expect(new TextDecoder().decode(fbContent)).toEqual("Hello World");
|
|
|
|
expect(await spacePrimitives.fetchFileList()).toEqual([fileMeta]);
|
|
|
|
// Write binary file
|
|
const buf = new Uint8Array(1024 * 1024);
|
|
buf.set([1, 2, 3, 4, 5]);
|
|
await spacePrimitives.writeFile("test.bin", buf);
|
|
const fileData = await spacePrimitives.readFile("test.bin");
|
|
expect(fileData.data.length).toEqual(1024 * 1024);
|
|
expect((await spacePrimitives.fetchFileList()).length).toEqual(2);
|
|
|
|
await spacePrimitives.deleteFile("test.bin");
|
|
expect(await spacePrimitives.fetchFileList()).toEqual([fileMeta]);
|
|
|
|
// Clean up
|
|
await spacePrimitives.deleteFile("test.txt");
|
|
expect(await spacePrimitives.fetchFileList()).toEqual([]);
|
|
|
|
// Test weird file names
|
|
await spacePrimitives.writeFile("test+'s.txt", stringToBytes("Hello world!"));
|
|
expect(stringToBytes("Hello world!")).toEqual(
|
|
(await spacePrimitives.readFile("test+'s.txt")).data,
|
|
);
|
|
await spacePrimitives.deleteFile("test+'s.txt");
|
|
|
|
// Check deletion of weird file file name
|
|
try {
|
|
await spacePrimitives.getFileMeta("test+'s.txt");
|
|
expect(false).toBeTruthy();
|
|
} catch (e: any) {
|
|
expect(e).toEqual(notFoundError);
|
|
}
|
|
}
|
|
|
|
async function testFileOverwriting(spacePrimitives: SpacePrimitives) {
|
|
// Test overwriting existing files
|
|
await spacePrimitives.writeFile("overwrite.txt", stringToBytes("Original"));
|
|
const _originalMeta = await spacePrimitives.getFileMeta("overwrite.txt");
|
|
|
|
await spacePrimitives.writeFile("overwrite.txt", stringToBytes("Updated"));
|
|
const updatedData = await spacePrimitives.readFile("overwrite.txt");
|
|
expect(new TextDecoder().decode(updatedData.data)).toEqual("Updated");
|
|
|
|
// File list should still have only one entry for this file
|
|
const filesAfterOverwrite = await spacePrimitives.fetchFileList();
|
|
const overwriteFiles = filesAfterOverwrite.filter(
|
|
(f) => f.name === "overwrite.txt",
|
|
);
|
|
expect(overwriteFiles.length).toEqual(1);
|
|
|
|
await spacePrimitives.deleteFile("overwrite.txt");
|
|
}
|
|
|
|
async function testEmptyFiles(spacePrimitives: SpacePrimitives) {
|
|
// Test empty file
|
|
await spacePrimitives.writeFile("empty.txt", new Uint8Array(0));
|
|
const emptyFile = await spacePrimitives.readFile("empty.txt");
|
|
expect(emptyFile.data.length).toEqual(0);
|
|
expect(emptyFile.meta.size).toEqual(0);
|
|
await spacePrimitives.deleteFile("empty.txt");
|
|
}
|
|
|
|
async function testUnicodeContent(spacePrimitives: SpacePrimitives) {
|
|
// Test files with Unicode characters
|
|
const unicodeContent = "Hello 世界! 🌍 Здравствуй мир!";
|
|
await spacePrimitives.writeFile("unicode.txt", stringToBytes(unicodeContent));
|
|
const unicodeFile = await spacePrimitives.readFile("unicode.txt");
|
|
expect(new TextDecoder().decode(unicodeFile.data)).toEqual(unicodeContent);
|
|
await spacePrimitives.deleteFile("unicode.txt");
|
|
}
|
|
|
|
async function testSpecialFileNames(spacePrimitives: SpacePrimitives) {
|
|
// Test file names with various special characters
|
|
const specialNames = [
|
|
"file with spaces.txt",
|
|
"file-with-hyphens.txt",
|
|
"file_with_underscores.txt",
|
|
"file.with.dots.txt",
|
|
"UPPERCASE.TXT",
|
|
"123numeric.txt",
|
|
"émojis🚀file.txt",
|
|
];
|
|
|
|
for (const fileName of specialNames) {
|
|
await spacePrimitives.writeFile(
|
|
fileName,
|
|
stringToBytes(`Content of ${fileName}`),
|
|
);
|
|
const fileData = await spacePrimitives.readFile(fileName);
|
|
expect(new TextDecoder().decode(fileData.data)).toEqual(
|
|
`Content of ${fileName}`,
|
|
);
|
|
}
|
|
|
|
// Verify all special files are in the list
|
|
const allFiles = await spacePrimitives.fetchFileList();
|
|
for (const fileName of specialNames) {
|
|
const found = allFiles.find((f) => f.name === fileName);
|
|
expect(found, `File ${fileName} should be in the file list`).toBeTruthy();
|
|
}
|
|
|
|
// Clean up special files
|
|
for (const fileName of specialNames) {
|
|
await spacePrimitives.deleteFile(fileName);
|
|
}
|
|
}
|
|
|
|
async function testErrorHandling(spacePrimitives: SpacePrimitives) {
|
|
// Test error cases
|
|
try {
|
|
await spacePrimitives.readFile("nonexistent.txt");
|
|
expect(false, "Should throw error for non-existent file").toBeTruthy();
|
|
} catch (e: any) {
|
|
expect(e).toEqual(notFoundError);
|
|
}
|
|
|
|
try {
|
|
await spacePrimitives.deleteFile("nonexistent.txt");
|
|
expect(
|
|
false,
|
|
"Should throw error when deleting non-existent file",
|
|
).toBeTruthy();
|
|
} catch (e: any) {
|
|
expect(e).toEqual(notFoundError);
|
|
}
|
|
}
|
|
|
|
async function testLargeFiles(spacePrimitives: SpacePrimitives) {
|
|
// Test large file content
|
|
const largeContent = new Uint8Array(5 * 1024 * 1024); // 5MB
|
|
for (let i = 0; i < largeContent.length; i++) {
|
|
largeContent[i] = i % 256;
|
|
}
|
|
|
|
await spacePrimitives.writeFile("large.bin", largeContent);
|
|
const largeFile = await spacePrimitives.readFile("large.bin");
|
|
expect(largeFile.data.length).toEqual(largeContent.length);
|
|
expect(largeFile.meta.size).toEqual(largeContent.length);
|
|
|
|
// Verify content integrity
|
|
for (let i = 0; i < Math.min(1000, largeContent.length); i++) {
|
|
expect(largeFile.data[i]).toEqual(largeContent[i]);
|
|
}
|
|
|
|
await spacePrimitives.deleteFile("large.bin");
|
|
}
|
|
|
|
async function testMetadataPreservation(spacePrimitives: SpacePrimitives) {
|
|
// Test metadata preservation
|
|
const testContent = stringToBytes("Hello meta!");
|
|
const customMeta: FileMeta = {
|
|
name: "meta-test.txt",
|
|
perm: "rw",
|
|
created: 1000000,
|
|
contentType: "text/plain", // Use a content type that matches the file extension
|
|
lastModified: 2000000,
|
|
size: testContent.length, // Use actual content length
|
|
};
|
|
|
|
await spacePrimitives.writeFile("meta-test.txt", testContent, customMeta);
|
|
const metaFile = await spacePrimitives.readFile("meta-test.txt");
|
|
|
|
// Check that some metadata is preserved (implementations may handle timestamps differently)
|
|
expect(
|
|
metaFile.meta.lastModified > 0,
|
|
"LastModified timestamp should be set",
|
|
).toBeTruthy();
|
|
expect(metaFile.meta.name).toEqual("meta-test.txt");
|
|
expect(metaFile.meta.size).toEqual(testContent.length);
|
|
|
|
await spacePrimitives.deleteFile("meta-test.txt");
|
|
}
|
|
|
|
function stringToBytes(str: string): Uint8Array {
|
|
return new TextEncoder().encode(str);
|
|
}
|