diff options
Diffstat (limited to 'crates/test_utils')
-rw-r--r-- | crates/test_utils/src/lib.rs | 50 |
1 files changed, 44 insertions, 6 deletions
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs index d55bae62a..d9c22c180 100644 --- a/crates/test_utils/src/lib.rs +++ b/crates/test_utils/src/lib.rs | |||
@@ -11,6 +11,7 @@ mod fixture; | |||
11 | mod assert_linear; | 11 | mod assert_linear; |
12 | 12 | ||
13 | use std::{ | 13 | use std::{ |
14 | collections::BTreeMap, | ||
14 | convert::{TryFrom, TryInto}, | 15 | convert::{TryFrom, TryInto}, |
15 | env, fs, | 16 | env, fs, |
16 | path::{Path, PathBuf}, | 17 | path::{Path, PathBuf}, |
@@ -205,14 +206,25 @@ pub fn add_cursor(text: &str, offset: TextSize) -> String { | |||
205 | /// | 206 | /// |
206 | /// // ^^^ first line | 207 | /// // ^^^ first line |
207 | /// // | second line | 208 | /// // | second line |
209 | /// | ||
210 | /// Annotations point to the last line that actually was long enough for the | ||
211 | /// range, not counting annotations themselves. So overlapping annotations are | ||
212 | /// possible: | ||
213 | /// ```no_run | ||
214 | /// // stuff other stuff | ||
215 | /// // ^^ 'st' | ||
216 | /// // ^^^^^ 'stuff' | ||
217 | /// // ^^^^^^^^^^^ 'other stuff' | ||
218 | /// ``` | ||
208 | pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> { | 219 | pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> { |
209 | let mut res = Vec::new(); | 220 | let mut res = Vec::new(); |
210 | let mut prev_line_start: Option<TextSize> = Some(0.into()); | 221 | // map from line length to beginning of last line that had that length |
222 | let mut line_start_map = BTreeMap::new(); | ||
211 | let mut line_start: TextSize = 0.into(); | 223 | let mut line_start: TextSize = 0.into(); |
212 | let mut prev_line_annotations: Vec<(TextSize, usize)> = Vec::new(); | 224 | let mut prev_line_annotations: Vec<(TextSize, usize)> = Vec::new(); |
213 | for line in text.split_inclusive('\n') { | 225 | for line in text.split_inclusive('\n') { |
214 | let mut this_line_annotations = Vec::new(); | 226 | let mut this_line_annotations = Vec::new(); |
215 | if let Some(idx) = line.find("//") { | 227 | let line_length = if let Some(idx) = line.find("//") { |
216 | let annotation_offset = TextSize::of(&line[..idx + "//".len()]); | 228 | let annotation_offset = TextSize::of(&line[..idx + "//".len()]); |
217 | for annotation in extract_line_annotations(&line[idx + "//".len()..]) { | 229 | for annotation in extract_line_annotations(&line[idx + "//".len()..]) { |
218 | match annotation { | 230 | match annotation { |
@@ -222,7 +234,9 @@ pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> { | |||
222 | let range = if file { | 234 | let range = if file { |
223 | TextRange::up_to(TextSize::of(text)) | 235 | TextRange::up_to(TextSize::of(text)) |
224 | } else { | 236 | } else { |
225 | range + prev_line_start.unwrap() | 237 | let line_start = line_start_map.range(range.end()..).next().unwrap(); |
238 | |||
239 | range + line_start.1 | ||
226 | }; | 240 | }; |
227 | res.push((range, content)) | 241 | res.push((range, content)) |
228 | } | 242 | } |
@@ -238,9 +252,14 @@ pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> { | |||
238 | } | 252 | } |
239 | } | 253 | } |
240 | } | 254 | } |
241 | } | 255 | idx.try_into().unwrap() |
256 | } else { | ||
257 | TextSize::of(line) | ||
258 | }; | ||
259 | |||
260 | line_start_map = line_start_map.split_off(&line_length); | ||
261 | line_start_map.insert(line_length, line_start); | ||
242 | 262 | ||
243 | prev_line_start = Some(line_start); | ||
244 | line_start += TextSize::of(line); | 263 | line_start += TextSize::of(line); |
245 | 264 | ||
246 | prev_line_annotations = this_line_annotations; | 265 | prev_line_annotations = this_line_annotations; |
@@ -296,7 +315,7 @@ fn extract_line_annotations(mut line: &str) -> Vec<LineAnnotation> { | |||
296 | } | 315 | } |
297 | 316 | ||
298 | #[test] | 317 | #[test] |
299 | fn test_extract_annotations() { | 318 | fn test_extract_annotations_1() { |
300 | let text = stdx::trim_indent( | 319 | let text = stdx::trim_indent( |
301 | r#" | 320 | r#" |
302 | fn main() { | 321 | fn main() { |
@@ -321,6 +340,25 @@ fn main() { | |||
321 | assert_eq!(res[3].0.len(), 115); | 340 | assert_eq!(res[3].0.len(), 115); |
322 | } | 341 | } |
323 | 342 | ||
343 | #[test] | ||
344 | fn test_extract_annotations_2() { | ||
345 | let text = stdx::trim_indent( | ||
346 | r#" | ||
347 | fn main() { | ||
348 | (x, y); | ||
349 | //^ a | ||
350 | // ^ b | ||
351 | //^^^^^^^^ c | ||
352 | }"#, | ||
353 | ); | ||
354 | let res = extract_annotations(&text) | ||
355 | .into_iter() | ||
356 | .map(|(range, ann)| (&text[range], ann)) | ||
357 | .collect::<Vec<_>>(); | ||
358 | |||
359 | assert_eq!(res, [("x", "a".into()), ("y", "b".into()), ("(x, y)", "c".into())]); | ||
360 | } | ||
361 | |||
324 | /// Returns `false` if slow tests should not run, otherwise returns `true` and | 362 | /// Returns `false` if slow tests should not run, otherwise returns `true` and |
325 | /// also creates a file at `./target/.slow_tests_cookie` which serves as a flag | 363 | /// also creates a file at `./target/.slow_tests_cookie` which serves as a flag |
326 | /// that slow tests did run. | 364 | /// that slow tests did run. |