// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved. // SPDX-License-Identifier: Apache-2.0 package parser // import "miniflux.app/v2/internal/reader/parser" import ( "os" "strings" "testing" ) func BenchmarkParse(b *testing.B) { var testCases = map[string][]string{ "large_atom.xml": {"https://dustri.org/b", ""}, "large_rss.xml": {"https://dustri.org/b", ""}, "small_atom.xml": {"https://github.com/miniflux/v2/commits/main", ""}, } for filename := range testCases { data, err := os.ReadFile("./testdata/" + filename) if err != nil { b.Fatalf(`Unable to read file %q: %v`, filename, err) } testCases[filename][1] = string(data) } for range b.N { for _, v := range testCases { ParseFeed(v[0], strings.NewReader(v[1])) } } } func FuzzParse(f *testing.F) { f.Add("https://z.org", ` Example Feed 2003-12-13T18:30:02Z John Doe urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6 a urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a 2003-12-13T18:30:02Z c `) f.Add("https://z.org", ` a http://z.org a http://z.org d Tue, 03 Jun 2003 09:39:21 GMT l `) f.Add("https://z.org", ` a http://z.org/ a / c `) f.Add("http://z.org", `{ "version": "http://jsonfeed.org/version/1", "title": "a", "home_page_url": "http://z.org/", "feed_url": "http://z.org/a.json", "items": [ {"id": "2","content_text": "a","url": "https://z.org/2"}, {"id": "1","content_html": " dive into mark 2003-12-13T18:30:02Z Mark Pilgrim Atom 0.3 snapshot tag:diveintomark.org,2003:3.2397 2003-12-13T08:29:29-04:00 2003-12-13T18:30:02Z It's a test HTML content

]]>
` feed, err := ParseFeed("https://example.org/", strings.NewReader(data)) if err != nil { t.Error(err) } if feed.Title != "dive into mark" { t.Errorf("Incorrect title, got: %s", feed.Title) } } func TestParseAtom10Feed(t *testing.T) { data := ` Example Feed 2003-12-13T18:30:02Z John Doe urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6 Atom-Powered Robots Run Amok urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a 2003-12-13T18:30:02Z Some text. ` feed, err := ParseFeed("https://example.org/", strings.NewReader(data)) if err != nil { t.Error(err) } if feed.Title != "Example Feed" { t.Errorf("Incorrect title, got: %s", feed.Title) } } func TestParseAtomFeedWithRelativeURL(t *testing.T) { data := ` Example Feed Test /blog/article.html 2003-12-13T18:30:02Z Some text. ` feed, err := ParseFeed("https://example.org/blog/atom.xml", strings.NewReader(data)) if err != nil { t.Fatal(err) } if feed.FeedURL != "https://example.org/blog/atom.xml" { t.Errorf("Incorrect feed URL, got: %s", feed.FeedURL) } if feed.SiteURL != "https://example.org/blog" { t.Errorf("Incorrect site URL, got: %s", feed.SiteURL) } if feed.Entries[0].URL != "https://example.org/blog/article.html" { t.Errorf("Incorrect entry URL, got: %s", feed.Entries[0].URL) } } func TestParseRSS(t *testing.T) { data := ` Liftoff News http://liftoff.msfc.nasa.gov/ Star City http://liftoff.msfc.nasa.gov/news/2003/news-starcity.asp How do Americans get ready to work with Russians aboard the International Space Station? They take a crash course in culture, language and protocol at Russia's <a href="http://howe.iki.rssi.ru/GCTC/gctc_e.htm">Star City</a>. Tue, 03 Jun 2003 09:39:21 GMT http://liftoff.msfc.nasa.gov/2003/06/03.html#item573 ` feed, err := ParseFeed("http://liftoff.msfc.nasa.gov/", strings.NewReader(data)) if err != nil { t.Error(err) } if feed.Title != "Liftoff News" { t.Errorf("Incorrect title, got: %s", feed.Title) } } func TestParseRSSFeedWithRelativeURL(t *testing.T) { data := ` Example Feed /blog Example Entry /blog/article.html Something Tue, 03 Jun 2003 09:39:21 GMT 1234 ` feed, err := ParseFeed("http://example.org/rss.xml", strings.NewReader(data)) if err != nil { t.Error(err) } if feed.Title != "Example Feed" { t.Errorf("Incorrect title, got: %s", feed.Title) } if feed.FeedURL != "http://example.org/rss.xml" { t.Errorf("Incorrect feed URL, got: %s", feed.FeedURL) } if feed.SiteURL != "http://example.org/blog" { t.Errorf("Incorrect site URL, got: %s", feed.SiteURL) } if feed.Entries[0].URL != "http://example.org/blog/article.html" { t.Errorf("Incorrect entry URL, got: %s", feed.Entries[0].URL) } } func TestParseRDF(t *testing.T) { data := ` RDF Example http://example.org/ Title http://example.org/item Test ` feed, err := ParseFeed("http://example.org/", strings.NewReader(data)) if err != nil { t.Error(err) } if feed.Title != "RDF Example" { t.Errorf("Incorrect title, got: %s", feed.Title) } } func TestParseRDFWithRelativeURL(t *testing.T) { data := ` RDF Example /blog Title /blog/article.html Test ` feed, err := ParseFeed("http://example.org/rdf.xml", strings.NewReader(data)) if err != nil { t.Error(err) } if feed.FeedURL != "http://example.org/rdf.xml" { t.Errorf("Incorrect feed URL, got: %s", feed.FeedURL) } if feed.SiteURL != "http://example.org/blog" { t.Errorf("Incorrect site URL, got: %s", feed.SiteURL) } if feed.Entries[0].URL != "http://example.org/blog/article.html" { t.Errorf("Incorrect entry URL, got: %s", feed.Entries[0].URL) } } func TestParseJson(t *testing.T) { data := `{ "version": "https://jsonfeed.org/version/1", "title": "My Example Feed", "home_page_url": "https://example.org/", "feed_url": "https://example.org/feed.json", "items": [ { "id": "2", "content_text": "This is a second item.", "url": "https://example.org/second-item" }, { "id": "1", "content_html": "

