You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

markdown.rs 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641
  1. extern crate tera;
  2. extern crate front_matter;
  3. extern crate templates;
  4. extern crate rendering;
  5. extern crate config;
  6. use std::collections::HashMap;
  7. use tera::Tera;
  8. use config::Config;
  9. use front_matter::InsertAnchor;
  10. use templates::GUTENBERG_TERA;
  11. use rendering::{RenderContext, render_content};
  12. #[test]
  13. fn can_do_render_content_simple() {
  14. let tera_ctx = Tera::default();
  15. let permalinks_ctx = HashMap::new();
  16. let config = Config::default();
  17. let context = RenderContext::new(&tera_ctx, &config, "", &permalinks_ctx, InsertAnchor::None);
  18. let res = render_content("hello", &context).unwrap();
  19. assert_eq!(res.body, "<p>hello</p>\n");
  20. }
  21. #[test]
  22. fn doesnt_highlight_code_block_with_highlighting_off() {
  23. let tera_ctx = Tera::default();
  24. let permalinks_ctx = HashMap::new();
  25. let mut config = Config::default();
  26. config.highlight_code = false;
  27. let context = RenderContext::new(&tera_ctx, &config, "", &permalinks_ctx, InsertAnchor::None);
  28. let res = render_content("```\n$ gutenberg server\n```", &context).unwrap();
  29. assert_eq!(
  30. res.body,
  31. "<pre><code>$ gutenberg server\n</code></pre>\n"
  32. );
  33. }
  34. #[test]
  35. fn can_highlight_code_block_no_lang() {
  36. let tera_ctx = Tera::default();
  37. let permalinks_ctx = HashMap::new();
  38. let mut config = Config::default();
  39. config.highlight_code = true;
  40. let context = RenderContext::new(&tera_ctx, &config, "", &permalinks_ctx, InsertAnchor::None);
  41. let res = render_content("```\n$ gutenberg server\n$ ping\n```", &context).unwrap();
  42. assert_eq!(
  43. res.body,
  44. "<pre style=\"background-color:#2b303b;\">\n<span style=\"color:#c0c5ce;\">$ gutenberg server\n</span><span style=\"color:#c0c5ce;\">$ ping\n</span></pre>"
  45. );
  46. }
  47. #[test]
  48. fn can_highlight_code_block_with_lang() {
  49. let tera_ctx = Tera::default();
  50. let permalinks_ctx = HashMap::new();
  51. let mut config = Config::default();
  52. config.highlight_code = true;
  53. let context = RenderContext::new(&tera_ctx, &config, "", &permalinks_ctx, InsertAnchor::None);
  54. let res = render_content("```python\nlist.append(1)\n```", &context).unwrap();
  55. assert_eq!(
  56. res.body,
  57. "<pre style=\"background-color:#2b303b;\">\n<span style=\"color:#c0c5ce;\">list.</span><span style=\"color:#bf616a;\">append</span><span style=\"color:#c0c5ce;\">(</span><span style=\"color:#d08770;\">1</span><span style=\"color:#c0c5ce;\">)\n</span></pre>"
  58. );
  59. }
  60. #[test]
  61. fn can_higlight_code_block_with_unknown_lang() {
  62. let tera_ctx = Tera::default();
  63. let permalinks_ctx = HashMap::new();
  64. let mut config = Config::default();
  65. config.highlight_code = true;
  66. let context = RenderContext::new(&tera_ctx, &config, "", &permalinks_ctx, InsertAnchor::None);
  67. let res = render_content("```yolo\nlist.append(1)\n```", &context).unwrap();
  68. // defaults to plain text
  69. assert_eq!(
  70. res.body,
  71. "<pre style=\"background-color:#2b303b;\">\n<span style=\"color:#c0c5ce;\">list.append(1)\n</span></pre>"
  72. );
  73. }
  74. #[test]
  75. fn can_render_shortcode() {
  76. let permalinks_ctx = HashMap::new();
  77. let config = Config::default();
  78. let context = RenderContext::new(&GUTENBERG_TERA, &config, "", &permalinks_ctx, InsertAnchor::None);
  79. let res = render_content(r#"
  80. Hello
  81. {{ youtube(id="ub36ffWAqgQ") }}
  82. "#, &context).unwrap();
  83. assert!(res.body.contains("<p>Hello</p>\n<div >"));
  84. assert!(res.body.contains(r#"<iframe src="https://www.youtube.com/embed/ub36ffWAqgQ""#));
  85. }
  86. #[test]
  87. fn can_render_shortcode_with_markdown_char_in_args_name() {
  88. let permalinks_ctx = HashMap::new();
  89. let config = Config::default();
  90. let context = RenderContext::new(&GUTENBERG_TERA, &config, "", &permalinks_ctx, InsertAnchor::None);
  91. let input = vec![
  92. "name",
  93. "na_me",
  94. "n_a_me",
  95. "n1",
  96. ];
  97. for i in input {
  98. let res = render_content(&format!("{{{{ youtube(id=\"hey\", {}=1) }}}}", i), &context).unwrap();
  99. assert!(res.body.contains(r#"<iframe src="https://www.youtube.com/embed/hey""#));
  100. }
  101. }
  102. #[test]
  103. fn can_render_shortcode_with_markdown_char_in_args_value() {
  104. let permalinks_ctx = HashMap::new();
  105. let config = Config::default();
  106. let context = RenderContext::new(&GUTENBERG_TERA, &config, "", &permalinks_ctx, InsertAnchor::None);
  107. let input = vec![
  108. "ub36ffWAqgQ-hey",
  109. "ub36ffWAqgQ_hey",
  110. "ub36ffWAqgQ_he_y",
  111. "ub36ffWAqgQ*hey",
  112. "ub36ffWAqgQ#hey",
  113. ];
  114. for i in input {
  115. let res = render_content(&format!("{{{{ youtube(id=\"{}\") }}}}", i), &context).unwrap();
  116. assert!(res.body.contains(&format!(r#"<iframe src="https://www.youtube.com/embed/{}""#, i)));
  117. }
  118. }
  119. #[test]
  120. fn can_render_body_shortcode_with_markdown_char_in_name() {
  121. let permalinks_ctx = HashMap::new();
  122. let mut tera = Tera::default();
  123. tera.extend(&GUTENBERG_TERA).unwrap();
  124. let input = vec![
  125. "quo_te",
  126. "qu_o_te",
  127. ];
  128. let config = Config::default();
  129. for i in input {
  130. tera.add_raw_template(&format!("shortcodes/{}.html", i), "<blockquote>{{ body }} - {{ author}}</blockquote>").unwrap();
  131. let context = RenderContext::new(&tera, &config, "", &permalinks_ctx, InsertAnchor::None);
  132. let res = render_content(&format!("{{% {}(author=\"Bob\") %}}\nhey\n{{% end %}}", i), &context).unwrap();
  133. println!("{:?}", res);
  134. assert!(res.body.contains("<blockquote>hey - Bob</blockquote>"));
  135. }
  136. }
  137. #[test]
  138. fn can_render_body_shortcode_and_paragraph_after() {
  139. let permalinks_ctx = HashMap::new();
  140. let mut tera = Tera::default();
  141. tera.extend(&GUTENBERG_TERA).unwrap();
  142. let shortcode = "<p>{{ body }}</p>";
  143. let markdown_string = r#"
  144. {% figure() %}
  145. This is a figure caption.
  146. {% end %}
  147. Here is another paragraph.
  148. "#;
  149. let expected = "<p>This is a figure caption.</p>
  150. <p>Here is another paragraph.</p>
  151. ";
  152. tera.add_raw_template(&format!("shortcodes/{}.html", "figure"), shortcode).unwrap();
  153. let config = Config::default();
  154. let context = RenderContext::new(&tera, &config, "", &permalinks_ctx, InsertAnchor::None);
  155. let res = render_content(markdown_string, &context).unwrap();
  156. println!("{:?}", res);
  157. assert_eq!(res.body, expected);
  158. }
  159. #[test]
  160. fn can_render_two_body_shortcode_and_paragraph_after_with_line_break_between() {
  161. let permalinks_ctx = HashMap::new();
  162. let mut tera = Tera::default();
  163. tera.extend(&GUTENBERG_TERA).unwrap();
  164. let shortcode = "<p>{{ body }}</p>";
  165. let markdown_string = r#"
  166. {% figure() %}
  167. This is a figure caption.
  168. {% end %}
  169. {% figure() %}
  170. This is a figure caption.
  171. {% end %}
  172. Here is another paragraph.
  173. "#;
  174. let expected = "<p>This is a figure caption.</p>
  175. <p>This is a figure caption.</p>
  176. <p>Here is another paragraph.</p>
  177. ";
  178. tera.add_raw_template(&format!("shortcodes/{}.html", "figure"), shortcode).unwrap();
  179. let config = Config::default();
  180. let context = RenderContext::new(&tera, &config, "", &permalinks_ctx, InsertAnchor::None);
  181. let res = render_content(markdown_string, &context).unwrap();
  182. println!("{:?}", res);
  183. assert_eq!(res.body, expected);
  184. }
  185. #[test]
  186. fn can_render_several_shortcode_in_row() {
  187. let permalinks_ctx = HashMap::new();
  188. let config = Config::default();
  189. let context = RenderContext::new(&GUTENBERG_TERA, &config, "", &permalinks_ctx, InsertAnchor::None);
  190. let res = render_content(r#"
  191. Hello
  192. {{ youtube(id="ub36ffWAqgQ") }}
  193. {{ youtube(id="ub36ffWAqgQ", autoplay=true) }}
  194. {{ vimeo(id="210073083") }}
  195. {{ streamable(id="c0ic") }}
  196. {{ gist(url="https://gist.github.com/Keats/32d26f699dcc13ebd41b") }}
  197. "#, &context).unwrap();
  198. assert!(res.body.contains("<p>Hello</p>\n<div >"));
  199. assert!(res.body.contains(r#"<iframe src="https://www.youtube.com/embed/ub36ffWAqgQ""#));
  200. assert!(res.body.contains(r#"<iframe src="https://www.youtube.com/embed/ub36ffWAqgQ?autoplay=1""#));
  201. assert!(res.body.contains(r#"<iframe src="https://www.streamable.com/e/c0ic""#));
  202. assert!(res.body.contains(r#"//player.vimeo.com/video/210073083""#));
  203. }
  204. #[test]
  205. fn doesnt_render_ignored_shortcodes() {
  206. let permalinks_ctx = HashMap::new();
  207. let mut config = Config::default();
  208. config.highlight_code = false;
  209. let context = RenderContext::new(&GUTENBERG_TERA, &config, "", &permalinks_ctx, InsertAnchor::None);
  210. let res = render_content(r#"```{{/* youtube(id="w7Ft2ymGmfc") */}}```"#, &context).unwrap();
  211. assert_eq!(res.body, "<p><code>{{ youtube(id=&quot;w7Ft2ymGmfc&quot;) }}</code></p>\n");
  212. }
  213. #[test]
  214. fn can_render_shortcode_with_body() {
  215. let mut tera = Tera::default();
  216. tera.extend(&GUTENBERG_TERA).unwrap();
  217. tera.add_raw_template("shortcodes/quote.html", "<blockquote>{{ body }} - {{ author }}</blockquote>").unwrap();
  218. let permalinks_ctx = HashMap::new();
  219. let config = Config::default();
  220. let context = RenderContext::new(&tera, &config, "", &permalinks_ctx, InsertAnchor::None);
  221. let res = render_content(r#"
  222. Hello
  223. {% quote(author="Keats") %}
  224. A quote
  225. {% end %}
  226. "#, &context).unwrap();
  227. assert_eq!(res.body, "<p>Hello</p>\n<blockquote>A quote - Keats</blockquote>\n");
  228. }
  229. #[test]
  230. fn errors_rendering_unknown_shortcode() {
  231. let tera_ctx = Tera::default();
  232. let permalinks_ctx = HashMap::new();
  233. let config = Config::default();
  234. let context = RenderContext::new(&tera_ctx, &config, "", &permalinks_ctx, InsertAnchor::None);
  235. let res = render_content("{{ hello(flash=true) }}", &context);
  236. assert!(res.is_err());
  237. }
  238. #[test]
  239. fn can_make_valid_relative_link() {
  240. let mut permalinks = HashMap::new();
  241. permalinks.insert("pages/about.md".to_string(), "https://vincent.is/about".to_string());
  242. let tera_ctx = Tera::default();
  243. let config = Config::default();
  244. let context = RenderContext::new(&tera_ctx, &config, "", &permalinks, InsertAnchor::None);
  245. let res = render_content(
  246. r#"[rel link](./pages/about.md), [abs link](https://vincent.is/about)"#,
  247. &context,
  248. ).unwrap();
  249. assert!(
  250. res.body.contains(r#"<p><a href="https://vincent.is/about">rel link</a>, <a href="https://vincent.is/about">abs link</a></p>"#)
  251. );
  252. }
  253. #[test]
  254. fn can_make_relative_links_with_anchors() {
  255. let mut permalinks = HashMap::new();
  256. permalinks.insert("pages/about.md".to_string(), "https://vincent.is/about".to_string());
  257. let tera_ctx = Tera::default();
  258. let config = Config::default();
  259. let context = RenderContext::new(&tera_ctx, &config, "", &permalinks, InsertAnchor::None);
  260. let res = render_content(r#"[rel link](./pages/about.md#cv)"#, &context).unwrap();
  261. assert!(
  262. res.body.contains(r#"<p><a href="https://vincent.is/about#cv">rel link</a></p>"#)
  263. );
  264. }
  265. #[test]
  266. fn errors_relative_link_inexistant() {
  267. let tera_ctx = Tera::default();
  268. let permalinks_ctx = HashMap::new();
  269. let config = Config::default();
  270. let context = RenderContext::new(&tera_ctx, &config, "", &permalinks_ctx, InsertAnchor::None);
  271. let res = render_content("[rel link](./pages/about.md)", &context);
  272. assert!(res.is_err());
  273. }
  274. #[test]
  275. fn can_add_id_to_headers() {
  276. let tera_ctx = Tera::default();
  277. let permalinks_ctx = HashMap::new();
  278. let config = Config::default();
  279. let context = RenderContext::new(&tera_ctx, &config, "", &permalinks_ctx, InsertAnchor::None);
  280. let res = render_content(r#"# Hello"#, &context).unwrap();
  281. assert_eq!(res.body, "<h1 id=\"hello\">Hello</h1>\n");
  282. }
  283. #[test]
  284. fn can_add_id_to_headers_same_slug() {
  285. let tera_ctx = Tera::default();
  286. let permalinks_ctx = HashMap::new();
  287. let config = Config::default();
  288. let context = RenderContext::new(&tera_ctx, &config, "", &permalinks_ctx, InsertAnchor::None);
  289. let res = render_content("# Hello\n# Hello", &context).unwrap();
  290. assert_eq!(res.body, "<h1 id=\"hello\">Hello</h1>\n<h1 id=\"hello-1\">Hello</h1>\n");
  291. }
  292. #[test]
  293. fn can_insert_anchor_left() {
  294. let permalinks_ctx = HashMap::new();
  295. let config = Config::default();
  296. let context = RenderContext::new(&GUTENBERG_TERA, &config, "", &permalinks_ctx, InsertAnchor::Left);
  297. let res = render_content("# Hello", &context).unwrap();
  298. assert_eq!(
  299. res.body,
  300. "<h1 id=\"hello\"><a class=\"gutenberg-anchor\" href=\"#hello\" aria-label=\"Anchor link for: hello\">🔗</a>\nHello</h1>\n"
  301. );
  302. }
  303. #[test]
  304. fn can_insert_anchor_right() {
  305. let permalinks_ctx = HashMap::new();
  306. let config = Config::default();
  307. let context = RenderContext::new(&GUTENBERG_TERA, &config, "", &permalinks_ctx, InsertAnchor::Right);
  308. let res = render_content("# Hello", &context).unwrap();
  309. assert_eq!(
  310. res.body,
  311. "<h1 id=\"hello\">Hello<a class=\"gutenberg-anchor\" href=\"#hello\" aria-label=\"Anchor link for: hello\">🔗</a>\n</h1>\n"
  312. );
  313. }
  314. // See https://github.com/Keats/gutenberg/issues/42
  315. #[test]
  316. fn can_insert_anchor_with_exclamation_mark() {
  317. let permalinks_ctx = HashMap::new();
  318. let config = Config::default();
  319. let context = RenderContext::new(&GUTENBERG_TERA, &config, "", &permalinks_ctx, InsertAnchor::Left);
  320. let res = render_content("# Hello!", &context).unwrap();
  321. assert_eq!(
  322. res.body,
  323. "<h1 id=\"hello\"><a class=\"gutenberg-anchor\" href=\"#hello\" aria-label=\"Anchor link for: hello\">🔗</a>\nHello!</h1>\n"
  324. );
  325. }
  326. // See https://github.com/Keats/gutenberg/issues/53
  327. #[test]
  328. fn can_insert_anchor_with_link() {
  329. let permalinks_ctx = HashMap::new();
  330. let config = Config::default();
  331. let context = RenderContext::new(&GUTENBERG_TERA, &config, "", &permalinks_ctx, InsertAnchor::Left);
  332. let res = render_content("## [Rust](https://rust-lang.org)", &context).unwrap();
  333. assert_eq!(
  334. res.body,
  335. "<h2 id=\"rust\"><a class=\"gutenberg-anchor\" href=\"#rust\" aria-label=\"Anchor link for: rust\">🔗</a>\n<a href=\"https://rust-lang.org\">Rust</a></h2>\n"
  336. );
  337. }
  338. #[test]
  339. fn can_insert_anchor_with_other_special_chars() {
  340. let permalinks_ctx = HashMap::new();
  341. let config = Config::default();
  342. let context = RenderContext::new(&GUTENBERG_TERA, &config, "", &permalinks_ctx, InsertAnchor::Left);
  343. let res = render_content("# Hello*_()", &context).unwrap();
  344. assert_eq!(
  345. res.body,
  346. "<h1 id=\"hello\"><a class=\"gutenberg-anchor\" href=\"#hello\" aria-label=\"Anchor link for: hello\">🔗</a>\nHello*_()</h1>\n"
  347. );
  348. }
  349. #[test]
  350. fn can_make_toc() {
  351. let permalinks_ctx = HashMap::new();
  352. let config = Config::default();
  353. let context = RenderContext::new(
  354. &GUTENBERG_TERA,
  355. &config,
  356. "https://mysite.com/something",
  357. &permalinks_ctx,
  358. InsertAnchor::Left,
  359. );
  360. let res = render_content(r#"
  361. # Header 1
  362. ## Header 2
  363. ## Another Header 2
  364. ### Last one
  365. "#, &context).unwrap();
  366. let toc = res.toc;
  367. assert_eq!(toc.len(), 1);
  368. assert_eq!(toc[0].children.len(), 2);
  369. assert_eq!(toc[0].children[1].children.len(), 1);
  370. }
  371. #[test]
  372. fn can_ignore_tags_in_toc() {
  373. let permalinks_ctx = HashMap::new();
  374. let config = Config::default();
  375. let context = RenderContext::new(
  376. &GUTENBERG_TERA,
  377. &config,
  378. "https://mysite.com/something",
  379. &permalinks_ctx,
  380. InsertAnchor::Left,
  381. );
  382. let res = render_content(r#"
  383. ## header with `code`
  384. ## [anchor](https://duckduckgo.com/) in header
  385. ## **bold** and *italics*
  386. "#, &context).unwrap();
  387. let toc = res.toc;
  388. assert_eq!(toc[0].id, "header-with-code");
  389. assert_eq!(toc[0].title, "header with code");
  390. assert_eq!(toc[1].id, "anchor-in-header");
  391. assert_eq!(toc[1].title, "anchor in header");
  392. assert_eq!(toc[2].id, "bold-and-italics");
  393. assert_eq!(toc[2].title, "bold and italics");
  394. }
  395. #[test]
  396. fn can_understand_backtick_in_titles() {
  397. let permalinks_ctx = HashMap::new();
  398. let config = Config::default();
  399. let context = RenderContext::new(&GUTENBERG_TERA, &config, "", &permalinks_ctx, InsertAnchor::None);
  400. let res = render_content("# `Hello`", &context).unwrap();
  401. assert_eq!(
  402. res.body,
  403. "<h1 id=\"hello\"><code>Hello</code></h1>\n"
  404. );
  405. }
  406. #[test]
  407. fn can_understand_backtick_in_paragraphs() {
  408. let permalinks_ctx = HashMap::new();
  409. let config = Config::default();
  410. let context = RenderContext::new(&GUTENBERG_TERA, &config, "", &permalinks_ctx, InsertAnchor::None);
  411. let res = render_content("Hello `world`", &context).unwrap();
  412. assert_eq!(
  413. res.body,
  414. "<p>Hello <code>world</code></p>\n"
  415. );
  416. }
  417. // https://github.com/Keats/gutenberg/issues/297
  418. #[test]
  419. fn can_understand_links_in_header() {
  420. let permalinks_ctx = HashMap::new();
  421. let config = Config::default();
  422. let context = RenderContext::new(&GUTENBERG_TERA, &config, "", &permalinks_ctx, InsertAnchor::None);
  423. let res = render_content("# [Rust](https://rust-lang.org)", &context).unwrap();
  424. assert_eq!(
  425. res.body,
  426. "<h1 id=\"rust\"><a href=\"https://rust-lang.org\">Rust</a></h1>\n"
  427. );
  428. }
  429. #[test]
  430. fn can_understand_link_with_title_in_header() {
  431. let permalinks_ctx = HashMap::new();
  432. let config = Config::default();
  433. let context = RenderContext::new(&GUTENBERG_TERA, &config, "", &permalinks_ctx, InsertAnchor::None);
  434. let res = render_content("# [Rust](https://rust-lang.org \"Rust homepage\")", &context).unwrap();
  435. assert_eq!(
  436. res.body,
  437. "<h1 id=\"rust\"><a href=\"https://rust-lang.org\" title=\"Rust homepage\">Rust</a></h1>\n"
  438. );
  439. }
  440. #[test]
  441. fn can_make_valid_relative_link_in_header() {
  442. let mut permalinks = HashMap::new();
  443. permalinks.insert("pages/about.md".to_string(), "https://vincent.is/about/".to_string());
  444. let tera_ctx = Tera::default();
  445. let config = Config::default();
  446. let context = RenderContext::new(&tera_ctx, &config, "", &permalinks, InsertAnchor::None);
  447. let res = render_content(
  448. r#" # [rel link](./pages/about.md)"#,
  449. &context,
  450. ).unwrap();
  451. assert_eq!(
  452. res.body,
  453. "<h1 id=\"rel-link\"><a href=\"https://vincent.is/about/\">rel link</a></h1>\n"
  454. );
  455. }
  456. #[test]
  457. fn can_make_permalinks_with_colocated_assets_for_link() {
  458. let permalinks_ctx = HashMap::new();
  459. let config = Config::default();
  460. let context = RenderContext::new(&GUTENBERG_TERA, &config, "https://vincent.is/about/", &permalinks_ctx, InsertAnchor::None);
  461. let res = render_content("[an image](image.jpg)", &context).unwrap();
  462. assert_eq!(
  463. res.body,
  464. "<p><a href=\"https://vincent.is/about/image.jpg\">an image</a></p>\n"
  465. );
  466. }
  467. #[test]
  468. fn can_make_permalinks_with_colocated_assets_for_image() {
  469. let permalinks_ctx = HashMap::new();
  470. let config = Config::default();
  471. let context = RenderContext::new(&GUTENBERG_TERA, &config, "https://vincent.is/about/", &permalinks_ctx, InsertAnchor::None);
  472. let res = render_content("![alt text](image.jpg)", &context).unwrap();
  473. assert_eq!(
  474. res.body,
  475. "<p><img src=\"https://vincent.is/about/image.jpg\" alt=\"alt text\" /></p>\n"
  476. );
  477. }
  478. #[test]
  479. fn markdown_doesnt_wrap_html_in_paragraph() {
  480. let permalinks_ctx = HashMap::new();
  481. let config = Config::default();
  482. let context = RenderContext::new(&GUTENBERG_TERA, &config, "https://vincent.is/about/", &permalinks_ctx, InsertAnchor::None);
  483. let res = render_content(r#"
  484. Some text
  485. <h1>Helo</h1>
  486. <div>
  487. <a href="mobx-flow.png">
  488. <img src="mobx-flow.png" alt="MobX flow">
  489. </a>
  490. </div>
  491. "#, &context).unwrap();
  492. assert_eq!(
  493. res.body,
  494. "<p>Some text</p>\n<h1>Helo</h1>\n<div>\n<a href=\"mobx-flow.png\">\n <img src=\"mobx-flow.png\" alt=\"MobX flow\">\n </a>\n</div>\n"
  495. );
  496. }
  497. #[test]
  498. fn can_validate_valid_external_links() {
  499. let permalinks_ctx = HashMap::new();
  500. let mut config = Config::default();
  501. config.check_external_links = true;
  502. let context = RenderContext::new(&GUTENBERG_TERA, &config, "https://vincent.is/about/", &permalinks_ctx, InsertAnchor::None);
  503. let res = render_content("[a link](http://google.com)", &context).unwrap();
  504. assert_eq!(
  505. res.body,
  506. "<p><a href=\"http://google.com\">a link</a></p>\n"
  507. );
  508. }
  509. #[test]
  510. fn can_show_error_message_for_invalid_external_links() {
  511. let permalinks_ctx = HashMap::new();
  512. let mut config = Config::default();
  513. config.check_external_links = true;
  514. let context = RenderContext::new(&GUTENBERG_TERA, &config, "https://vincent.is/about/", &permalinks_ctx, InsertAnchor::None);
  515. let res = render_content("[a link](http://google.comy)", &context);
  516. assert!(res.is_err());
  517. let err = res.unwrap_err();
  518. assert!(err.description().contains("Link http://google.comy is not valid"));
  519. }
  520. #[test]
  521. fn doesnt_try_to_validate_email_links_mailto() {
  522. let permalinks_ctx = HashMap::new();
  523. let mut config = Config::default();
  524. config.check_external_links = true;
  525. let context = RenderContext::new(&GUTENBERG_TERA, &config, "https://vincent.is/about/", &permalinks_ctx, InsertAnchor::None);
  526. let res = render_content("Email: [foo@bar.baz](mailto:foo@bar.baz)", &context).unwrap();
  527. assert_eq!(
  528. res.body,
  529. "<p>Email: <a href=\"mailto:foo@bar.baz\">foo@bar.baz</a></p>\n"
  530. );
  531. }
  532. #[test]
  533. fn doesnt_try_to_validate_email_links_angled_brackets() {
  534. let permalinks_ctx = HashMap::new();
  535. let mut config = Config::default();
  536. config.check_external_links = true;
  537. let context = RenderContext::new(&GUTENBERG_TERA, &config, "https://vincent.is/about/", &permalinks_ctx, InsertAnchor::None);
  538. let res = render_content("Email: <foo@bar.baz>", &context).unwrap();
  539. assert_eq!(
  540. res.body,
  541. "<p>Email: <a href=\"mailto:foo@bar.baz\">foo@bar.baz</a></p>\n"
  542. );
  543. }
  544. #[test]
  545. fn can_handle_summaries() {
  546. let tera_ctx = Tera::default();
  547. let permalinks_ctx = HashMap::new();
  548. let config = Config::default();
  549. let context = RenderContext::new(&tera_ctx, &config, "", &permalinks_ctx, InsertAnchor::None);
  550. let res = render_content("Hello [world]\n\n<!-- more -->\n\nBla bla\n\n[world]: https://vincent.is/about/", &context).unwrap();
  551. assert_eq!(
  552. res.body,
  553. "<p>Hello <a href=\"https://vincent.is/about/\">world</a></p>\n<p><a name=\"continue-reading\"></a></p>\n<p>Bla bla</p>\n"
  554. );
  555. assert_eq!(
  556. res.summary_len,
  557. Some("<p>Hello <a href=\"https://vincent.is/about/\">world</a></p>\n".len())
  558. );
  559. }