1"""
2Python Markdown
3
4A Python implementation of John Gruber's Markdown.
5
6Documentation: https://python-markdown.github.io/
7GitHub: https://github.com/Python-Markdown/markdown/
8PyPI: https://pypi.org/project/Markdown/
9
10Started by Manfred Stienstra (http://www.dwerg.net/).
11Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
12Currently maintained by Waylan Limberg (https://github.com/waylan),
13Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
14
15Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
16Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
17Copyright 2004 Manfred Stienstra (the original version)
18
19License: BSD (see LICENSE.md for details).
20"""
21
22import unittest
23from markdown.test_tools import TestCase
24
25
26class TestSetextHeaders(TestCase):
27
28    def test_setext_h1(self):
29        self.assertMarkdownRenders(
30            self.dedent(
31                """
32                This is an H1
33                =============
34                """
35            ),
36
37            '<h1>This is an H1</h1>'
38        )
39
40    def test_setext_h2(self):
41        self.assertMarkdownRenders(
42            self.dedent(
43                """
44                This is an H2
45                -------------
46                """
47            ),
48
49            '<h2>This is an H2</h2>'
50        )
51
52    def test_setext_h1_mismatched_length(self):
53        self.assertMarkdownRenders(
54            self.dedent(
55                """
56                This is an H1
57                ===
58                """
59            ),
60
61            '<h1>This is an H1</h1>'
62        )
63
64    def test_setext_h2_mismatched_length(self):
65        self.assertMarkdownRenders(
66            self.dedent(
67                """
68                This is an H2
69                ---
70                """
71            ),
72
73            '<h2>This is an H2</h2>'
74        )
75
76    def test_setext_h1_followed_by_p(self):
77        self.assertMarkdownRenders(
78            self.dedent(
79                """
80                This is an H1
81                =============
82                Followed by a Paragraph with no blank line.
83                """
84            ),
85            self.dedent(
86                """
87                <h1>This is an H1</h1>
88                <p>Followed by a Paragraph with no blank line.</p>
89                """
90            )
91        )
92
93    def test_setext_h2_followed_by_p(self):
94        self.assertMarkdownRenders(
95            self.dedent(
96                """
97                This is an H2
98                -------------
99                Followed by a Paragraph with no blank line.
100                """
101            ),
102            self.dedent(
103                """
104                <h2>This is an H2</h2>
105                <p>Followed by a Paragraph with no blank line.</p>
106                """
107            )
108        )
109
110    # TODO: fix this
111    # see https://johnmacfarlane.net/babelmark2/?normalize=1&text=Paragraph%0AAn+H1%0A%3D%3D%3D%3D%3D
112    @unittest.skip('This is broken in Python-Markdown')
113    def test_p_followed_by_setext_h1(self):
114        self.assertMarkdownRenders(
115            self.dedent(
116                """
117                This is a Paragraph.
118                Followed by an H1 with no blank line.
119                =====================================
120                """
121            ),
122            self.dedent(
123                """
124                <p>This is a Paragraph.</p>
125                <h1>Followed by an H1 with no blank line.</h1>
126                """
127            )
128        )
129
130    # TODO: fix this
131    # see https://johnmacfarlane.net/babelmark2/?normalize=1&text=Paragraph%0AAn+H2%0A-----
132    @unittest.skip('This is broken in Python-Markdown')
133    def test_p_followed_by_setext_h2(self):
134        self.assertMarkdownRenders(
135            self.dedent(
136                """
137                This is a Paragraph.
138                Followed by an H2 with no blank line.
139                -------------------------------------
140                """
141            ),
142            self.dedent(
143                """
144                <p>This is a Paragraph.</p>
145                <h2>Followed by an H2 with no blank line.</h2>
146                """
147            )
148        )
149
150
151class TestHashHeaders(TestCase):
152
153    def test_hash_h1_open(self):
154        self.assertMarkdownRenders(
155            '# This is an H1',
156
157            '<h1>This is an H1</h1>'
158        )
159
160    def test_hash_h2_open(self):
161        self.assertMarkdownRenders(
162            '## This is an H2',
163
164            '<h2>This is an H2</h2>'
165        )
166
167    def test_hash_h3_open(self):
168        self.assertMarkdownRenders(
169            '### This is an H3',
170
171            '<h3>This is an H3</h3>'
172        )
173
174    def test_hash_h4_open(self):
175        self.assertMarkdownRenders(
176            '#### This is an H4',
177
178            '<h4>This is an H4</h4>'
179        )
180
181    def test_hash_h5_open(self):
182        self.assertMarkdownRenders(
183            '##### This is an H5',
184
185            '<h5>This is an H5</h5>'
186        )
187
188    def test_hash_h6_open(self):
189        self.assertMarkdownRenders(
190            '###### This is an H6',
191
192            '<h6>This is an H6</h6>'
193        )
194
195    def test_hash_gt6_open(self):
196        self.assertMarkdownRenders(
197            '####### This is an H6',
198
199            '<h6># This is an H6</h6>'
200        )
201
202    def test_hash_h1_open_missing_space(self):
203        self.assertMarkdownRenders(
204            '#This is an H1',
205
206            '<h1>This is an H1</h1>'
207        )
208
209    def test_hash_h2_open_missing_space(self):
210        self.assertMarkdownRenders(
211            '##This is an H2',
212
213            '<h2>This is an H2</h2>'
214        )
215
216    def test_hash_h3_open_missing_space(self):
217        self.assertMarkdownRenders(
218            '###This is an H3',
219
220            '<h3>This is an H3</h3>'
221        )
222
223    def test_hash_h4_open_missing_space(self):
224        self.assertMarkdownRenders(
225            '####This is an H4',
226
227            '<h4>This is an H4</h4>'
228        )
229
230    def test_hash_h5_open_missing_space(self):
231        self.assertMarkdownRenders(
232            '#####This is an H5',
233
234            '<h5>This is an H5</h5>'
235        )
236
237    def test_hash_h6_open_missing_space(self):
238        self.assertMarkdownRenders(
239            '######This is an H6',
240
241            '<h6>This is an H6</h6>'
242        )
243
244    def test_hash_gt6_open_missing_space(self):
245        self.assertMarkdownRenders(
246            '#######This is an H6',
247
248            '<h6>#This is an H6</h6>'
249        )
250
251    def test_hash_h1_closed(self):
252        self.assertMarkdownRenders(
253            '# This is an H1 #',
254
255            '<h1>This is an H1</h1>'
256        )
257
258    def test_hash_h2_closed(self):
259        self.assertMarkdownRenders(
260            '## This is an H2 ##',
261
262            '<h2>This is an H2</h2>'
263        )
264
265    def test_hash_h3_closed(self):
266        self.assertMarkdownRenders(
267            '### This is an H3 ###',
268
269            '<h3>This is an H3</h3>'
270        )
271
272    def test_hash_h4_closed(self):
273        self.assertMarkdownRenders(
274            '#### This is an H4 ####',
275
276            '<h4>This is an H4</h4>'
277        )
278
279    def test_hash_h5_closed(self):
280        self.assertMarkdownRenders(
281            '##### This is an H5 #####',
282
283            '<h5>This is an H5</h5>'
284        )
285
286    def test_hash_h6_closed(self):
287        self.assertMarkdownRenders(
288            '###### This is an H6 ######',
289
290            '<h6>This is an H6</h6>'
291        )
292
293    def test_hash_gt6_closed(self):
294        self.assertMarkdownRenders(
295            '####### This is an H6 #######',
296
297            '<h6># This is an H6</h6>'
298        )
299
300    def test_hash_h1_closed_missing_space(self):
301        self.assertMarkdownRenders(
302            '#This is an H1#',
303
304            '<h1>This is an H1</h1>'
305        )
306
307    def test_hash_h2_closed_missing_space(self):
308        self.assertMarkdownRenders(
309            '##This is an H2##',
310
311            '<h2>This is an H2</h2>'
312        )
313
314    def test_hash_h3_closed_missing_space(self):
315        self.assertMarkdownRenders(
316            '###This is an H3###',
317
318            '<h3>This is an H3</h3>'
319        )
320
321    def test_hash_h4_closed_missing_space(self):
322        self.assertMarkdownRenders(
323            '####This is an H4####',
324
325            '<h4>This is an H4</h4>'
326        )
327
328    def test_hash_h5_closed_missing_space(self):
329        self.assertMarkdownRenders(
330            '#####This is an H5#####',
331
332            '<h5>This is an H5</h5>'
333        )
334
335    def test_hash_h6_closed_missing_space(self):
336        self.assertMarkdownRenders(
337            '######This is an H6######',
338
339            '<h6>This is an H6</h6>'
340        )
341
342    def test_hash_gt6_closed_missing_space(self):
343        self.assertMarkdownRenders(
344            '#######This is an H6#######',
345
346            '<h6>#This is an H6</h6>'
347        )
348
349    def test_hash_h1_closed_mismatch(self):
350        self.assertMarkdownRenders(
351            '# This is an H1 ##',
352
353            '<h1>This is an H1</h1>'
354        )
355
356    def test_hash_h2_closed_mismatch(self):
357        self.assertMarkdownRenders(
358            '## This is an H2 #',
359
360            '<h2>This is an H2</h2>'
361        )
362
363    def test_hash_h3_closed_mismatch(self):
364        self.assertMarkdownRenders(
365            '### This is an H3 #',
366
367            '<h3>This is an H3</h3>'
368        )
369
370    def test_hash_h4_closed_mismatch(self):
371        self.assertMarkdownRenders(
372            '#### This is an H4 #',
373
374            '<h4>This is an H4</h4>'
375        )
376
377    def test_hash_h5_closed_mismatch(self):
378        self.assertMarkdownRenders(
379            '##### This is an H5 #',
380
381            '<h5>This is an H5</h5>'
382        )
383
384    def test_hash_h6_closed_mismatch(self):
385        self.assertMarkdownRenders(
386            '###### This is an H6 #',
387
388            '<h6>This is an H6</h6>'
389        )
390
391    def test_hash_gt6_closed_mismatch(self):
392        self.assertMarkdownRenders(
393            '####### This is an H6 ##################',
394
395            '<h6># This is an H6</h6>'
396        )
397
398    def test_hash_h1_followed_by_p(self):
399        self.assertMarkdownRenders(
400            self.dedent(
401                """
402                # This is an H1
403                Followed by a Paragraph with no blank line.
404                """
405            ),
406            self.dedent(
407                """
408                <h1>This is an H1</h1>
409                <p>Followed by a Paragraph with no blank line.</p>
410                """
411            )
412        )
413
414    def test_hash_h2_followed_by_p(self):
415        self.assertMarkdownRenders(
416            self.dedent(
417                """
418                ## This is an H2
419                Followed by a Paragraph with no blank line.
420                """
421            ),
422            self.dedent(
423                """
424                <h2>This is an H2</h2>
425                <p>Followed by a Paragraph with no blank line.</p>
426                """
427            )
428        )
429
430    def test_hash_h3_followed_by_p(self):
431        self.assertMarkdownRenders(
432            self.dedent(
433                """
434                ### This is an H3
435                Followed by a Paragraph with no blank line.
436                """
437            ),
438            self.dedent(
439                """
440                <h3>This is an H3</h3>
441                <p>Followed by a Paragraph with no blank line.</p>
442                """
443            )
444        )
445
446    def test_hash_h4_followed_by_p(self):
447        self.assertMarkdownRenders(
448            self.dedent(
449                """
450                #### This is an H4
451                Followed by a Paragraph with no blank line.
452                """
453            ),
454            self.dedent(
455                """
456                <h4>This is an H4</h4>
457                <p>Followed by a Paragraph with no blank line.</p>
458                """
459            )
460        )
461
462    def test_hash_h5_followed_by_p(self):
463        self.assertMarkdownRenders(
464            self.dedent(
465                """
466                ##### This is an H5
467                Followed by a Paragraph with no blank line.
468                """
469            ),
470            self.dedent(
471                """
472                <h5>This is an H5</h5>
473                <p>Followed by a Paragraph with no blank line.</p>
474                """
475            )
476        )
477
478    def test_hash_h6_followed_by_p(self):
479        self.assertMarkdownRenders(
480            self.dedent(
481                """
482                ###### This is an H6
483                Followed by a Paragraph with no blank line.
484                """
485            ),
486            self.dedent(
487                """
488                <h6>This is an H6</h6>
489                <p>Followed by a Paragraph with no blank line.</p>
490                """
491            )
492        )
493
494    def test_hash_h1_leading_space(self):
495        self.assertMarkdownRenders(
496            ' # This is an H1',
497
498            '<p># This is an H1</p>'
499        )
500
501    def test_hash_h2_leading_space(self):
502        self.assertMarkdownRenders(
503            ' ## This is an H2',
504
505            '<p>## This is an H2</p>'
506        )
507
508    def test_hash_h3_leading_space(self):
509        self.assertMarkdownRenders(
510            ' ### This is an H3',
511
512            '<p>### This is an H3</p>'
513        )
514
515    def test_hash_h4_leading_space(self):
516        self.assertMarkdownRenders(
517            ' #### This is an H4',
518
519            '<p>#### This is an H4</p>'
520        )
521
522    def test_hash_h5_leading_space(self):
523        self.assertMarkdownRenders(
524            ' ##### This is an H5',
525
526            '<p>##### This is an H5</p>'
527        )
528
529    def test_hash_h6_leading_space(self):
530        self.assertMarkdownRenders(
531            ' ###### This is an H6',
532
533            '<p>###### This is an H6</p>'
534        )
535
536    def test_hash_h1_open_trailing_space(self):
537        self.assertMarkdownRenders(
538            '# This is an H1 ',
539
540            '<h1>This is an H1</h1>'
541        )
542
543    def test_hash_h2_open_trailing_space(self):
544        self.assertMarkdownRenders(
545            '## This is an H2 ',
546
547            '<h2>This is an H2</h2>'
548        )
549
550    def test_hash_h3_open_trailing_space(self):
551        self.assertMarkdownRenders(
552            '### This is an H3 ',
553
554            '<h3>This is an H3</h3>'
555        )
556
557    def test_hash_h4_open_trailing_space(self):
558        self.assertMarkdownRenders(
559            '#### This is an H4 ',
560
561            '<h4>This is an H4</h4>'
562        )
563
564    def test_hash_h5_open_trailing_space(self):
565        self.assertMarkdownRenders(
566            '##### This is an H5 ',
567
568            '<h5>This is an H5</h5>'
569        )
570
571    def test_hash_h6_open_trailing_space(self):
572        self.assertMarkdownRenders(
573            '###### This is an H6 ',
574
575            '<h6>This is an H6</h6>'
576        )
577
578    def test_hash_gt6_open_trailing_space(self):
579        self.assertMarkdownRenders(
580            '####### This is an H6 ',
581
582            '<h6># This is an H6</h6>'
583        )
584
585    # TODO: Possibly change the following behavior. While this follows the behavior
586    # of markdown.pl, it is rather uncommon and not nessecarily intuitive.
587    # See: https://johnmacfarlane.net/babelmark2/?normalize=1&text=%23+This+is+an+H1+%23+
588    def test_hash_h1_closed_trailing_space(self):
589        self.assertMarkdownRenders(
590            '# This is an H1 # ',
591
592            '<h1>This is an H1 #</h1>'
593        )
594
595    def test_hash_h2_closed_trailing_space(self):
596        self.assertMarkdownRenders(
597            '## This is an H2 ## ',
598
599            '<h2>This is an H2 ##</h2>'
600        )
601
602    def test_hash_h3_closed_trailing_space(self):
603        self.assertMarkdownRenders(
604            '### This is an H3 ### ',
605
606            '<h3>This is an H3 ###</h3>'
607        )
608
609    def test_hash_h4_closed_trailing_space(self):
610        self.assertMarkdownRenders(
611            '#### This is an H4 #### ',
612
613            '<h4>This is an H4 ####</h4>'
614        )
615
616    def test_hash_h5_closed_trailing_space(self):
617        self.assertMarkdownRenders(
618            '##### This is an H5 ##### ',
619
620            '<h5>This is an H5 #####</h5>'
621        )
622
623    def test_hash_h6_closed_trailing_space(self):
624        self.assertMarkdownRenders(
625            '###### This is an H6 ###### ',
626
627            '<h6>This is an H6 ######</h6>'
628        )
629
630    def test_hash_gt6_closed_trailing_space(self):
631        self.assertMarkdownRenders(
632            '####### This is an H6 ####### ',
633
634            '<h6># This is an H6 #######</h6>'
635        )
636
637    def test_no_blank_lines_between_hashs(self):
638        self.assertMarkdownRenders(
639            self.dedent(
640                """
641                # This is an H1
642                ## This is an H2
643                """
644            ),
645            self.dedent(
646                """
647                <h1>This is an H1</h1>
648                <h2>This is an H2</h2>
649                """
650            )
651        )
652
653    def test_random_hash_levels(self):
654        self.assertMarkdownRenders(
655            self.dedent(
656                """
657                ### H3
658                ###### H6
659                # H1
660                ##### H5
661                #### H4
662                ## H2
663                ### H3
664                """
665            ),
666            self.dedent(
667                """
668                <h3>H3</h3>
669                <h6>H6</h6>
670                <h1>H1</h1>
671                <h5>H5</h5>
672                <h4>H4</h4>
673                <h2>H2</h2>
674                <h3>H3</h3>
675                """
676            )
677        )
678
679    def test_hash_followed_by_p(self):
680        self.assertMarkdownRenders(
681            self.dedent(
682                """
683                # This is an H1
684                Followed by a Paragraph with no blank line.
685                """
686            ),
687            self.dedent(
688                """
689                <h1>This is an H1</h1>
690                <p>Followed by a Paragraph with no blank line.</p>
691                """
692            )
693        )
694
695    def test_p_followed_by_hash(self):
696        self.assertMarkdownRenders(
697            self.dedent(
698                """
699                This is a Paragraph.
700                # Followed by an H1 with no blank line.
701                """
702            ),
703            self.dedent(
704                """
705                <p>This is a Paragraph.</p>
706                <h1>Followed by an H1 with no blank line.</h1>
707                """
708            )
709        )
710
711    def test_escaped_hash(self):
712        self.assertMarkdownRenders(
713            "### H3 \\###",
714            self.dedent(
715                """
716                <h3>H3 #</h3>
717                """
718            )
719        )
720
721    def test_unescaped_hash(self):
722        self.assertMarkdownRenders(
723            "### H3 \\\\###",
724            self.dedent(
725                """
726                <h3>H3 \\</h3>
727                """
728            )
729        )
730