content_rewrite_test.go 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101
  1. // SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
  2. // SPDX-License-Identifier: Apache-2.0
  3. package rewrite // import "miniflux.app/v2/internal/reader/rewrite"
  4. import (
  5. "os"
  6. "reflect"
  7. "strings"
  8. "testing"
  9. "miniflux.app/v2/internal/config"
  10. "miniflux.app/v2/internal/model"
  11. )
  12. func TestParseRules(t *testing.T) {
  13. rulesText := `add_dynamic_image,replace("article/(.*).svg"|"article/$1.png"),remove(".spam, .ads:not(.keep)")`
  14. expected := []rule{
  15. {name: "add_dynamic_image"},
  16. {name: "replace", args: []string{"article/(.*).svg", "article/$1.png"}},
  17. {name: "remove", args: []string{".spam, .ads:not(.keep)"}},
  18. }
  19. actual := parseRules(rulesText)
  20. if !reflect.DeepEqual(expected, actual) {
  21. t.Errorf(`Parsed rules do not match expected rules: got %v instead of %v`, actual, expected)
  22. }
  23. }
  24. func TestReplaceTextLinks(t *testing.T) {
  25. scenarios := map[string]string{
  26. `This is a link to example.org`: `This is a link to example.org`,
  27. `This is a link to ftp://example.org`: `This is a link to ftp://example.org`,
  28. `This is a link to www.example.org`: `This is a link to www.example.org`,
  29. `This is a link to http://example.org`: `This is a link to <a href="http://example.org">http://example.org</a>`,
  30. `This is a link to http://example.org, end of sentence.`: `This is a link to <a href="http://example.org">http://example.org</a>, end of sentence.`,
  31. `This is a link to https://example.org`: `This is a link to <a href="https://example.org">https://example.org</a>`,
  32. `This is a link to https://www.example.org/path/to?q=s`: `This is a link to <a href="https://www.example.org/path/to?q=s">https://www.example.org/path/to?q=s</a>`,
  33. `This is a link to https://example.org/index#hash-tag, http://example.org/.`: `This is a link to <a href="https://example.org/index#hash-tag">https://example.org/index#hash-tag</a>, <a href="http://example.org/">http://example.org/</a>.`,
  34. }
  35. for input, expected := range scenarios {
  36. actual := replaceTextLinks(input)
  37. if actual != expected {
  38. t.Errorf(`Unexpected link replacement, got "%s" instead of "%s"`, actual, expected)
  39. }
  40. }
  41. }
  42. func TestRewriteWithNoMatchingRule(t *testing.T) {
  43. controlEntry := &model.Entry{
  44. URL: "https://example.org/article",
  45. Title: `A title`,
  46. Content: `Some text.`,
  47. }
  48. testEntry := &model.Entry{
  49. URL: "https://example.org/article",
  50. Title: `A title`,
  51. Content: `Some text.`,
  52. }
  53. ApplyContentRewriteRules(testEntry, ``)
  54. if !reflect.DeepEqual(testEntry, controlEntry) {
  55. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  56. }
  57. }
  58. func TestRewriteYoutubeVideoLink(t *testing.T) {
  59. config.Opts = config.NewOptions()
  60. controlEntry := &model.Entry{
  61. URL: "https://www.youtube.com/watch?v=1234",
  62. Title: `A title`,
  63. Content: `<iframe width="650" height="350" frameborder="0" src="https://www.youtube-nocookie.com/embed/1234" allowfullscreen></iframe><br>Video Description`,
  64. }
  65. testEntry := &model.Entry{
  66. URL: "https://www.youtube.com/watch?v=1234",
  67. Title: `A title`,
  68. Content: `Video Description`,
  69. }
  70. ApplyContentRewriteRules(testEntry, ``)
  71. if !reflect.DeepEqual(testEntry, controlEntry) {
  72. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  73. }
  74. }
  75. func TestRewriteYoutubeShortLink(t *testing.T) {
  76. config.Opts = config.NewOptions()
  77. controlEntry := &model.Entry{
  78. URL: "https://www.youtube.com/shorts/1LUWKWZkPjo",
  79. Title: `A title`,
  80. Content: `<iframe width="650" height="350" frameborder="0" src="https://www.youtube-nocookie.com/embed/1LUWKWZkPjo" allowfullscreen></iframe><br>Video Description`,
  81. }
  82. testEntry := &model.Entry{
  83. URL: "https://www.youtube.com/shorts/1LUWKWZkPjo",
  84. Title: `A title`,
  85. Content: `Video Description`,
  86. }
  87. ApplyContentRewriteRules(testEntry, ``)
  88. if !reflect.DeepEqual(testEntry, controlEntry) {
  89. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  90. }
  91. }
  92. func TestRewriteIncorrectYoutubeLink(t *testing.T) {
  93. config.Opts = config.NewOptions()
  94. controlEntry := &model.Entry{
  95. URL: "https://www.youtube.com/some-page",
  96. Title: `A title`,
  97. Content: `Video Description`,
  98. }
  99. testEntry := &model.Entry{
  100. URL: "https://www.youtube.com/some-page",
  101. Title: `A title`,
  102. Content: `Video Description`,
  103. }
  104. ApplyContentRewriteRules(testEntry, ``)
  105. if !reflect.DeepEqual(testEntry, controlEntry) {
  106. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  107. }
  108. }
  109. func TestRewriteYoutubeLinkAndCustomEmbedURL(t *testing.T) {
  110. os.Clearenv()
  111. os.Setenv("YOUTUBE_EMBED_URL_OVERRIDE", "https://invidious.custom/embed/")
  112. var err error
  113. parser := config.NewParser()
  114. config.Opts, err = parser.ParseEnvironmentVariables()
  115. if err != nil {
  116. t.Fatalf(`Parsing failure: %v`, err)
  117. }
  118. controlEntry := &model.Entry{
  119. URL: "https://www.youtube.com/watch?v=1234",
  120. Title: `A title`,
  121. Content: `<iframe width="650" height="350" frameborder="0" src="https://invidious.custom/embed/1234" allowfullscreen></iframe><br>Video Description`,
  122. }
  123. testEntry := &model.Entry{
  124. URL: "https://www.youtube.com/watch?v=1234",
  125. Title: `A title`,
  126. Content: `Video Description`,
  127. }
  128. ApplyContentRewriteRules(testEntry, ``)
  129. if !reflect.DeepEqual(testEntry, controlEntry) {
  130. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  131. }
  132. }
  133. func TestRewriteYoutubeVideoLinkUsingInvidious(t *testing.T) {
  134. config.Opts = config.NewOptions()
  135. controlEntry := &model.Entry{
  136. URL: "https://www.youtube.com/watch?v=1234",
  137. Title: `A title`,
  138. Content: `<iframe width="650" height="350" frameborder="0" src="https://yewtu.be/embed/1234" allowfullscreen></iframe><br>Video Description`,
  139. }
  140. testEntry := &model.Entry{
  141. URL: "https://www.youtube.com/watch?v=1234",
  142. Title: `A title`,
  143. Content: `Video Description`,
  144. }
  145. ApplyContentRewriteRules(testEntry, `add_youtube_video_using_invidious_player`)
  146. if !reflect.DeepEqual(testEntry, controlEntry) {
  147. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  148. }
  149. }
  150. func TestRewriteYoutubeShortLinkUsingInvidious(t *testing.T) {
  151. config.Opts = config.NewOptions()
  152. controlEntry := &model.Entry{
  153. URL: "https://www.youtube.com/shorts/1LUWKWZkPjo",
  154. Title: `A title`,
  155. Content: `<iframe width="650" height="350" frameborder="0" src="https://yewtu.be/embed/1LUWKWZkPjo" allowfullscreen></iframe><br>Video Description`,
  156. }
  157. testEntry := &model.Entry{
  158. URL: "https://www.youtube.com/shorts/1LUWKWZkPjo",
  159. Title: `A title`,
  160. Content: `Video Description`,
  161. }
  162. ApplyContentRewriteRules(testEntry, `add_youtube_video_using_invidious_player`)
  163. if !reflect.DeepEqual(testEntry, controlEntry) {
  164. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  165. }
  166. }
  167. func TestRewriteWithInexistingCustomRule(t *testing.T) {
  168. controlEntry := &model.Entry{
  169. URL: "https://www.youtube.com/watch?v=1234",
  170. Title: `A title`,
  171. Content: `Video Description`,
  172. }
  173. testEntry := &model.Entry{
  174. URL: "https://www.youtube.com/watch?v=1234",
  175. Title: `A title`,
  176. Content: `Video Description`,
  177. }
  178. ApplyContentRewriteRules(testEntry, `some rule`)
  179. if !reflect.DeepEqual(testEntry, controlEntry) {
  180. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  181. }
  182. }
  183. func TestRewriteWithXkcdLink(t *testing.T) {
  184. controlEntry := &model.Entry{
  185. URL: "https://xkcd.com/1912/",
  186. Title: `A title`,
  187. Content: `<figure><img src="https://imgs.xkcd.com/comics/thermostat.png" alt="Your problem is so terrible, I worry that, if I help you, I risk drawing the attention of whatever god of technology inflicted it on you."/><figcaption><p>Your problem is so terrible, I worry that, if I help you, I risk drawing the attention of whatever god of technology inflicted it on you.</p></figcaption></figure>`,
  188. }
  189. testEntry := &model.Entry{
  190. URL: "https://xkcd.com/1912/",
  191. Title: `A title`,
  192. Content: `<img src="https://imgs.xkcd.com/comics/thermostat.png" title="Your problem is so terrible, I worry that, if I help you, I risk drawing the attention of whatever god of technology inflicted it on you." alt="Your problem is so terrible, I worry that, if I help you, I risk drawing the attention of whatever god of technology inflicted it on you." />`,
  193. }
  194. ApplyContentRewriteRules(testEntry, ``)
  195. if !reflect.DeepEqual(testEntry, controlEntry) {
  196. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  197. }
  198. }
  199. func TestRewriteWithXkcdLinkHtmlInjection(t *testing.T) {
  200. controlEntry := &model.Entry{
  201. URL: "https://xkcd.com/1912/",
  202. Title: `A title`,
  203. Content: `<figure><img src="https://imgs.xkcd.com/comics/thermostat.png" alt="&lt;foo&gt;"/><figcaption><p>&lt;foo&gt;</p></figcaption></figure>`,
  204. }
  205. testEntry := &model.Entry{
  206. URL: "https://xkcd.com/1912/",
  207. Title: `A title`,
  208. Content: `<img src="https://imgs.xkcd.com/comics/thermostat.png" title="<foo>" alt="<foo>" />`,
  209. }
  210. ApplyContentRewriteRules(testEntry, ``)
  211. if !reflect.DeepEqual(testEntry, controlEntry) {
  212. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  213. }
  214. }
  215. func TestRewriteWithXkcdLinkAndImageNoTitle(t *testing.T) {
  216. controlEntry := &model.Entry{
  217. URL: "https://xkcd.com/1912/",
  218. Title: `A title`,
  219. Content: `<img src="https://imgs.xkcd.com/comics/thermostat.png" alt="Your problem is so terrible, I worry that, if I help you, I risk drawing the attention of whatever god of technology inflicted it on you." />`,
  220. }
  221. testEntry := &model.Entry{
  222. URL: "https://xkcd.com/1912/",
  223. Title: `A title`,
  224. Content: `<img src="https://imgs.xkcd.com/comics/thermostat.png" alt="Your problem is so terrible, I worry that, if I help you, I risk drawing the attention of whatever god of technology inflicted it on you." />`,
  225. }
  226. ApplyContentRewriteRules(testEntry, ``)
  227. if !reflect.DeepEqual(testEntry, controlEntry) {
  228. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  229. }
  230. }
  231. func TestRewriteWithXkcdLinkAndNoImage(t *testing.T) {
  232. controlEntry := &model.Entry{
  233. URL: "https://xkcd.com/1912/",
  234. Title: `A title`,
  235. Content: `test`,
  236. }
  237. testEntry := &model.Entry{
  238. URL: "https://xkcd.com/1912/",
  239. Title: `A title`,
  240. Content: `test`,
  241. }
  242. ApplyContentRewriteRules(testEntry, ``)
  243. if !reflect.DeepEqual(testEntry, controlEntry) {
  244. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  245. }
  246. }
  247. func TestRewriteWithXkcdAndNoImage(t *testing.T) {
  248. controlEntry := &model.Entry{
  249. URL: "https://xkcd.com/1912/",
  250. Title: `A title`,
  251. Content: `test`,
  252. }
  253. testEntry := &model.Entry{
  254. URL: "https://xkcd.com/1912/",
  255. Title: `A title`,
  256. Content: `test`,
  257. }
  258. ApplyContentRewriteRules(testEntry, ``)
  259. if !reflect.DeepEqual(testEntry, controlEntry) {
  260. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  261. }
  262. }
  263. func TestRewriteMailtoLink(t *testing.T) {
  264. controlEntry := &model.Entry{
  265. URL: "https://www.qwantz.com/",
  266. Title: `A title`,
  267. Content: `<a href="mailto:ryan@qwantz.com?subject=blah%20blah">contact [blah blah]</a>`,
  268. }
  269. testEntry := &model.Entry{
  270. URL: "https://www.qwantz.com/",
  271. Title: `A title`,
  272. Content: `<a href="mailto:ryan@qwantz.com?subject=blah%20blah">contact</a>`,
  273. }
  274. ApplyContentRewriteRules(testEntry, ``)
  275. if !reflect.DeepEqual(testEntry, controlEntry) {
  276. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  277. }
  278. }
  279. func TestRewriteWithPDFLink(t *testing.T) {
  280. controlEntry := &model.Entry{
  281. URL: "https://example.org/document.pdf",
  282. Title: `A title`,
  283. Content: `<a href="https://example.org/document.pdf">PDF</a><br>test`,
  284. }
  285. testEntry := &model.Entry{
  286. URL: "https://example.org/document.pdf",
  287. Title: `A title`,
  288. Content: `test`,
  289. }
  290. ApplyContentRewriteRules(testEntry, ``)
  291. if !reflect.DeepEqual(testEntry, controlEntry) {
  292. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  293. }
  294. }
  295. func TestRewriteWithNoLazyImage(t *testing.T) {
  296. controlEntry := &model.Entry{
  297. URL: "https://example.org/article",
  298. Title: `A title`,
  299. Content: `<img src="https://example.org/image.jpg" alt="Image"><noscript><p>Some text</p></noscript>`,
  300. }
  301. testEntry := &model.Entry{
  302. URL: "https://example.org/article",
  303. Title: `A title`,
  304. Content: `<img src="https://example.org/image.jpg" alt="Image"><noscript><p>Some text</p></noscript>`,
  305. }
  306. ApplyContentRewriteRules(testEntry, "add_dynamic_image")
  307. if !reflect.DeepEqual(testEntry, controlEntry) {
  308. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  309. }
  310. }
  311. func TestRewriteWithLazyImage(t *testing.T) {
  312. controlEntry := &model.Entry{
  313. URL: "https://example.org/article",
  314. Title: `A title`,
  315. Content: `<img src="https://example.org/image.jpg" data-url="https://example.org/image.jpg" alt="Image"/><noscript><img src="https://example.org/fallback.jpg" alt="Fallback"/></noscript>`,
  316. }
  317. testEntry := &model.Entry{
  318. URL: "https://example.org/article",
  319. Title: `A title`,
  320. Content: `<img src="" data-url="https://example.org/image.jpg" alt="Image"><noscript><img src="https://example.org/fallback.jpg" alt="Fallback"></noscript>`,
  321. }
  322. ApplyContentRewriteRules(testEntry, "add_dynamic_image")
  323. if !reflect.DeepEqual(testEntry, controlEntry) {
  324. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  325. }
  326. }
  327. func TestRewriteWithLazyDivImage(t *testing.T) {
  328. controlEntry := &model.Entry{
  329. URL: "https://example.org/article",
  330. Title: `A title`,
  331. Content: `<img src="https://example.org/image.jpg" alt="Image"/><noscript><img src="https://example.org/fallback.jpg" alt="Fallback"/></noscript>`,
  332. }
  333. testEntry := &model.Entry{
  334. URL: "https://example.org/article",
  335. Title: `A title`,
  336. Content: `<div data-url="https://example.org/image.jpg" alt="Image"></div><noscript><img src="https://example.org/fallback.jpg" alt="Fallback"></noscript>`,
  337. }
  338. ApplyContentRewriteRules(testEntry, "add_dynamic_image")
  339. if !reflect.DeepEqual(testEntry, controlEntry) {
  340. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  341. }
  342. }
  343. func TestRewriteWithUnknownLazyNoScriptImage(t *testing.T) {
  344. controlEntry := &model.Entry{
  345. URL: "https://example.org/article",
  346. Title: `A title`,
  347. Content: `<img src="" data-non-candidate="https://example.org/image.jpg" alt="Image"/><img src="https://example.org/fallback.jpg" alt="Fallback"/>`,
  348. }
  349. testEntry := &model.Entry{
  350. URL: "https://example.org/article",
  351. Title: `A title`,
  352. Content: `<img src="" data-non-candidate="https://example.org/image.jpg" alt="Image"><noscript><img src="https://example.org/fallback.jpg" alt="Fallback"></noscript>`,
  353. }
  354. ApplyContentRewriteRules(testEntry, "add_dynamic_image")
  355. if !reflect.DeepEqual(testEntry, controlEntry) {
  356. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  357. }
  358. }
  359. func TestRewriteWithLazySrcset(t *testing.T) {
  360. controlEntry := &model.Entry{
  361. URL: "https://example.org/article",
  362. Title: `A title`,
  363. Content: `<img srcset="https://example.org/image.jpg" data-srcset="https://example.org/image.jpg" alt="Image"/>`,
  364. }
  365. testEntry := &model.Entry{
  366. URL: "https://example.org/article",
  367. Title: `A title`,
  368. Content: `<img srcset="" data-srcset="https://example.org/image.jpg" alt="Image">`,
  369. }
  370. ApplyContentRewriteRules(testEntry, "add_dynamic_image")
  371. if !reflect.DeepEqual(testEntry, controlEntry) {
  372. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  373. }
  374. }
  375. func TestRewriteWithImageAndLazySrcset(t *testing.T) {
  376. controlEntry := &model.Entry{
  377. URL: "https://example.org/article",
  378. Title: `A title`,
  379. Content: `<img src="meow" srcset="https://example.org/image.jpg" data-srcset="https://example.org/image.jpg" alt="Image"/>`,
  380. }
  381. testEntry := &model.Entry{
  382. URL: "https://example.org/article",
  383. Title: `A title`,
  384. Content: `<img src="meow" srcset="" data-srcset="https://example.org/image.jpg" alt="Image">`,
  385. }
  386. ApplyContentRewriteRules(testEntry, "add_dynamic_image")
  387. if !reflect.DeepEqual(testEntry, controlEntry) {
  388. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  389. }
  390. }
  391. func TestRewriteWithNoLazyIframe(t *testing.T) {
  392. controlEntry := &model.Entry{
  393. URL: "https://example.org/article",
  394. Title: `A title`,
  395. Content: `<iframe src="https://example.org/embed" allowfullscreen></iframe>`,
  396. }
  397. testEntry := &model.Entry{
  398. URL: "https://example.org/article",
  399. Title: `A title`,
  400. Content: `<iframe src="https://example.org/embed" allowfullscreen></iframe>`,
  401. }
  402. ApplyContentRewriteRules(testEntry, "add_dynamic_iframe")
  403. if !reflect.DeepEqual(testEntry, controlEntry) {
  404. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  405. }
  406. }
  407. func TestRewriteWithLazyIframe(t *testing.T) {
  408. controlEntry := &model.Entry{
  409. URL: "https://example.org/article",
  410. Title: `A title`,
  411. Content: `<iframe data-src="https://example.org/embed" allowfullscreen="" src="https://example.org/embed"></iframe>`,
  412. }
  413. testEntry := &model.Entry{
  414. URL: "https://example.org/article",
  415. Title: `A title`,
  416. Content: `<iframe data-src="https://example.org/embed" allowfullscreen></iframe>`,
  417. }
  418. ApplyContentRewriteRules(testEntry, "add_dynamic_iframe")
  419. if !reflect.DeepEqual(testEntry, controlEntry) {
  420. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  421. }
  422. }
  423. func TestRewriteWithLazyIframeAndSrc(t *testing.T) {
  424. controlEntry := &model.Entry{
  425. URL: "https://example.org/article",
  426. Title: `A title`,
  427. Content: `<iframe src="https://example.org/embed" data-src="https://example.org/embed" allowfullscreen=""></iframe>`,
  428. }
  429. testEntry := &model.Entry{
  430. URL: "https://example.org/article",
  431. Title: `A title`,
  432. Content: `<iframe src="about:blank" data-src="https://example.org/embed" allowfullscreen></iframe>`,
  433. }
  434. ApplyContentRewriteRules(testEntry, "add_dynamic_iframe")
  435. if !reflect.DeepEqual(testEntry, controlEntry) {
  436. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  437. }
  438. }
  439. func TestNewLineRewriteRule(t *testing.T) {
  440. controlEntry := &model.Entry{
  441. URL: "https://example.org/article",
  442. Title: `A title`,
  443. Content: `A<br>B<br>C`,
  444. }
  445. testEntry := &model.Entry{
  446. URL: "https://example.org/article",
  447. Title: `A title`,
  448. Content: "A\nB\nC",
  449. }
  450. ApplyContentRewriteRules(testEntry, "nl2br")
  451. if !reflect.DeepEqual(testEntry, controlEntry) {
  452. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  453. }
  454. }
  455. func TestConvertTextLinkRewriteRule(t *testing.T) {
  456. controlEntry := &model.Entry{
  457. URL: "https://example.org/article",
  458. Title: `A title`,
  459. Content: `Test: <a href="http://example.org/a/b">http://example.org/a/b</a>`,
  460. }
  461. testEntry := &model.Entry{
  462. URL: "https://example.org/article",
  463. Title: `A title`,
  464. Content: `Test: http://example.org/a/b`,
  465. }
  466. ApplyContentRewriteRules(testEntry, "convert_text_link")
  467. if !reflect.DeepEqual(testEntry, controlEntry) {
  468. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  469. }
  470. }
  471. func TestMediumImage(t *testing.T) {
  472. controlEntry := &model.Entry{
  473. URL: "https://example.org/article",
  474. Title: `A title`,
  475. Content: `<img alt="Image for post" class="t u v if aj" src="https://miro.medium.com/max/2560/1*ephLSqSzQYLvb7faDwzRbw.jpeg" width="1280" height="720" srcset="https://miro.medium.com/max/552/1*ephLSqSzQYLvb7faDwzRbw.jpeg 276w, https://miro.medium.com/max/1104/1*ephLSqSzQYLvb7faDwzRbw.jpeg 552w, https://miro.medium.com/max/1280/1*ephLSqSzQYLvb7faDwzRbw.jpeg 640w, https://miro.medium.com/max/1400/1*ephLSqSzQYLvb7faDwzRbw.jpeg 700w" sizes="700px"/>`,
  476. }
  477. testEntry := &model.Entry{
  478. URL: "https://example.org/article",
  479. Title: `A title`,
  480. Content: `
  481. <figure class="ht hu hv hw hx hy cy cz paragraph-image">
  482. <div class="hz ia ib ic aj">
  483. <div class="cy cz hs">
  484. <div class="ii s ib ij">
  485. <div class="ik il s">
  486. <div class="id ie t u v if aj bk ig ih">
  487. <img alt="Image for post" class="t u v if aj im in io" src="https://miro.medium.com/max/60/1*ephLSqSzQYLvb7faDwzRbw.jpeg?q=20" width="1280" height="720"/>
  488. </div>
  489. <img alt="Image for post" class="id ie t u v if aj c" width="1280" height="720"/>
  490. <noscript>
  491. <img alt="Image for post" class="t u v if aj" src="https://miro.medium.com/max/2560/1*ephLSqSzQYLvb7faDwzRbw.jpeg" width="1280" height="720" srcSet="https://miro.medium.com/max/552/1*ephLSqSzQYLvb7faDwzRbw.jpeg 276w, https://miro.medium.com/max/1104/1*ephLSqSzQYLvb7faDwzRbw.jpeg 552w, https://miro.medium.com/max/1280/1*ephLSqSzQYLvb7faDwzRbw.jpeg 640w, https://miro.medium.com/max/1400/1*ephLSqSzQYLvb7faDwzRbw.jpeg 700w" sizes="700px"/>
  492. </noscript>
  493. </div>
  494. </div>
  495. </div>
  496. </div>
  497. </figure>
  498. `,
  499. }
  500. ApplyContentRewriteRules(testEntry, "fix_medium_images")
  501. testEntry.Content = strings.TrimSpace(testEntry.Content)
  502. if !reflect.DeepEqual(testEntry, controlEntry) {
  503. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  504. }
  505. }
  506. func TestRewriteNoScriptImageWithoutNoScriptTag(t *testing.T) {
  507. controlEntry := &model.Entry{
  508. URL: "https://example.org/article",
  509. Title: `A title`,
  510. Content: `<figure><img src="https://developer.mozilla.org/static/img/favicon144.png" alt="The beautiful MDN logo."/><figcaption>MDN Logo</figcaption></figure>`,
  511. }
  512. testEntry := &model.Entry{
  513. URL: "https://example.org/article",
  514. Title: `A title`,
  515. Content: `<figure><img src="https://developer.mozilla.org/static/img/favicon144.png" alt="The beautiful MDN logo."><figcaption>MDN Logo</figcaption></figure>`,
  516. }
  517. ApplyContentRewriteRules(testEntry, "use_noscript_figure_images")
  518. testEntry.Content = strings.TrimSpace(testEntry.Content)
  519. if !reflect.DeepEqual(testEntry, controlEntry) {
  520. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  521. }
  522. }
  523. func TestRewriteNoScriptImageWithNoScriptTag(t *testing.T) {
  524. controlEntry := &model.Entry{
  525. URL: "https://example.org/article",
  526. Title: `A title`,
  527. Content: `<figure><img src="http://example.org/logo.svg"/><figcaption>MDN Logo</figcaption></figure>`,
  528. }
  529. testEntry := &model.Entry{
  530. URL: "https://example.org/article",
  531. Title: `A title`,
  532. Content: `<figure><img src="https://developer.mozilla.org/static/img/favicon144.png" alt="The beautiful MDN logo."><noscript><img src="http://example.org/logo.svg"></noscript><figcaption>MDN Logo</figcaption></figure>`,
  533. }
  534. ApplyContentRewriteRules(testEntry, "use_noscript_figure_images")
  535. testEntry.Content = strings.TrimSpace(testEntry.Content)
  536. if !reflect.DeepEqual(testEntry, controlEntry) {
  537. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  538. }
  539. }
  540. func TestRewriteReplaceCustom(t *testing.T) {
  541. controlEntry := &model.Entry{
  542. URL: "https://example.org/article",
  543. Title: `A title`,
  544. Content: `<img src="http://example.org/logo.svg"><img src="https://example.org/article/picture.png">`,
  545. }
  546. testEntry := &model.Entry{
  547. URL: "https://example.org/article",
  548. Title: `A title`,
  549. Content: `<img src="http://example.org/logo.svg"><img src="https://example.org/article/picture.svg">`,
  550. }
  551. ApplyContentRewriteRules(testEntry, `replace("article/(.*).svg"|"article/$1.png")`)
  552. if !reflect.DeepEqual(testEntry, controlEntry) {
  553. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  554. }
  555. }
  556. func TestRewriteReplaceTitleCustom(t *testing.T) {
  557. controlEntry := &model.Entry{
  558. URL: "https://example.org/article",
  559. Title: `Ouch, a thistle`,
  560. Content: `The replace_title rewrite rule should not modify the content.`,
  561. }
  562. testEntry := &model.Entry{
  563. URL: "https://example.org/article",
  564. Title: `A title`,
  565. Content: `The replace_title rewrite rule should not modify the content.`,
  566. }
  567. ApplyContentRewriteRules(testEntry, `replace_title("(?i)^a\\s*ti"|"Ouch, a this")`)
  568. if !reflect.DeepEqual(testEntry, controlEntry) {
  569. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  570. }
  571. }
  572. func TestRewriteRemoveCustom(t *testing.T) {
  573. controlEntry := &model.Entry{
  574. URL: "https://example.org/article",
  575. Title: `A title`,
  576. Content: `<div>Lorem Ipsum <span class="ads keep">Super important info</span></div>`,
  577. }
  578. testEntry := &model.Entry{
  579. URL: "https://example.org/article",
  580. Title: `A title`,
  581. Content: `<div>Lorem Ipsum <span class="spam">I dont want to see this</span><span class="ads keep">Super important info</span></div>`,
  582. }
  583. ApplyContentRewriteRules(testEntry, `remove(".spam, .ads:not(.keep)")`)
  584. if !reflect.DeepEqual(testEntry, controlEntry) {
  585. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  586. }
  587. }
  588. func TestRewriteAddCastopodEpisode(t *testing.T) {
  589. controlEntry := &model.Entry{
  590. URL: "https://podcast.demo/@demo/episodes/test",
  591. Title: `A title`,
  592. Content: `<iframe width="650" frameborder="0" src="https://podcast.demo/@demo/episodes/test/embed/light"></iframe><br>Episode Description`,
  593. }
  594. testEntry := &model.Entry{
  595. URL: "https://podcast.demo/@demo/episodes/test",
  596. Title: `A title`,
  597. Content: `Episode Description`,
  598. }
  599. ApplyContentRewriteRules(testEntry, `add_castopod_episode`)
  600. if !reflect.DeepEqual(testEntry, controlEntry) {
  601. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  602. }
  603. }
  604. func TestRewriteBase64Decode(t *testing.T) {
  605. controlEntry := &model.Entry{
  606. URL: "https://example.org/article",
  607. Title: `A title`,
  608. Content: `This is some base64 encoded content`,
  609. }
  610. testEntry := &model.Entry{
  611. URL: "https://example.org/article",
  612. Title: `A title`,
  613. Content: `VGhpcyBpcyBzb21lIGJhc2U2NCBlbmNvZGVkIGNvbnRlbnQ=`,
  614. }
  615. ApplyContentRewriteRules(testEntry, `base64_decode`)
  616. if !reflect.DeepEqual(testEntry, controlEntry) {
  617. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  618. }
  619. }
  620. func TestRewriteBase64DecodeInHTML(t *testing.T) {
  621. controlEntry := &model.Entry{
  622. URL: "https://example.org/article",
  623. Title: `A title`,
  624. Content: `<div>Lorem Ipsum not valid base64<span class="base64">This is some base64 encoded content</span></div>`,
  625. }
  626. testEntry := &model.Entry{
  627. URL: "https://example.org/article",
  628. Title: `A title`,
  629. Content: `<div>Lorem Ipsum not valid base64<span class="base64">VGhpcyBpcyBzb21lIGJhc2U2NCBlbmNvZGVkIGNvbnRlbnQ=</span></div>`,
  630. }
  631. ApplyContentRewriteRules(testEntry, `base64_decode`)
  632. if !reflect.DeepEqual(testEntry, controlEntry) {
  633. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  634. }
  635. }
  636. func TestRewriteBase64DecodeArgs(t *testing.T) {
  637. controlEntry := &model.Entry{
  638. URL: "https://example.org/article",
  639. Title: `A title`,
  640. Content: `<div>Lorem Ipsum<span class="base64">This is some base64 encoded content</span></div>`,
  641. }
  642. testEntry := &model.Entry{
  643. URL: "https://example.org/article",
  644. Title: `A title`,
  645. Content: `<div>Lorem Ipsum<span class="base64">VGhpcyBpcyBzb21lIGJhc2U2NCBlbmNvZGVkIGNvbnRlbnQ=</span></div>`,
  646. }
  647. ApplyContentRewriteRules(testEntry, `base64_decode(".base64")`)
  648. if !reflect.DeepEqual(testEntry, controlEntry) {
  649. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  650. }
  651. }
  652. func TestRewriteRemoveTables(t *testing.T) {
  653. controlEntry := &model.Entry{
  654. URL: "https://example.org/article",
  655. Title: `A title`,
  656. Content: `<p>Test</p><p>Hello World!</p><p>Test</p>`,
  657. }
  658. testEntry := &model.Entry{
  659. URL: "https://example.org/article",
  660. Title: `A title`,
  661. Content: `<table class="container"><tbody><tr><td><p>Test</p><table class="row"><tbody><tr><td><p>Hello World!</p></td><td><p>Test</p></td></tr></tbody></table></td></tr></tbody></table>`,
  662. }
  663. ApplyContentRewriteRules(testEntry, `remove_tables`)
  664. if !reflect.DeepEqual(testEntry, controlEntry) {
  665. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  666. }
  667. }
  668. func TestRemoveClickbait(t *testing.T) {
  669. controlEntry := &model.Entry{
  670. URL: "https://example.org/article",
  671. Title: `This Is Amazing`,
  672. Content: `Some description`,
  673. }
  674. testEntry := &model.Entry{
  675. URL: "https://example.org/article",
  676. Title: `THIS IS AMAZING`,
  677. Content: `Some description`,
  678. }
  679. ApplyContentRewriteRules(testEntry, `remove_clickbait`)
  680. if !reflect.DeepEqual(testEntry, controlEntry) {
  681. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  682. }
  683. }
  684. func TestAddHackerNewsLinksUsingHack(t *testing.T) {
  685. testEntry := &model.Entry{
  686. URL: "https://example.org/article",
  687. Title: `A title`,
  688. Content: `<p>Article URL: <a href="https://example.org/url">https://example.org/article</a></p>
  689. <p>Comments URL: <a href="https://news.ycombinator.com/item?id=37620043">https://news.ycombinator.com/item?id=37620043</a></p>
  690. <p>Points: 23</p>
  691. <p># Comments: 38</p>`,
  692. }
  693. controlEntry := &model.Entry{
  694. URL: "https://example.org/article",
  695. Title: `A title`,
  696. Content: `<p>Article URL: <a href="https://example.org/url">https://example.org/article</a></p>
  697. <p>Comments URL: <a href="https://news.ycombinator.com/item?id=37620043">https://news.ycombinator.com/item?id=37620043</a> <a href="hack://item?id=37620043">Open with HACK</a></p>
  698. <p>Points: 23</p>
  699. <p># Comments: 38</p>`,
  700. }
  701. ApplyContentRewriteRules(testEntry, `add_hn_links_using_hack`)
  702. if !reflect.DeepEqual(testEntry, controlEntry) {
  703. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  704. }
  705. }
  706. func TestAddHackerNewsLinksUsingOpener(t *testing.T) {
  707. testEntry := &model.Entry{
  708. URL: "https://example.org/article",
  709. Title: `A title`,
  710. Content: `<p>Article URL: <a href="https://example.org/url">https://example.org/article</a></p>
  711. <p>Comments URL: <a href="https://news.ycombinator.com/item?id=37620043">https://news.ycombinator.com/item?id=37620043</a></p>
  712. <p>Points: 23</p>
  713. <p># Comments: 38</p>`,
  714. }
  715. controlEntry := &model.Entry{
  716. URL: "https://example.org/article",
  717. Title: `A title`,
  718. Content: `<p>Article URL: <a href="https://example.org/url">https://example.org/article</a></p>
  719. <p>Comments URL: <a href="https://news.ycombinator.com/item?id=37620043">https://news.ycombinator.com/item?id=37620043</a> <a href="opener://x-callback-url/show-options?url=https%3A%2F%2Fnews.ycombinator.com%2Fitem%3Fid%3D37620043">Open with Opener</a></p>
  720. <p>Points: 23</p>
  721. <p># Comments: 38</p>`,
  722. }
  723. ApplyContentRewriteRules(testEntry, `add_hn_links_using_opener`)
  724. if !reflect.DeepEqual(testEntry, controlEntry) {
  725. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  726. }
  727. }
  728. func TestAddImageTitle(t *testing.T) {
  729. testEntry := &model.Entry{
  730. URL: "https://example.org/article",
  731. Title: `A title`,
  732. Content: `
  733. <img src="pif" title="pouf">
  734. <img src="pif" title="pouf" alt='"onerror=alert(1) a="'>
  735. <img src="pif" title="pouf" alt='&quot;onerror=alert(1) a=&quot'>
  736. <img src="pif" title="pouf" alt=';&amp;quot;onerror=alert(1) a=;&amp;quot;'>
  737. <img src="pif" alt="pouf" title='"onerror=alert(1) a="'>
  738. <img src="pif" alt="pouf" title='&quot;onerror=alert(1) a=&quot'>
  739. <img src="pif" alt="pouf" title=';&amp;quot;onerror=alert(1) a=;&amp;quot;'>
  740. `,
  741. }
  742. controlEntry := &model.Entry{
  743. URL: "https://example.org/article",
  744. Title: `A title`,
  745. Content: `<figure><img src="pif" alt=""/><figcaption><p>pouf</p></figcaption></figure>
  746. <figure><img src="pif" alt="" onerror="alert(1)" a=""/><figcaption><p>pouf</p></figcaption></figure>
  747. <figure><img src="pif" alt="" onerror="alert(1)" a=""/><figcaption><p>pouf</p></figcaption></figure>
  748. <figure><img src="pif" alt=";&#34;onerror=alert(1) a=;&#34;"/><figcaption><p>pouf</p></figcaption></figure>
  749. <figure><img src="pif" alt="pouf"/><figcaption><p>&#34;onerror=alert(1) a=&#34;</p></figcaption></figure>
  750. <figure><img src="pif" alt="pouf"/><figcaption><p>&#34;onerror=alert(1) a=&#34;</p></figcaption></figure>
  751. <figure><img src="pif" alt="pouf"/><figcaption><p>;&amp;quot;onerror=alert(1) a=;&amp;quot;</p></figcaption></figure>
  752. `,
  753. }
  754. ApplyContentRewriteRules(testEntry, `add_image_title`)
  755. if !reflect.DeepEqual(testEntry, controlEntry) {
  756. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  757. }
  758. }
  759. func TestFixGhostCard(t *testing.T) {
  760. testEntry := &model.Entry{
  761. URL: "https://example.org/article",
  762. Title: `A title`,
  763. Content: `<figure class="kg-card kg-bookmark-card">
  764. <a class="kg-bookmark-container" href="https://example.org/article">
  765. <div class="kg-bookmark-content">
  766. <div class="kg-bookmark-title">Example Article</div>
  767. <div class="kg-bookmark-description">Lorem ipsum odor amet, consectetuer adipiscing elit. Pretium magnis luctus ligula conubia quam, donec orci vehicula efficitur...</div>
  768. <div class="kg-bookmark-metadata">
  769. <img class="kg-bookmark-icon" src="https://example.org/favicon.ico" alt="">
  770. <span class="kg-bookmark-author">Example</span>
  771. <span class="kg-bookmark-publisher">Test Author</span>
  772. </div>
  773. </div>
  774. <div class="kg-bookmark-thumbnail">
  775. <img src="https://example.org/article-image.jpg" alt="" onerror="this.style.display = 'none'">
  776. </div>
  777. </a>
  778. </figure>`,
  779. }
  780. controlEntry := &model.Entry{
  781. URL: "https://example.org/article",
  782. Title: `A title`,
  783. Content: `<a href="https://example.org/article">Example Article - Example</a>`,
  784. }
  785. ApplyContentRewriteRules(testEntry, `fix_ghost_cards`)
  786. if !reflect.DeepEqual(testEntry, controlEntry) {
  787. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  788. }
  789. }
  790. func TestFixGhostCardNoCard(t *testing.T) {
  791. testEntry := &model.Entry{
  792. URL: "https://example.org/article",
  793. Title: `A title`,
  794. Content: `<a href="https://example.org/article">Example Article - Example</a>`,
  795. }
  796. controlEntry := &model.Entry{
  797. URL: "https://example.org/article",
  798. Title: `A title`,
  799. Content: `<a href="https://example.org/article">Example Article - Example</a>`,
  800. }
  801. ApplyContentRewriteRules(testEntry, `fix_ghost_cards`)
  802. if !reflect.DeepEqual(testEntry, controlEntry) {
  803. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  804. }
  805. }
  806. func TestFixGhostCardInvalidCard(t *testing.T) {
  807. testEntry := &model.Entry{
  808. URL: "https://example.org/article",
  809. Title: `A title`,
  810. Content: `<figure class="kg-card kg-bookmark-card">
  811. <a href="https://example.org/article">This card does not have the required fields</a>
  812. </figure>`,
  813. }
  814. controlEntry := &model.Entry{
  815. URL: "https://example.org/article",
  816. Title: `A title`,
  817. Content: `<figure class="kg-card kg-bookmark-card">
  818. <a href="https://example.org/article">This card does not have the required fields</a>
  819. </figure>`,
  820. }
  821. ApplyContentRewriteRules(testEntry, `fix_ghost_cards`)
  822. if !reflect.DeepEqual(testEntry, controlEntry) {
  823. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  824. }
  825. }
  826. func TestFixGhostCardMissingAuthor(t *testing.T) {
  827. testEntry := &model.Entry{
  828. URL: "https://example.org/article",
  829. Title: `A title`,
  830. Content: `<figure class="kg-card kg-bookmark-card">
  831. <a class="kg-bookmark-container" href="https://example.org/article">
  832. <div class="kg-bookmark-content">
  833. <div class="kg-bookmark-title">Example Article</div>
  834. <div class="kg-bookmark-description">Lorem ipsum odor amet, consectetuer adipiscing elit. Pretium magnis luctus ligula conubia quam, donec orci vehicula efficitur...</div>
  835. </div>
  836. <div class="kg-bookmark-thumbnail">
  837. <img src="https://example.org/article-image.jpg" alt="" onerror="this.style.display = 'none'">
  838. </div>
  839. </a>
  840. </figure>`,
  841. }
  842. controlEntry := &model.Entry{
  843. URL: "https://example.org/article",
  844. Title: `A title`,
  845. Content: `<a href="https://example.org/article">Example Article</a>`,
  846. }
  847. ApplyContentRewriteRules(testEntry, `fix_ghost_cards`)
  848. if !reflect.DeepEqual(testEntry, controlEntry) {
  849. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  850. }
  851. }
  852. func TestFixGhostCardDuplicatedAuthor(t *testing.T) {
  853. testEntry := &model.Entry{
  854. URL: "https://example.org/article",
  855. Title: `A title`,
  856. Content: `<figure class="kg-card kg-bookmark-card">
  857. <a class="kg-bookmark-container" href="https://example.org/article">
  858. <div class="kg-bookmark-content">
  859. <div class="kg-bookmark-title">Example Article - Example</div>
  860. <div class="kg-bookmark-description">Lorem ipsum odor amet, consectetuer adipiscing elit. Pretium magnis luctus ligula conubia quam, donec orci vehicula efficitur...</div>
  861. <div class="kg-bookmark-metadata">
  862. <img class="kg-bookmark-icon" src="https://example.org/favicon.ico" alt="">
  863. <span class="kg-bookmark-author">Example</span>
  864. <span class="kg-bookmark-publisher">Test Author</span>
  865. </div>
  866. </div>
  867. <div class="kg-bookmark-thumbnail">
  868. <img src="https://example.org/article-image.jpg" alt="" onerror="this.style.display = 'none'">
  869. </div>
  870. </a>
  871. </figure>`,
  872. }
  873. controlEntry := &model.Entry{
  874. URL: "https://example.org/article",
  875. Title: `A title`,
  876. Content: `<a href="https://example.org/article">Example Article - Example</a>`,
  877. }
  878. ApplyContentRewriteRules(testEntry, `fix_ghost_cards`)
  879. if !reflect.DeepEqual(testEntry, controlEntry) {
  880. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  881. }
  882. }
  883. func TestFixGhostCardMultiple(t *testing.T) {
  884. testEntry := &model.Entry{
  885. URL: "https://example.org/article",
  886. Title: `A title`,
  887. Content: `<figure class="kg-card kg-bookmark-card">
  888. <a class="kg-bookmark-container" href="https://example.org/article1">
  889. <div class="kg-bookmark-content">
  890. <div class="kg-bookmark-title">Example Article 1 - Example</div>
  891. <div class="kg-bookmark-description">Lorem ipsum odor amet, consectetuer adipiscing elit. Pretium magnis luctus ligula conubia quam, donec orci vehicula efficitur...</div>
  892. <div class="kg-bookmark-metadata">
  893. <img class="kg-bookmark-icon" src="https://example.org/favicon.ico" alt="">
  894. <span class="kg-bookmark-author">Example</span>
  895. <span class="kg-bookmark-publisher">Test Author</span>
  896. </div>
  897. </div>
  898. <div class="kg-bookmark-thumbnail">
  899. <img src="https://example.org/article-image.jpg" alt="" onerror="this.style.display = 'none'">
  900. </div>
  901. </a>
  902. </figure>
  903. <figure class="kg-card kg-bookmark-card">
  904. <a class="kg-bookmark-container" href="https://example.org/article2">
  905. <div class="kg-bookmark-content">
  906. <div class="kg-bookmark-title">Example Article 2 - Example</div>
  907. <div class="kg-bookmark-description">Lorem ipsum odor amet, consectetuer adipiscing elit. Pretium magnis luctus ligula conubia quam, donec orci vehicula efficitur...</div>
  908. <div class="kg-bookmark-metadata">
  909. <img class="kg-bookmark-icon" src="https://example.org/favicon.ico" alt="">
  910. <span class="kg-bookmark-author">Example</span>
  911. <span class="kg-bookmark-publisher">Test Author</span>
  912. </div>
  913. </div>
  914. <div class="kg-bookmark-thumbnail">
  915. <img src="https://example.org/article-image.jpg" alt="" onerror="this.style.display = 'none'">
  916. </div>
  917. </a>
  918. </figure>`,
  919. }
  920. controlEntry := &model.Entry{
  921. URL: "https://example.org/article",
  922. Title: `A title`,
  923. Content: `<ul><li><a href="https://example.org/article1">Example Article 1 - Example</a></li><li><a href="https://example.org/article2">Example Article 2 - Example</a></li></ul>`,
  924. }
  925. ApplyContentRewriteRules(testEntry, `fix_ghost_cards`)
  926. if !reflect.DeepEqual(testEntry, controlEntry) {
  927. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  928. }
  929. }
  930. func TestFixGhostCardMultipleSplit(t *testing.T) {
  931. testEntry := &model.Entry{
  932. URL: "https://example.org/article",
  933. Title: `A title`,
  934. Content: `<figure class="kg-card kg-bookmark-card">
  935. <a class="kg-bookmark-container" href="https://example.org/article1">
  936. <div class="kg-bookmark-content">
  937. <div class="kg-bookmark-title">Example Article 1 - Example</div>
  938. <div class="kg-bookmark-description">Lorem ipsum odor amet, consectetuer adipiscing elit. Pretium magnis luctus ligula conubia quam, donec orci vehicula efficitur...</div>
  939. <div class="kg-bookmark-metadata">
  940. <img class="kg-bookmark-icon" src="https://example.org/favicon.ico" alt="">
  941. <span class="kg-bookmark-author">Example</span>
  942. <span class="kg-bookmark-publisher">Test Author</span>
  943. </div>
  944. </div>
  945. <div class="kg-bookmark-thumbnail">
  946. <img src="https://example.org/article-image.jpg" alt="" onerror="this.style.display = 'none'">
  947. </div>
  948. </a>
  949. </figure>
  950. <p>This separates the two cards</p>
  951. <figure class="kg-card kg-bookmark-card">
  952. <a class="kg-bookmark-container" href="https://example.org/article2">
  953. <div class="kg-bookmark-content">
  954. <div class="kg-bookmark-title">Example Article 2 - Example</div>
  955. <div class="kg-bookmark-description">Lorem ipsum odor amet, consectetuer adipiscing elit. Pretium magnis luctus ligula conubia quam, donec orci vehicula efficitur...</div>
  956. <div class="kg-bookmark-metadata">
  957. <img class="kg-bookmark-icon" src="https://example.org/favicon.ico" alt="">
  958. <span class="kg-bookmark-author">Example</span>
  959. <span class="kg-bookmark-publisher">Test Author</span>
  960. </div>
  961. </div>
  962. <div class="kg-bookmark-thumbnail">
  963. <img src="https://example.org/article-image.jpg" alt="" onerror="this.style.display = 'none'">
  964. </div>
  965. </a>
  966. </figure>`,
  967. }
  968. controlEntry := &model.Entry{
  969. URL: "https://example.org/article",
  970. Title: `A title`,
  971. Content: `<a href="https://example.org/article1">Example Article 1 - Example</a>
  972. <p>This separates the two cards</p>
  973. <a href="https://example.org/article2">Example Article 2 - Example</a>`,
  974. }
  975. ApplyContentRewriteRules(testEntry, `fix_ghost_cards`)
  976. if !reflect.DeepEqual(testEntry, controlEntry) {
  977. t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
  978. }
  979. }