aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKirill Bulatov <[email protected]>2020-02-14 23:06:14 +0000
committerKirill Bulatov <[email protected]>2020-02-14 23:06:14 +0000
commit426c0f26fe90e7d4fcf5950e217a64843e651fe9 (patch)
tree27cb96ad44bf04a00b249bab75f76b3f5792b154
parent9ba801befd70892bf40429512e890389171aa59f (diff)
If possible, use --exact flag when running tests
-rw-r--r--crates/ra_ide/src/lib.rs2
-rw-r--r--crates/ra_ide/src/runnables.rs111
-rw-r--r--crates/ra_lsp_server/src/cargo_target_spec.rs16
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs4
4 files changed, 101 insertions, 32 deletions
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs
index 689921f3f..9d66c365b 100644
--- a/crates/ra_ide/src/lib.rs
+++ b/crates/ra_ide/src/lib.rs
@@ -71,7 +71,7 @@ pub use crate::{
71 references::{ 71 references::{
72 Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult, SearchScope, 72 Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult, SearchScope,
73 }, 73 },
74 runnables::{Runnable, RunnableKind}, 74 runnables::{Runnable, RunnableKind, TestId},
75 source_change::{FileSystemEdit, SourceChange, SourceFileEdit}, 75 source_change::{FileSystemEdit, SourceChange, SourceFileEdit},
76 syntax_highlighting::HighlightedRange, 76 syntax_highlighting::HighlightedRange,
77}; 77};
diff --git a/crates/ra_ide/src/runnables.rs b/crates/ra_ide/src/runnables.rs
index b6b0c70f9..863b85591 100644
--- a/crates/ra_ide/src/runnables.rs
+++ b/crates/ra_ide/src/runnables.rs
@@ -1,6 +1,6 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir::InFile; 3use hir::{InFile, SourceBinder};
4use itertools::Itertools; 4use itertools::Itertools;
5use ra_db::SourceDatabase; 5use ra_db::SourceDatabase;
6use ra_ide_db::RootDatabase; 6use ra_ide_db::RootDatabase;
@@ -10,6 +10,7 @@ use ra_syntax::{
10}; 10};
11 11
12use crate::FileId; 12use crate::FileId;
13use std::fmt::Display;
13 14
14#[derive(Debug)] 15#[derive(Debug)]
15pub struct Runnable { 16pub struct Runnable {
@@ -18,38 +19,86 @@ pub struct Runnable {
18} 19}
19 20
20#[derive(Debug)] 21#[derive(Debug)]
22pub enum TestId {
23 Name(String),
24 Path(String),
25}
26
27impl Display for TestId {
28 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
29 match self {
30 TestId::Name(name) => write!(f, "{}", name),
31 TestId::Path(path) => write!(f, "{}", path),
32 }
33 }
34}
35
36#[derive(Debug)]
21pub enum RunnableKind { 37pub enum RunnableKind {
22 Test { name: String }, 38 Test { test_id: TestId },
23 TestMod { path: String }, 39 TestMod { path: String },
24 Bench { name: String }, 40 Bench { test_id: TestId },
25 Bin, 41 Bin,
26} 42}
27 43
28pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> { 44pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> {
29 let parse = db.parse(file_id); 45 let parse = db.parse(file_id);
30 parse.tree().syntax().descendants().filter_map(|i| runnable(db, file_id, i)).collect() 46 let mut sb = SourceBinder::new(db);
47 parse.tree().syntax().descendants().filter_map(|i| runnable(db, &mut sb, file_id, i)).collect()
31} 48}
32 49
33fn runnable(db: &RootDatabase, file_id: FileId, item: SyntaxNode) -> Option<Runnable> { 50fn runnable(
51 db: &RootDatabase,
52 source_binder: &mut SourceBinder<RootDatabase>,
53 file_id: FileId,
54 item: SyntaxNode,
55) -> Option<Runnable> {
34 match_ast! { 56 match_ast! {
35 match item { 57 match item {
36 ast::FnDef(it) => { runnable_fn(it) }, 58 ast::FnDef(it) => { runnable_fn(db, source_binder, file_id, it) },
37 ast::Module(it) => { runnable_mod(db, file_id, it) }, 59 ast::Module(it) => { runnable_mod(db, source_binder, file_id, it) },
38 _ => { None }, 60 _ => { None },
39 } 61 }
40 } 62 }
41} 63}
42 64
43fn runnable_fn(fn_def: ast::FnDef) -> Option<Runnable> { 65fn runnable_fn(
44 let name = fn_def.name()?.text().clone(); 66 db: &RootDatabase,
45 let kind = if name == "main" { 67 source_binder: &mut SourceBinder<RootDatabase>,
68 file_id: FileId,
69 fn_def: ast::FnDef,
70) -> Option<Runnable> {
71 let name_string = fn_def.name()?.text().to_string();
72
73 let kind = if name_string == "main" {
46 RunnableKind::Bin 74 RunnableKind::Bin
47 } else if has_test_related_attribute(&fn_def) {
48 RunnableKind::Test { name: name.to_string() }
49 } else if fn_def.has_atom_attr("bench") {
50 RunnableKind::Bench { name: name.to_string() }
51 } else { 75 } else {
52 return None; 76 let test_id = if let Some(module) = fn_def
77 .syntax()
78 .ancestors()
79 .find_map(ast::Module::cast)
80 .and_then(|module| source_binder.to_def(InFile::new(file_id.into(), module)))
81 {
82 let path = module
83 .path_to_root(db)
84 .into_iter()
85 .rev()
86 .filter_map(|it| it.name(db))
87 .map(|name| name.to_string())
88 .chain(std::iter::once(name_string))
89 .join("::");
90 TestId::Path(path)
91 } else {
92 TestId::Name(name_string)
93 };
94
95 if has_test_related_attribute(&fn_def) {
96 RunnableKind::Test { test_id }
97 } else if fn_def.has_atom_attr("bench") {
98 RunnableKind::Bench { test_id }
99 } else {
100 return None;
101 }
53 }; 102 };
54 Some(Runnable { range: fn_def.syntax().text_range(), kind }) 103 Some(Runnable { range: fn_def.syntax().text_range(), kind })
55} 104}
@@ -68,7 +117,12 @@ fn has_test_related_attribute(fn_def: &ast::FnDef) -> bool {
68 .any(|attribute_text| attribute_text.contains("test")) 117 .any(|attribute_text| attribute_text.contains("test"))
69} 118}
70 119
71fn runnable_mod(db: &RootDatabase, file_id: FileId, module: ast::Module) -> Option<Runnable> { 120fn runnable_mod(
121 db: &RootDatabase,
122 source_binder: &mut SourceBinder<RootDatabase>,
123 file_id: FileId,
124 module: ast::Module,
125) -> Option<Runnable> {
72 let has_test_function = module 126 let has_test_function = module
73 .item_list()? 127 .item_list()?
74 .items() 128 .items()
@@ -76,13 +130,12 @@ fn runnable_mod(db: &RootDatabase, file_id: FileId, module: ast::Module) -> Opti
76 ast::ModuleItem::FnDef(it) => Some(it), 130 ast::ModuleItem::FnDef(it) => Some(it),
77 _ => None, 131 _ => None,
78 }) 132 })
79 .any(|f| f.has_atom_attr("test")); 133 .any(|f| has_test_related_attribute(&f));
80 if !has_test_function { 134 if !has_test_function {
81 return None; 135 return None;
82 } 136 }
83 let range = module.syntax().text_range(); 137 let range = module.syntax().text_range();
84 let mut sb = hir::SourceBinder::new(db); 138 let module = source_binder.to_def(InFile::new(file_id.into(), module))?;
85 let module = sb.to_def(InFile::new(file_id.into(), module))?;
86 139
87 let path = module.path_to_root(db).into_iter().rev().filter_map(|it| it.name(db)).join("::"); 140 let path = module.path_to_root(db).into_iter().rev().filter_map(|it| it.name(db)).join("::");
88 Some(Runnable { range, kind: RunnableKind::TestMod { path } }) 141 Some(Runnable { range, kind: RunnableKind::TestMod { path } })
@@ -121,13 +174,17 @@ mod tests {
121 Runnable { 174 Runnable {
122 range: [22; 46), 175 range: [22; 46),
123 kind: Test { 176 kind: Test {
124 name: "test_foo", 177 test_id: Name(
178 "test_foo",
179 ),
125 }, 180 },
126 }, 181 },
127 Runnable { 182 Runnable {
128 range: [47; 81), 183 range: [47; 81),
129 kind: Test { 184 kind: Test {
130 name: "test_foo", 185 test_id: Name(
186 "test_foo",
187 ),
131 }, 188 },
132 }, 189 },
133 ] 190 ]
@@ -160,7 +217,9 @@ mod tests {
160 Runnable { 217 Runnable {
161 range: [28; 57), 218 range: [28; 57),
162 kind: Test { 219 kind: Test {
163 name: "test_foo1", 220 test_id: Path(
221 "test_mod::test_foo1",
222 ),
164 }, 223 },
165 }, 224 },
166 ] 225 ]
@@ -195,7 +254,9 @@ mod tests {
195 Runnable { 254 Runnable {
196 range: [46; 79), 255 range: [46; 79),
197 kind: Test { 256 kind: Test {
198 name: "test_foo1", 257 test_id: Path(
258 "foo::test_mod::test_foo1",
259 ),
199 }, 260 },
200 }, 261 },
201 ] 262 ]
@@ -232,7 +293,9 @@ mod tests {
232 Runnable { 293 Runnable {
233 range: [68; 105), 294 range: [68; 105),
234 kind: Test { 295 kind: Test {
235 name: "test_foo1", 296 test_id: Path(
297 "foo::bar::test_mod::test_foo1",
298 ),
236 }, 299 },
237 }, 300 },
238 ] 301 ]
diff --git a/crates/ra_lsp_server/src/cargo_target_spec.rs b/crates/ra_lsp_server/src/cargo_target_spec.rs
index 594caffe2..5fd1e7b6b 100644
--- a/crates/ra_lsp_server/src/cargo_target_spec.rs
+++ b/crates/ra_lsp_server/src/cargo_target_spec.rs
@@ -1,6 +1,6 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use ra_ide::{FileId, RunnableKind}; 3use ra_ide::{FileId, RunnableKind, TestId};
4use ra_project_model::{self, ProjectWorkspace, TargetKind}; 4use ra_project_model::{self, ProjectWorkspace, TargetKind};
5 5
6use crate::{world::WorldSnapshot, Result}; 6use crate::{world::WorldSnapshot, Result};
@@ -13,13 +13,16 @@ pub(crate) fn runnable_args(
13 let spec = CargoTargetSpec::for_file(world, file_id)?; 13 let spec = CargoTargetSpec::for_file(world, file_id)?;
14 let mut res = Vec::new(); 14 let mut res = Vec::new();
15 match kind { 15 match kind {
16 RunnableKind::Test { name } => { 16 RunnableKind::Test { test_id } => {
17 res.push("test".to_string()); 17 res.push("test".to_string());
18 if let Some(spec) = spec { 18 if let Some(spec) = spec {
19 spec.push_to(&mut res); 19 spec.push_to(&mut res);
20 } 20 }
21 res.push("--".to_string()); 21 res.push("--".to_string());
22 res.push(name.to_string()); 22 res.push(test_id.to_string());
23 if let TestId::Path(_) = test_id {
24 res.push("--exact".to_string());
25 }
23 res.push("--nocapture".to_string()); 26 res.push("--nocapture".to_string());
24 } 27 }
25 RunnableKind::TestMod { path } => { 28 RunnableKind::TestMod { path } => {
@@ -31,13 +34,16 @@ pub(crate) fn runnable_args(
31 res.push(path.to_string()); 34 res.push(path.to_string());
32 res.push("--nocapture".to_string()); 35 res.push("--nocapture".to_string());
33 } 36 }
34 RunnableKind::Bench { name } => { 37 RunnableKind::Bench { test_id } => {
35 res.push("bench".to_string()); 38 res.push("bench".to_string());
36 if let Some(spec) = spec { 39 if let Some(spec) = spec {
37 spec.push_to(&mut res); 40 spec.push_to(&mut res);
38 } 41 }
39 res.push("--".to_string()); 42 res.push("--".to_string());
40 res.push(name.to_string()); 43 res.push(test_id.to_string());
44 if let TestId::Path(_) = test_id {
45 res.push("--exact".to_string());
46 }
41 res.push("--nocapture".to_string()); 47 res.push("--nocapture".to_string());
42 } 48 }
43 RunnableKind::Bin => { 49 RunnableKind::Bin => {
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index 2e598fdcd..5879a1f7a 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -918,9 +918,9 @@ fn to_lsp_runnable(
918 let args = runnable_args(world, file_id, &runnable.kind)?; 918 let args = runnable_args(world, file_id, &runnable.kind)?;
919 let line_index = world.analysis().file_line_index(file_id)?; 919 let line_index = world.analysis().file_line_index(file_id)?;
920 let label = match &runnable.kind { 920 let label = match &runnable.kind {
921 RunnableKind::Test { name } => format!("test {}", name), 921 RunnableKind::Test { test_id } => format!("test {}", test_id),
922 RunnableKind::TestMod { path } => format!("test-mod {}", path), 922 RunnableKind::TestMod { path } => format!("test-mod {}", path),
923 RunnableKind::Bench { name } => format!("bench {}", name), 923 RunnableKind::Bench { test_id } => format!("bench {}", test_id),
924 RunnableKind::Bin => "run binary".to_string(), 924 RunnableKind::Bin => "run binary".to_string(),
925 }; 925 };
926 Ok(req::Runnable { 926 Ok(req::Runnable {