86 lines
3.2 KiB
TypeScript
86 lines
3.2 KiB
TypeScript
import { mkdir, mkdtemp, realpath, rm, symlink, writeFile } from 'node:fs/promises'
|
|
import { tmpdir } from 'node:os'
|
|
import path from 'node:path'
|
|
import { describe, expect, it } from 'vitest'
|
|
import { findRepoSymbol, isRepoImagePath, pathInsideRoot, resolveRepoEntry } from './repoPath'
|
|
|
|
describe('pathInsideRoot', () => {
|
|
const root = '/repo'
|
|
|
|
it('拼在仓库根里', () => {
|
|
expect(pathInsideRoot(root, 'backend/src/a.py')).toBe('/repo/backend/src/a.py')
|
|
expect(pathInsideRoot(root, 'vendor/agents')).toBe('/repo/vendor/agents')
|
|
})
|
|
|
|
it('..、绝对路径、盘符不算', () => {
|
|
expect(pathInsideRoot(root, '../etc/passwd')).toBeUndefined()
|
|
expect(pathInsideRoot(root, 'foo/../../etc/passwd')).toBeUndefined()
|
|
expect(pathInsideRoot(root, '/etc/passwd')).toBeUndefined()
|
|
expect(pathInsideRoot(root, './x.md')).toBeUndefined()
|
|
expect(pathInsideRoot(root, 'C:/foo')).toBeUndefined()
|
|
})
|
|
})
|
|
|
|
describe('isRepoImagePath', () => {
|
|
it('仓库里的图片算,跑出去的和不是图片的不算', () => {
|
|
expect(isRepoImagePath('frontend/a.png')).toBe(true)
|
|
expect(isRepoImagePath('frontend/a.PNG')).toBe(true)
|
|
expect(isRepoImagePath('../a.png')).toBe(false)
|
|
expect(isRepoImagePath('./a.png')).toBe(false)
|
|
expect(isRepoImagePath('/a.png')).toBe(false)
|
|
expect(isRepoImagePath('C:/a.png')).toBe(false)
|
|
expect(isRepoImagePath('README.md')).toBe(false)
|
|
})
|
|
})
|
|
|
|
describe('findRepoSymbol', () => {
|
|
const tree = [
|
|
{
|
|
name: 'Agent',
|
|
children: [
|
|
{ name: 'owner_id' },
|
|
{ name: 'Nested', children: [{ name: 'inner' }] },
|
|
],
|
|
},
|
|
{ name: 'load' },
|
|
]
|
|
|
|
it('按类名、函数名找', () => {
|
|
expect(findRepoSymbol(tree, 'Agent')?.name).toBe('Agent')
|
|
expect(findRepoSymbol(tree, 'load')?.name).toBe('load')
|
|
})
|
|
|
|
it('类名.成员先找类,再在里面找成员', () => {
|
|
expect(findRepoSymbol(tree, 'Agent.owner_id')?.name).toBe('owner_id')
|
|
expect(findRepoSymbol(tree, 'Agent.inner')?.name).toBe('inner')
|
|
expect(findRepoSymbol(tree, 'Agent.missing')).toBeUndefined()
|
|
expect(findRepoSymbol(tree, 'Missing')).toBeUndefined()
|
|
})
|
|
})
|
|
|
|
describe('resolveRepoEntry', () => {
|
|
it('文件和目录在仓库里,跑到外面的符号链接不算', async () => {
|
|
const root = await mkdtemp(path.join(tmpdir(), 'repo-link-'))
|
|
const outside = await mkdtemp(path.join(tmpdir(), 'repo-link-out-'))
|
|
try {
|
|
await writeFile(path.join(root, 'ok.txt'), 'ok')
|
|
await mkdir(path.join(root, 'dir'))
|
|
await writeFile(path.join(outside, 'secret'), 'x')
|
|
await symlink(path.join(outside, 'secret'), path.join(root, 'leak'))
|
|
|
|
const file = await resolveRepoEntry(root, 'ok.txt')
|
|
expect(file?.isDirectory).toBe(false)
|
|
expect(file?.fsPath).toBe(await realpath(path.join(root, 'ok.txt')))
|
|
|
|
expect((await resolveRepoEntry(root, 'dir'))?.isDirectory).toBe(true)
|
|
expect(await resolveRepoEntry(root, 'leak')).toBeUndefined()
|
|
expect(await resolveRepoEntry(root, 'missing')).toBeUndefined()
|
|
expect(await resolveRepoEntry(root, '../secret')).toBeUndefined()
|
|
}
|
|
finally {
|
|
await rm(root, { recursive: true, force: true })
|
|
await rm(outside, { recursive: true, force: true })
|
|
}
|
|
})
|
|
})
|