]> git.lizzy.rs Git - rust.git/blob - src/librustc_span/source_map/tests.rs
clean up error codes explanation
[rust.git] / src / librustc_span / source_map / tests.rs
1 use super::*;
2
3 use rustc_data_structures::sync::Lrc;
4
5 fn init_source_map() -> SourceMap {
6     let sm = SourceMap::new(FilePathMapping::empty());
7     sm.new_source_file(PathBuf::from("blork.rs").into(), "first line.\nsecond line".to_string());
8     sm.new_source_file(PathBuf::from("empty.rs").into(), String::new());
9     sm.new_source_file(PathBuf::from("blork2.rs").into(), "first line.\nsecond line".to_string());
10     sm
11 }
12
13 /// Tests `lookup_byte_offset`.
14 #[test]
15 fn t3() {
16     let sm = init_source_map();
17
18     let srcfbp1 = sm.lookup_byte_offset(BytePos(23));
19     assert_eq!(srcfbp1.sf.name, PathBuf::from("blork.rs").into());
20     assert_eq!(srcfbp1.pos, BytePos(23));
21
22     let srcfbp1 = sm.lookup_byte_offset(BytePos(24));
23     assert_eq!(srcfbp1.sf.name, PathBuf::from("empty.rs").into());
24     assert_eq!(srcfbp1.pos, BytePos(0));
25
26     let srcfbp2 = sm.lookup_byte_offset(BytePos(25));
27     assert_eq!(srcfbp2.sf.name, PathBuf::from("blork2.rs").into());
28     assert_eq!(srcfbp2.pos, BytePos(0));
29 }
30
31 /// Tests `bytepos_to_file_charpos`.
32 #[test]
33 fn t4() {
34     let sm = init_source_map();
35
36     let cp1 = sm.bytepos_to_file_charpos(BytePos(22));
37     assert_eq!(cp1, CharPos(22));
38
39     let cp2 = sm.bytepos_to_file_charpos(BytePos(25));
40     assert_eq!(cp2, CharPos(0));
41 }
42
43 /// Tests zero-length `SourceFile`s.
44 #[test]
45 fn t5() {
46     let sm = init_source_map();
47
48     let loc1 = sm.lookup_char_pos(BytePos(22));
49     assert_eq!(loc1.file.name, PathBuf::from("blork.rs").into());
50     assert_eq!(loc1.line, 2);
51     assert_eq!(loc1.col, CharPos(10));
52
53     let loc2 = sm.lookup_char_pos(BytePos(25));
54     assert_eq!(loc2.file.name, PathBuf::from("blork2.rs").into());
55     assert_eq!(loc2.line, 1);
56     assert_eq!(loc2.col, CharPos(0));
57 }
58
59 fn init_source_map_mbc() -> SourceMap {
60     let sm = SourceMap::new(FilePathMapping::empty());
61     // "€" is a three-byte UTF8 char.
62     sm.new_source_file(
63         PathBuf::from("blork.rs").into(),
64         "fir€st €€€€ line.\nsecond line".to_string(),
65     );
66     sm.new_source_file(
67         PathBuf::from("blork2.rs").into(),
68         "first line€€.\n€ second line".to_string(),
69     );
70     sm
71 }
72
73 /// Tests `bytepos_to_file_charpos` in the presence of multi-byte chars.
74 #[test]
75 fn t6() {
76     let sm = init_source_map_mbc();
77
78     let cp1 = sm.bytepos_to_file_charpos(BytePos(3));
79     assert_eq!(cp1, CharPos(3));
80
81     let cp2 = sm.bytepos_to_file_charpos(BytePos(6));
82     assert_eq!(cp2, CharPos(4));
83
84     let cp3 = sm.bytepos_to_file_charpos(BytePos(56));
85     assert_eq!(cp3, CharPos(12));
86
87     let cp4 = sm.bytepos_to_file_charpos(BytePos(61));
88     assert_eq!(cp4, CharPos(15));
89 }
90
91 /// Test `span_to_lines` for a span ending at the end of a `SourceFile`.
92 #[test]
93 fn t7() {
94     let sm = init_source_map();
95     let span = Span::with_root_ctxt(BytePos(12), BytePos(23));
96     let file_lines = sm.span_to_lines(span).unwrap();
97
98     assert_eq!(file_lines.file.name, PathBuf::from("blork.rs").into());
99     assert_eq!(file_lines.lines.len(), 1);
100     assert_eq!(file_lines.lines[0].line_index, 1);
101 }
102
103 /// Given a string like " ~~~~~~~~~~~~ ", produces a span
104 /// converting that range. The idea is that the string has the same
105 /// length as the input, and we uncover the byte positions. Note
106 /// that this can span lines and so on.
107 fn span_from_selection(input: &str, selection: &str) -> Span {
108     assert_eq!(input.len(), selection.len());
109     let left_index = selection.find('~').unwrap() as u32;
110     let right_index = selection.rfind('~').map(|x| x as u32).unwrap_or(left_index);
111     Span::with_root_ctxt(BytePos(left_index), BytePos(right_index + 1))
112 }
113
114 /// Tests `span_to_snippet` and `span_to_lines` for a span converting 3
115 /// lines in the middle of a file.
116 #[test]
117 fn span_to_snippet_and_lines_spanning_multiple_lines() {
118     let sm = SourceMap::new(FilePathMapping::empty());
119     let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n";
120     let selection = "     \n    ~~\n~~~\n~~~~~     \n   \n";
121     sm.new_source_file(Path::new("blork.rs").to_owned().into(), inputtext.to_string());
122     let span = span_from_selection(inputtext, selection);
123
124     // Check that we are extracting the text we thought we were extracting.
125     assert_eq!(&sm.span_to_snippet(span).unwrap(), "BB\nCCC\nDDDDD");
126
127     // Check that span_to_lines gives us the complete result with the lines/cols we expected.
128     let lines = sm.span_to_lines(span).unwrap();
129     let expected = vec![
130         LineInfo { line_index: 1, start_col: CharPos(4), end_col: CharPos(6) },
131         LineInfo { line_index: 2, start_col: CharPos(0), end_col: CharPos(3) },
132         LineInfo { line_index: 3, start_col: CharPos(0), end_col: CharPos(5) },
133     ];
134     assert_eq!(lines.lines, expected);
135 }
136
137 /// Test span_to_snippet for a span ending at the end of a `SourceFile`.
138 #[test]
139 fn t8() {
140     let sm = init_source_map();
141     let span = Span::with_root_ctxt(BytePos(12), BytePos(23));
142     let snippet = sm.span_to_snippet(span);
143
144     assert_eq!(snippet, Ok("second line".to_string()));
145 }
146
147 /// Test `span_to_str` for a span ending at the end of a `SourceFile`.
148 #[test]
149 fn t9() {
150     let sm = init_source_map();
151     let span = Span::with_root_ctxt(BytePos(12), BytePos(23));
152     let sstr = sm.span_to_string(span);
153
154     assert_eq!(sstr, "blork.rs:2:1: 2:12");
155 }
156
157 /// Tests failing to merge two spans on different lines.
158 #[test]
159 fn span_merging_fail() {
160     let sm = SourceMap::new(FilePathMapping::empty());
161     let inputtext = "bbbb BB\ncc CCC\n";
162     let selection1 = "     ~~\n      \n";
163     let selection2 = "       \n   ~~~\n";
164     sm.new_source_file(Path::new("blork.rs").to_owned().into(), inputtext.to_owned());
165     let span1 = span_from_selection(inputtext, selection1);
166     let span2 = span_from_selection(inputtext, selection2);
167
168     assert!(sm.merge_spans(span1, span2).is_none());
169 }
170
171 /// Returns the span corresponding to the `n`th occurrence of `substring` in `source_text`.
172 trait SourceMapExtension {
173     fn span_substr(
174         &self,
175         file: &Lrc<SourceFile>,
176         source_text: &str,
177         substring: &str,
178         n: usize,
179     ) -> Span;
180 }
181
182 impl SourceMapExtension for SourceMap {
183     fn span_substr(
184         &self,
185         file: &Lrc<SourceFile>,
186         source_text: &str,
187         substring: &str,
188         n: usize,
189     ) -> Span {
190         println!(
191             "span_substr(file={:?}/{:?}, substring={:?}, n={})",
192             file.name, file.start_pos, substring, n
193         );
194         let mut i = 0;
195         let mut hi = 0;
196         loop {
197             let offset = source_text[hi..].find(substring).unwrap_or_else(|| {
198                 panic!(
199                     "source_text `{}` does not have {} occurrences of `{}`, only {}",
200                     source_text, n, substring, i
201                 );
202             });
203             let lo = hi + offset;
204             hi = lo + substring.len();
205             if i == n {
206                 let span = Span::with_root_ctxt(
207                     BytePos(lo as u32 + file.start_pos.0),
208                     BytePos(hi as u32 + file.start_pos.0),
209                 );
210                 assert_eq!(&self.span_to_snippet(span).unwrap()[..], substring);
211                 return span;
212             }
213             i += 1;
214         }
215     }
216 }