chore: bump version to 2.80.27 and update core features
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* Unit tests for the centralized path resolver.
|
||||
*/
|
||||
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import {
|
||||
expandTilde,
|
||||
resolvePathInput,
|
||||
isInside,
|
||||
} from '../src/lib/paths';
|
||||
|
||||
describe('expandTilde', () => {
|
||||
test('expands "~" to home', () => {
|
||||
expect(expandTilde('~')).toBe(os.homedir());
|
||||
});
|
||||
|
||||
test('expands "~/foo" to home/foo', () => {
|
||||
expect(expandTilde('~/foo')).toBe(path.join(os.homedir(), 'foo'));
|
||||
});
|
||||
|
||||
test('leaves absolute paths untouched', () => {
|
||||
expect(expandTilde('/tmp/x')).toBe('/tmp/x');
|
||||
});
|
||||
|
||||
test('returns empty for blank input', () => {
|
||||
expect(expandTilde('')).toBe('');
|
||||
expect(expandTilde(' ')).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolvePathInput', () => {
|
||||
test('accepts absolute paths', () => {
|
||||
expect(resolvePathInput('/tmp/abc')).toBe(path.normalize('/tmp/abc'));
|
||||
});
|
||||
|
||||
test('accepts ~/-prefixed paths after expansion', () => {
|
||||
expect(resolvePathInput('~/notes')).toBe(path.normalize(path.join(os.homedir(), 'notes')));
|
||||
});
|
||||
|
||||
test('rejects relative paths to prevent surprises', () => {
|
||||
expect(resolvePathInput('relative/dir')).toBe('');
|
||||
expect(resolvePathInput('./local')).toBe('');
|
||||
});
|
||||
|
||||
test('returns empty on blank / undefined', () => {
|
||||
expect(resolvePathInput('')).toBe('');
|
||||
expect(resolvePathInput(undefined as any)).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('isInside', () => {
|
||||
test('a path is inside itself', () => {
|
||||
expect(isInside('/tmp/a', '/tmp/a')).toBe(true);
|
||||
});
|
||||
|
||||
test('detects direct descendants', () => {
|
||||
expect(isInside('/tmp/a', '/tmp/a/b')).toBe(true);
|
||||
});
|
||||
|
||||
test('detects deep descendants', () => {
|
||||
expect(isInside('/tmp/a', '/tmp/a/b/c/d.txt')).toBe(true);
|
||||
});
|
||||
|
||||
test('rejects siblings', () => {
|
||||
expect(isInside('/tmp/a', '/tmp/b')).toBe(false);
|
||||
});
|
||||
|
||||
test('rejects path-traversal escapes', () => {
|
||||
// Even though string-prefix would say "/tmp/a/../b" starts with "/tmp/a/",
|
||||
// path.resolve normalizes the dotdot back to the parent → not inside.
|
||||
expect(isInside('/tmp/a', '/tmp/a/../b')).toBe(false);
|
||||
});
|
||||
|
||||
test('rejects siblings whose name shares a prefix', () => {
|
||||
// "/tmp/agents-evil" must not be considered inside "/tmp/agents".
|
||||
expect(isInside('/tmp/agents', '/tmp/agents-evil')).toBe(false);
|
||||
});
|
||||
|
||||
test('returns false on empty inputs', () => {
|
||||
expect(isInside('', '/tmp/a')).toBe(false);
|
||||
expect(isInside('/tmp/a', '')).toBe(false);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user