| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105 |
- // SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
- // SPDX-License-Identifier: Apache-2.0
- package json // import "miniflux.app/v2/internal/reader/json"
- import (
- "bytes"
- "crypto/sha256"
- "encoding/hex"
- "testing"
- "time"
- )
- func TestParseJsonFeedVersion1(t *testing.T) {
- data := `{
- "version": "https://jsonfeed.org/version/1",
- "title": "My Example Feed",
- "icon": "https://micro.blog/jsonfeed/avatar.jpg",
- "favicon": "https://micro.blog/jsonfeed/favicon.png",
- "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": "<p>Hello, world!</p>",
- "url": "https://example.org/initial-post"
- }
- ]
- }`
- feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
- if err != nil {
- t.Fatal(err)
- }
- if feed.Title != "My Example Feed" {
- t.Errorf("Incorrect title, got: %s", feed.Title)
- }
- if feed.Description != "" {
- t.Errorf("Incorrect description, got: %s", feed.Description)
- }
- if feed.FeedURL != "https://example.org/feed.json" {
- t.Errorf("Incorrect feed URL, got: %s", feed.FeedURL)
- }
- if feed.SiteURL != "https://example.org/" {
- t.Errorf("Incorrect site URL, got: %s", feed.SiteURL)
- }
- if feed.IconURL != "https://micro.blog/jsonfeed/favicon.png" {
- t.Errorf("Incorrect icon URL, got: %s", feed.IconURL)
- }
- if len(feed.Entries) != 2 {
- t.Errorf("Incorrect number of entries, got: %d", len(feed.Entries))
- }
- if feed.Entries[0].Hash != "d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35" {
- t.Errorf("Incorrect entry hash, got: %s", feed.Entries[0].Hash)
- }
- if feed.Entries[0].URL != "https://example.org/second-item" {
- t.Errorf("Incorrect entry URL, got: %s", feed.Entries[0].URL)
- }
- if feed.Entries[0].Title != "This is a second item." {
- t.Errorf(`Incorrect entry title, got: "%s"`, feed.Entries[0].Title)
- }
- if feed.Entries[0].Content != "This is a second item." {
- t.Errorf("Incorrect entry content, got: %s", feed.Entries[0].Content)
- }
- if feed.Entries[1].Hash != "6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b" {
- t.Errorf("Incorrect entry hash, got: %s", feed.Entries[1].Hash)
- }
- if feed.Entries[1].URL != "https://example.org/initial-post" {
- t.Errorf("Incorrect entry URL, got: %s", feed.Entries[1].URL)
- }
- if feed.Entries[1].Title != "Hello, world!" {
- t.Errorf(`Incorrect entry title, got: "%s"`, feed.Entries[1].Title)
- }
- if feed.Entries[1].Content != "<p>Hello, world!</p>" {
- t.Errorf("Incorrect entry content, got: %s", feed.Entries[1].Content)
- }
- }
- func TestParseFeedWithDescription(t *testing.T) {
- data := `{
- "version": "https://jsonfeed.org/version/1",
- "title": "My Example Feed",
- "description": "This is a sample feed description.",
- "home_page_url": "https://example.org/",
- "feed_url": "https://example.org/feed.json",
- "items": []
- }`
- feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
- if err != nil {
- t.Fatal(err)
- }
- if feed.Description != "This is a sample feed description." {
- t.Errorf("Incorrect description, got: %s", feed.Description)
- }
- }
- func TestParsePodcast(t *testing.T) {
- data := `{
- "version": "https://jsonfeed.org/version/1",
- "user_comment": "This is a podcast feed. You can add this feed to your podcast client using the following URL: http://therecord.co/feed.json",
- "title": "The Record",
- "home_page_url": "http://therecord.co/",
- "feed_url": "http://therecord.co/feed.json",
- "items": [
- {
- "id": "http://therecord.co/chris-parrish",
- "title": "Special #1 - Chris Parrish",
- "url": "http://therecord.co/chris-parrish",
- "content_text": "Chris has worked at Adobe and as a founder of Rogue Sheep, which won an Apple Design Award for Postage. Chris’s new company is Aged & Distilled with Guy English — which shipped Napkin, a Mac app for visual collaboration. Chris is also the co-host of The Record. He lives on Bainbridge Island, a quick ferry ride from Seattle.",
- "content_html": "Chris has worked at <a href=\"http://adobe.com/\">Adobe</a> and as a founder of Rogue Sheep, which won an Apple Design Award for Postage. Chris’s new company is Aged & Distilled with Guy English — which shipped <a href=\"http://aged-and-distilled.com/napkin/\">Napkin</a>, a Mac app for visual collaboration. Chris is also the co-host of The Record. He lives on <a href=\"http://www.ci.bainbridge-isl.wa.us/\">Bainbridge Island</a>, a quick ferry ride from Seattle.",
- "summary": "Brent interviews Chris Parrish, co-host of The Record and one-half of Aged & Distilled.",
- "date_published": "2014-05-09T14:04:00-07:00",
- "attachments": [
- {
- "url": "http://therecord.co/downloads/The-Record-sp1e1-ChrisParrish.m4a",
- "mime_type": "audio/x-m4a",
- "size_in_bytes": 89970236,
- "duration_in_seconds": 6629
- }
- ]
- }
- ]
- }`
- feed, err := Parse("http://therecord.co/feed.json", bytes.NewBufferString(data))
- if err != nil {
- t.Fatal(err)
- }
- if feed.Title != "The Record" {
- t.Errorf("Incorrect title, got: %s", feed.Title)
- }
- if feed.FeedURL != "http://therecord.co/feed.json" {
- t.Errorf("Incorrect feed URL, got: %s", feed.FeedURL)
- }
- if feed.SiteURL != "http://therecord.co/" {
- t.Errorf("Incorrect site URL, got: %s", feed.SiteURL)
- }
- if len(feed.Entries) != 1 {
- t.Fatalf("Incorrect number of entries, got: %d", len(feed.Entries))
- }
- if feed.Entries[0].Hash != "6b678e57962a1b001e4e873756563cdc08bbd06ca561e764e0baa9a382485797" {
- t.Errorf("Incorrect entry hash, got: %s", feed.Entries[0].Hash)
- }
- if feed.Entries[0].URL != "http://therecord.co/chris-parrish" {
- t.Errorf("Incorrect entry URL, got: %s", feed.Entries[0].URL)
- }
- if feed.Entries[0].Title != "Special #1 - Chris Parrish" {
- t.Errorf(`Incorrect entry title, got: "%s"`, feed.Entries[0].Title)
- }
- if feed.Entries[0].Content != `Chris has worked at <a href="http://adobe.com/">Adobe</a> and as a founder of Rogue Sheep, which won an Apple Design Award for Postage. Chris’s new company is Aged & Distilled with Guy English — which shipped <a href="http://aged-and-distilled.com/napkin/">Napkin</a>, a Mac app for visual collaboration. Chris is also the co-host of The Record. He lives on <a href="http://www.ci.bainbridge-isl.wa.us/">Bainbridge Island</a>, a quick ferry ride from Seattle.` {
- t.Errorf(`Incorrect entry content, got: "%s"`, feed.Entries[0].Content)
- }
- location, _ := time.LoadLocation("America/Vancouver")
- if !feed.Entries[0].Date.Equal(time.Date(2014, time.May, 9, 14, 4, 0, 0, location)) {
- t.Errorf("Incorrect entry date, got: %v", feed.Entries[0].Date)
- }
- if len(feed.Entries[0].Enclosures) != 1 {
- t.Fatalf("Incorrect number of enclosures, got: %d", len(feed.Entries[0].Enclosures))
- }
- if feed.Entries[0].Enclosures[0].URL != "http://therecord.co/downloads/The-Record-sp1e1-ChrisParrish.m4a" {
- t.Errorf("Incorrect enclosure URL, got: %s", feed.Entries[0].Enclosures[0].URL)
- }
- if feed.Entries[0].Enclosures[0].MimeType != "audio/x-m4a" {
- t.Errorf("Incorrect enclosure type, got: %s", feed.Entries[0].Enclosures[0].MimeType)
- }
- if feed.Entries[0].Enclosures[0].Size != 89970236 {
- t.Errorf("Incorrect enclosure length, got: %d", feed.Entries[0].Enclosures[0].Size)
- }
- }
- func TestParseFeedWithFeedURLWithTrailingSpace(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": []
- }`
- feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
- if err != nil {
- t.Fatal(err)
- }
- if feed.FeedURL != "https://example.org/feed.json" {
- t.Errorf("Incorrect feed URL, got: %s", feed.FeedURL)
- }
- }
- func TestParseFeedWithRelativeFeedURL(t *testing.T) {
- data := `{
- "version": "https://jsonfeed.org/version/1",
- "title": "My Example Feed",
- "home_page_url": "https://example.org/",
- "feed_url": "/feed.json",
- "items": []
- }`
- feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
- if err != nil {
- t.Fatal(err)
- }
- if feed.FeedURL != "https://example.org/feed.json" {
- t.Errorf("Incorrect feed URL, got: %s", feed.FeedURL)
- }
- }
- func TestParseFeedSiteURLWithTrailingSpace(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": []
- }`
- feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
- if err != nil {
- t.Fatal(err)
- }
- if feed.SiteURL != "https://example.org/" {
- t.Errorf("Incorrect site URL, got: %s", feed.SiteURL)
- }
- }
- func TestParseFeedWithRelativeSiteURL(t *testing.T) {
- data := `{
- "version": "https://jsonfeed.org/version/1",
- "title": "My Example Feed",
- "home_page_url": "/home ",
- "feed_url": "https://example.org/feed.json",
- "items": []
- }`
- feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
- if err != nil {
- t.Fatal(err)
- }
- if feed.SiteURL != "https://example.org/home" {
- t.Errorf("Incorrect site URL, got: %s", feed.SiteURL)
- }
- }
- func TestParseFeedWithoutTitle(t *testing.T) {
- data := `{
- "version": "https://jsonfeed.org/version/1",
- "home_page_url": "https://example.org/",
- "feed_url": "https://example.org/feed.json",
- "items": [
- {
- "id": "2347259",
- "url": "https://example.org/2347259",
- "content_text": "Cats are neat. \n\nhttps://example.org/cats",
- "date_published": "2016-02-09T14:22:00-07:00"
- }
- ]
- }`
- feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
- if err != nil {
- t.Fatal(err)
- }
- if feed.Title != "https://example.org/" {
- t.Errorf("Incorrect title, got: %s", feed.Title)
- }
- }
- func TestParseFeedWithoutHomePage(t *testing.T) {
- data := `{
- "version": "https://jsonfeed.org/version/1",
- "feed_url": "https://example.org/feed.json",
- "title": "Some test",
- "items": [
- {
- "id": "2347259",
- "url": "https://example.org/2347259",
- "content_text": "Cats are neat. \n\nhttps://example.org/cats",
- "date_published": "2016-02-09T14:22:00-07:00"
- }
- ]
- }`
- feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
- if err != nil {
- t.Fatal(err)
- }
- if feed.SiteURL != "https://example.org/feed.json" {
- t.Errorf("Incorrect title, got: %s", feed.Title)
- }
- }
- func TestParseFeedWithoutFeedURL(t *testing.T) {
- data := `{
- "version": "https://jsonfeed.org/version/1",
- "title": "Some test",
- "items": [
- {
- "id": "2347259",
- "url": "https://example.org/2347259",
- "content_text": "Cats are neat. \n\nhttps://example.org/cats",
- "date_published": "2016-02-09T14:22:00-07:00"
- }
- ]
- }`
- feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
- if err != nil {
- t.Fatal(err)
- }
- if feed.SiteURL != "https://example.org/feed.json" {
- t.Errorf("Incorrect title, got: %s", feed.Title)
- }
- }
- func TestParseItemWithoutAttachmentURL(t *testing.T) {
- data := `{
- "version": "https://jsonfeed.org/version/1",
- "user_comment": "This is a podcast feed. You can add this feed to your podcast client using the following URL: http://therecord.co/feed.json",
- "title": "The Record",
- "home_page_url": "http://therecord.co/",
- "feed_url": "http://therecord.co/feed.json",
- "items": [
- {
- "id": "http://therecord.co/chris-parrish",
- "title": "Special #1 - Chris Parrish",
- "url": "http://therecord.co/chris-parrish",
- "content_text": "Chris has worked at Adobe and as a founder of Rogue Sheep, which won an Apple Design Award for Postage. Chris’s new company is Aged & Distilled with Guy English — which shipped Napkin, a Mac app for visual collaboration. Chris is also the co-host of The Record. He lives on Bainbridge Island, a quick ferry ride from Seattle.",
- "date_published": "2014-05-09T14:04:00-07:00",
- "attachments": [
- {
- "url": "",
- "mime_type": "audio/x-m4a",
- "size_in_bytes": 0
- }
- ]
- }
- ]
- }`
- feed, err := Parse("http://therecord.co/feed.json", bytes.NewBufferString(data))
- if err != nil {
- t.Fatal(err)
- }
- if len(feed.Entries) != 1 {
- t.Fatalf("Incorrect number of entries, got: %d", len(feed.Entries))
- }
- if len(feed.Entries[0].Enclosures) != 0 {
- t.Errorf("Incorrect number of enclosures, got: %d", len(feed.Entries[0].Enclosures))
- }
- }
- func TestParseItemWithRelativeURL(t *testing.T) {
- data := `{
- "version": "https://jsonfeed.org/version/1",
- "title": "Example",
- "home_page_url": "https://example.org/",
- "feed_url": "https://example.org/feed.json",
- "items": [
- {
- "id": "2347259",
- "url": "something.html",
- "date_published": "2016-02-09T14:22:00-07:00"
- }
- ]
- }`
- feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
- if err != nil {
- t.Fatal(err)
- }
- if feed.Entries[0].URL != "https://example.org/something.html" {
- t.Errorf("Incorrect entry URL, got: %s", feed.Entries[0].URL)
- }
- }
- func TestParseItemWithExternalURLAndNoURL(t *testing.T) {
- data := `{
- "version": "https://jsonfeed.org/version/1",
- "title": "Example",
- "home_page_url": "https://example.org/",
- "feed_url": "https://example.org/feed.json",
- "items": [
- {
- "id": "1234259",
- "external_url": "some_page.html"
- }
- ]
- }`
- feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
- if err != nil {
- t.Fatal(err)
- }
- if len(feed.Entries) != 1 {
- t.Fatalf("Incorrect number of entries, got: %d", len(feed.Entries))
- }
- if feed.Entries[0].URL != "https://example.org/some_page.html" {
- t.Errorf("Incorrect entry URL, got: %s", feed.Entries[0].URL)
- }
- }
- func TestParseItemWithExternalURLAndURL(t *testing.T) {
- data := `{
- "version": "https://jsonfeed.org/version/1",
- "title": "Example",
- "home_page_url": "https://example.org/",
- "feed_url": "https://example.org/feed.json",
- "items": [
- {
- "id": "1234259",
- "url": "https://example.org/article",
- "external_url": "https://example.org/another-article"
- }
- ]
- }`
- feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
- if err != nil {
- t.Fatal(err)
- }
- if len(feed.Entries) != 1 {
- t.Fatalf("Incorrect number of entries, got: %d", len(feed.Entries))
- }
- if feed.Entries[0].URL != "https://example.org/article" {
- t.Errorf("Incorrect entry URL, got: %s", feed.Entries[0].URL)
- }
- }
- func TestParseItemWithLegacyAuthorField(t *testing.T) {
- data := `{
- "version": "https://jsonfeed.org/version/1",
- "user_comment": "This is a microblog feed. You can add this to your feed reader using the following URL: https://example.org/feed.json",
- "title": "Brent Simmons’s Microblog",
- "home_page_url": "https://example.org/",
- "feed_url": "https://example.org/feed.json",
- "author": {
- "name": "Brent Simmons",
- "url": "http://example.org/",
- "avatar": "https://example.org/avatar.png"
- },
- "items": [
- {
- "id": "2347259",
- "url": "https://example.org/2347259",
- "content_text": "Cats are neat. \n\nhttps://example.org/cats",
- "date_published": "2016-02-09T14:22:00-07:00"
- }
- ]
- }`
- feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
- if err != nil {
- t.Fatal(err)
- }
- if len(feed.Entries) != 1 {
- t.Errorf("Incorrect number of entries, got: %d", len(feed.Entries))
- }
- if feed.Entries[0].Author != "Brent Simmons" {
- t.Errorf("Incorrect entry author, got: %s", feed.Entries[0].Author)
- }
- }
- func TestParseItemWithMultipleAuthorFields(t *testing.T) {
- data := `{
- "version": "https://jsonfeed.org/version/1.1",
- "user_comment": "This is a microblog feed. You can add this to your feed reader using the following URL: https://example.org/feed.json",
- "title": "Brent Simmons’s Microblog",
- "home_page_url": "https://example.org/",
- "feed_url": "https://example.org/feed.json",
- "author": {
- "name": "Deprecated Author Field",
- "url": "http://example.org/",
- "avatar": "https://example.org/avatar.png"
- },
- "authors": [
- {
- "name": "Brent Simmons",
- "url": "http://example.org/",
- "avatar": "https://example.org/avatar.png"
- }
- ],
- "items": [
- {
- "id": "2347259",
- "url": "https://example.org/2347259",
- "content_text": "Cats are neat. \n\nhttps://example.org/cats",
- "date_published": "2016-02-09T14:22:00-07:00"
- }
- ]
- }`
- feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
- if err != nil {
- t.Fatal(err)
- }
- if len(feed.Entries) != 1 {
- t.Errorf("Incorrect number of entries, got: %d", len(feed.Entries))
- }
- if feed.Entries[0].Author != "Brent Simmons, Deprecated Author Field" {
- t.Errorf("Incorrect entry author, got: %s", feed.Entries[0].Author)
- }
- }
- func TestParseItemWithMultipleDuplicateAuthors(t *testing.T) {
- data := `{
- "version": "https://jsonfeed.org/version/1.1",
- "title": "Example",
- "home_page_url": "https://example.org/",
- "feed_url": "https://example.org/feed.json",
- "items": [
- {
- "id": "2347259",
- "url": "https://example.org/2347259",
- "content_text": "Cats are neat. \n\nhttps://example.org/cats",
- "date_published": "2016-02-09T14:22:00-07:00",
- "authors": [
- {
- "name": "Author B",
- "url": "http://example.org/",
- "avatar": "https://example.org/avatar.png"
- },
- {
- "name": "Author A",
- "url": "http://example.org/",
- "avatar": "https://example.org/avatar.png"
- },
- {
- "name": "Author B",
- "url": "http://example.org/",
- "avatar": "https://example.org/avatar.png"
- }
- ]
- }
- ]
- }`
- feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
- if err != nil {
- t.Fatal(err)
- }
- if len(feed.Entries) != 1 {
- t.Errorf("Incorrect number of entries, got: %d", len(feed.Entries))
- }
- if feed.Entries[0].Author != "Author A, Author B" {
- t.Errorf("Incorrect entry author, got: %s", feed.Entries[0].Author)
- }
- }
- func TestParseItemWithAuthorsObject(t *testing.T) {
- data := `{
- "version": "https://jsonfeed.org/version/1.1",
- "title": "Example",
- "home_page_url": "https://example.org/",
- "feed_url": "https://example.org/feed.json",
- "items": [
- {
- "id": "1",
- "title": "Example Item",
- "url": "https://example.org/item",
- "date_published": "2020-01-02T03:04:05Z",
- "authors": {
- "name": "Example Author"
- }
- }
- ]
- }`
- feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
- if err != nil {
- t.Fatal(err)
- }
- if len(feed.Entries) != 1 {
- t.Fatalf("Incorrect number of entries, got: %d", len(feed.Entries))
- }
- if feed.Entries[0].Author != "Example Author" {
- t.Errorf("Incorrect entry author, got: %s", feed.Entries[0].Author)
- }
- }
- func TestParseItemWithInvalidDate(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": "2347259",
- "url": "https://example.org/2347259",
- "content_text": "Cats are neat. \n\nhttps://example.org/cats",
- "date_published": "Tomorrow"
- }
- ]
- }`
- feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
- if err != nil {
- t.Fatal(err)
- }
- if len(feed.Entries) != 1 {
- t.Errorf("Incorrect number of entries, got: %d", len(feed.Entries))
- }
- duration := time.Since(feed.Entries[0].Date)
- if duration.Seconds() > 1 {
- t.Errorf("Incorrect entry date, got: %v", feed.Entries[0].Date)
- }
- }
- func TestParseItemWithMissingTitleUsesSummaryFallback(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": [
- {
- "summary": "Summary title",
- "content_text": "Content text title",
- "content_html": "<p>HTML title</p>"
- }
- ]
- }`
- feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
- if err != nil {
- t.Fatal(err)
- }
- if len(feed.Entries) != 1 {
- t.Errorf("Incorrect number of entries, got: %d", len(feed.Entries))
- }
- if feed.Entries[0].Title != "Summary title" {
- t.Errorf("Incorrect entry title, got: %s", feed.Entries[0].Title)
- }
- }
- func TestParseItemWithMissingTitleUsesContentTextFallback(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": [
- {
- "summary": " ",
- "content_text": "Content text title",
- "content_html": "<p>HTML title</p>"
- }
- ]
- }`
- feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
- if err != nil {
- t.Fatal(err)
- }
- if len(feed.Entries) != 1 {
- t.Errorf("Incorrect number of entries, got: %d", len(feed.Entries))
- }
- if feed.Entries[0].Title != "Content text title" {
- t.Errorf("Incorrect entry title, got: %s", feed.Entries[0].Title)
- }
- }
- func TestParseItemWithMissingTitleUsesHTMLFallback(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": [
- {
- "summary": "",
- "content_text": "",
- "content_html": "<p>HTML title</p>"
- }
- ]
- }`
- feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
- if err != nil {
- t.Fatal(err)
- }
- if len(feed.Entries) != 1 {
- t.Errorf("Incorrect number of entries, got: %d", len(feed.Entries))
- }
- if feed.Entries[0].Title != "HTML title" {
- t.Errorf("Incorrect entry title, got: %s", feed.Entries[0].Title)
- }
- }
- func TestParseItemWithMissingTitleUsesURLFallback(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": [
- {
- "url": "https://example.org/item"
- }
- ]
- }`
- feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
- if err != nil {
- t.Fatal(err)
- }
- if len(feed.Entries) != 1 {
- t.Errorf("Incorrect number of entries, got: %d", len(feed.Entries))
- }
- if feed.Entries[0].Title != "https://example.org/item" {
- t.Errorf("Incorrect entry title, got: %s", feed.Entries[0].Title)
- }
- }
- func TestParseItemWithTooLongUnicodeTitle(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": [
- {
- "title": "I’m riding my electric bike and came across this castle. It’s called “Schloss Richmond”. 🚴♂️"
- }
- ]
- }`
- feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
- if err != nil {
- t.Fatal(err)
- }
- if len(feed.Entries) != 1 {
- t.Errorf("Incorrect number of entries, got: %d", len(feed.Entries))
- }
- if len(feed.Entries[0].Title) != 110 {
- t.Errorf("Incorrect entry title, got: %s", feed.Entries[0].Title)
- }
- if len([]rune(feed.Entries[0].Title)) != 93 {
- t.Errorf("Incorrect entry title, got: %s", feed.Entries[0].Title)
- }
- }
- func TestParseItemTitleWithXMLTags(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": [
- {
- "title": "</example>"
- }
- ]
- }`
- feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
- if err != nil {
- t.Fatal(err)
- }
- if len(feed.Entries) != 1 {
- t.Errorf("Incorrect number of entries, got: %d", len(feed.Entries))
- }
- if feed.Entries[0].Title != "</example>" {
- t.Errorf("Incorrect entry title, got: %s", feed.Entries[0].Title)
- }
- }
- func TestParseItemHashPrefersIDOverURL(t *testing.T) {
- data := `{
- "version": "https://jsonfeed.org/version/1",
- "title": "Example",
- "home_page_url": "https://example.org/",
- "feed_url": "https://example.org/feed.json",
- "items": [
- {
- "id": "id-value",
- "url": "https://example.org/article"
- }
- ]
- }`
- feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
- if err != nil {
- t.Fatal(err)
- }
- expected := sha256.Sum256([]byte("id-value"))
- if feed.Entries[0].Hash != hex.EncodeToString(expected[:]) {
- t.Errorf("Incorrect entry hash, got: %s", feed.Entries[0].Hash)
- }
- }
- func TestParseItemHashUsesURLWhenNoID(t *testing.T) {
- data := `{
- "version": "https://jsonfeed.org/version/1",
- "title": "Example",
- "home_page_url": "https://example.org/",
- "feed_url": "https://example.org/feed.json",
- "items": [
- {
- "url": "https://example.org/article"
- }
- ]
- }`
- feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
- if err != nil {
- t.Fatal(err)
- }
- expected := sha256.Sum256([]byte("https://example.org/article"))
- if feed.Entries[0].Hash != hex.EncodeToString(expected[:]) {
- t.Errorf("Incorrect entry hash, got: %s", feed.Entries[0].Hash)
- }
- }
- func TestParseItemHashUsesExternalURLFallback(t *testing.T) {
- data := `{
- "version": "https://jsonfeed.org/version/1",
- "title": "Example",
- "home_page_url": "https://example.org/",
- "feed_url": "https://example.org/feed.json",
- "items": [
- {
- "external_url": "https://example.org/external"
- }
- ]
- }`
- feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
- if err != nil {
- t.Fatal(err)
- }
- if len(feed.Entries) != 1 {
- t.Fatalf("Incorrect number of entries, got: %d", len(feed.Entries))
- }
- expected := sha256.Sum256([]byte("https://example.org/external"))
- if feed.Entries[0].Hash != hex.EncodeToString(expected[:]) {
- t.Errorf("Incorrect entry hash, got: %s", feed.Entries[0].Hash)
- }
- }
- func TestParseItemHashFallsBackToContent(t *testing.T) {
- data := `{
- "version": "https://jsonfeed.org/version/1",
- "title": "Example",
- "home_page_url": "https://example.org/",
- "feed_url": "https://example.org/feed.json",
- "items": [
- {
- "content_text": "Text",
- "content_html": "<p>HTML</p>",
- "summary": "Summary"
- }
- ]
- }`
- feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
- if err != nil {
- t.Fatal(err)
- }
- expected := sha256.Sum256([]byte("Text<p>HTML</p>Summary"))
- if feed.Entries[0].Hash != hex.EncodeToString(expected[:]) {
- t.Errorf("Incorrect entry hash, got: %s", feed.Entries[0].Hash)
- }
- }
- func TestParseItemTags(t *testing.T) {
- data := `{
- "version": "https://jsonfeed.org/version/1",
- "user_comment": "This is a microblog feed. You can add this to your feed reader using the following URL: https://example.org/feed.json",
- "title": "Brent Simmons’s Microblog",
- "home_page_url": "https://example.org/",
- "feed_url": "https://example.org/feed.json",
- "author": {
- "name": "Brent Simmons",
- "url": "http://example.org/",
- "avatar": "https://example.org/avatar.png"
- },
- "items": [
- {
- "id": "2347259",
- "url": "https://example.org/2347259",
- "content_text": "Cats are neat. \n\nhttps://example.org/cats",
- "date_published": "2016-02-09T14:22:00-07:00",
- "tags": [
- " tag 1",
- " ",
- "tag 2",
- "tag 2",
- "aaa"
- ]
- }
- ]
- }`
- feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
- if err != nil {
- t.Fatal(err)
- }
- if len(feed.Entries) != 1 {
- t.Errorf("Incorrect number of entries, got: %d", len(feed.Entries))
- }
- if len(feed.Entries[0].Tags) != 3 {
- t.Errorf("Incorrect number of Tags, got: %d", len(feed.Entries[0].Tags))
- }
- expected := []string{"aaa", "tag 1", "tag 2"}
- for i, tag := range feed.Entries[0].Tags {
- if tag != expected[i] {
- t.Errorf("Incorrect entry tag, got %q instead of %q", tag, expected[i])
- }
- }
- }
- func TestParseFeedFavicon(t *testing.T) {
- data := `{
- "version": "https://jsonfeed.org/version/1",
- "title": "My Example Feed",
- "favicon": "https://example.org/jsonfeed/favicon.png",
- "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": "<p>Hello, world!</p>",
- "url": "https://example.org/initial-post"
- }
- ]
- }`
- feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
- if err != nil {
- t.Fatal(err)
- }
- if feed.IconURL != "https://example.org/jsonfeed/favicon.png" {
- t.Errorf("Incorrect icon URL, got: %s", feed.IconURL)
- }
- }
- func TestParseFeedIcon(t *testing.T) {
- data := `{
- "version": "https://jsonfeed.org/version/1",
- "title": "My Example Feed",
- "icon": "https://example.org/jsonfeed/icon.png",
- "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": "<p>Hello, world!</p>",
- "url": "https://example.org/initial-post"
- }
- ]
- }`
- feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
- if err != nil {
- t.Fatal(err)
- }
- if feed.IconURL != "https://example.org/jsonfeed/icon.png" {
- t.Errorf("Incorrect icon URL, got: %s", feed.IconURL)
- }
- }
- func TestParseFeedWithRelativeAttachmentURL(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",
- "attachments": [
- {
- "url": " /attachment.mp3 ",
- "mime_type": "audio/mpeg",
- "size_in_bytes": 123456
- }
- ]
- }
- ]
- }`
- feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
- if err != nil {
- t.Fatal(err)
- }
- if len(feed.Entries[0].Enclosures) != 1 {
- t.Fatalf("Incorrect number of enclosures, got: %d", len(feed.Entries[0].Enclosures))
- }
- if feed.Entries[0].Enclosures[0].URL != "https://example.org/attachment.mp3" {
- t.Errorf("Incorrect enclosure URL, got: %q", feed.Entries[0].Enclosures[0].URL)
- }
- }
- func TestParseInvalidJSON(t *testing.T) {
- data := `garbage`
- _, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
- if err == nil {
- t.Error("Parse should returns an error")
- }
- }
- func TestParseNullJSONFeed(t *testing.T) {
- data := `null`
- feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
- if err != nil {
- t.Fatalf("Unexpected error when parsing null feed: %v", err)
- }
- if feed == nil {
- t.Fatalf("Feed should not be nil")
- }
- }
|