UNPKG

milodb

Version:

A simple mini database with optional encryption to store key-value pairs

159 lines (136 loc) 6.03 kB
const assert = require('assert'); const fs = require('fs').promises; const path = require('path'); const MinoDB = require('../src/index'); // Helper function to clean up test database async function cleanup() { try { await fs.unlink(path.join(__dirname, '..', 'db', 'database.json')); } catch (err) { if (err.code !== 'ENOENT') throw err; } } // Helper function to delay execution const delay = ms => new Promise(resolve => setTimeout(resolve, ms)); async function runTests() { console.log('Starting tests...\n'); // Test 1: Basic Operations console.log('Test 1: Basic Operations'); const db = new MinoDB('test-password', true); // Test set and get await db.set('test-key', 'test-value'); const value = await db.get('test-key'); assert.strictEqual(value, 'test-value', 'Basic set/get failed'); console.log('✓ Basic set/get passed'); // Test delete await db.delete('test-key'); const deletedValue = await db.get('test-key'); assert.strictEqual(deletedValue, null, 'Delete operation failed'); console.log('✓ Delete operation passed'); // Test 2: TTL Support console.log('\nTest 2: TTL Support'); await db.set('temp-key', 'temp-value', 1000); // 1 second TTL const tempValue = await db.get('temp-key'); assert.strictEqual(tempValue, 'temp-value', 'TTL set failed'); console.log('✓ TTL set passed'); await delay(1100); // Wait for TTL to expire const expiredValue = await db.get('temp-key'); assert.strictEqual(expiredValue, null, 'TTL expiration failed'); console.log('✓ TTL expiration passed'); // Test 3: Batch Operations console.log('\nTest 3: Batch Operations'); const batchResults = await db.batch([ { type: 'set', key: 'batch1', value: 'value1' }, { type: 'set', key: 'batch2', value: 'value2', ttl: 1000 }, { type: 'delete', key: 'batch1' } ]); assert.strictEqual(batchResults.length, 3, 'Batch operation count mismatch'); assert.strictEqual(batchResults[0].success, true, 'Batch set failed'); assert.strictEqual(batchResults[1].success, true, 'Batch set with TTL failed'); assert.strictEqual(batchResults[2].success, true, 'Batch delete failed'); console.log('✓ Batch operations passed'); // Test 4: Search Operations console.log('\nTest 4: Search Operations'); await db.set('search1', 'hello world'); await db.set('search2', 'hello universe'); await db.set('search3', 'different text'); // Test basic search const searchResults = await db.search('hello'); assert.strictEqual(Object.keys(searchResults).length, 2, 'Basic search failed'); console.log('✓ Basic search passed'); // Test regex search const regexResults = await db.search('hello', { regex: true }); assert.strictEqual(Object.keys(regexResults).length, 2, 'Regex search failed'); console.log('✓ Regex search passed'); // Test case-sensitive search const caseResults = await db.search('HELLO', { caseSensitive: true }); assert.strictEqual(Object.keys(caseResults).length, 0, 'Case-sensitive search failed'); console.log('✓ Case-sensitive search passed'); // Test 5: Database Statistics console.log('\nTest 5: Database Statistics'); const stats = await db.stats(); assert.strictEqual(typeof stats.total, 'number', 'Stats total type mismatch'); assert.strictEqual(typeof stats.expired, 'number', 'Stats expired type mismatch'); assert.strictEqual(typeof stats.active, 'number', 'Stats active type mismatch'); console.log('✓ Database statistics passed'); // Test 6: Error Handling console.log('\nTest 6: Error Handling'); // Test invalid key type try { await db.set(123, 'value'); assert.fail('Should have thrown error for invalid key type'); } catch (err) { assert.strictEqual(err.message, 'Key must be a string', 'Invalid key type error message mismatch'); } console.log('✓ Invalid key type handling passed'); // Test empty key try { await db.set('', 'value'); assert.fail('Should have thrown error for empty key'); } catch (err) { assert.strictEqual(err.message, 'Key cannot be empty', 'Empty key error message mismatch'); } console.log('✓ Empty key handling passed'); // Test undefined value try { await db.set('key', undefined); assert.fail('Should have thrown error for undefined value'); } catch (err) { assert.strictEqual(err.message, 'Value cannot be undefined', 'Undefined value error message mismatch'); } console.log('✓ Undefined value handling passed'); // Test 7: Encryption console.log('\nTest 7: Encryption'); const encDbPath = path.join(__dirname, '..', 'db', 'encryption-test.json'); // Clean up before test try { await fs.unlink(encDbPath); } catch (e) {} const EncryptedMinoDB = require('../src/index'); const encryptedDb = new EncryptedMinoDB('encryption-password', true); encryptedDb.dbPath = encDbPath; await encryptedDb.set('encrypted-key', 'sensitive-data'); // Try to read with wrong password const wrongDb = new EncryptedMinoDB('wrong-password', true); wrongDb.dbPath = encDbPath; try { await wrongDb.get('encrypted-key'); assert.fail('Should have thrown error for wrong password'); } catch (err) { assert( err.message.includes('decrypt') || err.message.includes('unable to authenticate') || err.message.includes('Unsupported state'), 'Wrong password error message mismatch' ); } console.log('✓ Encryption handling passed'); // Clean up after test try { await fs.unlink(encDbPath); } catch (e) {} // Cleanup await cleanup(); console.log('\nAll tests passed successfully! 🎉'); } // Run the tests runTests().catch(err => { console.error('Test failed:', err); process.exit(1); });