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