diff --git a/internal/reader/icon/finder_test.go b/internal/reader/icon/finder_test.go
index d30e69c6..161c3b65 100644
--- a/internal/reader/icon/finder_test.go
+++ b/internal/reader/icon/finder_test.go
@@ -112,22 +112,237 @@ func TestParseInvalidImageDataURLWithWrongPrefix(t *testing.T) {
}
}
-func TestParseDocumentWithWhitespaceIconURL(t *testing.T) {
- html := ``
+func TestFindIconURLsFromHTMLDocument_MultipleIcons(t *testing.T) {
+ html := `
+
+
+
+
+
+
+
+`
iconURLs, err := findIconURLsFromHTMLDocument(strings.NewReader(html), "text/html")
if err != nil {
t.Fatal(err)
}
- if len(iconURLs) != 1 {
- t.Fatalf(`Invalid number of icon URLs, got %d`, len(iconURLs))
+ expected := []string{
+ "/favicon.ico",
+ "/shortcut-favicon.ico",
+ "/icon-shortcut.ico",
+ "/apple-touch-icon.png",
}
- if iconURLs[0] != "/static/img/favicon.ico" {
- t.Errorf(`Invalid icon URL, got %q`, iconURLs[0])
+ if len(iconURLs) != len(expected) {
+ t.Fatalf("Expected %d icon URLs, got %d", len(expected), len(iconURLs))
+ }
+
+ for i, expectedURL := range expected {
+ if iconURLs[i] != expectedURL {
+ t.Errorf("Expected icon URL %d to be %q, got %q", i, expectedURL, iconURLs[i])
+ }
+ }
+}
+
+func TestFindIconURLsFromHTMLDocument_CaseInsensitiveRel(t *testing.T) {
+ html := `
+
+
+
+
+
+
+
+
+
+`
+
+ iconURLs, err := findIconURLsFromHTMLDocument(strings.NewReader(html), "text/html")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ expected := []string{
+ "/favicon1.ico",
+ "/favicon2.ico",
+ "/favicon3.ico",
+ "/favicon4.ico",
+ "/favicon5.ico",
+ "/favicon6.ico",
+ }
+
+ if len(iconURLs) != len(expected) {
+ t.Fatalf("Expected %d icon URLs, got %d", len(expected), len(iconURLs))
+ }
+
+ for i, expectedURL := range expected {
+ if iconURLs[i] != expectedURL {
+ t.Errorf("Expected icon URL %d to be %q, got %q", i, expectedURL, iconURLs[i])
+ }
+ }
+}
+
+func TestFindIconURLsFromHTMLDocument_NoIcons(t *testing.T) {
+ html := `
+
+
+ No Icons Here
+
+
+
+`
+
+ iconURLs, err := findIconURLsFromHTMLDocument(strings.NewReader(html), "text/html")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if len(iconURLs) != 0 {
+ t.Fatalf("Expected 0 icon URLs, got %d: %v", len(iconURLs), iconURLs)
+ }
+}
+
+func TestFindIconURLsFromHTMLDocument_EmptyHref(t *testing.T) {
+ html := `
+
+
+
+
+
+
+
+`
+
+ iconURLs, err := findIconURLsFromHTMLDocument(strings.NewReader(html), "text/html")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ expected := []string{"/valid-icon.ico"}
+
+ if len(iconURLs) != len(expected) {
+ t.Fatalf("Expected %d icon URLs, got %d", len(expected), len(iconURLs))
+ }
+
+ if iconURLs[0] != expected[0] {
+ t.Errorf("Expected icon URL to be %q, got %q", expected[0], iconURLs[0])
+ }
+}
+
+func TestFindIconURLsFromHTMLDocument_DataURLs(t *testing.T) {
+ html := `
+
+
+
+
+
+
+`
+
+ iconURLs, err := findIconURLsFromHTMLDocument(strings.NewReader(html), "text/html")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // The function processes queries in order: rel="icon", then rel="shortcut icon", etc.
+ // So both rel="icon" links are found first, then the rel="shortcut icon" link
+ expected := []string{
+ "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChAGAhGAQ+QAAAABJRU5ErkJggg==",
+ "/regular-icon.ico",
+ "data:image/svg+xml,",
+ }
+
+ if len(iconURLs) != len(expected) {
+ t.Fatalf("Expected %d icon URLs, got %d", len(expected), len(iconURLs))
+ }
+
+ for i, expectedURL := range expected {
+ if iconURLs[i] != expectedURL {
+ t.Errorf("Expected icon URL %d to be %q, got %q", i, expectedURL, iconURLs[i])
+ }
+ }
+}
+
+func TestFindIconURLsFromHTMLDocument_RelativeAndAbsoluteURLs(t *testing.T) {
+ html := `
+
+
+
+
+
+
+
+
+`
+
+ iconURLs, err := findIconURLsFromHTMLDocument(strings.NewReader(html), "text/html")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ expected := []string{
+ "/absolute-path.ico",
+ "relative-path.ico",
+ "../parent-dir.ico",
+ "https://example.com/external.ico",
+ "//cdn.example.com/protocol-relative.ico",
+ }
+
+ if len(iconURLs) != len(expected) {
+ t.Fatalf("Expected %d icon URLs, got %d", len(expected), len(iconURLs))
+ }
+
+ for i, expectedURL := range expected {
+ if iconURLs[i] != expectedURL {
+ t.Errorf("Expected icon URL %d to be %q, got %q", i, expectedURL, iconURLs[i])
+ }
+ }
+}
+
+func TestFindIconURLsFromHTMLDocument_InvalidHTML(t *testing.T) {
+ html := `
+
+
+
+
+
+`
+
+ iconURLs, err := findIconURLsFromHTMLDocument(strings.NewReader(html), "text/html")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // goquery should handle malformed HTML gracefully
+ if len(iconURLs) == 0 {
+ t.Fatal("Expected to find some icon URLs even with malformed HTML")
+ }
+
+ // Should at least find the valid ones
+ foundValidIcon := false
+ for _, url := range iconURLs {
+ if url == "/valid-before-error.ico" || url == "/valid-after-error.ico" {
+ foundValidIcon = true
+ break
+ }
+ }
+
+ if !foundValidIcon {
+ t.Errorf("Expected to find at least one valid icon URL, got: %v", iconURLs)
+ }
+}
+
+func TestFindIconURLsFromHTMLDocument_EmptyDocument(t *testing.T) {
+ iconURLs, err := findIconURLsFromHTMLDocument(strings.NewReader(""), "text/html")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if len(iconURLs) != 0 {
+ t.Fatalf("Expected 0 icon URLs from empty document, got %d", len(iconURLs))
}
}