@@ -32,4 +32,167 @@ describe("BaiduFileSystem", () => {
3232 ) ;
3333 expect ( updateDynamicRulesMock ) . not . toHaveBeenCalled ( ) ;
3434 } ) ;
35+
36+ it ( "create should reject expectedVersion as unsupported" , async ( ) => {
37+ const fs = new BaiduFileSystem ( "/apps" , "token" ) ;
38+
39+ await expect ( fs . create ( "test.txt" , { expectedVersion : "version" } ) ) . rejects . toMatchObject ( {
40+ provider : "baidu" ,
41+ unsupported : true ,
42+ } ) ;
43+ } ) ;
44+
45+ it ( "writer should reject createOnly when target already exists" , async ( ) => {
46+ const fs = new BaiduFileSystem ( "/apps" , "token" ) ;
47+ vi . spyOn ( fs , "list" ) . mockResolvedValue ( [
48+ {
49+ name : "test.txt" ,
50+ path : "/apps" ,
51+ size : 1 ,
52+ digest : "md5" ,
53+ createtime : 1 ,
54+ updatetime : 1 ,
55+ } ,
56+ ] ) ;
57+
58+ const writer = await fs . create ( "test.txt" , { createOnly : true } ) ;
59+
60+ await expect ( writer . write ( "content" ) ) . rejects . toMatchObject ( {
61+ provider : "baidu" ,
62+ conflict : true ,
63+ } ) ;
64+ } ) ;
65+
66+ it ( "writer should ask Baidu to fail server-side createOnly collisions" , async ( ) => {
67+ const fs = new BaiduFileSystem ( "/apps" , "token" ) ;
68+ vi . spyOn ( fs , "list" ) . mockResolvedValue ( [ ] ) ;
69+ const requestSpy = vi
70+ . spyOn ( fs , "request" )
71+ . mockResolvedValueOnce ( { errno : 0 , uploadid : "upload-id" } )
72+ . mockResolvedValueOnce ( { errno : 0 } )
73+ . mockResolvedValueOnce ( { errno : 0 } ) ;
74+
75+ const writer = await fs . create ( "test.txt" , { createOnly : true } ) ;
76+
77+ await expect ( writer . write ( "content" ) ) . resolves . toBeUndefined ( ) ;
78+
79+ expect ( String ( ( requestSpy . mock . calls [ 0 ] [ 1 ] as RequestInit ) . body ) ) . toContain ( "rtype=0" ) ;
80+ expect ( String ( ( requestSpy . mock . calls [ 2 ] [ 1 ] as RequestInit ) . body ) ) . toContain ( "rtype=0" ) ;
81+ } ) ;
82+
83+ it ( "writer should surface Baidu createOnly rejection as conflict" , async ( ) => {
84+ const fs = new BaiduFileSystem ( "/apps" , "token" ) ;
85+ vi . spyOn ( fs , "list" ) . mockResolvedValue ( [ ] ) ;
86+ vi . spyOn ( fs , "request" ) . mockResolvedValueOnce ( { errno : - 8 , errmsg : "file exists" } ) ;
87+
88+ const writer = await fs . create ( "test.txt" , { createOnly : true } ) ;
89+
90+ await expect ( writer . write ( "content" ) ) . rejects . toMatchObject ( {
91+ provider : "baidu" ,
92+ conflict : true ,
93+ } ) ;
94+ } ) ;
95+
96+ it ( "writer should reject expectedDigest when remote digest changed" , async ( ) => {
97+ const fs = new BaiduFileSystem ( "/apps" , "token" ) ;
98+ vi . spyOn ( fs , "list" ) . mockResolvedValue ( [
99+ {
100+ name : "test.txt" ,
101+ path : "/apps" ,
102+ size : 1 ,
103+ digest : "new-md5" ,
104+ createtime : 1 ,
105+ updatetime : 1 ,
106+ } ,
107+ ] ) ;
108+
109+ const writer = await fs . create ( "test.txt" , { expectedDigest : "old-md5" } ) ;
110+
111+ await expect ( writer . write ( "content" ) ) . rejects . toMatchObject ( {
112+ provider : "baidu" ,
113+ conflict : true ,
114+ } ) ;
115+ } ) ;
116+
117+ it ( "writer should allow best-effort expectedDigest when remote digest still matches" , async ( ) => {
118+ const fs = new BaiduFileSystem ( "/apps" , "token" ) ;
119+ vi . spyOn ( fs , "list" ) . mockResolvedValue ( [
120+ {
121+ name : "test.txt" ,
122+ path : "/apps" ,
123+ size : 1 ,
124+ digest : "old-md5" ,
125+ createtime : 1 ,
126+ updatetime : 1 ,
127+ } ,
128+ ] ) ;
129+ const requestSpy = vi
130+ . spyOn ( fs , "request" )
131+ . mockResolvedValueOnce ( { errno : 0 , uploadid : "upload-id" } )
132+ . mockResolvedValueOnce ( { errno : 0 } )
133+ . mockResolvedValueOnce ( { errno : 0 } ) ;
134+
135+ const writer = await fs . create ( "test.txt" , { expectedDigest : "old-md5" } ) ;
136+
137+ await expect ( writer . write ( "content" ) ) . resolves . toBeUndefined ( ) ;
138+ expect ( requestSpy ) . toHaveBeenCalledTimes ( 3 ) ;
139+ expect ( String ( ( requestSpy . mock . calls [ 0 ] [ 1 ] as RequestInit ) . body ) ) . toContain ( "rtype=3" ) ;
140+ expect ( String ( ( requestSpy . mock . calls [ 2 ] [ 1 ] as RequestInit ) . body ) ) . toContain ( "rtype=3" ) ;
141+ } ) ;
142+
143+ it ( "delete should be idempotent when Baidu reports file missing" , async ( ) => {
144+ const fetchMock = vi . fn ( ) . mockResolvedValue ( {
145+ json : async ( ) => ( { errno : - 9 } ) ,
146+ } ) ;
147+ vi . stubGlobal ( "fetch" , fetchMock ) ;
148+ const fs = new BaiduFileSystem ( "/apps" , "token" ) ;
149+
150+ await expect ( fs . delete ( "missing.txt" ) ) . resolves . toBeUndefined ( ) ;
151+ } ) ;
152+
153+ it ( "delete should reject expectedVersion as unsupported" , async ( ) => {
154+ const fs = new BaiduFileSystem ( "/apps" , "token" ) ;
155+
156+ await expect ( fs . delete ( "test.txt" , { expectedVersion : "version" } ) ) . rejects . toMatchObject ( {
157+ provider : "baidu" ,
158+ unsupported : true ,
159+ } ) ;
160+ } ) ;
161+
162+ it ( "delete should reject expectedDigest when remote digest changed" , async ( ) => {
163+ const fs = new BaiduFileSystem ( "/apps" , "token" ) ;
164+ vi . spyOn ( fs , "list" ) . mockResolvedValue ( [
165+ {
166+ name : "test.txt" ,
167+ path : "/apps" ,
168+ size : 1 ,
169+ digest : "new-md5" ,
170+ createtime : 1 ,
171+ updatetime : 1 ,
172+ } ,
173+ ] ) ;
174+
175+ await expect ( fs . delete ( "test.txt" , { expectedDigest : "old-md5" } ) ) . rejects . toMatchObject ( {
176+ provider : "baidu" ,
177+ conflict : true ,
178+ } ) ;
179+ } ) ;
180+
181+ it ( "delete should allow best-effort expectedDigest when remote digest still matches" , async ( ) => {
182+ const fs = new BaiduFileSystem ( "/apps" , "token" ) ;
183+ vi . spyOn ( fs , "list" ) . mockResolvedValue ( [
184+ {
185+ name : "test.txt" ,
186+ path : "/apps" ,
187+ size : 1 ,
188+ digest : "old-md5" ,
189+ createtime : 1 ,
190+ updatetime : 1 ,
191+ } ,
192+ ] ) ;
193+ const requestSpy = vi . spyOn ( fs , "request" ) . mockResolvedValue ( { errno : 0 } ) ;
194+
195+ await expect ( fs . delete ( "test.txt" , { expectedDigest : "old-md5" } ) ) . resolves . toBeUndefined ( ) ;
196+ expect ( requestSpy ) . toHaveBeenCalledTimes ( 1 ) ;
197+ } ) ;
35198} ) ;
0 commit comments