From df2d3a6d543562ecf46e7066636fd224f9955a72 Mon Sep 17 00:00:00 2001 From: Affaan Mustafa Date: Fri, 13 Feb 2026 18:21:39 -0800 Subject: [PATCH] test: add Round 119 tests for appendFile type safety, renameAlias reserved names, and context extraction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - appendFile: null/undefined/number content throws TypeError (no try/catch like writeFile) - renameAlias: reserved names rejected for newAlias (parallel check to setAlias, case-insensitive) - parseSessionMetadata: "Context to Load" code block extraction — missing close, nested blocks, empty Total tests: 917 --- tests/lib/session-aliases.test.js | 30 ++++++++++++++++ tests/lib/session-manager.test.js | 60 +++++++++++++++++++++++++++++++ tests/lib/utils.test.js | 43 ++++++++++++++++++++++ 3 files changed, 133 insertions(+) diff --git a/tests/lib/session-aliases.test.js b/tests/lib/session-aliases.test.js index 97e6d5cd..c1c7c283 100644 --- a/tests/lib/session-aliases.test.js +++ b/tests/lib/session-aliases.test.js @@ -1617,6 +1617,36 @@ function runTests() { 'Non-reserved name should succeed'); })) passed++; else failed++; + // ── Round 119: renameAlias with reserved newAlias name — parallel reserved check ── + console.log('\nRound 119: renameAlias (reserved newAlias name — parallel check to setAlias):'); + if (test('renameAlias rejects reserved names for newAlias (same reserved list as setAlias)', () => { + resetAliases(); + aliases.setAlias('my-alias', '/path/to/session'); + + // Rename to reserved name 'list' — should fail + const listResult = aliases.renameAlias('my-alias', 'list'); + assert.strictEqual(listResult.success, false, '"list" should be rejected'); + assert.ok(listResult.error.includes('reserved'), + 'Error should mention "reserved"'); + + // Rename to reserved name 'help' (uppercase) — should fail + const helpResult = aliases.renameAlias('my-alias', 'Help'); + assert.strictEqual(helpResult.success, false, '"Help" should be rejected'); + + // Rename to reserved name 'delete' — should fail + const deleteResult = aliases.renameAlias('my-alias', 'DELETE'); + assert.strictEqual(deleteResult.success, false, '"DELETE" should be rejected'); + + // Verify alias is unchanged + const resolved = aliases.resolveAlias('my-alias'); + assert.ok(resolved, 'Original alias should still exist after failed renames'); + assert.strictEqual(resolved.sessionPath, '/path/to/session'); + + // Valid rename works + const validResult = aliases.renameAlias('my-alias', 'new-valid-name'); + assert.strictEqual(validResult.success, true, 'Non-reserved name should succeed'); + })) passed++; else failed++; + // Summary console.log(`\nResults: Passed: ${passed}, Failed: ${failed}`); process.exit(failed > 0 ? 1 : 0); diff --git a/tests/lib/session-manager.test.js b/tests/lib/session-manager.test.js index 63a556a9..4d1617d7 100644 --- a/tests/lib/session-manager.test.js +++ b/tests/lib/session-manager.test.js @@ -2186,6 +2186,66 @@ file.ts assert.strictEqual(hexLower.shortId, 'a1b2c3d4'); })) passed++; else failed++; + // ── Round 119: parseSessionMetadata "Context to Load" code block extraction ── + console.log('\nRound 119: parseSessionMetadata ("Context to Load" — code block extraction edge cases):'); + if (test('parseSessionMetadata extracts Context to Load from code block, handles missing/nested blocks', () => { + // Valid context extraction + const validContent = [ + '# Session\n\n', + '### Context to Load\n', + '```\n', + 'file1.js\n', + 'file2.ts\n', + '```\n' + ].join(''); + const validMeta = sessionManager.parseSessionMetadata(validContent); + assert.strictEqual(validMeta.context, 'file1.js\nfile2.ts', + 'Should extract content between ``` markers and trim'); + + // Missing closing backticks — regex doesn't match, context stays empty + const noClose = [ + '# Session\n\n', + '### Context to Load\n', + '```\n', + 'file1.js\n', + 'file2.ts\n' + ].join(''); + const noCloseMeta = sessionManager.parseSessionMetadata(noClose); + assert.strictEqual(noCloseMeta.context, '', + 'Missing closing ``` should result in empty context (regex no match)'); + + // No code block after header — just plain text + const noBlock = [ + '# Session\n\n', + '### Context to Load\n', + 'file1.js\n', + 'file2.ts\n' + ].join(''); + const noBlockMeta = sessionManager.parseSessionMetadata(noBlock); + assert.strictEqual(noBlockMeta.context, '', + 'Plain text without ``` should not be captured as context'); + + // Nested code block — lazy [\s\S]*? stops at first ``` + const nested = [ + '# Session\n\n', + '### Context to Load\n', + '```\n', + 'first block\n', + '```\n', + 'second block\n', + '```\n' + ].join(''); + const nestedMeta = sessionManager.parseSessionMetadata(nested); + assert.strictEqual(nestedMeta.context, 'first block', + 'Lazy quantifier should stop at first closing ``` (not greedy)'); + + // Empty code block + const emptyBlock = '# Session\n\n### Context to Load\n```\n```\n'; + const emptyMeta = sessionManager.parseSessionMetadata(emptyBlock); + assert.strictEqual(emptyMeta.context, '', + 'Empty code block should result in empty context (trim of empty)'); + })) 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 d2c2db43..ecb9e35b 100644 --- a/tests/lib/utils.test.js +++ b/tests/lib/utils.test.js @@ -1974,6 +1974,49 @@ function runTests() { } })) passed++; else failed++; + // ── Round 119: appendFile with non-string content — TypeError propagates (no try/catch) ── + console.log('\nRound 119: appendFile (non-string content — TypeError propagates like writeFile):'); + if (test('appendFile with null/number content throws TypeError (no try/catch wrapper)', () => { + const tmpDir = fs.mkdtempSync(path.join(utils.getTempDir(), 'r119-appendfile-type-')); + const testFile = path.join(tmpDir, 'test.txt'); + try { + // Create file with initial content + fs.writeFileSync(testFile, 'initial'); + + // null content → TypeError from fs.appendFileSync + assert.throws( + () => utils.appendFile(testFile, null), + (err) => err instanceof TypeError, + 'appendFile(path, null) should throw TypeError' + ); + + // undefined content → TypeError + assert.throws( + () => utils.appendFile(testFile, undefined), + (err) => err instanceof TypeError, + 'appendFile(path, undefined) should throw TypeError' + ); + + // number content → TypeError + assert.throws( + () => utils.appendFile(testFile, 42), + (err) => err instanceof TypeError, + 'appendFile(path, 42) should throw TypeError' + ); + + // Verify original content is unchanged after failed appends + assert.strictEqual(utils.readFile(testFile), 'initial', + 'File content should be unchanged after failed appends'); + + // Contrast: string append works + utils.appendFile(testFile, ' appended'); + assert.strictEqual(utils.readFile(testFile), 'initial appended', + 'String append should work correctly'); + } finally { + fs.rmSync(tmpDir, { recursive: true, force: true }); + } + })) passed++; else failed++; + // Summary console.log('\n=== Test Results ==='); console.log(`Passed: ${passed}`);