Files
uptodownbot/internal/handler/handler_test.go
db123 37e7f918d0
All checks were successful
CI / build (push) Successful in 51s
refactor: remove container selection, extract helpers, add logging and tests
- Remove container picker UI, keyboard, settings, and ContainerOptions
  entirely — yt-dlp handles container format automatically
- Remove Container field from DownloadJob struct and related references
- Extract buildFormatList helper to deduplicate format list building
  between handleURLInput and handleBackStep
- Break runDownload into trackDownloadProgress + handleDownloadCompletion
- Add HTTP timeout (30s) to downloadFile helper
- Log applyQuota and AddHistory errors instead of discarding
- Log nil stepState warnings in all handler entry points
- Include job.StderrLog in download failure messages
- Add tests for buildFormatList, findFormatByID, determineMediaType,
  and buildFormatString
- Update README with search, DRM fallback, and quota feature docs
- Remove unused strings import from keyboard.go
2026-06-25 23:41:26 +03:30

205 lines
4.5 KiB
Go

package handler
import (
"testing"
"uptodownBot/internal/domain"
)
func TestBuildFormatList(t *testing.T) {
formats := []domain.Format{
{ID: "1", HasVideo: true, HasAudio: false, Resolution: "1920x1080"},
{ID: "2", HasVideo: false, HasAudio: true, Bitrate: "128k"},
{ID: "3", HasVideo: true, HasAudio: false, Resolution: "1280x720"},
{ID: "4", HasVideo: true, HasAudio: true, Resolution: "640x480"},
}
ids, err := buildFormatList(formats)
if err != nil {
t.Fatalf("buildFormatList() error: %v", err)
}
if len(ids) == 0 {
t.Fatal("buildFormatList() returned empty list")
}
if ids[0] != "best" {
t.Errorf("first ID = %q, want best", ids[0])
}
// Best, then all video formats, then all audio-only
wantVideo := map[string]bool{"1": true, "3": true, "4": true}
wantAudio := map[string]bool{"2": true}
seenAudio := false
for i := 1; i < len(ids); i++ {
if wantVideo[ids[i]] {
if seenAudio {
t.Errorf("video format %q found after audio-only formats", ids[i])
}
}
if wantAudio[ids[i]] {
seenAudio = true
}
}
}
func TestFindFormatByID(t *testing.T) {
formats := []domain.Format{
{ID: "1", Resolution: "1920x1080"},
{ID: "2", Bitrate: "128k"},
}
f := findFormatByID(formats, "1")
if f == nil {
t.Fatal("findFormatByID(1) = nil, want non-nil")
}
if f.ID != "1" {
t.Errorf("findFormatByID(1).ID = %q, want 1", f.ID)
}
f = findFormatByID(formats, "nonexistent")
if f != nil {
t.Errorf("findFormatByID(nonexistent) = %+v, want nil", f)
}
}
func TestStepStateDetermineMediaType(t *testing.T) {
tests := []struct {
name string
ss *stepState
want domain.MediaType
}{
{
name: "nil main format",
ss: &stepState{},
want: domain.MediaTypeVideoAudio,
},
{
name: "audio only no secondary",
ss: &stepState{MainFormat: &domain.Format{IsAudioOnly: true}},
want: domain.MediaTypeAudio,
},
{
name: "audio only with secondary",
ss: &stepState{MainFormat: &domain.Format{IsAudioOnly: true}, SecondaryFmt: &domain.Format{HasVideo: true}},
want: domain.MediaTypeVideoAudio,
},
{
name: "has video, has audio",
ss: &stepState{MainFormat: &domain.Format{HasVideo: true, HasAudio: true}},
want: domain.MediaTypeVideoAudio,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := tt.ss.determineMediaType()
if got != tt.want {
t.Errorf("determineMediaType() = %v, want %v", got, tt.want)
}
})
}
}
func TestStepStateBuildFormatString(t *testing.T) {
tests := []struct {
name string
ss *stepState
want string
}{
{
name: "best format",
ss: &stepState{MainFormatID: "best"},
want: "",
},
{
name: "single format",
ss: &stepState{MainFormatID: "137"},
want: "137",
},
{
name: "combined format",
ss: &stepState{MainFormatID: "137", SecondaryID: "140", SecondaryFmt: &domain.Format{ID: "140"}},
want: "137+140",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := tt.ss.buildFormatString()
if got != tt.want {
t.Errorf("buildFormatString() = %q, want %q", got, tt.want)
}
})
}
}
func TestFormatBytes(t *testing.T) {
tests := []struct {
input int64
want string
}{
{0, "0B"},
{1, "1B"},
{1023, "1023B"},
{1024, "1.0KB"},
{1536, "1.5KB"},
{1048576, "1.0MB"},
{1073741824, "1.0GB"},
{1099511627776, "1.0TB"},
}
for _, tt := range tests {
got := formatBytes(tt.input)
if got != tt.want {
t.Errorf("formatBytes(%d) = %q, want %q", tt.input, got, tt.want)
}
}
}
func TestFormatDuration(t *testing.T) {
tests := []struct {
input float64
want string
}{
{0, "0:00"},
{5, "0:05"},
{60, "1:00"},
{65, "1:05"},
{3600, "1:00:00"},
{3661, "1:01:01"},
{86400, "24:00:00"},
}
for _, tt := range tests {
got := formatDuration(tt.input)
if got != tt.want {
t.Errorf("formatDuration(%f) = %q, want %q", tt.input, got, tt.want)
}
}
}
func TestFormatLabelForDisplay(t *testing.T) {
tests := []struct {
f domain.Format
want string
}{
{
f: domain.Format{Resolution: "1920x1080", Filesize: 1048576},
want: "1920x1080 (1.0MB)",
},
{
f: domain.Format{Resolution: "1920x1080"},
want: "1920x1080",
},
{
f: domain.Format{Bitrate: "128k", Filesize: 1048576},
want: "128k (1.0MB)",
},
{
f: domain.Format{Bitrate: "128k"},
want: "128k",
},
{
f: domain.Format{ID: "137"},
want: "137",
},
}
for _, tt := range tests {
got := formatLabelForDisplay(tt.f)
if got != tt.want {
t.Errorf("formatLabelForDisplay(%+v) = %q, want %q", tt.f, got, tt.want)
}
}
}