@@ -6,7 +6,7 @@ import { spawnSync } from "node:child_process";
66
77import { afterEach , assert , describe , it , vi } from "vitest" ;
88
9- import { searchWorkspaceEntries } from "./workspaceEntries" ;
9+ import { browseDirectories , searchWorkspaceEntries } from "./workspaceEntries" ;
1010
1111const tempDirs : string [ ] = [ ] ;
1212
@@ -200,3 +200,80 @@ describe("searchWorkspaceEntries", () => {
200200 assert . isAtMost ( peakReads , 32 ) ;
201201 } ) ;
202202} ) ;
203+
204+ describe ( "browseDirectories" , ( ) => {
205+ afterEach ( ( ) => {
206+ vi . restoreAllMocks ( ) ;
207+ for ( const dir of tempDirs . splice ( 0 , tempDirs . length ) ) {
208+ fs . rmSync ( dir , { recursive : true , force : true } ) ;
209+ }
210+ } ) ;
211+
212+ it ( "returns directory entries relative to cwd with resolvedParent" , async ( ) => {
213+ const cwd = makeTempDir ( "marcode-browse-basic-" ) ;
214+ fs . mkdirSync ( path . join ( cwd , "alpha" ) ) ;
215+ fs . mkdirSync ( path . join ( cwd , "beta" ) ) ;
216+ writeFile ( cwd , "readme.md" , "" ) ;
217+
218+ const result = await browseDirectories ( { cwd, pathQuery : "" , limit : 100 } ) ;
219+ const names = result . entries . map ( ( entry ) => entry . path ) ;
220+
221+ assert . sameMembers ( names , [ "alpha" , "beta" ] ) ;
222+ assert . equal ( result . resolvedParent , path . resolve ( cwd ) ) ;
223+ assert . isFalse ( result . truncated ) ;
224+ } ) ;
225+
226+ it ( "resolves absolute paths in pathQuery regardless of cwd" , async ( ) => {
227+ const cwd = makeTempDir ( "marcode-browse-cwd-" ) ;
228+ const other = makeTempDir ( "marcode-browse-abs-" ) ;
229+ fs . mkdirSync ( path . join ( other , "nested" ) ) ;
230+
231+ const result = await browseDirectories ( { cwd, pathQuery : `${ other } /` , limit : 100 } ) ;
232+ const names = result . entries . map ( ( entry ) => entry . path ) ;
233+
234+ assert . equal ( result . resolvedParent , path . resolve ( other ) ) ;
235+ assert . include (
236+ names . map ( ( name ) => path . basename ( name ) ) ,
237+ "nested" ,
238+ ) ;
239+ } ) ;
240+
241+ it ( "expands ~/ in cwd to the user's home directory" , async ( ) => {
242+ const homeDir = os . homedir ( ) ;
243+ const sentinel = `marcode-browse-home-sentinel-${ process . pid } -${ Date . now ( ) } ` ;
244+ const sentinelPath = path . join ( homeDir , sentinel ) ;
245+ fs . mkdirSync ( sentinelPath ) ;
246+ try {
247+ const result = await browseDirectories ( { cwd : "~/" , pathQuery : "" , limit : 100 } ) ;
248+
249+ assert . equal ( result . resolvedParent , path . resolve ( homeDir ) ) ;
250+ assert . isTrue ( result . entries . some ( ( entry ) => path . basename ( entry . path ) === sentinel ) ) ;
251+ } finally {
252+ fs . rmSync ( sentinelPath , { recursive : true , force : true } ) ;
253+ }
254+ } ) ;
255+
256+ it ( "resolves ../ relative to cwd" , async ( ) => {
257+ const parent = makeTempDir ( "marcode-browse-parent-" ) ;
258+ const child = path . join ( parent , "child" ) ;
259+ fs . mkdirSync ( child ) ;
260+ fs . mkdirSync ( path . join ( parent , "sibling" ) ) ;
261+
262+ const result = await browseDirectories ( { cwd : child , pathQuery : "../" , limit : 100 } ) ;
263+
264+ assert . equal ( result . resolvedParent , path . resolve ( parent ) ) ;
265+ const names = result . entries . map ( ( entry ) => path . basename ( entry . path ) ) ;
266+ assert . includeMembers ( names , [ "child" , "sibling" ] ) ;
267+ } ) ;
268+
269+ it ( "returns empty entries and resolvedParent when directory does not exist" , async ( ) => {
270+ const cwd = makeTempDir ( "marcode-browse-missing-" ) ;
271+ const missing = path . join ( cwd , "does-not-exist" ) ;
272+
273+ const result = await browseDirectories ( { cwd : missing , pathQuery : "" , limit : 100 } ) ;
274+
275+ assert . deepEqual ( [ ...result . entries ] , [ ] ) ;
276+ assert . equal ( result . resolvedParent , path . resolve ( missing ) ) ;
277+ assert . isFalse ( result . truncated ) ;
278+ } ) ;
279+ } ) ;
0 commit comments