organize completion tests better

This commit is contained in:
Aleksey Kladov 2018-12-21 18:13:21 +03:00
parent d4ef07b235
commit 45232dfa68
5 changed files with 488 additions and 393 deletions

View file

@ -16,7 +16,7 @@ use hir::source_binder;
use crate::{
db,
Cancelable, FilePosition,
completion::completion_item::Completions,
completion::completion_item::{Completions, CompletionKind},
};
pub use crate::completion::completion_item::{CompletionItem, InsertText};
@ -81,7 +81,12 @@ fn param_completions(acc: &mut Completions, ctx: SyntaxNodeRef) {
Some((label, lookup))
}
})
.for_each(|(label, lookup)| CompletionItem::new(label).lookup_by(lookup).add_to(acc));
.for_each(|(label, lookup)| {
CompletionItem::new(label)
.lookup_by(lookup)
.kind(CompletionKind::Magic)
.add_to(acc)
});
fn process<'a, N: ast::FnDefOwner<'a>>(
node: N,
@ -104,342 +109,62 @@ fn is_node<'a, N: AstNode<'a>>(node: SyntaxNodeRef<'a>) -> bool {
}
}
#[cfg(test)]
fn check_completion(code: &str, expected_completions: &str, kind: CompletionKind) {
use crate::mock_analysis::{single_file_with_position, analysis_and_position};
let (analysis, position) = if code.contains("//-") {
analysis_and_position(code)
} else {
single_file_with_position(code)
};
let completions = completions(&analysis.imp.db, position).unwrap().unwrap();
completions.assert_match(expected_completions, kind);
}
#[cfg(test)]
mod tests {
use test_utils::assert_eq_dbg;
use crate::mock_analysis::single_file_with_position;
use super::*;
fn is_snippet(completion_item: &CompletionItem) -> bool {
match completion_item.insert_text() {
InsertText::Snippet { .. } => true,
_ => false,
}
}
fn check_scope_completion(code: &str, expected_completions: &str) {
let (analysis, position) = single_file_with_position(code);
let completions = completions(&analysis.imp.db, position)
.unwrap()
.unwrap()
.into_iter()
.filter(|c| !is_snippet(c))
.collect::<Vec<_>>();
assert_eq_dbg(expected_completions, &completions);
}
fn check_snippet_completion(code: &str, expected_completions: &str) {
let (analysis, position) = single_file_with_position(code);
let completions = completions(&analysis.imp.db, position)
.unwrap()
.unwrap()
.into_iter()
.filter(is_snippet)
.collect::<Vec<_>>();
assert_eq_dbg(expected_completions, &completions);
}
#[test]
fn test_completion_let_scope() {
check_scope_completion(
r"
fn quux(x: i32) {
let y = 92;
1 + <|>;
let z = ();
}
",
r#"[CompletionItem { label: "y", lookup: None, snippet: None },
CompletionItem { label: "x", lookup: None, snippet: None },
CompletionItem { label: "quux", lookup: None, snippet: None }]"#,
);
}
#[test]
fn test_completion_if_let_scope() {
check_scope_completion(
r"
fn quux() {
if let Some(x) = foo() {
let y = 92;
};
if let Some(a) = bar() {
let b = 62;
1 + <|>
}
}
",
r#"[CompletionItem { label: "b", lookup: None, snippet: None },
CompletionItem { label: "a", lookup: None, snippet: None },
CompletionItem { label: "quux", lookup: None, snippet: None }]"#,
);
}
#[test]
fn test_completion_for_scope() {
check_scope_completion(
r"
fn quux() {
for x in &[1, 2, 3] {
<|>
}
}
",
r#"[CompletionItem { label: "x", lookup: None, snippet: None },
CompletionItem { label: "quux", lookup: None, snippet: None }]"#,
);
}
#[test]
fn test_completion_mod_scope() {
check_scope_completion(
r"
struct Foo;
enum Baz {}
fn quux() {
<|>
}
",
r#"[CompletionItem { label: "quux", lookup: None, snippet: None },
CompletionItem { label: "Foo", lookup: None, snippet: None },
CompletionItem { label: "Baz", lookup: None, snippet: None }]"#,
);
}
#[test]
fn test_completion_mod_scope_no_self_use() {
check_scope_completion(
r"
use foo<|>;
",
r#"[]"#,
);
}
#[test]
fn test_completion_self_path() {
check_scope_completion(
r"
use self::m::<|>;
mod m {
struct Bar;
}
",
r#"[CompletionItem { label: "Bar", lookup: None, snippet: None }]"#,
);
}
#[test]
fn test_completion_mod_scope_nested() {
check_scope_completion(
r"
struct Foo;
mod m {
struct Bar;
fn quux() { <|> }
}
",
r#"[CompletionItem { label: "quux", lookup: None, snippet: None },
CompletionItem { label: "Bar", lookup: None, snippet: None }]"#,
);
}
#[test]
fn test_complete_type() {
check_scope_completion(
r"
struct Foo;
fn x() -> <|>
",
r#"[CompletionItem { label: "Foo", lookup: None, snippet: None },
CompletionItem { label: "x", lookup: None, snippet: None }]"#,
)
}
#[test]
fn test_complete_shadowing() {
check_scope_completion(
r"
fn foo() -> {
let bar = 92;
{
let bar = 62;
<|>
}
}
",
r#"[CompletionItem { label: "bar", lookup: None, snippet: None },
CompletionItem { label: "foo", lookup: None, snippet: None }]"#,
)
}
#[test]
fn test_complete_self() {
check_scope_completion(
r"
impl S { fn foo(&self) { <|> } }
",
r#"[CompletionItem { label: "self", lookup: None, snippet: None }]"#,
)
}
#[test]
fn test_completion_kewords() {
check_snippet_completion(r"
fn quux() {
<|>
}
", r#"[CompletionItem { label: "if", lookup: None, snippet: Some("if $0 {}") },
CompletionItem { label: "match", lookup: None, snippet: Some("match $0 {}") },
CompletionItem { label: "while", lookup: None, snippet: Some("while $0 {}") },
CompletionItem { label: "loop", lookup: None, snippet: Some("loop {$0}") },
CompletionItem { label: "return", lookup: None, snippet: Some("return") },
CompletionItem { label: "pd", lookup: None, snippet: Some("eprintln!(\"$0 = {:?}\", $0);") },
CompletionItem { label: "ppd", lookup: None, snippet: Some("eprintln!(\"$0 = {:#?}\", $0);") }]"#);
}
#[test]
fn test_completion_else() {
check_snippet_completion(r"
fn quux() {
if true {
()
} <|>
}
", r#"[CompletionItem { label: "if", lookup: None, snippet: Some("if $0 {}") },
CompletionItem { label: "match", lookup: None, snippet: Some("match $0 {}") },
CompletionItem { label: "while", lookup: None, snippet: Some("while $0 {}") },
CompletionItem { label: "loop", lookup: None, snippet: Some("loop {$0}") },
CompletionItem { label: "else", lookup: None, snippet: Some("else {$0}") },
CompletionItem { label: "else if", lookup: None, snippet: Some("else if $0 {}") },
CompletionItem { label: "return", lookup: None, snippet: Some("return") },
CompletionItem { label: "pd", lookup: None, snippet: Some("eprintln!(\"$0 = {:?}\", $0);") },
CompletionItem { label: "ppd", lookup: None, snippet: Some("eprintln!(\"$0 = {:#?}\", $0);") }]"#);
}
#[test]
fn test_completion_return_value() {
check_snippet_completion(r"
fn quux() -> i32 {
<|>
92
}
", r#"[CompletionItem { label: "if", lookup: None, snippet: Some("if $0 {}") },
CompletionItem { label: "match", lookup: None, snippet: Some("match $0 {}") },
CompletionItem { label: "while", lookup: None, snippet: Some("while $0 {}") },
CompletionItem { label: "loop", lookup: None, snippet: Some("loop {$0}") },
CompletionItem { label: "return", lookup: None, snippet: Some("return $0;") },
CompletionItem { label: "pd", lookup: None, snippet: Some("eprintln!(\"$0 = {:?}\", $0);") },
CompletionItem { label: "ppd", lookup: None, snippet: Some("eprintln!(\"$0 = {:#?}\", $0);") }]"#);
check_snippet_completion(r"
fn quux() {
<|>
92
}
", r#"[CompletionItem { label: "if", lookup: None, snippet: Some("if $0 {}") },
CompletionItem { label: "match", lookup: None, snippet: Some("match $0 {}") },
CompletionItem { label: "while", lookup: None, snippet: Some("while $0 {}") },
CompletionItem { label: "loop", lookup: None, snippet: Some("loop {$0}") },
CompletionItem { label: "return", lookup: None, snippet: Some("return;") },
CompletionItem { label: "pd", lookup: None, snippet: Some("eprintln!(\"$0 = {:?}\", $0);") },
CompletionItem { label: "ppd", lookup: None, snippet: Some("eprintln!(\"$0 = {:#?}\", $0);") }]"#);
}
#[test]
fn test_completion_return_no_stmt() {
check_snippet_completion(r"
fn quux() -> i32 {
match () {
() => <|>
}
}
", r#"[CompletionItem { label: "if", lookup: None, snippet: Some("if $0 {}") },
CompletionItem { label: "match", lookup: None, snippet: Some("match $0 {}") },
CompletionItem { label: "while", lookup: None, snippet: Some("while $0 {}") },
CompletionItem { label: "loop", lookup: None, snippet: Some("loop {$0}") },
CompletionItem { label: "return", lookup: None, snippet: Some("return $0") },
CompletionItem { label: "pd", lookup: None, snippet: Some("eprintln!(\"$0 = {:?}\", $0);") },
CompletionItem { label: "ppd", lookup: None, snippet: Some("eprintln!(\"$0 = {:#?}\", $0);") }]"#);
}
#[test]
fn test_continue_break_completion() {
check_snippet_completion(r"
fn quux() -> i32 {
loop { <|> }
}
", r#"[CompletionItem { label: "if", lookup: None, snippet: Some("if $0 {}") },
CompletionItem { label: "match", lookup: None, snippet: Some("match $0 {}") },
CompletionItem { label: "while", lookup: None, snippet: Some("while $0 {}") },
CompletionItem { label: "loop", lookup: None, snippet: Some("loop {$0}") },
CompletionItem { label: "continue", lookup: None, snippet: Some("continue") },
CompletionItem { label: "break", lookup: None, snippet: Some("break") },
CompletionItem { label: "return", lookup: None, snippet: Some("return $0") },
CompletionItem { label: "pd", lookup: None, snippet: Some("eprintln!(\"$0 = {:?}\", $0);") },
CompletionItem { label: "ppd", lookup: None, snippet: Some("eprintln!(\"$0 = {:#?}\", $0);") }]"#);
check_snippet_completion(r"
fn quux() -> i32 {
loop { || { <|> } }
}
", r#"[CompletionItem { label: "if", lookup: None, snippet: Some("if $0 {}") },
CompletionItem { label: "match", lookup: None, snippet: Some("match $0 {}") },
CompletionItem { label: "while", lookup: None, snippet: Some("while $0 {}") },
CompletionItem { label: "loop", lookup: None, snippet: Some("loop {$0}") },
CompletionItem { label: "return", lookup: None, snippet: Some("return $0") },
CompletionItem { label: "pd", lookup: None, snippet: Some("eprintln!(\"$0 = {:?}\", $0);") },
CompletionItem { label: "ppd", lookup: None, snippet: Some("eprintln!(\"$0 = {:#?}\", $0);") }]"#);
fn check_magic_completion(code: &str, expected_completions: &str) {
check_completion(code, expected_completions, CompletionKind::Magic);
}
#[test]
fn test_param_completion_last_param() {
check_scope_completion(r"
check_magic_completion(
r"
fn foo(file_id: FileId) {}
fn bar(file_id: FileId) {}
fn baz(file<|>) {}
", r#"[CompletionItem { label: "file_id: FileId", lookup: Some("file_id"), snippet: None }]"#);
",
r#"file_id "file_id: FileId""#,
);
}
#[test]
fn test_param_completion_nth_param() {
check_scope_completion(r"
check_magic_completion(
r"
fn foo(file_id: FileId) {}
fn bar(file_id: FileId) {}
fn baz(file<|>, x: i32) {}
", r#"[CompletionItem { label: "file_id: FileId", lookup: Some("file_id"), snippet: None }]"#);
",
r#"file_id "file_id: FileId""#,
);
}
#[test]
fn test_param_completion_trait_param() {
check_scope_completion(r"
check_magic_completion(
r"
pub(crate) trait SourceRoot {
pub fn contains(&self, file_id: FileId) -> bool;
pub fn module_map(&self) -> &ModuleMap;
pub fn lines(&self, file_id: FileId) -> &LineIndex;
pub fn syntax(&self, file<|>)
}
", r#"[CompletionItem { label: "self", lookup: None, snippet: None },
CompletionItem { label: "SourceRoot", lookup: None, snippet: None },
CompletionItem { label: "file_id: FileId", lookup: Some("file_id"), snippet: None }]"#);
}
#[test]
fn test_item_snippets() {
// check_snippet_completion(r"
// <|>
// ",
// r##"[CompletionItem { label: "Test function", lookup: None, snippet: Some("#[test]\nfn test_${1:feature}() {\n$0\n}"##,
// );
check_snippet_completion(r"
#[cfg(test)]
mod tests {
<|>
}
",
r##"[CompletionItem { label: "Test function", lookup: Some("tfn"), snippet: Some("#[test]\nfn ${1:feature}() {\n $0\n}") },
CompletionItem { label: "pub(crate)", lookup: None, snippet: Some("pub(crate) $0") }]"##,
r#"file_id "file_id: FileId""#,
);
}
}