test: add 3 tests for no-match rewrite, CR-only grepFile, and null write (R99)

- replaceInFile returns true even when pattern doesn't match (silent rewrite)
- grepFile treats CR-only (\r) file as single line (splits on \n only)
- writeSessionContent(null) returns false (TypeError caught by try/catch)
This commit is contained in:
Affaan Mustafa
2026-02-13 15:41:15 -08:00
parent 274cca025e
commit 78ad952433
2 changed files with 62 additions and 0 deletions

View File

@@ -1593,6 +1593,19 @@ src/main.ts
);
})) passed++; else failed++;
// ── Round 99: writeSessionContent with null path returns false (error caught) ──
console.log('\nRound 99: writeSessionContent (null path — error handling):');
if (test('writeSessionContent(null, content) returns false (TypeError caught by try/catch)', () => {
// session-manager.js lines 372-378: writeSessionContent wraps fs.writeFileSync
// in a try/catch. When sessionPath is null, fs.writeFileSync throws TypeError:
// 'The "path" argument must be of type string or Buffer or URL. Received null'
// The catch block catches this and returns false (does not propagate).
const result = sessionManager.writeSessionContent(null, 'some content');
assert.strictEqual(result, false,
'null path should be caught by try/catch and return false');
})) passed++; else failed++;
// Summary
console.log(`\nResults: Passed: ${passed}, Failed: ${failed}`);
process.exit(failed > 0 ? 1 : 0);

View File

@@ -1373,6 +1373,55 @@ function runTests() {
}
})) passed++; else failed++;
// ── Round 99: replaceInFile returns true even when pattern not found ──
console.log('\nRound 99: replaceInFile (no-match still returns true):');
if (test('replaceInFile returns true and rewrites file even when search does not match', () => {
// utils.js lines 405-417: replaceInFile reads content, calls content.replace(search, replace),
// and writes back the result. When the search pattern doesn't match anything,
// String.replace() returns the original string unchanged, but the function still
// writes it back to disk (changing mtime) and returns true. This means callers
// cannot distinguish "replacement made" from "no match found."
const tmpDir = fs.mkdtempSync(path.join(utils.getTempDir(), 'r99-no-match-'));
const testFile = path.join(tmpDir, 'test.txt');
try {
fs.writeFileSync(testFile, 'hello world');
const result = utils.replaceInFile(testFile, 'NONEXISTENT_PATTERN', 'replacement');
assert.strictEqual(result, true,
'replaceInFile returns true even when pattern is not found (no match guard)');
const content = fs.readFileSync(testFile, 'utf8');
assert.strictEqual(content, 'hello world',
'Content should be unchanged since pattern did not match');
} finally {
fs.rmSync(tmpDir, { recursive: true, force: true });
}
})) passed++; else failed++;
// ── Round 99: grepFile with CR-only line endings (\r without \n) ──
console.log('\nRound 99: grepFile (CR-only line endings — classic Mac format):');
if (test('grepFile treats CR-only file as a single line (splits on \\n only)', () => {
// utils.js line 474: `content.split('\\n')` splits only on \\n (LF).
// A file using \\r (CR) line endings (classic Mac format) has no \\n characters,
// so split('\\n') returns the entire content as a single element array.
// This means grepFile reports everything on "line 1" regardless of \\r positions.
const tmpDir = fs.mkdtempSync(path.join(utils.getTempDir(), 'r99-cr-only-'));
const testFile = path.join(tmpDir, 'cr-only.txt');
try {
// Write file with CR-only line endings (no LF)
fs.writeFileSync(testFile, 'alpha\rbeta\rgamma');
const matches = utils.grepFile(testFile, 'beta');
assert.strictEqual(matches.length, 1,
'Should find exactly 1 match (entire file is one "line")');
assert.strictEqual(matches[0].lineNumber, 1,
'Match should be reported on line 1 (no \\n splitting occurred)');
assert.ok(matches[0].content.includes('\r'),
'Content should contain \\r characters (unsplit)');
} finally {
fs.rmSync(tmpDir, { recursive: true, force: true });
}
})) passed++; else failed++;
// Summary
console.log('\n=== Test Results ===');
console.log(`Passed: ${passed}`);