mirror of
https://github.com/krau/SaveAny-Bot.git
synced 2026-09-09 09:46:37 +08:00
Add comprehensive tests for ytdlp parameter parsing
Co-authored-by: krau <71133316+krau@users.noreply.github.com>
This commit is contained in:
co-authored by
krau
parent
9ee9972dec
commit
1b9c8cd2ad
@@ -0,0 +1,126 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestYtdlpArgumentParsing tests the URL and flag separation logic
|
||||||
|
func TestYtdlpArgumentParsing(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
input string
|
||||||
|
expectedURLs []string
|
||||||
|
expectedFlags []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Single URL without flags",
|
||||||
|
input: "/ytdlp https://example.com/video",
|
||||||
|
expectedURLs: []string{"https://example.com/video"},
|
||||||
|
expectedFlags: []string{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Multiple URLs without flags",
|
||||||
|
input: "/ytdlp https://example.com/v1 https://example.com/v2",
|
||||||
|
expectedURLs: []string{"https://example.com/v1", "https://example.com/v2"},
|
||||||
|
expectedFlags: []string{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "URL with format flag",
|
||||||
|
input: "/ytdlp --format best https://example.com/video",
|
||||||
|
expectedURLs: []string{"https://example.com/video"},
|
||||||
|
expectedFlags: []string{"--format", "best"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "URL with extract-audio flag",
|
||||||
|
input: "/ytdlp --extract-audio --audio-format mp3 https://example.com/video",
|
||||||
|
expectedURLs: []string{"https://example.com/video"},
|
||||||
|
expectedFlags: []string{"--extract-audio", "--audio-format", "mp3"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Multiple URLs with flags",
|
||||||
|
input: "/ytdlp --format best https://example.com/v1 https://example.com/v2",
|
||||||
|
expectedURLs: []string{"https://example.com/v1", "https://example.com/v2"},
|
||||||
|
expectedFlags: []string{"--format", "best"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Flags mixed with URLs",
|
||||||
|
input: "/ytdlp https://example.com/v1 --format best https://example.com/v2",
|
||||||
|
expectedURLs: []string{"https://example.com/v1", "https://example.com/v2"},
|
||||||
|
expectedFlags: []string{"--format", "best"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Short flag",
|
||||||
|
input: "/ytdlp -f best https://example.com/video",
|
||||||
|
expectedURLs: []string{"https://example.com/video"},
|
||||||
|
expectedFlags: []string{"-f", "best"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Boolean flag",
|
||||||
|
input: "/ytdlp --extract-audio https://example.com/video",
|
||||||
|
expectedURLs: []string{"https://example.com/video"},
|
||||||
|
expectedFlags: []string{"--extract-audio"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
args := strings.Split(tt.input, " ")
|
||||||
|
|
||||||
|
// Simulate the parsing logic from handleYtdlpCmd
|
||||||
|
var urls []string
|
||||||
|
var flags []string
|
||||||
|
|
||||||
|
for i := 1; i < len(args); i++ {
|
||||||
|
arg := strings.TrimSpace(args[i])
|
||||||
|
if arg == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if it's a flag (starts with - or --)
|
||||||
|
if strings.HasPrefix(arg, "-") {
|
||||||
|
flags = append(flags, arg)
|
||||||
|
// Check if the next argument is a value for this flag (not starting with -)
|
||||||
|
if i+1 < len(args) && !strings.HasPrefix(strings.TrimSpace(args[i+1]), "-") {
|
||||||
|
nextArg := strings.TrimSpace(args[i+1])
|
||||||
|
// Only treat as flag value if it's not a valid URL
|
||||||
|
u, err := url.Parse(nextArg)
|
||||||
|
if err != nil || u.Scheme == "" || u.Host == "" {
|
||||||
|
flags = append(flags, nextArg)
|
||||||
|
i++ // Skip the next argument as it's been consumed
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Try to parse as URL
|
||||||
|
u, err := url.Parse(arg)
|
||||||
|
if err != nil || u.Scheme == "" || u.Host == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
urls = append(urls, arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify URLs
|
||||||
|
if len(urls) != len(tt.expectedURLs) {
|
||||||
|
t.Errorf("Expected %d URLs, got %d", len(tt.expectedURLs), len(urls))
|
||||||
|
}
|
||||||
|
for i, expectedURL := range tt.expectedURLs {
|
||||||
|
if i >= len(urls) || urls[i] != expectedURL {
|
||||||
|
t.Errorf("Expected URL[%d] to be '%s', got '%s'", i, expectedURL, urls[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify flags
|
||||||
|
if len(flags) != len(tt.expectedFlags) {
|
||||||
|
t.Errorf("Expected %d flags, got %d", len(tt.expectedFlags), len(flags))
|
||||||
|
}
|
||||||
|
for i, expectedFlag := range tt.expectedFlags {
|
||||||
|
if i >= len(flags) || flags[i] != expectedFlag {
|
||||||
|
t.Errorf("Expected flag[%d] to be '%s', got '%s'", i, expectedFlag, flags[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
package ytdlp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
storcfg "github.com/krau/SaveAny-Bot/config/storage"
|
||||||
|
storenum "github.com/krau/SaveAny-Bot/pkg/enums/storage"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MockStorage is a simple mock for testing
|
||||||
|
type MockStorage struct{}
|
||||||
|
|
||||||
|
func (m *MockStorage) Init(ctx context.Context, cfg storcfg.StorageConfig) error { return nil }
|
||||||
|
func (m *MockStorage) Type() storenum.StorageType { return "mock" }
|
||||||
|
func (m *MockStorage) Name() string { return "test-storage" }
|
||||||
|
func (m *MockStorage) JoinStoragePath(p string) string { return "test-path" }
|
||||||
|
func (m *MockStorage) Save(ctx context.Context, reader io.Reader, path string) error { return nil }
|
||||||
|
func (m *MockStorage) Exists(ctx context.Context, path string) bool { return false }
|
||||||
|
|
||||||
|
func TestNewTask(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
urls := []string{"https://example.com/video"}
|
||||||
|
flags := []string{"--format", "best"}
|
||||||
|
stor := &MockStorage{}
|
||||||
|
storPath := "test-path"
|
||||||
|
|
||||||
|
task := NewTask("test-id", ctx, urls, flags, stor, storPath, nil)
|
||||||
|
|
||||||
|
if task == nil {
|
||||||
|
t.Fatal("NewTask returned nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if task.ID != "test-id" {
|
||||||
|
t.Errorf("Expected task ID 'test-id', got '%s'", task.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(task.URLs) != 1 || task.URLs[0] != "https://example.com/video" {
|
||||||
|
t.Errorf("Expected URLs to contain 'https://example.com/video', got %v", task.URLs)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(task.Flags) != 2 || task.Flags[0] != "--format" || task.Flags[1] != "best" {
|
||||||
|
t.Errorf("Expected flags to contain '--format' and 'best', got %v", task.Flags)
|
||||||
|
}
|
||||||
|
|
||||||
|
if task.Storage.Name() != "test-storage" {
|
||||||
|
t.Errorf("Expected storage name 'test-storage', got '%s'", task.Storage.Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewTaskWithoutFlags(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
urls := []string{"https://example.com/video1", "https://example.com/video2"}
|
||||||
|
var flags []string // No flags
|
||||||
|
stor := &MockStorage{}
|
||||||
|
storPath := "test-path"
|
||||||
|
|
||||||
|
task := NewTask("test-id-2", ctx, urls, flags, stor, storPath, nil)
|
||||||
|
|
||||||
|
if task == nil {
|
||||||
|
t.Fatal("NewTask returned nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(task.URLs) != 2 {
|
||||||
|
t.Errorf("Expected 2 URLs, got %d", len(task.URLs))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(task.Flags) != 0 {
|
||||||
|
t.Errorf("Expected 0 flags, got %d", len(task.Flags))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTaskTitle(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
stor := &MockStorage{}
|
||||||
|
|
||||||
|
// Test with single URL
|
||||||
|
task1 := NewTask("id1", ctx, []string{"https://example.com/video"}, nil, stor, "path", nil)
|
||||||
|
title1 := task1.Title()
|
||||||
|
if title1 == "" {
|
||||||
|
t.Error("Task title should not be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test with multiple URLs
|
||||||
|
task2 := NewTask("id2", ctx, []string{"https://example.com/v1", "https://example.com/v2"}, nil, stor, "path", nil)
|
||||||
|
title2 := task2.Title()
|
||||||
|
if title2 == "" {
|
||||||
|
t.Error("Task title should not be empty")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTaskType(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
stor := &MockStorage{}
|
||||||
|
task := NewTask("id", ctx, []string{"https://example.com"}, nil, stor, "path", nil)
|
||||||
|
|
||||||
|
taskType := task.Type()
|
||||||
|
if taskType.String() != "ytdlp" {
|
||||||
|
t.Errorf("Expected task type 'ytdlp', got '%s'", taskType.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTaskID(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
stor := &MockStorage{}
|
||||||
|
expectedID := "test-task-id-123"
|
||||||
|
|
||||||
|
task := NewTask(expectedID, ctx, []string{"https://example.com"}, nil, stor, "path", nil)
|
||||||
|
|
||||||
|
if task.TaskID() != expectedID {
|
||||||
|
t.Errorf("Expected task ID '%s', got '%s'", expectedID, task.TaskID())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package ctxkey
|
package ctxkey
|
||||||
|
|
||||||
//go:generate go-enum --values --names --flag --nocase --noprefix
|
|
||||||
// ENUM(content-length)
|
// ENUM(content-length)
|
||||||
|
//
|
||||||
|
//go:generate go-enum --values --names --flag --nocase --noprefix
|
||||||
type ContextKey string
|
type ContextKey string
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package tasktype
|
package tasktype
|
||||||
|
|
||||||
//go:generate go-enum --values --names --flag --nocase
|
|
||||||
// ENUM(tgfiles,tphpics,parseditem,directlinks,aria2,ytdlp)
|
// ENUM(tgfiles,tphpics,parseditem,directlinks,aria2,ytdlp)
|
||||||
|
//
|
||||||
|
//go:generate go-enum --values --names --flag --nocase
|
||||||
type TaskType string
|
type TaskType string
|
||||||
|
|||||||
Reference in New Issue
Block a user