From 9305d806b019086b8c9aa19d6544deeb3db007c6 Mon Sep 17 00:00:00 2001 From: Administrator Date: Sat, 21 Mar 2026 15:11:56 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=85=20test:=20add=204=20new=20tests=20for?= =?UTF-8?q?=20untested=20code=20paths?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Concurrent saves preserve both hosters and globalSettings (write queue) - Backup recovery when main config file is corrupted (.bak fallback) - encrypt() rejects empty/null/undefined password - decrypt() rejects empty/null password All 63 tests passing. Co-Authored-By: Claude Opus 4.6 (1M context) --- tests/backup-crypto.test.js | 12 ++++++++++++ tests/config-store.test.js | 23 +++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/tests/backup-crypto.test.js b/tests/backup-crypto.test.js index 605554c..597d7cb 100644 --- a/tests/backup-crypto.test.js +++ b/tests/backup-crypto.test.js @@ -49,6 +49,18 @@ describe('backup-crypto', () => { assert.deepStrictEqual(result, sampleConfig); }); + it('encrypt rejects empty password', () => { + assert.throws(() => encrypt(sampleConfig, ''), /Passwort/); + assert.throws(() => encrypt(sampleConfig, null), /Passwort/); + assert.throws(() => encrypt(sampleConfig, undefined), /Passwort/); + }); + + it('decrypt rejects empty password', () => { + const buf = encrypt(sampleConfig, 'valid'); + assert.throws(() => decrypt(buf, ''), /Passwort/); + assert.throws(() => decrypt(buf, null), /Passwort/); + }); + it('each encryption produces different output (random salt/iv)', () => { const a = encrypt(sampleConfig, 'same'); const b = encrypt(sampleConfig, 'same'); diff --git a/tests/config-store.test.js b/tests/config-store.test.js index f62e24a..82e4146 100644 --- a/tests/config-store.test.js +++ b/tests/config-store.test.js @@ -131,4 +131,27 @@ describe('ConfigStore', () => { assert.equal(config.globalSettings.scaleParallelUploads, false); assert.equal(config.globalSettings.logFilePath, ''); }); + + it('concurrent saves preserve both sections', async () => { + const save1 = store.save({ hosters: { 'doodstream.com': [{ id: 'c1', enabled: true, authType: 'api', apiKey: 'concurrent-key' }] } }); + const save2 = store.save({ globalSettings: { alwaysOnTop: true } }); + await Promise.all([save1, save2]); + const config = store.load(); + assert.equal(config.hosters['doodstream.com'][0].apiKey, 'concurrent-key'); + assert.equal(config.globalSettings.alwaysOnTop, true); + }); + + it('backup recovery when main file is corrupted', () => { + // Write valid config first + fs.writeFileSync(store.filePath, JSON.stringify({ + hosters: { 'doodstream.com': [{ id: 'bak-1', authType: 'api', apiKey: 'from-backup' }] }, + hosterSettings: {}, globalSettings: {}, history: [] + }), 'utf-8'); + // Copy to backup + fs.copyFileSync(store.filePath, store.filePath + '.bak'); + // Corrupt main file + fs.writeFileSync(store.filePath, 'CORRUPTED!!!', 'utf-8'); + const config = store.load(); + assert.equal(config.hosters['doodstream.com'][0].apiKey, 'from-backup'); + }); });