aboutsummaryrefslogtreecommitdiff
path: root/crates/test_utils
diff options
context:
space:
mode:
Diffstat (limited to 'crates/test_utils')
-rw-r--r--crates/test_utils/Cargo.toml1
-rw-r--r--crates/test_utils/src/lib.rs77
-rw-r--r--crates/test_utils/src/mark.rs4
3 files changed, 68 insertions, 14 deletions
diff --git a/crates/test_utils/Cargo.toml b/crates/test_utils/Cargo.toml
index 6821db1e8..e719f4f7c 100644
--- a/crates/test_utils/Cargo.toml
+++ b/crates/test_utils/Cargo.toml
@@ -3,6 +3,7 @@ edition = "2018"
3name = "test_utils" 3name = "test_utils"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6license = "MIT OR Apache-2.0"
6 7
7[lib] 8[lib]
8doctest = false 9doctest = false
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs
index e4aa894ac..ad586c882 100644
--- a/crates/test_utils/src/lib.rs
+++ b/crates/test_utils/src/lib.rs
@@ -179,31 +179,80 @@ pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> {
179 let mut res = Vec::new(); 179 let mut res = Vec::new();
180 let mut prev_line_start: Option<TextSize> = None; 180 let mut prev_line_start: Option<TextSize> = None;
181 let mut line_start: TextSize = 0.into(); 181 let mut line_start: TextSize = 0.into();
182 let mut prev_line_annotations: Vec<(TextSize, usize)> = Vec::new();
182 for line in lines_with_ends(text) { 183 for line in lines_with_ends(text) {
183 if let Some(idx) = line.find("//^") { 184 let mut this_line_annotations = Vec::new();
184 let offset = prev_line_start.unwrap() + TextSize::of(&line[..idx + "//".len()]); 185 if let Some(idx) = line.find("//") {
185 for (line_range, text) in extract_line_annotations(&line[idx + "//".len()..]) { 186 let annotation_offset = TextSize::of(&line[..idx + "//".len()]);
186 res.push((line_range + offset, text)) 187 for annotation in extract_line_annotations(&line[idx + "//".len()..]) {
188 match annotation {
189 LineAnnotation::Annotation { mut range, content } => {
190 range += annotation_offset;
191 this_line_annotations.push((range.end(), res.len()));
192 res.push((range + prev_line_start.unwrap(), content))
193 }
194 LineAnnotation::Continuation { mut offset, content } => {
195 offset += annotation_offset;
196 let &(_, idx) = prev_line_annotations
197 .iter()
198 .find(|&&(off, _idx)| off == offset)
199 .unwrap();
200 res[idx].1.push('\n');
201 res[idx].1.push_str(&content);
202 res[idx].1.push('\n');
203 }
204 }
187 } 205 }
188 } 206 }
207
189 prev_line_start = Some(line_start); 208 prev_line_start = Some(line_start);
190 line_start += TextSize::of(line); 209 line_start += TextSize::of(line);
210
211 prev_line_annotations = this_line_annotations;
191 } 212 }
192 res 213 res
193} 214}
194 215
195fn extract_line_annotations(mut line: &str) -> Vec<(TextRange, String)> { 216enum LineAnnotation {
217 Annotation { range: TextRange, content: String },
218 Continuation { offset: TextSize, content: String },
219}
220
221fn extract_line_annotations(mut line: &str) -> Vec<LineAnnotation> {
196 let mut res = Vec::new(); 222 let mut res = Vec::new();
197 let mut offset: TextSize = 0.into(); 223 let mut offset: TextSize = 0.into();
198 while !line.is_empty() { 224 let marker: fn(char) -> bool = if line.contains('^') { |c| c == '^' } else { |c| c == '|' };
199 let len = line.chars().take_while(|&it| it == '^').count(); 225 loop {
200 assert!(len > 0); 226 match line.find(marker) {
227 Some(idx) => {
228 offset += TextSize::try_from(idx).unwrap();
229 line = &line[idx..];
230 }
231 None => break,
232 };
233
234 let mut len = line.chars().take_while(|&it| it == '^').count();
235 let mut continuation = false;
236 if len == 0 {
237 assert!(line.starts_with('|'));
238 continuation = true;
239 len = 1;
240 }
201 let range = TextRange::at(offset, len.try_into().unwrap()); 241 let range = TextRange::at(offset, len.try_into().unwrap());
202 let next = line[len..].find('^').map_or(line.len(), |it| it + len); 242 let next = line[len..].find(marker).map_or(line.len(), |it| it + len);
203 res.push((range, line[len..][..next - len].trim().to_string())); 243 let content = line[len..][..next - len].trim().to_string();
244
245 let annotation = if continuation {
246 LineAnnotation::Continuation { offset: range.end(), content }
247 } else {
248 LineAnnotation::Annotation { range, content }
249 };
250 res.push(annotation);
251
204 line = &line[next..]; 252 line = &line[next..];
205 offset += TextSize::try_from(next).unwrap(); 253 offset += TextSize::try_from(next).unwrap();
206 } 254 }
255
207 res 256 res
208} 257}
209 258
@@ -215,14 +264,18 @@ fn main() {
215 let (x, y) = (9, 2); 264 let (x, y) = (9, 2);
216 //^ def ^ def 265 //^ def ^ def
217 zoo + 1 266 zoo + 1
218} //^^^ i32 267} //^^^ type:
268 // | i32
219 "#, 269 "#,
220 ); 270 );
221 let res = extract_annotations(&text) 271 let res = extract_annotations(&text)
222 .into_iter() 272 .into_iter()
223 .map(|(range, ann)| (&text[range], ann)) 273 .map(|(range, ann)| (&text[range], ann))
224 .collect::<Vec<_>>(); 274 .collect::<Vec<_>>();
225 assert_eq!(res, vec![("x", "def".into()), ("y", "def".into()), ("zoo", "i32".into()),]); 275 assert_eq!(
276 res,
277 vec![("x", "def".into()), ("y", "def".into()), ("zoo", "type:\ni32\n".into()),]
278 );
226} 279}
227 280
228// Comparison functionality borrowed from cargo: 281// Comparison functionality borrowed from cargo:
diff --git a/crates/test_utils/src/mark.rs b/crates/test_utils/src/mark.rs
index 7c309a894..97f5a93ad 100644
--- a/crates/test_utils/src/mark.rs
+++ b/crates/test_utils/src/mark.rs
@@ -62,7 +62,7 @@ pub struct MarkChecker {
62 62
63impl MarkChecker { 63impl MarkChecker {
64 pub fn new(mark: &'static AtomicUsize) -> MarkChecker { 64 pub fn new(mark: &'static AtomicUsize) -> MarkChecker {
65 let value_on_entry = mark.load(Ordering::SeqCst); 65 let value_on_entry = mark.load(Ordering::Relaxed);
66 MarkChecker { mark, value_on_entry } 66 MarkChecker { mark, value_on_entry }
67 } 67 }
68} 68}
@@ -72,7 +72,7 @@ impl Drop for MarkChecker {
72 if std::thread::panicking() { 72 if std::thread::panicking() {
73 return; 73 return;
74 } 74 }
75 let value_on_exit = self.mark.load(Ordering::SeqCst); 75 let value_on_exit = self.mark.load(Ordering::Relaxed);
76 assert!(value_on_exit > self.value_on_entry, "mark was not hit") 76 assert!(value_on_exit > self.value_on_entry, "mark was not hit")
77 } 77 }
78} 78}