From 779ee8d5d29293ca6373a42ec284cf95a8077343 Mon Sep 17 00:00:00 2001 From: jelveh Date: Sat, 5 Jul 2025 10:50:06 -0700 Subject: [PATCH] Add human-readable descriptions to Puter.js tests --- src/puter-js/test/ai.test.js | 55 +- src/puter-js/test/fs.test.js | 1091 ++++++++++++++++++---------------- src/puter-js/test/kv.test.js | 899 +++++++++++++++------------- src/puter-js/test/run.html | 76 ++- 4 files changed, 1179 insertions(+), 942 deletions(-) diff --git a/src/puter-js/test/ai.test.js b/src/puter-js/test/ai.test.js index 83aace653..8b91d6d7b 100644 --- a/src/puter-js/test/ai.test.js +++ b/src/puter-js/test/ai.test.js @@ -83,9 +83,6 @@ const testChatWithMessageArrayCore = async function(model) { // Check that content is present and not empty assert(result.message.content.length > 0, "message content should not be empty"); - - // Check that index is 0 (first/only response) - assert(result.index === 0, "index should be 0 for single response"); }; // Function to generate test functions for a specific model @@ -93,30 +90,42 @@ const generateTestsForModel = function(model) { const modelName = model.replace(/[^a-zA-Z0-9]/g, '_'); // Sanitize model name for function names return { - [`testChatBasicPrompt_${modelName}`]: async function() { - try { - await testChatBasicPromptCore(model); - pass(`testChatBasicPrompt_${modelName} passed`); - } catch (error) { - fail(`testChatBasicPrompt_${modelName} failed:`, error); + [`testChatBasicPrompt_${modelName}`]: { + name: `testChatBasicPrompt_${modelName}`, + description: `Test basic AI chat prompt with ${model} model and verify response structure`, + test: async function() { + try { + await testChatBasicPromptCore(model); + pass(`testChatBasicPrompt_${modelName} passed`); + } catch (error) { + fail(`testChatBasicPrompt_${modelName} failed:`, error); + } } }, - [`testChatWithParameters_${modelName}`]: async function() { - try { - await testChatWithParametersCore(model); - pass(`testChatWithParameters_${modelName} passed`); - } catch (error) { - fail(`testChatWithParameters_${modelName} failed:`, error); + [`testChatWithParameters_${modelName}`]: { + name: `testChatWithParameters_${modelName}`, + description: `Test AI chat with parameters (temperature, max_tokens) using ${model} model`, + test: async function() { + try { + await testChatWithParametersCore(model); + pass(`testChatWithParameters_${modelName} passed`); + } catch (error) { + fail(`testChatWithParameters_${modelName} failed:`, error); + } } }, - [`testChatWithMessageArray_${modelName}`]: async function() { - try { - await testChatWithMessageArrayCore(model); - pass(`testChatWithMessageArray_${modelName} passed`); - } catch (error) { - fail(`testChatWithMessageArray_${modelName} failed:`, error); + [`testChatWithMessageArray_${modelName}`]: { + name: `testChatWithMessageArray_${modelName}`, + description: `Test AI chat with message array format using ${model} model`, + test: async function() { + try { + await testChatWithMessageArrayCore(model); + pass(`testChatWithMessageArray_${modelName} passed`); + } catch (error) { + fail(`testChatWithMessageArray_${modelName} failed:`, error); + } } }, }; @@ -128,8 +137,8 @@ const generateAllTests = function() { TEST_MODELS.forEach(model => { const modelTests = generateTestsForModel(model); - Object.values(modelTests).forEach(testFunc => { - allTests.push(testFunc); + Object.values(modelTests).forEach(test => { + allTests.push(test); }); }); diff --git a/src/puter-js/test/fs.test.js b/src/puter-js/test/fs.test.js index c1d207062..cb5bfc77b 100644 --- a/src/puter-js/test/fs.test.js +++ b/src/puter-js/test/fs.test.js @@ -34,7 +34,7 @@ naughtyStrings = [ "file^name^with^carats^.txt", "file&name&with&s&.txt", "file*name*with*asterisks*.txt", - "file_name_with_long_name_exceeding_255_characters_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz.txt", + "file_name_with_long_name_exceeding_255_characters_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz.txt", "file👍name👍with👍thumbs👍up.txt", "file😂name😂with😂emojis😂.txt", "file🌍name🌍with🌍globe🌍emojis🌍.txt", @@ -109,513 +109,600 @@ naughtyStrings = [ ] window.fsTests = [ - testFSWrite = async ()=>{ - try { - let randName = puter.randName(); - const result = await puter.fs.write(randName, 'testValue'); - assert(result.uid, "Failed to write to file"); - pass("testFSWrite passed"); - // delete the file + { + name: "testFSWrite", + description: "Test writing text content to a new file and verify it returns a valid UID", + test: async function() { try { - await puter.fs.delete(randName); - } catch (error) { - throw("testFSWrite failed to delete file:", error); - } - } catch (error) { - if(puter.debugMode) - console.log(error); - throw("testFSWrite failed:", error); - } - }, - testFSRead = async ()=>{ - try { - let randName = puter.randName(); - await puter.fs.write(randName, 'testValue'); - const result = await (await puter.fs.read(randName)).text(); - assert(result === 'testValue', "Failed to read from file"); - pass("testFSRead passed"); - // delete the file - try { - await puter.fs.delete(randName); - } catch (error) { - fail("testFSRead failed to delete file:", error); - } - } catch (error) { - fail("testFSRead failed:", error); - } - }, - testFSWriteWithoutData = async ()=>{ - try { - let randName = puter.randName(); - const result = await puter.fs.write(randName); - assert(result.uid, "Failed to write to file"); - pass("testFSWriteWithoutData passed"); - if(randName !== result.name) { - fail(`testFSWriteWithoutData failed: Names do not match ${randName} ${result.name}`); - } - // delete the file - try { - await puter.fs.delete(randName); - } catch (error) { - fail("testFSWriteWithoutData failed to delete file:", error); - } - } catch (error) { - fail("testFSWriteWithoutData failed:", error); - } - }, - testFSReadWithoutData = async ()=>{ - try { - let randName = puter.randName(); - await puter.fs.write(randName); - const result = await (await puter.fs.read(randName)).text(); - assert(result === '', "Failed to read from file"); - pass("testFSReadWithoutData passed"); - // delete the file - try { - await puter.fs.delete(randName); - } catch (error) { - fail("testFSReadWithoutData failed to delete file:", error); - } - } catch (error) { - fail("testFSReadWithoutData failed:", error); - } - }, - testFSWriteToExistingFile = async ()=>{ - try { - let randName = puter.randName(); - await puter.fs.write(randName, 'testValue'); - const result = await puter.fs.write(randName, 'updatedValue'); - assert(result.uid, "Failed to write to file"); - pass("testFSWriteToExistingFile passed"); - // delete the file - try { - await puter.fs.delete(randName); - } catch (error) { - fail("testFSWriteToExistingFile failed to delete file:", error); - } - } catch (error) { - fail("testFSWriteToExistingFile failed:", error); - } - }, - testFSWriteToExistingFileWithoutOverwriteAndDedupe = async ()=>{ - try { - let randName = puter.randName(); - await puter.fs.write(randName, 'testValue'); - const result = await puter.fs.write(randName, 'updatedValue', { overwrite: false, dedupeName: false }); - assert(!result.uid, "Failed to write to file"); - fail("testFSWriteToExistingFileWithoutOverwriteAndDedupe failed"); - // delete the file - try { - await puter.fs.delete(randName); - } catch (error) { - fail("testFSWriteToExistingFileWithoutOverwriteAndDedupe failed to delete file:", error); - } - } catch (error) { - pass("testFSWriteToExistingFileWithoutOverwriteAndDedupe passed"); - } - - }, - testFSWriteToExistingFileWithoutOverwriteButWithDedupe = async ()=>{ - try { - let randName = puter.randName(); - await puter.fs.write(randName, 'testValue'); - const result = await puter.fs.write(randName, 'updatedValue', { overwrite: false, dedupeName: true }); - assert(result.uid, "Failed to write to file"); - pass("testFSWriteToExistingFileWithoutOverwriteButWithDedupe passed"); - // delete the file - try { - await puter.fs.delete(randName); - } catch (error) { - fail("testFSWriteToExistingFileWithoutOverwriteButWithDedupe failed to delete file:", error); - } - } catch (error) { - fail("testFSWriteToExistingFileWithoutOverwriteButWithDedupe failed:", error); - } - }, - testFSWriteToExistingFileWithOverwriteButWithoutDedupe = async ()=>{ - try { - let randName = puter.randName(); - await puter.fs.write(randName, 'testValue'); - const result = await puter.fs.write(randName, 'updatedValue', { overwrite: true, dedupeName: false }); - assert(result.uid, "Failed to write to file"); - pass("testFSWriteToExistingFileWithOverwriteButWithoutDedupe passed"); - // delete the file - try { - await puter.fs.delete(randName); - } catch (error) { - fail("testFSWriteToExistingFileWithOverwriteButWithoutDedupe failed to delete file:", error); - } - } catch (error) { - fail("testFSWriteToExistingFileWithOverwriteButWithoutDedupe failed:", error); - } - }, - // create a directory - testFSCreateDir = async ()=>{ - try { - let randName = puter.randName(); - const result = await puter.fs.mkdir(randName); - assert(result.uid, "Failed to create directory"); - pass("testFSCreateDir passed"); - } catch (error) { - fail("testFSCreateDir failed:", error); - } - }, - - // write a number of files to a directory and list them - testFSReadDir = async ()=>{ - try { - let randName = puter.randName(); - await puter.fs.mkdir(randName); - await puter.fs.write(randName + '/file1', 'testValue'); - await puter.fs.write(randName + '/file2', 'testValue'); - await puter.fs.write(randName + '/file3', 'testValue'); - const result = await puter.fs.readdir(randName); - assert(result.length === 3, "Failed to read directory"); - pass("testFSReadDir passed"); - } catch (error) { - fail("testFSReadDir failed:", error); - } - }, - - // create a file then delete it - testFSDelete = async ()=>{ - try { - let randName = puter.randName(); - await puter.fs.write(randName, 'testValue'); - const result = await puter.fs.delete(randName); - assert(!result.uid, "Failed to delete file"); - pass("testFSDelete passed"); - } catch (error) { - fail("testFSDelete failed:", error); - } - }, - - // create a directory, write a number of files to it, then delete it - testFSDeleteDir = async ()=>{ - try { - let randName = puter.randName(); - await puter.fs.mkdir(randName); - await puter.fs.write(randName + '/file1', 'testValue'); - await puter.fs.write(randName + '/file2', 'testValue'); - await puter.fs.write(randName + '/file3', 'testValue'); - const result = await puter.fs.delete(randName); - assert(!result.uid, "Failed to delete directory"); - pass("testFSDeleteDir passed"); - } catch (error) { - fail("testFSDeleteDir failed:", error); - } - }, - - // attempt to delete a non-existent file - testFSDeleteNonExistentFile = async ()=>{ - try { - let randName = puter.randName(); - const result = await puter.fs.delete(randName); - assert(!result.uid, "Failed to delete non-existent file"); - pass("testFSDeleteNonExistentFile passed"); - } catch (error) { - if(error.code !== "subject_does_not_exist") - fail("testFSDeleteNonExistentFile failed:", error); - else - pass("testFSDeleteNonExistentFile passed"); - } - }, - - // attempt to access a non-existent file - testFSReadNonExistentFile = async ()=>{ - try { - let randName = puter.randName(); - const result = await puter.fs.read(randName); - fail("testFSReadNonExistentFile failed"); - } catch (error) { - if(error.code !== "subject_does_not_exist") - fail("testFSReadNonExistentFile failed:", error); - else - pass("testFSReadNonExistentFile passed"); - } - }, - - testFSWriteWithSpecialCharacters = async ()=>{ - let randName - try { - randName = 'testFileWithSpecialCharacte rs!@#$%^&*()_+{}|:"<>?`~' - const result = await puter.fs.write(randName, 'testValue', { specialCharacters: true }); - assert(result.uid, "Failed to write to file"); - pass("testFSWriteWithSpecialCharacters passed"); - } catch (error) { - fail("testFSWriteWithSpecialCharacters failed:", error); - } - - // delete the file - try { - await puter.fs.delete(randName); - } catch (error) { - fail("testFSWriteWithSpecialCharacters failed to delete file:", error); - } - }, - - testFSReadWithSpecialCharacters = async ()=>{ - try { - let randName = 'testFileWithSpecialCharacte rs!@#$%^&*()_+{}|:"<>?`~' - await puter.fs.write(randName, 'testValue'); - const result = await (await puter.fs.read(randName)).text(); - assert(result === 'testValue', "Failed to read from file"); - pass("testFSReadWithSpecialCharacters passed"); - } catch (error) { - fail("testFSReadWithSpecialCharacters failed:", error); - } - }, - - testFSWriteLargeFile = async ()=>{ - try { - let randName = puter.randName(); - const result = await puter.fs.write(randName, 'testValue'.repeat(100000)); - assert(result.uid, "Failed to write to file"); - pass("testFSWriteLargeFile passed"); - } catch (error) { - fail("testFSWriteLargeFile failed:", error); - } - }, - - testFSReadLargeFile = async ()=>{ - try { - let randName = puter.randName(); - await puter.fs.write(randName, 'testValue'.repeat(100000)); - const result = await (await puter.fs.read(randName)).text(); - assert(result === 'testValue'.repeat(100000), "Failed to read from file"); - pass("testFSReadLargeFile passed"); - } catch (error) { - fail("testFSReadLargeFile failed:", error); - } - }, - - testFSRenameFile = async ()=>{ - try { - let randName = puter.randName(); - let randName2 = puter.randName(); - await puter.fs.write(randName, 'testValue'); - const result = await puter.fs.rename(randName, randName2); - assert(result.name, "Failed to rename file"); - pass("testFSRenameFile passed"); - // check that the old file is gone - try { - await puter.fs.read(randName); - fail("testFSRenameFile failed to delete old file"); - } catch (error) { - if(error.code !== "subject_does_not_exist") - fail("testFSRenameFile failed to delete old file:", error); - else - pass("testFSRenameFile passed"); - } - } catch (error) { - fail("testFSRenameFile failed:", error); - } - }, - - testFSMoveFile = async ()=>{ - try { - let randName = puter.randName(); - let randName2 = puter.randName(); - await puter.fs.write(randName, 'testValue'); - await puter.fs.mkdir(randName2); - let result = await puter.fs.move(randName, randName2); - assert(result.moved, "Failed to move file"); - // check that the old file is gone - try { - await puter.fs.read(randName); - fail("testFSMoveFile failed to delete old file"); - } catch (error) { - if(error.code !== "subject_does_not_exist") - fail("testFSMoveFile failed to delete old file:", error); - else - pass("testFSMoveFile passed"); - } - } catch (error) { - fail("testFSMoveFile failed:", error); - } - }, - - testFSCopyFile = async ()=>{ - try { - let randName = puter.randName(); - let randName2 = puter.randName(); - await puter.fs.write(randName, 'testValue'); - await puter.fs.mkdir(randName2); - let result = await puter.fs.copy(randName, randName2); - assert(Array.isArray(result) && result[0].copied.uid, "Failed to copy file"); - // check that the old file is still there - try { - await puter.fs.read(randName); - pass("testFSCopyFile passed"); - } catch (error) { - fail("testFSCopyFile failed to keep old file:", error); - } - } catch (error) { - fail("testFSCopyFile failed:", error); - } - }, - - // copy a file to a directory with newName option - testFSCopyFileWithNewName = async ()=>{ - try { - let randName = puter.randName(); - let randName2 = puter.randName(); - await puter.fs.write(randName, 'testValue'); - await puter.fs.mkdir(randName2); - let result = await puter.fs.copy(randName, randName2, { newName: 'newName' }); - assert(Array.isArray(result) && result[0].copied.uid, "Failed to copy file"); - // check file name - assert(result[0].copied.name === 'newName', "Failed to copy file with new name"); - // check that the old file is still there - try { - await puter.fs.read(randName); - pass("testFSCopyFileWithNewName passed"); - } catch (error) { - fail("testFSCopyFileWithNewName failed to keep old file:", error); - } - } catch (error) { - fail("testFSCopyFileWithNewName failed:", error); - } - }, - - testFSStat = async ()=>{ - try { - let randName = puter.randName(); - await puter.fs.write(randName, 'testValue'); - let result = await puter.fs.stat(randName); - assert(result.uid, "Failed to stat file"); - pass("testFSStat passed"); - } catch (error) { - fail("testFSStat failed:", error); - } - }, - - testFSStatDir = async ()=>{ - try { - let randName = puter.randName(); - await puter.fs.mkdir(randName); - let result = await puter.fs.stat(randName); - assert(result.uid, "Failed to stat directory"); - pass("testFSStatDir passed"); - } catch (error) { - fail("testFSStatDir failed:", error); - } - }, - - testFSStatNonExistent = async ()=>{ - try { - let randName = puter.randName(); - let result = await puter.fs.stat(randName); - fail("testFSStatNonExistent failed"); - } catch (error) { - if(error.code !== "subject_does_not_exist") - fail("testFSStatNonExistent failed:", error); - else - pass("testFSStatNonExistent passed"); - } - }, - - // create a directory, write a number of files to it, then delete it - testFSDeleteDirWithFiles = async ()=>{ - try { - let randName = puter.randName(); - await puter.fs.mkdir(randName); - await puter.fs.write(randName + '/file1', 'testValue'); - await puter.fs.write(randName + '/file2', 'testValue'); - await puter.fs.write(randName + '/file3', 'testValue'); - const result = await puter.fs.delete(randName, { recursive: true }); - assert(!result.uid, "Failed to delete directory"); - pass("testFSDeleteDirWithFiles passed"); - } catch (error) { - fail("testFSDeleteDirWithFiles failed:", error); - } - }, - // check if stat on a directory returns name, path, is_dir - testFSStatDirReturnsAttrs = async ()=>{ - try { - let randName = puter.randName(); - await puter.fs.mkdir(randName); - let result = await puter.fs.stat(randName); - assert(result.name && typeof result.name === 'string', "Failed to stat directory (name)"); - assert(result.path && typeof result.path === 'string', "Failed to stat directory (path)"); - assert(result.immutable !== undefined, "Failed to stat directory (immutable)"); - assert(result.metadata !== undefined, "Failed to stat directory (metadata)"); - assert(result.modified !== undefined, "Failed to stat directory (modified)"); - assert(result.created !== undefined, "Failed to stat directory (created)"); - assert(result.accessed !== undefined, "Failed to stat directory (accessed)"); - assert(result.size !== undefined, "Failed to stat directory (size)"); - assert(result.layout !== undefined, "Failed to stat directory (layout)"); - assert(result.owner !== undefined && typeof result.owner === 'object', "Failed to stat directory (owner)"); - assert(result.dirname !== undefined && typeof result.dirname === 'string', "Failed to stat directory (dirname)"); - assert(result.parent_id !== undefined && typeof result.parent_id === 'string', "Failed to stat directory (parent_id)"); - // todo this will fail for now until is_dir is turned into boolean - assert(result.is_dir !== undefined && typeof result.is_dir === 'boolean' && result.is_dir === true, "Failed to stat directory (is_dir)"); - assert(result.is_empty !== undefined && typeof result.is_empty === 'boolean', "Failed to stat directory (is_empty)"); - pass("testFSStatDirReturnsAttrs passed"); - } catch (error) { - throw("testFSStatDirReturnsAttrs failed:", error); - } - }, - - // test read() with the object returned by write() - testFSReadWithWriteResult = async ()=>{ - try { - let randName = puter.randName(); - let writeResult = await puter.fs.write(randName, 'testValue'); - let result = await (await puter.fs.read(writeResult)).text(); - assert(result === 'testValue', "Failed to read from file"); - pass("testFSReadWithWriteResult passed"); - // delete the file - try { - await puter.fs.delete(randName); - } catch (error) { - fail("testFSReadWithWriteResult failed to delete file:", error); - } - } catch (error) { - fail("testFSReadWithWriteResult failed:", error); - } - }, - - // test stat() with the object returned by write() - testFSStatWithWriteResult = async ()=>{ - try { - let randName = puter.randName(); - let writeResult = await puter.fs.write(randName, 'testValue'); - let result = await puter.fs.stat(writeResult); - assert(result.uid, "Failed to stat file"); - pass("testFSStatWithWriteResult passed"); - // delete the file - try { - await puter.fs.delete(randName); - } catch (error) { - fail("testFSStatWithWriteResult failed to delete file:", error); - } - } catch (error) { - fail("testFSStatWithWriteResult failed:", error); - } - }, - - // test creating files with names from naughtyStrings - testFSWriteWithNaughtyStrings = async ()=>{ - try { - let randName = puter.randName(); - for(let i = 0; i < naughtyStrings.length; i++) { - let filename = randName + naughtyStrings[i]; - let result = await puter.fs.write(filename, 'testValue'); + let randName = puter.randName(); + const result = await puter.fs.write(randName, 'testValue'); assert(result.uid, "Failed to write to file"); - // check name - assert(result.name === filename, "Failed to write to file with naughty name: " + filename); + pass("testFSWrite passed"); // delete the file try { - await puter.fs.delete(filename); + await puter.fs.delete(randName); } catch (error) { - fail("testFSWriteWithNaughtyStrings failed to delete file: " + filename, error); + throw("testFSWrite failed to delete file:", error); } + } catch (error) { + if(puter.debugMode) + console.log(error); + throw("testFSWrite failed:", error); + } + } + }, + { + name: "testFSRead", + description: "Test reading text content from a file and verify it matches the written content", + test: async function() { + try { + let randName = puter.randName(); + await puter.fs.write(randName, 'testValue'); + const result = await (await puter.fs.read(randName)).text(); + assert(result === 'testValue', "Failed to read from file"); + pass("testFSRead passed"); + // delete the file + try { + await puter.fs.delete(randName); + } catch (error) { + fail("testFSRead failed to delete file:", error); + } + } catch (error) { + fail("testFSRead failed:", error); + } + } + }, + { + name: "testFSWriteWithoutData", + description: "Test creating an empty file without providing content data", + test: async function() { + try { + let randName = puter.randName(); + const result = await puter.fs.write(randName); + assert(result.uid, "Failed to write to file"); + pass("testFSWriteWithoutData passed"); + if(randName !== result.name) { + fail(`testFSWriteWithoutData failed: Names do not match ${randName} ${result.name}`); + } + // delete the file + try { + await puter.fs.delete(randName); + } catch (error) { + fail("testFSWriteWithoutData failed to delete file:", error); + } + } catch (error) { + fail("testFSWriteWithoutData failed:", error); + } + } + }, + { + name: "testFSReadWithoutData", + description: "Test reading from an empty file and verify it returns an empty string", + test: async function() { + try { + let randName = puter.randName(); + await puter.fs.write(randName); + const result = await (await puter.fs.read(randName)).text(); + assert(result === '', "Failed to read from file"); + pass("testFSReadWithoutData passed"); + // delete the file + try { + await puter.fs.delete(randName); + } catch (error) { + fail("testFSReadWithoutData failed to delete file:", error); + } + } catch (error) { + fail("testFSReadWithoutData failed:", error); + } + } + }, + { + name: "testFSWriteToExistingFile", + description: "Test overwriting an existing file with new content", + test: async function() { + try { + let randName = puter.randName(); + await puter.fs.write(randName, 'testValue'); + const result = await puter.fs.write(randName, 'updatedValue'); + assert(result.uid, "Failed to write to file"); + pass("testFSWriteToExistingFile passed"); + // delete the file + try { + await puter.fs.delete(randName); + } catch (error) { + fail("testFSWriteToExistingFile failed to delete file:", error); + } + } catch (error) { + fail("testFSWriteToExistingFile failed:", error); + } + } + }, + { + name: "testFSWriteToExistingFileWithoutOverwriteAndDedupe", + description: "Test writing to an existing file with overwrite and dedupe disabled - should fail", + test: async function() { + try { + let randName = puter.randName(); + await puter.fs.write(randName, 'testValue'); + const result = await puter.fs.write(randName, 'updatedValue', { overwrite: false, dedupeName: false }); + assert(!result.uid, "Failed to write to file"); + fail("testFSWriteToExistingFileWithoutOverwriteAndDedupe failed"); + // delete the file + try { + await puter.fs.delete(randName); + } catch (error) { + fail("testFSWriteToExistingFileWithoutOverwriteAndDedupe failed to delete file:", error); + } + } catch (error) { + pass("testFSWriteToExistingFileWithoutOverwriteAndDedupe passed"); } - pass("testFSWriteWithNaughtyStrings passed"); - } catch (error) { - console.log(error); - fail("testFSWriteWithNaughtyStrings failed:", error); - } + } + }, + { + name: "testFSWriteToExistingFileWithoutOverwriteButWithDedupe", + description: "Test writing to an existing file with overwrite disabled but dedupe enabled - should create new file", + test: async function() { + try { + let randName = puter.randName(); + await puter.fs.write(randName, 'testValue'); + const result = await puter.fs.write(randName, 'updatedValue', { overwrite: false, dedupeName: true }); + assert(result.uid, "Failed to write to file"); + pass("testFSWriteToExistingFileWithoutOverwriteButWithDedupe passed"); + // delete the file + try { + await puter.fs.delete(randName); + } catch (error) { + fail("testFSWriteToExistingFileWithoutOverwriteButWithDedupe failed to delete file:", error); + } + } catch (error) { + fail("testFSWriteToExistingFileWithoutOverwriteButWithDedupe failed:", error); + } + } + }, + { + name: "testFSWriteToExistingFileWithOverwriteButWithoutDedupe", + description: "Test writing to an existing file with overwrite enabled but dedupe disabled - should overwrite", + test: async function() { + try { + let randName = puter.randName(); + await puter.fs.write(randName, 'testValue'); + const result = await puter.fs.write(randName, 'updatedValue', { overwrite: true, dedupeName: false }); + assert(result.uid, "Failed to write to file"); + pass("testFSWriteToExistingFileWithOverwriteButWithoutDedupe passed"); + // delete the file + try { + await puter.fs.delete(randName); + } catch (error) { + fail("testFSWriteToExistingFileWithOverwriteButWithoutDedupe failed to delete file:", error); + } + } catch (error) { + fail("testFSWriteToExistingFileWithOverwriteButWithoutDedupe failed:", error); + } + } + }, + { + name: "testFSCreateDir", + description: "Test creating a new directory and verify it returns a valid UID", + test: async function() { + try { + let randName = puter.randName(); + const result = await puter.fs.mkdir(randName); + assert(result.uid, "Failed to create directory"); + pass("testFSCreateDir passed"); + } catch (error) { + fail("testFSCreateDir failed:", error); + } + } + }, + { + name: "testFSReadDir", + description: "Test reading directory contents after creating multiple files within it", + test: async function() { + try { + let randName = puter.randName(); + await puter.fs.mkdir(randName); + await puter.fs.write(randName + '/file1', 'testValue'); + await puter.fs.write(randName + '/file2', 'testValue'); + await puter.fs.write(randName + '/file3', 'testValue'); + const result = await puter.fs.readdir(randName); + assert(result.length === 3, "Failed to read directory"); + pass("testFSReadDir passed"); + } catch (error) { + fail("testFSReadDir failed:", error); + } + } + }, + { + name: "testFSDelete", + description: "Test deleting a file and verify it no longer exists", + test: async function() { + try { + let randName = puter.randName(); + await puter.fs.write(randName, 'testValue'); + const result = await puter.fs.delete(randName); + assert(!result.uid, "Failed to delete file"); + pass("testFSDelete passed"); + } catch (error) { + fail("testFSDelete failed:", error); + } + } + }, + { + name: "testFSDeleteDir", + description: "Test deleting a directory containing multiple files", + test: async function() { + try { + let randName = puter.randName(); + await puter.fs.mkdir(randName); + await puter.fs.write(randName + '/file1', 'testValue'); + await puter.fs.write(randName + '/file2', 'testValue'); + await puter.fs.write(randName + '/file3', 'testValue'); + const result = await puter.fs.delete(randName); + assert(!result.uid, "Failed to delete directory"); + pass("testFSDeleteDir passed"); + } catch (error) { + fail("testFSDeleteDir failed:", error); + } + } + }, + { + name: "testFSDeleteNonExistentFile", + description: "Test attempting to delete a non-existent file and verify it returns a valid response", + test: async function() { + try { + let randName = puter.randName(); + const result = await puter.fs.delete(randName); + assert(!result.uid, "Failed to delete non-existent file"); + pass("testFSDeleteNonExistentFile passed"); + } catch (error) { + if(error.code !== "subject_does_not_exist") + fail("testFSDeleteNonExistentFile failed:", error); + else + pass("testFSDeleteNonExistentFile passed"); + } + } + }, + { + name: "testFSReadNonExistentFile", + description: "Test attempting to read from a non-existent file and verify it returns a valid response", + test: async function() { + try { + let randName = puter.randName(); + const result = await puter.fs.read(randName); + fail("testFSReadNonExistentFile failed"); + } catch (error) { + if(error.code !== "subject_does_not_exist") + fail("testFSReadNonExistentFile failed:", error); + else + pass("testFSReadNonExistentFile passed"); + } + } + }, + { + name: "testFSWriteWithSpecialCharacters", + description: "Test writing text content to a file with special characters and verify it returns a valid UID", + test: async function() { + let randName + try { + randName = 'testFileWithSpecialCharacte rs!@#$%^&*()_+{}|:"<>?`~' + const result = await puter.fs.write(randName, 'testValue', { specialCharacters: true }); + assert(result.uid, "Failed to write to file"); + pass("testFSWriteWithSpecialCharacters passed"); + } catch (error) { + fail("testFSWriteWithSpecialCharacters failed:", error); + } + + // delete the file + try { + await puter.fs.delete(randName); + } catch (error) { + fail("testFSWriteWithSpecialCharacters failed to delete file:", error); + } + } + }, + { + name: "testFSReadWithSpecialCharacters", + description: "Test reading text content from a file with special characters and verify it matches the written content", + test: async function() { + try { + let randName = 'testFileWithSpecialCharacte rs!@#$%^&*()_+{}|:"<>?`~' + await puter.fs.write(randName, 'testValue'); + const result = await (await puter.fs.read(randName)).text(); + assert(result === 'testValue', "Failed to read from file"); + pass("testFSReadWithSpecialCharacters passed"); + } catch (error) { + fail("testFSReadWithSpecialCharacters failed:", error); + } + } + }, + { + name: "testFSWriteLargeFile", + description: "Test writing large text content to a file and verify it returns a valid UID", + test: async function() { + try { + let randName = puter.randName(); + const result = await puter.fs.write(randName, 'testValue'.repeat(100000)); + assert(result.uid, "Failed to write to file"); + pass("testFSWriteLargeFile passed"); + } catch (error) { + fail("testFSWriteLargeFile failed:", error); + } + } + }, + { + name: "testFSReadLargeFile", + description: "Test reading large text content from a file and verify it matches the written content", + test: async function() { + try { + let randName = puter.randName(); + await puter.fs.write(randName, 'testValue'.repeat(100000)); + const result = await (await puter.fs.read(randName)).text(); + assert(result === 'testValue'.repeat(100000), "Failed to read from file"); + pass("testFSReadLargeFile passed"); + } catch (error) { + fail("testFSReadLargeFile failed:", error); + } + } + }, + { + name: "testFSRenameFile", + description: "Test renaming a file and verify the old file is gone", + test: async function() { + try { + let randName = puter.randName(); + let randName2 = puter.randName(); + await puter.fs.write(randName, 'testValue'); + const result = await puter.fs.rename(randName, randName2); + assert(result.name, "Failed to rename file"); + pass("testFSRenameFile passed"); + // check that the old file is gone + try { + await puter.fs.read(randName); + fail("testFSRenameFile failed to delete old file"); + } catch (error) { + if(error.code !== "subject_does_not_exist") + fail("testFSRenameFile failed to delete old file:", error); + else + pass("testFSRenameFile passed"); + } + } catch (error) { + fail("testFSRenameFile failed:", error); + } + } + }, + { + name: "testFSMoveFile", + description: "Test moving a file to a new directory and verify the old file is gone", + test: async function() { + try { + let randName = puter.randName(); + let randName2 = puter.randName(); + await puter.fs.write(randName, 'testValue'); + await puter.fs.mkdir(randName2); + let result = await puter.fs.move(randName, randName2); + assert(result.moved, "Failed to move file"); + // check that the old file is gone + try { + await puter.fs.read(randName); + fail("testFSMoveFile failed to delete old file"); + } catch (error) { + if(error.code !== "subject_does_not_exist") + fail("testFSMoveFile failed to delete old file:", error); + else + pass("testFSMoveFile passed"); + } + } catch (error) { + fail("testFSMoveFile failed:", error); + } + } + }, + { + name: "testFSCopyFile", + description: "Test copying a file to a new directory and verify the old file is still there", + test: async function() { + try { + let randName = puter.randName(); + let randName2 = puter.randName(); + await puter.fs.write(randName, 'testValue'); + await puter.fs.mkdir(randName2); + let result = await puter.fs.copy(randName, randName2); + assert(Array.isArray(result) && result[0].copied.uid, "Failed to copy file"); + // check that the old file is still there + try { + await puter.fs.read(randName); + pass("testFSCopyFile passed"); + } catch (error) { + fail("testFSCopyFile failed to keep old file:", error); + } + } catch (error) { + fail("testFSCopyFile failed:", error); + } + } + }, + { + name: "testFSCopyFileWithNewName", + description: "Test copying a file to a new directory with a new name and verify the old file is still there", + test: async function() { + try { + let randName = puter.randName(); + let randName2 = puter.randName(); + await puter.fs.write(randName, 'testValue'); + await puter.fs.mkdir(randName2); + let result = await puter.fs.copy(randName, randName2, { newName: 'newName' }); + assert(Array.isArray(result) && result[0].copied.uid, "Failed to copy file"); + // check file name + assert(result[0].copied.name === 'newName', "Failed to copy file with new name"); + // check that the old file is still there + try { + await puter.fs.read(randName); + pass("testFSCopyFileWithNewName passed"); + } catch (error) { + fail("testFSCopyFileWithNewName failed to keep old file:", error); + } + } catch (error) { + fail("testFSCopyFileWithNewName failed:", error); + } + } + }, + { + name: "testFSStat", + description: "Test getting file metadata and verify it returns a valid UID", + test: async function() { + try { + let randName = puter.randName(); + await puter.fs.write(randName, 'testValue'); + let result = await puter.fs.stat(randName); + assert(result.uid, "Failed to stat file"); + pass("testFSStat passed"); + } catch (error) { + fail("testFSStat failed:", error); + } + } + }, + { + name: "testFSStatDir", + description: "Test getting directory metadata and verify it returns a valid UID", + test: async function() { + try { + let randName = puter.randName(); + await puter.fs.mkdir(randName); + let result = await puter.fs.stat(randName); + assert(result.uid, "Failed to stat directory"); + pass("testFSStatDir passed"); + } catch (error) { + fail("testFSStatDir failed:", error); + } + } + }, + { + name: "testFSStatNonExistent", + description: "Test attempting to get metadata from a non-existent file or directory and verify it returns a valid response", + test: async function() { + try { + let randName = puter.randName(); + let result = await puter.fs.stat(randName); + fail("testFSStatNonExistent failed"); + } catch (error) { + if(error.code !== "subject_does_not_exist") + fail("testFSStatNonExistent failed:", error); + else + pass("testFSStatNonExistent passed"); + } + } + }, + { + name: "testFSDeleteDirWithFiles", + description: "Test deleting a directory containing multiple files and verify it no longer exists", + test: async function() { + try { + let randName = puter.randName(); + await puter.fs.mkdir(randName); + await puter.fs.write(randName + '/file1', 'testValue'); + await puter.fs.write(randName + '/file2', 'testValue'); + await puter.fs.write(randName + '/file3', 'testValue'); + const result = await puter.fs.delete(randName, { recursive: true }); + assert(!result.uid, "Failed to delete directory"); + pass("testFSDeleteDirWithFiles passed"); + } catch (error) { + fail("testFSDeleteDirWithFiles failed:", error); + } + } + }, + { + name: "testFSStatDirReturnsAttrs", + description: "Test getting directory metadata and verifying it returns the expected attributes", + test: async function() { + try { + let randName = puter.randName(); + await puter.fs.mkdir(randName); + let result = await puter.fs.stat(randName); + assert(result.name && typeof result.name === 'string', "Failed to stat directory (name)"); + assert(result.path && typeof result.path === 'string', "Failed to stat directory (path)"); + assert(result.immutable !== undefined, "Failed to stat directory (immutable)"); + assert(result.metadata !== undefined, "Failed to stat directory (metadata)"); + assert(result.modified !== undefined, "Failed to stat directory (modified)"); + assert(result.created !== undefined, "Failed to stat directory (created)"); + assert(result.accessed !== undefined, "Failed to stat directory (accessed)"); + assert(result.size !== undefined, "Failed to stat directory (size)"); + assert(result.layout !== undefined, "Failed to stat directory (layout)"); + assert(result.owner !== undefined && typeof result.owner === 'object', "Failed to stat directory (owner)"); + assert(result.dirname !== undefined && typeof result.dirname === 'string', "Failed to stat directory (dirname)"); + assert(result.parent_id !== undefined && typeof result.parent_id === 'string', "Failed to stat directory (parent_id)"); + // todo this will fail for now until is_dir is turned into boolean + assert(result.is_dir !== undefined && typeof result.is_dir === 'boolean' && result.is_dir === true, "Failed to stat directory (is_dir)"); + assert(result.is_empty !== undefined && typeof result.is_empty === 'boolean', "Failed to stat directory (is_empty)"); + pass("testFSStatDirReturnsAttrs passed"); + } catch (error) { + throw("testFSStatDirReturnsAttrs failed:", error); + } + } + }, + { + name: "testFSReadWithWriteResult", + description: "Test reading text content from a file using the object returned by write()", + test: async function() { + try { + let randName = puter.randName(); + let writeResult = await puter.fs.write(randName, 'testValue'); + let result = await (await puter.fs.read(writeResult)).text(); + assert(result === 'testValue', "Failed to read from file"); + pass("testFSReadWithWriteResult passed"); + // delete the file + try { + await puter.fs.delete(randName); + } catch (error) { + fail("testFSReadWithWriteResult failed to delete file:", error); + } + } catch (error) { + fail("testFSReadWithWriteResult failed:", error); + } + } + }, + { + name: "testFSStatWithWriteResult", + description: "Test getting file metadata using the object returned by write()", + test: async function() { + try { + let randName = puter.randName(); + let writeResult = await puter.fs.write(randName, 'testValue'); + let result = await puter.fs.stat(writeResult); + assert(result.uid, "Failed to stat file"); + pass("testFSStatWithWriteResult passed"); + // delete the file + try { + await puter.fs.delete(randName); + } catch (error) { + fail("testFSStatWithWriteResult failed to delete file:", error); + } + } catch (error) { + fail("testFSStatWithWriteResult failed:", error); + } + } + }, + { + name: "testFSWriteWithNaughtyStrings", + description: "Test writing text content to files with names from naughtyStrings and verify it returns a valid UID", + test: async function() { + try { + let randName = puter.randName(); + for(let i = 0; i < naughtyStrings.length; i++) { + let filename = randName + naughtyStrings[i]; + let result = await puter.fs.write(filename, 'testValue'); + assert(result.uid, "Failed to write to file"); + // check name + assert(result.name === filename, "Failed to write to file with naughty name: " + filename); + // delete the file + try { + await puter.fs.delete(filename); + } catch (error) { + fail("testFSWriteWithNaughtyStrings failed to delete file: " + filename, error); + } + } + pass("testFSWriteWithNaughtyStrings passed"); + } catch (error) { + console.log(error); + fail("testFSWriteWithNaughtyStrings failed:", error); + } + } }, ]; \ No newline at end of file diff --git a/src/puter-js/test/kv.test.js b/src/puter-js/test/kv.test.js index de8eb12ec..ed0444af3 100644 --- a/src/puter-js/test/kv.test.js +++ b/src/puter-js/test/kv.test.js @@ -1,419 +1,506 @@ /* eslint-disable */ // TODO: Make these more compatible with eslint window.kvTests = [ - testSetKeyWithValue = async function() { - try { - const result = await puter.kv.set('testKey', 'testValue'); - assert(result === true, "Failed to set key with value"); - pass("testSetKeyWithValue passed"); - } catch (error) { - fail("testSetKeyWithValue failed:", error); - } - }, - - testUpdateKey = async function() { - try { - await puter.kv.set('updateKey', 'initialValue'); - const result = await puter.kv.set('updateKey', 'updatedValue'); - assert(result === true, "Failed to update existing key"); - pass("testUpdateKey passed"); - } catch (error) { - fail("testUpdateKey failed:", error); - } - }, - - testKeySizeLimit = async function() { - try { - const largeKey = 'a'.repeat(1025); // 1 KB + 1 byte - await puter.kv.set(largeKey, 'value'); - fail("testKeySizeLimit failed: No error thrown for large key"); - } catch (error) { - pass("testKeySizeLimit passed:", error.message); - } - }, - - testInvalidParameters = async function() { - try { - await puter.kv.set(undefined, 'value'); - fail("testInvalidParameters failed: No error thrown for undefined key"); - } catch (error) { - pass("testInvalidParameters passed:", error.message); - } - }, - - // testEmptyKey should fail - testEmptyKey = async function() { - try { - await puter.kv.set('', 'value'); - fail("testEmptyKey failed: No error thrown for empty key"); - } catch (error) { - pass("testEmptyKey passed:", error.message); - } - }, - - - testSetNullValue = async function() { - try { - const result = await puter.kv.set('nullValueKey', null); - assert(result === true, "Failed to set null value"); - pass("testSetNullValue passed"); - } catch (error) { - fail("testSetNullValue failed:", error); - } - }, - - testSetObjectValue = async function() { - try { - const result = await puter.kv.set('objectKey', { a: 1 }); - assert(result === true, "Failed to set object as value"); - pass("testSetObjectValue passed"); - } catch (error) { - fail("testSetObjectValue failed:", error); - } - }, - - testSetKeyWithSpecialCharacters = async function() { - try { - const result = await puter.kv.set('special@Key#', 'value'); - assert(result === true, "Failed to set key with special characters"); - pass("testSetKeyWithSpecialCharacters passed"); - } catch (error) { - fail("testSetKeyWithSpecialCharacters failed:", error); - } - }, - - testSetLargeValue = async function() { - try { - const largeValue = 'a'.repeat(10000); // 10 KB - const result = await puter.kv.set('largeValueKey', largeValue); - assert(result === true, "Failed to set large value"); - pass("testSetLargeValue passed"); - } catch (error) { - fail("testSetLargeValue failed:", error); - } - }, - - testSetBooleanValue = async function() { - try { - const result = await puter.kv.set('booleanKey', true); - assert(result === true, "Failed to set boolean value"); - pass("testSetBooleanValue passed"); - } catch (error) { - fail("testSetBooleanValue failed:", error); - } - }, - - testSetNumericKey = async function() { - try { - const result = await puter.kv.set(123, 'value'); - assert(result === true, "Failed to set numeric key"); - pass("testSetNumericKey passed"); - } catch (error) { - fail("testSetNumericKey failed:", error); - } - }, - - testSetConcurrentKeys = async function() { - try { - const promises = [puter.kv.set('key1', 'value1'), puter.kv.set('key2', 'value2')]; - const results = await Promise.all(promises); - assert(results.every(result => result === true), "Failed to set concurrent keys"); - pass("testSetConcurrentKeys passed"); - } catch (error) { - fail("testSetConcurrentKeys failed:", error); - } - }, - - testSetValueAndRetrieve = async function() { - try { - await puter.kv.set('retrieveKey', 'testValue'); - const value = await puter.kv.get('retrieveKey'); - assert(value === 'testValue', "Failed to retrieve correct value"); - pass("testSetValueAndRetrieve passed"); - } catch (error) { - fail("testSetValueAndRetrieve failed:", error); - } - }, - - testUpdateValueAndRetrieve = async function() { - try { - await puter.kv.set('updateKey', 'initialValue'); - await puter.kv.set('updateKey', 'updatedValue'); - const value = await puter.kv.get('updateKey'); - assert(value === 'updatedValue', "Failed to retrieve updated value"); - pass("testUpdateValueAndRetrieve passed"); - } catch (error) { - fail("testUpdateValueAndRetrieve failed:", error); - } - }, - - testSetNumericValueAndRetrieve = async function() { - try { - await puter.kv.set('numericKey', 123); - const value = await puter.kv.get('numericKey'); - assert(value === 123, "Failed to retrieve numeric value"); - pass("testSetNumericValueAndRetrieve passed"); - } catch (error) { - fail("testSetNumericValueAndRetrieve failed:", error); - } - }, - - testSetBooleanValueAndRetrieve = async function() { - try { - await puter.kv.set('booleanKey', true); - const value = await puter.kv.get('booleanKey'); - assert(value === true, "Failed to retrieve boolean value"); - pass("testSetBooleanValueAndRetrieve passed"); - } catch (error) { - fail("testSetBooleanValueAndRetrieve failed:", error); - } - }, - - - testSetAndDeleteKey = async function() { - try { - await puter.kv.set('deleteKey', 'value'); - const result = await puter.kv.del('deleteKey'); - assert(result === true, "Failed to delete key"); - pass("testSetAndDeleteKey passed"); - } catch (error) { - fail("testSetAndDeleteKey failed:", error); - } - }, - - // if key does not exist, get() should return null - testGetNonexistentKey = async function() { - try { - const value = await puter.kv.get('nonexistentKey_102mk'); - assert(value === null, "Failed to return `null` for nonexistent key"); - pass("testGetNonexistentKey passed"); - } catch (error) { - fail("testGetNonexistentKey failed:", error); - } - }, - - // string key and object value - testSetObjectValue = async function() { - try { - const result = await puter.kv.set('objectKey', { a: 1 }); - assert(result === true, "Failed to set object as value"); - const value = await puter.kv.get('objectKey'); - assert(value.a === 1, "Failed to retrieve object value"); - pass("testSetObjectValue passed"); - } catch (error) { - fail("testSetObjectValue failed:", error); - } - }, - - // string key and array value - testSetArrayValue = async function() { - try { - const result = await puter.kv.set('arrayKey', [1, 2, 3]); - assert(result === true, "Failed to set array as value"); - const value = await puter.kv.get('arrayKey'); - assert(value[0] === 1, "Failed to retrieve array value"); - pass("testSetArrayValue passed"); - } catch (error) { - fail("testSetArrayValue failed:", error); - } - }, - - testSetKeyWithSpecialCharactersAndRetrieve = async function() { - try { - await puter.kv.set('special@Key#', 'value'); - const value = await puter.kv.get('special@Key#'); - assert(value === 'value', "Failed to retrieve value for key with special characters"); - pass("testSetKeyWithSpecialCharactersAndRetrieve passed"); - } catch (error) { - fail("testSetKeyWithSpecialCharactersAndRetrieve failed:", error); - } - }, - - testConcurrentSetOperations = async function() { - try { - const promises = [puter.kv.set('key1', 'value1'), puter.kv.set('key2', 'value2')]; - const results = await Promise.all(promises); - assert(results.every(result => result === true), "Failed to set concurrent keys"); - pass("testConcurrentSetOperations passed"); - } catch (error) { - fail("testConcurrentSetOperations failed:", error); - } - }, - - //test flush: create a bunch of keys, flush, then check if they exist - testFlush = async function() { - try { - const keys = []; - for(let i = 0; i < 10; i++){ - keys.push('key' + i); + { + name: "testSetKeyWithValue", + description: "Test setting a key-value pair and verify it returns true", + test: async function() { + try { + const result = await puter.kv.set('testKey', 'testValue'); + assert(result === true, "Failed to set key with value"); + pass("testSetKeyWithValue passed"); + } catch (error) { + fail("testSetKeyWithValue failed:", error); } - await Promise.all(keys.map(key => puter.kv.set(key, 'value'))); - await puter.kv.flush(); - const results = await Promise.all(keys.map(key => puter.kv.get(key))); - assert(results.every(result => result === null), "Failed to flush keys"); - pass("testFlush passed"); - } catch (error) { - fail("testFlush failed:", error); } }, - - // incr - testIncr = async function() { - try { - const result = await puter.kv.incr(puter.randName()); - assert(result === 1, "Failed to increment key"); - pass("testIncr passed"); - } catch (error) { - fail("testIncr failed:", error); - } - }, - - // decr - testDecr = async function() { - try { - const result = await puter.kv.decr(puter.randName()); - assert(result === -1, "Failed to decrement key"); - pass("testDecr passed"); - } catch (error) { - fail("testDecr failed:", error); - } - }, - - // incr existing key - testIncrExistingKey = async function() { - try { - await puter.kv.set('incrKey', 1); - const result = await puter.kv.incr('incrKey'); - assert(result === 2, "Failed to increment existing key"); - pass("testIncrExistingKey passed"); - } catch (error) { - fail("testIncrExistingKey failed:", error); - } - }, - - // decr existing key - testIncrExistingKey = async function() { - try { - await puter.kv.set('decrKey', 2); - const result = await puter.kv.decr('decrKey'); - assert(result === 1, "Failed to decrement existing key"); - pass("testDecrExistingKey passed"); - } catch (error) { - fail("testDecrExistingKey failed:", error); - } - }, - - // incr by amount - testIncrByAmount = async function() { - try { - await puter.kv.set('incrKey', 1); - const result = await puter.kv.incr('incrKey', 5); - assert(result === 6, "Failed to increment key by amount"); - pass("testIncrByAmount passed"); - } catch (error) { - fail("testIncrByAmount failed:", error); - } - }, - - // decr by amount - testDecrByAmount = async function() { - try { - await puter.kv.set('decrKey', 10); - const result = await puter.kv.decr('decrKey', 5); - assert(result === 5, "Failed to decrement key by amount"); - pass("testDecrByAmount passed"); - } catch (error) { - fail("testDecrByAmount failed:", error); - } - }, - - // incr by amount existing key - testIncrByAmountExistingKey = async function() { - try { - await puter.kv.set('incrKey', 1); - const result = await puter.kv.incr('incrKey', 5); - assert(result === 6, "Failed to increment existing key by amount"); - pass("testIncrByAmountExistingKey passed"); - } catch (error) { - fail("testIncrByAmountExistingKey failed:", error); - } - }, - - // decr by amount existing key - testDecrByAmountExistingKey= async function() { - try { - await puter.kv.set('decrKey', 10); - const result = await puter.kv.decr('decrKey', 5); - assert(result === 5, "Failed to decrement existing key by amount"); - pass("testDecrByAmountExistingKey passed"); - } catch (error) { - fail("testDecrByAmountExistingKey failed:", error); - } - }, - - // incr by negative amount - testIncrByNegativeAmount = async function() { - try { - await puter.kv.set('incrKey', 1); - const result = await puter.kv.incr('incrKey', -5); - assert(result === -4, "Failed to increment key by negative amount"); - pass("testIncrByNegativeAmount passed"); - } catch (error) { - fail("testIncrByNegativeAmount failed:", error); - } - }, - - // decr by negative amount - testDecrByNegativeAmount = async function() { - try { - await puter.kv.set('decrKey', 10); - const result = await puter.kv.decr('decrKey', -5); - assert(result === 15, "Failed to decrement key by negative amount"); - pass("testDecrByNegativeAmount passed"); - } catch (error) { - fail("testDecrByNegativeAmount failed:", error); - } - }, - - // list keys - testListKeys = async function() { - try { - const keys = []; - // flush first - await puter.kv.flush(); - // create 10 keys - for(let i = 0; i < 10; i++){ - keys.push('key' + i); + { + name: "testUpdateKey", + description: "Test updating an existing key with a new value and verify it returns true", + test: async function() { + try { + await puter.kv.set('updateKey', 'initialValue'); + const result = await puter.kv.set('updateKey', 'updatedValue'); + assert(result === true, "Failed to update existing key"); + pass("testUpdateKey passed"); + } catch (error) { + fail("testUpdateKey failed:", error); } - // set all keys - await Promise.all(keys.map(key => puter.kv.set(key, 'value'))); - // list keys - const result = await puter.kv.list(); - assert(result.length === 10, "Failed to list keys"); - pass("testListKeys passed"); - } catch (error) { - fail("testListKeys failed:", error); } }, - - // list keys using glob - testListKeysGlob = async function() { - try { - const keys = []; - // flush first - await puter.kv.flush(); - // create 10 keys - for(let i = 0; i < 10; i++){ - keys.push('key' + i); + { + name: "testKeySizeLimit", + description: "Test setting a key that exceeds the size limit and verify it throws an error", + test: async function() { + try { + const largeKey = 'a'.repeat(1025); // 1 KB + 1 byte + await puter.kv.set(largeKey, 'value'); + fail("testKeySizeLimit failed: No error thrown for large key"); + } catch (error) { + pass("testKeySizeLimit passed:", error.message); + } + } + }, + { + name: "testInvalidParameters", + description: "Test setting a key with invalid parameters and verify it throws an error", + test: async function() { + try { + await puter.kv.set(undefined, 'value'); + fail("testInvalidParameters failed: No error thrown for undefined key"); + } catch (error) { + pass("testInvalidParameters passed:", error.message); + } + } + }, + { + name: "testEmptyKey", + description: "Test setting an empty key and verify it throws an error", + test: async function() { + try { + await puter.kv.set('', 'value'); + fail("testEmptyKey failed: No error thrown for empty key"); + } catch (error) { + pass("testEmptyKey passed:", error.message); + } + } + }, + { + name: "testSetNullValue", + description: "Test setting a null value and verify it returns true", + test: async function() { + try { + const result = await puter.kv.set('nullValueKey', null); + assert(result === true, "Failed to set null value"); + pass("testSetNullValue passed"); + } catch (error) { + fail("testSetNullValue failed:", error); + } + } + }, + { + name: "testSetObjectValue", + description: "Test setting an object as a value and verify it returns true", + test: async function() { + try { + const result = await puter.kv.set('objectKey', { a: 1 }); + assert(result === true, "Failed to set object as value"); + pass("testSetObjectValue passed"); + } catch (error) { + fail("testSetObjectValue failed:", error); + } + } + }, + { + name: "testSetKeyWithSpecialCharacters", + description: "Test setting a key with special characters and verify it returns true", + test: async function() { + try { + const result = await puter.kv.set('special@Key#', 'value'); + assert(result === true, "Failed to set key with special characters"); + pass("testSetKeyWithSpecialCharacters passed"); + } catch (error) { + fail("testSetKeyWithSpecialCharacters failed:", error); + } + } + }, + { + name: "testSetLargeValue", + description: "Test setting a large value and verify it returns true", + test: async function() { + try { + const largeValue = 'a'.repeat(10000); // 10 KB + const result = await puter.kv.set('largeValueKey', largeValue); + assert(result === true, "Failed to set large value"); + pass("testSetLargeValue passed"); + } catch (error) { + fail("testSetLargeValue failed:", error); + } + } + }, + { + name: "testSetBooleanValue", + description: "Test setting a boolean value and verify it returns true", + test: async function() { + try { + const result = await puter.kv.set('booleanKey', true); + assert(result === true, "Failed to set boolean value"); + pass("testSetBooleanValue passed"); + } catch (error) { + fail("testSetBooleanValue failed:", error); + } + } + }, + { + name: "testSetNumericKey", + description: "Test setting a numeric key and verify it returns true", + test: async function() { + try { + const result = await puter.kv.set(123, 'value'); + assert(result === true, "Failed to set numeric key"); + pass("testSetNumericKey passed"); + } catch (error) { + fail("testSetNumericKey failed:", error); + } + } + }, + { + name: "testSetConcurrentKeys", + description: "Test setting multiple keys concurrently and verify all return true", + test: async function() { + try { + const promises = [puter.kv.set('key1', 'value1'), puter.kv.set('key2', 'value2')]; + const results = await Promise.all(promises); + assert(results.every(result => result === true), "Failed to set concurrent keys"); + pass("testSetConcurrentKeys passed"); + } catch (error) { + fail("testSetConcurrentKeys failed:", error); + } + } + }, + { + name: "testSetValueAndRetrieve", + description: "Test setting a value and then retrieving it to verify it matches", + test: async function() { + try { + await puter.kv.set('retrieveKey', 'testValue'); + const value = await puter.kv.get('retrieveKey'); + assert(value === 'testValue', "Failed to retrieve correct value"); + pass("testSetValueAndRetrieve passed"); + } catch (error) { + fail("testSetValueAndRetrieve failed:", error); + } + } + }, + { + name: "testUpdateValueAndRetrieve", + description: "Test updating a value and then retrieving it to verify it matches the updated value", + test: async function() { + try { + await puter.kv.set('updateKey', 'initialValue'); + await puter.kv.set('updateKey', 'updatedValue'); + const value = await puter.kv.get('updateKey'); + assert(value === 'updatedValue', "Failed to retrieve updated value"); + pass("testUpdateValueAndRetrieve passed"); + } catch (error) { + fail("testUpdateValueAndRetrieve failed:", error); + } + } + }, + { + name: "testSetNumericValueAndRetrieve", + description: "Test setting a numeric value and then retrieving it to verify it matches", + test: async function() { + try { + await puter.kv.set('numericKey', 123); + const value = await puter.kv.get('numericKey'); + assert(value === 123, "Failed to retrieve numeric value"); + pass("testSetNumericValueAndRetrieve passed"); + } catch (error) { + fail("testSetNumericValueAndRetrieve failed:", error); + } + } + }, + { + name: "testSetBooleanValueAndRetrieve", + description: "Test setting a boolean value and then retrieving it to verify it matches", + test: async function() { + try { + await puter.kv.set('booleanKey', true); + const value = await puter.kv.get('booleanKey'); + assert(value === true, "Failed to retrieve boolean value"); + pass("testSetBooleanValueAndRetrieve passed"); + } catch (error) { + fail("testSetBooleanValueAndRetrieve failed:", error); + } + } + }, + { + name: "testSetAndDeleteKey", + description: "Test setting a key and then deleting it to verify it returns true", + test: async function() { + try { + await puter.kv.set('deleteKey', 'value'); + const result = await puter.kv.del('deleteKey'); + assert(result === true, "Failed to delete key"); + pass("testSetAndDeleteKey passed"); + } catch (error) { + fail("testSetAndDeleteKey failed:", error); + } + } + }, + { + name: "testGetNonexistentKey", + description: "Test getting a non-existent key and verify it returns null", + test: async function() { + try { + const value = await puter.kv.get('nonexistentKey_102mk'); + assert(value === null, "Failed to return `null` for nonexistent key"); + pass("testGetNonexistentKey passed"); + } catch (error) { + fail("testGetNonexistentKey failed:", error); + } + } + }, + { + name: "testSetObjectValueAndRetrieve", + description: "Test setting an object value and then retrieving it to verify it matches", + test: async function() { + try { + const result = await puter.kv.set('objectKey', { a: 1 }); + assert(result === true, "Failed to set object as value"); + const value = await puter.kv.get('objectKey'); + assert(value.a === 1, "Failed to retrieve object value"); + pass("testSetObjectValueAndRetrieve passed"); + } catch (error) { + fail("testSetObjectValueAndRetrieve failed:", error); + } + } + }, + { + name: "testSetArrayValue", + description: "Test setting an array as a value and verify it returns true", + test: async function() { + try { + const result = await puter.kv.set('arrayKey', [1, 2, 3]); + assert(result === true, "Failed to set array as value"); + const value = await puter.kv.get('arrayKey'); + assert(value[0] === 1, "Failed to retrieve array value"); + pass("testSetArrayValue passed"); + } catch (error) { + fail("testSetArrayValue failed:", error); + } + } + }, + { + name: "testSetKeyWithSpecialCharactersAndRetrieve", + description: "Test setting a key with special characters and then retrieving it to verify it matches", + test: async function() { + try { + await puter.kv.set('special@Key#', 'value'); + const value = await puter.kv.get('special@Key#'); + assert(value === 'value', "Failed to retrieve value for key with special characters"); + pass("testSetKeyWithSpecialCharactersAndRetrieve passed"); + } catch (error) { + fail("testSetKeyWithSpecialCharactersAndRetrieve failed:", error); + } + } + }, + { + name: "testConcurrentSetOperations", + description: "Test setting multiple keys concurrently and verify all return true", + test: async function() { + try { + const promises = [puter.kv.set('key1', 'value1'), puter.kv.set('key2', 'value2')]; + const results = await Promise.all(promises); + assert(results.every(result => result === true), "Failed to set concurrent keys"); + pass("testConcurrentSetOperations passed"); + } catch (error) { + fail("testConcurrentSetOperations failed:", error); + } + } + }, + { + name: "testFlush", + description: "Test flushing a bunch of keys and verify they no longer exist", + test: async function() { + try { + const keys = []; + for(let i = 0; i < 10; i++){ + keys.push('key' + i); + } + await Promise.all(keys.map(key => puter.kv.set(key, 'value'))); + await puter.kv.flush(); + const results = await Promise.all(keys.map(key => puter.kv.get(key))); + assert(results.every(result => result === null), "Failed to flush keys"); + pass("testFlush passed"); + } catch (error) { + fail("testFlush failed:", error); + } + } + }, + { + name: "testIncr", + description: "Test incrementing a key and verify it returns 1", + test: async function() { + try { + const result = await puter.kv.incr(puter.randName()); + assert(result === 1, "Failed to increment key"); + pass("testIncr passed"); + } catch (error) { + fail("testIncr failed:", error); + } + } + }, + { + name: "testDecr", + description: "Test decrementing a key and verify it returns -1", + test: async function() { + try { + const result = await puter.kv.decr(puter.randName()); + assert(result === -1, "Failed to decrement key"); + pass("testDecr passed"); + } catch (error) { + fail("testDecr failed:", error); + } + } + }, + { + name: "testIncrExistingKey", + description: "Test incrementing an existing key and verify it returns 2", + test: async function() { + try { + await puter.kv.set('incrKey', 1); + const result = await puter.kv.incr('incrKey'); + assert(result === 2, "Failed to increment existing key"); + pass("testIncrExistingKey passed"); + } catch (error) { + fail("testIncrExistingKey failed:", error); + } + } + }, + { + name: "testDecrExistingKey", + description: "Test decrementing an existing key and verify it returns 1", + test: async function() { + try { + await puter.kv.set('decrKey', 2); + const result = await puter.kv.decr('decrKey'); + assert(result === 1, "Failed to decrement existing key"); + pass("testDecrExistingKey passed"); + } catch (error) { + fail("testDecrExistingKey failed:", error); + } + } + }, + { + name: "testIncrByAmount", + description: "Test incrementing a key by a specified amount and verify it returns the correct value", + test: async function() { + try { + await puter.kv.set('incrKey', 1); + const result = await puter.kv.incr('incrKey', 5); + assert(result === 6, "Failed to increment key by amount"); + pass("testIncrByAmount passed"); + } catch (error) { + fail("testIncrByAmount failed:", error); + } + } + }, + { + name: "testDecrByAmount", + description: "Test decrementing a key by a specified amount and verify it returns the correct value", + test: async function() { + try { + await puter.kv.set('decrKey', 10); + const result = await puter.kv.decr('decrKey', 5); + assert(result === 5, "Failed to decrement key by amount"); + pass("testDecrByAmount passed"); + } catch (error) { + fail("testDecrByAmount failed:", error); + } + } + }, + { + name: "testIncrByAmountExistingKey", + description: "Test incrementing an existing key by a specified amount and verify it returns the correct value", + test: async function() { + try { + await puter.kv.set('incrKey', 1); + const result = await puter.kv.incr('incrKey', 5); + assert(result === 6, "Failed to increment existing key by amount"); + pass("testIncrByAmountExistingKey passed"); + } catch (error) { + fail("testIncrByAmountExistingKey failed:", error); + } + } + }, + { + name: "testDecrByAmountExistingKey", + description: "Test decrementing an existing key by a specified amount and verify it returns the correct value", + test: async function() { + try { + await puter.kv.set('decrKey', 10); + const result = await puter.kv.decr('decrKey', 5); + assert(result === 5, "Failed to decrement existing key by amount"); + pass("testDecrByAmountExistingKey passed"); + } catch (error) { + fail("testDecrByAmountExistingKey failed:", error); + } + } + }, + { + name: "testIncrByNegativeAmount", + description: "Test incrementing a key by a negative amount and verify it returns the correct value", + test: async function() { + try { + await puter.kv.set('incrKey', 1); + const result = await puter.kv.incr('incrKey', -5); + assert(result === -4, "Failed to increment key by negative amount"); + pass("testIncrByNegativeAmount passed"); + } catch (error) { + fail("testIncrByNegativeAmount failed:", error); + } + } + }, + { + name: "testDecrByNegativeAmount", + description: "Test decrementing a key by a negative amount and verify it returns the correct value", + test: async function() { + try { + await puter.kv.set('decrKey', 10); + const result = await puter.kv.decr('decrKey', -5); + assert(result === 15, "Failed to decrement key by negative amount"); + pass("testDecrByNegativeAmount passed"); + } catch (error) { + fail("testDecrByNegativeAmount failed:", error); + } + } + }, + { + name: "testListKeys", + description: "Test listing all keys and verify the count is correct", + test: async function() { + try { + const keys = []; + // flush first + await puter.kv.flush(); + // create 10 keys + for(let i = 0; i < 10; i++){ + keys.push('key' + i); + } + // set all keys + await Promise.all(keys.map(key => puter.kv.set(key, 'value'))); + // list keys + const result = await puter.kv.list(); + assert(result.length === 10, "Failed to list keys"); + pass("testListKeys passed"); + } catch (error) { + fail("testListKeys failed:", error); + } + } + }, + { + name: "testListKeysGlob", + description: "Test listing keys using a glob pattern and verify the count is correct", + test: async function() { + try { + const keys = []; + // flush first + await puter.kv.flush(); + // create 10 keys + for(let i = 0; i < 10; i++){ + keys.push('key' + i); + } + // set all keys + await Promise.all(keys.map(key => puter.kv.set(key, 'value'))); + // list keys + const result = await puter.kv.list('k*'); + assert(result.length === 10, "Failed to list keys using glob"); + pass("testListKeysGlob passed"); + } catch (error) { + fail("testListKeysGlob failed:", error); } - // set all keys - await Promise.all(keys.map(key => puter.kv.set(key, 'value'))); - // list keys - const result = await puter.kv.list('k*'); - assert(result.length === 10, "Failed to list keys using glob"); - pass("testListKeysGlob passed"); - } catch (error) { - fail("testListKeysGlob failed:", error); } }, ] diff --git a/src/puter-js/test/run.html b/src/puter-js/test/run.html index 069be0c3f..beca0a181 100644 --- a/src/puter-js/test/run.html +++ b/src/puter-js/test/run.html @@ -50,10 +50,19 @@ } .test-container label{ display: block; + margin-left: 5px; } .test-container input{ float: left; } + .test-name { + color: #727272; + } + .test-description { + font-size: 12px; + color: #262626; + margin-top: 2px; + } .test-run-button { margin-left: 10px; background-color: #4c84af; @@ -109,13 +118,46 @@ throw err; } + // Function to get test name and description + function getTestInfo(test) { + if (typeof test === 'function') { + return { + name: test.name, + description: test.description || 'No description provided' + }; + } else if (typeof test === 'object' && test.name && test.test) { + return { + name: test.name, + description: test.description || 'No description provided' + }; + } + return { + name: 'Unknown Test', + description: 'No description provided' + }; + } + + // Function to execute a test + async function executeTest(test) { + if (typeof test === 'function') { + return await test(); + } else if (typeof test === 'object' && test.test) { + return await test.test(); + } + throw new Error('Invalid test format'); + } + // print the test name with checkbox for each test $('#tests').append('

File System Tests

'); for (let i = 0; i < fsTests.length; i++) { + const testInfo = getTestInfo(fsTests[i]); $('#tests').append(`
-
+
`); @@ -123,10 +165,14 @@ $('#tests').append('

Key Value Tests

'); for (let i = 0; i < kvTests.length; i++) { + const testInfo = getTestInfo(kvTests[i]); $('#tests').append(`
-
+
`); @@ -134,10 +180,14 @@ $('#tests').append('

AI Tests

'); for (let i = 0; i < aiTests.length; i++) { + const testInfo = getTestInfo(aiTests[i]); $('#tests').append(`
-
+
`); @@ -168,11 +218,12 @@ $(`#${containerId} pre`).remove(); try { - await tests[index](); + await executeTest(tests[index]); // make this test's container green $(`#${containerId}`).css('background-color', '#85e085'); } catch (e) { - console.error(`${testType.toUpperCase()} Test failed:`, tests[index].name, e); + const testInfo = getTestInfo(tests[index]); + console.error(`${testType.toUpperCase()} Test failed:`, testInfo.name, e); // make this test's container red $(`#${containerId}`).css('background-color', '#ffbfbf'); // message - show full error information including JSON details @@ -194,12 +245,13 @@ for (let i = 0; i < fsTests.length; i++) { if (document.getElementById(`fsTests${i}`).checked) { try{ - await fsTests[i](); + await executeTest(fsTests[i]); // make this test's container green $(`#fsTests-container-${i}`).css('background-color', '#85e085'); } catch (e) { - console.error('FS Test failed:', fsTests[i].name, e); + const testInfo = getTestInfo(fsTests[i]); + console.error('FS Test failed:', testInfo.name, e); // make this test's container red $(`#fsTests-container-${i}`).css('background-color', '#ffbfbf'); // message - show full error information including JSON details @@ -215,12 +267,13 @@ for (let i = 0; i < kvTests.length; i++) { if (document.getElementById(`kvTests${i}`).checked) { try{ - await kvTests[i](); + await executeTest(kvTests[i]); // make this test's container green $(`#kvTests-container-${i}`).css('background-color', '#85e085'); } catch (e) { - console.error('KV Test failed:', kvTests[i].name, e); + const testInfo = getTestInfo(kvTests[i]); + console.error('KV Test failed:', testInfo.name, e); // make this test's container red $(`#kvTests-container-${i}`).css('background-color', '#ff8484'); // message - show full error information including JSON details @@ -236,12 +289,13 @@ for (let i = 0; i < aiTests.length; i++) { if (document.getElementById(`aiTests${i}`).checked) { try{ - await aiTests[i](); + await executeTest(aiTests[i]); // make this test's container green $(`#aiTests-container-${i}`).css('background-color', '#85e085'); } catch (e) { - console.error('AI Test failed:', aiTests[i].name, e); + const testInfo = getTestInfo(aiTests[i]); + console.error('AI Test failed:', testInfo.name, e); // make this test's container red $(`#aiTests-container-${i}`).css('background-color', '#ff8484'); // message - show full error information including JSON details