]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/test_snippet.rs
Auto merge of #57760 - dlrobertson:varargs1, r=alexreg
[rust.git] / src / libsyntax / test_snippet.rs
1 use crate::source_map::{SourceMap, FilePathMapping};
2 use crate::with_globals;
3
4 use errors::Handler;
5 use errors::emitter::EmitterWriter;
6
7 use std::io;
8 use std::io::prelude::*;
9 use rustc_data_structures::sync::Lrc;
10 use std::str;
11 use std::sync::{Arc, Mutex};
12 use std::path::Path;
13 use syntax_pos::{BytePos, NO_EXPANSION, Span, MultiSpan};
14
15 /// Identify a position in the text by the Nth occurrence of a string.
16 struct Position {
17     string: &'static str,
18     count: usize,
19 }
20
21 struct SpanLabel {
22     start: Position,
23     end: Position,
24     label: &'static str,
25 }
26
27 struct Shared<T: Write> {
28     data: Arc<Mutex<T>>,
29 }
30
31 impl<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
41 fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &str) {
42     with_globals(|| {
43         let output = Arc::new(Mutex::new(Vec::new()));
44
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());
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);
54             println!("text: {:?}", source_map.span_to_snippet(span));
55         }
56
57         let emitter = EmitterWriter::new(Box::new(Shared { data: output.clone() }),
58                                         Some(source_map.clone()),
59                                         false,
60                                         false);
61         let handler = Handler::with_emitter(true, false, Box::new(emitter));
62         handler.span_err(msp, "foo");
63
64         assert!(expected_output.chars().next() == Some('\n'),
65                 "expected output should begin with newline");
66         let expected_output = &expected_output[1..];
67
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);
72
73         assert!(expected_output == actual_output)
74     })
75 }
76
77 fn 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);
81     Span::new(BytePos(start as u32), BytePos(end as u32), NO_EXPANSION)
82 }
83
84 fn 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]
102 fn ends_on_col0() {
103     test_harness(r#"
104 fn 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#"
121 error: foo
122  --> test.rs:2:10
123   |
124 2 |   fn foo() {
125   |  __________^
126 3 | | }
127   | |_^ test
128
129 "#);
130 }
131
132 #[test]
133 fn ends_on_col2() {
134     test_harness(r#"
135 fn 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#"
154 error: foo
155  --> test.rs:2:10
156   |
157 2 |   fn foo() {
158   |  __________^
159 3 | |
160 4 | |
161 5 | |   }
162   | |___^ test
163
164 "#);
165 }
166 #[test]
167 fn non_nested() {
168     test_harness(r#"
169 fn 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#"
200 error: foo
201  --> test.rs:3:3
202   |
203 3 |      X0 Y0
204   |  ____^__-
205   | | ___|
206   | ||
207 4 | ||   X1 Y1
208 5 | ||   X2 Y2
209   | ||____^__- `Y` is a good letter too
210   |  |____|
211   |       `X` is a good letter
212
213 "#);
214 }
215
216 #[test]
217 fn nested() {
218     test_harness(r#"
219 fn 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     ],
248 r#"
249 error: foo
250  --> test.rs:3:3
251   |
252 3 |      X0 Y0
253   |  ____^__-
254   | | ___|
255   | ||
256 4 | ||   Y1 X1
257   | ||____-__^ `X` is a good letter
258   | |_____|
259   |       `Y` is a good letter too
260
261 "#);
262 }
263
264 #[test]
265 fn different_overlap() {
266     test_harness(r#"
267 fn 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#"
299 error: foo
300  --> test.rs:3:6
301   |
302 3 |      X0 Y0 Z0
303   |   ______^
304 4 |  |   X1 Y1 Z1
305   |  |_________-
306 5 | ||   X2 Y2 Z2
307   | ||____^ `X` is a good letter
308 6 | |    X3 Y3 Z3
309   | |_____- `Y` is a good letter too
310
311 "#);
312 }
313
314 #[test]
315 fn triple_overlap() {
316     test_harness(r#"
317 fn 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#"
359 error: foo
360  --> test.rs:3:3
361   |
362 3 |       X0 Y0 Z0
363   |  _____^__-__-
364   | | ____|__|
365   | || ___|
366   | |||
367 4 | |||   X1 Y1 Z1
368 5 | |||   X2 Y2 Z2
369   | |||____^__-__- `Z` label
370   |  ||____|__|
371   |   |____|  `Y` is a good letter too
372   |        `X` is a good letter
373
374 "#);
375 }
376
377 #[test]
378 fn minimum_depth() {
379     test_harness(r#"
380 fn 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#"
423 error: foo
424  --> test.rs:3:6
425   |
426 3 |      X0 Y0 Z0
427   |   ______^
428 4 |  |   X1 Y1 Z1
429   |  |____^_-
430   | ||____|
431   | |     `X` is a good letter
432 5 | |    X2 Y2 Z2
433   | |____-______- `Y` is a good letter too
434   |  ____|
435   | |
436 6 | |    X3 Y3 Z3
437   | |________- `Z`
438
439 "#);
440 }
441
442 #[test]
443 fn non_overlaping() {
444     test_harness(r#"
445 fn 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 {
455                 string: "X0",
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#"
477 error: foo
478  --> test.rs:3:3
479   |
480 3 | /   X0 Y0 Z0
481 4 | |   X1 Y1 Z1
482   | |____^ `X` is a good letter
483 5 |     X2 Y2 Z2
484   |  ______-
485 6 | |   X3 Y3 Z3
486   | |__________- `Y` is a good letter too
487
488 "#);
489 }
490
491 #[test]
492 fn overlaping_start_and_end() {
493     test_harness(r#"
494 fn 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#"
526 error: foo
527  --> test.rs:3:6
528   |
529 3 |      X0 Y0 Z0
530   |   ______^
531 4 |  |   X1 Y1 Z1
532   |  |____^____-
533   | ||____|
534   | |     `X` is a good letter
535 5 | |    X2 Y2 Z2
536 6 | |    X3 Y3 Z3
537   | |___________- `Y` is a good letter too
538
539 "#);
540 }
541
542 #[test]
543 fn multiple_labels_primary_without_message() {
544     test_harness(r#"
545 fn 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#"
585 error: foo
586  --> test.rs:3:7
587   |
588 3 |   a { b { c } d }
589   |   ----^^^^-^^-- `a` is a good letter
590
591 "#);
592 }
593
594 #[test]
595 fn multiple_labels_secondary_without_message() {
596     test_harness(r#"
597 fn 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#"
626 error: foo
627  --> test.rs:3:3
628   |
629 3 |   a { b { c } d }
630   |   ^^^^-------^^ `a` is a good letter
631
632 "#);
633 }
634
635 #[test]
636 fn multiple_labels_primary_without_message_2() {
637     test_harness(r#"
638 fn 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#"
678 error: foo
679  --> test.rs:3:7
680   |
681 3 |   a { b { c } d }
682   |   ----^^^^-^^--
683   |       |
684   |       `b` is a good letter
685
686 "#);
687 }
688
689 #[test]
690 fn multiple_labels_secondary_without_message_2() {
691     test_harness(r#"
692 fn 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#"
721 error: foo
722  --> test.rs:3:3
723   |
724 3 |   a { b { c } d }
725   |   ^^^^-------^^
726   |       |
727   |       `b` is a good letter
728
729 "#);
730 }
731
732 #[test]
733 fn multiple_labels_secondary_without_message_3() {
734     test_harness(r#"
735 fn 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#"
764 error: foo
765  --> test.rs:3:3
766   |
767 3 |   a  bc  d
768   |   ^^^^----
769   |   |
770   |   `a` is a good letter
771
772 "#);
773 }
774
775 #[test]
776 fn multiple_labels_without_message() {
777     test_harness(r#"
778 fn 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#"
807 error: foo
808  --> test.rs:3:3
809   |
810 3 |   a { b { c } d }
811   |   ^^^^-------^^
812
813 "#);
814 }
815
816 #[test]
817 fn multiple_labels_without_message_2() {
818     test_harness(r#"
819 fn 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#"
859 error: foo
860  --> test.rs:3:7
861   |
862 3 |   a { b { c } d }
863   |   ----^^^^-^^--
864
865 "#);
866 }
867
868 #[test]
869 fn multiple_labels_with_message() {
870     test_harness(r#"
871 fn 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#"
900 error: foo
901  --> test.rs:3:3
902   |
903 3 |   a { b { c } d }
904   |   ^^^^-------^^
905   |   |   |
906   |   |   `b` is a good letter
907   |   `a` is a good letter
908
909 "#);
910 }
911
912 #[test]
913 fn single_label_with_message() {
914     test_harness(r#"
915 fn 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#"
933 error: foo
934  --> test.rs:3:3
935   |
936 3 |   a { b { c } d }
937   |   ^^^^^^^^^^^^^ `a` is a good letter
938
939 "#);
940 }
941
942 #[test]
943 fn single_label_without_message() {
944     test_harness(r#"
945 fn 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#"
963 error: foo
964  --> test.rs:3:3
965   |
966 3 |   a { b { c } d }
967   |   ^^^^^^^^^^^^^
968
969 "#);
970 }
971
972 #[test]
973 fn long_snippet() {
974     test_harness(r#"
975 fn foo() {
976   X0 Y0 Z0
977   X1 Y1 Z1
978 1
979 2
980 3
981 4
982 5
983 6
984 7
985 8
986 9
987 10
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#"
1017 error: foo
1018   --> test.rs:3:6
1019    |
1020 3  |      X0 Y0 Z0
1021    |   ______^
1022 4  |  |   X1 Y1 Z1
1023    |  |____^____-
1024    | ||____|
1025    | |     `X` is a good letter
1026 5  | |  1
1027 6  | |  2
1028 7  | |  3
1029 ...  |
1030 15 | |    X2 Y2 Z2
1031 16 | |    X3 Y3 Z3
1032    | |___________- `Y` is a good letter too
1033
1034 "#);
1035 }
1036
1037 #[test]
1038 fn long_snippet_multiple_spans() {
1039     test_harness(r#"
1040 fn foo() {
1041   X0 Y0 Z0
1042 1
1043 2
1044 3
1045   X1 Y1 Z1
1046 4
1047 5
1048 6
1049   X2 Y2 Z2
1050 7
1051 8
1052 9
1053 10
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#"
1082 error: foo
1083   --> test.rs:3:6
1084    |
1085 3  |      X0 Y0 Z0
1086    |   ______^
1087 4  |  | 1
1088 5  |  | 2
1089 6  |  | 3
1090 7  |  |   X1 Y1 Z1
1091    |  |_________-
1092 8  | || 4
1093 9  | || 5
1094 10 | || 6
1095 11 | ||   X2 Y2 Z2
1096    | ||__________- `Z` is a good letter too
1097 ...   |
1098 15 |  | 10
1099 16 |  |   X3 Y3 Z3
1100    |  |_______^ `Y` is a good letter
1101
1102 "#);
1103 }
1104