Skip to content

Commit b8caa3a

Browse files
test(sdk): make list-directory boundary cases portable
1 parent 46046f2 commit b8caa3a

1 file changed

Lines changed: 40 additions & 7 deletions

File tree

sdk/src/__tests__/list-directory.test.ts

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import { describe, expect, it, mock } from 'bun:test'
22

3+
import path from 'path'
4+
35
import { listDirectory } from '../tools/list-directory'
46

57
import type { CodebuffFileSystem } from '@codebuff/common/types/filesystem'
68
import type { Dirent, PathLike } from 'node:fs'
79

8-
const PROJECT_ROOT = '/workspace/project'
10+
const PROJECT_ROOT = path.resolve('workspace', 'project')
911

1012
function createFs(realpaths: Record<string, string>) {
1113
const readdir = mock(async (_path: PathLike) => {
@@ -55,9 +57,10 @@ describe('listDirectory', () => {
5557
})
5658

5759
it('lists a directory inside the project and preserves the requested path', async () => {
60+
const childPath = path.join(PROJECT_ROOT, 'src')
5861
const { fs, readdir } = createFs({
5962
[PROJECT_ROOT]: PROJECT_ROOT,
60-
[`${PROJECT_ROOT}/src`]: `${PROJECT_ROOT}/src`,
63+
[childPath]: childPath,
6164
})
6265

6366
const result = await listDirectory({
@@ -76,13 +79,13 @@ describe('listDirectory', () => {
7679
},
7780
},
7881
])
79-
expect(readdir).toHaveBeenCalledWith(`${PROJECT_ROOT}/src`, {
82+
expect(readdir).toHaveBeenCalledWith(childPath, {
8083
withFileTypes: true,
8184
})
8285
})
8386

8487
it('rejects sibling paths that only share the project prefix', async () => {
85-
const siblingPath = '/workspace/project-evil'
88+
const siblingPath = path.resolve(PROJECT_ROOT, '..', 'project-evil')
8689
const { fs, readdir } = createFs({
8790
[PROJECT_ROOT]: PROJECT_ROOT,
8891
[siblingPath]: siblingPath,
@@ -107,7 +110,7 @@ describe('listDirectory', () => {
107110
})
108111

109112
it('rejects the project parent directory', async () => {
110-
const parentPath = '/workspace'
113+
const parentPath = path.dirname(PROJECT_ROOT)
111114
const { fs, readdir } = createFs({
112115
[PROJECT_ROOT]: PROJECT_ROOT,
113116
[parentPath]: parentPath,
@@ -132,10 +135,11 @@ describe('listDirectory', () => {
132135
})
133136

134137
it('rejects directories that escape through a symlink', async () => {
135-
const symlinkPath = `${PROJECT_ROOT}/link`
138+
const symlinkPath = path.join(PROJECT_ROOT, 'link')
139+
const outsidePath = path.resolve(PROJECT_ROOT, '..', 'outside')
136140
const { fs, readdir } = createFs({
137141
[PROJECT_ROOT]: PROJECT_ROOT,
138-
[symlinkPath]: '/outside',
142+
[symlinkPath]: outsidePath,
139143
})
140144

141145
const result = await listDirectory({
@@ -155,4 +159,33 @@ describe('listDirectory', () => {
155159
])
156160
expect(readdir).not.toHaveBeenCalled()
157161
})
162+
163+
it('allows a symlink that resolves inside the project', async () => {
164+
const symlinkPath = path.join(PROJECT_ROOT, 'link')
165+
const realTarget = path.join(PROJECT_ROOT, 'src')
166+
const { fs, readdir } = createFs({
167+
[PROJECT_ROOT]: PROJECT_ROOT,
168+
[symlinkPath]: realTarget,
169+
})
170+
171+
const result = await listDirectory({
172+
directoryPath: 'link',
173+
projectPath: PROJECT_ROOT,
174+
fs,
175+
})
176+
177+
expect(result).toEqual([
178+
{
179+
type: 'json',
180+
value: {
181+
files: ['index.ts'],
182+
directories: [],
183+
path: 'link',
184+
},
185+
},
186+
])
187+
expect(readdir).toHaveBeenCalledWith(realTarget, {
188+
withFileTypes: true,
189+
})
190+
})
158191
})

0 commit comments

Comments
 (0)