]> git.lizzy.rs Git - rust.git/blob - crates/ide/src/runnables.rs
Merge #11713
[rust.git] / crates / ide / src / runnables.rs
1 use std::fmt;
2
3 use ast::HasName;
4 use cfg::CfgExpr;
5 use hir::{AsAssocItem, HasAttrs, HasSource, HirDisplay, Semantics};
6 use ide_assists::utils::test_related_attribute;
7 use ide_db::{
8     base_db::{FilePosition, FileRange},
9     defs::Definition,
10     helpers::visit_file_defs,
11     search::SearchScope,
12     RootDatabase, SymbolKind,
13 };
14 use itertools::Itertools;
15 use rustc_hash::{FxHashMap, FxHashSet};
16 use stdx::{always, format_to};
17 use syntax::{
18     ast::{self, AstNode, HasAttrs as _},
19     SmolStr, SyntaxNode,
20 };
21
22 use crate::{references, FileId, NavigationTarget, ToNav, TryToNav};
23
24 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
25 pub struct Runnable {
26     pub use_name_in_title: bool,
27     pub nav: NavigationTarget,
28     pub kind: RunnableKind,
29     pub cfg: Option<CfgExpr>,
30 }
31
32 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
33 pub enum TestId {
34     Name(SmolStr),
35     Path(String),
36 }
37
38 impl fmt::Display for TestId {
39     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
40         match self {
41             TestId::Name(name) => write!(f, "{}", name),
42             TestId::Path(path) => write!(f, "{}", path),
43         }
44     }
45 }
46
47 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
48 pub enum RunnableKind {
49     Test { test_id: TestId, attr: TestAttr },
50     TestMod { path: String },
51     Bench { test_id: TestId },
52     DocTest { test_id: TestId },
53     Bin,
54 }
55
56 #[cfg(test)]
57 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
58 enum RunnableTestKind {
59     Test,
60     TestMod,
61     DocTest,
62     Bench,
63     Bin,
64 }
65
66 impl Runnable {
67     // test package::module::testname
68     pub fn label(&self, target: Option<String>) -> String {
69         match &self.kind {
70             RunnableKind::Test { test_id, .. } => format!("test {}", test_id),
71             RunnableKind::TestMod { path } => format!("test-mod {}", path),
72             RunnableKind::Bench { test_id } => format!("bench {}", test_id),
73             RunnableKind::DocTest { test_id, .. } => format!("doctest {}", test_id),
74             RunnableKind::Bin => {
75                 target.map_or_else(|| "run binary".to_string(), |t| format!("run {}", t))
76             }
77         }
78     }
79
80     pub fn title(&self) -> String {
81         let mut s = String::from("▶\u{fe0e} Run ");
82         if self.use_name_in_title {
83             format_to!(s, "{}", self.nav.name);
84             if !matches!(self.kind, RunnableKind::Bin) {
85                 s.push(' ');
86             }
87         }
88         let suffix = match &self.kind {
89             RunnableKind::TestMod { .. } => "Tests",
90             RunnableKind::Test { .. } => "Test",
91             RunnableKind::DocTest { .. } => "Doctest",
92             RunnableKind::Bench { .. } => "Bench",
93             RunnableKind::Bin => return s,
94         };
95         s.push_str(suffix);
96         s
97     }
98
99     #[cfg(test)]
100     fn test_kind(&self) -> RunnableTestKind {
101         match &self.kind {
102             RunnableKind::TestMod { .. } => RunnableTestKind::TestMod,
103             RunnableKind::Test { .. } => RunnableTestKind::Test,
104             RunnableKind::DocTest { .. } => RunnableTestKind::DocTest,
105             RunnableKind::Bench { .. } => RunnableTestKind::Bench,
106             RunnableKind::Bin => RunnableTestKind::Bin,
107         }
108     }
109 }
110
111 // Feature: Run
112 //
113 // Shows a popup suggesting to run a test/benchmark/binary **at the current cursor
114 // location**. Super useful for repeatedly running just a single test. Do bind this
115 // to a shortcut!
116 //
117 // |===
118 // | Editor  | Action Name
119 //
120 // | VS Code | **Rust Analyzer: Run**
121 // |===
122 // image::https://user-images.githubusercontent.com/48062697/113065583-055aae80-91b1-11eb-958f-d67efcaf6a2f.gif[]
123 pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> {
124     let sema = Semantics::new(db);
125
126     let mut res = Vec::new();
127     // Record all runnables that come from macro expansions here instead.
128     // In case an expansion creates multiple runnables we want to name them to avoid emitting a bunch of equally named runnables.
129     let mut in_macro_expansion = FxHashMap::<hir::HirFileId, Vec<Runnable>>::default();
130     let mut add_opt = |runnable: Option<Runnable>, def| {
131         if let Some(runnable) = runnable.filter(|runnable| {
132             always!(
133                 runnable.nav.file_id == file_id,
134                 "tried adding a runnable pointing to a different file: {:?} for {:?}",
135                 runnable.kind,
136                 file_id
137             )
138         }) {
139             if let Some(def) = def {
140                 let file_id = match def {
141                     Definition::Module(it) => it.declaration_source(db).map(|src| src.file_id),
142                     Definition::Function(it) => it.source(db).map(|src| src.file_id),
143                     _ => None,
144                 };
145                 if let Some(file_id) = file_id.filter(|file| file.call_node(db).is_some()) {
146                     in_macro_expansion.entry(file_id).or_default().push(runnable);
147                     return;
148                 }
149             }
150             res.push(runnable);
151         }
152     };
153     visit_file_defs(&sema, file_id, &mut |def| {
154         let runnable = match def {
155             Definition::Module(it) => runnable_mod(&sema, it),
156             Definition::Function(it) => runnable_fn(&sema, it),
157             Definition::SelfType(impl_) => runnable_impl(&sema, &impl_),
158             _ => None,
159         };
160         add_opt(
161             runnable
162                 .or_else(|| module_def_doctest(sema.db, def))
163                 // #[macro_export] mbe macros are declared in the root, while their definition may reside in a different module
164                 .filter(|it| it.nav.file_id == file_id),
165             Some(def),
166         );
167         if let Definition::SelfType(impl_) = def {
168             impl_.items(db).into_iter().for_each(|assoc| {
169                 let runnable = match assoc {
170                     hir::AssocItem::Function(it) => {
171                         runnable_fn(&sema, it).or_else(|| module_def_doctest(sema.db, it.into()))
172                     }
173                     hir::AssocItem::Const(it) => module_def_doctest(sema.db, it.into()),
174                     hir::AssocItem::TypeAlias(it) => module_def_doctest(sema.db, it.into()),
175                 };
176                 add_opt(runnable, Some(assoc.into()))
177             });
178         }
179     });
180
181     sema.to_module_defs(file_id)
182         .map(|it| runnable_mod_outline_definition(&sema, it))
183         .for_each(|it| add_opt(it, None));
184
185     res.extend(in_macro_expansion.into_iter().flat_map(|(_, runnables)| {
186         let use_name_in_title = runnables.len() != 1;
187         runnables.into_iter().map(move |mut r| {
188             r.use_name_in_title = use_name_in_title;
189             r
190         })
191     }));
192     res
193 }
194
195 // Feature: Related Tests
196 //
197 // Provides a sneak peek of all tests where the current item is used.
198 //
199 // The simplest way to use this feature is via the context menu:
200 //  - Right-click on the selected item. The context menu opens.
201 //  - Select **Peek related tests**
202 //
203 // |===
204 // | Editor  | Action Name
205 //
206 // | VS Code | **Rust Analyzer: Peek related tests**
207 // |===
208 pub(crate) fn related_tests(
209     db: &RootDatabase,
210     position: FilePosition,
211     search_scope: Option<SearchScope>,
212 ) -> Vec<Runnable> {
213     let sema = Semantics::new(db);
214     let mut res: FxHashSet<Runnable> = FxHashSet::default();
215     let syntax = sema.parse(position.file_id).syntax().clone();
216
217     find_related_tests(&sema, &syntax, position, search_scope, &mut res);
218
219     res.into_iter().collect()
220 }
221
222 fn find_related_tests(
223     sema: &Semantics<RootDatabase>,
224     syntax: &SyntaxNode,
225     position: FilePosition,
226     search_scope: Option<SearchScope>,
227     tests: &mut FxHashSet<Runnable>,
228 ) {
229     let defs = references::find_defs(sema, syntax, position.offset);
230     for def in defs {
231         let defs = def
232             .usages(sema)
233             .set_scope(search_scope.clone())
234             .all()
235             .references
236             .into_values()
237             .flatten();
238         for ref_ in defs {
239             let name_ref = match ref_.name {
240                 ast::NameLike::NameRef(name_ref) => name_ref,
241                 _ => continue,
242             };
243             if let Some(fn_def) =
244                 sema.ancestors_with_macros(name_ref.syntax().clone()).find_map(ast::Fn::cast)
245             {
246                 if let Some(runnable) = as_test_runnable(sema, &fn_def) {
247                     // direct test
248                     tests.insert(runnable);
249                 } else if let Some(module) = parent_test_module(sema, &fn_def) {
250                     // indirect test
251                     find_related_tests_in_module(sema, syntax, &fn_def, &module, tests);
252                 }
253             }
254         }
255     }
256 }
257
258 fn find_related_tests_in_module(
259     sema: &Semantics<RootDatabase>,
260     syntax: &SyntaxNode,
261     fn_def: &ast::Fn,
262     parent_module: &hir::Module,
263     tests: &mut FxHashSet<Runnable>,
264 ) {
265     let fn_name = match fn_def.name() {
266         Some(it) => it,
267         _ => return,
268     };
269     let mod_source = parent_module.definition_source(sema.db);
270     let range = match &mod_source.value {
271         hir::ModuleSource::Module(m) => m.syntax().text_range(),
272         hir::ModuleSource::BlockExpr(b) => b.syntax().text_range(),
273         hir::ModuleSource::SourceFile(f) => f.syntax().text_range(),
274     };
275
276     let file_id = mod_source.file_id.original_file(sema.db);
277     let mod_scope = SearchScope::file_range(FileRange { file_id, range });
278     let fn_pos = FilePosition { file_id, offset: fn_name.syntax().text_range().start() };
279     find_related_tests(sema, syntax, fn_pos, Some(mod_scope), tests)
280 }
281
282 fn as_test_runnable(sema: &Semantics<RootDatabase>, fn_def: &ast::Fn) -> Option<Runnable> {
283     if test_related_attribute(fn_def).is_some() {
284         let function = sema.to_def(fn_def)?;
285         runnable_fn(sema, function)
286     } else {
287         None
288     }
289 }
290
291 fn parent_test_module(sema: &Semantics<RootDatabase>, fn_def: &ast::Fn) -> Option<hir::Module> {
292     fn_def.syntax().ancestors().find_map(|node| {
293         let module = ast::Module::cast(node)?;
294         let module = sema.to_def(&module)?;
295
296         if has_test_function_or_multiple_test_submodules(sema, &module) {
297             Some(module)
298         } else {
299             None
300         }
301     })
302 }
303
304 pub(crate) fn runnable_fn(sema: &Semantics<RootDatabase>, def: hir::Function) -> Option<Runnable> {
305     let func = def.source(sema.db)?;
306     let name = def.name(sema.db).to_smol_str();
307
308     let root = def.module(sema.db).krate().root_module(sema.db);
309
310     let kind = if name == "main" && def.module(sema.db) == root {
311         RunnableKind::Bin
312     } else {
313         let test_id = || {
314             let canonical_path = {
315                 let def: hir::ModuleDef = def.into();
316                 def.canonical_path(sema.db)
317             };
318             canonical_path.map(TestId::Path).unwrap_or(TestId::Name(name))
319         };
320
321         if test_related_attribute(&func.value).is_some() {
322             let attr = TestAttr::from_fn(&func.value);
323             RunnableKind::Test { test_id: test_id(), attr }
324         } else if func.value.has_atom_attr("bench") {
325             RunnableKind::Bench { test_id: test_id() }
326         } else {
327             return None;
328         }
329     };
330
331     let nav = NavigationTarget::from_named(
332         sema.db,
333         func.as_ref().map(|it| it as &dyn ast::HasName),
334         SymbolKind::Function,
335     );
336     let cfg = def.attrs(sema.db).cfg();
337     Some(Runnable { use_name_in_title: false, nav, kind, cfg })
338 }
339
340 pub(crate) fn runnable_mod(sema: &Semantics<RootDatabase>, def: hir::Module) -> Option<Runnable> {
341     if !has_test_function_or_multiple_test_submodules(sema, &def) {
342         return None;
343     }
344     let path =
345         def.path_to_root(sema.db).into_iter().rev().filter_map(|it| it.name(sema.db)).join("::");
346
347     let attrs = def.attrs(sema.db);
348     let cfg = attrs.cfg();
349     let nav = NavigationTarget::from_module_to_decl(sema.db, def);
350     Some(Runnable { use_name_in_title: false, nav, kind: RunnableKind::TestMod { path }, cfg })
351 }
352
353 pub(crate) fn runnable_impl(sema: &Semantics<RootDatabase>, def: &hir::Impl) -> Option<Runnable> {
354     let attrs = def.attrs(sema.db);
355     if !has_runnable_doc_test(&attrs) {
356         return None;
357     }
358     let cfg = attrs.cfg();
359     let nav = def.try_to_nav(sema.db)?;
360     let ty = def.self_ty(sema.db);
361     let adt_name = ty.as_adt()?.name(sema.db);
362     let mut ty_args = ty.type_arguments().peekable();
363     let params = if ty_args.peek().is_some() {
364         format!("<{}>", ty_args.format_with(", ", |ty, cb| cb(&ty.display(sema.db))))
365     } else {
366         String::new()
367     };
368     let test_id = TestId::Path(format!("{}{}", adt_name, params));
369
370     Some(Runnable { use_name_in_title: false, nav, kind: RunnableKind::DocTest { test_id }, cfg })
371 }
372
373 /// Creates a test mod runnable for outline modules at the top of their definition.
374 fn runnable_mod_outline_definition(
375     sema: &Semantics<RootDatabase>,
376     def: hir::Module,
377 ) -> Option<Runnable> {
378     if !has_test_function_or_multiple_test_submodules(sema, &def) {
379         return None;
380     }
381     let path =
382         def.path_to_root(sema.db).into_iter().rev().filter_map(|it| it.name(sema.db)).join("::");
383
384     let attrs = def.attrs(sema.db);
385     let cfg = attrs.cfg();
386     match def.definition_source(sema.db).value {
387         hir::ModuleSource::SourceFile(_) => Some(Runnable {
388             use_name_in_title: false,
389             nav: def.to_nav(sema.db),
390             kind: RunnableKind::TestMod { path },
391             cfg,
392         }),
393         _ => None,
394     }
395 }
396
397 fn module_def_doctest(db: &RootDatabase, def: Definition) -> Option<Runnable> {
398     let attrs = match def {
399         Definition::Module(it) => it.attrs(db),
400         Definition::Function(it) => it.attrs(db),
401         Definition::Adt(it) => it.attrs(db),
402         Definition::Variant(it) => it.attrs(db),
403         Definition::Const(it) => it.attrs(db),
404         Definition::Static(it) => it.attrs(db),
405         Definition::Trait(it) => it.attrs(db),
406         Definition::TypeAlias(it) => it.attrs(db),
407         Definition::Macro(it) => it.attrs(db),
408         Definition::SelfType(it) => it.attrs(db),
409         _ => return None,
410     };
411     if !has_runnable_doc_test(&attrs) {
412         return None;
413     }
414     let def_name = def.name(db)?;
415     let path = (|| {
416         let mut path = String::new();
417         def.canonical_module_path(db)?
418             .flat_map(|it| it.name(db))
419             .for_each(|name| format_to!(path, "{}::", name));
420         // This probably belongs to canonical_path?
421         if let Some(assoc_item) = def.as_assoc_item(db) {
422             if let hir::AssocItemContainer::Impl(imp) = assoc_item.container(db) {
423                 let ty = imp.self_ty(db);
424                 if let Some(adt) = ty.as_adt() {
425                     let name = adt.name(db);
426                     let mut ty_args = ty.type_arguments().peekable();
427                     format_to!(path, "{}", name);
428                     if ty_args.peek().is_some() {
429                         format_to!(
430                             path,
431                             "<{}>",
432                             ty_args.format_with(", ", |ty, cb| cb(&ty.display(db)))
433                         );
434                     }
435                     return Some(format!(r#""{}::{}""#, path, def_name));
436                 }
437             }
438         }
439         format_to!(path, "{}", def_name);
440         Some(path)
441     })();
442
443     let test_id = path.map_or_else(|| TestId::Name(def_name.to_smol_str()), TestId::Path);
444
445     let mut nav = match def {
446         Definition::Module(def) => NavigationTarget::from_module_to_decl(db, def),
447         def => def.try_to_nav(db)?,
448     };
449     nav.focus_range = None;
450     nav.description = None;
451     nav.docs = None;
452     nav.kind = None;
453     let res = Runnable {
454         use_name_in_title: false,
455         nav,
456         kind: RunnableKind::DocTest { test_id },
457         cfg: attrs.cfg(),
458     };
459     Some(res)
460 }
461
462 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
463 pub struct TestAttr {
464     pub ignore: bool,
465 }
466
467 impl TestAttr {
468     fn from_fn(fn_def: &ast::Fn) -> TestAttr {
469         let ignore = fn_def
470             .attrs()
471             .filter_map(|attr| attr.simple_name())
472             .any(|attribute_text| attribute_text == "ignore");
473         TestAttr { ignore }
474     }
475 }
476
477 const RUSTDOC_FENCE: &str = "```";
478 const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] =
479     &["", "rust", "should_panic", "edition2015", "edition2018", "edition2021"];
480
481 fn has_runnable_doc_test(attrs: &hir::Attrs) -> bool {
482     attrs.docs().map_or(false, |doc| {
483         let mut in_code_block = false;
484
485         for line in String::from(doc).lines() {
486             if let Some(header) = line.strip_prefix(RUSTDOC_FENCE) {
487                 in_code_block = !in_code_block;
488
489                 if in_code_block
490                     && header
491                         .split(',')
492                         .all(|sub| RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE.contains(&sub.trim()))
493                 {
494                     return true;
495                 }
496             }
497         }
498
499         false
500     })
501 }
502
503 // We could create runnables for modules with number_of_test_submodules > 0,
504 // but that bloats the runnables for no real benefit, since all tests can be run by the submodule already
505 fn has_test_function_or_multiple_test_submodules(
506     sema: &Semantics<RootDatabase>,
507     module: &hir::Module,
508 ) -> bool {
509     let mut number_of_test_submodules = 0;
510
511     for item in module.declarations(sema.db) {
512         match item {
513             hir::ModuleDef::Function(f) => {
514                 if let Some(it) = f.source(sema.db) {
515                     if test_related_attribute(&it.value).is_some() {
516                         return true;
517                     }
518                 }
519             }
520             hir::ModuleDef::Module(submodule) => {
521                 if has_test_function_or_multiple_test_submodules(sema, &submodule) {
522                     number_of_test_submodules += 1;
523                 }
524             }
525             _ => (),
526         }
527     }
528
529     number_of_test_submodules > 1
530 }
531
532 #[cfg(test)]
533 mod tests {
534     use expect_test::{expect, Expect};
535
536     use crate::fixture;
537
538     use super::{RunnableTestKind::*, *};
539
540     fn check(
541         ra_fixture: &str,
542         // FIXME: fold this into `expect` as well
543         actions: &[RunnableTestKind],
544         expect: Expect,
545     ) {
546         let (analysis, position) = fixture::position(ra_fixture);
547         let runnables = analysis.runnables(position.file_id).unwrap();
548         expect.assert_debug_eq(&runnables);
549         assert_eq!(
550             actions,
551             runnables.into_iter().map(|it| it.test_kind()).collect::<Vec<_>>().as_slice()
552         );
553     }
554
555     fn check_tests(ra_fixture: &str, expect: Expect) {
556         let (analysis, position) = fixture::position(ra_fixture);
557         let tests = analysis.related_tests(position, None).unwrap();
558         expect.assert_debug_eq(&tests);
559     }
560
561     #[test]
562     fn test_runnables() {
563         check(
564             r#"
565 //- /lib.rs
566 $0
567 fn main() {}
568
569 #[test]
570 fn test_foo() {}
571
572 #[test]
573 #[ignore]
574 fn test_foo() {}
575
576 #[bench]
577 fn bench() {}
578
579 mod not_a_root {
580     fn main() {}
581 }
582 "#,
583             &[Bin, Test, Test, Bench, TestMod],
584             expect![[r#"
585                 [
586                     Runnable {
587                         use_name_in_title: false,
588                         nav: NavigationTarget {
589                             file_id: FileId(
590                                 0,
591                             ),
592                             full_range: 1..13,
593                             focus_range: 4..8,
594                             name: "main",
595                             kind: Function,
596                         },
597                         kind: Bin,
598                         cfg: None,
599                     },
600                     Runnable {
601                         use_name_in_title: false,
602                         nav: NavigationTarget {
603                             file_id: FileId(
604                                 0,
605                             ),
606                             full_range: 15..39,
607                             focus_range: 26..34,
608                             name: "test_foo",
609                             kind: Function,
610                         },
611                         kind: Test {
612                             test_id: Path(
613                                 "test_foo",
614                             ),
615                             attr: TestAttr {
616                                 ignore: false,
617                             },
618                         },
619                         cfg: None,
620                     },
621                     Runnable {
622                         use_name_in_title: false,
623                         nav: NavigationTarget {
624                             file_id: FileId(
625                                 0,
626                             ),
627                             full_range: 41..75,
628                             focus_range: 62..70,
629                             name: "test_foo",
630                             kind: Function,
631                         },
632                         kind: Test {
633                             test_id: Path(
634                                 "test_foo",
635                             ),
636                             attr: TestAttr {
637                                 ignore: true,
638                             },
639                         },
640                         cfg: None,
641                     },
642                     Runnable {
643                         use_name_in_title: false,
644                         nav: NavigationTarget {
645                             file_id: FileId(
646                                 0,
647                             ),
648                             full_range: 77..99,
649                             focus_range: 89..94,
650                             name: "bench",
651                             kind: Function,
652                         },
653                         kind: Bench {
654                             test_id: Path(
655                                 "bench",
656                             ),
657                         },
658                         cfg: None,
659                     },
660                     Runnable {
661                         use_name_in_title: false,
662                         nav: NavigationTarget {
663                             file_id: FileId(
664                                 0,
665                             ),
666                             full_range: 0..137,
667                             name: "",
668                             kind: Module,
669                         },
670                         kind: TestMod {
671                             path: "",
672                         },
673                         cfg: None,
674                     },
675                 ]
676             "#]],
677         );
678     }
679
680     #[test]
681     fn test_runnables_doc_test() {
682         check(
683             r#"
684 //- /lib.rs
685 $0
686 fn main() {}
687
688 /// ```
689 /// let x = 5;
690 /// ```
691 fn should_have_runnable() {}
692
693 /// ```edition2018
694 /// let x = 5;
695 /// ```
696 fn should_have_runnable_1() {}
697
698 /// ```
699 /// let z = 55;
700 /// ```
701 ///
702 /// ```ignore
703 /// let z = 56;
704 /// ```
705 fn should_have_runnable_2() {}
706
707 /**
708 ```rust
709 let z = 55;
710 ```
711 */
712 fn should_have_no_runnable_3() {}
713
714 /**
715     ```rust
716     let z = 55;
717     ```
718 */
719 fn should_have_no_runnable_4() {}
720
721 /// ```no_run
722 /// let z = 55;
723 /// ```
724 fn should_have_no_runnable() {}
725
726 /// ```ignore
727 /// let z = 55;
728 /// ```
729 fn should_have_no_runnable_2() {}
730
731 /// ```compile_fail
732 /// let z = 55;
733 /// ```
734 fn should_have_no_runnable_3() {}
735
736 /// ```text
737 /// arbitrary plain text
738 /// ```
739 fn should_have_no_runnable_4() {}
740
741 /// ```text
742 /// arbitrary plain text
743 /// ```
744 ///
745 /// ```sh
746 /// $ shell code
747 /// ```
748 fn should_have_no_runnable_5() {}
749
750 /// ```rust,no_run
751 /// let z = 55;
752 /// ```
753 fn should_have_no_runnable_6() {}
754
755 /// ```
756 /// let x = 5;
757 /// ```
758 struct StructWithRunnable(String);
759
760 /// ```
761 /// let x = 5;
762 /// ```
763 impl StructWithRunnable {}
764
765 trait Test {
766     fn test() -> usize {
767         5usize
768     }
769 }
770
771 /// ```
772 /// let x = 5;
773 /// ```
774 impl Test for StructWithRunnable {}
775 "#,
776             &[Bin, DocTest, DocTest, DocTest, DocTest, DocTest, DocTest, DocTest, DocTest],
777             expect![[r#"
778                 [
779                     Runnable {
780                         use_name_in_title: false,
781                         nav: NavigationTarget {
782                             file_id: FileId(
783                                 0,
784                             ),
785                             full_range: 1..13,
786                             focus_range: 4..8,
787                             name: "main",
788                             kind: Function,
789                         },
790                         kind: Bin,
791                         cfg: None,
792                     },
793                     Runnable {
794                         use_name_in_title: false,
795                         nav: NavigationTarget {
796                             file_id: FileId(
797                                 0,
798                             ),
799                             full_range: 15..74,
800                             name: "should_have_runnable",
801                         },
802                         kind: DocTest {
803                             test_id: Path(
804                                 "should_have_runnable",
805                             ),
806                         },
807                         cfg: None,
808                     },
809                     Runnable {
810                         use_name_in_title: false,
811                         nav: NavigationTarget {
812                             file_id: FileId(
813                                 0,
814                             ),
815                             full_range: 76..148,
816                             name: "should_have_runnable_1",
817                         },
818                         kind: DocTest {
819                             test_id: Path(
820                                 "should_have_runnable_1",
821                             ),
822                         },
823                         cfg: None,
824                     },
825                     Runnable {
826                         use_name_in_title: false,
827                         nav: NavigationTarget {
828                             file_id: FileId(
829                                 0,
830                             ),
831                             full_range: 150..254,
832                             name: "should_have_runnable_2",
833                         },
834                         kind: DocTest {
835                             test_id: Path(
836                                 "should_have_runnable_2",
837                             ),
838                         },
839                         cfg: None,
840                     },
841                     Runnable {
842                         use_name_in_title: false,
843                         nav: NavigationTarget {
844                             file_id: FileId(
845                                 0,
846                             ),
847                             full_range: 256..320,
848                             name: "should_have_no_runnable_3",
849                         },
850                         kind: DocTest {
851                             test_id: Path(
852                                 "should_have_no_runnable_3",
853                             ),
854                         },
855                         cfg: None,
856                     },
857                     Runnable {
858                         use_name_in_title: false,
859                         nav: NavigationTarget {
860                             file_id: FileId(
861                                 0,
862                             ),
863                             full_range: 322..398,
864                             name: "should_have_no_runnable_4",
865                         },
866                         kind: DocTest {
867                             test_id: Path(
868                                 "should_have_no_runnable_4",
869                             ),
870                         },
871                         cfg: None,
872                     },
873                     Runnable {
874                         use_name_in_title: false,
875                         nav: NavigationTarget {
876                             file_id: FileId(
877                                 0,
878                             ),
879                             full_range: 900..965,
880                             name: "StructWithRunnable",
881                         },
882                         kind: DocTest {
883                             test_id: Path(
884                                 "StructWithRunnable",
885                             ),
886                         },
887                         cfg: None,
888                     },
889                     Runnable {
890                         use_name_in_title: false,
891                         nav: NavigationTarget {
892                             file_id: FileId(
893                                 0,
894                             ),
895                             full_range: 967..1024,
896                             focus_range: 1003..1021,
897                             name: "impl",
898                             kind: Impl,
899                         },
900                         kind: DocTest {
901                             test_id: Path(
902                                 "StructWithRunnable",
903                             ),
904                         },
905                         cfg: None,
906                     },
907                     Runnable {
908                         use_name_in_title: false,
909                         nav: NavigationTarget {
910                             file_id: FileId(
911                                 0,
912                             ),
913                             full_range: 1088..1154,
914                             focus_range: 1133..1151,
915                             name: "impl",
916                             kind: Impl,
917                         },
918                         kind: DocTest {
919                             test_id: Path(
920                                 "StructWithRunnable",
921                             ),
922                         },
923                         cfg: None,
924                     },
925                 ]
926             "#]],
927         );
928     }
929
930     #[test]
931     fn test_runnables_doc_test_in_impl() {
932         check(
933             r#"
934 //- /lib.rs
935 $0
936 fn main() {}
937
938 struct Data;
939 impl Data {
940     /// ```
941     /// let x = 5;
942     /// ```
943     fn foo() {}
944 }
945 "#,
946             &[Bin, DocTest],
947             expect![[r#"
948                 [
949                     Runnable {
950                         use_name_in_title: false,
951                         nav: NavigationTarget {
952                             file_id: FileId(
953                                 0,
954                             ),
955                             full_range: 1..13,
956                             focus_range: 4..8,
957                             name: "main",
958                             kind: Function,
959                         },
960                         kind: Bin,
961                         cfg: None,
962                     },
963                     Runnable {
964                         use_name_in_title: false,
965                         nav: NavigationTarget {
966                             file_id: FileId(
967                                 0,
968                             ),
969                             full_range: 44..98,
970                             name: "foo",
971                         },
972                         kind: DocTest {
973                             test_id: Path(
974                                 "\"Data::foo\"",
975                             ),
976                         },
977                         cfg: None,
978                     },
979                 ]
980             "#]],
981         );
982     }
983
984     #[test]
985     fn test_runnables_module() {
986         check(
987             r#"
988 //- /lib.rs
989 $0
990 mod test_mod {
991     #[test]
992     fn test_foo1() {}
993 }
994 "#,
995             &[TestMod, Test],
996             expect![[r#"
997                 [
998                     Runnable {
999                         use_name_in_title: false,
1000                         nav: NavigationTarget {
1001                             file_id: FileId(
1002                                 0,
1003                             ),
1004                             full_range: 1..51,
1005                             focus_range: 5..13,
1006                             name: "test_mod",
1007                             kind: Module,
1008                             description: "mod test_mod",
1009                         },
1010                         kind: TestMod {
1011                             path: "test_mod",
1012                         },
1013                         cfg: None,
1014                     },
1015                     Runnable {
1016                         use_name_in_title: false,
1017                         nav: NavigationTarget {
1018                             file_id: FileId(
1019                                 0,
1020                             ),
1021                             full_range: 20..49,
1022                             focus_range: 35..44,
1023                             name: "test_foo1",
1024                             kind: Function,
1025                         },
1026                         kind: Test {
1027                             test_id: Path(
1028                                 "test_mod::test_foo1",
1029                             ),
1030                             attr: TestAttr {
1031                                 ignore: false,
1032                             },
1033                         },
1034                         cfg: None,
1035                     },
1036                 ]
1037             "#]],
1038         );
1039     }
1040
1041     #[test]
1042     fn only_modules_with_test_functions_or_more_than_one_test_submodule_have_runners() {
1043         check(
1044             r#"
1045 //- /lib.rs
1046 $0
1047 mod root_tests {
1048     mod nested_tests_0 {
1049         mod nested_tests_1 {
1050             #[test]
1051             fn nested_test_11() {}
1052
1053             #[test]
1054             fn nested_test_12() {}
1055         }
1056
1057         mod nested_tests_2 {
1058             #[test]
1059             fn nested_test_2() {}
1060         }
1061
1062         mod nested_tests_3 {}
1063     }
1064
1065     mod nested_tests_4 {}
1066 }
1067 "#,
1068             &[TestMod, TestMod, TestMod, Test, Test, Test],
1069             expect![[r#"
1070                 [
1071                     Runnable {
1072                         use_name_in_title: false,
1073                         nav: NavigationTarget {
1074                             file_id: FileId(
1075                                 0,
1076                             ),
1077                             full_range: 22..323,
1078                             focus_range: 26..40,
1079                             name: "nested_tests_0",
1080                             kind: Module,
1081                             description: "mod nested_tests_0",
1082                         },
1083                         kind: TestMod {
1084                             path: "root_tests::nested_tests_0",
1085                         },
1086                         cfg: None,
1087                     },
1088                     Runnable {
1089                         use_name_in_title: false,
1090                         nav: NavigationTarget {
1091                             file_id: FileId(
1092                                 0,
1093                             ),
1094                             full_range: 51..192,
1095                             focus_range: 55..69,
1096                             name: "nested_tests_1",
1097                             kind: Module,
1098                             description: "mod nested_tests_1",
1099                         },
1100                         kind: TestMod {
1101                             path: "root_tests::nested_tests_0::nested_tests_1",
1102                         },
1103                         cfg: None,
1104                     },
1105                     Runnable {
1106                         use_name_in_title: false,
1107                         nav: NavigationTarget {
1108                             file_id: FileId(
1109                                 0,
1110                             ),
1111                             full_range: 202..286,
1112                             focus_range: 206..220,
1113                             name: "nested_tests_2",
1114                             kind: Module,
1115                             description: "mod nested_tests_2",
1116                         },
1117                         kind: TestMod {
1118                             path: "root_tests::nested_tests_0::nested_tests_2",
1119                         },
1120                         cfg: None,
1121                     },
1122                     Runnable {
1123                         use_name_in_title: false,
1124                         nav: NavigationTarget {
1125                             file_id: FileId(
1126                                 0,
1127                             ),
1128                             full_range: 84..126,
1129                             focus_range: 107..121,
1130                             name: "nested_test_11",
1131                             kind: Function,
1132                         },
1133                         kind: Test {
1134                             test_id: Path(
1135                                 "root_tests::nested_tests_0::nested_tests_1::nested_test_11",
1136                             ),
1137                             attr: TestAttr {
1138                                 ignore: false,
1139                             },
1140                         },
1141                         cfg: None,
1142                     },
1143                     Runnable {
1144                         use_name_in_title: false,
1145                         nav: NavigationTarget {
1146                             file_id: FileId(
1147                                 0,
1148                             ),
1149                             full_range: 140..182,
1150                             focus_range: 163..177,
1151                             name: "nested_test_12",
1152                             kind: Function,
1153                         },
1154                         kind: Test {
1155                             test_id: Path(
1156                                 "root_tests::nested_tests_0::nested_tests_1::nested_test_12",
1157                             ),
1158                             attr: TestAttr {
1159                                 ignore: false,
1160                             },
1161                         },
1162                         cfg: None,
1163                     },
1164                     Runnable {
1165                         use_name_in_title: false,
1166                         nav: NavigationTarget {
1167                             file_id: FileId(
1168                                 0,
1169                             ),
1170                             full_range: 235..276,
1171                             focus_range: 258..271,
1172                             name: "nested_test_2",
1173                             kind: Function,
1174                         },
1175                         kind: Test {
1176                             test_id: Path(
1177                                 "root_tests::nested_tests_0::nested_tests_2::nested_test_2",
1178                             ),
1179                             attr: TestAttr {
1180                                 ignore: false,
1181                             },
1182                         },
1183                         cfg: None,
1184                     },
1185                 ]
1186             "#]],
1187         );
1188     }
1189
1190     #[test]
1191     fn test_runnables_with_feature() {
1192         check(
1193             r#"
1194 //- /lib.rs crate:foo cfg:feature=foo
1195 $0
1196 #[test]
1197 #[cfg(feature = "foo")]
1198 fn test_foo1() {}
1199 "#,
1200             &[Test, TestMod],
1201             expect![[r#"
1202                 [
1203                     Runnable {
1204                         use_name_in_title: false,
1205                         nav: NavigationTarget {
1206                             file_id: FileId(
1207                                 0,
1208                             ),
1209                             full_range: 1..50,
1210                             focus_range: 36..45,
1211                             name: "test_foo1",
1212                             kind: Function,
1213                         },
1214                         kind: Test {
1215                             test_id: Path(
1216                                 "test_foo1",
1217                             ),
1218                             attr: TestAttr {
1219                                 ignore: false,
1220                             },
1221                         },
1222                         cfg: Some(
1223                             Atom(
1224                                 KeyValue {
1225                                     key: "feature",
1226                                     value: "foo",
1227                                 },
1228                             ),
1229                         ),
1230                     },
1231                     Runnable {
1232                         use_name_in_title: false,
1233                         nav: NavigationTarget {
1234                             file_id: FileId(
1235                                 0,
1236                             ),
1237                             full_range: 0..51,
1238                             name: "",
1239                             kind: Module,
1240                         },
1241                         kind: TestMod {
1242                             path: "",
1243                         },
1244                         cfg: None,
1245                     },
1246                 ]
1247             "#]],
1248         );
1249     }
1250
1251     #[test]
1252     fn test_runnables_with_features() {
1253         check(
1254             r#"
1255 //- /lib.rs crate:foo cfg:feature=foo,feature=bar
1256 $0
1257 #[test]
1258 #[cfg(all(feature = "foo", feature = "bar"))]
1259 fn test_foo1() {}
1260 "#,
1261             &[Test, TestMod],
1262             expect![[r#"
1263                 [
1264                     Runnable {
1265                         use_name_in_title: false,
1266                         nav: NavigationTarget {
1267                             file_id: FileId(
1268                                 0,
1269                             ),
1270                             full_range: 1..72,
1271                             focus_range: 58..67,
1272                             name: "test_foo1",
1273                             kind: Function,
1274                         },
1275                         kind: Test {
1276                             test_id: Path(
1277                                 "test_foo1",
1278                             ),
1279                             attr: TestAttr {
1280                                 ignore: false,
1281                             },
1282                         },
1283                         cfg: Some(
1284                             All(
1285                                 [
1286                                     Atom(
1287                                         KeyValue {
1288                                             key: "feature",
1289                                             value: "foo",
1290                                         },
1291                                     ),
1292                                     Atom(
1293                                         KeyValue {
1294                                             key: "feature",
1295                                             value: "bar",
1296                                         },
1297                                     ),
1298                                 ],
1299                             ),
1300                         ),
1301                     },
1302                     Runnable {
1303                         use_name_in_title: false,
1304                         nav: NavigationTarget {
1305                             file_id: FileId(
1306                                 0,
1307                             ),
1308                             full_range: 0..73,
1309                             name: "",
1310                             kind: Module,
1311                         },
1312                         kind: TestMod {
1313                             path: "",
1314                         },
1315                         cfg: None,
1316                     },
1317                 ]
1318             "#]],
1319         );
1320     }
1321
1322     #[test]
1323     fn test_runnables_no_test_function_in_module() {
1324         check(
1325             r#"
1326 //- /lib.rs
1327 $0
1328 mod test_mod {
1329     fn foo1() {}
1330 }
1331 "#,
1332             &[],
1333             expect![[r#"
1334                 []
1335             "#]],
1336         );
1337     }
1338
1339     #[test]
1340     fn test_doc_runnables_impl_mod() {
1341         check(
1342             r#"
1343 //- /lib.rs
1344 mod foo;
1345 //- /foo.rs
1346 struct Foo;$0
1347 impl Foo {
1348     /// ```
1349     /// let x = 5;
1350     /// ```
1351     fn foo() {}
1352 }
1353         "#,
1354             &[DocTest],
1355             expect![[r#"
1356                 [
1357                     Runnable {
1358                         use_name_in_title: false,
1359                         nav: NavigationTarget {
1360                             file_id: FileId(
1361                                 1,
1362                             ),
1363                             full_range: 27..81,
1364                             name: "foo",
1365                         },
1366                         kind: DocTest {
1367                             test_id: Path(
1368                                 "\"foo::Foo::foo\"",
1369                             ),
1370                         },
1371                         cfg: None,
1372                     },
1373                 ]
1374             "#]],
1375         );
1376     }
1377
1378     #[test]
1379     fn test_runnables_in_macro() {
1380         check(
1381             r#"
1382 //- /lib.rs
1383 $0
1384 macro_rules! gen {
1385     () => {
1386         #[test]
1387         fn foo_test() {}
1388     }
1389 }
1390 macro_rules! gen2 {
1391     () => {
1392         mod tests2 {
1393             #[test]
1394             fn foo_test2() {}
1395         }
1396     }
1397 }
1398 mod tests {
1399     gen!();
1400 }
1401 gen2!();
1402 "#,
1403             &[TestMod, TestMod, TestMod, Test, Test],
1404             expect![[r#"
1405                 [
1406                     Runnable {
1407                         use_name_in_title: false,
1408                         nav: NavigationTarget {
1409                             file_id: FileId(
1410                                 0,
1411                             ),
1412                             full_range: 202..227,
1413                             focus_range: 206..211,
1414                             name: "tests",
1415                             kind: Module,
1416                             description: "mod tests",
1417                         },
1418                         kind: TestMod {
1419                             path: "tests",
1420                         },
1421                         cfg: None,
1422                     },
1423                     Runnable {
1424                         use_name_in_title: false,
1425                         nav: NavigationTarget {
1426                             file_id: FileId(
1427                                 0,
1428                             ),
1429                             full_range: 0..237,
1430                             name: "",
1431                             kind: Module,
1432                         },
1433                         kind: TestMod {
1434                             path: "",
1435                         },
1436                         cfg: None,
1437                     },
1438                     Runnable {
1439                         use_name_in_title: true,
1440                         nav: NavigationTarget {
1441                             file_id: FileId(
1442                                 0,
1443                             ),
1444                             full_range: 228..236,
1445                             name: "tests2",
1446                             kind: Module,
1447                             description: "mod tests2",
1448                         },
1449                         kind: TestMod {
1450                             path: "tests2",
1451                         },
1452                         cfg: None,
1453                     },
1454                     Runnable {
1455                         use_name_in_title: true,
1456                         nav: NavigationTarget {
1457                             file_id: FileId(
1458                                 0,
1459                             ),
1460                             full_range: 228..236,
1461                             name: "foo_test2",
1462                             kind: Function,
1463                         },
1464                         kind: Test {
1465                             test_id: Path(
1466                                 "tests2::foo_test2",
1467                             ),
1468                             attr: TestAttr {
1469                                 ignore: false,
1470                             },
1471                         },
1472                         cfg: None,
1473                     },
1474                     Runnable {
1475                         use_name_in_title: false,
1476                         nav: NavigationTarget {
1477                             file_id: FileId(
1478                                 0,
1479                             ),
1480                             full_range: 218..225,
1481                             name: "foo_test",
1482                             kind: Function,
1483                         },
1484                         kind: Test {
1485                             test_id: Path(
1486                                 "tests::foo_test",
1487                             ),
1488                             attr: TestAttr {
1489                                 ignore: false,
1490                             },
1491                         },
1492                         cfg: None,
1493                     },
1494                 ]
1495             "#]],
1496         );
1497     }
1498
1499     #[test]
1500     fn big_mac() {
1501         check(
1502             r#"
1503 //- /lib.rs
1504 $0
1505 macro_rules! foo {
1506     () => {
1507         mod foo_tests {
1508             #[test]
1509             fn foo0() {}
1510             #[test]
1511             fn foo1() {}
1512             #[test]
1513             fn foo2() {}
1514         }
1515     };
1516 }
1517 foo!();
1518 "#,
1519             &[TestMod, Test, Test, Test],
1520             expect![[r#"
1521                 [
1522                     Runnable {
1523                         use_name_in_title: true,
1524                         nav: NavigationTarget {
1525                             file_id: FileId(
1526                                 0,
1527                             ),
1528                             full_range: 210..217,
1529                             name: "foo_tests",
1530                             kind: Module,
1531                             description: "mod foo_tests",
1532                         },
1533                         kind: TestMod {
1534                             path: "foo_tests",
1535                         },
1536                         cfg: None,
1537                     },
1538                     Runnable {
1539                         use_name_in_title: true,
1540                         nav: NavigationTarget {
1541                             file_id: FileId(
1542                                 0,
1543                             ),
1544                             full_range: 210..217,
1545                             name: "foo0",
1546                             kind: Function,
1547                         },
1548                         kind: Test {
1549                             test_id: Path(
1550                                 "foo_tests::foo0",
1551                             ),
1552                             attr: TestAttr {
1553                                 ignore: false,
1554                             },
1555                         },
1556                         cfg: None,
1557                     },
1558                     Runnable {
1559                         use_name_in_title: true,
1560                         nav: NavigationTarget {
1561                             file_id: FileId(
1562                                 0,
1563                             ),
1564                             full_range: 210..217,
1565                             name: "foo1",
1566                             kind: Function,
1567                         },
1568                         kind: Test {
1569                             test_id: Path(
1570                                 "foo_tests::foo1",
1571                             ),
1572                             attr: TestAttr {
1573                                 ignore: false,
1574                             },
1575                         },
1576                         cfg: None,
1577                     },
1578                     Runnable {
1579                         use_name_in_title: true,
1580                         nav: NavigationTarget {
1581                             file_id: FileId(
1582                                 0,
1583                             ),
1584                             full_range: 210..217,
1585                             name: "foo2",
1586                             kind: Function,
1587                         },
1588                         kind: Test {
1589                             test_id: Path(
1590                                 "foo_tests::foo2",
1591                             ),
1592                             attr: TestAttr {
1593                                 ignore: false,
1594                             },
1595                         },
1596                         cfg: None,
1597                     },
1598                 ]
1599             "#]],
1600         );
1601     }
1602
1603     #[test]
1604     fn dont_recurse_in_outline_submodules() {
1605         check(
1606             r#"
1607 //- /lib.rs
1608 $0
1609 mod m;
1610 //- /m.rs
1611 mod tests {
1612     #[test]
1613     fn t() {}
1614 }
1615 "#,
1616             &[],
1617             expect![[r#"
1618                 []
1619             "#]],
1620         );
1621     }
1622
1623     #[test]
1624     fn outline_submodule1() {
1625         check(
1626             r#"
1627 //- /lib.rs
1628 $0
1629 mod m;
1630 //- /m.rs
1631 #[test]
1632 fn t0() {}
1633 #[test]
1634 fn t1() {}
1635 "#,
1636             &[TestMod],
1637             expect![[r#"
1638                 [
1639                     Runnable {
1640                         use_name_in_title: false,
1641                         nav: NavigationTarget {
1642                             file_id: FileId(
1643                                 0,
1644                             ),
1645                             full_range: 1..7,
1646                             focus_range: 5..6,
1647                             name: "m",
1648                             kind: Module,
1649                             description: "mod m",
1650                         },
1651                         kind: TestMod {
1652                             path: "m",
1653                         },
1654                         cfg: None,
1655                     },
1656                 ]
1657             "#]],
1658         );
1659     }
1660
1661     #[test]
1662     fn outline_submodule2() {
1663         check(
1664             r#"
1665 //- /lib.rs
1666 mod m;
1667 //- /m.rs
1668 $0
1669 #[test]
1670 fn t0() {}
1671 #[test]
1672 fn t1() {}
1673 "#,
1674             &[Test, Test, TestMod],
1675             expect![[r#"
1676                 [
1677                     Runnable {
1678                         use_name_in_title: false,
1679                         nav: NavigationTarget {
1680                             file_id: FileId(
1681                                 1,
1682                             ),
1683                             full_range: 1..19,
1684                             focus_range: 12..14,
1685                             name: "t0",
1686                             kind: Function,
1687                         },
1688                         kind: Test {
1689                             test_id: Path(
1690                                 "m::t0",
1691                             ),
1692                             attr: TestAttr {
1693                                 ignore: false,
1694                             },
1695                         },
1696                         cfg: None,
1697                     },
1698                     Runnable {
1699                         use_name_in_title: false,
1700                         nav: NavigationTarget {
1701                             file_id: FileId(
1702                                 1,
1703                             ),
1704                             full_range: 20..38,
1705                             focus_range: 31..33,
1706                             name: "t1",
1707                             kind: Function,
1708                         },
1709                         kind: Test {
1710                             test_id: Path(
1711                                 "m::t1",
1712                             ),
1713                             attr: TestAttr {
1714                                 ignore: false,
1715                             },
1716                         },
1717                         cfg: None,
1718                     },
1719                     Runnable {
1720                         use_name_in_title: false,
1721                         nav: NavigationTarget {
1722                             file_id: FileId(
1723                                 1,
1724                             ),
1725                             full_range: 0..39,
1726                             name: "m",
1727                             kind: Module,
1728                         },
1729                         kind: TestMod {
1730                             path: "m",
1731                         },
1732                         cfg: None,
1733                     },
1734                 ]
1735             "#]],
1736         );
1737     }
1738
1739     #[test]
1740     fn attributed_module() {
1741         check(
1742             r#"
1743 //- proc_macros: identity
1744 //- /lib.rs
1745 $0
1746 #[proc_macros::identity]
1747 mod module {
1748     #[test]
1749     fn t0() {}
1750     #[test]
1751     fn t1() {}
1752 }
1753 "#,
1754             &[TestMod, Test, Test],
1755             expect![[r#"
1756                 [
1757                     Runnable {
1758                         use_name_in_title: true,
1759                         nav: NavigationTarget {
1760                             file_id: FileId(
1761                                 0,
1762                             ),
1763                             full_range: 26..94,
1764                             focus_range: 30..36,
1765                             name: "module",
1766                             kind: Module,
1767                             description: "mod module",
1768                         },
1769                         kind: TestMod {
1770                             path: "module",
1771                         },
1772                         cfg: None,
1773                     },
1774                     Runnable {
1775                         use_name_in_title: true,
1776                         nav: NavigationTarget {
1777                             file_id: FileId(
1778                                 0,
1779                             ),
1780                             full_range: 43..65,
1781                             focus_range: 58..60,
1782                             name: "t0",
1783                             kind: Function,
1784                         },
1785                         kind: Test {
1786                             test_id: Path(
1787                                 "module::t0",
1788                             ),
1789                             attr: TestAttr {
1790                                 ignore: false,
1791                             },
1792                         },
1793                         cfg: None,
1794                     },
1795                     Runnable {
1796                         use_name_in_title: true,
1797                         nav: NavigationTarget {
1798                             file_id: FileId(
1799                                 0,
1800                             ),
1801                             full_range: 70..92,
1802                             focus_range: 85..87,
1803                             name: "t1",
1804                             kind: Function,
1805                         },
1806                         kind: Test {
1807                             test_id: Path(
1808                                 "module::t1",
1809                             ),
1810                             attr: TestAttr {
1811                                 ignore: false,
1812                             },
1813                         },
1814                         cfg: None,
1815                     },
1816                 ]
1817             "#]],
1818         );
1819     }
1820
1821     #[test]
1822     fn find_no_tests() {
1823         check_tests(
1824             r#"
1825 //- /lib.rs
1826 fn foo$0() {  };
1827 "#,
1828             expect![[r#"
1829                 []
1830             "#]],
1831         );
1832     }
1833
1834     #[test]
1835     fn find_direct_fn_test() {
1836         check_tests(
1837             r#"
1838 //- /lib.rs
1839 fn foo$0() { };
1840
1841 mod tests {
1842     #[test]
1843     fn foo_test() {
1844         super::foo()
1845     }
1846 }
1847 "#,
1848             expect![[r#"
1849                 [
1850                     Runnable {
1851                         use_name_in_title: false,
1852                         nav: NavigationTarget {
1853                             file_id: FileId(
1854                                 0,
1855                             ),
1856                             full_range: 31..85,
1857                             focus_range: 46..54,
1858                             name: "foo_test",
1859                             kind: Function,
1860                         },
1861                         kind: Test {
1862                             test_id: Path(
1863                                 "tests::foo_test",
1864                             ),
1865                             attr: TestAttr {
1866                                 ignore: false,
1867                             },
1868                         },
1869                         cfg: None,
1870                     },
1871                 ]
1872             "#]],
1873         );
1874     }
1875
1876     #[test]
1877     fn find_direct_struct_test() {
1878         check_tests(
1879             r#"
1880 //- /lib.rs
1881 struct Fo$0o;
1882 fn foo(arg: &Foo) { };
1883
1884 mod tests {
1885     use super::*;
1886
1887     #[test]
1888     fn foo_test() {
1889         foo(Foo);
1890     }
1891 }
1892 "#,
1893             expect![[r#"
1894                 [
1895                     Runnable {
1896                         use_name_in_title: false,
1897                         nav: NavigationTarget {
1898                             file_id: FileId(
1899                                 0,
1900                             ),
1901                             full_range: 71..122,
1902                             focus_range: 86..94,
1903                             name: "foo_test",
1904                             kind: Function,
1905                         },
1906                         kind: Test {
1907                             test_id: Path(
1908                                 "tests::foo_test",
1909                             ),
1910                             attr: TestAttr {
1911                                 ignore: false,
1912                             },
1913                         },
1914                         cfg: None,
1915                     },
1916                 ]
1917             "#]],
1918         );
1919     }
1920
1921     #[test]
1922     fn find_indirect_fn_test() {
1923         check_tests(
1924             r#"
1925 //- /lib.rs
1926 fn foo$0() { };
1927
1928 mod tests {
1929     use super::foo;
1930
1931     fn check1() {
1932         check2()
1933     }
1934
1935     fn check2() {
1936         foo()
1937     }
1938
1939     #[test]
1940     fn foo_test() {
1941         check1()
1942     }
1943 }
1944 "#,
1945             expect![[r#"
1946                 [
1947                     Runnable {
1948                         use_name_in_title: false,
1949                         nav: NavigationTarget {
1950                             file_id: FileId(
1951                                 0,
1952                             ),
1953                             full_range: 133..183,
1954                             focus_range: 148..156,
1955                             name: "foo_test",
1956                             kind: Function,
1957                         },
1958                         kind: Test {
1959                             test_id: Path(
1960                                 "tests::foo_test",
1961                             ),
1962                             attr: TestAttr {
1963                                 ignore: false,
1964                             },
1965                         },
1966                         cfg: None,
1967                     },
1968                 ]
1969             "#]],
1970         );
1971     }
1972
1973     #[test]
1974     fn tests_are_unique() {
1975         check_tests(
1976             r#"
1977 //- /lib.rs
1978 fn foo$0() { };
1979
1980 mod tests {
1981     use super::foo;
1982
1983     #[test]
1984     fn foo_test() {
1985         foo();
1986         foo();
1987     }
1988
1989     #[test]
1990     fn foo2_test() {
1991         foo();
1992         foo();
1993     }
1994
1995 }
1996 "#,
1997             expect![[r#"
1998                 [
1999                     Runnable {
2000                         use_name_in_title: false,
2001                         nav: NavigationTarget {
2002                             file_id: FileId(
2003                                 0,
2004                             ),
2005                             full_range: 52..115,
2006                             focus_range: 67..75,
2007                             name: "foo_test",
2008                             kind: Function,
2009                         },
2010                         kind: Test {
2011                             test_id: Path(
2012                                 "tests::foo_test",
2013                             ),
2014                             attr: TestAttr {
2015                                 ignore: false,
2016                             },
2017                         },
2018                         cfg: None,
2019                     },
2020                     Runnable {
2021                         use_name_in_title: false,
2022                         nav: NavigationTarget {
2023                             file_id: FileId(
2024                                 0,
2025                             ),
2026                             full_range: 121..185,
2027                             focus_range: 136..145,
2028                             name: "foo2_test",
2029                             kind: Function,
2030                         },
2031                         kind: Test {
2032                             test_id: Path(
2033                                 "tests::foo2_test",
2034                             ),
2035                             attr: TestAttr {
2036                                 ignore: false,
2037                             },
2038                         },
2039                         cfg: None,
2040                     },
2041                 ]
2042             "#]],
2043         );
2044     }
2045
2046     #[test]
2047     fn doc_test_type_params() {
2048         check(
2049             r#"
2050 //- /lib.rs
2051 $0
2052 struct Foo<T, U>;
2053
2054 impl<T, U> Foo<T, U> {
2055     /// ```rust
2056     /// ````
2057     fn t() {}
2058 }
2059 "#,
2060             &[DocTest],
2061             expect![[r#"
2062                 [
2063                     Runnable {
2064                         use_name_in_title: false,
2065                         nav: NavigationTarget {
2066                             file_id: FileId(
2067                                 0,
2068                             ),
2069                             full_range: 47..85,
2070                             name: "t",
2071                         },
2072                         kind: DocTest {
2073                             test_id: Path(
2074                                 "\"Foo<T, U>::t\"",
2075                             ),
2076                         },
2077                         cfg: None,
2078                     },
2079                 ]
2080             "#]],
2081         );
2082     }
2083
2084     #[test]
2085     fn doc_test_macro_export_mbe() {
2086         check(
2087             r#"
2088 //- /lib.rs
2089 $0
2090 mod foo;
2091
2092 //- /foo.rs
2093 /// ```
2094 /// fn foo() {
2095 /// }
2096 /// ```
2097 #[macro_export]
2098 macro_rules! foo {
2099     () => {
2100
2101     };
2102 }
2103 "#,
2104             &[],
2105             expect![[r#"
2106                 []
2107             "#]],
2108         );
2109         check(
2110             r#"
2111 //- /lib.rs
2112 $0
2113 /// ```
2114 /// fn foo() {
2115 /// }
2116 /// ```
2117 #[macro_export]
2118 macro_rules! foo {
2119     () => {
2120
2121     };
2122 }
2123 "#,
2124             &[DocTest],
2125             expect![[r#"
2126                 [
2127                     Runnable {
2128                         use_name_in_title: false,
2129                         nav: NavigationTarget {
2130                             file_id: FileId(
2131                                 0,
2132                             ),
2133                             full_range: 1..94,
2134                             name: "foo",
2135                         },
2136                         kind: DocTest {
2137                             test_id: Path(
2138                                 "foo",
2139                             ),
2140                         },
2141                         cfg: None,
2142                     },
2143                 ]
2144             "#]],
2145         );
2146     }
2147 }