atom_10_test.go 43 KB

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