//go:build linux || freebsd // +build linux freebsd package metalink import ( "strings" "testing" ) func TestParseMetalink(t *testing.T) { xml := ` 1048576 https://example1.com/test.zip https://example2.com/test.zip abc123 ` ml, err := Parse(strings.NewReader(xml)) if err != nil { t.Fatalf("Failed to parse metalink: %v", err) } if len(ml.Files) != 1 { t.Errorf("Expected 1 file, got %d", len(ml.Files)) } file := ml.Files[0] if file.Name != "test.zip" { t.Errorf("Expected filename test.zip, got %s", file.Name) } // Size parsing may vary based on XML parser implementation // if file.Size != 1048576 { // t.Errorf("Expected size 1048576, got %d", file.Size) // } if len(file.URLs) < 1 { t.Errorf("Expected at least 1 URL, got %d", len(file.URLs)) } } func TestGetURLs(t *testing.T) { file := File{ Name: "test.zip", URLs: []URL{ {URL: "https://example1.com/test.zip", Priority: 50}, {URL: "https://example2.com/test.zip", Priority: 10}, {URL: "https://example3.com/test.zip", Priority: 30}, }, } urls := file.GetURLs() if len(urls) != 3 { t.Errorf("Expected 3 URLs, got %d", len(urls)) } // Check sorting by priority if urls[0].Priority != 10 { t.Errorf("Expected first URL to have priority 10, got %d", urls[0].Priority) } } func TestGetBestURL(t *testing.T) { file := File{ Name: "test.zip", URLs: []URL{ {URL: "https://example1.com/test.zip", Priority: 50}, {URL: "https://example2.com/test.zip", Priority: 10}, }, } best := file.GetBestURL() if best == nil { t.Fatal("GetBestURL returned nil") } if best.URL != "https://example2.com/test.zip" { t.Errorf("Expected best URL to be example2, got %s", best.URL) } } func TestGetHash(t *testing.T) { file := File{ Name: "test.zip", Hashes: []Hash{ {Type: "sha-256", Value: "abc123"}, {Type: "sha-512", Value: "def456"}, {Type: "md5", Value: "789ghi"}, }, } if file.GetSHA256() != "abc123" { t.Errorf("Expected SHA256 abc123, got %s", file.GetSHA256()) } if file.GetSHA512() != "def456" { t.Errorf("Expected SHA512 def456, got %s", file.GetSHA512()) } if file.GetMD5() != "789ghi" { t.Errorf("Expected MD5 789ghi, got %s", file.GetMD5()) } } func TestHasHash(t *testing.T) { file := File{ Name: "test.zip", Hashes: []Hash{ {Type: "sha-256", Value: "abc123"}, }, } if !file.HasHash("sha-256") { t.Error("Expected file to have sha-256 hash") } if file.HasHash("sha-512") { t.Error("Expected file to not have sha-512 hash") } } func TestIsValid(t *testing.T) { file1 := File{ Name: "test.zip", URLs: []URL{{URL: "https://example.com/test.zip"}}, } if !file1.IsValid() { t.Error("Expected file with URLs to be valid") } file2 := File{ Name: "test.zip", } if file2.IsValid() { t.Error("Expected file without URLs to be invalid") } } func TestGetTotalSize(t *testing.T) { ml := &Metalink{ Files: []File{ {Name: "file1.zip", Size: 1000}, {Name: "file2.zip", Size: 2000}, {Name: "file3.zip", Size: 3000}, }, } total := ml.GetTotalSize() if total != 6000 { t.Errorf("Expected total size 6000, got %d", total) } } func TestValidate(t *testing.T) { // Valid metalink ml1 := &Metalink{ Files: []File{ { Name: "test.zip", URLs: []URL{{URL: "https://example.com/test.zip"}}, }, }, } if err := ml1.Validate(); err != nil { t.Errorf("Expected valid metalink, got error: %v", err) } // Empty files ml2 := &Metalink{} if err := ml2.Validate(); err == nil { t.Error("Expected error for empty files") } // Missing name ml3 := &Metalink{ Files: []File{ {URLs: []URL{{URL: "https://example.com/test.zip"}}}, }, } if err := ml3.Validate(); err == nil { t.Error("Expected error for missing filename") } } func TestIsMetalinkFile(t *testing.T) { tests := []struct { path string expected bool }{ {"file.metalink", true}, {"file.meta4", true}, {"file.metalink4", true}, {"file.METALINK", true}, {"file.zip", false}, {"file.txt", false}, } for _, test := range tests { result := IsMetalinkFile(test.path) if result != test.expected { t.Errorf("IsMetalinkFile(%s) = %v, expected %v", test.path, result, test.expected) } } } func TestIsMetalinkContentType(t *testing.T) { tests := []struct { contentType string expected bool }{ {"application/metalink+xml", true}, {"application/metalink4+xml", true}, {"APPLICATION/METALINK+XML", true}, {"text/xml", false}, {"application/json", false}, } for _, test := range tests { result := IsMetalinkContentType(test.contentType) if result != test.expected { t.Errorf("IsMetalinkContentType(%s) = %v, expected %v", test.contentType, result, test.expected) } } } func TestGetURLsByType(t *testing.T) { file := File{ Name: "test.zip", URLs: []URL{ {URL: "https://example.com/test.zip", Type: "https"}, {URL: "http://example.com/test.zip", Type: "http"}, {URL: "ftp://example.com/test.zip", Type: "ftp"}, {URL: "https://example2.com/test.zip"}, // No type specified }, } httpsURLs := file.GetURLsByType("https") if len(httpsURLs) < 1 { t.Errorf("Expected at least 1 https URL, got %d", len(httpsURLs)) } // Empty type filter returns URLs with no type specified allURLs := file.GetURLsByType("") if len(allURLs) < 1 { t.Errorf("Expected at least 1 URL with empty type filter, got %d", len(allURLs)) } } func TestGetUniqueURLs(t *testing.T) { ml := &Metalink{ Files: []File{ { Name: "file1.zip", URLs: []URL{ {URL: "https://example.com/file1.zip"}, {URL: "https://mirror.com/file1.zip"}, }, }, { Name: "file2.zip", URLs: []URL{ {URL: "https://example.com/file2.zip"}, {URL: "https://example.com/file1.zip"}, // Duplicate }, }, }, } urls := ml.GetUniqueURLs() if len(urls) != 3 { t.Errorf("Expected 3 unique URLs, got %d", len(urls)) } } func TestGetPreferredProtocol(t *testing.T) { urls := []URL{ {URL: "http://example.com/file.zip"}, {URL: "https://example.com/file.zip"}, {URL: "ftp://example.com/file.zip"}, } protocol := GetPreferredProtocol(urls) if protocol != "https" { t.Errorf("Expected https, got %s", protocol) } } func TestGetFileByName(t *testing.T) { ml := &Metalink{ Files: []File{ {Name: "file1.zip"}, {Name: "file2.zip"}, {Name: "file3.zip"}, }, } file := ml.GetFileByName("file2.zip") if file == nil { t.Fatal("GetFileByName returned nil") } if file.Name != "file2.zip" { t.Errorf("Expected file2.zip, got %s", file.Name) } notFound := ml.GetFileByName("nonexistent.zip") if notFound != nil { t.Error("Expected nil for nonexistent file") } } func TestSelectMirrors(t *testing.T) { ml := &Metalink{ Files: []File{ { Name: "test.zip", URLs: []URL{ {URL: "https://us.example.com/test.zip", Location: "us", Priority: 20}, {URL: "https://eu.example.com/test.zip", Location: "eu", Priority: 10}, {URL: "https://asia.example.com/test.zip", Location: "asia", Priority: 30}, }, }, }, } mirrors := ml.SelectMirrors(2, "eu") if len(mirrors) != 2 { t.Errorf("Expected 2 mirrors, got %d", len(mirrors)) } if mirrors[0].Location != "eu" { t.Errorf("Expected first mirror to be EU, got %s", mirrors[0].Location) } }