mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-03-30 13:43:26 +08:00
test: add Round 104 edge-case tests (detectFromLockFile null, resolveSessionAlias traversal, whitespace notes)
- detectFromLockFile(null): throws TypeError — no input validation before
path.join (package-manager.js:95)
- resolveSessionAlias('../etc/passwd'): returns path-traversal input unchanged
when alias lookup fails, documenting the passthrough behavior
- parseSessionMetadata with whitespace-only notes: trim() → "" → hasNotes=false,
whitespace-only notes treated as absent
Total tests: 872 (all passing)
This commit is contained in:
@@ -1455,6 +1455,20 @@ function runTests() {
|
|||||||
}
|
}
|
||||||
})) passed++; else failed++;
|
})) passed++; else failed++;
|
||||||
|
|
||||||
|
// ── Round 104: detectFromLockFile with null projectDir (no input validation) ──
|
||||||
|
console.log('\nRound 104: detectFromLockFile (null projectDir — throws TypeError):');
|
||||||
|
if (test('detectFromLockFile(null) throws TypeError (path.join rejects null)', () => {
|
||||||
|
// package-manager.js line 95: `path.join(projectDir, pm.lockFile)` — there is no
|
||||||
|
// guard checking that projectDir is a string before passing it to path.join().
|
||||||
|
// When projectDir is null, path.join(null, 'package-lock.json') throws a TypeError
|
||||||
|
// because path.join only accepts string arguments.
|
||||||
|
assert.throws(
|
||||||
|
() => pm.detectFromLockFile(null),
|
||||||
|
{ name: 'TypeError' },
|
||||||
|
'path.join(null, ...) should throw TypeError (no input validation in detectFromLockFile)'
|
||||||
|
);
|
||||||
|
})) passed++; else failed++;
|
||||||
|
|
||||||
// Summary
|
// Summary
|
||||||
console.log('\n=== Test Results ===');
|
console.log('\n=== Test Results ===');
|
||||||
console.log(`Passed: ${passed}`);
|
console.log(`Passed: ${passed}`);
|
||||||
|
|||||||
@@ -1355,6 +1355,26 @@ function runTests() {
|
|||||||
'Object.keys of array returns numeric string indices, not named alias keys');
|
'Object.keys of array returns numeric string indices, not named alias keys');
|
||||||
})) passed++; else failed++;
|
})) passed++; else failed++;
|
||||||
|
|
||||||
|
// ── Round 104: resolveSessionAlias with path-traversal input (passthrough without validation) ──
|
||||||
|
console.log('\nRound 104: resolveSessionAlias (path-traversal input — returned unchanged):');
|
||||||
|
if (test('resolveSessionAlias returns path-traversal input as-is when alias lookup fails', () => {
|
||||||
|
// session-aliases.js lines 365-374: resolveSessionAlias first tries resolveAlias(),
|
||||||
|
// which rejects '../etc/passwd' because the regex /^[a-zA-Z0-9_-]+$/ fails on dots
|
||||||
|
// and slashes (returns null). Then the function falls through to line 373:
|
||||||
|
// `return aliasOrId` — returning the potentially dangerous input unchanged.
|
||||||
|
// Callers that blindly use this return value could be at risk.
|
||||||
|
resetAliases();
|
||||||
|
const traversal = '../etc/passwd';
|
||||||
|
const result = aliases.resolveSessionAlias(traversal);
|
||||||
|
assert.strictEqual(result, traversal,
|
||||||
|
'Path-traversal input should be returned as-is (resolveAlias rejects it, fallback returns input)');
|
||||||
|
// Also test with another invalid alias pattern
|
||||||
|
const dotSlash = './../../secrets';
|
||||||
|
const result2 = aliases.resolveSessionAlias(dotSlash);
|
||||||
|
assert.strictEqual(result2, dotSlash,
|
||||||
|
'Another path-traversal pattern also returned unchanged');
|
||||||
|
})) passed++; else failed++;
|
||||||
|
|
||||||
// Summary
|
// Summary
|
||||||
console.log(`\nResults: Passed: ${passed}, Failed: ${failed}`);
|
console.log(`\nResults: Passed: ${passed}, Failed: ${failed}`);
|
||||||
process.exit(failed > 0 ? 1 : 0);
|
process.exit(failed > 0 ? 1 : 0);
|
||||||
|
|||||||
@@ -1689,6 +1689,34 @@ src/main.ts
|
|||||||
'Second unchecked item');
|
'Second unchecked item');
|
||||||
})) passed++; else failed++;
|
})) passed++; else failed++;
|
||||||
|
|
||||||
|
// ── Round 104: parseSessionMetadata with whitespace-only notes section ──
|
||||||
|
console.log('\nRound 104: parseSessionMetadata (whitespace-only notes — trim reduces to empty):');
|
||||||
|
if (test('parseSessionMetadata treats whitespace-only notes as absent (trim → empty string → falsy)', () => {
|
||||||
|
// session-manager.js line 139: `metadata.notes = notesSection[1].trim()` — when the
|
||||||
|
// Notes section heading exists but only contains whitespace/newlines, trim() returns "".
|
||||||
|
// Then getSessionStats line 178: `hasNotes: !!metadata.notes` — `!!""` is `false`.
|
||||||
|
// So a notes section with only whitespace is treated as "no notes."
|
||||||
|
const content = `# Session
|
||||||
|
|
||||||
|
### Notes for Next Session
|
||||||
|
\t
|
||||||
|
|
||||||
|
### Context to Load
|
||||||
|
\`\`\`
|
||||||
|
file.ts
|
||||||
|
\`\`\`
|
||||||
|
`;
|
||||||
|
const meta = sessionManager.parseSessionMetadata(content);
|
||||||
|
assert.strictEqual(meta.notes, '',
|
||||||
|
'Whitespace-only notes should trim to empty string');
|
||||||
|
// Verify getSessionStats reports hasNotes as false
|
||||||
|
const stats = sessionManager.getSessionStats(content);
|
||||||
|
assert.strictEqual(stats.hasNotes, false,
|
||||||
|
'hasNotes should be false because !!"" is false (whitespace-only notes treated as absent)');
|
||||||
|
assert.strictEqual(stats.hasContext, true,
|
||||||
|
'hasContext should be true (context section has actual content)');
|
||||||
|
})) passed++; else failed++;
|
||||||
|
|
||||||
// Summary
|
// Summary
|
||||||
console.log(`\nResults: Passed: ${passed}, Failed: ${failed}`);
|
console.log(`\nResults: Passed: ${passed}, Failed: ${failed}`);
|
||||||
process.exit(failed > 0 ? 1 : 0);
|
process.exit(failed > 0 ? 1 : 0);
|
||||||
|
|||||||
Reference in New Issue
Block a user