mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 13:33:31 +00:00
add doctest support #4317
Signed-off-by: Benjamin Coenen <5719034+bnjjj@users.noreply.github.com>
This commit is contained in:
parent
15de338703
commit
fe52f8f028
3 changed files with 65 additions and 6 deletions
|
@ -9,6 +9,7 @@ use ra_syntax::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::FileId;
|
use crate::FileId;
|
||||||
|
use ast::DocCommentsOwner;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -37,6 +38,7 @@ pub enum RunnableKind {
|
||||||
Test { test_id: TestId, attr: TestAttr },
|
Test { test_id: TestId, attr: TestAttr },
|
||||||
TestMod { path: String },
|
TestMod { path: String },
|
||||||
Bench { test_id: TestId },
|
Bench { test_id: TestId },
|
||||||
|
DocTest { test_id: TestId },
|
||||||
Bin,
|
Bin,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,6 +83,8 @@ fn runnable_fn(sema: &Semantics<RootDatabase>, fn_def: ast::FnDef) -> Option<Run
|
||||||
RunnableKind::Test { test_id, attr }
|
RunnableKind::Test { test_id, attr }
|
||||||
} else if fn_def.has_atom_attr("bench") {
|
} else if fn_def.has_atom_attr("bench") {
|
||||||
RunnableKind::Bench { test_id }
|
RunnableKind::Bench { test_id }
|
||||||
|
} else if has_doc_test(&fn_def) {
|
||||||
|
RunnableKind::DocTest { test_id }
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -117,6 +121,10 @@ fn has_test_related_attribute(fn_def: &ast::FnDef) -> bool {
|
||||||
.any(|attribute_text| attribute_text.contains("test"))
|
.any(|attribute_text| attribute_text.contains("test"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn has_doc_test(fn_def: &ast::FnDef) -> bool {
|
||||||
|
fn_def.doc_comment_text().map_or(false, |comment| comment.contains("```"))
|
||||||
|
}
|
||||||
|
|
||||||
fn runnable_mod(sema: &Semantics<RootDatabase>, module: ast::Module) -> Option<Runnable> {
|
fn runnable_mod(sema: &Semantics<RootDatabase>, module: ast::Module) -> Option<Runnable> {
|
||||||
let has_test_function = module
|
let has_test_function = module
|
||||||
.item_list()?
|
.item_list()?
|
||||||
|
@ -194,6 +202,41 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_runnables_doc_test() {
|
||||||
|
let (analysis, pos) = analysis_and_position(
|
||||||
|
r#"
|
||||||
|
//- /lib.rs
|
||||||
|
<|> //empty
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
/// ```
|
||||||
|
/// let x = 5;
|
||||||
|
/// ```
|
||||||
|
fn foo() {}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
let runnables = analysis.runnables(pos.file_id).unwrap();
|
||||||
|
assert_debug_snapshot!(&runnables,
|
||||||
|
@r###"
|
||||||
|
[
|
||||||
|
Runnable {
|
||||||
|
range: 1..21,
|
||||||
|
kind: Bin,
|
||||||
|
},
|
||||||
|
Runnable {
|
||||||
|
range: 22..64,
|
||||||
|
kind: DocTest {
|
||||||
|
test_id: Path(
|
||||||
|
"foo",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_runnables_module() {
|
fn test_runnables_module() {
|
||||||
let (analysis, pos) = analysis_and_position(
|
let (analysis, pos) = analysis_and_position(
|
||||||
|
|
|
@ -27,7 +27,7 @@ impl CargoTargetSpec {
|
||||||
RunnableKind::Test { test_id, attr } => {
|
RunnableKind::Test { test_id, attr } => {
|
||||||
args.push("test".to_string());
|
args.push("test".to_string());
|
||||||
if let Some(spec) = spec {
|
if let Some(spec) = spec {
|
||||||
spec.push_to(&mut args);
|
spec.push_to(&mut args, kind);
|
||||||
}
|
}
|
||||||
extra_args.push(test_id.to_string());
|
extra_args.push(test_id.to_string());
|
||||||
if let TestId::Path(_) = test_id {
|
if let TestId::Path(_) = test_id {
|
||||||
|
@ -35,13 +35,13 @@ impl CargoTargetSpec {
|
||||||
}
|
}
|
||||||
extra_args.push("--nocapture".to_string());
|
extra_args.push("--nocapture".to_string());
|
||||||
if attr.ignore {
|
if attr.ignore {
|
||||||
extra_args.push("--ignored".to_string())
|
extra_args.push("--ignored".to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RunnableKind::TestMod { path } => {
|
RunnableKind::TestMod { path } => {
|
||||||
args.push("test".to_string());
|
args.push("test".to_string());
|
||||||
if let Some(spec) = spec {
|
if let Some(spec) = spec {
|
||||||
spec.push_to(&mut args);
|
spec.push_to(&mut args, kind);
|
||||||
}
|
}
|
||||||
extra_args.push(path.to_string());
|
extra_args.push(path.to_string());
|
||||||
extra_args.push("--nocapture".to_string());
|
extra_args.push("--nocapture".to_string());
|
||||||
|
@ -49,7 +49,7 @@ impl CargoTargetSpec {
|
||||||
RunnableKind::Bench { test_id } => {
|
RunnableKind::Bench { test_id } => {
|
||||||
args.push("bench".to_string());
|
args.push("bench".to_string());
|
||||||
if let Some(spec) = spec {
|
if let Some(spec) = spec {
|
||||||
spec.push_to(&mut args);
|
spec.push_to(&mut args, kind);
|
||||||
}
|
}
|
||||||
extra_args.push(test_id.to_string());
|
extra_args.push(test_id.to_string());
|
||||||
if let TestId::Path(_) = test_id {
|
if let TestId::Path(_) = test_id {
|
||||||
|
@ -57,10 +57,19 @@ impl CargoTargetSpec {
|
||||||
}
|
}
|
||||||
extra_args.push("--nocapture".to_string());
|
extra_args.push("--nocapture".to_string());
|
||||||
}
|
}
|
||||||
|
RunnableKind::DocTest { test_id } => {
|
||||||
|
args.push("test".to_string());
|
||||||
|
args.push("--doc".to_string());
|
||||||
|
if let Some(spec) = spec {
|
||||||
|
spec.push_to(&mut args, kind);
|
||||||
|
}
|
||||||
|
extra_args.push(test_id.to_string());
|
||||||
|
extra_args.push("--nocapture".to_string());
|
||||||
|
}
|
||||||
RunnableKind::Bin => {
|
RunnableKind::Bin => {
|
||||||
args.push("run".to_string());
|
args.push("run".to_string());
|
||||||
if let Some(spec) = spec {
|
if let Some(spec) = spec {
|
||||||
spec.push_to(&mut args);
|
spec.push_to(&mut args, kind);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,9 +100,14 @@ impl CargoTargetSpec {
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn push_to(self, buf: &mut Vec<String>) {
|
pub(crate) fn push_to(self, buf: &mut Vec<String>, kind: &RunnableKind) {
|
||||||
buf.push("--package".to_string());
|
buf.push("--package".to_string());
|
||||||
buf.push(self.package);
|
buf.push(self.package);
|
||||||
|
|
||||||
|
// Can't mix --doc with other target flags
|
||||||
|
if let RunnableKind::DocTest { .. } = kind {
|
||||||
|
return;
|
||||||
|
}
|
||||||
match self.target_kind {
|
match self.target_kind {
|
||||||
TargetKind::Bin => {
|
TargetKind::Bin => {
|
||||||
buf.push("--bin".to_string());
|
buf.push("--bin".to_string());
|
||||||
|
|
|
@ -835,6 +835,7 @@ pub fn handle_code_lens(
|
||||||
for runnable in world.analysis().runnables(file_id)? {
|
for runnable in world.analysis().runnables(file_id)? {
|
||||||
let title = match &runnable.kind {
|
let title = match &runnable.kind {
|
||||||
RunnableKind::Test { .. } | RunnableKind::TestMod { .. } => "▶️\u{fe0e}Run Test",
|
RunnableKind::Test { .. } | RunnableKind::TestMod { .. } => "▶️\u{fe0e}Run Test",
|
||||||
|
RunnableKind::DocTest { .. } => "▶️\u{fe0e}Run Doctest",
|
||||||
RunnableKind::Bench { .. } => "Run Bench",
|
RunnableKind::Bench { .. } => "Run Bench",
|
||||||
RunnableKind::Bin => "Run",
|
RunnableKind::Bin => "Run",
|
||||||
}
|
}
|
||||||
|
@ -1018,6 +1019,7 @@ fn to_lsp_runnable(
|
||||||
RunnableKind::Test { test_id, .. } => format!("test {}", test_id),
|
RunnableKind::Test { test_id, .. } => format!("test {}", test_id),
|
||||||
RunnableKind::TestMod { path } => format!("test-mod {}", path),
|
RunnableKind::TestMod { path } => format!("test-mod {}", path),
|
||||||
RunnableKind::Bench { test_id } => format!("bench {}", test_id),
|
RunnableKind::Bench { test_id } => format!("bench {}", test_id),
|
||||||
|
RunnableKind::DocTest { test_id, .. } => format!("doctest {}", test_id),
|
||||||
RunnableKind::Bin => "run binary".to_string(),
|
RunnableKind::Bin => "run binary".to_string(),
|
||||||
};
|
};
|
||||||
Ok(req::Runnable {
|
Ok(req::Runnable {
|
||||||
|
|
Loading…
Reference in a new issue