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.

362 lines
13KB

  1. extern crate tera;
  2. extern crate front_matter;
  3. extern crate templates;
  4. extern crate rendering;
  5. use std::collections::HashMap;
  6. use tera::Tera;
  7. use front_matter::InsertAnchor;
  8. use templates::GUTENBERG_TERA;
  9. use rendering::{Context, markdown_to_html};
  10. #[test]
  11. fn can_do_markdown_to_html_simple() {
  12. let tera_ctx = Tera::default();
  13. let permalinks_ctx = HashMap::new();
  14. let context = Context::new(&tera_ctx, true, "base16-ocean-dark".to_string(), "", &permalinks_ctx, InsertAnchor::None);
  15. let res = markdown_to_html("hello", &context).unwrap();
  16. assert_eq!(res.0, "<p>hello</p>\n");
  17. }
  18. #[test]
  19. fn doesnt_highlight_code_block_with_highlighting_off() {
  20. let tera_ctx = Tera::default();
  21. let permalinks_ctx = HashMap::new();
  22. let mut context = Context::new(&tera_ctx, true, "base16-ocean-dark".to_string(), "", &permalinks_ctx, InsertAnchor::None);
  23. context.highlight_code = false;
  24. let res = markdown_to_html("```\n$ gutenberg server\n```", &context).unwrap();
  25. assert_eq!(
  26. res.0,
  27. "<pre><code>$ gutenberg server\n</code></pre>\n"
  28. );
  29. }
  30. #[test]
  31. fn can_highlight_code_block_no_lang() {
  32. let tera_ctx = Tera::default();
  33. let permalinks_ctx = HashMap::new();
  34. let context = Context::new(&tera_ctx, true, "base16-ocean-dark".to_string(), "", &permalinks_ctx, InsertAnchor::None);
  35. let res = markdown_to_html("```\n$ gutenberg server\n$ ping\n```", &context).unwrap();
  36. assert_eq!(
  37. res.0,
  38. "<pre style=\"background-color:#2b303b\">\n<span style=\"background-color:#2b303b;color:#c0c5ce;\">$ gutenberg server\n</span><span style=\"background-color:#2b303b;color:#c0c5ce;\">$ ping\n</span></pre>"
  39. );
  40. }
  41. #[test]
  42. fn can_highlight_code_block_with_lang() {
  43. let tera_ctx = Tera::default();
  44. let permalinks_ctx = HashMap::new();
  45. let context = Context::new(&tera_ctx, true, "base16-ocean-dark".to_string(), "", &permalinks_ctx, InsertAnchor::None);
  46. let res = markdown_to_html("```python\nlist.append(1)\n```", &context).unwrap();
  47. assert_eq!(
  48. res.0,
  49. "<pre style=\"background-color:#2b303b\">\n<span style=\"background-color:#2b303b;color:#c0c5ce;\">list</span><span style=\"background-color:#2b303b;color:#c0c5ce;\">.</span><span style=\"background-color:#2b303b;color:#bf616a;\">append</span><span style=\"background-color:#2b303b;color:#c0c5ce;\">(</span><span style=\"background-color:#2b303b;color:#d08770;\">1</span><span style=\"background-color:#2b303b;color:#c0c5ce;\">)</span><span style=\"background-color:#2b303b;color:#c0c5ce;\">\n</span></pre>"
  50. );
  51. }
  52. #[test]
  53. fn can_higlight_code_block_with_unknown_lang() {
  54. let tera_ctx = Tera::default();
  55. let permalinks_ctx = HashMap::new();
  56. let context = Context::new(&tera_ctx, true, "base16-ocean-dark".to_string(), "", &permalinks_ctx, InsertAnchor::None);
  57. let res = markdown_to_html("```yolo\nlist.append(1)\n```", &context).unwrap();
  58. // defaults to plain text
  59. assert_eq!(
  60. res.0,
  61. "<pre style=\"background-color:#2b303b\">\n<span style=\"background-color:#2b303b;color:#c0c5ce;\">list.append(1)\n</span></pre>"
  62. );
  63. }
  64. #[test]
  65. fn can_render_shortcode() {
  66. let permalinks_ctx = HashMap::new();
  67. let context = Context::new(&GUTENBERG_TERA, true, "base16-ocean-dark".to_string(), "", &permalinks_ctx, InsertAnchor::None);
  68. let res = markdown_to_html(r#"
  69. Hello
  70. {{ youtube(id="ub36ffWAqgQ") }}
  71. "#, &context).unwrap();
  72. assert!(res.0.contains("<p>Hello</p>\n<div >"));
  73. assert!(res.0.contains(r#"<iframe src="https://www.youtube.com/embed/ub36ffWAqgQ""#));
  74. }
  75. #[test]
  76. fn can_render_shortcode_with_markdown_char_in_args_name() {
  77. let permalinks_ctx = HashMap::new();
  78. let context = Context::new(&GUTENBERG_TERA, true, "base16-ocean-dark".to_string(), "", &permalinks_ctx, InsertAnchor::None);
  79. let input = vec![
  80. "name",
  81. "na_me",
  82. "n_a_me",
  83. "n1",
  84. ];
  85. for i in input {
  86. let res = markdown_to_html(&format!("{{{{ youtube(id=\"hey\", {}=1) }}}}", i), &context).unwrap();
  87. assert!(res.0.contains(r#"<iframe src="https://www.youtube.com/embed/hey""#));
  88. }
  89. }
  90. #[test]
  91. fn can_render_shortcode_with_markdown_char_in_args_value() {
  92. let permalinks_ctx = HashMap::new();
  93. let context = Context::new(&GUTENBERG_TERA, true, "base16-ocean-dark".to_string(), "", &permalinks_ctx, InsertAnchor::None);
  94. let input = vec![
  95. "ub36ffWAqgQ-hey",
  96. "ub36ffWAqgQ_hey",
  97. "ub36ffWAqgQ_he_y",
  98. "ub36ffWAqgQ*hey",
  99. "ub36ffWAqgQ#hey",
  100. ];
  101. for i in input {
  102. let res = markdown_to_html(&format!("{{{{ youtube(id=\"{}\") }}}}", i), &context).unwrap();
  103. assert!(res.0.contains(&format!(r#"<iframe src="https://www.youtube.com/embed/{}""#, i)));
  104. }
  105. }
  106. #[test]
  107. fn can_render_body_shortcode_with_markdown_char_in_name() {
  108. let permalinks_ctx = HashMap::new();
  109. let mut tera = Tera::default();
  110. tera.extend(&GUTENBERG_TERA).unwrap();
  111. let input = vec![
  112. "quo_te",
  113. "qu_o_te",
  114. ];
  115. for i in input {
  116. tera.add_raw_template(&format!("shortcodes/{}.html", i), "<blockquote>{{ body }} - {{ author}}</blockquote>").unwrap();
  117. let context = Context::new(&tera, true, "base16-ocean-dark".to_string(), "", &permalinks_ctx, InsertAnchor::None);
  118. let res = markdown_to_html(&format!("{{% {}(author=\"Bob\") %}}\nhey\n{{% end %}}", i), &context).unwrap();
  119. println!("{:?}", res);
  120. assert!(res.0.contains("<blockquote>hey - Bob</blockquote>"));
  121. }
  122. }
  123. #[test]
  124. fn can_render_several_shortcode_in_row() {
  125. let permalinks_ctx = HashMap::new();
  126. let context = Context::new(&GUTENBERG_TERA, true, "base16-ocean-dark".to_string(), "", &permalinks_ctx, InsertAnchor::None);
  127. let res = markdown_to_html(r#"
  128. Hello
  129. {{ youtube(id="ub36ffWAqgQ") }}
  130. {{ youtube(id="ub36ffWAqgQ", autoplay=true) }}
  131. {{ vimeo(id="210073083") }}
  132. {{ streamable(id="c0ic") }}
  133. {{ gist(url="https://gist.github.com/Keats/32d26f699dcc13ebd41b") }}
  134. "#, &context).unwrap();
  135. assert!(res.0.contains("<p>Hello</p>\n<div >"));
  136. assert!(res.0.contains(r#"<iframe src="https://www.youtube.com/embed/ub36ffWAqgQ""#));
  137. assert!(res.0.contains(r#"<iframe src="https://www.youtube.com/embed/ub36ffWAqgQ?autoplay=1""#));
  138. assert!(res.0.contains(r#"<iframe src="https://www.streamable.com/e/c0ic""#));
  139. assert!(res.0.contains(r#"//player.vimeo.com/video/210073083""#));
  140. }
  141. #[test]
  142. fn doesnt_render_shortcode_in_code_block() {
  143. let permalinks_ctx = HashMap::new();
  144. let context = Context::new(&GUTENBERG_TERA, true, "base16-ocean-dark".to_string(), "", &permalinks_ctx, InsertAnchor::None);
  145. let res = markdown_to_html(r#"```{{ youtube(id="w7Ft2ymGmfc") }}```"#, &context).unwrap();
  146. assert_eq!(res.0, "<p><code>{{ youtube(id=&quot;w7Ft2ymGmfc&quot;) }}</code></p>\n");
  147. }
  148. #[test]
  149. fn can_render_shortcode_with_body() {
  150. let mut tera = Tera::default();
  151. tera.extend(&GUTENBERG_TERA).unwrap();
  152. tera.add_raw_template("shortcodes/quote.html", "<blockquote>{{ body }} - {{ author}}</blockquote>").unwrap();
  153. let permalinks_ctx = HashMap::new();
  154. let context = Context::new(&tera, true, "base16-ocean-dark".to_string(), "", &permalinks_ctx, InsertAnchor::None);
  155. let res = markdown_to_html(r#"
  156. Hello
  157. {% quote(author="Keats") %}
  158. A quote
  159. {% end %}
  160. "#, &context).unwrap();
  161. assert_eq!(res.0, "<p>Hello\n</p><blockquote>A quote - Keats</blockquote>");
  162. }
  163. #[test]
  164. fn errors_rendering_unknown_shortcode() {
  165. let tera_ctx = Tera::default();
  166. let permalinks_ctx = HashMap::new();
  167. let context = Context::new(&tera_ctx, true, "base16-ocean-dark".to_string(), "", &permalinks_ctx, InsertAnchor::None);
  168. let res = markdown_to_html("{{ hello(flash=true) }}", &context);
  169. assert!(res.is_err());
  170. }
  171. #[test]
  172. fn can_make_valid_relative_link() {
  173. let mut permalinks = HashMap::new();
  174. permalinks.insert("pages/about.md".to_string(), "https://vincent.is/about".to_string());
  175. let tera_ctx = Tera::default();
  176. let context = Context::new(&tera_ctx, true, "base16-ocean-dark".to_string(), "", &permalinks, InsertAnchor::None);
  177. let res = markdown_to_html(
  178. r#"[rel link](./pages/about.md), [abs link](https://vincent.is/about)"#,
  179. &context
  180. ).unwrap();
  181. assert!(
  182. res.0.contains(r#"<p><a href="https://vincent.is/about">rel link</a>, <a href="https://vincent.is/about">abs link</a></p>"#)
  183. );
  184. }
  185. #[test]
  186. fn can_make_relative_links_with_anchors() {
  187. let mut permalinks = HashMap::new();
  188. permalinks.insert("pages/about.md".to_string(), "https://vincent.is/about".to_string());
  189. let tera_ctx = Tera::default();
  190. let context = Context::new(&tera_ctx, true, "base16-ocean-dark".to_string(), "", &permalinks, InsertAnchor::None);
  191. let res = markdown_to_html(r#"[rel link](./pages/about.md#cv)"#, &context).unwrap();
  192. assert!(
  193. res.0.contains(r#"<p><a href="https://vincent.is/about#cv">rel link</a></p>"#)
  194. );
  195. }
  196. #[test]
  197. fn errors_relative_link_inexistant() {
  198. let tera_ctx = Tera::default();
  199. let permalinks_ctx = HashMap::new();
  200. let context = Context::new(&tera_ctx, true, "base16-ocean-dark".to_string(), "", &permalinks_ctx, InsertAnchor::None);
  201. let res = markdown_to_html("[rel link](./pages/about.md)", &context);
  202. assert!(res.is_err());
  203. }
  204. #[test]
  205. fn can_add_id_to_headers() {
  206. let tera_ctx = Tera::default();
  207. let permalinks_ctx = HashMap::new();
  208. let context = Context::new(&tera_ctx, true, "base16-ocean-dark".to_string(), "", &permalinks_ctx, InsertAnchor::None);
  209. let res = markdown_to_html(r#"# Hello"#, &context).unwrap();
  210. assert_eq!(res.0, "<h1 id=\"hello\">Hello</h1>\n");
  211. }
  212. #[test]
  213. fn can_add_id_to_headers_same_slug() {
  214. let tera_ctx = Tera::default();
  215. let permalinks_ctx = HashMap::new();
  216. let context = Context::new(&tera_ctx, true, "base16-ocean-dark".to_string(), "", &permalinks_ctx, InsertAnchor::None);
  217. let res = markdown_to_html("# Hello\n# Hello", &context).unwrap();
  218. assert_eq!(res.0, "<h1 id=\"hello\">Hello</h1>\n<h1 id=\"hello-1\">Hello</h1>\n");
  219. }
  220. #[test]
  221. fn can_insert_anchor_left() {
  222. let permalinks_ctx = HashMap::new();
  223. let context = Context::new(&GUTENBERG_TERA, true, "base16-ocean-dark".to_string(), "", &permalinks_ctx, InsertAnchor::Left);
  224. let res = markdown_to_html("# Hello", &context).unwrap();
  225. assert_eq!(
  226. res.0,
  227. "<h1 id=\"hello\"><a class=\"gutenberg-anchor\" href=\"#hello\" aria-label=\"Anchor link for: hello\">🔗</a>\nHello</h1>\n"
  228. );
  229. }
  230. #[test]
  231. fn can_insert_anchor_right() {
  232. let permalinks_ctx = HashMap::new();
  233. let context = Context::new(&GUTENBERG_TERA, true, "base16-ocean-dark".to_string(), "", &permalinks_ctx, InsertAnchor::Right);
  234. let res = markdown_to_html("# Hello", &context).unwrap();
  235. assert_eq!(
  236. res.0,
  237. "<h1 id=\"hello\">Hello<a class=\"gutenberg-anchor\" href=\"#hello\" aria-label=\"Anchor link for: hello\">🔗</a>\n</h1>\n"
  238. );
  239. }
  240. // See https://github.com/Keats/gutenberg/issues/42
  241. #[test]
  242. fn can_insert_anchor_with_exclamation_mark() {
  243. let permalinks_ctx = HashMap::new();
  244. let context = Context::new(&GUTENBERG_TERA, true, "base16-ocean-dark".to_string(), "", &permalinks_ctx, InsertAnchor::Left);
  245. let res = markdown_to_html("# Hello!", &context).unwrap();
  246. assert_eq!(
  247. res.0,
  248. "<h1 id=\"hello\"><a class=\"gutenberg-anchor\" href=\"#hello\" aria-label=\"Anchor link for: hello\">🔗</a>\nHello!</h1>\n"
  249. );
  250. }
  251. // See https://github.com/Keats/gutenberg/issues/53
  252. #[test]
  253. fn can_insert_anchor_with_link() {
  254. let permalinks_ctx = HashMap::new();
  255. let context = Context::new(&GUTENBERG_TERA, true, "base16-ocean-dark".to_string(), "", &permalinks_ctx, InsertAnchor::Left);
  256. let res = markdown_to_html("## [](#xresources)Xresources", &context).unwrap();
  257. assert_eq!(
  258. res.0,
  259. "<h2 id=\"xresources\"><a class=\"gutenberg-anchor\" href=\"#xresources\" aria-label=\"Anchor link for: xresources\">🔗</a>\nXresources</h2>\n"
  260. );
  261. }
  262. #[test]
  263. fn can_insert_anchor_with_other_special_chars() {
  264. let permalinks_ctx = HashMap::new();
  265. let context = Context::new(&GUTENBERG_TERA, true, "base16-ocean-dark".to_string(), "", &permalinks_ctx, InsertAnchor::Left);
  266. let res = markdown_to_html("# Hello*_()", &context).unwrap();
  267. assert_eq!(
  268. res.0,
  269. "<h1 id=\"hello\"><a class=\"gutenberg-anchor\" href=\"#hello\" aria-label=\"Anchor link for: hello\">🔗</a>\nHello*_()</h1>\n"
  270. );
  271. }
  272. #[test]
  273. fn can_make_toc() {
  274. let permalinks_ctx = HashMap::new();
  275. let context = Context::new(
  276. &GUTENBERG_TERA,
  277. true,
  278. "base16-ocean-dark".to_string(),
  279. "https://mysite.com/something",
  280. &permalinks_ctx,
  281. InsertAnchor::Left
  282. );
  283. let res = markdown_to_html(r#"
  284. # Header 1
  285. ## Header 2
  286. ## Another Header 2
  287. ### Last one
  288. "#, &context).unwrap();
  289. let toc = res.1;
  290. assert_eq!(toc.len(), 1);
  291. assert_eq!(toc[0].children.len(), 2);
  292. assert_eq!(toc[0].children[1].children.len(), 1);
  293. }
  294. #[test]
  295. fn can_understand_backtick_in_titles() {
  296. let permalinks_ctx = HashMap::new();
  297. let context = Context::new(&GUTENBERG_TERA, true, "base16-ocean-dark".to_string(), "", &permalinks_ctx, InsertAnchor::None);
  298. let res = markdown_to_html("# `Hello`", &context).unwrap();
  299. assert_eq!(
  300. res.0,
  301. "<h1 id=\"hello\"><code>Hello</code></h1>\n"
  302. );
  303. }
  304. #[test]
  305. fn can_understand_backtick_in_paragraphs() {
  306. let permalinks_ctx = HashMap::new();
  307. let context = Context::new(&GUTENBERG_TERA, true, "base16-ocean-dark".to_string(), "", &permalinks_ctx, InsertAnchor::None);
  308. let res = markdown_to_html("Hello `world`", &context).unwrap();
  309. assert_eq!(
  310. res.0,
  311. "<p>Hello <code>world</code></p>\n"
  312. );
  313. }