Markdown parser fork with extended syntax for personal use.
1use markdown::{
2 mdast::{Definition, Image, ImageReference, Node, Paragraph, ReferenceKind, Root, Text},
3 message, to_html, to_html_with_options, to_mdast,
4 unist::Position,
5 CompileOptions, Constructs, Options, ParseOptions,
6};
7use pretty_assertions::assert_eq;
8
9#[test]
10fn image() -> Result<(), message::Message> {
11 assert_eq!(
12 to_html("[link](/uri \"title\")"),
13 "<p><a href=\"/uri\" title=\"title\">link</a></p>",
14 "should support links"
15 );
16 assert_eq!(
17 to_html(""),
18 "<p><img src=\"/url\" alt=\"foo\" title=\"title\" /></p>",
19 "should support image w/ resource"
20 );
21
22 assert_eq!(
23 to_html("[foo *bar*]: train.jpg \"train & tracks\"\n\n![foo *bar*]"),
24 "<p><img src=\"train.jpg\" alt=\"foo bar\" title=\"train & tracks\" /></p>",
25 "should support image as shortcut reference"
26 );
27
28 assert_eq!(
29 to_html("](/url2)"),
30 "<p><img src=\"/url2\" alt=\"foo bar\" /></p>",
31 "should “support” images in images"
32 );
33
34 assert_eq!(
35 to_html("](/url2)"),
36 "<p><img src=\"/url2\" alt=\"foo bar\" /></p>",
37 "should “support” links in images"
38 );
39
40 assert_eq!(
41 to_html("[foo *bar*]: train.jpg \"train & tracks\"\n\n![foo *bar*][]"),
42 "<p><img src=\"train.jpg\" alt=\"foo bar\" title=\"train & tracks\" /></p>",
43 "should support “content” in images"
44 );
45
46 assert_eq!(
47 to_html("[FOOBAR]: train.jpg \"train & tracks\"\n\n![foo *bar*][foobar]"),
48 "<p><img src=\"train.jpg\" alt=\"foo bar\" title=\"train & tracks\" /></p>",
49 "should support “content” in images"
50 );
51
52 assert_eq!(
53 to_html(""),
54 "<p><img src=\"train.jpg\" alt=\"foo\" /></p>",
55 "should support images w/o title"
56 );
57
58 assert_eq!(
59 to_html("My "),
60 "<p>My <img src=\"/path/to/train.jpg\" alt=\"foo bar\" title=\"title\" /></p>",
61 "should support images w/ lots of whitespace"
62 );
63
64 assert_eq!(
65 to_html(""),
66 "<p><img src=\"url\" alt=\"foo\" /></p>",
67 "should support images w/ enclosed destinations"
68 );
69
70 assert_eq!(
71 to_html(""),
72 "<p><img src=\"/url\" alt=\"\" /></p>",
73 "should support images w/ empty labels"
74 );
75
76 assert_eq!(
77 to_html("[bar]: /url\n\n![foo][bar]"),
78 "<p><img src=\"/url\" alt=\"foo\" /></p>",
79 "should support full references (1)"
80 );
81
82 assert_eq!(
83 to_html("[BAR]: /url\n\n![foo][bar]"),
84 "<p><img src=\"/url\" alt=\"foo\" /></p>",
85 "should support full references (2)"
86 );
87
88 assert_eq!(
89 to_html("[foo]: /url \"title\"\n\n![foo][]"),
90 "<p><img src=\"/url\" alt=\"foo\" title=\"title\" /></p>",
91 "should support collapsed references (1)"
92 );
93
94 assert_eq!(
95 to_html("[*foo* bar]: /url \"title\"\n\n![*foo* bar][]"),
96 "<p><img src=\"/url\" alt=\"foo bar\" title=\"title\" /></p>",
97 "should support collapsed references (2)"
98 );
99
100 assert_eq!(
101 to_html("[foo]: /url \"title\"\n\n![Foo][]"),
102 "<p><img src=\"/url\" alt=\"Foo\" title=\"title\" /></p>",
103 "should support case-insensitive labels"
104 );
105
106 assert_eq!(
107 to_html("[foo]: /url \"title\"\n\n![foo] \n[]"),
108 "<p><img src=\"/url\" alt=\"foo\" title=\"title\" />\n[]</p>",
109 "should not support whitespace between sets of brackets"
110 );
111
112 assert_eq!(
113 to_html("[foo]: /url \"title\"\n\n![foo]"),
114 "<p><img src=\"/url\" alt=\"foo\" title=\"title\" /></p>",
115 "should support shortcut references (1)"
116 );
117
118 assert_eq!(
119 to_html("[*foo* bar]: /url \"title\"\n\n![*foo* bar]"),
120 "<p><img src=\"/url\" alt=\"foo bar\" title=\"title\" /></p>",
121 "should support shortcut references (2)"
122 );
123
124 assert_eq!(
125 to_html("[[foo]]: /url \"title\"\n\n![[foo]]"),
126 "<p>[[foo]]: /url "title"</p>\n<p>![[foo]]</p>",
127 "should not support link labels w/ unescaped brackets"
128 );
129
130 assert_eq!(
131 to_html("[foo]: /url \"title\"\n\n![Foo]"),
132 "<p><img src=\"/url\" alt=\"Foo\" title=\"title\" /></p>",
133 "should support case-insensitive label matching"
134 );
135
136 assert_eq!(
137 to_html("[foo]: /url \"title\"\n\n!\\[foo]"),
138 "<p>![foo]</p>",
139 "should “support” an escaped bracket instead of an image"
140 );
141
142 assert_eq!(
143 to_html("[foo]: /url \"title\"\n\n\\![foo]"),
144 "<p>!<a href=\"/url\" title=\"title\">foo</a></p>",
145 "should support an escaped bang instead of an image, but still have a link"
146 );
147
148 // Extra
149 assert_eq!(
150 to_html("![foo]()"),
151 "<p><img src=\"\" alt=\"foo\" /></p>",
152 "should support images w/o destination"
153 );
154
155 assert_eq!(
156 to_html(""),
157 "<p><img src=\"\" alt=\"foo\" /></p>",
158 "should support images w/ explicit empty destination"
159 );
160
161 assert_eq!(
162 to_html(""),
163 "<p><img src=\"example.png\" alt=\"\" /></p>",
164 "should support images w/o alt"
165 );
166
167 assert_eq!(
168 to_html(""),
169 "<p><img src=\"bravo.png\" alt=\"alpha\" /></p>",
170 "should support images w/ empty title (1)"
171 );
172
173 assert_eq!(
174 to_html(""),
175 "<p><img src=\"bravo.png\" alt=\"alpha\" /></p>",
176 "should support images w/ empty title (2)"
177 );
178
179 assert_eq!(
180 to_html(")"),
181 "<p><img src=\"bravo.png\" alt=\"alpha\" /></p>",
182 "should support images w/ empty title (3)"
183 );
184
185 assert_eq!(
186 to_html(""),
187 "<p><img src=\"example.com/&%C2%A9&\" alt=\"&©&\" title=\"&©&\" /></p>",
188 "should support character references in images"
189 );
190
191 // Extra
192 // See: <https://github.com/commonmark/commonmark.js/issues/192>
193 assert_eq!(
194 to_html(""),
195 "<p><img src=\"\" alt=\"\" /></p>",
196 "should ignore an empty title"
197 );
198
199 assert_eq!(
200 to_html_with_options(
201 "![x]()",
202 &Options {
203 parse: ParseOptions {
204 constructs: Constructs {
205 label_start_image: false,
206 ..Default::default()
207 },
208 ..Default::default()
209 },
210 ..Default::default()
211 }
212 )?,
213 "<p>!<a href=\"\">x</a></p>",
214 "should support turning off label start (image)"
215 );
216
217 assert_eq!(
218 to_html(")"),
219 "<p><img src=\"\" alt=\"\" /></p>",
220 "should ignore non-http protocols by default"
221 );
222
223 assert_eq!(
224 to_html_with_options(
225 ")",
226 &Options {
227 compile: CompileOptions {
228 allow_dangerous_protocol: true,
229 ..Default::default()
230 },
231 ..Default::default()
232 }
233 )?,
234 "<p><img src=\"javascript:alert(1)\" alt=\"\" /></p>",
235 "should allow non-http protocols w/ `allowDangerousProtocol`"
236 );
237
238 assert_eq!(
239 to_html_with_options(
240 ")",
241 &Options {
242 compile: CompileOptions {
243 allow_any_img_src: true,
244 allow_dangerous_protocol: false,
245 ..Default::default()
246 },
247 ..Default::default()
248 }
249 )?,
250 "<p><img src=\"javascript:alert(1)\" alt=\"\" /></p>",
251 "should allow non-http protocols with the `allow_any_img_src` option"
252 );
253
254 assert_eq!(
255 to_mdast(
256 "a ![alpha]() b  c.",
257 &Default::default()
258 )?,
259 Node::Root(Root {
260 children: vec![Node::Paragraph(Paragraph {
261 children: vec![
262 Node::Text(Text {
263 value: "a ".into(),
264 position: Some(Position::new(1, 1, 0, 1, 3, 2))
265 }),
266 Node::Image(Image {
267 alt: "alpha".into(),
268 url: String::new(),
269 title: None,
270 position: Some(Position::new(1, 3, 2, 1, 13, 12))
271 }),
272 Node::Text(Text {
273 value: " b ".into(),
274 position: Some(Position::new(1, 13, 12, 1, 16, 15))
275 }),
276 Node::Image(Image {
277 alt: "bravo".into(),
278 url: "charlie".into(),
279 title: Some("delta".into()),
280 position: Some(Position::new(1, 16, 15, 1, 41, 40))
281 }),
282 Node::Text(Text {
283 value: " c.".into(),
284 position: Some(Position::new(1, 41, 40, 1, 44, 43))
285 })
286 ],
287 position: Some(Position::new(1, 1, 0, 1, 44, 43))
288 })],
289 position: Some(Position::new(1, 1, 0, 1, 44, 43))
290 }),
291 "should support image (resource) as `Image`s in mdast"
292 );
293
294 assert_eq!(
295 to_mdast(
296 "[x]: y\n\na ![x] b ![x][] c ![d][x] e.",
297 &Default::default()
298 )?,
299 Node::Root(Root {
300 children: vec![
301 Node::Definition(Definition {
302 identifier: "x".into(),
303 label: Some("x".into()),
304 url: "y".into(),
305 title: None,
306 position: Some(Position::new(1, 1, 0, 1, 7, 6))
307 }),
308 Node::Paragraph(Paragraph {
309 children: vec![
310 Node::Text(Text {
311 value: "a ".into(),
312 position: Some(Position::new(3, 1, 8, 3, 3, 10))
313 }),
314 Node::ImageReference(ImageReference {
315 reference_kind: ReferenceKind::Shortcut,
316 identifier: "x".into(),
317 label: Some("x".into()),
318 alt: "x".into(),
319 position: Some(Position::new(3, 3, 10, 3, 7, 14))
320 }),
321 Node::Text(Text {
322 value: " b ".into(),
323 position: Some(Position::new(3, 7, 14, 3, 10, 17))
324 }),
325 Node::ImageReference(ImageReference {
326 reference_kind: ReferenceKind::Collapsed,
327 identifier: "x".into(),
328 label: Some("x".into()),
329 alt: "x".into(),
330 position: Some(Position::new(3, 10, 17, 3, 16, 23))
331 }),
332 Node::Text(Text {
333 value: " c ".into(),
334 position: Some(Position::new(3, 16, 23, 3, 19, 26))
335 }),
336 Node::ImageReference(ImageReference {
337 reference_kind: ReferenceKind::Full,
338 identifier: "x".into(),
339 label: Some("x".into()),
340 alt: "d".into(),
341 position: Some(Position::new(3, 19, 26, 3, 26, 33))
342 }),
343 Node::Text(Text {
344 value: " e.".into(),
345 position: Some(Position::new(3, 26, 33, 3, 29, 36))
346 }),
347 ],
348 position: Some(Position::new(3, 1, 8, 3, 29, 36))
349 }),
350 ],
351 position: Some(Position::new(1, 1, 0, 3, 29, 36))
352 }),
353 "should support image (reference) as `ImageReference`s in mdast"
354 );
355 Ok(())
356}