atom_10_test.go 41 KB

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