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