Hello, world!

", "url": "https://example.org/initial-post" } ] }` feed, err := ParseFeed("https://example.org/feed.json", strings.NewReader(data)) if err != nil { t.Error(err) } if feed.Title != "My Example Feed" { t.Errorf("Incorrect title, got: %s", feed.Title) } } func TestParseJsonFeedWithRelativeURL(t *testing.T) { data := `{ "version": "https://jsonfeed.org/version/1", "title": "My Example Feed", "home_page_url": "/blog", "feed_url": "/blog/feed.json", "items": [ { "id": "2", "content_text": "This is a second item.", "url": "/blog/article.html" } ] }` feed, err := ParseFeed("https://example.org/blog/feed.json", strings.NewReader(data)) if err != nil { t.Error(err) } if feed.Title != "My Example Feed" { t.Errorf("Incorrect title, got: %s", feed.Title) } if feed.FeedURL != "https://example.org/blog/feed.json" { t.Errorf("Incorrect feed URL, got: %s", feed.FeedURL) } if feed.SiteURL != "https://example.org/blog" { t.Errorf("Incorrect site URL, got: %s", feed.SiteURL) } if feed.Entries[0].URL != "https://example.org/blog/article.html" { t.Errorf("Incorrect entry URL, got: %s", feed.Entries[0].URL) } } func TestParseUnknownFeed(t *testing.T) { data := ` Title of document some content ` _, err := ParseFeed("https://example.org/", strings.NewReader(data)) if err == nil { t.Error("ParseFeed must returns an error") } } func TestParseEmptyFeed(t *testing.T) { _, err := ParseFeed("", strings.NewReader("")) if err == nil { t.Error("ParseFeed must returns an error") } }