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