package main import ( "net/url" "testing" ) func TestIsYouTube(t *testing.T) { tests := []struct { raw string want bool }{ {"https://www.youtube.com/watch?v=dQw4w9WgXcQ", true}, {"https://youtu.be/dQw4w9WgXcQ?t=42", true}, {"https://www.youtube.com/shorts/abc_123", true}, {"https://youtube.com/live/abc-123", true}, {"https://m.youtube.com/watch?v=abc&feature=share", true}, {"https://www.youtube.com/", false}, {"https://www.youtube.com/watch?list=PL123", false}, {"https://youtube.com.evil.example/watch?v=abc", false}, {"https://example.com/", false}, } for _, tt := range tests { t.Run(tt.raw, func(t *testing.T) { u, err := url.Parse(tt.raw) if err != nil { t.Fatal(err) } if got := isYouTube(u); got != tt.want { t.Errorf("isYouTube(%q) = %v, want %v", tt.raw, got, tt.want) } }) } } func TestParseMetaTags(t *testing.T) { page := &fetched{ contentType: "text/html; charset=utf-8", body: []byte(` plain title `), } tags, err := parseMetaTags(page) if err != nil { t.Fatal(err) } want := map[string]string{ "title": "plain title", "description": "plain description", "og:title": "OGP タイトル", "og:description": "OGP の説明 & その続き", "og:image": "https://example.com/card.png", } for key, value := range want { if tags[key] != value { t.Errorf("tags[%q] = %q, want %q", key, tags[key], value) } } if got := tags.first("og:title", "twitter:title", "title"); got != "OGP タイトル" { t.Errorf("first title = %q, want the OGP one", got) } if got := tags.first("twitter:title", "title"); got != "plain title" { t.Errorf("first title = %q, want the fallback", got) } if got := tags.first("nothing:here"); got != "" { t.Errorf("first of an absent key = %q, want empty", got) } } func TestParseMetaTagsShiftJIS(t *testing.T) { // "テスト" encoded as Shift_JIS, declared in the Content-Type header. body := []byte(``) page := &fetched{contentType: "text/html; charset=Shift_JIS", body: body} tags, err := parseMetaTags(page) if err != nil { t.Fatal(err) } if tags["og:title"] != "テスト" { t.Errorf("og:title = %q, want テスト", tags["og:title"]) } } func TestParseMetaTagsTruncated(t *testing.T) { // A page cut off at maxHTMLBytes ends mid markup; what was read still counts. page := &fetched{ contentType: "text/html", body: []byte(`