1use super::types::{BidiMapper, SortedSourceMap, SourceMapDiff};
6
7#[cfg(test)]
8mod tests {
9 use super::*;
10 use crate::sourcemap::*;
11 use crate::tokens::Span;
12 fn mk_span(start: usize, end: usize, line: usize, col: usize) -> Span {
13 Span::new(start, end, line, col)
14 }
15 #[test]
16 fn test_line_offsets_single_line() {
17 let sm = SourceMap::new("hello world");
18 assert_eq!(sm.line_count(), 1);
19 assert_eq!(sm.line_content(1), "hello world");
20 }
21 #[test]
22 fn test_line_offsets_multi_line() {
23 let sm = SourceMap::new("line1\nline2\nline3");
24 assert_eq!(sm.line_count(), 3);
25 assert_eq!(sm.line_content(1), "line1");
26 assert_eq!(sm.line_content(2), "line2");
27 assert_eq!(sm.line_content(3), "line3");
28 }
29 #[test]
30 fn test_line_content_out_of_bounds() {
31 let sm = SourceMap::new("hello");
32 assert_eq!(sm.line_content(0), "");
33 assert_eq!(sm.line_content(99), "");
34 }
35 #[test]
36 fn test_offset_to_position_first_line() {
37 let sm = SourceMap::new("hello\nworld");
38 assert_eq!(sm.offset_to_position(0), (1, 1));
39 assert_eq!(sm.offset_to_position(4), (1, 5));
40 }
41 #[test]
42 fn test_offset_to_position_second_line() {
43 let sm = SourceMap::new("hello\nworld");
44 assert_eq!(sm.offset_to_position(6), (2, 1));
45 assert_eq!(sm.offset_to_position(10), (2, 5));
46 }
47 #[test]
48 fn test_position_to_offset_roundtrip() {
49 let sm = SourceMap::new("abc\ndef\nghi");
50 for offset in 0..11 {
51 let (line, col) = sm.offset_to_position(offset);
52 let back = sm.position_to_offset(line, col);
53 assert_eq!(back, offset, "roundtrip failed for offset {}", offset);
54 }
55 }
56 #[test]
57 fn test_position_to_offset_clamped() {
58 let sm = SourceMap::new("abc");
59 let off = sm.position_to_offset(1, 100);
60 assert_eq!(off, 3);
61 }
62 #[test]
63 fn test_builder_basic() {
64 let mut builder = SourceMapBuilder::new("def foo := 42");
65 builder.add_definition(mk_span(4, 7, 1, 5), "foo");
66 builder.add_literal(mk_span(11, 13, 1, 12));
67 let sm = builder.build();
68 assert_eq!(sm.entries().len(), 2);
69 }
70 #[test]
71 fn test_builder_add_reference() {
72 let mut builder = SourceMapBuilder::new("foo + bar");
73 builder.add_reference(mk_span(0, 3, 1, 1), "foo");
74 builder.add_reference(mk_span(6, 9, 1, 7), "bar");
75 let sm = builder.build();
76 let refs = sm.references_to("foo");
77 assert_eq!(refs.len(), 1);
78 assert_eq!(refs[0].span.start, 0);
79 }
80 #[test]
81 fn test_builder_entry_count() {
82 let mut builder = SourceMapBuilder::new("test");
83 assert_eq!(builder.entry_count(), 0);
84 builder.add_keyword(mk_span(0, 4, 1, 1));
85 assert_eq!(builder.entry_count(), 1);
86 }
87 #[test]
88 fn test_builder_sorted_output() {
89 let mut builder = SourceMapBuilder::new("a b c");
90 builder.add_entry(
91 mk_span(4, 5, 1, 5),
92 EntryKind::Reference,
93 Some("c".to_string()),
94 );
95 builder.add_entry(
96 mk_span(0, 1, 1, 1),
97 EntryKind::Reference,
98 Some("a".to_string()),
99 );
100 builder.add_entry(
101 mk_span(2, 3, 1, 3),
102 EntryKind::Reference,
103 Some("b".to_string()),
104 );
105 let sm = builder.build();
106 let entries = sm.entries();
107 assert!(entries[0].span.start <= entries[1].span.start);
108 assert!(entries[1].span.start <= entries[2].span.start);
109 }
110 #[test]
111 fn test_entry_at() {
112 let mut builder = SourceMapBuilder::new("def foo := 42");
113 builder.add_keyword(mk_span(0, 3, 1, 1));
114 builder.add_definition(mk_span(4, 7, 1, 5), "foo");
115 builder.add_literal(mk_span(11, 13, 1, 12));
116 let sm = builder.build();
117 let kw = sm.entry_at(1, 2);
118 assert!(kw.is_some());
119 assert_eq!(
120 kw.expect("test operation should succeed").kind,
121 EntryKind::Keyword
122 );
123 let def = sm.entry_at(1, 5);
124 assert!(def.is_some());
125 assert_eq!(
126 def.expect("type conversion should succeed").name.as_deref(),
127 Some("foo")
128 );
129 }
130 #[test]
131 fn test_entry_at_empty() {
132 let sm = SourceMap::new("hello");
133 assert!(sm.entry_at(1, 1).is_none());
134 }
135 #[test]
136 fn test_definitions_query() {
137 let mut builder = SourceMapBuilder::new("def a def b");
138 builder.add_definition(mk_span(4, 5, 1, 5), "a");
139 builder.add_definition(mk_span(10, 11, 1, 11), "b");
140 builder.add_reference(mk_span(0, 1, 1, 1), "a");
141 let sm = builder.build();
142 let defs = sm.definitions();
143 assert_eq!(defs.len(), 2);
144 }
145 #[test]
146 fn test_references_to() {
147 let mut builder = SourceMapBuilder::new("foo foo bar foo");
148 builder.add_reference(mk_span(0, 3, 1, 1), "foo");
149 builder.add_reference(mk_span(4, 7, 1, 5), "foo");
150 builder.add_reference(mk_span(8, 11, 1, 9), "bar");
151 builder.add_reference(mk_span(12, 15, 1, 13), "foo");
152 let sm = builder.build();
153 assert_eq!(sm.references_to("foo").len(), 3);
154 assert_eq!(sm.references_to("bar").len(), 1);
155 assert_eq!(sm.references_to("baz").len(), 0);
156 }
157 #[test]
158 fn test_entries_in_range() {
159 let mut builder = SourceMapBuilder::new("abcdefghij");
160 builder.add_entry(
161 mk_span(0, 3, 1, 1),
162 EntryKind::Reference,
163 Some("a".to_string()),
164 );
165 builder.add_entry(
166 mk_span(4, 7, 1, 5),
167 EntryKind::Reference,
168 Some("b".to_string()),
169 );
170 builder.add_entry(
171 mk_span(8, 10, 1, 9),
172 EntryKind::Reference,
173 Some("c".to_string()),
174 );
175 let sm = builder.build();
176 let range_start = mk_span(2, 2, 1, 3);
177 let range_end = mk_span(6, 6, 1, 7);
178 let in_range = sm.entries_in_range(&range_start, &range_end);
179 assert_eq!(in_range.len(), 2);
180 }
181 #[test]
182 fn test_hover_info_on_definition() {
183 let mut builder = SourceMapBuilder::new("def foo := 42");
184 builder.add_definition_with_type(mk_span(4, 7, 1, 5), "foo", "Nat");
185 let sm = builder.build();
186 let hover = sm.hover_info(1, 5);
187 assert!(hover.is_some());
188 let info = hover.expect("test operation should succeed");
189 assert_eq!(info.name, "foo");
190 assert_eq!(info.kind, EntryKind::Definition);
191 assert_eq!(info.ty.as_deref(), Some("Nat"));
192 assert!(info.definition_span.is_some());
193 }
194 #[test]
195 fn test_hover_info_on_reference() {
196 let mut builder = SourceMapBuilder::new("def foo := foo");
197 builder.add_definition(mk_span(4, 7, 1, 5), "foo");
198 builder.add_reference(mk_span(11, 14, 1, 12), "foo");
199 let sm = builder.build();
200 let hover = sm.hover_info(1, 12);
201 assert!(hover.is_some());
202 let info = hover.expect("test operation should succeed");
203 assert_eq!(info.name, "foo");
204 assert_eq!(info.kind, EntryKind::Reference);
205 assert!(info.definition_span.is_some());
206 assert_eq!(
207 info.definition_span.expect("span should be present").start,
208 4
209 );
210 }
211 #[test]
212 fn test_hover_info_no_entry() {
213 let sm = SourceMap::new("hello");
214 assert!(sm.hover_info(1, 1).is_none());
215 }
216 #[test]
217 fn test_hover_info_with_doc_comment() {
218 let source = "/-- A doc comment -/
219def foo := 42";
220 let mut builder = SourceMapBuilder::new(source);
221 builder.add_doc_comment(mk_span(0, 20, 1, 1), "A doc comment");
222 builder.add_definition(mk_span(25, 28, 2, 5), "foo");
223 let sm = builder.build();
224 let hover = sm.hover_info(2, 5);
225 assert!(hover.is_some());
226 let info = hover.expect("test operation should succeed");
227 assert_eq!(info.name, "foo");
228 assert_eq!(info.doc.as_deref(), Some("A doc comment"));
229 }
230 #[test]
231 fn test_hover_info_doc_comment_separated_by_non_whitespace() {
232 let source = "/-- doc -/ something def foo := 42";
233 let mut builder = SourceMapBuilder::new(source);
234 builder.add_doc_comment(mk_span(0, 10, 1, 1), "doc");
235 builder.add_reference(mk_span(11, 20, 1, 12), "something");
236 builder.add_definition(mk_span(25, 28, 1, 26), "foo");
237 let sm = builder.build();
238 let hover = sm.hover_info(1, 26);
239 assert!(hover.is_some());
240 let info = hover.expect("test operation should succeed");
241 assert!(info.doc.is_none());
242 }
243 #[test]
244 fn test_hover_info_doc_comment_via_reference() {
245 let source = "/-- bar docs -/
246def bar := 0
247bar";
248 let mut builder = SourceMapBuilder::new(source);
249 builder.add_doc_comment(mk_span(0, 15, 1, 1), "bar docs");
250 builder.add_definition(mk_span(20, 23, 2, 5), "bar");
251 builder.add_reference(mk_span(29, 32, 3, 1), "bar");
252 let sm = builder.build();
253 let hover = sm.hover_info(3, 1);
254 assert!(hover.is_some());
255 let info = hover.expect("test operation should succeed");
256 assert_eq!(info.name, "bar");
257 assert_eq!(info.doc.as_deref(), Some("bar docs"));
258 }
259 #[test]
260 fn test_semantic_tokens_from_entries() {
261 let mut builder = SourceMapBuilder::new("def foo := 42");
262 builder.add_keyword(mk_span(0, 3, 1, 1));
263 builder.add_definition(mk_span(4, 7, 1, 5), "foo");
264 builder.add_literal(mk_span(11, 13, 1, 12));
265 let sm = builder.build();
266 let tokens = sm.semantic_tokens();
267 assert_eq!(tokens.len(), 3);
268 assert_eq!(tokens[0].token_type, SemanticTokenType::Keyword);
269 assert_eq!(tokens[1].token_type, SemanticTokenType::Function);
270 assert!(tokens[1].modifiers.contains(&SemanticModifier::Definition));
271 assert_eq!(tokens[2].token_type, SemanticTokenType::Number);
272 }
273 #[test]
274 fn test_semantic_tokens_precomputed() {
275 let mut builder = SourceMapBuilder::new("x");
276 builder.add_semantic_token(SemanticToken::new(
277 mk_span(0, 1, 1, 1),
278 SemanticTokenType::Variable,
279 ));
280 let sm = builder.build();
281 let tokens = sm.semantic_tokens();
282 assert_eq!(tokens.len(), 1);
283 assert_eq!(tokens[0].token_type, SemanticTokenType::Variable);
284 }
285 #[test]
286 fn test_go_to_definition() {
287 let mut builder = SourceMapBuilder::new("def foo := foo");
288 builder.add_definition(mk_span(4, 7, 1, 5), "foo");
289 builder.add_reference(mk_span(11, 14, 1, 12), "foo");
290 let sm = builder.build();
291 let def_span = sm.go_to_definition(1, 12);
292 assert!(def_span.is_some());
293 assert_eq!(def_span.expect("span should be present").start, 4);
294 }
295 #[test]
296 fn test_find_all_occurrences() {
297 let mut builder = SourceMapBuilder::new("def foo := foo + foo");
298 builder.add_definition(mk_span(4, 7, 1, 5), "foo");
299 builder.add_reference(mk_span(11, 14, 1, 12), "foo");
300 builder.add_reference(mk_span(17, 20, 1, 18), "foo");
301 let sm = builder.build();
302 let all = sm.find_all_occurrences(1, 5);
303 assert_eq!(all.len(), 3);
304 }
305 #[test]
306 fn test_span_text() {
307 let sm = SourceMap::new("hello world");
308 let span = mk_span(6, 11, 1, 7);
309 assert_eq!(sm.span_text(&span), "world");
310 }
311 #[test]
312 fn test_source_entry_contains_offset() {
313 let entry = SourceEntry::new(mk_span(5, 10, 1, 6), EntryKind::Reference);
314 assert!(!entry.contains_offset(4));
315 assert!(entry.contains_offset(5));
316 assert!(entry.contains_offset(9));
317 assert!(!entry.contains_offset(10));
318 }
319 #[test]
320 fn test_source_entry_with_name() {
321 let entry = SourceEntry::with_name(mk_span(0, 3, 1, 1), EntryKind::Definition, "foo");
322 assert_eq!(entry.name.as_deref(), Some("foo"));
323 assert!(entry.ty_info.is_none());
324 }
325 #[test]
326 fn test_source_entry_with_name_and_type() {
327 let entry = SourceEntry::with_name_and_type(
328 mk_span(0, 3, 1, 1),
329 EntryKind::Definition,
330 "foo",
331 "Nat",
332 );
333 assert_eq!(entry.name.as_deref(), Some("foo"));
334 assert_eq!(entry.ty_info.as_deref(), Some("Nat"));
335 }
336 #[test]
337 fn test_entries_of_kind() {
338 let mut builder = SourceMapBuilder::new("test");
339 builder.add_keyword(mk_span(0, 1, 1, 1));
340 builder.add_keyword(mk_span(1, 2, 1, 2));
341 builder.add_literal(mk_span(2, 3, 1, 3));
342 let sm = builder.build();
343 assert_eq!(sm.entries_of_kind(&EntryKind::Keyword).len(), 2);
344 assert_eq!(sm.entries_of_kind(&EntryKind::Literal).len(), 1);
345 assert_eq!(sm.entries_of_kind(&EntryKind::Definition).len(), 0);
346 }
347 #[test]
348 fn test_builder_add_various_kinds() {
349 let mut builder = SourceMapBuilder::new("test source");
350 builder.add_binder(mk_span(0, 1, 1, 1), "x");
351 builder.add_constructor(mk_span(1, 2, 1, 2), "Foo");
352 builder.add_operator(mk_span(2, 3, 1, 3), "+");
353 builder.add_comment(mk_span(3, 4, 1, 4));
354 builder.add_doc_comment(mk_span(4, 5, 1, 5), "docs");
355 builder.add_tactic(mk_span(5, 6, 1, 6), "simp");
356 builder.add_pattern(mk_span(6, 7, 1, 7), Some("pat"));
357 builder.add_type_annotation(mk_span(7, 8, 1, 8));
358 let sm = builder.build();
359 assert_eq!(sm.entries().len(), 8);
360 }
361 #[test]
362 fn test_semantic_token_constructors() {
363 let tok = SemanticToken::new(mk_span(0, 1, 1, 1), SemanticTokenType::Keyword);
364 assert!(tok.modifiers.is_empty());
365 let tok2 = SemanticToken::with_modifiers(
366 mk_span(0, 1, 1, 1),
367 SemanticTokenType::Function,
368 vec![SemanticModifier::Definition, SemanticModifier::Declaration],
369 );
370 assert_eq!(tok2.modifiers.len(), 2);
371 }
372}
373#[cfg(test)]
374mod extended_sourcemap_tests {
375 use super::*;
376 use crate::sourcemap::*;
377 use crate::tokens::Span;
378 fn mk_span(start: usize, end: usize, line: usize, col: usize) -> Span {
379 Span::new(start, end, line, col)
380 }
381 #[test]
382 fn test_source_position_origin() {
383 let pos = SourcePosition::origin();
384 assert_eq!(pos.offset, 0);
385 assert_eq!(pos.line, 1);
386 assert_eq!(pos.column, 1);
387 }
388 #[test]
389 fn test_source_position_advance_col() {
390 let pos = SourcePosition::origin().advance_col(1);
391 assert_eq!(pos.offset, 1);
392 assert_eq!(pos.column, 2);
393 assert_eq!(pos.line, 1);
394 }
395 #[test]
396 fn test_source_position_advance_line() {
397 let pos = SourcePosition::origin().advance_line(1);
398 assert_eq!(pos.line, 2);
399 assert_eq!(pos.column, 1);
400 }
401 #[test]
402 fn test_source_position_ordering() {
403 let a = SourcePosition::new(5, 1, 5);
404 let b = SourcePosition::new(10, 2, 3);
405 assert!(a.is_before(&b));
406 assert!(b.is_after(&a));
407 }
408 #[test]
409 fn test_source_region_contains() {
410 let span = mk_span(10, 20, 1, 10);
411 let region = SourceRegion::new("body", span);
412 assert!(region.contains_offset(15));
413 assert!(!region.contains_offset(25));
414 assert_eq!(region.byte_len(), 10);
415 }
416 #[test]
417 fn test_definition_index_basic() {
418 let mut idx = DefinitionIndex::new();
419 idx.register("foo", mk_span(0, 3, 1, 1));
420 idx.register("foo", mk_span(10, 13, 2, 1));
421 assert_eq!(idx.lookup("foo").len(), 2);
422 assert!(idx.contains("foo"));
423 assert!(!idx.contains("bar"));
424 }
425 #[test]
426 fn test_definition_index_merge() {
427 let mut a = DefinitionIndex::new();
428 a.register("foo", mk_span(0, 3, 1, 1));
429 let mut b = DefinitionIndex::new();
430 b.register("bar", mk_span(5, 8, 2, 1));
431 a.merge(b);
432 assert_eq!(a.len(), 2);
433 assert!(a.contains("foo"));
434 assert!(a.contains("bar"));
435 }
436 #[test]
437 fn test_reference_index_basic() {
438 let mut idx = ReferenceIndex::new();
439 idx.record("add", mk_span(0, 3, 1, 1));
440 idx.record("add", mk_span(10, 13, 2, 1));
441 idx.record("sub", mk_span(5, 8, 1, 5));
442 assert_eq!(idx.uses_of("add").len(), 2);
443 assert_eq!(idx.total_references(), 3);
444 }
445 #[test]
446 fn test_document_symbol_flatten() {
447 let mut sym = DocumentSymbol::new(
448 "Foo".to_string(),
449 SymbolKind::Structure,
450 mk_span(0, 100, 1, 1),
451 mk_span(0, 3, 1, 1),
452 );
453 let child = DocumentSymbol::new(
454 "bar".to_string(),
455 SymbolKind::Field,
456 mk_span(10, 20, 2, 3),
457 mk_span(10, 13, 2, 3),
458 );
459 sym.add_child(child);
460 let flat = sym.flatten();
461 assert_eq!(flat.len(), 2);
462 assert_eq!(flat[0].name, "Foo");
463 assert_eq!(flat[1].name, "bar");
464 }
465 #[test]
466 fn test_document_symbol_find_by_name() {
467 let mut sym = DocumentSymbol::new(
468 "Root".to_string(),
469 SymbolKind::Namespace,
470 mk_span(0, 200, 1, 1),
471 mk_span(0, 4, 1, 1),
472 );
473 let inner = DocumentSymbol::new(
474 "inner_fn".to_string(),
475 SymbolKind::Definition,
476 mk_span(10, 50, 2, 1),
477 mk_span(10, 18, 2, 1),
478 );
479 sym.add_child(inner);
480 assert!(sym.find_by_name("inner_fn").is_some());
481 assert!(sym.find_by_name("missing").is_none());
482 }
483 #[test]
484 fn test_source_index_symbol_at_offset() {
485 let mut idx = SourceIndex::new();
486 let sym = DocumentSymbol::new(
487 "myDef".to_string(),
488 SymbolKind::Definition,
489 mk_span(5, 50, 1, 5),
490 mk_span(5, 10, 1, 5),
491 );
492 idx.add_symbol(sym);
493 assert!(idx.symbol_at_offset(10).is_some());
494 assert!(idx.symbol_at_offset(100).is_none());
495 }
496 #[test]
497 fn test_goto_definition_result() {
498 let spans = vec![mk_span(0, 5, 1, 1)];
499 let result = GoToDefinitionResult::new("foo".to_string(), spans, true);
500 assert!(result.found());
501 assert!(result.is_local);
502 assert_eq!(
503 result.primary_span().expect("span should be present").start,
504 0
505 );
506 }
507 #[test]
508 fn test_goto_definition_not_found() {
509 let result = GoToDefinitionResult::new("unknown".to_string(), vec![], false);
510 assert!(!result.found());
511 assert!(result.primary_span().is_none());
512 }
513 #[test]
514 fn test_diagnostic_severity_ordering() {
515 assert!(DiagnosticSeverity::Hint < DiagnosticSeverity::Warning);
516 assert!(DiagnosticSeverity::Warning < DiagnosticSeverity::Error);
517 }
518 #[test]
519 fn test_source_diagnostic_constructors() {
520 let span = mk_span(0, 5, 1, 1);
521 let err = SourceDiagnostic::error(span.clone(), "bad token");
522 assert!(err.is_error());
523 assert!(!err.is_warning());
524 let warn = SourceDiagnostic::warning(span, "maybe bad");
525 assert!(warn.is_warning());
526 }
527 #[test]
528 fn test_source_diagnostic_with_code() {
529 let span = mk_span(0, 5, 1, 1);
530 let diag = SourceDiagnostic::error(span, "msg").with_code("E001");
531 assert_eq!(diag.code.as_deref(), Some("E001"));
532 }
533 #[test]
534 fn test_source_map_stats() {
535 let entries = vec![
536 SourceEntry::new(mk_span(0, 1, 1, 1), EntryKind::Definition),
537 SourceEntry::new(mk_span(1, 2, 1, 2), EntryKind::Reference),
538 SourceEntry::new(mk_span(2, 3, 1, 3), EntryKind::Tactic),
539 SourceEntry::new(mk_span(3, 4, 1, 4), EntryKind::Comment),
540 SourceEntry::new(mk_span(4, 5, 1, 5), EntryKind::Operator),
541 ];
542 let stats = SourceMapStats::from_entries(&entries);
543 assert_eq!(stats.total_entries, 5);
544 assert_eq!(stats.definitions, 1);
545 assert_eq!(stats.references, 1);
546 assert_eq!(stats.tactics, 1);
547 assert_eq!(stats.comments, 1);
548 assert_eq!(stats.operators, 1);
549 }
550}
551#[cfg(test)]
552mod sourcemap_ext_tests {
553 use super::*;
554 use crate::sourcemap::*;
555 use crate::tokens::Span;
556 #[test]
557 fn test_bidi_mapper() {
558 let mut m = BidiMapper::new();
559 m.add(0, 0);
560 m.add(5, 10);
561 m.add(10, 20);
562 assert_eq!(m.to_gen(0), Some(0));
563 assert_eq!(m.to_gen(7), Some(10));
564 assert_eq!(m.to_orig(15), Some(5));
565 }
566 #[test]
567 fn test_range_transform() {
568 let rt = RangeTransform::new(0, 10, 0, 10);
569 assert!(rt.is_length_preserving());
570 let rt2 = RangeTransform::new(0, 10, 0, 20);
571 assert!(!rt2.is_length_preserving());
572 }
573 #[test]
574 fn test_map_chain() {
575 let mut m1 = BidiMapper::new();
576 m1.add(0, 0);
577 m1.add(5, 5);
578 let mut m2 = BidiMapper::new();
579 m2.add(0, 0);
580 m2.add(5, 10);
581 let chain = MapChain::new(m1, m2);
582 let c = chain.a_to_c(5);
583 assert_eq!(c, Some(10));
584 }
585}
586#[allow(dead_code)]
588#[allow(missing_docs)]
589pub fn diff_mappers(old: &BidiMapper, new: &BidiMapper) -> SourceMapDiff {
590 let old_set: std::collections::HashSet<(usize, usize)> = old.forward.iter().cloned().collect();
591 let new_set: std::collections::HashSet<(usize, usize)> = new.forward.iter().cloned().collect();
592 let added = new_set.difference(&old_set).count();
593 let removed = old_set.difference(&new_set).count();
594 SourceMapDiff {
595 added,
596 removed,
597 modified: 0,
598 }
599}
600#[cfg(test)]
601mod sourcemap_ext2_tests {
602 use super::*;
603 use crate::sourcemap::*;
604 use crate::tokens::Span;
605 #[test]
606 fn test_source_map_cache() {
607 let mut cache = SourceMapCache::new();
608 cache.insert(1, 5, 10, 3);
609 assert_eq!(cache.lookup(1, 5), Some((10, 3)));
610 assert_eq!(cache.lookup(2, 0), None);
611 }
612 #[test]
613 fn test_diff_mappers() {
614 let mut m1 = BidiMapper::new();
615 m1.add(0, 0);
616 m1.add(5, 10);
617 let mut m2 = BidiMapper::new();
618 m2.add(0, 0);
619 m2.add(6, 12);
620 let diff = diff_mappers(&m1, &m2);
621 assert_eq!(diff.added, 1);
622 assert_eq!(diff.removed, 1);
623 }
624}
625#[cfg(test)]
626mod sorted_sourcemap_tests {
627 use super::*;
628 use crate::sourcemap::*;
629 use crate::tokens::Span;
630 #[test]
631 fn test_sorted_source_map() {
632 let mut sm = SortedSourceMap::new();
633 sm.add(0, 0);
634 sm.add(10, 5);
635 sm.add(20, 15);
636 assert_eq!(sm.lookup(0), Some(0));
637 assert_eq!(sm.lookup(15), Some(5));
638 assert_eq!(sm.lookup(100), Some(15));
639 }
640}
641#[allow(dead_code)]
643#[allow(missing_docs)]
644pub fn format_map_entry_json(
645 orig_line: usize,
646 orig_col: usize,
647 gen_line: usize,
648 gen_col: usize,
649) -> String {
650 format!(
651 r#"{{"origLine":{},"origCol":{},"genLine":{},"genCol":{}}}"#,
652 orig_line, orig_col, gen_line, gen_col
653 )
654}
655#[cfg(test)]
656mod sourcemap_batch_tests {
657 use super::*;
658 use crate::sourcemap::*;
659 use crate::tokens::Span;
660 #[test]
661 fn test_format_map_entry_json() {
662 let s = format_map_entry_json(1, 0, 2, 5);
663 assert!(s.contains("origLine"));
664 assert!(s.contains("genLine"));
665 }
666 #[test]
667 fn test_source_map_batch() {
668 let mut batch = SourceMapBatch::new();
669 batch.add(RangeTransform::new(0, 10, 0, 10));
670 batch.add(RangeTransform::new(10, 20, 10, 25));
671 assert_eq!(batch.total_coverage(), 20);
672 assert_eq!(batch.length_preserving_count(), 1);
673 }
674}
675#[allow(dead_code)]
677#[allow(missing_docs)]
678pub fn merge_sorted_maps(a: SortedSourceMap, b: SortedSourceMap) -> SortedSourceMap {
679 let mut result = SortedSourceMap::new();
680 for (gen, orig) in a.pairs.into_iter().chain(b.pairs) {
681 result.add(gen, orig);
682 }
683 result
684}
685#[allow(dead_code)]
687#[allow(missing_docs)]
688pub fn is_injective(map: &SortedSourceMap) -> bool {
689 let gens: Vec<usize> = map.pairs.iter().map(|(g, _)| *g).collect();
690 let mut seen = std::collections::HashSet::new();
691 gens.iter().all(|g| seen.insert(*g))
692}
693#[cfg(test)]
694mod sourcemap_pad {
695 use super::*;
696 use crate::sourcemap::*;
697 use crate::tokens::Span;
698 #[test]
699 fn test_merge_sorted_maps() {
700 let mut a = SortedSourceMap::new();
701 a.add(0, 0);
702 let mut b = SortedSourceMap::new();
703 b.add(5, 10);
704 let merged = merge_sorted_maps(a, b);
705 assert_eq!(merged.len(), 2);
706 }
707 #[test]
708 fn test_is_injective() {
709 let mut m = SortedSourceMap::new();
710 m.add(0, 0);
711 m.add(5, 10);
712 assert!(is_injective(&m));
713 }
714}
715#[allow(dead_code)]
717#[allow(missing_docs)]
718pub fn total_mappings(m: &SortedSourceMap) -> usize {
719 m.len()
720}
721#[allow(dead_code)]
723#[allow(missing_docs)]
724pub fn max_gen_offset(m: &SortedSourceMap) -> Option<usize> {
725 m.pairs.iter().map(|(g, _)| *g).max()
726}
727#[allow(dead_code)]
729#[allow(missing_docs)]
730pub fn min_gen_offset(m: &SortedSourceMap) -> Option<usize> {
731 m.pairs.iter().map(|(g, _)| *g).min()
732}
733#[allow(dead_code)]
735#[allow(missing_docs)]
736pub fn covers_gen_offset(m: &SortedSourceMap, gen: usize) -> bool {
737 m.pairs.iter().any(|(g, _)| *g == gen)
738}
739#[allow(dead_code)]
741#[allow(missing_docs)]
742pub fn all_orig_offsets(m: &SortedSourceMap) -> Vec<usize> {
743 m.pairs.iter().map(|(_, o)| *o).collect()
744}
745#[cfg(test)]
746mod sourcemap_pad2 {
747 use super::*;
748 use crate::sourcemap::*;
749 use crate::tokens::Span;
750 #[test]
751 fn test_max_min_gen_offset() {
752 let mut m = SortedSourceMap::new();
753 m.add(5, 10);
754 m.add(2, 4);
755 m.add(8, 20);
756 assert_eq!(max_gen_offset(&m), Some(8));
757 assert_eq!(min_gen_offset(&m), Some(2));
758 }
759 #[test]
760 fn test_covers_gen_offset() {
761 let mut m = SortedSourceMap::new();
762 m.add(3, 6);
763 assert!(covers_gen_offset(&m, 3));
764 assert!(!covers_gen_offset(&m, 4));
765 }
766}
767#[allow(dead_code)]
769#[allow(missing_docs)]
770pub fn is_sorted_ascending(m: &SortedSourceMap) -> bool {
771 m.pairs.windows(2).all(|w| w[0].0 <= w[1].0)
772}
773#[allow(dead_code)]
775#[allow(missing_docs)]
776pub fn filter_gen_range(m: &SortedSourceMap, lo: usize, hi: usize) -> SortedSourceMap {
777 let mut result = SortedSourceMap::new();
778 for &(gen, orig) in &m.pairs {
779 if gen >= lo && gen < hi {
780 result.add(gen, orig);
781 }
782 }
783 result
784}
785#[allow(dead_code)]
787#[allow(missing_docs)]
788pub fn count_to_orig(m: &SortedSourceMap, orig: usize) -> usize {
789 m.pairs.iter().filter(|(_, o)| *o == orig).count()
790}