]> git.proxmox.com Git - rustc.git/blame - src/libsyntax/test_snippet.rs
New upstream version 1.34.2+dfsg1
[rustc.git] / src / libsyntax / test_snippet.rs
CommitLineData
9fa01778
XL
1use crate::source_map::{SourceMap, FilePathMapping};
2use crate::with_globals;
3
476ff2be
SL
4use errors::Handler;
5use errors::emitter::EmitterWriter;
9fa01778 6
476ff2be
SL
7use std::io;
8use std::io::prelude::*;
0531ce1d 9use rustc_data_structures::sync::Lrc;
476ff2be
SL
10use std::str;
11use std::sync::{Arc, Mutex};
ff7c6d11 12use std::path::Path;
476ff2be
SL
13use syntax_pos::{BytePos, NO_EXPANSION, Span, MultiSpan};
14
15/// Identify a position in the text by the Nth occurrence of a string.
16struct Position {
17 string: &'static str,
18 count: usize,
19}
20
21struct SpanLabel {
22 start: Position,
23 end: Position,
24 label: &'static str,
25}
26
27struct Shared<T: Write> {
28 data: Arc<Mutex<T>>,
29}
30
31impl<T: Write> Write for Shared<T> {
32 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
33 self.data.lock().unwrap().write(buf)
34 }
35
36 fn flush(&mut self) -> io::Result<()> {
37 self.data.lock().unwrap().flush()
38 }
39}
40
41fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &str) {
0531ce1d
XL
42 with_globals(|| {
43 let output = Arc::new(Mutex::new(Vec::new()));
44
a1dfa0c6
XL
45 let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty()));
46 source_map.new_source_file(Path::new("test.rs").to_owned().into(), file_text.to_owned());
0531ce1d
XL
47
48 let primary_span = make_span(&file_text, &span_labels[0].start, &span_labels[0].end);
49 let mut msp = MultiSpan::from_span(primary_span);
50 for span_label in span_labels {
51 let span = make_span(&file_text, &span_label.start, &span_label.end);
52 msp.push_span_label(span, span_label.label.to_string());
53 println!("span: {:?} label: {:?}", span, span_label.label);
a1dfa0c6 54 println!("text: {:?}", source_map.span_to_snippet(span));
0531ce1d 55 }
476ff2be 56
0531ce1d 57 let emitter = EmitterWriter::new(Box::new(Shared { data: output.clone() }),
a1dfa0c6 58 Some(source_map.clone()),
0531ce1d
XL
59 false,
60 false);
61 let handler = Handler::with_emitter(true, false, Box::new(emitter));
62 handler.span_err(msp, "foo");
476ff2be 63
0531ce1d
XL
64 assert!(expected_output.chars().next() == Some('\n'),
65 "expected output should begin with newline");
66 let expected_output = &expected_output[1..];
476ff2be 67
0531ce1d
XL
68 let bytes = output.lock().unwrap();
69 let actual_output = str::from_utf8(&bytes).unwrap();
70 println!("expected output:\n------\n{}------", expected_output);
71 println!("actual output:\n------\n{}------", actual_output);
476ff2be 72
0531ce1d
XL
73 assert!(expected_output == actual_output)
74 })
476ff2be
SL
75}
76
77fn make_span(file_text: &str, start: &Position, end: &Position) -> Span {
78 let start = make_pos(file_text, start);
79 let end = make_pos(file_text, end) + end.string.len(); // just after matching thing ends
80 assert!(start <= end);
ea8adc8c 81 Span::new(BytePos(start as u32), BytePos(end as u32), NO_EXPANSION)
476ff2be
SL
82}
83
84fn make_pos(file_text: &str, pos: &Position) -> usize {
85 let mut remainder = file_text;
86 let mut offset = 0;
87 for _ in 0..pos.count {
88 if let Some(n) = remainder.find(&pos.string) {
89 offset += n;
90 remainder = &remainder[n + 1..];
91 } else {
92 panic!("failed to find {} instances of {:?} in {:?}",
93 pos.count,
94 pos.string,
95 file_text);
96 }
97 }
98 offset
99}
100
101#[test]
102fn ends_on_col0() {
103 test_harness(r#"
104fn foo() {
105}
106"#,
107 vec![
108 SpanLabel {
109 start: Position {
110 string: "{",
111 count: 1,
112 },
113 end: Position {
114 string: "}",
115 count: 1,
116 },
117 label: "test",
118 },
119 ],
120 r#"
121error: foo
122 --> test.rs:2:10
123 |
1242 | fn foo() {
cc61c64b 125 | __________^
476ff2be 1263 | | }
cc61c64b 127 | |_^ test
476ff2be
SL
128
129"#);
130}
131
132#[test]
133fn ends_on_col2() {
134 test_harness(r#"
135fn foo() {
136
137
138 }
139"#,
140 vec![
141 SpanLabel {
142 start: Position {
143 string: "{",
144 count: 1,
145 },
146 end: Position {
147 string: "}",
148 count: 1,
149 },
150 label: "test",
151 },
152 ],
153 r#"
154error: foo
155 --> test.rs:2:10
156 |
1572 | fn foo() {
cc61c64b 158 | __________^
476ff2be
SL
1593 | |
1604 | |
1615 | | }
cc61c64b 162 | |___^ test
476ff2be
SL
163
164"#);
165}
166#[test]
167fn non_nested() {
168 test_harness(r#"
169fn foo() {
170 X0 Y0
171 X1 Y1
172 X2 Y2
173}
174"#,
175 vec![
176 SpanLabel {
177 start: Position {
178 string: "X0",
179 count: 1,
180 },
181 end: Position {
182 string: "X2",
183 count: 1,
184 },
185 label: "`X` is a good letter",
186 },
187 SpanLabel {
188 start: Position {
189 string: "Y0",
190 count: 1,
191 },
192 end: Position {
193 string: "Y2",
194 count: 1,
195 },
196 label: "`Y` is a good letter too",
197 },
198 ],
199 r#"
200error: foo
201 --> test.rs:3:3
202 |
2033 | X0 Y0
cc61c64b 204 | ____^__-
476ff2be 205 | | ___|
cc61c64b 206 | ||
476ff2be
SL
2074 | || X1 Y1
2085 | || X2 Y2
cc61c64b 209 | ||____^__- `Y` is a good letter too
476ff2be 210 | |____|
cc61c64b 211 | `X` is a good letter
476ff2be
SL
212
213"#);
214}
215
216#[test]
217fn nested() {
218 test_harness(r#"
219fn foo() {
220 X0 Y0
221 Y1 X1
222}
223"#,
224 vec![
225 SpanLabel {
226 start: Position {
227 string: "X0",
228 count: 1,
229 },
230 end: Position {
231 string: "X1",
232 count: 1,
233 },
234 label: "`X` is a good letter",
235 },
236 SpanLabel {
237 start: Position {
238 string: "Y0",
239 count: 1,
240 },
241 end: Position {
242 string: "Y1",
243 count: 1,
244 },
245 label: "`Y` is a good letter too",
246 },
247 ],
248r#"
249error: foo
250 --> test.rs:3:3
251 |
2523 | X0 Y0
cc61c64b 253 | ____^__-
476ff2be 254 | | ___|
cc61c64b 255 | ||
476ff2be 2564 | || Y1 X1
cc61c64b 257 | ||____-__^ `X` is a good letter
476ff2be 258 | |_____|
cc61c64b 259 | `Y` is a good letter too
476ff2be
SL
260
261"#);
262}
263
264#[test]
265fn different_overlap() {
266 test_harness(r#"
267fn foo() {
268 X0 Y0 Z0
269 X1 Y1 Z1
270 X2 Y2 Z2
271 X3 Y3 Z3
272}
273"#,
274 vec![
275 SpanLabel {
276 start: Position {
277 string: "Y0",
278 count: 1,
279 },
280 end: Position {
281 string: "X2",
282 count: 1,
283 },
284 label: "`X` is a good letter",
285 },
286 SpanLabel {
287 start: Position {
288 string: "Z1",
289 count: 1,
290 },
291 end: Position {
292 string: "X3",
293 count: 1,
294 },
295 label: "`Y` is a good letter too",
296 },
297 ],
298 r#"
299error: foo
300 --> test.rs:3:6
301 |
3023 | X0 Y0 Z0
cc61c64b 303 | ______^
476ff2be 3044 | | X1 Y1 Z1
cc61c64b 305 | |_________-
476ff2be 3065 | || X2 Y2 Z2
cc61c64b 307 | ||____^ `X` is a good letter
476ff2be 3086 | | X3 Y3 Z3
cc61c64b 309 | |_____- `Y` is a good letter too
476ff2be
SL
310
311"#);
312}
313
314#[test]
315fn triple_overlap() {
316 test_harness(r#"
317fn foo() {
318 X0 Y0 Z0
319 X1 Y1 Z1
320 X2 Y2 Z2
321}
322"#,
323 vec![
324 SpanLabel {
325 start: Position {
326 string: "X0",
327 count: 1,
328 },
329 end: Position {
330 string: "X2",
331 count: 1,
332 },
333 label: "`X` is a good letter",
334 },
335 SpanLabel {
336 start: Position {
337 string: "Y0",
338 count: 1,
339 },
340 end: Position {
341 string: "Y2",
342 count: 1,
343 },
344 label: "`Y` is a good letter too",
345 },
346 SpanLabel {
347 start: Position {
348 string: "Z0",
349 count: 1,
350 },
351 end: Position {
352 string: "Z2",
353 count: 1,
354 },
355 label: "`Z` label",
356 },
357 ],
358 r#"
359error: foo
360 --> test.rs:3:3
361 |
3623 | X0 Y0 Z0
cc61c64b 363 | _____^__-__-
476ff2be 364 | | ____|__|
cc61c64b
XL
365 | || ___|
366 | |||
476ff2be
SL
3674 | ||| X1 Y1 Z1
3685 | ||| X2 Y2 Z2
cc61c64b 369 | |||____^__-__- `Z` label
476ff2be 370 | ||____|__|
cc61c64b
XL
371 | |____| `Y` is a good letter too
372 | `X` is a good letter
476ff2be
SL
373
374"#);
375}
376
377#[test]
378fn minimum_depth() {
379 test_harness(r#"
380fn foo() {
381 X0 Y0 Z0
382 X1 Y1 Z1
383 X2 Y2 Z2
384 X3 Y3 Z3
385}
386"#,
387 vec![
388 SpanLabel {
389 start: Position {
390 string: "Y0",
391 count: 1,
392 },
393 end: Position {
394 string: "X1",
395 count: 1,
396 },
397 label: "`X` is a good letter",
398 },
399 SpanLabel {
400 start: Position {
401 string: "Y1",
402 count: 1,
403 },
404 end: Position {
405 string: "Z2",
406 count: 1,
407 },
408 label: "`Y` is a good letter too",
409 },
410 SpanLabel {
411 start: Position {
412 string: "X2",
413 count: 1,
414 },
415 end: Position {
416 string: "Y3",
417 count: 1,
418 },
419 label: "`Z`",
420 },
421 ],
422 r#"
423error: foo
424 --> test.rs:3:6
425 |
4263 | X0 Y0 Z0
cc61c64b 427 | ______^
476ff2be 4284 | | X1 Y1 Z1
cc61c64b 429 | |____^_-
476ff2be 430 | ||____|
cc61c64b 431 | | `X` is a good letter
476ff2be 4325 | | X2 Y2 Z2
cc61c64b 433 | |____-______- `Y` is a good letter too
476ff2be 434 | ____|
cc61c64b 435 | |
476ff2be 4366 | | X3 Y3 Z3
cc61c64b 437 | |________- `Z`
476ff2be
SL
438
439"#);
440}
441
442#[test]
443fn non_overlaping() {
444 test_harness(r#"
445fn foo() {
446 X0 Y0 Z0
447 X1 Y1 Z1
448 X2 Y2 Z2
449 X3 Y3 Z3
450}
451"#,
452 vec![
453 SpanLabel {
454 start: Position {
cc61c64b 455 string: "X0",
476ff2be
SL
456 count: 1,
457 },
458 end: Position {
459 string: "X1",
460 count: 1,
461 },
462 label: "`X` is a good letter",
463 },
464 SpanLabel {
465 start: Position {
466 string: "Y2",
467 count: 1,
468 },
469 end: Position {
470 string: "Z3",
471 count: 1,
472 },
473 label: "`Y` is a good letter too",
474 },
475 ],
476 r#"
477error: foo
cc61c64b 478 --> test.rs:3:3
476ff2be 479 |
cc61c64b 4803 | / X0 Y0 Z0
476ff2be 4814 | | X1 Y1 Z1
cc61c64b 482 | |____^ `X` is a good letter
476ff2be 4835 | X2 Y2 Z2
cc61c64b 484 | ______-
476ff2be 4856 | | X3 Y3 Z3
cc61c64b 486 | |__________- `Y` is a good letter too
476ff2be
SL
487
488"#);
489}
32a655c1 490
476ff2be
SL
491#[test]
492fn overlaping_start_and_end() {
493 test_harness(r#"
494fn foo() {
495 X0 Y0 Z0
496 X1 Y1 Z1
497 X2 Y2 Z2
498 X3 Y3 Z3
499}
500"#,
501 vec![
502 SpanLabel {
503 start: Position {
504 string: "Y0",
505 count: 1,
506 },
507 end: Position {
508 string: "X1",
509 count: 1,
510 },
511 label: "`X` is a good letter",
512 },
513 SpanLabel {
514 start: Position {
515 string: "Z1",
516 count: 1,
517 },
518 end: Position {
519 string: "Z3",
520 count: 1,
521 },
522 label: "`Y` is a good letter too",
523 },
524 ],
525 r#"
526error: foo
527 --> test.rs:3:6
528 |
5293 | X0 Y0 Z0
cc61c64b 530 | ______^
476ff2be 5314 | | X1 Y1 Z1
cc61c64b 532 | |____^____-
476ff2be 533 | ||____|
cc61c64b 534 | | `X` is a good letter
476ff2be
SL
5355 | | X2 Y2 Z2
5366 | | X3 Y3 Z3
cc61c64b 537 | |___________- `Y` is a good letter too
476ff2be
SL
538
539"#);
540}
32a655c1
SL
541
542#[test]
543fn multiple_labels_primary_without_message() {
544 test_harness(r#"
545fn foo() {
546 a { b { c } d }
547}
548"#,
549 vec![
550 SpanLabel {
551 start: Position {
552 string: "b",
553 count: 1,
554 },
555 end: Position {
556 string: "}",
557 count: 1,
558 },
559 label: "",
560 },
561 SpanLabel {
562 start: Position {
563 string: "a",
564 count: 1,
565 },
566 end: Position {
567 string: "d",
568 count: 1,
569 },
570 label: "`a` is a good letter",
571 },
572 SpanLabel {
573 start: Position {
574 string: "c",
575 count: 1,
576 },
577 end: Position {
578 string: "c",
579 count: 1,
580 },
581 label: "",
582 },
583 ],
584 r#"
585error: foo
586 --> test.rs:3:7
587 |
5883 | a { b { c } d }
589 | ----^^^^-^^-- `a` is a good letter
590
591"#);
592}
593
594#[test]
595fn multiple_labels_secondary_without_message() {
596 test_harness(r#"
597fn foo() {
598 a { b { c } d }
599}
600"#,
601 vec![
602 SpanLabel {
603 start: Position {
604 string: "a",
605 count: 1,
606 },
607 end: Position {
608 string: "d",
609 count: 1,
610 },
611 label: "`a` is a good letter",
612 },
613 SpanLabel {
614 start: Position {
615 string: "b",
616 count: 1,
617 },
618 end: Position {
619 string: "}",
620 count: 1,
621 },
622 label: "",
623 },
624 ],
625 r#"
626error: foo
627 --> test.rs:3:3
628 |
6293 | a { b { c } d }
630 | ^^^^-------^^ `a` is a good letter
631
632"#);
633}
634
635#[test]
636fn multiple_labels_primary_without_message_2() {
637 test_harness(r#"
638fn foo() {
639 a { b { c } d }
640}
641"#,
642 vec![
643 SpanLabel {
644 start: Position {
645 string: "b",
646 count: 1,
647 },
648 end: Position {
649 string: "}",
650 count: 1,
651 },
652 label: "`b` is a good letter",
653 },
654 SpanLabel {
655 start: Position {
656 string: "a",
657 count: 1,
658 },
659 end: Position {
660 string: "d",
661 count: 1,
662 },
663 label: "",
664 },
665 SpanLabel {
666 start: Position {
667 string: "c",
668 count: 1,
669 },
670 end: Position {
671 string: "c",
672 count: 1,
673 },
674 label: "",
675 },
676 ],
677 r#"
678error: foo
679 --> test.rs:3:7
680 |
6813 | a { b { c } d }
682 | ----^^^^-^^--
683 | |
684 | `b` is a good letter
685
686"#);
687}
688
689#[test]
690fn multiple_labels_secondary_without_message_2() {
691 test_harness(r#"
692fn foo() {
693 a { b { c } d }
694}
695"#,
696 vec![
697 SpanLabel {
698 start: Position {
699 string: "a",
700 count: 1,
701 },
702 end: Position {
703 string: "d",
704 count: 1,
705 },
706 label: "",
707 },
708 SpanLabel {
709 start: Position {
710 string: "b",
711 count: 1,
712 },
713 end: Position {
714 string: "}",
715 count: 1,
716 },
717 label: "`b` is a good letter",
718 },
719 ],
720 r#"
721error: foo
722 --> test.rs:3:3
723 |
7243 | a { b { c } d }
725 | ^^^^-------^^
726 | |
727 | `b` is a good letter
728
729"#);
730}
731
041b39d2
XL
732#[test]
733fn multiple_labels_secondary_without_message_3() {
734 test_harness(r#"
735fn foo() {
736 a bc d
737}
738"#,
739 vec![
740 SpanLabel {
741 start: Position {
742 string: "a",
743 count: 1,
744 },
745 end: Position {
746 string: "b",
747 count: 1,
748 },
749 label: "`a` is a good letter",
750 },
751 SpanLabel {
752 start: Position {
753 string: "c",
754 count: 1,
755 },
756 end: Position {
757 string: "d",
758 count: 1,
759 },
760 label: "",
761 },
762 ],
763 r#"
764error: foo
765 --> test.rs:3:3
766 |
7673 | a bc d
768 | ^^^^----
769 | |
770 | `a` is a good letter
771
772"#);
773}
774
32a655c1
SL
775#[test]
776fn multiple_labels_without_message() {
777 test_harness(r#"
778fn foo() {
779 a { b { c } d }
780}
781"#,
782 vec![
783 SpanLabel {
784 start: Position {
785 string: "a",
786 count: 1,
787 },
788 end: Position {
789 string: "d",
790 count: 1,
791 },
792 label: "",
793 },
794 SpanLabel {
795 start: Position {
796 string: "b",
797 count: 1,
798 },
799 end: Position {
800 string: "}",
801 count: 1,
802 },
803 label: "",
804 },
805 ],
806 r#"
807error: foo
808 --> test.rs:3:3
809 |
8103 | a { b { c } d }
811 | ^^^^-------^^
812
813"#);
814}
815
816#[test]
817fn multiple_labels_without_message_2() {
818 test_harness(r#"
819fn foo() {
820 a { b { c } d }
821}
822"#,
823 vec![
824 SpanLabel {
825 start: Position {
826 string: "b",
827 count: 1,
828 },
829 end: Position {
830 string: "}",
831 count: 1,
832 },
833 label: "",
834 },
835 SpanLabel {
836 start: Position {
837 string: "a",
838 count: 1,
839 },
840 end: Position {
841 string: "d",
842 count: 1,
843 },
844 label: "",
845 },
846 SpanLabel {
847 start: Position {
848 string: "c",
849 count: 1,
850 },
851 end: Position {
852 string: "c",
853 count: 1,
854 },
855 label: "",
856 },
857 ],
858 r#"
859error: foo
860 --> test.rs:3:7
861 |
8623 | a { b { c } d }
863 | ----^^^^-^^--
864
865"#);
866}
867
868#[test]
869fn multiple_labels_with_message() {
870 test_harness(r#"
871fn foo() {
872 a { b { c } d }
873}
874"#,
875 vec![
876 SpanLabel {
877 start: Position {
878 string: "a",
879 count: 1,
880 },
881 end: Position {
882 string: "d",
883 count: 1,
884 },
885 label: "`a` is a good letter",
886 },
887 SpanLabel {
888 start: Position {
889 string: "b",
890 count: 1,
891 },
892 end: Position {
893 string: "}",
894 count: 1,
895 },
896 label: "`b` is a good letter",
897 },
898 ],
899 r#"
900error: foo
901 --> test.rs:3:3
902 |
9033 | a { b { c } d }
904 | ^^^^-------^^
905 | | |
906 | | `b` is a good letter
907 | `a` is a good letter
908
909"#);
910}
911
912#[test]
913fn single_label_with_message() {
914 test_harness(r#"
915fn foo() {
916 a { b { c } d }
917}
918"#,
919 vec![
920 SpanLabel {
921 start: Position {
922 string: "a",
923 count: 1,
924 },
925 end: Position {
926 string: "d",
927 count: 1,
928 },
929 label: "`a` is a good letter",
930 },
931 ],
932 r#"
933error: foo
934 --> test.rs:3:3
935 |
9363 | a { b { c } d }
937 | ^^^^^^^^^^^^^ `a` is a good letter
938
939"#);
940}
941
942#[test]
943fn single_label_without_message() {
944 test_harness(r#"
945fn foo() {
946 a { b { c } d }
947}
948"#,
949 vec![
950 SpanLabel {
951 start: Position {
952 string: "a",
953 count: 1,
954 },
955 end: Position {
956 string: "d",
957 count: 1,
958 },
959 label: "",
960 },
961 ],
962 r#"
963error: foo
964 --> test.rs:3:3
965 |
9663 | a { b { c } d }
967 | ^^^^^^^^^^^^^
968
969"#);
970}
cc61c64b
XL
971
972#[test]
973fn long_snippet() {
974 test_harness(r#"
975fn foo() {
976 X0 Y0 Z0
977 X1 Y1 Z1
9781
9792
9803
9814
9825
9836
9847
9858
9869
98710
988 X2 Y2 Z2
989 X3 Y3 Z3
990}
991"#,
992 vec![
993 SpanLabel {
994 start: Position {
995 string: "Y0",
996 count: 1,
997 },
998 end: Position {
999 string: "X1",
1000 count: 1,
1001 },
1002 label: "`X` is a good letter",
1003 },
1004 SpanLabel {
1005 start: Position {
1006 string: "Z1",
1007 count: 1,
1008 },
1009 end: Position {
1010 string: "Z3",
1011 count: 1,
1012 },
1013 label: "`Y` is a good letter too",
1014 },
1015 ],
1016 r#"
1017error: foo
1018 --> test.rs:3:6
1019 |
10203 | X0 Y0 Z0
1021 | ______^
10224 | | X1 Y1 Z1
1023 | |____^____-
1024 | ||____|
1025 | | `X` is a good letter
10265 | | 1
10276 | | 2
10287 | | 3
1029... |
103015 | | X2 Y2 Z2
103116 | | X3 Y3 Z3
1032 | |___________- `Y` is a good letter too
1033
1034"#);
1035}
1036
1037#[test]
1038fn long_snippet_multiple_spans() {
1039 test_harness(r#"
1040fn foo() {
1041 X0 Y0 Z0
10421
10432
10443
1045 X1 Y1 Z1
10464
10475
10486
1049 X2 Y2 Z2
10507
10518
10529
105310
1054 X3 Y3 Z3
1055}
1056"#,
1057 vec![
1058 SpanLabel {
1059 start: Position {
1060 string: "Y0",
1061 count: 1,
1062 },
1063 end: Position {
1064 string: "Y3",
1065 count: 1,
1066 },
1067 label: "`Y` is a good letter",
1068 },
1069 SpanLabel {
1070 start: Position {
1071 string: "Z1",
1072 count: 1,
1073 },
1074 end: Position {
1075 string: "Z2",
1076 count: 1,
1077 },
1078 label: "`Z` is a good letter too",
1079 },
1080 ],
1081 r#"
1082error: foo
1083 --> test.rs:3:6
1084 |
10853 | X0 Y0 Z0
1086 | ______^
10874 | | 1
10885 | | 2
10896 | | 3
10907 | | X1 Y1 Z1
1091 | |_________-
10928 | || 4
10939 | || 5
109410 | || 6
109511 | || X2 Y2 Z2
1096 | ||__________- `Z` is a good letter too
1097... |
109815 | | 10
109916 | | X3 Y3 Z3
1100 | |_______^ `Y` is a good letter
1101
1102"#);
1103}
1104