Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions crates/assists/src/handlers/ignore_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use syntax::{ast, AstNode};

use crate::{utils::test_related_attribute, AssistContext, AssistId, AssistKind, Assists};

// Assist: ignore_test
//
// Adds `#[ignore]` attribute to the test.
//
// ```
// <|>#[test]
// fn arithmetics {
// assert_eq!(2 + 2, 5);
// }
// ```
// ->
// ```
// #[test]
// #[ignore]
// fn arithmetics {
// assert_eq!(2 + 2, 5);
// }
// ```
pub(crate) fn ignore_test(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
let attr: ast::Attr = ctx.find_node_at_offset()?;
let func = attr.syntax().parent().and_then(ast::Fn::cast)?;
let attr = test_related_attribute(&func)?;

acc.add(
AssistId("ignore_test", AssistKind::None),
"Ignore this test",
attr.syntax().text_range(),
|builder| builder.insert(attr.syntax().text_range().end(), &format!("\n#[ignore]")),
)
}
2 changes: 2 additions & 0 deletions crates/assists/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ mod handlers {
mod generate_function;
mod generate_impl;
mod generate_new;
mod ignore_test;
mod infer_function_return_type;
mod inline_local_variable;
mod introduce_named_lifetime;
Expand Down Expand Up @@ -189,6 +190,7 @@ mod handlers {
generate_function::generate_function,
generate_impl::generate_impl,
generate_new::generate_new,
ignore_test::ignore_test,
infer_function_return_type::infer_function_return_type,
inline_local_variable::inline_local_variable,
introduce_named_lifetime::introduce_named_lifetime,
Expand Down
20 changes: 20 additions & 0 deletions crates/assists/src/tests/generated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,26 @@ impl<T: Clone> Ctx<T> {
)
}

#[test]
fn doctest_ignore_test() {
check_doc_test(
"ignore_test",
r#####"
<|>#[test]
fn arithmetics {
assert_eq!(2 + 2, 5);
}
"#####,
r#####"
#[test]
#[ignore]
fn arithmetics {
assert_eq!(2 + 2, 5);
}
"#####,
)
}

#[test]
fn doctest_infer_function_return_type() {
check_doc_test(
Expand Down
18 changes: 18 additions & 0 deletions crates/assists/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use ide_db::RootDatabase;
use itertools::Itertools;
use syntax::{
ast::edit::AstNodeEdit,
ast::AttrsOwner,
ast::NameOwner,
ast::{self, edit, make, ArgListOwner},
AstNode, Direction,
Expand Down Expand Up @@ -82,6 +83,23 @@ pub fn extract_trivial_expression(block: &ast::BlockExpr) -> Option<ast::Expr> {
None
}

/// This is a method with a heuristics to support test methods annotated with custom test annotations, such as
/// `#[test_case(...)]`, `#[tokio::test]` and similar.
/// Also a regular `#[test]` annotation is supported.
///
/// It may produce false positives, for example, `#[wasm_bindgen_test]` requires a different command to run the test,
/// but it's better than not to have the runnables for the tests at all.
pub fn test_related_attribute(fn_def: &ast::Fn) -> Option<ast::Attr> {
fn_def.attrs().find_map(|attr| {
let path = attr.path()?;
if path.syntax().text().to_string().contains("test") {
Some(attr)
} else {
None
}
})
}

#[derive(Copy, Clone, PartialEq)]
pub enum DefaultMethods {
Only,
Expand Down
5 changes: 3 additions & 2 deletions crates/ide/src/fn_references.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
//! This module implements a methods and free functions search in the specified file.
//! We have to skip tests, so cannot reuse file_structure module.

use assists::utils::test_related_attribute;
use hir::Semantics;
use ide_db::RootDatabase;
use syntax::{ast, ast::NameOwner, AstNode, SyntaxNode};

use crate::{runnables::has_test_related_attribute, FileId, FileRange};
use crate::{FileId, FileRange};

pub(crate) fn find_all_methods(db: &RootDatabase, file_id: FileId) -> Vec<FileRange> {
let sema = Semantics::new(db);
Expand All @@ -15,7 +16,7 @@ pub(crate) fn find_all_methods(db: &RootDatabase, file_id: FileId) -> Vec<FileRa

fn method_range(item: SyntaxNode, file_id: FileId) -> Option<FileRange> {
ast::Fn::cast(item).and_then(|fn_def| {
if has_test_related_attribute(&fn_def) {
if test_related_attribute(&fn_def).is_some() {
None
} else {
fn_def.name().map(|name| FileRange { file_id, range: name.syntax().text_range() })
Expand Down
19 changes: 3 additions & 16 deletions crates/ide/src/runnables.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::fmt;

use assists::utils::test_related_attribute;
use cfg::CfgExpr;
use hir::{AsAssocItem, Attrs, HirFileId, InFile, Semantics};
use ide_db::RootDatabase;
Expand Down Expand Up @@ -156,7 +157,7 @@ fn runnable_fn(
None => TestId::Name(name_string),
};

if has_test_related_attribute(&fn_def) {
if test_related_attribute(&fn_def).is_some() {
let attr = TestAttr::from_fn(&fn_def);
RunnableKind::Test { test_id, attr }
} else if fn_def.has_atom_attr("bench") {
Expand Down Expand Up @@ -235,20 +236,6 @@ impl TestAttr {
}
}

/// This is a method with a heuristics to support test methods annotated with custom test annotations, such as
/// `#[test_case(...)]`, `#[tokio::test]` and similar.
/// Also a regular `#[test]` annotation is supported.
///
/// It may produce false positives, for example, `#[wasm_bindgen_test]` requires a different command to run the test,
/// but it's better than not to have the runnables for the tests at all.
pub(crate) fn has_test_related_attribute(fn_def: &ast::Fn) -> bool {
fn_def
.attrs()
.filter_map(|attr| attr.path())
.map(|path| path.syntax().to_string().to_lowercase())
.any(|attribute_text| attribute_text.contains("test"))
}

const RUSTDOC_FENCE: &str = "```";
const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] =
&["", "rust", "should_panic", "edition2015", "edition2018"];
Expand Down Expand Up @@ -307,7 +294,7 @@ fn has_test_function_or_multiple_test_submodules(module: &ast::Module) -> bool {
for item in item_list.items() {
match item {
ast::Item::Fn(f) => {
if has_test_related_attribute(&f) {
if test_related_attribute(&f).is_some() {
return true;
}
}
Expand Down