@@ -29,7 +29,7 @@ describe("getStorageBasePath - customStoragePath", () => {
2929
3030 expect ( result ) . toBe ( customPath )
3131 expect ( ( fsPromises as any ) . mkdir ) . toHaveBeenCalledWith ( customPath , { recursive : true } )
32- expect ( ( fsPromises as any ) . access ) . toHaveBeenCalledWith ( customPath , expect . any ( Number ) )
32+ expect ( ( fsPromises as any ) . access ) . toHaveBeenCalledWith ( customPath , 7 ) // 7 = R_OK(4) | W_OK(2) | X_OK(1 )
3333 } )
3434
3535 it ( "falls back to default and shows an error when custom path is not writable" , async ( ) => {
@@ -63,4 +63,93 @@ describe("getStorageBasePath - customStoragePath", () => {
6363 const firstArg = showErrorSpy . mock . calls [ 0 ] [ 0 ]
6464 expect ( typeof firstArg ) . toBe ( "string" )
6565 } )
66+ it ( "returns the default path when customStoragePath is an empty string and does not touch fs" , async ( ) => {
67+ vi . spyOn ( vscode . workspace , "getConfiguration" ) . mockReturnValue ( {
68+ get : vi . fn ( ) . mockReturnValue ( "" ) ,
69+ } as any )
70+
71+ const fsPromises = await import ( "fs/promises" )
72+ const { getStorageBasePath } = await import ( "../storage" )
73+
74+ const result = await getStorageBasePath ( defaultPath )
75+
76+ expect ( result ) . toBe ( defaultPath )
77+ expect ( ( fsPromises as any ) . mkdir ) . not . toHaveBeenCalled ( )
78+ expect ( ( fsPromises as any ) . access ) . not . toHaveBeenCalled ( )
79+ } )
80+
81+ it ( "falls back to default when mkdir fails and does not attempt access" , async ( ) => {
82+ const customPath = "/test/storage/failmkdir"
83+
84+ vi . spyOn ( vscode . workspace , "getConfiguration" ) . mockReturnValue ( {
85+ get : vi . fn ( ) . mockReturnValue ( customPath ) ,
86+ } as any )
87+
88+ const showErrorSpy = vi . spyOn ( vscode . window , "showErrorMessage" ) . mockResolvedValue ( undefined as any )
89+
90+ const fsPromises = await import ( "fs/promises" )
91+ const { getStorageBasePath } = await import ( "../storage" )
92+
93+ const mkdirMock = ( fsPromises as any ) . mkdir as ReturnType < typeof vi . fn >
94+ mkdirMock . mockImplementationOnce ( async ( p : string ) => {
95+ if ( p === customPath ) {
96+ const err : any = new Error ( "EACCES: permission denied" )
97+ err . code = "EACCES"
98+ throw err
99+ }
100+ return Promise . resolve ( )
101+ } )
102+
103+ const result = await getStorageBasePath ( defaultPath )
104+
105+ expect ( result ) . toBe ( defaultPath )
106+ expect ( ( fsPromises as any ) . access ) . not . toHaveBeenCalled ( )
107+ expect ( showErrorSpy ) . toHaveBeenCalledTimes ( 1 )
108+ } )
109+
110+ it ( "passes the correct permission flags (R_OK | W_OK | X_OK) to fs.access" , async ( ) => {
111+ const customPath = "/test/storage/path"
112+ vi . spyOn ( vscode . workspace , "getConfiguration" ) . mockReturnValue ( {
113+ get : vi . fn ( ) . mockReturnValue ( customPath ) ,
114+ } as any )
115+
116+ const fsPromises = await import ( "fs/promises" )
117+ const { getStorageBasePath } = await import ( "../storage" )
118+
119+ await getStorageBasePath ( defaultPath )
120+
121+ const constants = ( fsPromises as any ) . constants
122+ const expectedFlags = constants . R_OK | constants . W_OK | constants . X_OK
123+
124+ expect ( ( fsPromises as any ) . access ) . toHaveBeenCalledWith ( customPath , expectedFlags )
125+ } )
126+
127+ it ( "falls back when directory is readable but not writable (partial permissions)" , async ( ) => {
128+ const customPath = "/test/storage/readonly"
129+ vi . spyOn ( vscode . workspace , "getConfiguration" ) . mockReturnValue ( {
130+ get : vi . fn ( ) . mockReturnValue ( customPath ) ,
131+ } as any )
132+
133+ const showErrorSpy = vi . spyOn ( vscode . window , "showErrorMessage" ) . mockResolvedValue ( undefined as any )
134+
135+ const fsPromises = await import ( "fs/promises" )
136+ const { getStorageBasePath } = await import ( "../storage" )
137+
138+ const accessMock = ( fsPromises as any ) . access as ReturnType < typeof vi . fn >
139+ const constants = ( fsPromises as any ) . constants
140+ accessMock . mockImplementationOnce ( async ( p : string , mode ?: number ) => {
141+ // Simulate readable (R_OK) but not writable/executable (W_OK | X_OK)
142+ if ( p === customPath && mode && mode & ( constants . W_OK | constants . X_OK ) ) {
143+ const err : any = new Error ( "EACCES: permission denied" )
144+ err . code = "EACCES"
145+ throw err
146+ }
147+ return Promise . resolve ( )
148+ } )
149+
150+ const result = await getStorageBasePath ( defaultPath )
151+
152+ expect ( result ) . toBe ( defaultPath )
153+ expect ( showErrorSpy ) . toHaveBeenCalledTimes ( 1 )
154+ } )
66155} )
0 commit comments