@@ -239,3 +239,130 @@ func buildConfigFetcher(proxyConfig *base.DownloaderProxyConfig) fetcher.Fetcher
239239 fetcher .Setup (newController )
240240 return fetcher
241241}
242+
243+ // TestFetcher_Patch tests the Patch functionality for BT fetcher.
244+ // It tests modifying selected files after Resolve (without downloading).
245+ func TestFetcher_Patch (t * testing.T ) {
246+ f := buildFetcher ()
247+
248+ // Resolve a multi-file torrent
249+ err := f .Resolve (& base.Request {
250+ URL : "./testdata/test.torrent" ,
251+ }, nil )
252+ if err != nil {
253+ t .Fatalf ("Resolve failed: %v" , err )
254+ }
255+
256+ // Verify initial state: 3 files, all selected by default
257+ meta := f .Meta ()
258+ if len (meta .Res .Files ) != 3 {
259+ t .Fatalf ("Expected 3 files, got %d" , len (meta .Res .Files ))
260+ }
261+ if len (meta .Opts .SelectFiles ) != 3 {
262+ t .Fatalf ("Expected 3 selected files, got %d" , len (meta .Opts .SelectFiles ))
263+ }
264+
265+ // Total size of all files: 107484864
266+ totalSize := int64 (107484864 )
267+ if meta .Res .Size != totalSize {
268+ t .Fatalf ("Expected total size %d, got %d" , totalSize , meta .Res .Size )
269+ }
270+
271+ t .Run ("Patch with valid indices" , func (t * testing.T ) {
272+ // Select only file 0 and 2 (c.txt and a.txt)
273+ err := f .Patch (nil , & base.Options {
274+ SelectFiles : []int {0 , 2 },
275+ })
276+ if err != nil {
277+ t .Fatalf ("Patch failed: %v" , err )
278+ }
279+
280+ meta := f .Meta ()
281+ if ! reflect .DeepEqual (meta .Opts .SelectFiles , []int {0 , 2 }) {
282+ t .Errorf ("Expected SelectFiles [0, 2], got %v" , meta .Opts .SelectFiles )
283+ }
284+
285+ // Size should be recalculated: c.txt (98501754) + a.txt (78114) = 98579868
286+ expectedSize := int64 (98501754 + 78114 )
287+ if meta .Res .Size != expectedSize {
288+ t .Errorf ("Expected size %d, got %d" , expectedSize , meta .Res .Size )
289+ }
290+ })
291+
292+ t .Run ("Patch with invalid indices are silently ignored" , func (t * testing.T ) {
293+ // Mix of valid (0, 1) and invalid (-1, 5, 100) indices
294+ err := f .Patch (nil , & base.Options {
295+ SelectFiles : []int {- 1 , 0 , 5 , 1 , 100 },
296+ })
297+ if err != nil {
298+ t .Fatalf ("Patch should not return error for invalid indices: %v" , err )
299+ }
300+
301+ meta := f .Meta ()
302+ // Only valid indices 0 and 1 should remain
303+ if ! reflect .DeepEqual (meta .Opts .SelectFiles , []int {0 , 1 }) {
304+ t .Errorf ("Expected SelectFiles [0, 1], got %v" , meta .Opts .SelectFiles )
305+ }
306+
307+ // Size should be: c.txt (98501754) + b.txt (8904996) = 107406750
308+ expectedSize := int64 (98501754 + 8904996 )
309+ if meta .Res .Size != expectedSize {
310+ t .Errorf ("Expected size %d, got %d" , expectedSize , meta .Res .Size )
311+ }
312+ })
313+
314+ t .Run ("Patch with all invalid indices results in empty selection" , func (t * testing.T ) {
315+ err := f .Patch (nil , & base.Options {
316+ SelectFiles : []int {- 5 , 10 , 999 },
317+ })
318+ if err != nil {
319+ t .Fatalf ("Patch should not return error: %v" , err )
320+ }
321+
322+ meta := f .Meta ()
323+ if len (meta .Opts .SelectFiles ) != 0 {
324+ t .Errorf ("Expected empty SelectFiles, got %v" , meta .Opts .SelectFiles )
325+ }
326+
327+ // Note: CalcSize with empty selectFiles calculates total size of all files
328+ // This is by design - empty selection in CalcSize means "all files"
329+ // But SelectFiles being empty means no files are selected for download
330+ if meta .Res .Size != totalSize {
331+ t .Errorf ("Expected size %d (CalcSize with empty slice = all files), got %d" , totalSize , meta .Res .Size )
332+ }
333+ })
334+
335+ t .Run ("Patch with nil opts does nothing" , func (t * testing.T ) {
336+ // First set a known state
337+ f .Patch (nil , & base.Options {SelectFiles : []int {1 }})
338+ prevSelectFiles := f .Meta ().Opts .SelectFiles
339+
340+ // Patch with nil opts
341+ err := f .Patch (nil , nil )
342+ if err != nil {
343+ t .Fatalf ("Patch with nil opts should not fail: %v" , err )
344+ }
345+
346+ // Should remain unchanged
347+ if ! reflect .DeepEqual (f .Meta ().Opts .SelectFiles , prevSelectFiles ) {
348+ t .Errorf ("SelectFiles should remain unchanged after nil opts Patch" )
349+ }
350+ })
351+
352+ t .Run ("Patch progress array is resized" , func (t * testing.T ) {
353+ btFetcher := f .(* Fetcher )
354+ // Initialize progress array
355+ btFetcher .data .Progress = make (fetcher.Progress , 3 )
356+
357+ err := f .Patch (nil , & base.Options {
358+ SelectFiles : []int {0 , 2 },
359+ })
360+ if err != nil {
361+ t .Fatalf ("Patch failed: %v" , err )
362+ }
363+
364+ if len (btFetcher .data .Progress ) != 2 {
365+ t .Errorf ("Expected Progress length 2, got %d" , len (btFetcher .data .Progress ))
366+ }
367+ })
368+ }
0 commit comments