use std::fmt;
-use ast::NameOwner;
+use ast::HasName;
use cfg::CfgExpr;
-use either::Either;
use hir::{AsAssocItem, HasAttrs, HasSource, HirDisplay, Semantics};
use ide_assists::utils::test_related_attribute;
use ide_db::{
base_db::{FilePosition, FileRange},
+ defs::Definition,
helpers::visit_file_defs,
search::SearchScope,
RootDatabase, SymbolKind,
};
use itertools::Itertools;
-use rustc_hash::FxHashSet;
-use stdx::always;
-use syntax::ast::{self, AstNode, AttrsOwner};
+use rustc_hash::{FxHashMap, FxHashSet};
+use stdx::{always, format_to};
+use syntax::{
+ ast::{self, AstNode, HasAttrs as _},
+ SmolStr, SyntaxNode,
+};
-use crate::{display::TryToNav, references, FileId, NavigationTarget};
+use crate::{references, FileId, NavigationTarget, ToNav, TryToNav};
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct Runnable {
+ pub use_name_in_title: bool,
pub nav: NavigationTarget,
pub kind: RunnableKind,
pub cfg: Option<CfgExpr>,
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum TestId {
- Name(String),
+ Name(SmolStr),
Path(String),
}
Bin,
}
-#[derive(Debug, Eq, PartialEq)]
-pub struct RunnableAction {
- pub run_title: &'static str,
- pub debugee: bool,
+#[cfg(test)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
+enum RunnableTestKind {
+ Test,
+ TestMod,
+ DocTest,
+ Bench,
+ Bin,
}
-const TEST: RunnableAction = RunnableAction { run_title: "▶\u{fe0e} Run Test", debugee: true };
-const TEST_MOD: RunnableAction =
- RunnableAction { run_title: "▶\u{fe0e} Run Tests", debugee: true };
-const DOCTEST: RunnableAction =
- RunnableAction { run_title: "▶\u{fe0e} Run Doctest", debugee: false };
-const BENCH: RunnableAction = RunnableAction { run_title: "▶\u{fe0e} Run Bench", debugee: true };
-const BIN: RunnableAction = RunnableAction { run_title: "▶\u{fe0e} Run", debugee: true };
-
impl Runnable {
// test package::module::testname
pub fn label(&self, target: Option<String>) -> String {
}
}
- pub fn action(&self) -> &'static RunnableAction {
+ pub fn title(&self) -> String {
+ let mut s = String::from("▶\u{fe0e} Run ");
+ if self.use_name_in_title {
+ format_to!(s, "{}", self.nav.name);
+ if !matches!(self.kind, RunnableKind::Bin) {
+ s.push(' ');
+ }
+ }
+ let suffix = match &self.kind {
+ RunnableKind::TestMod { .. } => "Tests",
+ RunnableKind::Test { .. } => "Test",
+ RunnableKind::DocTest { .. } => "Doctest",
+ RunnableKind::Bench { .. } => "Bench",
+ RunnableKind::Bin => return s,
+ };
+ s.push_str(suffix);
+ s
+ }
+
+ #[cfg(test)]
+ fn test_kind(&self) -> RunnableTestKind {
match &self.kind {
- RunnableKind::TestMod { .. } => &TEST_MOD,
- RunnableKind::Test { .. } => &TEST,
- RunnableKind::DocTest { .. } => &DOCTEST,
- RunnableKind::Bench { .. } => &BENCH,
- RunnableKind::Bin => &BIN,
+ RunnableKind::TestMod { .. } => RunnableTestKind::TestMod,
+ RunnableKind::Test { .. } => RunnableTestKind::Test,
+ RunnableKind::DocTest { .. } => RunnableTestKind::DocTest,
+ RunnableKind::Bench { .. } => RunnableTestKind::Bench,
+ RunnableKind::Bin => RunnableTestKind::Bin,
}
}
}
let sema = Semantics::new(db);
let mut res = Vec::new();
- let mut add_opt = |runnable: Option<Runnable>| {
+ // Record all runnables that come from macro expansions here instead.
+ // In case an expansion creates multiple runnables we want to name them to avoid emitting a bunch of equally named runnables.
+ let mut in_macro_expansion = FxHashMap::<hir::HirFileId, Vec<Runnable>>::default();
+ let mut add_opt = |runnable: Option<Runnable>, def| {
if let Some(runnable) = runnable.filter(|runnable| {
always!(
runnable.nav.file_id == file_id,
file_id
)
}) {
+ if let Some(def) = def {
+ let file_id = match def {
+ Definition::Module(it) => it.declaration_source(db).map(|src| src.file_id),
+ Definition::Function(it) => it.source(db).map(|src| src.file_id),
+ _ => None,
+ };
+ if let Some(file_id) = file_id.filter(|file| file.call_node(db).is_some()) {
+ in_macro_expansion.entry(file_id).or_default().push(runnable);
+ return;
+ }
+ }
res.push(runnable);
}
};
- visit_file_defs(&sema, file_id, &mut |def| match def {
- Either::Left(def) => {
- let runnable = match def {
- hir::ModuleDef::Module(it) => runnable_mod(&sema, it),
- hir::ModuleDef::Function(it) => runnable_fn(&sema, it),
- _ => None,
- };
- add_opt(runnable.or_else(|| module_def_doctest(&sema, def)));
- }
- Either::Right(impl_) => {
- add_opt(runnable_impl(&sema, &impl_));
- impl_
- .items(db)
- .into_iter()
- .map(|assoc| match assoc {
+ visit_file_defs(&sema, file_id, &mut |def| {
+ let runnable = match def {
+ Definition::Module(it) => runnable_mod(&sema, it),
+ Definition::Function(it) => runnable_fn(&sema, it),
+ Definition::SelfType(impl_) => runnable_impl(&sema, &impl_),
+ _ => None,
+ };
+ add_opt(runnable.or_else(|| module_def_doctest(sema.db, def)), Some(def));
+ if let Definition::SelfType(impl_) = def {
+ impl_.items(db).into_iter().for_each(|assoc| {
+ let runnable = match assoc {
hir::AssocItem::Function(it) => {
- runnable_fn(&sema, it).or_else(|| module_def_doctest(&sema, it.into()))
+ runnable_fn(&sema, it).or_else(|| module_def_doctest(sema.db, it.into()))
}
- hir::AssocItem::Const(it) => module_def_doctest(&sema, it.into()),
- hir::AssocItem::TypeAlias(it) => module_def_doctest(&sema, it.into()),
- })
- .for_each(|r| add_opt(r));
+ hir::AssocItem::Const(it) => module_def_doctest(sema.db, it.into()),
+ hir::AssocItem::TypeAlias(it) => module_def_doctest(sema.db, it.into()),
+ };
+ add_opt(runnable, Some(assoc.into()))
+ });
}
});
+
+ sema.to_module_defs(file_id)
+ .map(|it| runnable_mod_outline_definition(&sema, it))
+ .for_each(|it| add_opt(it, None));
+
+ res.extend(in_macro_expansion.into_iter().flat_map(|(_, runnables)| {
+ let use_name_in_title = runnables.len() != 1;
+ runnables.into_iter().map(move |mut r| {
+ r.use_name_in_title = use_name_in_title;
+ r
+ })
+ }));
res
}
) -> Vec<Runnable> {
let sema = Semantics::new(db);
let mut res: FxHashSet<Runnable> = FxHashSet::default();
+ let syntax = sema.parse(position.file_id).syntax().clone();
- find_related_tests(&sema, position, search_scope, &mut res);
+ find_related_tests(&sema, &syntax, position, search_scope, &mut res);
- res.into_iter().collect_vec()
+ res.into_iter().collect()
}
fn find_related_tests(
sema: &Semantics<RootDatabase>,
+ syntax: &SyntaxNode,
position: FilePosition,
search_scope: Option<SearchScope>,
tests: &mut FxHashSet<Runnable>,
) {
- if let Some(refs) = references::find_all_refs(sema, position, search_scope) {
- for (file_id, refs) in refs.references {
- let file = sema.parse(file_id);
- let file = file.syntax();
- let functions = refs.iter().filter_map(|(range, _)| {
- let token = file.token_at_offset(range.start()).next()?;
- let token = sema.descend_into_macros(token);
- token.ancestors().find_map(ast::Fn::cast)
- });
-
- for fn_def in functions {
+ let defs = references::find_defs(sema, syntax, position.offset);
+ for def in defs {
+ let defs = def
+ .usages(sema)
+ .set_scope(search_scope.clone())
+ .all()
+ .references
+ .into_values()
+ .flatten();
+ for ref_ in defs {
+ let name_ref = match ref_.name {
+ ast::NameLike::NameRef(name_ref) => name_ref,
+ _ => continue,
+ };
+ if let Some(fn_def) =
+ sema.ancestors_with_macros(name_ref.syntax().clone()).find_map(ast::Fn::cast)
+ {
if let Some(runnable) = as_test_runnable(sema, &fn_def) {
// direct test
tests.insert(runnable);
} else if let Some(module) = parent_test_module(sema, &fn_def) {
// indirect test
- find_related_tests_in_module(sema, &fn_def, &module, tests);
+ find_related_tests_in_module(sema, syntax, &fn_def, &module, tests);
}
}
}
fn find_related_tests_in_module(
sema: &Semantics<RootDatabase>,
+ syntax: &SyntaxNode,
fn_def: &ast::Fn,
parent_module: &hir::Module,
tests: &mut FxHashSet<Runnable>,
) {
- if let Some(fn_name) = fn_def.name() {
- let mod_source = parent_module.definition_source(sema.db);
- let range = match mod_source.value {
- hir::ModuleSource::Module(m) => m.syntax().text_range(),
- hir::ModuleSource::BlockExpr(b) => b.syntax().text_range(),
- hir::ModuleSource::SourceFile(f) => f.syntax().text_range(),
- };
+ let fn_name = match fn_def.name() {
+ Some(it) => it,
+ _ => return,
+ };
+ let mod_source = parent_module.definition_source(sema.db);
+ let range = match &mod_source.value {
+ hir::ModuleSource::Module(m) => m.syntax().text_range(),
+ hir::ModuleSource::BlockExpr(b) => b.syntax().text_range(),
+ hir::ModuleSource::SourceFile(f) => f.syntax().text_range(),
+ };
- let file_id = mod_source.file_id.original_file(sema.db);
- let mod_scope = SearchScope::file_range(FileRange { file_id, range });
- let fn_pos = FilePosition { file_id, offset: fn_name.syntax().text_range().start() };
- find_related_tests(sema, fn_pos, Some(mod_scope), tests)
- }
+ let file_id = mod_source.file_id.original_file(sema.db);
+ let mod_scope = SearchScope::file_range(FileRange { file_id, range });
+ let fn_pos = FilePosition { file_id, offset: fn_name.syntax().text_range().start() };
+ find_related_tests(sema, syntax, fn_pos, Some(mod_scope), tests)
}
fn as_test_runnable(sema: &Semantics<RootDatabase>, fn_def: &ast::Fn) -> Option<Runnable> {
pub(crate) fn runnable_fn(sema: &Semantics<RootDatabase>, def: hir::Function) -> Option<Runnable> {
let func = def.source(sema.db)?;
- let name_string = def.name(sema.db).to_string();
+ let name = def.name(sema.db).to_smol_str();
let root = def.module(sema.db).krate().root_module(sema.db);
- let kind = if name_string == "main" && def.module(sema.db) == root {
+ let kind = if name == "main" && def.module(sema.db) == root {
RunnableKind::Bin
} else {
- let canonical_path = {
- let def: hir::ModuleDef = def.into();
- def.canonical_path(sema.db)
+ let test_id = || {
+ let canonical_path = {
+ let def: hir::ModuleDef = def.into();
+ def.canonical_path(sema.db)
+ };
+ canonical_path.map(TestId::Path).unwrap_or(TestId::Name(name))
};
- let test_id = canonical_path.map(TestId::Path).unwrap_or(TestId::Name(name_string));
if test_related_attribute(&func.value).is_some() {
let attr = TestAttr::from_fn(&func.value);
- RunnableKind::Test { test_id, attr }
+ RunnableKind::Test { test_id: test_id(), attr }
} else if func.value.has_atom_attr("bench") {
- RunnableKind::Bench { test_id }
+ RunnableKind::Bench { test_id: test_id() }
} else {
return None;
}
let nav = NavigationTarget::from_named(
sema.db,
- func.as_ref().map(|it| it as &dyn ast::NameOwner),
+ func.as_ref().map(|it| it as &dyn ast::HasName),
SymbolKind::Function,
);
let cfg = def.attrs(sema.db).cfg();
- Some(Runnable { nav, kind, cfg })
+ Some(Runnable { use_name_in_title: false, nav, kind, cfg })
}
pub(crate) fn runnable_mod(sema: &Semantics<RootDatabase>, def: hir::Module) -> Option<Runnable> {
let attrs = def.attrs(sema.db);
let cfg = attrs.cfg();
let nav = NavigationTarget::from_module_to_decl(sema.db, def);
- Some(Runnable { nav, kind: RunnableKind::TestMod { path }, cfg })
+ Some(Runnable { use_name_in_title: false, nav, kind: RunnableKind::TestMod { path }, cfg })
}
pub(crate) fn runnable_impl(sema: &Semantics<RootDatabase>, def: &hir::Impl) -> Option<Runnable> {
};
let test_id = TestId::Path(format!("{}{}", adt_name, params));
- Some(Runnable { nav, kind: RunnableKind::DocTest { test_id }, cfg })
+ Some(Runnable { use_name_in_title: false, nav, kind: RunnableKind::DocTest { test_id }, cfg })
+}
+
+/// Creates a test mod runnable for outline modules at the top of their definition.
+fn runnable_mod_outline_definition(
+ sema: &Semantics<RootDatabase>,
+ def: hir::Module,
+) -> Option<Runnable> {
+ if !has_test_function_or_multiple_test_submodules(sema, &def) {
+ return None;
+ }
+ let path =
+ def.path_to_root(sema.db).into_iter().rev().filter_map(|it| it.name(sema.db)).join("::");
+
+ let attrs = def.attrs(sema.db);
+ let cfg = attrs.cfg();
+ match def.definition_source(sema.db).value {
+ hir::ModuleSource::SourceFile(_) => Some(Runnable {
+ use_name_in_title: false,
+ nav: def.to_nav(sema.db),
+ kind: RunnableKind::TestMod { path },
+ cfg,
+ }),
+ _ => None,
+ }
}
-fn module_def_doctest(sema: &Semantics<RootDatabase>, def: hir::ModuleDef) -> Option<Runnable> {
+fn module_def_doctest(db: &RootDatabase, def: Definition) -> Option<Runnable> {
let attrs = match def {
- hir::ModuleDef::Module(it) => it.attrs(sema.db),
- hir::ModuleDef::Function(it) => it.attrs(sema.db),
- hir::ModuleDef::Adt(it) => it.attrs(sema.db),
- hir::ModuleDef::Variant(it) => it.attrs(sema.db),
- hir::ModuleDef::Const(it) => it.attrs(sema.db),
- hir::ModuleDef::Static(it) => it.attrs(sema.db),
- hir::ModuleDef::Trait(it) => it.attrs(sema.db),
- hir::ModuleDef::TypeAlias(it) => it.attrs(sema.db),
- hir::ModuleDef::BuiltinType(_) => return None,
+ Definition::Module(it) => it.attrs(db),
+ Definition::Function(it) => it.attrs(db),
+ Definition::Adt(it) => it.attrs(db),
+ Definition::Variant(it) => it.attrs(db),
+ Definition::Const(it) => it.attrs(db),
+ Definition::Static(it) => it.attrs(db),
+ Definition::Trait(it) => it.attrs(db),
+ Definition::TypeAlias(it) => it.attrs(db),
+ Definition::Macro(it) => it.attrs(db),
+ Definition::SelfType(it) => it.attrs(db),
+ _ => return None,
};
if !has_runnable_doc_test(&attrs) {
return None;
}
- let def_name = def.name(sema.db).map(|it| it.to_string());
- let test_id = def
- .canonical_path(sema.db)
- // This probably belongs to canonical path?
- .map(|path| {
- let assoc_def = match def {
- hir::ModuleDef::Function(it) => it.as_assoc_item(sema.db),
- hir::ModuleDef::Const(it) => it.as_assoc_item(sema.db),
- hir::ModuleDef::TypeAlias(it) => it.as_assoc_item(sema.db),
- _ => None,
- };
- // FIXME: this also looks very wrong
- if let Some(assoc_def) = assoc_def {
- if let hir::AssocItemContainer::Impl(imp) = assoc_def.container(sema.db) {
- let ty = imp.self_ty(sema.db);
- if let Some(adt) = ty.as_adt() {
- let name = adt.name(sema.db);
- let idx = path.rfind(':').map_or(0, |idx| idx + 1);
- let (prefix, suffix) = path.split_at(idx);
- let mut ty_args = ty.type_arguments().peekable();
- let params = if ty_args.peek().is_some() {
- format!(
- "<{}>",
- ty_args.format_with(", ", |ty, cb| cb(&ty.display(sema.db)))
- )
- } else {
- String::new()
- };
- return format!("{}{}{}::{}", prefix, name, params, suffix);
+ let def_name = def.name(db)?;
+ let path = (|| {
+ let mut path = String::new();
+ def.canonical_module_path(db)?
+ .flat_map(|it| it.name(db))
+ .for_each(|name| format_to!(path, "{}::", name));
+ // This probably belongs to canonical_path?
+ if let Some(assoc_item) = def.as_assoc_item(db) {
+ if let hir::AssocItemContainer::Impl(imp) = assoc_item.container(db) {
+ let ty = imp.self_ty(db);
+ if let Some(adt) = ty.as_adt() {
+ let name = adt.name(db);
+ let mut ty_args = ty.type_arguments().peekable();
+ format_to!(path, "{}", name);
+ if ty_args.peek().is_some() {
+ format_to!(
+ path,
+ "<{}>",
+ ty_args.format_with(", ", |ty, cb| cb(&ty.display(db)))
+ );
}
+ format_to!(path, "::{}", def_name);
+ return Some(path);
}
}
- path
- })
- .map(TestId::Path)
- .or_else(|| def_name.clone().map(TestId::Name))?;
+ }
+ format_to!(path, "{}", def_name);
+ Some(path)
+ })();
+
+ let test_id = path.map_or_else(|| TestId::Name(def_name.to_smol_str()), TestId::Path);
let mut nav = match def {
- hir::ModuleDef::Module(def) => NavigationTarget::from_module_to_decl(sema.db, def),
- def => def.try_to_nav(sema.db)?,
+ Definition::Module(def) => NavigationTarget::from_module_to_decl(db, def),
+ def => def.try_to_nav(db)?,
};
nav.focus_range = None;
nav.description = None;
nav.docs = None;
nav.kind = None;
- let res = Runnable { nav, kind: RunnableKind::DocTest { test_id }, cfg: attrs.cfg() };
+ let res = Runnable {
+ use_name_in_title: false,
+ nav,
+ kind: RunnableKind::DocTest { test_id },
+ cfg: attrs.cfg(),
+ };
Some(res)
}
use crate::fixture;
- use super::*;
+ use super::{RunnableTestKind::*, *};
fn check(
ra_fixture: &str,
// FIXME: fold this into `expect` as well
- actions: &[&RunnableAction],
+ actions: &[RunnableTestKind],
expect: Expect,
) {
let (analysis, position) = fixture::position(ra_fixture);
expect.assert_debug_eq(&runnables);
assert_eq!(
actions,
- runnables.into_iter().map(|it| it.action()).collect::<Vec<_>>().as_slice()
+ runnables.into_iter().map(|it| it.test_kind()).collect::<Vec<_>>().as_slice()
);
}
fn main() {}
}
"#,
- &[&BIN, &TEST, &TEST, &BENCH],
+ &[Bin, Test, Test, Bench, TestMod],
expect![[r#"
[
Runnable {
+ use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
cfg: None,
},
Runnable {
+ use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
cfg: None,
},
Runnable {
+ use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
cfg: None,
},
Runnable {
+ use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
},
cfg: None,
},
+ Runnable {
+ use_name_in_title: false,
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 0..137,
+ name: "",
+ kind: Module,
+ },
+ kind: TestMod {
+ path: "",
+ },
+ cfg: None,
+ },
]
"#]],
);
/// ```
impl Test for StructWithRunnable {}
"#,
- &[&BIN, &DOCTEST, &DOCTEST, &DOCTEST, &DOCTEST, &DOCTEST, &DOCTEST, &DOCTEST, &DOCTEST],
+ &[Bin, DocTest, DocTest, DocTest, DocTest, DocTest, DocTest, DocTest, DocTest],
expect![[r#"
[
Runnable {
+ use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
cfg: None,
},
Runnable {
+ use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
cfg: None,
},
Runnable {
+ use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
cfg: None,
},
Runnable {
+ use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
cfg: None,
},
Runnable {
+ use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
cfg: None,
},
Runnable {
+ use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
cfg: None,
},
Runnable {
+ use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
cfg: None,
},
Runnable {
+ use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
cfg: None,
},
Runnable {
+ use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
fn foo() {}
}
"#,
- &[&BIN, &DOCTEST],
+ &[Bin, DocTest],
expect![[r#"
[
Runnable {
+ use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
cfg: None,
},
Runnable {
+ use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
fn test_foo1() {}
}
"#,
- &[&TEST_MOD, &TEST],
+ &[TestMod, Test],
expect![[r#"
[
Runnable {
+ use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
cfg: None,
},
Runnable {
+ use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
mod nested_tests_4 {}
}
"#,
- &[&TEST_MOD, &TEST_MOD, &TEST_MOD, &TEST, &TEST, &TEST],
+ &[TestMod, TestMod, TestMod, Test, Test, Test],
expect![[r#"
[
Runnable {
+ use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
cfg: None,
},
Runnable {
+ use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
cfg: None,
},
Runnable {
+ use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
cfg: None,
},
Runnable {
+ use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
cfg: None,
},
Runnable {
+ use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
cfg: None,
},
Runnable {
+ use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
#[cfg(feature = "foo")]
fn test_foo1() {}
"#,
- &[&TEST],
+ &[Test, TestMod],
expect![[r#"
[
Runnable {
+ use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
),
),
},
+ Runnable {
+ use_name_in_title: false,
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 0..51,
+ name: "",
+ kind: Module,
+ },
+ kind: TestMod {
+ path: "",
+ },
+ cfg: None,
+ },
]
"#]],
);
#[cfg(all(feature = "foo", feature = "bar"))]
fn test_foo1() {}
"#,
- &[&TEST],
+ &[Test, TestMod],
expect![[r#"
[
Runnable {
+ use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
),
),
},
+ Runnable {
+ use_name_in_title: false,
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 0..73,
+ name: "",
+ kind: Module,
+ },
+ kind: TestMod {
+ path: "",
+ },
+ cfg: None,
+ },
]
"#]],
);
fn foo() {}
}
"#,
- &[&DOCTEST],
+ &[DocTest],
expect![[r#"
[
Runnable {
+ use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
1,
}
macro_rules! gen2 {
() => {
- mod m_tests {
+ mod tests2 {
#[test]
- fn foo_test() {}
+ fn foo_test2() {}
}
}
}
}
gen2!();
"#,
- &[&TEST_MOD, &TEST_MOD, &TEST, &TEST],
+ &[TestMod, TestMod, TestMod, Test, Test],
expect![[r#"
[
Runnable {
+ use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
cfg: None,
},
Runnable {
+ use_name_in_title: false,
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 0..237,
+ name: "",
+ kind: Module,
+ },
+ kind: TestMod {
+ path: "",
+ },
+ cfg: None,
+ },
+ Runnable {
+ use_name_in_title: true,
nav: NavigationTarget {
file_id: FileId(
0,
),
full_range: 228..236,
focus_range: 228..236,
- name: "m_tests",
+ name: "tests2",
kind: Module,
- description: "mod m_tests",
+ description: "mod tests2",
},
kind: TestMod {
- path: "m_tests",
+ path: "tests2",
+ },
+ cfg: None,
+ },
+ Runnable {
+ use_name_in_title: true,
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 228..236,
+ name: "foo_test2",
+ kind: Function,
+ },
+ kind: Test {
+ test_id: Path(
+ "tests2::foo_test2",
+ ),
+ attr: TestAttr {
+ ignore: false,
+ },
},
cfg: None,
},
Runnable {
+ use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
),
full_range: 218..225,
- focus_range: 218..225,
name: "foo_test",
kind: Function,
},
},
cfg: None,
},
+ ]
+ "#]],
+ );
+ }
+
+ #[test]
+ fn big_mac() {
+ check(
+ r#"
+//- /lib.rs
+$0
+macro_rules! foo {
+ () => {
+ mod foo_tests {
+ #[test]
+ fn foo0() {}
+ #[test]
+ fn foo1() {}
+ #[test]
+ fn foo2() {}
+ }
+ };
+}
+foo!();
+"#,
+ &[TestMod, Test, Test, Test],
+ expect![[r#"
+ [
+ Runnable {
+ use_name_in_title: true,
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 210..217,
+ focus_range: 210..217,
+ name: "foo_tests",
+ kind: Module,
+ description: "mod foo_tests",
+ },
+ kind: TestMod {
+ path: "foo_tests",
+ },
+ cfg: None,
+ },
Runnable {
+ use_name_in_title: true,
nav: NavigationTarget {
file_id: FileId(
0,
),
- full_range: 228..236,
- focus_range: 228..236,
- name: "foo_test",
+ full_range: 210..217,
+ name: "foo0",
kind: Function,
},
kind: Test {
test_id: Path(
- "m_tests::foo_test",
+ "foo_tests::foo0",
+ ),
+ attr: TestAttr {
+ ignore: false,
+ },
+ },
+ cfg: None,
+ },
+ Runnable {
+ use_name_in_title: true,
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 210..217,
+ name: "foo1",
+ kind: Function,
+ },
+ kind: Test {
+ test_id: Path(
+ "foo_tests::foo1",
+ ),
+ attr: TestAttr {
+ ignore: false,
+ },
+ },
+ cfg: None,
+ },
+ Runnable {
+ use_name_in_title: true,
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 210..217,
+ name: "foo2",
+ kind: Function,
+ },
+ kind: Test {
+ test_id: Path(
+ "foo_tests::foo2",
),
attr: TestAttr {
ignore: false,
#[test]
fn t1() {}
"#,
- &[&TEST_MOD],
+ &[TestMod],
expect![[r#"
[
Runnable {
+ use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
#[test]
fn t1() {}
"#,
- &[&TEST, &TEST],
+ &[Test, Test, TestMod],
expect![[r#"
[
Runnable {
+ use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
1,
cfg: None,
},
Runnable {
+ use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
1,
},
cfg: None,
},
+ Runnable {
+ use_name_in_title: false,
+ nav: NavigationTarget {
+ file_id: FileId(
+ 1,
+ ),
+ full_range: 0..39,
+ name: "m",
+ kind: Module,
+ },
+ kind: TestMod {
+ path: "m",
+ },
+ cfg: None,
+ },
+ ]
+ "#]],
+ );
+ }
+
+ #[test]
+ fn attributed_module() {
+ check(
+ r#"
+//- proc_macros: identity
+//- /lib.rs
+$0
+#[proc_macros::identity]
+mod module {
+ #[test]
+ fn t0() {}
+ #[test]
+ fn t1() {}
+}
+"#,
+ &[TestMod, Test, Test],
+ expect![[r#"
+ [
+ Runnable {
+ use_name_in_title: true,
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 26..94,
+ focus_range: 30..36,
+ name: "module",
+ kind: Module,
+ description: "mod module",
+ },
+ kind: TestMod {
+ path: "module",
+ },
+ cfg: None,
+ },
+ Runnable {
+ use_name_in_title: true,
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 43..65,
+ focus_range: 58..60,
+ name: "t0",
+ kind: Function,
+ },
+ kind: Test {
+ test_id: Path(
+ "module::t0",
+ ),
+ attr: TestAttr {
+ ignore: false,
+ },
+ },
+ cfg: None,
+ },
+ Runnable {
+ use_name_in_title: true,
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 70..92,
+ focus_range: 85..87,
+ name: "t1",
+ kind: Function,
+ },
+ kind: Test {
+ test_id: Path(
+ "module::t1",
+ ),
+ attr: TestAttr {
+ ignore: false,
+ },
+ },
+ cfg: None,
+ },
]
"#]],
);
expect![[r#"
[
Runnable {
+ use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
}
"#,
expect![[r#"
- [
- Runnable {
- nav: NavigationTarget {
- file_id: FileId(
- 0,
- ),
- full_range: 71..122,
- focus_range: 86..94,
- name: "foo_test",
- kind: Function,
- },
- kind: Test {
- test_id: Path(
- "tests::foo_test",
- ),
- attr: TestAttr {
- ignore: false,
+ [
+ Runnable {
+ use_name_in_title: false,
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 71..122,
+ focus_range: 86..94,
+ name: "foo_test",
+ kind: Function,
},
+ kind: Test {
+ test_id: Path(
+ "tests::foo_test",
+ ),
+ attr: TestAttr {
+ ignore: false,
+ },
+ },
+ cfg: None,
},
- cfg: None,
- },
- ]
+ ]
"#]],
);
}
expect![[r#"
[
Runnable {
+ use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
}
"#,
expect![[r#"
- [
- Runnable {
- nav: NavigationTarget {
- file_id: FileId(
- 0,
- ),
- full_range: 52..115,
- focus_range: 67..75,
- name: "foo_test",
- kind: Function,
- },
- kind: Test {
- test_id: Path(
- "tests::foo_test",
- ),
- attr: TestAttr {
- ignore: false,
+ [
+ Runnable {
+ use_name_in_title: false,
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 52..115,
+ focus_range: 67..75,
+ name: "foo_test",
+ kind: Function,
},
+ kind: Test {
+ test_id: Path(
+ "tests::foo_test",
+ ),
+ attr: TestAttr {
+ ignore: false,
+ },
+ },
+ cfg: None,
},
- cfg: None,
- },
- Runnable {
- nav: NavigationTarget {
- file_id: FileId(
- 0,
- ),
- full_range: 121..185,
- focus_range: 136..145,
- name: "foo2_test",
- kind: Function,
- },
- kind: Test {
- test_id: Path(
- "tests::foo2_test",
- ),
- attr: TestAttr {
- ignore: false,
+ Runnable {
+ use_name_in_title: false,
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 121..185,
+ focus_range: 136..145,
+ name: "foo2_test",
+ kind: Function,
},
+ kind: Test {
+ test_id: Path(
+ "tests::foo2_test",
+ ),
+ attr: TestAttr {
+ ignore: false,
+ },
+ },
+ cfg: None,
},
- cfg: None,
- },
- ]
+ ]
"#]],
);
}
fn t() {}
}
"#,
- &[&DOCTEST],
+ &[DocTest],
expect![[r#"
[
Runnable {
+ use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,