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