1 use source_map::{SourceMap, FilePathMapping};
3 use errors::emitter::EmitterWriter;
5 use std::io::prelude::*;
6 use rustc_data_structures::sync::Lrc;
8 use std::sync::{Arc, Mutex};
10 use syntax_pos::{BytePos, NO_EXPANSION, Span, MultiSpan};
13 /// Identify a position in the text by the Nth occurrence of a string.
25 struct Shared<T: Write> {
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)
34 fn flush(&mut self) -> io::Result<()> {
35 self.data.lock().unwrap().flush()
39 fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &str) {
41 let output = Arc::new(Mutex::new(Vec::new()));
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());
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));
55 let emitter = EmitterWriter::new(Box::new(Shared { data: output.clone() }),
56 Some(source_map.clone()),
59 let handler = Handler::with_emitter(true, false, Box::new(emitter));
60 handler.span_err(msp, "foo");
62 assert!(expected_output.chars().next() == Some('\n'),
63 "expected output should begin with newline");
64 let expected_output = &expected_output[1..];
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);
71 assert!(expected_output == actual_output)
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)
82 fn make_pos(file_text: &str, pos: &Position) -> usize {
83 let mut remainder = file_text;
85 for _ in 0..pos.count {
86 if let Some(n) = remainder.find(&pos.string) {
88 remainder = &remainder[n + 1..];
90 panic!("failed to find {} instances of {:?} in {:?}",
183 label: "`X` is a good letter",
194 label: "`Y` is a good letter too",
207 | ||____^__- `Y` is a good letter too
209 | `X` is a good letter
232 label: "`X` is a good letter",
243 label: "`Y` is a good letter too",
255 | ||____-__^ `X` is a good letter
257 | `Y` is a good letter too
263 fn different_overlap() {
282 label: "`X` is a good letter",
293 label: "`Y` is a good letter too",
305 | ||____^ `X` is a good letter
307 | |_____- `Y` is a good letter too
313 fn triple_overlap() {
331 label: "`X` is a good letter",
342 label: "`Y` is a good letter too",
367 | |||____^__-__- `Z` label
369 | |____| `Y` is a good letter too
370 | `X` is a good letter
395 label: "`X` is a good letter",
406 label: "`Y` is a good letter too",
429 | | `X` is a good letter
431 | |____-______- `Y` is a good letter too
441 fn non_overlaping() {
460 label: "`X` is a good letter",
471 label: "`Y` is a good letter too",
480 | |____^ `X` is a good letter
484 | |__________- `Y` is a good letter too
490 fn overlaping_start_and_end() {
509 label: "`X` is a good letter",
520 label: "`Y` is a good letter too",
532 | | `X` is a good letter
535 | |___________- `Y` is a good letter too
541 fn multiple_labels_primary_without_message() {
568 label: "`a` is a good letter",
587 | ----^^^^-^^-- `a` is a good letter
593 fn multiple_labels_secondary_without_message() {
609 label: "`a` is a good letter",
628 | ^^^^-------^^ `a` is a good letter
634 fn multiple_labels_primary_without_message_2() {
650 label: "`b` is a good letter",
682 | `b` is a good letter
688 fn multiple_labels_secondary_without_message_2() {
715 label: "`b` is a good letter",
725 | `b` is a good letter
731 fn multiple_labels_secondary_without_message_3() {
747 label: "`a` is a good letter",
768 | `a` is a good letter
774 fn multiple_labels_without_message() {
815 fn multiple_labels_without_message_2() {
867 fn multiple_labels_with_message() {
883 label: "`a` is a good letter",
894 label: "`b` is a good letter",
904 | | `b` is a good letter
905 | `a` is a good letter
911 fn single_label_with_message() {
927 label: "`a` is a good letter",
935 | ^^^^^^^^^^^^^ `a` is a good letter
941 fn single_label_without_message() {
1000 label: "`X` is a good letter",
1011 label: "`Y` is a good letter too",
1023 | | `X` is a good letter
1030 | |___________- `Y` is a good letter too
1036 fn long_snippet_multiple_spans() {
1065 label: "`Y` is a good letter",
1076 label: "`Z` is a good letter too",
1094 | ||__________- `Z` is a good letter too
1098 | |_______^ `Y` is a good letter