atom_10_test.go 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606
  1. // Copyright 2019 Frédéric Guillot. All rights reserved.
  2. // Use of this source code is governed by the Apache 2.0
  3. // license that can be found in the LICENSE file.
  4. package atom // import "miniflux.app/reader/atom"
  5. import (
  6. "bytes"
  7. "testing"
  8. "time"
  9. )
  10. func TestParseAtomSample(t *testing.T) {
  11. data := `<?xml version="1.0" encoding="utf-8"?>
  12. <feed xmlns="http://www.w3.org/2005/Atom">
  13. <title>Example Feed</title>
  14. <link href="http://example.org/"/>
  15. <updated>2003-12-13T18:30:02Z</updated>
  16. <author>
  17. <name>John Doe</name>
  18. </author>
  19. <id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>
  20. <entry>
  21. <title>Atom-Powered Robots Run Amok</title>
  22. <link href="http://example.org/2003/12/13/atom03"/>
  23. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  24. <updated>2003-12-13T18:30:02Z</updated>
  25. <summary>Some text.</summary>
  26. </entry>
  27. </feed>`
  28. feed, err := Parse("http://example.org/feed.xml", bytes.NewBufferString(data))
  29. if err != nil {
  30. t.Fatal(err)
  31. }
  32. if feed.Title != "Example Feed" {
  33. t.Errorf("Incorrect title, got: %s", feed.Title)
  34. }
  35. if feed.FeedURL != "http://example.org/feed.xml" {
  36. t.Errorf("Incorrect feed URL, got: %s", feed.FeedURL)
  37. }
  38. if feed.SiteURL != "http://example.org/" {
  39. t.Errorf("Incorrect site URL, got: %s", feed.SiteURL)
  40. }
  41. if len(feed.Entries) != 1 {
  42. t.Errorf("Incorrect number of entries, got: %d", len(feed.Entries))
  43. }
  44. if !feed.Entries[0].Date.Equal(time.Date(2003, time.December, 13, 18, 30, 2, 0, time.UTC)) {
  45. t.Errorf("Incorrect entry date, got: %v", feed.Entries[0].Date)
  46. }
  47. if feed.Entries[0].Hash != "3841e5cf232f5111fc5841e9eba5f4b26d95e7d7124902e0f7272729d65601a6" {
  48. t.Errorf("Incorrect entry hash, got: %s", feed.Entries[0].Hash)
  49. }
  50. if feed.Entries[0].URL != "http://example.org/2003/12/13/atom03" {
  51. t.Errorf("Incorrect entry URL, got: %s", feed.Entries[0].URL)
  52. }
  53. if feed.Entries[0].CommentsURL != "" {
  54. t.Errorf("Incorrect entry Comments URL, got: %s", feed.Entries[0].CommentsURL)
  55. }
  56. if feed.Entries[0].Title != "Atom-Powered Robots Run Amok" {
  57. t.Errorf("Incorrect entry title, got: %s", feed.Entries[0].Title)
  58. }
  59. if feed.Entries[0].Content != "Some text." {
  60. t.Errorf("Incorrect entry content, got: %s", feed.Entries[0].Content)
  61. }
  62. if feed.Entries[0].Author != "John Doe" {
  63. t.Errorf("Incorrect entry author, got: %s", feed.Entries[0].Author)
  64. }
  65. }
  66. func TestParseFeedWithoutTitle(t *testing.T) {
  67. data := `<?xml version="1.0" encoding="utf-8"?>
  68. <feed xmlns="http://www.w3.org/2005/Atom">
  69. <link rel="alternate" type="text/html" href="https://example.org/"/>
  70. <link rel="self" type="application/atom+xml" href="https://example.org/feed"/>
  71. <updated>2003-12-13T18:30:02Z</updated>
  72. </feed>`
  73. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  74. if err != nil {
  75. t.Fatal(err)
  76. }
  77. if feed.Title != "https://example.org/" {
  78. t.Errorf("Incorrect feed title, got: %s", feed.Title)
  79. }
  80. }
  81. func TestParseEntryWithoutTitleButWithURL(t *testing.T) {
  82. data := `<?xml version="1.0" encoding="utf-8"?>
  83. <feed xmlns="http://www.w3.org/2005/Atom">
  84. <title>Example Feed</title>
  85. <link href="http://example.org/"/>
  86. <updated>2003-12-13T18:30:02Z</updated>
  87. <author>
  88. <name>John Doe</name>
  89. </author>
  90. <id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>
  91. <entry>
  92. <link href="http://example.org/2003/12/13/atom03"/>
  93. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  94. <updated>2003-12-13T18:30:02Z</updated>
  95. </entry>
  96. </feed>`
  97. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  98. if err != nil {
  99. t.Fatal(err)
  100. }
  101. if feed.Entries[0].Title != "http://example.org/2003/12/13/atom03" {
  102. t.Errorf("Incorrect entry title, got: %s", feed.Entries[0].Title)
  103. }
  104. }
  105. func TestParseEntryWithoutTitleButWithSummary(t *testing.T) {
  106. data := `<?xml version="1.0" encoding="utf-8"?>
  107. <feed xmlns="http://www.w3.org/2005/Atom">
  108. <title>Example Feed</title>
  109. <link href="http://example.org/"/>
  110. <updated>2003-12-13T18:30:02Z</updated>
  111. <author>
  112. <name>John Doe</name>
  113. </author>
  114. <id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>
  115. <entry>
  116. <link href="http://example.org/2003/12/13/atom03"/>
  117. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  118. <updated>2003-12-13T18:30:02Z</updated>
  119. <summary>Some text.</summary>
  120. </entry>
  121. </feed>`
  122. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  123. if err != nil {
  124. t.Fatal(err)
  125. }
  126. if feed.Entries[0].Title != "Some text." {
  127. t.Errorf("Incorrect entry title, got: %s", feed.Entries[0].Title)
  128. }
  129. }
  130. func TestParseEntryWithoutTitleButWithXHTMLContent(t *testing.T) {
  131. data := `<?xml version="1.0" encoding="utf-8"?>
  132. <feed xmlns="http://www.w3.org/2005/Atom">
  133. <title>Example Feed</title>
  134. <link href="http://example.org/"/>
  135. <updated>2003-12-13T18:30:02Z</updated>
  136. <author>
  137. <name>John Doe</name>
  138. </author>
  139. <id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>
  140. <entry>
  141. <link href="http://example.org/2003/12/13/atom03"/>
  142. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  143. <updated>2003-12-13T18:30:02Z</updated>
  144. <content type="xhtml">
  145. <div xmlns="http://www.w3.org/1999/xhtml">AT&amp;T bought <b>by SBC</b>!</div>
  146. </content>
  147. </entry>
  148. </feed>`
  149. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  150. if err != nil {
  151. t.Fatal(err)
  152. }
  153. if feed.Entries[0].Title != "AT&T bought by SBC!" {
  154. t.Errorf("Incorrect entry title, got: %s", feed.Entries[0].Title)
  155. }
  156. }
  157. func TestParseFeedURL(t *testing.T) {
  158. data := `<?xml version="1.0" encoding="utf-8"?>
  159. <feed xmlns="http://www.w3.org/2005/Atom">
  160. <title>Example Feed</title>
  161. <link rel="alternate" type="text/html" href="https://example.org/"/>
  162. <link rel="self" type="application/atom+xml" href="https://example.org/feed"/>
  163. <updated>2003-12-13T18:30:02Z</updated>
  164. </feed>`
  165. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  166. if err != nil {
  167. t.Fatal(err)
  168. }
  169. if feed.SiteURL != "https://example.org/" {
  170. t.Errorf("Incorrect site URL, got: %s", feed.SiteURL)
  171. }
  172. if feed.FeedURL != "https://example.org/feed" {
  173. t.Errorf("Incorrect feed URL, got: %s", feed.FeedURL)
  174. }
  175. }
  176. func TestParseFeedWithRelativeURL(t *testing.T) {
  177. data := `<?xml version="1.0" encoding="utf-8"?>
  178. <feed xmlns="http://www.w3.org/2005/Atom">
  179. <title>Example Feed</title>
  180. <link href="/blog/atom.xml" rel="self" type="application/atom+xml"/>
  181. <link href="/blog"/>
  182. <entry>
  183. <title>Test</title>
  184. <link href="/blog/article.html"/>
  185. <link href="/blog/article.html" rel="alternate" type="text/html"/>
  186. <id>/blog/article.html</id>
  187. <updated>2003-12-13T18:30:02Z</updated>
  188. <summary>Some text.</summary>
  189. </entry>
  190. </feed>`
  191. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  192. if err != nil {
  193. t.Fatal(err)
  194. }
  195. if feed.FeedURL != "https://example.org/blog/atom.xml" {
  196. t.Errorf("Incorrect feed URL, got: %s", feed.FeedURL)
  197. }
  198. if feed.SiteURL != "https://example.org/blog" {
  199. t.Errorf("Incorrect site URL, got: %s", feed.SiteURL)
  200. }
  201. if feed.Entries[0].URL != "https://example.org/blog/article.html" {
  202. t.Errorf("Incorrect entry URL, got: %s", feed.Entries[0].URL)
  203. }
  204. }
  205. func TestParseEntryWithRelativeURL(t *testing.T) {
  206. data := `<?xml version="1.0" encoding="utf-8"?>
  207. <feed xmlns="http://www.w3.org/2005/Atom">
  208. <title>Example Feed</title>
  209. <link href="http://example.org/"/>
  210. <entry>
  211. <title>Test</title>
  212. <link href="something.html"/>
  213. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  214. <updated>2003-12-13T18:30:02Z</updated>
  215. <summary>Some text.</summary>
  216. </entry>
  217. </feed>`
  218. feed, err := Parse("https://example.net/", bytes.NewBufferString(data))
  219. if err != nil {
  220. t.Fatal(err)
  221. }
  222. if feed.Entries[0].URL != "http://example.org/something.html" {
  223. t.Errorf("Incorrect entry URL, got: %s", feed.Entries[0].URL)
  224. }
  225. }
  226. func TestParseEntryURLWithTextHTMLType(t *testing.T) {
  227. data := `<?xml version="1.0" encoding="utf-8"?>
  228. <feed xmlns="http://www.w3.org/2005/Atom">
  229. <title>Example Feed</title>
  230. <link href="http://example.org/"/>
  231. <entry>
  232. <title>Test</title>
  233. <link href="http://example.org/something.html" type="text/html"/>
  234. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  235. <updated>2003-12-13T18:30:02Z</updated>
  236. <summary>Some text.</summary>
  237. </entry>
  238. </feed>`
  239. feed, err := Parse("https://example.net/", bytes.NewBufferString(data))
  240. if err != nil {
  241. t.Fatal(err)
  242. }
  243. if feed.Entries[0].URL != "http://example.org/something.html" {
  244. t.Errorf("Incorrect entry URL, got: %s", feed.Entries[0].URL)
  245. }
  246. }
  247. func TestParseEntryURLWithNoRelAndNoType(t *testing.T) {
  248. data := `<?xml version="1.0" encoding="utf-8"?>
  249. <feed xmlns="http://www.w3.org/2005/Atom">
  250. <title>Example Feed</title>
  251. <link href="http://example.org/"/>
  252. <entry>
  253. <title>Test</title>
  254. <link href="http://example.org/something.html"/>
  255. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  256. <updated>2003-12-13T18:30:02Z</updated>
  257. <summary>Some text.</summary>
  258. </entry>
  259. </feed>`
  260. feed, err := Parse("https://example.net/", bytes.NewBufferString(data))
  261. if err != nil {
  262. t.Fatal(err)
  263. }
  264. if feed.Entries[0].URL != "http://example.org/something.html" {
  265. t.Errorf("Incorrect entry URL, got: %s", feed.Entries[0].URL)
  266. }
  267. }
  268. func TestParseEntryURLWithAlternateRel(t *testing.T) {
  269. data := `<?xml version="1.0" encoding="utf-8"?>
  270. <feed xmlns="http://www.w3.org/2005/Atom">
  271. <title>Example Feed</title>
  272. <link href="http://example.org/"/>
  273. <entry>
  274. <title>Test</title>
  275. <link href="http://example.org/something.html" rel="alternate"/>
  276. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  277. <updated>2003-12-13T18:30:02Z</updated>
  278. <summary>Some text.</summary>
  279. </entry>
  280. </feed>`
  281. feed, err := Parse("https://example.net/", bytes.NewBufferString(data))
  282. if err != nil {
  283. t.Fatal(err)
  284. }
  285. if feed.Entries[0].URL != "http://example.org/something.html" {
  286. t.Errorf("Incorrect entry URL, got: %s", feed.Entries[0].URL)
  287. }
  288. }
  289. func TestParseEntryTitleWithWhitespaces(t *testing.T) {
  290. data := `<?xml version="1.0" encoding="utf-8"?>
  291. <feed xmlns="http://www.w3.org/2005/Atom">
  292. <title>Example Feed</title>
  293. <link href="http://example.org/"/>
  294. <entry>
  295. <title>
  296. Some Title
  297. </title>
  298. <link href="http://example.org/2003/12/13/atom03"/>
  299. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  300. <updated>2003-12-13T18:30:02Z</updated>
  301. <summary>Some text.</summary>
  302. </entry>
  303. </feed>`
  304. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  305. if err != nil {
  306. t.Fatal(err)
  307. }
  308. if feed.Entries[0].Title != "Some Title" {
  309. t.Errorf("Incorrect entry title, got: %s", feed.Entries[0].Title)
  310. }
  311. }
  312. func TestParseEntryWithPlainTextTitle(t *testing.T) {
  313. data := `<?xml version="1.0" encoding="utf-8"?>
  314. <feed xmlns="http://www.w3.org/2005/Atom">
  315. <title>Example Feed</title>
  316. <link href="http://example.org/"/>
  317. <entry>
  318. <title type="text">AT&amp;T bought by SBC!</title>
  319. <link href="http://example.org/2003/12/13/atom03"/>
  320. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  321. <updated>2003-12-13T18:30:02Z</updated>
  322. <summary>Some text.</summary>
  323. </entry>
  324. <entry>
  325. <title>AT&amp;T bought by SBC!</title>
  326. <link href="http://example.org/2003/12/13/atom03"/>
  327. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  328. <updated>2003-12-13T18:30:02Z</updated>
  329. <summary>Some text.</summary>
  330. </entry>
  331. </feed>`
  332. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  333. if err != nil {
  334. t.Fatal(err)
  335. }
  336. expected := `AT&T bought by SBC!`
  337. for i := 0; i < 2; i++ {
  338. if feed.Entries[i].Title != expected {
  339. t.Errorf("Incorrect title for entry #%d, got: %q", i, feed.Entries[i].Title)
  340. }
  341. }
  342. }
  343. func TestParseEntryWithHTMLTitle(t *testing.T) {
  344. data := `<?xml version="1.0" encoding="utf-8"?>
  345. <feed xmlns="http://www.w3.org/2005/Atom">
  346. <title>Example Feed</title>
  347. <link href="http://example.org/"/>
  348. <entry>
  349. <title type="html">&lt;code&gt;Test&lt;/code&gt; Test</title>
  350. <link href="http://example.org/2003/12/13/atom03"/>
  351. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  352. <updated>2003-12-13T18:30:02Z</updated>
  353. <summary>Some text.</summary>
  354. </entry>
  355. <entry>
  356. <title type="html"><![CDATA[Test &#8220;Test&#8221;]]></title>
  357. <link href="http://example.org/2003/12/13/atom03"/>
  358. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  359. <updated>2003-12-13T18:30:02Z</updated>
  360. <summary>Some text.</summary>
  361. </entry>
  362. <entry>
  363. <title>
  364. <![CDATA[Entry title with space around CDATA]]>
  365. </title>
  366. <link href="http://example.org/2003/12/13/atom03"/>
  367. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  368. <updated>2003-12-13T18:30:02Z</updated>
  369. <summary>Some text.</summary>
  370. </entry>
  371. </feed>`
  372. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  373. if err != nil {
  374. t.Fatal(err)
  375. }
  376. if feed.Entries[0].Title != "<code>Test</code> Test" {
  377. t.Errorf("Incorrect entry title, got: %q", feed.Entries[0].Title)
  378. }
  379. if feed.Entries[1].Title != "Test “Test”" {
  380. t.Errorf("Incorrect entry title, got: %q", feed.Entries[1].Title)
  381. }
  382. if feed.Entries[2].Title != "Entry title with space around CDATA" {
  383. t.Errorf("Incorrect entry title, got: %q", feed.Entries[2].Title)
  384. }
  385. }
  386. func TestParseEntryWithXHTMLTitle(t *testing.T) {
  387. data := `<?xml version="1.0" encoding="utf-8"?>
  388. <feed xmlns="http://www.w3.org/2005/Atom">
  389. <title>Example Feed</title>
  390. <link href="http://example.org/"/>
  391. <entry>
  392. <title type="xhtml">
  393. <div xmlns="http://www.w3.org/1999/xhtml">
  394. This is <b>XHTML</b> content.
  395. </div>
  396. </title>
  397. <link href="http://example.org/b"/>
  398. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  399. <updated>2003-12-13T18:30:02Z</updated>
  400. <summary>Some text.</summary>
  401. </entry>
  402. </feed>`
  403. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  404. if err != nil {
  405. t.Fatal(err)
  406. }
  407. if feed.Entries[0].Title != `This is <b>XHTML</b> content.` {
  408. t.Errorf("Incorrect entry title, got: %q", feed.Entries[1].Title)
  409. }
  410. }
  411. func TestParseEntryWithEmptyXHTMLTitle(t *testing.T) {
  412. data := `<?xml version="1.0" encoding="utf-8"?>
  413. <feed xmlns="http://www.w3.org/2005/Atom">
  414. <title>Example Feed</title>
  415. <link href="http://example.org/"/>
  416. <entry>
  417. <title type="xhtml">
  418. <div xmlns="http://www.w3.org/1999/xhtml"/>
  419. </title>
  420. <link href="http://example.org/entry"/>
  421. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  422. <updated>2003-12-13T18:30:02Z</updated>
  423. </entry>
  424. </feed>`
  425. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  426. if err != nil {
  427. t.Fatal(err)
  428. }
  429. if feed.Entries[0].Title != `http://example.org/entry` {
  430. t.Errorf("Incorrect entry title, got: %q", feed.Entries[0].Title)
  431. }
  432. }
  433. func TestParseEntryWithXHTMLTitleWithoutDiv(t *testing.T) {
  434. data := `<?xml version="1.0" encoding="utf-8"?>
  435. <feed xmlns="http://www.w3.org/2005/Atom">
  436. <title>Example Feed</title>
  437. <link href="http://example.org/"/>
  438. <entry>
  439. <title type="xhtml">
  440. test
  441. </title>
  442. <link href="http://example.org/entry"/>
  443. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  444. <updated>2003-12-13T18:30:02Z</updated>
  445. </entry>
  446. </feed>`
  447. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  448. if err != nil {
  449. t.Fatal(err)
  450. }
  451. if feed.Entries[0].Title != `test` {
  452. t.Errorf("Incorrect entry title, got: %q", feed.Entries[0].Title)
  453. }
  454. }
  455. func TestParseEntryWithNumericCharacterReferenceTitle(t *testing.T) {
  456. data := `<?xml version="1.0" encoding="utf-8"?>
  457. <feed xmlns="http://www.w3.org/2005/Atom">
  458. <title>Example Feed</title>
  459. <link href="http://example.org/"/>
  460. <entry>
  461. <title>&#931; &#xDF;</title>
  462. <link href="http://example.org/2003/12/13/atom03"/>
  463. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  464. <updated>2003-12-13T18:30:02Z</updated>
  465. <summary>Some text.</summary>
  466. </entry>
  467. </feed>`
  468. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  469. if err != nil {
  470. t.Fatal(err)
  471. }
  472. if feed.Entries[0].Title != "Σ ß" {
  473. t.Errorf("Incorrect entry title, got: %q", feed.Entries[0].Title)
  474. }
  475. }
  476. func TestParseEntryWithDoubleEncodedEntitiesTitle(t *testing.T) {
  477. data := `<?xml version="1.0" encoding="utf-8"?>
  478. <feed xmlns="http://www.w3.org/2005/Atom">
  479. <title>Example Feed</title>
  480. <link href="http://example.org/"/>
  481. <entry>
  482. <title>&amp;#39;AT&amp;amp;T&amp;#39;</title>
  483. <link href="http://example.org/2003/12/13/atom03"/>
  484. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  485. <updated>2003-12-13T18:30:02Z</updated>
  486. <summary>Some text.</summary>
  487. </entry>
  488. </feed>`
  489. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  490. if err != nil {
  491. t.Fatal(err)
  492. }
  493. if feed.Entries[0].Title != `&#39;AT&amp;T&#39;` {
  494. t.Errorf("Incorrect entry title, got: %q", feed.Entries[0].Title)
  495. }
  496. }
  497. func TestParseEntryWithXHTMLSummary(t *testing.T) {
  498. data := `<?xml version="1.0" encoding="utf-8"?>
  499. <feed xmlns="http://www.w3.org/2005/Atom">
  500. <title>Example Feed</title>
  501. <link href="http://example.org/"/>
  502. <entry>
  503. <title type="xhtml">Example</title>
  504. <link href="http://example.org/2003/12/13/atom03"/>
  505. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  506. <updated>2003-12-13T18:30:02Z</updated>
  507. <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Test: <code>std::unique_ptr&lt;S&gt;</code></p></div></summary>
  508. </entry>
  509. </feed>`
  510. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  511. if err != nil {
  512. t.Fatal(err)
  513. }
  514. if feed.Entries[0].Content != `<p>Test: <code>std::unique_ptr&lt;S&gt;</code></p>` {
  515. t.Errorf("Incorrect entry content, got: %s", feed.Entries[1].Content)
  516. }
  517. }
  518. func TestParseEntryWithHTMLSummary(t *testing.T) {
  519. data := `<?xml version="1.0" encoding="utf-8"?>
  520. <feed xmlns="http://www.w3.org/2005/Atom">
  521. <title>Example Feed</title>
  522. <link href="http://example.org/"/>
  523. <entry>
  524. <title type="html">Example</title>
  525. <link href="http://example.org/1"/>
  526. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  527. <updated>2003-12-13T18:30:02Z</updated>
  528. <summary type="html">&lt;code&gt;std::unique_ptr&amp;lt;S&amp;gt;&lt;/code&gt;</summary>
  529. </entry>
  530. <entry>
  531. <title type="html">Example</title>
  532. <link href="http://example.org/2"/>
  533. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  534. <updated>2003-12-13T18:30:02Z</updated>
  535. <summary type="text/html">&lt;code&gt;std::unique_ptr&amp;lt;S&amp;gt;&lt;/code&gt;</summary>
  536. </entry>
  537. <entry>
  538. <title type="html">Example</title>
  539. <link href="http://example.org/3"/>
  540. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  541. <updated>2003-12-13T18:30:02Z</updated>
  542. <summary type="html"><![CDATA[<code>std::unique_ptr&lt;S&gt;</code>]]></summary>
  543. </entry>
  544. </feed>`
  545. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  546. if err != nil {
  547. t.Fatal(err)
  548. }
  549. expected := `<code>std::unique_ptr&lt;S&gt;</code>`
  550. for i := 0; i < 3; i++ {
  551. if feed.Entries[i].Content != expected {
  552. t.Errorf("Incorrect content for entry #%d, got: %q", i, feed.Entries[i].Content)
  553. }
  554. }
  555. }
  556. func TestParseEntryWithTextSummary(t *testing.T) {
  557. data := `<?xml version="1.0" encoding="utf-8"?>
  558. <feed xmlns="http://www.w3.org/2005/Atom">
  559. <title>Example Feed</title>
  560. <link href="http://example.org/"/>
  561. <entry>
  562. <title type="html">Example</title>
  563. <link href="http://example.org/a"/>
  564. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  565. <updated>2003-12-13T18:30:02Z</updated>
  566. <summary>AT&amp;T &lt;S&gt;</summary>
  567. </entry>
  568. <entry>
  569. <title type="html">Example</title>
  570. <link href="http://example.org/b"/>
  571. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  572. <updated>2003-12-13T18:30:02Z</updated>
  573. <summary type="text">AT&amp;T &lt;S&gt;</summary>
  574. </entry>
  575. <entry>
  576. <title type="html">Example</title>
  577. <link href="http://example.org/c"/>
  578. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  579. <updated>2003-12-13T18:30:02Z</updated>
  580. <summary type="text/plain">AT&amp;T &lt;S&gt;</summary>
  581. </entry>
  582. <entry>
  583. <title type="html">Example</title>
  584. <link href="http://example.org/d"/>
  585. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  586. <updated>2003-12-13T18:30:02Z</updated>
  587. <summary type="text"><![CDATA[AT&T <S>]]></summary>
  588. </entry>
  589. </feed>`
  590. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  591. if err != nil {
  592. t.Fatal(err)
  593. }
  594. expected := `AT&amp;T &lt;S&gt;`
  595. for i := 0; i < 4; i++ {
  596. if feed.Entries[i].Content != expected {
  597. t.Errorf("Incorrect content for entry #%d, got: %q", i, feed.Entries[i].Content)
  598. }
  599. }
  600. }
  601. func TestParseEntryWithTextContent(t *testing.T) {
  602. data := `<?xml version="1.0" encoding="utf-8"?>
  603. <feed xmlns="http://www.w3.org/2005/Atom">
  604. <title>Example Feed</title>
  605. <link href="http://example.org/"/>
  606. <entry>
  607. <title type="html">Example</title>
  608. <link href="http://example.org/a"/>
  609. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  610. <updated>2003-12-13T18:30:02Z</updated>
  611. <content>AT&amp;T &lt;S&gt;</content>
  612. </entry>
  613. <entry>
  614. <title type="html">Example</title>
  615. <link href="http://example.org/b"/>
  616. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  617. <updated>2003-12-13T18:30:02Z</updated>
  618. <content type="text">AT&amp;T &lt;S&gt;</content>
  619. </entry>
  620. <entry>
  621. <title type="html">Example</title>
  622. <link href="http://example.org/c"/>
  623. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  624. <updated>2003-12-13T18:30:02Z</updated>
  625. <content type="text/plain">AT&amp;T &lt;S&gt;</content>
  626. </entry>
  627. <entry>
  628. <title type="html">Example</title>
  629. <link href="http://example.org/d"/>
  630. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  631. <updated>2003-12-13T18:30:02Z</updated>
  632. <content><![CDATA[AT&T <S>]]></content>
  633. </entry>
  634. </feed>`
  635. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  636. if err != nil {
  637. t.Fatal(err)
  638. }
  639. expected := `AT&amp;T &lt;S&gt;`
  640. for i := 0; i < 4; i++ {
  641. if feed.Entries[i].Content != expected {
  642. t.Errorf("Incorrect content for entry #%d, got: %q", i, feed.Entries[i].Content)
  643. }
  644. }
  645. }
  646. func TestParseEntryWithHTMLContent(t *testing.T) {
  647. data := `<?xml version="1.0" encoding="utf-8"?>
  648. <feed xmlns="http://www.w3.org/2005/Atom">
  649. <title>Example Feed</title>
  650. <link href="http://example.org/"/>
  651. <entry>
  652. <title type="html">Example</title>
  653. <link href="http://example.org/a"/>
  654. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  655. <updated>2003-12-13T18:30:02Z</updated>
  656. <content type="html">AT&amp;amp;T bought &lt;b&gt;by SBC&lt;/b&gt;!</content>
  657. </entry>
  658. <entry>
  659. <title type="html">Example</title>
  660. <link href="http://example.org/b"/>
  661. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  662. <updated>2003-12-13T18:30:02Z</updated>
  663. <content type="text/html">AT&amp;amp;T bought &lt;b&gt;by SBC&lt;/b&gt;!</content>
  664. </entry>
  665. <entry>
  666. <title type="html">Example</title>
  667. <link href="http://example.org/c"/>
  668. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  669. <updated>2003-12-13T18:30:02Z</updated>
  670. <content type="html"><![CDATA[AT&amp;T bought <b>by SBC</b>!]]></content>
  671. </entry>
  672. </feed>`
  673. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  674. if err != nil {
  675. t.Fatal(err)
  676. }
  677. expected := `AT&amp;T bought <b>by SBC</b>!`
  678. for i := 0; i < 3; i++ {
  679. if feed.Entries[i].Content != expected {
  680. t.Errorf("Incorrect content for entry #%d, got: %q", i, feed.Entries[i].Content)
  681. }
  682. }
  683. }
  684. func TestParseEntryWithXHTMLContent(t *testing.T) {
  685. data := `<?xml version="1.0" encoding="utf-8"?>
  686. <feed xmlns="http://www.w3.org/2005/Atom">
  687. <title>Example Feed</title>
  688. <link href="http://example.org/"/>
  689. <entry>
  690. <title>Example</title>
  691. <link href="http://example.org/2003/12/13/atom03"/>
  692. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  693. <updated>2003-12-13T18:30:02Z</updated>
  694. <content type="xhtml">
  695. <div xmlns="http://www.w3.org/1999/xhtml">AT&amp;T bought <b>by SBC</b>!</div>
  696. </content>
  697. </entry>
  698. </feed>`
  699. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  700. if err != nil {
  701. t.Fatal(err)
  702. }
  703. if feed.Entries[0].Content != `AT&amp;T bought <b>by SBC</b>!` {
  704. t.Errorf("Incorrect entry content, got: %q", feed.Entries[0].Content)
  705. }
  706. }
  707. func TestParseEntryWithAuthorName(t *testing.T) {
  708. data := `<?xml version="1.0" encoding="utf-8"?>
  709. <feed xmlns="http://www.w3.org/2005/Atom">
  710. <title>Example Feed</title>
  711. <link href="http://example.org/"/>
  712. <entry>
  713. <link href="http://example.org/2003/12/13/atom03"/>
  714. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  715. <updated>2003-12-13T18:30:02Z</updated>
  716. <summary>Some text.</summary>
  717. <author>
  718. <name>Me</name>
  719. <email>me@localhost</email>
  720. </author>
  721. </entry>
  722. </feed>`
  723. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  724. if err != nil {
  725. t.Fatal(err)
  726. }
  727. if feed.Entries[0].Author != "Me" {
  728. t.Errorf("Incorrect entry author, got: %s", feed.Entries[0].Author)
  729. }
  730. }
  731. func TestParseEntryWithoutAuthorName(t *testing.T) {
  732. data := `<?xml version="1.0" encoding="utf-8"?>
  733. <feed xmlns="http://www.w3.org/2005/Atom">
  734. <title>Example Feed</title>
  735. <link href="http://example.org/"/>
  736. <entry>
  737. <link href="http://example.org/2003/12/13/atom03"/>
  738. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  739. <updated>2003-12-13T18:30:02Z</updated>
  740. <summary>Some text.</summary>
  741. <author>
  742. <name/>
  743. <email>me@localhost</email>
  744. </author>
  745. </entry>
  746. </feed>`
  747. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  748. if err != nil {
  749. t.Fatal(err)
  750. }
  751. if feed.Entries[0].Author != "me@localhost" {
  752. t.Errorf("Incorrect entry author, got: %s", feed.Entries[0].Author)
  753. }
  754. }
  755. func TestParseEntryWithMultipleAuthors(t *testing.T) {
  756. data := `<?xml version="1.0" encoding="utf-8"?>
  757. <feed xmlns="http://www.w3.org/2005/Atom">
  758. <title>Example Feed</title>
  759. <link href="http://example.org/"/>
  760. <entry>
  761. <link href="http://example.org/2003/12/13/atom03"/>
  762. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  763. <updated>2003-12-13T18:30:02Z</updated>
  764. <summary>Some text.</summary>
  765. <author>
  766. <name>Alice</name>
  767. </author>
  768. <author>
  769. <name>Bob</name>
  770. </author>
  771. </entry>
  772. </feed>`
  773. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  774. if err != nil {
  775. t.Fatal(err)
  776. }
  777. if feed.Entries[0].Author != "Alice, Bob" {
  778. t.Errorf("Incorrect entry author, got: %s", feed.Entries[0].Author)
  779. }
  780. }
  781. func TestParseEntryWithoutAuthor(t *testing.T) {
  782. data := `<?xml version="1.0" encoding="utf-8"?>
  783. <feed xmlns="http://www.w3.org/2005/Atom">
  784. <title>Example Feed</title>
  785. <link href="http://example.org/"/>
  786. <author>
  787. <name>John Doe</name>
  788. </author>
  789. <entry>
  790. <link href="http://example.org/2003/12/13/atom03"/>
  791. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  792. <updated>2003-12-13T18:30:02Z</updated>
  793. <summary>Some text.</summary>
  794. </entry>
  795. </feed>`
  796. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  797. if err != nil {
  798. t.Fatal(err)
  799. }
  800. if feed.Entries[0].Author != "John Doe" {
  801. t.Errorf("Incorrect entry author, got: %s", feed.Entries[0].Author)
  802. }
  803. }
  804. func TestParseFeedWithMultipleAuthors(t *testing.T) {
  805. data := `<?xml version="1.0" encoding="utf-8"?>
  806. <feed xmlns="http://www.w3.org/2005/Atom">
  807. <title>Example Feed</title>
  808. <link href="http://example.org/"/>
  809. <author>
  810. <name>Alice</name>
  811. </author>
  812. <author>
  813. <name>Bob</name>
  814. </author>
  815. <entry>
  816. <link href="http://example.org/2003/12/13/atom03"/>
  817. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  818. <updated>2003-12-13T18:30:02Z</updated>
  819. <summary>Some text.</summary>
  820. </entry>
  821. </feed>`
  822. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  823. if err != nil {
  824. t.Fatal(err)
  825. }
  826. if feed.Entries[0].Author != "Alice, Bob" {
  827. t.Errorf("Incorrect entry author, got: %s", feed.Entries[0].Author)
  828. }
  829. }
  830. func TestParseFeedWithoutAuthor(t *testing.T) {
  831. data := `<?xml version="1.0" encoding="utf-8"?>
  832. <feed xmlns="http://www.w3.org/2005/Atom">
  833. <title>Example Feed</title>
  834. <link href="http://example.org/"/>
  835. <entry>
  836. <link href="http://example.org/2003/12/13/atom03"/>
  837. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  838. <updated>2003-12-13T18:30:02Z</updated>
  839. <summary>Some text.</summary>
  840. </entry>
  841. </feed>`
  842. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  843. if err != nil {
  844. t.Fatal(err)
  845. }
  846. if feed.Entries[0].Author != "" {
  847. t.Errorf("Incorrect entry author, got: %q", feed.Entries[0].Author)
  848. }
  849. }
  850. func TestParseEntryWithEnclosures(t *testing.T) {
  851. data := `<?xml version="1.0" encoding="utf-8"?>
  852. <feed xmlns="http://www.w3.org/2005/Atom">
  853. <id>http://www.example.org/myfeed</id>
  854. <title>My Podcast Feed</title>
  855. <updated>2005-07-15T12:00:00Z</updated>
  856. <author>
  857. <name>John Doe</name>
  858. </author>
  859. <link href="http://example.org" />
  860. <link rel="self" href="http://example.org/myfeed" />
  861. <entry>
  862. <id>http://www.example.org/entries/1</id>
  863. <title>Atom 1.0</title>
  864. <updated>2005-07-15T12:00:00Z</updated>
  865. <link href="http://www.example.org/entries/1" />
  866. <summary>An overview of Atom 1.0</summary>
  867. <link rel="enclosure"
  868. type="audio/mpeg"
  869. title="MP3"
  870. href="http://www.example.org/myaudiofile.mp3"
  871. length="1234" />
  872. <link rel="enclosure"
  873. type="application/x-bittorrent"
  874. title="BitTorrent"
  875. href="http://www.example.org/myaudiofile.torrent"
  876. length="4567" />
  877. <content type="xhtml">
  878. <div xmlns="http://www.w3.org/1999/xhtml">
  879. <h1>Show Notes</h1>
  880. <ul>
  881. <li>00:01:00 -- Introduction</li>
  882. <li>00:15:00 -- Talking about Atom 1.0</li>
  883. <li>00:30:00 -- Wrapping up</li>
  884. </ul>
  885. </div>
  886. </content>
  887. </entry>
  888. </feed>`
  889. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  890. if err != nil {
  891. t.Fatal(err)
  892. }
  893. if len(feed.Entries) != 1 {
  894. t.Errorf("Incorrect number of entries, got: %d", len(feed.Entries))
  895. }
  896. if feed.Entries[0].URL != "http://www.example.org/entries/1" {
  897. t.Errorf("Incorrect entry URL, got: %s", feed.Entries[0].URL)
  898. }
  899. if len(feed.Entries[0].Enclosures) != 2 {
  900. t.Fatalf("Incorrect number of enclosures, got: %d", len(feed.Entries[0].Enclosures))
  901. }
  902. expectedResults := []struct {
  903. url string
  904. mimeType string
  905. size int64
  906. }{
  907. {"http://www.example.org/myaudiofile.mp3", "audio/mpeg", 1234},
  908. {"http://www.example.org/myaudiofile.torrent", "application/x-bittorrent", 4567},
  909. }
  910. for index, enclosure := range feed.Entries[0].Enclosures {
  911. if expectedResults[index].url != enclosure.URL {
  912. t.Errorf(`Unexpected enclosure URL, got %q instead of %q`, enclosure.URL, expectedResults[index].url)
  913. }
  914. if expectedResults[index].mimeType != enclosure.MimeType {
  915. t.Errorf(`Unexpected enclosure type, got %q instead of %q`, enclosure.MimeType, expectedResults[index].mimeType)
  916. }
  917. if expectedResults[index].size != enclosure.Size {
  918. t.Errorf(`Unexpected enclosure size, got %d instead of %d`, enclosure.Size, expectedResults[index].size)
  919. }
  920. }
  921. }
  922. func TestParseEntryWithoutEnclosureURL(t *testing.T) {
  923. data := `<?xml version="1.0" encoding="utf-8"?>
  924. <feed xmlns="http://www.w3.org/2005/Atom">
  925. <id>http://www.example.org/myfeed</id>
  926. <title>My Podcast Feed</title>
  927. <updated>2005-07-15T12:00:00Z</updated>
  928. <link href="http://example.org" />
  929. <link rel="self" href="http://example.org/myfeed" />
  930. <entry>
  931. <id>http://www.example.org/entries/1</id>
  932. <title>Atom 1.0</title>
  933. <updated>2005-07-15T12:00:00Z</updated>
  934. <link href="http://www.example.org/entries/1" />
  935. <summary>An overview of Atom 1.0</summary>
  936. <link rel="enclosure" href="" length="0" />
  937. <content type="xhtml">Test</content>
  938. </entry>
  939. </feed>`
  940. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  941. if err != nil {
  942. t.Fatal(err)
  943. }
  944. if len(feed.Entries) != 1 {
  945. t.Errorf("Incorrect number of entries, got: %d", len(feed.Entries))
  946. }
  947. if feed.Entries[0].URL != "http://www.example.org/entries/1" {
  948. t.Errorf("Incorrect entry URL, got: %s", feed.Entries[0].URL)
  949. }
  950. if len(feed.Entries[0].Enclosures) != 0 {
  951. t.Fatalf("Incorrect number of enclosures, got: %d", len(feed.Entries[0].Enclosures))
  952. }
  953. }
  954. func TestParseEntryWithPublished(t *testing.T) {
  955. data := `<?xml version="1.0" encoding="utf-8"?>
  956. <feed xmlns="http://www.w3.org/2005/Atom">
  957. <title>Example Feed</title>
  958. <link href="http://example.org/"/>
  959. <entry>
  960. <link href="http://example.org/2003/12/13/atom03"/>
  961. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  962. <published>2003-12-13T18:30:02Z</published>
  963. <summary>Some text.</summary>
  964. </entry>
  965. </feed>`
  966. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  967. if err != nil {
  968. t.Fatal(err)
  969. }
  970. if !feed.Entries[0].Date.Equal(time.Date(2003, time.December, 13, 18, 30, 2, 0, time.UTC)) {
  971. t.Errorf("Incorrect entry date, got: %v", feed.Entries[0].Date)
  972. }
  973. }
  974. func TestParseEntryWithPublishedAndUpdated(t *testing.T) {
  975. data := `<?xml version="1.0" encoding="utf-8"?>
  976. <feed xmlns="http://www.w3.org/2005/Atom">
  977. <title>Example Feed</title>
  978. <link href="http://example.org/"/>
  979. <entry>
  980. <link href="http://example.org/2003/12/13/atom03"/>
  981. <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  982. <published>2002-11-12T18:30:02Z</published>
  983. <updated>2003-12-13T18:30:02Z</updated>
  984. <summary>Some text.</summary>
  985. </entry>
  986. </feed>`
  987. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  988. if err != nil {
  989. t.Fatal(err)
  990. }
  991. if !feed.Entries[0].Date.Equal(time.Date(2002, time.November, 12, 18, 30, 2, 0, time.UTC)) {
  992. t.Errorf("Incorrect entry date, got: %v", feed.Entries[0].Date)
  993. }
  994. }
  995. func TestParseInvalidXml(t *testing.T) {
  996. data := `garbage`
  997. _, err := Parse("https://example.org/", bytes.NewBufferString(data))
  998. if err == nil {
  999. t.Error("Parse should returns an error")
  1000. }
  1001. }
  1002. func TestParseTitleWithSingleQuote(t *testing.T) {
  1003. data := `
  1004. <?xml version="1.0" encoding="utf-8"?>
  1005. <feed xmlns="http://www.w3.org/2005/Atom">
  1006. <title>' or ’</title>
  1007. <link href="http://example.org/"/>
  1008. </feed>
  1009. `
  1010. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  1011. if err != nil {
  1012. t.Fatal(err)
  1013. }
  1014. if feed.Title != "' or ’" {
  1015. t.Errorf(`Incorrect title, got: %q`, feed.Title)
  1016. }
  1017. }
  1018. func TestParseTitleWithEncodedSingleQuote(t *testing.T) {
  1019. data := `
  1020. <?xml version="1.0" encoding="utf-8"?>
  1021. <feed xmlns="http://www.w3.org/2005/Atom">
  1022. <title type="html">Test&#39;s Blog</title>
  1023. <link href="http://example.org/"/>
  1024. </feed>
  1025. `
  1026. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  1027. if err != nil {
  1028. t.Fatal(err)
  1029. }
  1030. if feed.Title != "Test's Blog" {
  1031. t.Errorf(`Incorrect title, got: %q`, feed.Title)
  1032. }
  1033. }
  1034. func TestParseTitleWithSingleQuoteAndHTMLType(t *testing.T) {
  1035. data := `
  1036. <?xml version="1.0" encoding="utf-8"?>
  1037. <feed xmlns="http://www.w3.org/2005/Atom">
  1038. <title type="html">O’Hara</title>
  1039. <link href="http://example.org/"/>
  1040. </feed>
  1041. `
  1042. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  1043. if err != nil {
  1044. t.Fatal(err)
  1045. }
  1046. if feed.Title != "O’Hara" {
  1047. t.Errorf(`Incorrect title, got: %q`, feed.Title)
  1048. }
  1049. }
  1050. func TestParseWithHTMLEntity(t *testing.T) {
  1051. data := `
  1052. <?xml version="1.0" encoding="utf-8"?>
  1053. <feed xmlns="http://www.w3.org/2005/Atom">
  1054. <title>Example &nbsp; Feed</title>
  1055. <link href="http://example.org/"/>
  1056. </feed>
  1057. `
  1058. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  1059. if err != nil {
  1060. t.Fatal(err)
  1061. }
  1062. if feed.Title != "Example \u00a0 Feed" {
  1063. t.Errorf(`Incorrect title, got: %q`, feed.Title)
  1064. }
  1065. }
  1066. func TestParseWithInvalidCharacterEntity(t *testing.T) {
  1067. data := `
  1068. <?xml version="1.0" encoding="utf-8"?>
  1069. <feed xmlns="http://www.w3.org/2005/Atom">
  1070. <title>Example Feed</title>
  1071. <link href="http://example.org/a&b"/>
  1072. </feed>
  1073. `
  1074. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  1075. if err != nil {
  1076. t.Fatal(err)
  1077. }
  1078. if feed.SiteURL != "http://example.org/a&b" {
  1079. t.Errorf(`Incorrect URL, got: %q`, feed.SiteURL)
  1080. }
  1081. }
  1082. func TestParseMediaGroup(t *testing.T) {
  1083. data := `<?xml version="1.0" encoding="utf-8"?>
  1084. <feed xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
  1085. <id>http://www.example.org/myfeed</id>
  1086. <title>My Video Feed</title>
  1087. <updated>2005-07-15T12:00:00Z</updated>
  1088. <link href="http://example.org" />
  1089. <link rel="self" href="http://example.org/myfeed" />
  1090. <entry>
  1091. <id>http://www.example.org/entries/1</id>
  1092. <title>Some Video</title>
  1093. <updated>2005-07-15T12:00:00Z</updated>
  1094. <link href="http://www.example.org/entries/1" />
  1095. <media:group>
  1096. <media:title>Another title</media:title>
  1097. <media:content url="https://www.youtube.com/v/abcd" type="application/x-shockwave-flash" width="640" height="390"/>
  1098. <media:thumbnail url="https://example.org/thumbnail.jpg" width="480" height="360"/>
  1099. <media:description>Some description
  1100. A website: http://example.org/</media:description>
  1101. </media:group>
  1102. </entry>
  1103. </feed>`
  1104. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  1105. if err != nil {
  1106. t.Fatal(err)
  1107. }
  1108. if len(feed.Entries) != 1 {
  1109. t.Errorf("Incorrect number of entries, got: %d", len(feed.Entries))
  1110. }
  1111. if feed.Entries[0].URL != "http://www.example.org/entries/1" {
  1112. t.Errorf("Incorrect entry URL, got: %s", feed.Entries[0].URL)
  1113. }
  1114. if feed.Entries[0].Content != `Some description<br>A website: <a href="http://example.org/">http://example.org/</a>` {
  1115. t.Errorf("Incorrect entry content, got: %q", feed.Entries[0].Content)
  1116. }
  1117. if len(feed.Entries[0].Enclosures) != 2 {
  1118. t.Fatalf("Incorrect number of enclosures, got: %d", len(feed.Entries[0].Enclosures))
  1119. }
  1120. expectedResults := []struct {
  1121. url string
  1122. mimeType string
  1123. size int64
  1124. }{
  1125. {"https://example.org/thumbnail.jpg", "image/*", 0},
  1126. {"https://www.youtube.com/v/abcd", "application/x-shockwave-flash", 0},
  1127. }
  1128. for index, enclosure := range feed.Entries[0].Enclosures {
  1129. if expectedResults[index].url != enclosure.URL {
  1130. t.Errorf(`Unexpected enclosure URL, got %q instead of %q`, enclosure.URL, expectedResults[index].url)
  1131. }
  1132. if expectedResults[index].mimeType != enclosure.MimeType {
  1133. t.Errorf(`Unexpected enclosure type, got %q instead of %q`, enclosure.MimeType, expectedResults[index].mimeType)
  1134. }
  1135. if expectedResults[index].size != enclosure.Size {
  1136. t.Errorf(`Unexpected enclosure size, got %d instead of %d`, enclosure.Size, expectedResults[index].size)
  1137. }
  1138. }
  1139. }
  1140. func TestParseMediaElements(t *testing.T) {
  1141. data := `<?xml version="1.0" encoding="utf-8"?>
  1142. <feed xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
  1143. <id>http://www.example.org/myfeed</id>
  1144. <title>My Video Feed</title>
  1145. <updated>2005-07-15T12:00:00Z</updated>
  1146. <link href="http://example.org" />
  1147. <link rel="self" href="http://example.org/myfeed" />
  1148. <entry>
  1149. <id>http://www.example.org/entries/1</id>
  1150. <title>Some Video</title>
  1151. <updated>2005-07-15T12:00:00Z</updated>
  1152. <link href="http://www.example.org/entries/1" />
  1153. <media:title>Another title</media:title>
  1154. <media:content url="https://www.youtube.com/v/abcd" type="application/x-shockwave-flash" width="640" height="390"/>
  1155. <media:thumbnail url="https://example.org/thumbnail.jpg" width="480" height="360"/>
  1156. <media:description>Some description
  1157. A website: http://example.org/</media:description>
  1158. </entry>
  1159. </feed>`
  1160. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  1161. if err != nil {
  1162. t.Fatal(err)
  1163. }
  1164. if len(feed.Entries) != 1 {
  1165. t.Errorf("Incorrect number of entries, got: %d", len(feed.Entries))
  1166. }
  1167. if feed.Entries[0].URL != "http://www.example.org/entries/1" {
  1168. t.Errorf("Incorrect entry URL, got: %s", feed.Entries[0].URL)
  1169. }
  1170. if feed.Entries[0].Content != `Some description<br>A website: <a href="http://example.org/">http://example.org/</a>` {
  1171. t.Errorf("Incorrect entry content, got: %q", feed.Entries[0].Content)
  1172. }
  1173. if len(feed.Entries[0].Enclosures) != 2 {
  1174. t.Fatalf("Incorrect number of enclosures, got: %d", len(feed.Entries[0].Enclosures))
  1175. }
  1176. expectedResults := []struct {
  1177. url string
  1178. mimeType string
  1179. size int64
  1180. }{
  1181. {"https://example.org/thumbnail.jpg", "image/*", 0},
  1182. {"https://www.youtube.com/v/abcd", "application/x-shockwave-flash", 0},
  1183. }
  1184. for index, enclosure := range feed.Entries[0].Enclosures {
  1185. if expectedResults[index].url != enclosure.URL {
  1186. t.Errorf(`Unexpected enclosure URL, got %q instead of %q`, enclosure.URL, expectedResults[index].url)
  1187. }
  1188. if expectedResults[index].mimeType != enclosure.MimeType {
  1189. t.Errorf(`Unexpected enclosure type, got %q instead of %q`, enclosure.MimeType, expectedResults[index].mimeType)
  1190. }
  1191. if expectedResults[index].size != enclosure.Size {
  1192. t.Errorf(`Unexpected enclosure size, got %d instead of %d`, enclosure.Size, expectedResults[index].size)
  1193. }
  1194. }
  1195. }
  1196. func TestParseRepliesLinkRelationWithHTMLType(t *testing.T) {
  1197. data := `<?xml version="1.0" encoding="utf-8"?>
  1198. <feed xmlns="http://www.w3.org/2005/Atom"
  1199. xmlns:thr="http://purl.org/syndication/thread/1.0">
  1200. <id>http://www.example.org/myfeed</id>
  1201. <title>My Example Feed</title>
  1202. <updated>2005-07-28T12:00:00Z</updated>
  1203. <link href="http://www.example.org/myfeed" />
  1204. <author><name>James</name></author>
  1205. <entry>
  1206. <id>tag:entries.com,2005:1</id>
  1207. <title>My original entry</title>
  1208. <updated>2006-03-01T12:12:12Z</updated>
  1209. <link href="http://www.example.org/entries/1" />
  1210. <link rel="replies"
  1211. type="application/atom+xml"
  1212. href="http://www.example.org/mycommentsfeed.xml"
  1213. thr:count="10" thr:updated="2005-07-28T12:10:00Z" />
  1214. <link rel="replies"
  1215. type="text/html"
  1216. href="http://www.example.org/comments.html"
  1217. thr:count="10" thr:updated="2005-07-28T12:10:00Z" />
  1218. <summary>This is my original entry</summary>
  1219. </entry>
  1220. </feed>`
  1221. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  1222. if err != nil {
  1223. t.Fatal(err)
  1224. }
  1225. if len(feed.Entries) != 1 {
  1226. t.Errorf("Incorrect number of entries, got: %d", len(feed.Entries))
  1227. }
  1228. if feed.Entries[0].URL != "http://www.example.org/entries/1" {
  1229. t.Errorf("Incorrect entry URL, got: %s", feed.Entries[0].URL)
  1230. }
  1231. if feed.Entries[0].CommentsURL != "http://www.example.org/comments.html" {
  1232. t.Errorf("Incorrect entry comments URL, got: %s", feed.Entries[0].CommentsURL)
  1233. }
  1234. }
  1235. func TestParseRepliesLinkRelationWithXHTMLType(t *testing.T) {
  1236. data := `<?xml version="1.0" encoding="utf-8"?>
  1237. <feed xmlns="http://www.w3.org/2005/Atom"
  1238. xmlns:thr="http://purl.org/syndication/thread/1.0">
  1239. <id>http://www.example.org/myfeed</id>
  1240. <title>My Example Feed</title>
  1241. <updated>2005-07-28T12:00:00Z</updated>
  1242. <link href="http://www.example.org/myfeed" />
  1243. <author><name>James</name></author>
  1244. <entry>
  1245. <id>tag:entries.com,2005:1</id>
  1246. <title>My original entry</title>
  1247. <updated>2006-03-01T12:12:12Z</updated>
  1248. <link href="http://www.example.org/entries/1" />
  1249. <link rel="replies"
  1250. type="application/atom+xml"
  1251. href="http://www.example.org/mycommentsfeed.xml"
  1252. thr:count="10" thr:updated="2005-07-28T12:10:00Z" />
  1253. <link rel="replies"
  1254. type="application/xhtml+xml"
  1255. href="http://www.example.org/comments.xhtml"
  1256. thr:count="10" thr:updated="2005-07-28T12:10:00Z" />
  1257. <summary>This is my original entry</summary>
  1258. </entry>
  1259. </feed>`
  1260. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  1261. if err != nil {
  1262. t.Fatal(err)
  1263. }
  1264. if len(feed.Entries) != 1 {
  1265. t.Errorf("Incorrect number of entries, got: %d", len(feed.Entries))
  1266. }
  1267. if feed.Entries[0].URL != "http://www.example.org/entries/1" {
  1268. t.Errorf("Incorrect entry URL, got: %s", feed.Entries[0].URL)
  1269. }
  1270. if feed.Entries[0].CommentsURL != "http://www.example.org/comments.xhtml" {
  1271. t.Errorf("Incorrect entry comments URL, got: %s", feed.Entries[0].CommentsURL)
  1272. }
  1273. }
  1274. func TestParseRepliesLinkRelationWithNoType(t *testing.T) {
  1275. data := `<?xml version="1.0" encoding="utf-8"?>
  1276. <feed xmlns="http://www.w3.org/2005/Atom"
  1277. xmlns:thr="http://purl.org/syndication/thread/1.0">
  1278. <id>http://www.example.org/myfeed</id>
  1279. <title>My Example Feed</title>
  1280. <updated>2005-07-28T12:00:00Z</updated>
  1281. <link href="http://www.example.org/myfeed" />
  1282. <author><name>James</name></author>
  1283. <entry>
  1284. <id>tag:entries.com,2005:1</id>
  1285. <title>My original entry</title>
  1286. <updated>2006-03-01T12:12:12Z</updated>
  1287. <link href="http://www.example.org/entries/1" />
  1288. <link rel="replies"
  1289. href="http://www.example.org/mycommentsfeed.xml"
  1290. thr:count="10" thr:updated="2005-07-28T12:10:00Z" />
  1291. <summary>This is my original entry</summary>
  1292. </entry>
  1293. </feed>`
  1294. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  1295. if err != nil {
  1296. t.Fatal(err)
  1297. }
  1298. if len(feed.Entries) != 1 {
  1299. t.Errorf("Incorrect number of entries, got: %d", len(feed.Entries))
  1300. }
  1301. if feed.Entries[0].URL != "http://www.example.org/entries/1" {
  1302. t.Errorf("Incorrect entry URL, got: %s", feed.Entries[0].URL)
  1303. }
  1304. if feed.Entries[0].CommentsURL != "" {
  1305. t.Errorf("Incorrect entry comments URL, got: %s", feed.Entries[0].CommentsURL)
  1306. }
  1307. }
  1308. func TestAbsoluteCommentsURL(t *testing.T) {
  1309. data := `<?xml version="1.0" encoding="utf-8"?>
  1310. <feed xmlns="http://www.w3.org/2005/Atom"
  1311. xmlns:thr="http://purl.org/syndication/thread/1.0">
  1312. <id>http://www.example.org/myfeed</id>
  1313. <title>My Example Feed</title>
  1314. <updated>2005-07-28T12:00:00Z</updated>
  1315. <link href="http://www.example.org/myfeed" />
  1316. <author><name>James</name></author>
  1317. <entry>
  1318. <id>tag:entries.com,2005:1</id>
  1319. <title>My original entry</title>
  1320. <updated>2006-03-01T12:12:12Z</updated>
  1321. <link href="http://www.example.org/entries/1" />
  1322. <link rel="replies"
  1323. type="text/html"
  1324. href="invalid url"
  1325. thr:count="10" thr:updated="2005-07-28T12:10:00Z" />
  1326. <summary>This is my original entry</summary>
  1327. </entry>
  1328. </feed>`
  1329. feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
  1330. if err != nil {
  1331. t.Fatal(err)
  1332. }
  1333. if len(feed.Entries) != 1 {
  1334. t.Errorf("Incorrect number of entries, got: %d", len(feed.Entries))
  1335. }
  1336. if feed.Entries[0].URL != "http://www.example.org/entries/1" {
  1337. t.Errorf("Incorrect entry URL, got: %s", feed.Entries[0].URL)
  1338. }
  1339. if feed.Entries[0].CommentsURL != "" {
  1340. t.Errorf("Incorrect entry comments URL, got: %s", feed.Entries[0].CommentsURL)
  1341. }
  1342. }