1 use super::render::text_renderer::{RichAnnotation, TaggedLine, TrivialDecorator};
2 use super::{from_read, from_read_with_decorator, parse, TextDecorator};
3
4 /// Like assert_eq!(), but prints out the results normally as well
5 macro_rules! assert_eq_str {
6 ($a:expr, $b:expr) => {
7 if $a != $b {
8 println!("<<<\n{}===\n{}>>>", $a, $b);
9 assert_eq!($a, $b);
10 }
11 };
12 }
test_html(input: &[u8], expected: &str, width: usize)13 fn test_html(input: &[u8], expected: &str, width: usize) {
14 assert_eq_str!(from_read(input, width), expected);
15 }
16
test_html_decorator<D>(input: &[u8], expected: &str, width: usize, decorator: D) where D: TextDecorator,17 fn test_html_decorator<D>(input: &[u8], expected: &str, width: usize, decorator: D)
18 where
19 D: TextDecorator,
20 {
21 let output = from_read_with_decorator(input, width, decorator);
22 assert_eq_str!(output, expected);
23 }
24
25 #[test]
test_table()26 fn test_table() {
27 test_html(
28 br##"
29 <table>
30 <tr>
31 <td>1</td>
32 <td>2</td>
33 <td>3</td>
34 </tr>
35 </table>
36 "##,
37 r#"───┬───┬────
38 1 │2 │3
39 ───┴───┴────
40 "#,
41 12,
42 );
43 }
44
45 #[test]
test_thead()46 fn test_thead() {
47 test_html(
48 br##"
49 <table>
50 <thead>
51 <tr>
52 <th>Col1</th>
53 <th>Col2</th>
54 <th>Col3</th>
55 </tr>
56 </thead>
57 <tbody>
58 <tr>
59 <td>1</td>
60 <td>2</td>
61 <td>3</td>
62 </tr>
63 </tbody>
64 </table>
65 "##,
66 r#"────┬────┬─────
67 Col1│Col2│Col3
68 ────┼────┼─────
69 1 │2 │3
70 ────┴────┴─────
71 "#,
72 15,
73 );
74 }
75
76 #[test]
test_colspan()77 fn test_colspan() {
78 test_html(
79 br##"
80 <table>
81 <tr>
82 <td>1</td>
83 <td>2</td>
84 <td>3</td>
85 </tr>
86 <tr>
87 <td colspan="2">12</td>
88 <td>3</td>
89 </tr>
90 <tr>
91 <td>1</td>
92 <td colspan="2">23</td>
93 </tr>
94 </table>
95 "##,
96 r#"───┬───┬────
97 1 │2 │3
98 ───┴───┼────
99 12 │3
100 ───┬───┴────
101 1 │23
102 ───┴────────
103 "#,
104 12,
105 );
106 }
107
108 #[test]
test_para()109 fn test_para() {
110 assert_eq_str!(from_read(&b"<p>Hello</p>"[..], 10), "Hello\n");
111 }
112
113 #[test]
test_para2()114 fn test_para2() {
115 assert_eq_str!(
116 from_read(&b"<p>Hello, world!</p>"[..], 20),
117 "Hello, world!\n"
118 );
119 }
120
121 #[test]
test_blockquote()122 fn test_blockquote() {
123 assert_eq_str!(
124 from_read(
125 &br#"<p>Hello</p>
126 <blockquote>One, two, three</blockquote>
127 <p>foo</p>
128 "#[..],
129 12
130 ),
131 r#"Hello
132
133 > One, two,
134 > three
135
136 foo
137 "#
138 );
139 }
140
141 #[test]
test_ul()142 fn test_ul() {
143 test_html(
144 br#"
145 <ul>
146 <li>Item one</li>
147 <li>Item two</li>
148 <li>Item three</li>
149 </ul>
150 "#,
151 r#"* Item one
152 * Item two
153 * Item
154 three
155 "#,
156 10,
157 );
158 }
159
160 #[test]
test_ol1()161 fn test_ol1() {
162 test_html(
163 br#"
164 <ol>
165 <li>Item one</li>
166 <li>Item two</li>
167 <li>Item three</li>
168 </ol>
169 "#,
170 r#"1. Item one
171 2. Item two
172 3. Item
173 three
174 "#,
175 11,
176 );
177 }
178
179 #[test]
test_ol2()180 fn test_ol2() {
181 test_html(
182 br#"
183 <ol>
184 <li>Item one</li>
185 <li>Item two</li>
186 <li>Item three</li>
187 <li>Item four</li>
188 <li>Item five</li>
189 <li>Item six</li>
190 <li>Item seven</li>
191 <li>Item eight</li>
192 <li>Item nine</li>
193 <li>Item ten</li>
194 </ol>
195 "#,
196 r#"1. Item one
197 2. Item two
198 3. Item three
199 4. Item four
200 5. Item five
201 6. Item six
202 7. Item seven
203 8. Item eight
204 9. Item nine
205 10. Item ten
206 "#,
207 20,
208 );
209 }
210
211 #[test]
test_ol_start()212 fn test_ol_start() {
213 test_html(
214 br#"
215 <ol start="3">
216 <li>Item three</li>
217 <li>Item four</li>
218 </ol>
219 "#,
220 r#"3. Item three
221 4. Item four
222 "#,
223 20,
224 );
225 }
226
227 #[test]
test_ol_start_9()228 fn test_ol_start_9() {
229 test_html(
230 br#"
231 <ol start="9">
232 <li>Item nine</li>
233 <li>Item ten</li>
234 </ol>
235 "#,
236 r#"9. Item nine
237 10. Item ten
238 "#,
239 20,
240 );
241 }
242
243 #[test]
test_ol_start_neg()244 fn test_ol_start_neg() {
245 test_html(
246 br#"
247 <ol start="-1">
248 <li>Item minus one</li>
249 <li>Item zero</li>
250 <li>Item one</li>
251 </ol>
252 "#,
253 r#"-1. Item minus one
254 0. Item zero
255 1. Item one
256 "#,
257 20,
258 );
259 }
260
261 #[test]
test_strip_nl()262 fn test_strip_nl() {
263 test_html(
264 br#"
265 <p>
266 One
267 Two
268 Three
269 </p>
270 "#,
271 "One Two Three\n",
272 40,
273 );
274 }
275 #[test]
test_strip_nl2()276 fn test_strip_nl2() {
277 test_html(
278 br#"
279 <p>
280 One
281 <span>
282 Two
283 </span>
284 Three
285 </p>
286 "#,
287 "One Two Three\n",
288 40,
289 );
290 }
291 #[test]
test_strip_nl_tbl()292 fn test_strip_nl_tbl() {
293 test_html(
294 br#"
295 <table>
296 <tr>
297 <td>
298 One
299 <span>
300 Two
301 </span>
302 Three
303 </td>
304 </tr>
305 </table>
306 "#,
307 r"────────────────────
308 One Two Three
309 ────────────────────
310 ",
311 20,
312 );
313 }
314 #[test]
test_unknown_element()315 fn test_unknown_element() {
316 test_html(
317 br#"
318 <foo>
319 <table>
320 <tr>
321 <td>
322 One
323 <span><yyy>
324 Two
325 </yyy></span>
326 Three
327 </td>
328 </tr>
329 </table>
330 </foo>
331 "#,
332 r"────────────────────
333 One Two Three
334 ────────────────────
335 ",
336 20,
337 );
338 }
339 #[test]
test_strip_nl_tbl_p()340 fn test_strip_nl_tbl_p() {
341 test_html(
342 br#"
343 <table>
344 <tr>
345 <td><p>
346 One
347 <span>
348 Two
349 </span>
350 Three
351 </p></td>
352 </tr>
353 </table>
354 "#,
355 r"────────────────────
356 One Two Three
357 ────────────────────
358 ",
359 20,
360 );
361 }
362 #[test]
test_pre()363 fn test_pre() {
364 test_html(
365 br#"
366 <pre>foo
367 bar
368 wib asdf;
369 </pre>
370 <p>Hello</p>
371 "#,
372 r"foo
373 bar
374 wib asdf;
375
376 Hello
377 ",
378 20,
379 );
380 }
381 #[test]
test_link()382 fn test_link() {
383 test_html(
384 br#"
385 <p>Hello, <a href="http://www.example.com/">world</a></p>"#,
386 r"Hello, [world][1]
387
388 [1] http://www.example.com/
389 ",
390 80,
391 );
392 }
393 #[test]
test_link2()394 fn test_link2() {
395 test_html(
396 br#"
397 <p>Hello, <a href="http://www.example.com/">world</a>!</p>"#,
398 r"Hello, [world][1]!
399
400 [1] http://www.example.com/
401 ",
402 80,
403 );
404 }
405
406 #[test]
test_link3()407 fn test_link3() {
408 test_html(
409 br#"
410 <p>Hello, <a href="http://www.example.com/">w</a>orld</p>"#,
411 r"Hello, [w][1]orld
412
413 [1] http://www.example.com/
414 ",
415 80,
416 );
417 }
418
419 #[test]
test_link_wrap()420 fn test_link_wrap() {
421 test_html(
422 br#"
423 <a href="http://www.example.com/">Hello</a>"#,
424 r"[Hello][1]
425
426 [1] http:/
427 /www.examp
428 le.com/
429 ",
430 10,
431 );
432 }
433
434 #[test]
test_wrap()435 fn test_wrap() {
436 test_html(
437 br"<p>Hello, world. Superlongwordreally</p>",
438 r#"Hello,
439 world.
440 Superlon
441 gwordrea
442 lly
443 "#,
444 8,
445 );
446 }
447
448 #[test]
test_wrap2()449 fn test_wrap2() {
450 test_html(
451 br"<p>Hello, world. This is a long sentence with a
452 few words, which we want to be wrapped correctly.</p>",
453 r#"Hello, world. This
454 is a long sentence
455 with a few words,
456 which we want to be
457 wrapped correctly.
458 "#,
459 20,
460 );
461 }
462
463 #[test]
test_wrap3()464 fn test_wrap3() {
465 test_html(
466 br#"<p><a href="dest">http://example.org/blah/</a> one two three"#,
467 r#"[http://example.org/blah/
468 ][1] one two three
469
470 [1] dest
471 "#,
472 25,
473 );
474 }
475
476 #[test]
test_div()477 fn test_div() {
478 test_html(
479 br"<p>Hello</p><div>Div</div>",
480 r#"Hello
481
482 Div
483 "#,
484 20,
485 );
486 test_html(
487 br"<p>Hello</p><div>Div</div><div>Div2</div>",
488 r#"Hello
489
490 Div
491 Div2
492 "#,
493 20,
494 );
495 }
496
497 #[test]
test_img_alt()498 fn test_img_alt() {
499 test_html(
500 br"<p>Hello <img src='foo.jpg' alt='world'></p>",
501 "Hello [world]\n",
502 80,
503 );
504 }
505
506 #[test]
test_br()507 fn test_br() {
508 test_html(br"<p>Hello<br/>World</p>", "Hello\nWorld\n", 20);
509 }
510
511 #[test]
test_br2()512 fn test_br2() {
513 test_html(br"<p>Hello<br/><br/>World</p>", "Hello\n\nWorld\n", 20);
514 }
515
516 #[test]
test_br3()517 fn test_br3() {
518 test_html(br"<p>Hello<br/> <br/>World</p>", "Hello\n\nWorld\n", 20);
519 }
520
521 #[test]
test_subblock()522 fn test_subblock() {
523 test_html(
524 br#"<div>
525 <div>Here's a <a href="https://example.com/">link</a>.</div>
526 <div><ul>
527 <li>Bullet</li>
528 <li>Bullet</li>
529 <li>Bullet</li>
530 </ul></div>
531 </div>"#,
532 r"Here's a [link][1].
533
534 * Bullet
535 * Bullet
536 * Bullet
537
538 [1] https://example.com/
539 ",
540 80,
541 );
542 }
543
544 #[test]
545 fn test_controlchar() {
546 test_html("Foo\u{0080}Bar".as_bytes(), "FooBar\n", 80);
547 test_html("Foo\u{0080}Bar".as_bytes(), "FooB\nar\n", 4);
548 test_html("FooBa\u{0080}r".as_bytes(), "FooB\nar\n", 4);
549 }
550
551 #[test]
552 fn test_nested_table_1() {
553 test_html(
554 br##"
555 <table>
556 <tr>
557 <td>
558 <table><tr><td>1</td><td>2</td><td>3</td></tr></table>
559 </td>
560 <td>
561 <table><tr><td>4</td><td>5</td><td>6</td></tr></table>
562 </td>
563 <td>
564 <table><tr><td>7</td><td>8</td><td>9</td></tr></table>
565 </td>
566 </tr>
567 <tr>
568 <td>
569 <table><tr><td>1</td><td>2</td><td>3</td></tr></table>
570 </td>
571 <td>
572 <table><tr><td>4</td><td>5</td><td>6</td></tr></table>
573 </td>
574 <td>
575 <table><tr><td>7</td><td>8</td><td>9</td></tr></table>
576 </td>
577 </tr>
578 <tr>
579 <td>
580 <table><tr><td>1</td><td>2</td><td>3</td></tr></table>
581 </td>
582 <td>
583 <table><tr><td>4</td><td>5</td><td>6</td></tr></table>
584 </td>
585 <td>
586 <table><tr><td>7</td><td>8</td><td>9</td></tr></table>
587 </td>
588 </tr>
589 </table>
590 "##,
591 r#"─┬─┬──┬─┬─┬──┬─┬─┬───
592 1│2│3 │4│5│6 │7│8│9
593 ─┼─┼──┼─┼─┼──┼─┼─┼───
594 1│2│3 │4│5│6 │7│8│9
595 ─┼─┼──┼─┼─┼──┼─┼─┼───
596 1│2│3 │4│5│6 │7│8│9
597 ─┴─┴──┴─┴─┴──┴─┴─┴───
598 "#,
599 21,
600 );
601 }
602
603 #[test]
604 fn test_nested_table_2() {
605 test_html(
606 br##"
607 <table>
608 <tr>
609 <td>
610 <table>
611 <tr><td>1</td><td>a</td></tr>
612 <tr><td>2</td><td>b</td></tr>
613 </table>
614 </td>
615 <td><pre>one
616 two
617 three
618 four
619 five
620 </pre>
621 </td>
622 </tr>
623 </table>
624 "##,
625 r#"─┬───┬─────
626 1│a │one
627 ─┼───│two
628 2│b │three
629 │ │four
630 │ │five
631 ─┴───┴─────
632 "#,
633 11,
634 );
635 }
636
637 #[test]
638 fn test_h1() {
639 test_html(
640 br##"
641 <h1>Hi</h1>
642 <p>foo</p>
643 "##,
644 r#"# Hi
645
646 foo
647 "#,
648 21,
649 );
650 }
651
652 #[test]
653 fn test_h3() {
654 test_html(
655 br##"
656 <h3>Hi</h3>
657 <p>foo</p>
658 "##,
659 r#"### Hi
660
661 foo
662 "#,
663 21,
664 );
665 }
666
667 // General test that spacing is preserved
668 #[test]
669 fn test_pre2() {
670 test_html(
671 br##"<pre>Hello sp
672 world</pre>"##,
673 r#"Hello sp
674 world
675 "#,
676 21,
677 );
678 }
679
680 // Check that spans work correctly inside <pre>
681 #[test]
682 fn test_pre_span() {
683 test_html(
684 br##"
685 <pre>Hello <span>$</span>sp
686 <span>Hi</span> <span>$</span><span>foo</span>
687 <span>Hi</span> <span>foo</span><span>, </span><span>bar</span>
688 </pre>"##,
689 r#"Hello $sp
690 Hi $foo
691 Hi foo, bar
692 "#,
693 21,
694 );
695 }
696
697 // Check tab behaviour
698 #[test]
699 fn test_pre_tab() {
700 test_html(b"<pre>\tworld</pre>", " world\n", 40);
701 test_html(b"<pre>H\tworld</pre>", "H world\n", 40);
702 test_html(b"<pre>He\tworld</pre>", "He world\n", 40);
703 test_html(b"<pre>Hel\tworld</pre>", "Hel world\n", 40);
704 test_html(b"<pre>Hell\tworld</pre>", "Hell world\n", 40);
705 test_html(b"<pre>Hello\tworld</pre>", "Hello world\n", 40);
706 test_html(b"<pre>Helloo\tworld</pre>", "Helloo world\n", 40);
707 test_html(b"<pre>Hellooo\tworld</pre>", "Hellooo world\n", 40);
708 test_html(b"<pre>Helloooo\tworld</pre>", "Helloooo world\n", 40);
709 }
710
711 #[test]
712 fn test_em_strong() {
713 test_html(
714 br##"
715 <p>Hi <em>em</em> <strong>strong</strong></p>
716 "##,
717 r#"Hi *em* **strong**
718 "#,
719 21,
720 );
721 }
722
723 #[test]
724 #[ignore] // Not yet fixed!
725 fn test_nbsp_indent() {
726 test_html(
727 br##"
728 <div>Top</div>
729 <div> Indented</div>
730 <div> Indented again</div>
731 "##,
732 r#"Top
733 Indented
734 Indented again
735 "#,
736 21,
737 );
738 }
739
740 #[test]
741 fn test_deeply_nested() {
742 use ::std::iter::repeat;
743 let html = repeat("<foo>").take(1000).collect::<Vec<_>>().concat();
744 test_html(html.as_bytes(), "", 10);
745 }
746
747 #[test]
748 fn test_deeply_nested_table() {
749 use ::std::iter::repeat;
750 let html = repeat("<table><tr><td>hi</td><td>")
751 .take(1000)
752 .collect::<Vec<_>>()
753 .concat()
754 + &repeat("</td></tr></table>")
755 .take(1000)
756 .collect::<Vec<_>>()
757 .concat();
758 test_html(
759 html.as_bytes(),
760 r#"────┬─┬───
761 hi │h│
762 │i│
763 ────┴─┴───
764 "#,
765 10,
766 );
767 }
768
769 #[test]
770 fn test_table_no_id() {
771 let html = r#"<html><body><table>
772 <tr>
773 <td>hi, world</td>
774 </tr>
775 </table></body></html>"#;
776 test_html(
777 html.as_bytes(),
778 r#"──────────
779 hi, world
780 ──────────
781 "#,
782 10,
783 );
784 }
785
786 #[test]
787 fn test_table_cell_id() {
788 let html = r#"<html><body><table>
789 <tr>
790 <td id="bodyCell">hi, world</td>
791 </tr>
792 </table></body></html>"#;
793 test_html(
794 html.as_bytes(),
795 r#"──────────
796 hi, world
797 ──────────
798 "#,
799 10,
800 );
801 }
802
803 #[test]
804 fn test_table_row_id() {
805 let html = r#"<html><body><table>
806 <tr id="bodyrow">
807 <td>hi, world</td>
808 </tr>
809 </table></body></html>"#;
810 test_html(
811 html.as_bytes(),
812 r#"──────────
813 hi, world
814 ──────────
815 "#,
816 10,
817 );
818 }
819
820 #[test]
821 fn test_table_table_id() {
822 let html = r#"<html><body><table id="bodytable">
823 <tr>
824 <td>hi, world</td>
825 </tr>
826 </table></body></html>"#;
827 test_html(
828 html.as_bytes(),
829 r#"──────────
830 hi, world
831 ──────────
832 "#,
833 10,
834 );
835 }
836
837 #[test]
838 fn test_table_tbody_id() {
839 let html = r#"<html><body><table>
840 <tbody id="tb">
841 <tr>
842 <td>hi, world</td>
843 </tr>
844 </tbody>
845 </table></body></html>"#;
846 test_html(
847 html.as_bytes(),
848 r#"──────────
849 hi, world
850 ──────────
851 "#,
852 10,
853 );
854 }
855
856 #[test]
857 fn test_header_width() {
858 //0 size
859 test_html(
860 br##"
861 <h2>
862 <table>
863 <h3>Anything</h3>
864 </table>
865 </h2>
866 "##,
867 r#"## ### A
868 ## ### n
869 ## ### y
870 ## ### t
871 ## ### h
872 ## ### i
873 ## ### n
874 ## ### g
875 ##
876 ## ────
877 "#,
878 7,
879 );
880 //Underflow
881 test_html(
882 br##"
883 <h2>
884 <table>
885 <h3>Anything</h3>
886 </table>
887 </h2>
888 "##,
889 r#"## ### A
890 ## ### n
891 ## ### y
892 ## ### t
893 ## ### h
894 ## ### i
895 ## ### n
896 ## ### g
897 ##
898 ## ──
899 "#,
900 5,
901 );
902 }
903
904 #[test]
905 fn test_trivial_decorator() {
906 test_html_decorator(
907 br#"<div>
908 <div>Here's a <a href="https://example.com/">link</a>.</div>
909 <div><ul>
910 <li>Bullet</li>
911 <li>Bullet</li>
912 <li>Bullet</li>
913 </ul></div>
914 </div>"#,
915 r"Here's a link.
916
917 * Bullet
918 * Bullet
919 * Bullet
920 ",
921 80,
922 TrivialDecorator::new(),
923 );
924 }
925
926 #[test]
927 fn test_issue_16() {
928 test_html(b"<ul><li><!----></li></ul>", "", 10);
929 }
930
931 #[test]
932 fn test_pre_br() {
933 test_html(
934 b"<pre>Foo<br>Bar</pre>",
935 r#"Foo
936 Bar
937 "#,
938 10,
939 );
940 }
941
942 #[test]
943 fn test_pre_emptyline() {
944 test_html(br#"<pre>X<span id="i"> </span></pre>"#, "X \n", 10);
945 }
946
947 #[test]
948 fn test_link_id_longline() {
949 test_html(
950 br#"<a href="foo" id="i">quitelongline</a>"#,
951 r#"[quitelong
952 line][1]
953
954 [1] foo
955 "#,
956 10,
957 );
958 }
959
960 #[test]
961 fn test_dl() {
962 test_html(
963 br#"<dl><dt>Foo</dt><dd>Definition of foo</dd></dl>"#,
964 r#"*Foo*
965 Definition of foo
966 "#,
967 40,
968 );
969 }
970
971 #[test]
972 fn test_s() {
973 test_html(
974 br#"Hi <s>you</s>thee!"#,
975 "Hi y\u{336}o\u{336}u\u{336}thee!\n",
976 40,
977 );
978 }
979
980 #[test]
981 fn test_multi_parse() {
982 let html: &[u8] = b"one two three four five six seven eight nine ten eleven twelve thirteen \
983 fourteen fifteen sixteen seventeen";
984 let tree = parse(html);
985 assert_eq!(
986 "one two three four five six seven eight nine ten eleven twelve thirteen fourteen\n\
987 fifteen sixteen seventeen\n",
988 tree.clone().render_plain(80).into_string()
989 );
990 assert_eq!(
991 "one two three four five six seven eight nine ten eleven twelve\n\
992 thirteen fourteen fifteen sixteen seventeen\n",
993 tree.clone().render_plain(70).into_string()
994 );
995 assert_eq!(
996 "one two three four five six seven eight nine ten\n\
997 eleven twelve thirteen fourteen fifteen sixteen\n\
998 seventeen\n",
999 tree.clone().render_plain(50).into_string()
1000 );
1001 }
1002
1003 #[test]
1004 fn test_read_rich() {
1005 let html: &[u8] = b"<strong>bold</strong>";
1006 let lines = parse(html).render_rich(80).into_lines();
1007 let tag = vec![RichAnnotation::Strong];
1008 let line = TaggedLine::from_string("*bold*".to_owned(), &tag);
1009 assert_eq!(vec![line], lines);
1010 }
1011
1012 #[test]
1013 fn test_read_custom() {
1014 let html: &[u8] = b"<strong>bold</strong>";
1015 let lines = parse(html).render(80, TrivialDecorator::new()).into_lines();
1016 let tag = vec![()];
1017 let line = TaggedLine::from_string("bold".to_owned(), &tag);
1018 assert_eq!(vec![line], lines);
1019 }
1020
1021 #[test]
1022 fn test_pre_rich() {
1023 use RichAnnotation::*;
1024 assert_eq!(
1025 crate::parse("<pre>test</pre>".as_bytes())
1026 .render_rich(100)
1027 .into_lines(),
1028 [TaggedLine::from_string(
1029 "test".into(),
1030 &vec![Preformat(false)]
1031 )]
1032 );
1033
1034 assert_eq!(
1035 crate::parse("<pre>testlong</pre>".as_bytes())
1036 .render_rich(4)
1037 .into_lines(),
1038 [
1039 TaggedLine::from_string("test".into(), &vec![Preformat(false)]),
1040 TaggedLine::from_string("long".into(), &vec![Preformat(true)])
1041 ]
1042 );
1043 }
1044