]> git.proxmox.com Git - rustc.git/blame - src/libsyntax/test_snippet.rs
New upstream version 1.19.0+dfsg1
[rustc.git] / src / libsyntax / test_snippet.rs
CommitLineData
476ff2be
SL
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
7cac9316 11use codemap::{CodeMap, FilePathMapping};
476ff2be
SL
12use errors::Handler;
13use errors::emitter::EmitterWriter;
14use std::io;
15use std::io::prelude::*;
16use std::rc::Rc;
17use std::str;
18use std::sync::{Arc, Mutex};
19use syntax_pos::{BytePos, NO_EXPANSION, Span, MultiSpan};
20
21/// Identify a position in the text by the Nth occurrence of a string.
22struct Position {
23 string: &'static str,
24 count: usize,
25}
26
27struct SpanLabel {
28 start: Position,
29 end: Position,
30 label: &'static str,
31}
32
33struct Shared<T: Write> {
34 data: Arc<Mutex<T>>,
35}
36
37impl<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
47fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &str) {
48 let output = Arc::new(Mutex::new(Vec::new()));
49
7cac9316
XL
50 let code_map = Rc::new(CodeMap::new(FilePathMapping::empty()));
51 code_map.new_filemap_and_lines("test.rs", &file_text);
476ff2be
SL
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
79fn 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),
cc61c64b 86 ctxt: NO_EXPANSION,
476ff2be
SL
87 }
88}
89
90fn 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]
108fn ends_on_col0() {
109 test_harness(r#"
110fn 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#"
127error: foo
128 --> test.rs:2:10
129 |
1302 | fn foo() {
cc61c64b 131 | __________^
476ff2be 1323 | | }
cc61c64b 133 | |_^ test
476ff2be
SL
134
135"#);
136}
137
138#[test]
139fn ends_on_col2() {
140 test_harness(r#"
141fn 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#"
160error: foo
161 --> test.rs:2:10
162 |
1632 | fn foo() {
cc61c64b 164 | __________^
476ff2be
SL
1653 | |
1664 | |
1675 | | }
cc61c64b 168 | |___^ test
476ff2be
SL
169
170"#);
171}
172#[test]
173fn non_nested() {
174 test_harness(r#"
175fn 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#"
206error: foo
207 --> test.rs:3:3
208 |
2093 | X0 Y0
cc61c64b 210 | ____^__-
476ff2be 211 | | ___|
cc61c64b 212 | ||
476ff2be
SL
2134 | || X1 Y1
2145 | || X2 Y2
cc61c64b 215 | ||____^__- `Y` is a good letter too
476ff2be 216 | |____|
cc61c64b 217 | `X` is a good letter
476ff2be
SL
218
219"#);
220}
221
222#[test]
223fn nested() {
224 test_harness(r#"
225fn 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 ],
254r#"
255error: foo
256 --> test.rs:3:3
257 |
2583 | X0 Y0
cc61c64b 259 | ____^__-
476ff2be 260 | | ___|
cc61c64b 261 | ||
476ff2be 2624 | || Y1 X1
cc61c64b 263 | ||____-__^ `X` is a good letter
476ff2be 264 | |_____|
cc61c64b 265 | `Y` is a good letter too
476ff2be
SL
266
267"#);
268}
269
270#[test]
271fn different_overlap() {
272 test_harness(r#"
273fn 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#"
305error: foo
306 --> test.rs:3:6
307 |
3083 | X0 Y0 Z0
cc61c64b 309 | ______^
476ff2be 3104 | | X1 Y1 Z1
cc61c64b 311 | |_________-
476ff2be 3125 | || X2 Y2 Z2
cc61c64b 313 | ||____^ `X` is a good letter
476ff2be 3146 | | X3 Y3 Z3
cc61c64b 315 | |_____- `Y` is a good letter too
476ff2be
SL
316
317"#);
318}
319
320#[test]
321fn triple_overlap() {
322 test_harness(r#"
323fn 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#"
365error: foo
366 --> test.rs:3:3
367 |
3683 | X0 Y0 Z0
cc61c64b 369 | _____^__-__-
476ff2be 370 | | ____|__|
cc61c64b
XL
371 | || ___|
372 | |||
476ff2be
SL
3734 | ||| X1 Y1 Z1
3745 | ||| X2 Y2 Z2
cc61c64b 375 | |||____^__-__- `Z` label
476ff2be 376 | ||____|__|
cc61c64b
XL
377 | |____| `Y` is a good letter too
378 | `X` is a good letter
476ff2be
SL
379
380"#);
381}
382
383#[test]
384fn minimum_depth() {
385 test_harness(r#"
386fn 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#"
429error: foo
430 --> test.rs:3:6
431 |
4323 | X0 Y0 Z0
cc61c64b 433 | ______^
476ff2be 4344 | | X1 Y1 Z1
cc61c64b 435 | |____^_-
476ff2be 436 | ||____|
cc61c64b 437 | | `X` is a good letter
476ff2be 4385 | | X2 Y2 Z2
cc61c64b 439 | |____-______- `Y` is a good letter too
476ff2be 440 | ____|
cc61c64b 441 | |
476ff2be 4426 | | X3 Y3 Z3
cc61c64b 443 | |________- `Z`
476ff2be
SL
444
445"#);
446}
447
448#[test]
449fn non_overlaping() {
450 test_harness(r#"
451fn 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 {
cc61c64b 461 string: "X0",
476ff2be
SL
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#"
483error: foo
cc61c64b 484 --> test.rs:3:3
476ff2be 485 |
cc61c64b 4863 | / X0 Y0 Z0
476ff2be 4874 | | X1 Y1 Z1
cc61c64b 488 | |____^ `X` is a good letter
476ff2be 4895 | X2 Y2 Z2
cc61c64b 490 | ______-
476ff2be 4916 | | X3 Y3 Z3
cc61c64b 492 | |__________- `Y` is a good letter too
476ff2be
SL
493
494"#);
495}
32a655c1 496
476ff2be
SL
497#[test]
498fn overlaping_start_and_end() {
499 test_harness(r#"
500fn 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#"
532error: foo
533 --> test.rs:3:6
534 |
5353 | X0 Y0 Z0
cc61c64b 536 | ______^
476ff2be 5374 | | X1 Y1 Z1
cc61c64b 538 | |____^____-
476ff2be 539 | ||____|
cc61c64b 540 | | `X` is a good letter
476ff2be
SL
5415 | | X2 Y2 Z2
5426 | | X3 Y3 Z3
cc61c64b 543 | |___________- `Y` is a good letter too
476ff2be
SL
544
545"#);
546}
32a655c1
SL
547
548#[test]
549fn multiple_labels_primary_without_message() {
550 test_harness(r#"
551fn 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#"
591error: foo
592 --> test.rs:3:7
593 |
5943 | a { b { c } d }
595 | ----^^^^-^^-- `a` is a good letter
596
597"#);
598}
599
600#[test]
601fn multiple_labels_secondary_without_message() {
602 test_harness(r#"
603fn 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#"
632error: foo
633 --> test.rs:3:3
634 |
6353 | a { b { c } d }
636 | ^^^^-------^^ `a` is a good letter
637
638"#);
639}
640
641#[test]
642fn multiple_labels_primary_without_message_2() {
643 test_harness(r#"
644fn 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#"
684error: foo
685 --> test.rs:3:7
686 |
6873 | a { b { c } d }
688 | ----^^^^-^^--
689 | |
690 | `b` is a good letter
691
692"#);
693}
694
695#[test]
696fn multiple_labels_secondary_without_message_2() {
697 test_harness(r#"
698fn 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#"
727error: foo
728 --> test.rs:3:3
729 |
7303 | a { b { c } d }
731 | ^^^^-------^^
732 | |
733 | `b` is a good letter
734
735"#);
736}
737
738#[test]
739fn multiple_labels_without_message() {
740 test_harness(r#"
741fn 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#"
770error: foo
771 --> test.rs:3:3
772 |
7733 | a { b { c } d }
774 | ^^^^-------^^
775
776"#);
777}
778
779#[test]
780fn multiple_labels_without_message_2() {
781 test_harness(r#"
782fn 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#"
822error: foo
823 --> test.rs:3:7
824 |
8253 | a { b { c } d }
826 | ----^^^^-^^--
827
828"#);
829}
830
831#[test]
832fn multiple_labels_with_message() {
833 test_harness(r#"
834fn 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#"
863error: foo
864 --> test.rs:3:3
865 |
8663 | a { b { c } d }
867 | ^^^^-------^^
868 | | |
869 | | `b` is a good letter
870 | `a` is a good letter
871
872"#);
873}
874
875#[test]
876fn single_label_with_message() {
877 test_harness(r#"
878fn 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#"
896error: foo
897 --> test.rs:3:3
898 |
8993 | a { b { c } d }
900 | ^^^^^^^^^^^^^ `a` is a good letter
901
902"#);
903}
904
905#[test]
906fn single_label_without_message() {
907 test_harness(r#"
908fn 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#"
926error: foo
927 --> test.rs:3:3
928 |
9293 | a { b { c } d }
930 | ^^^^^^^^^^^^^
931
932"#);
933}
cc61c64b
XL
934
935#[test]
936fn long_snippet() {
937 test_harness(r#"
938fn foo() {
939 X0 Y0 Z0
940 X1 Y1 Z1
9411
9422
9433
9444
9455
9466
9477
9488
9499
95010
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#"
980error: foo
981 --> test.rs:3:6
982 |
9833 | X0 Y0 Z0
984 | ______^
9854 | | X1 Y1 Z1
986 | |____^____-
987 | ||____|
988 | | `X` is a good letter
9895 | | 1
9906 | | 2
9917 | | 3
992... |
99315 | | X2 Y2 Z2
99416 | | X3 Y3 Z3
995 | |___________- `Y` is a good letter too
996
997"#);
998}
999
1000#[test]
1001fn long_snippet_multiple_spans() {
1002 test_harness(r#"
1003fn foo() {
1004 X0 Y0 Z0
10051
10062
10073
1008 X1 Y1 Z1
10094
10105
10116
1012 X2 Y2 Z2
10137
10148
10159
101610
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#"
1045error: foo
1046 --> test.rs:3:6
1047 |
10483 | X0 Y0 Z0
1049 | ______^
10504 | | 1
10515 | | 2
10526 | | 3
10537 | | X1 Y1 Z1
1054 | |_________-
10558 | || 4
10569 | || 5
105710 | || 6
105811 | || X2 Y2 Z2
1059 | ||__________- `Z` is a good letter too
1060... |
106115 | | 10
106216 | | X3 Y3 Z3
1063 | |_______^ `Y` is a good letter
1064
1065"#);
1066}
1067