package storage import "testing" func TestBuildPreviewArgs(t *testing.T) { cfg := MoverConfig{Source: "/mnt/ssd", Dest: "/mnt/pool"} args, err := BuildPreviewArgs(cfg) if err != nil { t.Fatalf("BuildPreviewArgs: %v", err) } if args[0] != "rsync" { t.Errorf("args[0] = %q, want rsync", args[0]) } if args[1] != "-an" { t.Errorf("args[1] = %q, want -an", args[1]) } if args[2] != "--remove-source-files" { t.Errorf("args[2] = %q, want --remove-source-files", args[2]) } if args[3] != "--out-format=%n" { t.Errorf("args[3] = %q, want --out-format=%%n", args[3]) } if args[4] != "/mnt/ssd/" { t.Errorf("args[4] = %q, want /mnt/ssd/", args[4]) } if args[5] != "/mnt/pool/" { t.Errorf("args[5] = %q, want /mnt/pool/", args[5]) } } func TestBuildMoverArgs(t *testing.T) { cfg := MoverConfig{Source: "/mnt/ssd", Dest: "/mnt/pool", Inplace: false, RemoveSrc: true} args, err := BuildMoverArgs(cfg) if err != nil { t.Fatalf("BuildMoverArgs: %v", err) } if args[0] != "rsync" { t.Errorf("args[0] = %q, want rsync", args[0]) } foundRemove := false for _, a := range args { if a == "--remove-source-files" { foundRemove = true } } if !foundRemove { t.Errorf("--remove-source-files not found in args %v", args) } } func TestBuildMoverArgsExtraFlags(t *testing.T) { cfg := MoverConfig{Source: "/src", Dest: "/dst", ExtraFlags: []string{"--exclude=*.tmp", "--max-size=2G"}} args, err := BuildMoverArgs(cfg) if err != nil { t.Fatalf("BuildMoverArgs with extra flags: %v", err) } if args[0] != "rsync" { t.Errorf("args[0] = %q, want rsync", args[0]) } idx := -1 for i, a := range args { if a == "--exclude=*.tmp" { idx = i } } if idx == -1 { t.Errorf("--exclude=*.tmp not found in args %v", args) } } func TestParseExtraRsyncFlags(t *testing.T) { tests := []struct { name string input string want []string wantErr bool }{ {"empty", "", nil, false}, {"single flag", "--exclude=*.tmp", []string{"--exclude=*.tmp"}, false}, {"multiple flags", "--exclude=*.tmp\n--max-size=2G", []string{"--exclude=*.tmp", "--max-size=2G"}, false}, {"comment and empty", "# comment\n\n--exclude=*.tmp\n", []string{"--exclude=*.tmp"}, false}, {"missing dash", "exclude=*.tmp", nil, true}, {"forbidden char semicolon", "--flag;echo", nil, true}, {"forbidden char pipe", "--flag|grep", nil, true}, {"forbidden char dollar", "--flag$var", nil, true}, {"forbidden char backtick", "--flag`cmd`", nil, true}, {"newline in flag", "--flag\nline", nil, true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := ParseExtraRsyncFlags(tt.input) if tt.wantErr { if err == nil { t.Errorf("ParseExtraRsyncFlags(%q) = %v, want error", tt.input, got) } return } if err != nil { t.Errorf("unexpected error: %v", err) return } if len(got) != len(tt.want) { t.Errorf("ParseExtraRsyncFlags(%q) = %v, want %v", tt.input, got, tt.want) return } for i := range got { if got[i] != tt.want[i] { t.Errorf("ParseExtraRsyncFlags(%q)[%d] = %q, want %q", tt.input, i, got[i], tt.want[i]) } } }) } }