1+ import { describe , it , expect , vi , beforeEach } from 'vitest' ;
2+ import { createFile } from '../src/commands/files.js' ;
3+ import chalk from 'chalk' ;
4+ import * as PuterModule from '../src/modules/PuterModule.js' ;
5+ import * as auth from '../src/commands/auth.js' ;
6+ import * as commons from '../src/commons.js' ;
7+ import path from 'path' ;
8+
9+ // Mock console to prevent actual logging
10+ vi . spyOn ( console , 'log' ) . mockImplementation ( ( ) => { } ) ;
11+ vi . spyOn ( console , 'error' ) . mockImplementation ( ( ) => { } ) ;
12+
13+ // Mock dependencies
14+ vi . mock ( 'chalk' , ( ) => ( {
15+ default : {
16+ green : vi . fn ( text => text ) ,
17+ red : vi . fn ( text => text ) ,
18+ dim : vi . fn ( text => text ) ,
19+ yellow : vi . fn ( text => text ) ,
20+ cyan : vi . fn ( text => text ) ,
21+ }
22+ } ) ) ;
23+ vi . mock ( 'node-fetch' ) ;
24+ vi . mock ( 'conf' , ( ) => {
25+ const Conf = vi . fn ( ( ) => ( {
26+ get : vi . fn ( ) ,
27+ set : vi . fn ( ) ,
28+ clear : vi . fn ( ) ,
29+ } ) ) ;
30+ return { default : Conf } ;
31+ } ) ;
32+ vi . mock ( '../src/modules/PuterModule.js' ) ;
33+ vi . mock ( '../src/commands/auth.js' ) ;
34+ vi . mock ( '../src/commons.js' ) ;
35+
36+
37+ const mockPuter = {
38+ fs : {
39+ stat : vi . fn ( ) ,
40+ space : vi . fn ( ) ,
41+ mkdir : vi . fn ( ) ,
42+ upload : vi . fn ( ) ,
43+ } ,
44+ } ;
45+
46+ describe ( 'files.js' , ( ) => {
47+ beforeEach ( ( ) => {
48+ vi . clearAllMocks ( ) ;
49+ vi . spyOn ( PuterModule , 'getPuter' ) . mockReturnValue ( mockPuter ) ;
50+ vi . spyOn ( auth , 'getCurrentUserName' ) . mockReturnValue ( 'testuser' ) ;
51+ vi . spyOn ( auth , 'getCurrentDirectory' ) . mockReturnValue ( '/testuser/files' ) ;
52+ vi . spyOn ( commons , 'resolvePath' ) . mockImplementation ( ( current , newPath ) => path . join ( current , newPath ) ) ;
53+ } ) ;
54+
55+ describe ( 'createFile' , ( ) => {
56+ it ( 'should create a file successfully' , async ( ) => {
57+ mockPuter . fs . stat . mockRejectedValue ( { code : 'subject_does_not_exist' } ) ;
58+ mockPuter . fs . space . mockResolvedValue ( { used : 500 , capacity : 1000 } ) ;
59+ mockPuter . fs . upload . mockResolvedValue ( {
60+ name : 'test.txt' ,
61+ path : '/testuser/files/test.txt' ,
62+ uid : 'file-uid' ,
63+ } ) ;
64+
65+ const result = await createFile ( [ 'test.txt' , 'hello world' ] ) ;
66+
67+ expect ( result ) . toBe ( true ) ;
68+ expect ( mockPuter . fs . upload ) . toHaveBeenCalled ( ) ;
69+ expect ( console . log ) . toHaveBeenCalledWith ( expect . stringContaining ( 'File "test.txt" created successfully!' ) ) ;
70+ } ) ;
71+
72+ it ( 'should show usage and return false if no arguments are provided' , async ( ) => {
73+ const result = await createFile ( [ ] ) ;
74+ expect ( result ) . toBe ( false ) ;
75+ expect ( console . log ) . toHaveBeenCalledWith ( chalk . red ( 'Usage: touch <file_name> [content]' ) ) ;
76+ } ) ;
77+
78+ it ( 'should overwrite an existing file' , async ( ) => {
79+ mockPuter . fs . stat . mockResolvedValue ( { id : 'existing-file-id' } ) ;
80+ mockPuter . fs . space . mockResolvedValue ( { used : 500 , capacity : 1000 } ) ;
81+ mockPuter . fs . upload . mockResolvedValue ( {
82+ name : 'test.txt' ,
83+ path : '/testuser/files/test.txt' ,
84+ uid : 'file-uid' ,
85+ } ) ;
86+
87+ const result = await createFile ( [ 'test.txt' , 'new content' ] ) ;
88+
89+ expect ( result ) . toBe ( true ) ;
90+ expect ( console . log ) . toHaveBeenCalledWith ( chalk . yellow ( 'File "test.txt" already exists. It will be overwritten.' ) ) ;
91+ expect ( mockPuter . fs . upload ) . toHaveBeenCalled ( ) ;
92+ } ) ;
93+
94+ it ( 'should return false if there is not enough disk space' , async ( ) => {
95+ mockPuter . fs . stat . mockRejectedValue ( { code : 'subject_does_not_exist' } ) ;
96+ mockPuter . fs . space . mockResolvedValue ( { used : 1000 , capacity : 1000 } ) ;
97+ vi . spyOn ( commons , 'showDiskSpaceUsage' ) . mockImplementation ( ( ) => { } ) ;
98+
99+ const result = await createFile ( [ 'test.txt' ] ) ;
100+
101+ expect ( result ) . toBe ( false ) ;
102+ expect ( console . error ) . toHaveBeenCalledWith ( chalk . red ( 'Not enough disk space to create the file.' ) ) ;
103+ expect ( commons . showDiskSpaceUsage ) . toHaveBeenCalled ( ) ;
104+ } ) ;
105+
106+ it ( 'should create missing directories' , async ( ) => {
107+ // First stat for file fails, second for directory also fails
108+ mockPuter . fs . stat
109+ . mockRejectedValueOnce ( { code : 'subject_does_not_exist' } ) // file check
110+ . mockRejectedValueOnce ( { code : 'subject_does_not_exist' } ) ; // dir check
111+ mockPuter . fs . space . mockResolvedValue ( { used : 500 , capacity : 1000 } ) ;
112+ mockPuter . fs . mkdir . mockResolvedValue ( { } ) ;
113+ mockPuter . fs . upload . mockResolvedValue ( {
114+ name : 'test.txt' ,
115+ path : '/testuser/files/newdir/test.txt' ,
116+ uid : 'file-uid' ,
117+ } ) ;
118+
119+ const result = await createFile ( [ 'newdir/test.txt' , 'content' ] ) ;
120+
121+ expect ( result ) . toBe ( true ) ;
122+ expect ( mockPuter . fs . mkdir ) . toHaveBeenCalledWith ( '/testuser/files/newdir' , {
123+ overwrite : false ,
124+ dedupeName : true ,
125+ createMissingParents : true
126+ } ) ;
127+ expect ( mockPuter . fs . upload ) . toHaveBeenCalled ( ) ;
128+ } ) ;
129+
130+ it ( 'should handle API errors during file creation' , async ( ) => {
131+ mockPuter . fs . stat . mockRejectedValue ( { code : 'subject_does_not_exist' } ) ;
132+ mockPuter . fs . space . mockResolvedValue ( { used : 500 , capacity : 1000 } ) ;
133+ mockPuter . fs . upload . mockRejectedValue ( new Error ( 'API Error' ) ) ;
134+
135+ const result = await createFile ( [ 'test.txt' ] ) ;
136+
137+ expect ( result ) . toBe ( false ) ;
138+ expect ( console . error ) . toHaveBeenCalledWith ( chalk . red ( 'Failed to create file.\nError: API Error' ) ) ;
139+ } ) ;
140+ } ) ;
141+ } ) ;
0 commit comments