mirror of
https://github.com/pacnpal/Roo-Code.git
synced 2025-12-22 21:31:08 -05:00
Add test coverage
This commit is contained in:
97
src/utils/__tests__/cost.test.ts
Normal file
97
src/utils/__tests__/cost.test.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
import { calculateApiCost } from '../cost';
|
||||
import { ModelInfo } from '../../shared/api';
|
||||
|
||||
describe('Cost Utility', () => {
|
||||
describe('calculateApiCost', () => {
|
||||
const mockModelInfo: ModelInfo = {
|
||||
maxTokens: 8192,
|
||||
contextWindow: 200_000,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 3.0, // $3 per million tokens
|
||||
outputPrice: 15.0, // $15 per million tokens
|
||||
cacheWritesPrice: 3.75, // $3.75 per million tokens
|
||||
cacheReadsPrice: 0.3, // $0.30 per million tokens
|
||||
};
|
||||
|
||||
it('should calculate basic input/output costs correctly', () => {
|
||||
const cost = calculateApiCost(mockModelInfo, 1000, 500);
|
||||
|
||||
// Input cost: (3.0 / 1_000_000) * 1000 = 0.003
|
||||
// Output cost: (15.0 / 1_000_000) * 500 = 0.0075
|
||||
// Total: 0.003 + 0.0075 = 0.0105
|
||||
expect(cost).toBe(0.0105);
|
||||
});
|
||||
|
||||
it('should handle cache writes cost', () => {
|
||||
const cost = calculateApiCost(mockModelInfo, 1000, 500, 2000);
|
||||
|
||||
// Input cost: (3.0 / 1_000_000) * 1000 = 0.003
|
||||
// Output cost: (15.0 / 1_000_000) * 500 = 0.0075
|
||||
// Cache writes: (3.75 / 1_000_000) * 2000 = 0.0075
|
||||
// Total: 0.003 + 0.0075 + 0.0075 = 0.018
|
||||
expect(cost).toBeCloseTo(0.018, 6);
|
||||
});
|
||||
|
||||
it('should handle cache reads cost', () => {
|
||||
const cost = calculateApiCost(mockModelInfo, 1000, 500, undefined, 3000);
|
||||
|
||||
// Input cost: (3.0 / 1_000_000) * 1000 = 0.003
|
||||
// Output cost: (15.0 / 1_000_000) * 500 = 0.0075
|
||||
// Cache reads: (0.3 / 1_000_000) * 3000 = 0.0009
|
||||
// Total: 0.003 + 0.0075 + 0.0009 = 0.0114
|
||||
expect(cost).toBe(0.0114);
|
||||
});
|
||||
|
||||
it('should handle all cost components together', () => {
|
||||
const cost = calculateApiCost(mockModelInfo, 1000, 500, 2000, 3000);
|
||||
|
||||
// Input cost: (3.0 / 1_000_000) * 1000 = 0.003
|
||||
// Output cost: (15.0 / 1_000_000) * 500 = 0.0075
|
||||
// Cache writes: (3.75 / 1_000_000) * 2000 = 0.0075
|
||||
// Cache reads: (0.3 / 1_000_000) * 3000 = 0.0009
|
||||
// Total: 0.003 + 0.0075 + 0.0075 + 0.0009 = 0.0189
|
||||
expect(cost).toBe(0.0189);
|
||||
});
|
||||
|
||||
it('should handle missing prices gracefully', () => {
|
||||
const modelWithoutPrices: ModelInfo = {
|
||||
maxTokens: 8192,
|
||||
contextWindow: 200_000,
|
||||
supportsPromptCache: true
|
||||
};
|
||||
|
||||
const cost = calculateApiCost(modelWithoutPrices, 1000, 500, 2000, 3000);
|
||||
expect(cost).toBe(0);
|
||||
});
|
||||
|
||||
it('should handle zero tokens', () => {
|
||||
const cost = calculateApiCost(mockModelInfo, 0, 0, 0, 0);
|
||||
expect(cost).toBe(0);
|
||||
});
|
||||
|
||||
it('should handle undefined cache values', () => {
|
||||
const cost = calculateApiCost(mockModelInfo, 1000, 500);
|
||||
|
||||
// Input cost: (3.0 / 1_000_000) * 1000 = 0.003
|
||||
// Output cost: (15.0 / 1_000_000) * 500 = 0.0075
|
||||
// Total: 0.003 + 0.0075 = 0.0105
|
||||
expect(cost).toBe(0.0105);
|
||||
});
|
||||
|
||||
it('should handle missing cache prices', () => {
|
||||
const modelWithoutCachePrices: ModelInfo = {
|
||||
...mockModelInfo,
|
||||
cacheWritesPrice: undefined,
|
||||
cacheReadsPrice: undefined
|
||||
};
|
||||
|
||||
const cost = calculateApiCost(modelWithoutCachePrices, 1000, 500, 2000, 3000);
|
||||
|
||||
// Should only include input and output costs
|
||||
// Input cost: (3.0 / 1_000_000) * 1000 = 0.003
|
||||
// Output cost: (15.0 / 1_000_000) * 500 = 0.0075
|
||||
// Total: 0.003 + 0.0075 = 0.0105
|
||||
expect(cost).toBe(0.0105);
|
||||
});
|
||||
});
|
||||
});
|
||||
336
src/utils/__tests__/git.test.ts
Normal file
336
src/utils/__tests__/git.test.ts
Normal file
@@ -0,0 +1,336 @@
|
||||
import { jest } from '@jest/globals'
|
||||
import { searchCommits, getCommitInfo, getWorkingState, GitCommit } from '../git'
|
||||
import { ExecException } from 'child_process'
|
||||
|
||||
type ExecFunction = (
|
||||
command: string,
|
||||
options: { cwd?: string },
|
||||
callback: (error: ExecException | null, result?: { stdout: string; stderr: string }) => void
|
||||
) => void
|
||||
|
||||
type PromisifiedExec = (command: string, options?: { cwd?: string }) => Promise<{ stdout: string; stderr: string }>
|
||||
|
||||
// Mock child_process.exec
|
||||
jest.mock('child_process', () => ({
|
||||
exec: jest.fn()
|
||||
}))
|
||||
|
||||
// Mock util.promisify to return our own mock function
|
||||
jest.mock('util', () => ({
|
||||
promisify: jest.fn((fn: ExecFunction): PromisifiedExec => {
|
||||
return async (command: string, options?: { cwd?: string }) => {
|
||||
// Call the original mock to maintain the mock implementation
|
||||
return new Promise((resolve, reject) => {
|
||||
fn(command, options || {}, (error: ExecException | null, result?: { stdout: string; stderr: string }) => {
|
||||
if (error) {
|
||||
reject(error)
|
||||
} else {
|
||||
resolve(result!)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
}))
|
||||
|
||||
// Mock extract-text
|
||||
jest.mock('../../integrations/misc/extract-text', () => ({
|
||||
truncateOutput: jest.fn(text => text)
|
||||
}))
|
||||
|
||||
describe('git utils', () => {
|
||||
// Get the mock with proper typing
|
||||
const { exec } = jest.requireMock('child_process') as { exec: jest.MockedFunction<ExecFunction> }
|
||||
const cwd = '/test/path'
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks()
|
||||
})
|
||||
|
||||
describe('searchCommits', () => {
|
||||
const mockCommitData = [
|
||||
'abc123def456',
|
||||
'abc123',
|
||||
'fix: test commit',
|
||||
'John Doe',
|
||||
'2024-01-06',
|
||||
'def456abc789',
|
||||
'def456',
|
||||
'feat: new feature',
|
||||
'Jane Smith',
|
||||
'2024-01-05'
|
||||
].join('\n')
|
||||
|
||||
it('should return commits when git is installed and repo exists', async () => {
|
||||
// Set up mock responses
|
||||
const responses = new Map([
|
||||
['git --version', { stdout: 'git version 2.39.2', stderr: '' }],
|
||||
['git rev-parse --git-dir', { stdout: '.git', stderr: '' }],
|
||||
['git log -n 10 --format="%H%n%h%n%s%n%an%n%ad" --date=short --grep="test" --regexp-ignore-case', { stdout: mockCommitData, stderr: '' }]
|
||||
])
|
||||
|
||||
exec.mockImplementation((command: string, options: { cwd?: string }, callback: Function) => {
|
||||
// Find matching response
|
||||
for (const [cmd, response] of responses) {
|
||||
if (command === cmd) {
|
||||
callback(null, response)
|
||||
return
|
||||
}
|
||||
}
|
||||
callback(new Error(`Unexpected command: ${command}`))
|
||||
})
|
||||
|
||||
const result = await searchCommits('test', cwd)
|
||||
|
||||
// First verify the result is correct
|
||||
expect(result).toHaveLength(2)
|
||||
expect(result[0]).toEqual({
|
||||
hash: 'abc123def456',
|
||||
shortHash: 'abc123',
|
||||
subject: 'fix: test commit',
|
||||
author: 'John Doe',
|
||||
date: '2024-01-06'
|
||||
})
|
||||
|
||||
// Then verify all commands were called correctly
|
||||
expect(exec).toHaveBeenCalledWith(
|
||||
'git --version',
|
||||
{},
|
||||
expect.any(Function)
|
||||
)
|
||||
expect(exec).toHaveBeenCalledWith(
|
||||
'git rev-parse --git-dir',
|
||||
{ cwd },
|
||||
expect.any(Function)
|
||||
)
|
||||
expect(exec).toHaveBeenCalledWith(
|
||||
'git log -n 10 --format="%H%n%h%n%s%n%an%n%ad" --date=short --grep="test" --regexp-ignore-case',
|
||||
{ cwd },
|
||||
expect.any(Function)
|
||||
)
|
||||
}, 20000)
|
||||
|
||||
it('should return empty array when git is not installed', async () => {
|
||||
exec.mockImplementation((command: string, options: { cwd?: string }, callback: Function) => {
|
||||
if (command === 'git --version') {
|
||||
callback(new Error('git not found'))
|
||||
return
|
||||
}
|
||||
callback(new Error('Unexpected command'))
|
||||
})
|
||||
|
||||
const result = await searchCommits('test', cwd)
|
||||
expect(result).toEqual([])
|
||||
expect(exec).toHaveBeenCalledWith('git --version', {}, expect.any(Function))
|
||||
})
|
||||
|
||||
it('should return empty array when not in a git repository', async () => {
|
||||
const responses = new Map([
|
||||
['git --version', { stdout: 'git version 2.39.2', stderr: '' }],
|
||||
['git rev-parse --git-dir', null] // null indicates error should be called
|
||||
])
|
||||
|
||||
exec.mockImplementation((command: string, options: { cwd?: string }, callback: Function) => {
|
||||
const response = responses.get(command)
|
||||
if (response === null) {
|
||||
callback(new Error('not a git repository'))
|
||||
} else if (response) {
|
||||
callback(null, response)
|
||||
} else {
|
||||
callback(new Error('Unexpected command'))
|
||||
}
|
||||
})
|
||||
|
||||
const result = await searchCommits('test', cwd)
|
||||
expect(result).toEqual([])
|
||||
expect(exec).toHaveBeenCalledWith('git --version', {}, expect.any(Function))
|
||||
expect(exec).toHaveBeenCalledWith('git rev-parse --git-dir', { cwd }, expect.any(Function))
|
||||
})
|
||||
|
||||
it('should handle hash search when grep search returns no results', async () => {
|
||||
const responses = new Map([
|
||||
['git --version', { stdout: 'git version 2.39.2', stderr: '' }],
|
||||
['git rev-parse --git-dir', { stdout: '.git', stderr: '' }],
|
||||
['git log -n 10 --format="%H%n%h%n%s%n%an%n%ad" --date=short --grep="abc123" --regexp-ignore-case', { stdout: '', stderr: '' }],
|
||||
['git log -n 10 --format="%H%n%h%n%s%n%an%n%ad" --date=short --author-date-order abc123', { stdout: mockCommitData, stderr: '' }]
|
||||
])
|
||||
|
||||
exec.mockImplementation((command: string, options: { cwd?: string }, callback: Function) => {
|
||||
for (const [cmd, response] of responses) {
|
||||
if (command === cmd) {
|
||||
callback(null, response)
|
||||
return
|
||||
}
|
||||
}
|
||||
callback(new Error('Unexpected command'))
|
||||
})
|
||||
|
||||
const result = await searchCommits('abc123', cwd)
|
||||
expect(result).toHaveLength(2)
|
||||
expect(result[0]).toEqual({
|
||||
hash: 'abc123def456',
|
||||
shortHash: 'abc123',
|
||||
subject: 'fix: test commit',
|
||||
author: 'John Doe',
|
||||
date: '2024-01-06'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('getCommitInfo', () => {
|
||||
const mockCommitInfo = [
|
||||
'abc123def456',
|
||||
'abc123',
|
||||
'fix: test commit',
|
||||
'John Doe',
|
||||
'2024-01-06',
|
||||
'Detailed description'
|
||||
].join('\n')
|
||||
const mockStats = '1 file changed, 2 insertions(+), 1 deletion(-)'
|
||||
const mockDiff = '@@ -1,1 +1,2 @@\n-old line\n+new line'
|
||||
|
||||
it('should return formatted commit info', async () => {
|
||||
const responses = new Map([
|
||||
['git --version', { stdout: 'git version 2.39.2', stderr: '' }],
|
||||
['git rev-parse --git-dir', { stdout: '.git', stderr: '' }],
|
||||
['git show --format="%H%n%h%n%s%n%an%n%ad%n%b" --no-patch abc123', { stdout: mockCommitInfo, stderr: '' }],
|
||||
['git show --stat --format="" abc123', { stdout: mockStats, stderr: '' }],
|
||||
['git show --format="" abc123', { stdout: mockDiff, stderr: '' }]
|
||||
])
|
||||
|
||||
exec.mockImplementation((command: string, options: { cwd?: string }, callback: Function) => {
|
||||
for (const [cmd, response] of responses) {
|
||||
if (command.startsWith(cmd)) {
|
||||
callback(null, response)
|
||||
return
|
||||
}
|
||||
}
|
||||
callback(new Error('Unexpected command'))
|
||||
})
|
||||
|
||||
const result = await getCommitInfo('abc123', cwd)
|
||||
expect(result).toContain('Commit: abc123')
|
||||
expect(result).toContain('Author: John Doe')
|
||||
expect(result).toContain('Files Changed:')
|
||||
expect(result).toContain('Full Changes:')
|
||||
})
|
||||
|
||||
it('should return error message when git is not installed', async () => {
|
||||
exec.mockImplementation((command: string, options: { cwd?: string }, callback: Function) => {
|
||||
if (command === 'git --version') {
|
||||
callback(new Error('git not found'))
|
||||
return
|
||||
}
|
||||
callback(new Error('Unexpected command'))
|
||||
})
|
||||
|
||||
const result = await getCommitInfo('abc123', cwd)
|
||||
expect(result).toBe('Git is not installed')
|
||||
})
|
||||
|
||||
it('should return error message when not in a git repository', async () => {
|
||||
const responses = new Map([
|
||||
['git --version', { stdout: 'git version 2.39.2', stderr: '' }],
|
||||
['git rev-parse --git-dir', null] // null indicates error should be called
|
||||
])
|
||||
|
||||
exec.mockImplementation((command: string, options: { cwd?: string }, callback: Function) => {
|
||||
const response = responses.get(command)
|
||||
if (response === null) {
|
||||
callback(new Error('not a git repository'))
|
||||
} else if (response) {
|
||||
callback(null, response)
|
||||
} else {
|
||||
callback(new Error('Unexpected command'))
|
||||
}
|
||||
})
|
||||
|
||||
const result = await getCommitInfo('abc123', cwd)
|
||||
expect(result).toBe('Not a git repository')
|
||||
})
|
||||
})
|
||||
|
||||
describe('getWorkingState', () => {
|
||||
const mockStatus = ' M src/file1.ts\n?? src/file2.ts'
|
||||
const mockDiff = '@@ -1,1 +1,2 @@\n-old line\n+new line'
|
||||
|
||||
it('should return working directory changes', async () => {
|
||||
const responses = new Map([
|
||||
['git --version', { stdout: 'git version 2.39.2', stderr: '' }],
|
||||
['git rev-parse --git-dir', { stdout: '.git', stderr: '' }],
|
||||
['git status --short', { stdout: mockStatus, stderr: '' }],
|
||||
['git diff HEAD', { stdout: mockDiff, stderr: '' }]
|
||||
])
|
||||
|
||||
exec.mockImplementation((command: string, options: { cwd?: string }, callback: Function) => {
|
||||
for (const [cmd, response] of responses) {
|
||||
if (command === cmd) {
|
||||
callback(null, response)
|
||||
return
|
||||
}
|
||||
}
|
||||
callback(new Error('Unexpected command'))
|
||||
})
|
||||
|
||||
const result = await getWorkingState(cwd)
|
||||
expect(result).toContain('Working directory changes:')
|
||||
expect(result).toContain('src/file1.ts')
|
||||
expect(result).toContain('src/file2.ts')
|
||||
})
|
||||
|
||||
it('should return message when working directory is clean', async () => {
|
||||
const responses = new Map([
|
||||
['git --version', { stdout: 'git version 2.39.2', stderr: '' }],
|
||||
['git rev-parse --git-dir', { stdout: '.git', stderr: '' }],
|
||||
['git status --short', { stdout: '', stderr: '' }]
|
||||
])
|
||||
|
||||
exec.mockImplementation((command: string, options: { cwd?: string }, callback: Function) => {
|
||||
for (const [cmd, response] of responses) {
|
||||
if (command === cmd) {
|
||||
callback(null, response)
|
||||
return
|
||||
}
|
||||
}
|
||||
callback(new Error('Unexpected command'))
|
||||
})
|
||||
|
||||
const result = await getWorkingState(cwd)
|
||||
expect(result).toBe('No changes in working directory')
|
||||
})
|
||||
|
||||
it('should return error message when git is not installed', async () => {
|
||||
exec.mockImplementation((command: string, options: { cwd?: string }, callback: Function) => {
|
||||
if (command === 'git --version') {
|
||||
callback(new Error('git not found'))
|
||||
return
|
||||
}
|
||||
callback(new Error('Unexpected command'))
|
||||
})
|
||||
|
||||
const result = await getWorkingState(cwd)
|
||||
expect(result).toBe('Git is not installed')
|
||||
})
|
||||
|
||||
it('should return error message when not in a git repository', async () => {
|
||||
const responses = new Map([
|
||||
['git --version', { stdout: 'git version 2.39.2', stderr: '' }],
|
||||
['git rev-parse --git-dir', null] // null indicates error should be called
|
||||
])
|
||||
|
||||
exec.mockImplementation((command: string, options: { cwd?: string }, callback: Function) => {
|
||||
const response = responses.get(command)
|
||||
if (response === null) {
|
||||
callback(new Error('not a git repository'))
|
||||
} else if (response) {
|
||||
callback(null, response)
|
||||
} else {
|
||||
callback(new Error('Unexpected command'))
|
||||
}
|
||||
})
|
||||
|
||||
const result = await getWorkingState(cwd)
|
||||
expect(result).toBe('Not a git repository')
|
||||
})
|
||||
})
|
||||
})
|
||||
135
src/utils/__tests__/path.test.ts
Normal file
135
src/utils/__tests__/path.test.ts
Normal file
@@ -0,0 +1,135 @@
|
||||
import { arePathsEqual, getReadablePath } from '../path';
|
||||
import * as path from 'path';
|
||||
import os from 'os';
|
||||
|
||||
describe('Path Utilities', () => {
|
||||
const originalPlatform = process.platform;
|
||||
|
||||
afterEach(() => {
|
||||
Object.defineProperty(process, 'platform', {
|
||||
value: originalPlatform
|
||||
});
|
||||
});
|
||||
|
||||
describe('String.prototype.toPosix', () => {
|
||||
it('should convert backslashes to forward slashes', () => {
|
||||
const windowsPath = 'C:\\Users\\test\\file.txt';
|
||||
expect(windowsPath.toPosix()).toBe('C:/Users/test/file.txt');
|
||||
});
|
||||
|
||||
it('should not modify paths with forward slashes', () => {
|
||||
const unixPath = '/home/user/file.txt';
|
||||
expect(unixPath.toPosix()).toBe('/home/user/file.txt');
|
||||
});
|
||||
|
||||
it('should preserve extended-length Windows paths', () => {
|
||||
const extendedPath = '\\\\?\\C:\\Very\\Long\\Path';
|
||||
expect(extendedPath.toPosix()).toBe('\\\\?\\C:\\Very\\Long\\Path');
|
||||
});
|
||||
});
|
||||
|
||||
describe('arePathsEqual', () => {
|
||||
describe('on Windows', () => {
|
||||
beforeEach(() => {
|
||||
Object.defineProperty(process, 'platform', {
|
||||
value: 'win32'
|
||||
});
|
||||
});
|
||||
|
||||
it('should compare paths case-insensitively', () => {
|
||||
expect(arePathsEqual('C:\\Users\\Test', 'c:\\users\\test')).toBe(true);
|
||||
});
|
||||
|
||||
it('should handle different path separators', () => {
|
||||
// Convert both paths to use forward slashes after normalization
|
||||
const path1 = path.normalize('C:\\Users\\Test').replace(/\\/g, '/');
|
||||
const path2 = path.normalize('C:/Users/Test').replace(/\\/g, '/');
|
||||
expect(arePathsEqual(path1, path2)).toBe(true);
|
||||
});
|
||||
|
||||
it('should normalize paths with ../', () => {
|
||||
// Convert both paths to use forward slashes after normalization
|
||||
const path1 = path.normalize('C:\\Users\\Test\\..\\Test').replace(/\\/g, '/');
|
||||
const path2 = path.normalize('C:\\Users\\Test').replace(/\\/g, '/');
|
||||
expect(arePathsEqual(path1, path2)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('on POSIX', () => {
|
||||
beforeEach(() => {
|
||||
Object.defineProperty(process, 'platform', {
|
||||
value: 'darwin'
|
||||
});
|
||||
});
|
||||
|
||||
it('should compare paths case-sensitively', () => {
|
||||
expect(arePathsEqual('/Users/Test', '/Users/test')).toBe(false);
|
||||
});
|
||||
|
||||
it('should normalize paths', () => {
|
||||
expect(arePathsEqual('/Users/./Test', '/Users/Test')).toBe(true);
|
||||
});
|
||||
|
||||
it('should handle trailing slashes', () => {
|
||||
expect(arePathsEqual('/Users/Test/', '/Users/Test')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('edge cases', () => {
|
||||
it('should handle undefined paths', () => {
|
||||
expect(arePathsEqual(undefined, undefined)).toBe(true);
|
||||
expect(arePathsEqual('/test', undefined)).toBe(false);
|
||||
expect(arePathsEqual(undefined, '/test')).toBe(false);
|
||||
});
|
||||
|
||||
it('should handle root paths with trailing slashes', () => {
|
||||
expect(arePathsEqual('/', '/')).toBe(true);
|
||||
expect(arePathsEqual('C:\\', 'C:\\')).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getReadablePath', () => {
|
||||
const homeDir = os.homedir();
|
||||
const desktop = path.join(homeDir, 'Desktop');
|
||||
|
||||
it('should return basename when path equals cwd', () => {
|
||||
const cwd = '/Users/test/project';
|
||||
expect(getReadablePath(cwd, cwd)).toBe('project');
|
||||
});
|
||||
|
||||
it('should return relative path when inside cwd', () => {
|
||||
const cwd = '/Users/test/project';
|
||||
const filePath = '/Users/test/project/src/file.txt';
|
||||
expect(getReadablePath(cwd, filePath)).toBe('src/file.txt');
|
||||
});
|
||||
|
||||
it('should return absolute path when outside cwd', () => {
|
||||
const cwd = '/Users/test/project';
|
||||
const filePath = '/Users/test/other/file.txt';
|
||||
expect(getReadablePath(cwd, filePath)).toBe('/Users/test/other/file.txt');
|
||||
});
|
||||
|
||||
it('should handle Desktop as cwd', () => {
|
||||
const filePath = path.join(desktop, 'file.txt');
|
||||
expect(getReadablePath(desktop, filePath)).toBe(filePath.toPosix());
|
||||
});
|
||||
|
||||
it('should handle undefined relative path', () => {
|
||||
const cwd = '/Users/test/project';
|
||||
expect(getReadablePath(cwd)).toBe('project');
|
||||
});
|
||||
|
||||
it('should handle parent directory traversal', () => {
|
||||
const cwd = '/Users/test/project';
|
||||
const filePath = '../../other/file.txt';
|
||||
expect(getReadablePath(cwd, filePath)).toBe('/Users/other/file.txt');
|
||||
});
|
||||
|
||||
it('should normalize paths with redundant segments', () => {
|
||||
const cwd = '/Users/test/project';
|
||||
const filePath = '/Users/test/project/./src/../src/file.txt';
|
||||
expect(getReadablePath(cwd, filePath)).toBe('src/file.txt');
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user