1+ import { describe , it , expect , vi , beforeEach } from 'vitest' ;
2+ import { PintFsClient } from '../src/PintClient/fs' ;
3+ import { Client } from '../src/api-clients/pint/client' ;
4+ import * as pintApi from '../src/api-clients/pint' ;
5+
6+ // Mock the API functions
7+ vi . mock ( '../src/api-clients/pint' , ( ) => ( {
8+ createFile : vi . fn ( ) ,
9+ readFile : vi . fn ( ) ,
10+ performFileAction : vi . fn ( ) ,
11+ listDirectory : vi . fn ( ) ,
12+ createDirectory : vi . fn ( ) ,
13+ deleteDirectory : vi . fn ( ) ,
14+ getFileStat : vi . fn ( ) ,
15+ } ) ) ;
16+
17+ // Helper to create proper mock response
18+ const createMockResponse = ( data : any , error ?: any ) => ( {
19+ data,
20+ error,
21+ request : { } as any ,
22+ response : { } as any ,
23+ } ) ;
24+
25+ describe ( 'PintFsClient' , ( ) => {
26+ let client : PintFsClient ;
27+ let mockApiClient : Client ;
28+
29+ beforeEach ( ( ) => {
30+ vi . clearAllMocks ( ) ;
31+ mockApiClient = { } as Client ;
32+ client = new PintFsClient ( mockApiClient ) ;
33+ } ) ;
34+
35+ describe ( 'readFile' , ( ) => {
36+ it ( 'should successfully read a file and convert to Uint8Array' , async ( ) => {
37+ const mockResponse = createMockResponse ( { content : 'Hello World' } ) ;
38+ vi . mocked ( pintApi . readFile ) . mockResolvedValue ( mockResponse ) ;
39+
40+ const result = await client . readFile ( '/test/file.txt' ) ;
41+
42+ expect ( result ) . toEqual ( {
43+ type : 'ok' ,
44+ result : {
45+ content : new TextEncoder ( ) . encode ( 'Hello World' ) ,
46+ } ,
47+ } ) ;
48+ expect ( pintApi . readFile ) . toHaveBeenCalledWith ( {
49+ client : mockApiClient ,
50+ path : { path : '/test/file.txt' } ,
51+ } ) ;
52+ } ) ;
53+
54+ it ( 'should handle API error response' , async ( ) => {
55+ const mockResponse = createMockResponse ( undefined , { message : 'File not found' } ) ;
56+ vi . mocked ( pintApi . readFile ) . mockResolvedValue ( mockResponse ) ;
57+
58+ const result = await client . readFile ( '/test/missing.txt' ) ;
59+
60+ expect ( result ) . toEqual ( {
61+ type : 'error' ,
62+ error : 'File not found' ,
63+ errno : null ,
64+ } ) ;
65+ } ) ;
66+
67+ it ( 'should handle thrown exceptions' , async ( ) => {
68+ vi . mocked ( pintApi . readFile ) . mockRejectedValue ( new Error ( 'Network error' ) ) ;
69+
70+ const result = await client . readFile ( '/test/file.txt' ) ;
71+
72+ expect ( result ) . toEqual ( {
73+ type : 'error' ,
74+ error : 'Network error' ,
75+ errno : null ,
76+ } ) ;
77+ } ) ;
78+
79+ it ( 'should handle unknown error types' , async ( ) => {
80+ vi . mocked ( pintApi . readFile ) . mockRejectedValue ( 'String error' ) ;
81+
82+ const result = await client . readFile ( '/test/file.txt' ) ;
83+
84+ expect ( result ) . toEqual ( {
85+ type : 'error' ,
86+ error : 'Unknown error' ,
87+ errno : null ,
88+ } ) ;
89+ } ) ;
90+ } ) ;
91+
92+ describe ( 'readdir' , ( ) => {
93+ it ( 'should successfully read directory entries' , async ( ) => {
94+ const mockResponse = createMockResponse ( {
95+ files : [
96+ { name : 'file1.txt' , isDir : false } ,
97+ { name : 'subdir' , isDir : true } ,
98+ ] ,
99+ } ) ;
100+ vi . mocked ( pintApi . listDirectory ) . mockResolvedValue ( mockResponse ) ;
101+
102+ const result = await client . readdir ( '/test' ) ;
103+
104+ expect ( result ) . toEqual ( {
105+ type : 'ok' ,
106+ result : {
107+ entries : [
108+ { name : 'file1.txt' , type : 0 , isSymlink : false } ,
109+ { name : 'subdir' , type : 1 , isSymlink : false } ,
110+ ] ,
111+ } ,
112+ } ) ;
113+ expect ( pintApi . listDirectory ) . toHaveBeenCalledWith ( {
114+ client : mockApiClient ,
115+ path : { path : '/test' } ,
116+ } ) ;
117+ } ) ;
118+
119+ it ( 'should handle API error response' , async ( ) => {
120+ const mockResponse = createMockResponse ( undefined , { message : 'Permission denied' } ) ;
121+ vi . mocked ( pintApi . listDirectory ) . mockResolvedValue ( mockResponse ) ;
122+
123+ const result = await client . readdir ( '/protected' ) ;
124+
125+ expect ( result ) . toEqual ( {
126+ type : 'error' ,
127+ error : 'Permission denied' ,
128+ errno : null ,
129+ } ) ;
130+ } ) ;
131+ } ) ;
132+
133+ describe ( 'writeFile' , ( ) => {
134+ it ( 'should successfully write file content' , async ( ) => {
135+ const mockResponse = createMockResponse ( { } ) ;
136+ vi . mocked ( pintApi . createFile ) . mockResolvedValue ( mockResponse ) ;
137+
138+ const content = new TextEncoder ( ) . encode ( 'Hello World' ) ;
139+ const result = await client . writeFile ( '/test/new.txt' , content ) ;
140+
141+ expect ( result ) . toEqual ( {
142+ type : 'ok' ,
143+ result : { } ,
144+ } ) ;
145+ expect ( pintApi . createFile ) . toHaveBeenCalledWith ( {
146+ client : mockApiClient ,
147+ path : { path : '/test/new.txt' } ,
148+ body : { content : 'Hello World' } ,
149+ } ) ;
150+ } ) ;
151+
152+ it ( 'should handle API error response' , async ( ) => {
153+ const mockResponse = createMockResponse ( undefined , { message : 'Disk full' } ) ;
154+ vi . mocked ( pintApi . createFile ) . mockResolvedValue ( mockResponse ) ;
155+
156+ const content = new TextEncoder ( ) . encode ( 'data' ) ;
157+ const result = await client . writeFile ( '/test/file.txt' , content ) ;
158+
159+ expect ( result ) . toEqual ( {
160+ type : 'error' ,
161+ error : 'Disk full' ,
162+ errno : null ,
163+ } ) ;
164+ } ) ;
165+ } ) ;
166+
167+ describe ( 'remove' , ( ) => {
168+ it ( 'should successfully remove directory/file' , async ( ) => {
169+ const mockResponse = createMockResponse ( { } ) ;
170+ vi . mocked ( pintApi . deleteDirectory ) . mockResolvedValue ( mockResponse ) ;
171+
172+ const result = await client . remove ( '/test/path' ) ;
173+
174+ expect ( result ) . toEqual ( {
175+ type : 'ok' ,
176+ result : { } ,
177+ } ) ;
178+ expect ( pintApi . deleteDirectory ) . toHaveBeenCalledWith ( {
179+ client : mockApiClient ,
180+ path : { path : '/test/path' } ,
181+ } ) ;
182+ } ) ;
183+
184+ it ( 'should handle API error response' , async ( ) => {
185+ const mockResponse = createMockResponse ( undefined , { message : 'Path not found' } ) ;
186+ vi . mocked ( pintApi . deleteDirectory ) . mockResolvedValue ( mockResponse ) ;
187+
188+ const result = await client . remove ( '/test/missing' ) ;
189+
190+ expect ( result ) . toEqual ( {
191+ type : 'error' ,
192+ error : 'Path not found' ,
193+ errno : null ,
194+ } ) ;
195+ } ) ;
196+ } ) ;
197+
198+ describe ( 'mkdir' , ( ) => {
199+ it ( 'should successfully create directory' , async ( ) => {
200+ const mockResponse = createMockResponse ( { } ) ;
201+ vi . mocked ( pintApi . createDirectory ) . mockResolvedValue ( mockResponse ) ;
202+
203+ const result = await client . mkdir ( '/test/newdir' ) ;
204+
205+ expect ( result ) . toEqual ( {
206+ type : 'ok' ,
207+ result : { } ,
208+ } ) ;
209+ expect ( pintApi . createDirectory ) . toHaveBeenCalledWith ( {
210+ client : mockApiClient ,
211+ path : { path : '/test/newdir' } ,
212+ } ) ;
213+ } ) ;
214+
215+ it ( 'should handle API error response' , async ( ) => {
216+ const mockResponse = createMockResponse ( undefined , { message : 'Directory exists' } ) ;
217+ vi . mocked ( pintApi . createDirectory ) . mockResolvedValue ( mockResponse ) ;
218+
219+ const result = await client . mkdir ( '/test/existing' ) ;
220+
221+ expect ( result ) . toEqual ( {
222+ type : 'error' ,
223+ error : 'Directory exists' ,
224+ errno : null ,
225+ } ) ;
226+ } ) ;
227+ } ) ;
228+
229+ describe ( 'stat' , ( ) => {
230+ it ( 'should successfully get file stats' , async ( ) => {
231+ const mockResponse = createMockResponse ( {
232+ isDir : false ,
233+ size : 1024 ,
234+ modTime : '2023-01-01T12:00:00Z' ,
235+ } ) ;
236+ vi . mocked ( pintApi . getFileStat ) . mockResolvedValue ( mockResponse ) ;
237+
238+ const result = await client . stat ( '/test/file.txt' ) ;
239+
240+ const expectedTime = new Date ( '2023-01-01T12:00:00Z' ) . getTime ( ) ;
241+ expect ( result ) . toEqual ( {
242+ type : 'ok' ,
243+ result : {
244+ type : 0 , // file
245+ isSymlink : false ,
246+ size : 1024 ,
247+ mtime : expectedTime ,
248+ ctime : expectedTime ,
249+ atime : expectedTime ,
250+ } ,
251+ } ) ;
252+ expect ( pintApi . getFileStat ) . toHaveBeenCalledWith ( {
253+ client : mockApiClient ,
254+ path : { path : '/test/file.txt' } ,
255+ } ) ;
256+ } ) ;
257+
258+ it ( 'should handle directory stats' , async ( ) => {
259+ const mockResponse = createMockResponse ( {
260+ isDir : true ,
261+ size : 0 ,
262+ modTime : '2023-01-01T12:00:00Z' ,
263+ } ) ;
264+ vi . mocked ( pintApi . getFileStat ) . mockResolvedValue ( mockResponse ) ;
265+
266+ const result = await client . stat ( '/test/dir' ) ;
267+
268+ expect ( result . type ) . toBe ( 'ok' ) ;
269+ if ( result . type === 'ok' ) {
270+ expect ( result . result . type ) . toBe ( 1 ) ; // directory
271+ }
272+ } ) ;
273+
274+ it ( 'should handle API error response' , async ( ) => {
275+ const mockResponse = createMockResponse ( undefined , { message : 'File not found' } ) ;
276+ vi . mocked ( pintApi . getFileStat ) . mockResolvedValue ( mockResponse ) ;
277+
278+ const result = await client . stat ( '/test/missing.txt' ) ;
279+
280+ expect ( result ) . toEqual ( {
281+ type : 'error' ,
282+ error : 'File not found' ,
283+ errno : null ,
284+ } ) ;
285+ } ) ;
286+ } ) ;
287+
288+ describe ( 'copy' , ( ) => {
289+ it ( 'should successfully copy file' , async ( ) => {
290+ const mockResponse = createMockResponse ( { } ) ;
291+ vi . mocked ( pintApi . performFileAction ) . mockResolvedValue ( mockResponse ) ;
292+
293+ const result = await client . copy ( '/src/file.txt' , '/dest/file.txt' ) ;
294+
295+ expect ( result ) . toEqual ( {
296+ type : 'ok' ,
297+ result : { } ,
298+ } ) ;
299+ expect ( pintApi . performFileAction ) . toHaveBeenCalledWith ( {
300+ client : mockApiClient ,
301+ path : { path : '/src/file.txt' } ,
302+ body : {
303+ action : 'copy' ,
304+ destination : '/dest/file.txt' ,
305+ } ,
306+ } ) ;
307+ } ) ;
308+
309+ it ( 'should handle API error response' , async ( ) => {
310+ const mockResponse = createMockResponse ( undefined , { message : 'Source not found' } ) ;
311+ vi . mocked ( pintApi . performFileAction ) . mockResolvedValue ( mockResponse ) ;
312+
313+ const result = await client . copy ( '/src/missing.txt' , '/dest/file.txt' ) ;
314+
315+ expect ( result ) . toEqual ( {
316+ type : 'error' ,
317+ error : 'Source not found' ,
318+ errno : null ,
319+ } ) ;
320+ } ) ;
321+ } ) ;
322+
323+ describe ( 'rename' , ( ) => {
324+ it ( 'should successfully rename/move file' , async ( ) => {
325+ const mockResponse = createMockResponse ( { } ) ;
326+ vi . mocked ( pintApi . performFileAction ) . mockResolvedValue ( mockResponse ) ;
327+
328+ const result = await client . rename ( '/old/path.txt' , '/new/path.txt' ) ;
329+
330+ expect ( result ) . toEqual ( {
331+ type : 'ok' ,
332+ result : { } ,
333+ } ) ;
334+ expect ( pintApi . performFileAction ) . toHaveBeenCalledWith ( {
335+ client : mockApiClient ,
336+ path : { path : '/old/path.txt' } ,
337+ body : {
338+ action : 'move' ,
339+ destination : '/new/path.txt' ,
340+ } ,
341+ } ) ;
342+ } ) ;
343+
344+ it ( 'should handle API error response' , async ( ) => {
345+ const mockResponse = createMockResponse ( undefined , { message : 'Destination exists' } ) ;
346+ vi . mocked ( pintApi . performFileAction ) . mockResolvedValue ( mockResponse ) ;
347+
348+ const result = await client . rename ( '/old/path.txt' , '/new/path.txt' ) ;
349+
350+ expect ( result ) . toEqual ( {
351+ type : 'error' ,
352+ error : 'Destination exists' ,
353+ errno : null ,
354+ } ) ;
355+ } ) ;
356+ } ) ;
357+
358+ describe ( 'watch' , ( ) => {
359+ it ( 'should throw not implemented error' , async ( ) => {
360+ await expect (
361+ client . watch ( '/test' , { } , ( ) => { } )
362+ ) . rejects . toThrow ( 'Not implemented' ) ;
363+ } ) ;
364+ } ) ;
365+
366+ describe ( 'download' , ( ) => {
367+ it ( 'should throw not implemented error' , async ( ) => {
368+ await expect (
369+ client . download ( '/test' )
370+ ) . rejects . toThrow ( 'Not implemented' ) ;
371+ } ) ;
372+ } ) ;
373+ } ) ;
0 commit comments