From 6a0b231d340af0402b43168b3d159b43a191419b Mon Sep 17 00:00:00 2001 From: Affaan Mustafa Date: Fri, 13 Feb 2026 18:11:58 -0800 Subject: [PATCH] test: add Round 116 edge-case tests for replaceInFile null coercion, loadAliases extra fields, and ensureDir null path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - replaceInFile: null/undefined replacement coerced to string "null"/"undefined" by JS String.replace ToString - loadAliases: extra unknown JSON fields silently preserved through load/save round-trip (loose validation) - ensureDir: null/undefined path throws wrapped Error (ERR_INVALID_ARG_TYPE → re-thrown) Total tests: 908 --- tests/lib/session-aliases.test.js | 46 ++++++++++++++++++++++ tests/lib/utils.test.js | 64 +++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) diff --git a/tests/lib/session-aliases.test.js b/tests/lib/session-aliases.test.js index c5b0ccbb..e9b52bfc 100644 --- a/tests/lib/session-aliases.test.js +++ b/tests/lib/session-aliases.test.js @@ -1517,6 +1517,52 @@ function runTests() { assert.strictEqual(cleared.title, null, 'null clears title'); })) passed++; else failed++; + // ── Round 116: loadAliases with extra unknown fields — silently preserved ── + console.log('\nRound 116: loadAliases (extra unknown JSON fields — preserved by loose validation):'); + if (test('loadAliases preserves extra unknown fields because only aliases key is validated', () => { + resetAliases(); + + // Manually write an aliases file with extra fields + const aliasesPath = aliases.getAliasesPath(); + const customData = { + version: '1.0', + aliases: { + 'test-session': { + sessionPath: '/path/to/session', + createdAt: '2026-01-01T00:00:00.000Z', + updatedAt: '2026-01-01T00:00:00.000Z', + title: 'Test' + } + }, + metadata: { + totalCount: 1, + lastUpdated: '2026-01-01T00:00:00.000Z' + }, + customField: 'extra data', + debugInfo: { level: 3, verbose: true }, + tags: ['important', 'test'] + }; + fs.writeFileSync(aliasesPath, JSON.stringify(customData, null, 2), 'utf8'); + + // loadAliases only validates data.aliases — extra fields pass through + const loaded = aliases.loadAliases(); + assert.ok(loaded.aliases['test-session'], 'Should load the valid alias'); + assert.strictEqual(loaded.aliases['test-session'].title, 'Test'); + assert.strictEqual(loaded.customField, 'extra data', + 'Extra string field should be preserved'); + assert.deepStrictEqual(loaded.debugInfo, { level: 3, verbose: true }, + 'Extra object field should be preserved'); + assert.deepStrictEqual(loaded.tags, ['important', 'test'], + 'Extra array field should be preserved'); + + // After saving, extra fields survive a round-trip (saveAliases only updates metadata) + aliases.setAlias('new-alias', '/path/to/new'); + const reloaded = aliases.loadAliases(); + assert.ok(reloaded.aliases['new-alias'], 'New alias should be saved'); + assert.strictEqual(reloaded.customField, 'extra data', + 'Extra field should survive save/load round-trip'); + })) passed++; else failed++; + // Summary console.log(`\nResults: Passed: ${passed}, Failed: ${failed}`); process.exit(failed > 0 ? 1 : 0); diff --git a/tests/lib/utils.test.js b/tests/lib/utils.test.js index d9ecfeb2..cd03462f 100644 --- a/tests/lib/utils.test.js +++ b/tests/lib/utils.test.js @@ -1833,6 +1833,70 @@ function runTests() { } })) passed++; else failed++; + // ── Round 116: replaceInFile with null/undefined replacement — JS coerces to string ── + console.log('\nRound 116: replaceInFile (null/undefined replacement — JS coerces to string "null"/"undefined"):'); + if (test('replaceInFile with null replacement coerces to string "null" via String.replace ToString', () => { + const tmpDir = fs.mkdtempSync(path.join(utils.getTempDir(), 'r116-null-replace-')); + const testFile = path.join(tmpDir, 'test.txt'); + try { + // null replacement → String.replace coerces null to "null" + fs.writeFileSync(testFile, 'hello world'); + const result = utils.replaceInFile(testFile, 'world', null); + assert.strictEqual(result, true, 'Should succeed'); + const content = utils.readFile(testFile); + assert.strictEqual(content, 'hello null', + 'null replacement is coerced to string "null" by String.replace'); + + // undefined replacement → coerced to "undefined" + fs.writeFileSync(testFile, 'hello world'); + utils.replaceInFile(testFile, 'world', undefined); + const undefinedContent = utils.readFile(testFile); + assert.strictEqual(undefinedContent, 'hello undefined', + 'undefined replacement is coerced to string "undefined" by String.replace'); + + // Contrast: empty string replacement works as expected + fs.writeFileSync(testFile, 'hello world'); + utils.replaceInFile(testFile, 'world', ''); + const emptyContent = utils.readFile(testFile); + assert.strictEqual(emptyContent, 'hello ', + 'Empty string replacement correctly removes matched text'); + + // options.all with null replacement + fs.writeFileSync(testFile, 'foo bar foo baz foo'); + utils.replaceInFile(testFile, 'foo', null, { all: true }); + const allContent = utils.readFile(testFile); + assert.strictEqual(allContent, 'null bar null baz null', + 'replaceAll also coerces null to "null" for every occurrence'); + } finally { + fs.rmSync(tmpDir, { recursive: true, force: true }); + } + })) passed++; else failed++; + + // ── Round 116: ensureDir with null path — throws wrapped TypeError ── + console.log('\nRound 116: ensureDir (null path — fs.existsSync(null) throws TypeError):'); + if (test('ensureDir with null path throws wrapped Error from TypeError (ERR_INVALID_ARG_TYPE)', () => { + // fs.existsSync(null) throws TypeError in modern Node.js + // Caught by ensureDir catch block, err.code !== 'EEXIST' → re-thrown as wrapped Error + assert.throws( + () => utils.ensureDir(null), + (err) => { + // Should be a wrapped Error (not raw TypeError) + assert.ok(err instanceof Error, 'Should throw an Error'); + assert.ok(err.message.includes('Failed to create directory'), + 'Error message should include "Failed to create directory"'); + return true; + }, + 'ensureDir(null) should throw wrapped Error' + ); + + // undefined path — same behavior + assert.throws( + () => utils.ensureDir(undefined), + (err) => err instanceof Error && err.message.includes('Failed to create directory'), + 'ensureDir(undefined) should also throw wrapped Error' + ); + })) passed++; else failed++; + // Summary console.log('\n=== Test Results ==='); console.log(`Passed: ${passed}`);