1 use crate::source_map::{SourceMap, FilePathMapping};
2 use crate::with_default_globals;
5 use errors::emitter::EmitterWriter;
8 use std::io::prelude::*;
9 use rustc_data_structures::sync::Lrc;
11 use std::sync::{Arc, Mutex};
13 use syntax_pos::{BytePos, NO_EXPANSION, Span, MultiSpan};
15 /// Identify a position in the text by the Nth occurrence of a string.
27 struct Shared<T: Write> {
31 impl<T: Write> Write for Shared<T> {
32 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
33 self.data.lock().unwrap().write(buf)
36 fn flush(&mut self) -> io::Result<()> {
37 self.data.lock().unwrap().flush()
41 fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &str) {
42 with_default_globals(|| {
43 let output = Arc::new(Mutex::new(Vec::new()));
45 let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty()));
46 source_map.new_source_file(Path::new("test.rs").to_owned().into(), file_text.to_owned());
48 let primary_span = make_span(&file_text, &span_labels[0].start, &span_labels[0].end);
49 let mut msp = MultiSpan::from_span(primary_span);
50 for span_label in span_labels {
51 let span = make_span(&file_text, &span_label.start, &span_label.end);
52 msp.push_span_label(span, span_label.label.to_string());
53 println!("span: {:?} label: {:?}", span, span_label.label);
54 println!("text: {:?}", source_map.span_to_snippet(span));
57 let emitter = EmitterWriter::new(Box::new(Shared { data: output.clone() }),
58 Some(source_map.clone()),
62 let handler = Handler::with_emitter(true, None, Box::new(emitter));
63 handler.span_err(msp, "foo");
65 assert!(expected_output.chars().next() == Some('\n'),
66 "expected output should begin with newline");
67 let expected_output = &expected_output[1..];
69 let bytes = output.lock().unwrap();
70 let actual_output = str::from_utf8(&bytes).unwrap();
71 println!("expected output:\n------\n{}------", expected_output);
72 println!("actual output:\n------\n{}------", actual_output);
74 assert!(expected_output == actual_output)
78 fn make_span(file_text: &str, start: &Position, end: &Position) -> Span {
79 let start = make_pos(file_text, start);
80 let end = make_pos(file_text, end) + end.string.len(); // just after matching thing ends
81 assert!(start <= end);
82 Span::new(BytePos(start as u32), BytePos(end as u32), NO_EXPANSION)
85 fn make_pos(file_text: &str, pos: &Position) -> usize {
86 let mut remainder = file_text;
88 for _ in 0..pos.count {
89 if let Some(n) = remainder.find(&pos.string) {
91 remainder = &remainder[n + 1..];
93 panic!("failed to find {} instances of {:?} in {:?}",
186 label: "`X` is a good letter",
197 label: "`Y` is a good letter too",
210 | ||____^__- `Y` is a good letter too
212 | `X` is a good letter
235 label: "`X` is a good letter",
246 label: "`Y` is a good letter too",
258 | ||____-__^ `X` is a good letter
260 | `Y` is a good letter too
266 fn different_overlap() {
285 label: "`X` is a good letter",
296 label: "`Y` is a good letter too",
308 | ||____^ `X` is a good letter
310 | |_____- `Y` is a good letter too
316 fn triple_overlap() {
334 label: "`X` is a good letter",
345 label: "`Y` is a good letter too",
370 | |||____^__-__- `Z` label
372 | |____| `Y` is a good letter too
373 | `X` is a good letter
379 fn triple_exact_overlap() {
397 label: "`X` is a good letter",
408 label: "`Y` is a good letter too",
431 | | `X` is a good letter
432 | |____`Y` is a good letter too
458 label: "`X` is a good letter",
469 label: "`Y` is a good letter too",
492 | | `X` is a good letter
494 | |____-______- `Y` is a good letter too
504 fn non_overlaping() {
523 label: "`X` is a good letter",
534 label: "`Y` is a good letter too",
543 | |____^ `X` is a good letter
547 | |__________- `Y` is a good letter too
553 fn overlaping_start_and_end() {
572 label: "`X` is a good letter",
583 label: "`Y` is a good letter too",
595 | | `X` is a good letter
598 | |___________- `Y` is a good letter too
604 fn multiple_labels_primary_without_message() {
631 label: "`a` is a good letter",
650 | ----^^^^-^^-- `a` is a good letter
656 fn multiple_labels_secondary_without_message() {
672 label: "`a` is a good letter",
691 | ^^^^-------^^ `a` is a good letter
697 fn multiple_labels_primary_without_message_2() {
713 label: "`b` is a good letter",
745 | `b` is a good letter
751 fn multiple_labels_secondary_without_message_2() {
778 label: "`b` is a good letter",
788 | `b` is a good letter
794 fn multiple_labels_secondary_without_message_3() {
810 label: "`a` is a good letter",
831 | `a` is a good letter
837 fn multiple_labels_without_message() {
878 fn multiple_labels_without_message_2() {
930 fn multiple_labels_with_message() {
946 label: "`a` is a good letter",
957 label: "`b` is a good letter",
967 | | `b` is a good letter
968 | `a` is a good letter
974 fn single_label_with_message() {
990 label: "`a` is a good letter",
998 | ^^^^^^^^^^^^^ `a` is a good letter
1004 fn single_label_without_message() {
1063 label: "`X` is a good letter",
1074 label: "`Y` is a good letter too",
1086 | | `X` is a good letter
1093 | |___________- `Y` is a good letter too
1099 fn long_snippet_multiple_spans() {
1128 label: "`Y` is a good letter",
1139 label: "`Z` is a good letter too",
1157 | ||__________- `Z` is a good letter too
1161 | |_______^ `Y` is a good letter