From 748a4cacd24d9ecdca995e66117a10a1562e7d5d Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 28 Aug 2018 14:47:12 +0300 Subject: Reorganize tests --- crates/libeditor/src/code_actions.rs | 49 ++++++++++++ crates/libeditor/src/completion.rs | 52 +++++++++++++ crates/libeditor/src/extend_selection.rs | 55 +++++++++++++ crates/libeditor/src/lib.rs | 70 +++++++++++++++++ crates/libeditor/src/symbols.rs | 42 ++++++++++ crates/libeditor/src/test_utils.rs | 20 +++++ crates/libeditor/src/typing.rs | 129 +++++++++++++++++++++++++++++++ 7 files changed, 417 insertions(+) create mode 100644 crates/libeditor/src/test_utils.rs (limited to 'crates/libeditor/src') diff --git a/crates/libeditor/src/code_actions.rs b/crates/libeditor/src/code_actions.rs index cd5146d87..ca159c658 100644 --- a/crates/libeditor/src/code_actions.rs +++ b/crates/libeditor/src/code_actions.rs @@ -128,3 +128,52 @@ impl PushDisplay for String { write!(self, "{}", item).unwrap() } } + +#[cfg(test)] +mod tests { + use super::*; + use test_utils::check_action; + + #[test] + fn test_swap_comma() { + check_action( + "fn foo(x: i32,<|> y: Result<(), ()>) {}", + "fn foo(y: Result<(), ()>,<|> x: i32) {}", + |file, off| flip_comma(file, off).map(|f| f()), + ) + } + + #[test] + fn test_add_derive() { + check_action( + "struct Foo { a: i32, <|>}", + "#[derive(<|>)]\nstruct Foo { a: i32, }", + |file, off| add_derive(file, off).map(|f| f()), + ); + check_action( + "struct Foo { <|> a: i32, }", + "#[derive(<|>)]\nstruct Foo { a: i32, }", + |file, off| add_derive(file, off).map(|f| f()), + ); + check_action( + "#[derive(Clone)]\nstruct Foo { a: i32<|>, }", + "#[derive(Clone<|>)]\nstruct Foo { a: i32, }", + |file, off| add_derive(file, off).map(|f| f()), + ); + } + + #[test] + fn test_add_impl() { + check_action( + "struct Foo {<|>}\n", + "struct Foo {}\n\nimpl Foo {\n<|>\n}\n", + |file, off| add_impl(file, off).map(|f| f()), + ); + check_action( + "struct Foo {<|>}", + "struct Foo {}\n\nimpl Foo {\n<|>\n}", + |file, off| add_impl(file, off).map(|f| f()), + ); + } + +} diff --git a/crates/libeditor/src/completion.rs b/crates/libeditor/src/completion.rs index cea2d14d1..c6ce62661 100644 --- a/crates/libeditor/src/completion.rs +++ b/crates/libeditor/src/completion.rs @@ -37,3 +37,55 @@ fn complete(name_ref: ast::NameRef, scopes: &FnScopes) -> Vec { }) .collect() } + +#[cfg(test)] +mod tests { + use super::*; + use test_utils::{assert_eq_dbg, extract_offset}; + + fn do_check(code: &str, expected_completions: &str) { + let (off, code) = extract_offset(&code); + let file = File::parse(&code); + let completions = scope_completion(&file, off).unwrap(); + assert_eq_dbg(expected_completions, &completions); + } + + #[test] + fn test_completion_let_scope() { + do_check(r" + fn quux(x: i32) { + let y = 92; + 1 + <|>; + let z = (); + } + ", r#"[CompletionItem { name: "y" }, + CompletionItem { name: "x" }]"#); + } + + #[test] + fn test_completion_if_let_scope() { + do_check(r" + fn quux() { + if let Some(x) = foo() { + let y = 92; + }; + if let Some(a) = bar() { + let b = 62; + 1 + <|> + } + } + ", r#"[CompletionItem { name: "b" }, + CompletionItem { name: "a" }]"#); + } + + #[test] + fn test_completion_for_scope() { + do_check(r" + fn quux() { + for x in &[1, 2, 3] { + <|> + } + } + ", r#"[CompletionItem { name: "x" }]"#); + } +} diff --git a/crates/libeditor/src/extend_selection.rs b/crates/libeditor/src/extend_selection.rs index 154f89671..30cff6558 100644 --- a/crates/libeditor/src/extend_selection.rs +++ b/crates/libeditor/src/extend_selection.rs @@ -64,3 +64,58 @@ fn adj_comments(node: SyntaxNodeRef, dir: Direction) -> SyntaxNodeRef { } res } + +#[cfg(test)] +mod tests { + use super::*; + use test_utils::extract_offset; + + fn do_check(before: &str, afters: &[&str]) { + let (cursor, before) = extract_offset(before); + let file = File::parse(&before); + let mut range = TextRange::offset_len(cursor, 0.into()); + for &after in afters { + range = extend_selection(&file, range) + .unwrap(); + let actual = &before[range]; + assert_eq!(after, actual); + } + } + + #[test] + fn test_extend_selection_arith() { + do_check( + r#"fn foo() { <|>1 + 1 }"#, + &["1", "1 + 1", "{ 1 + 1 }"], + ); + } + + #[test] + fn test_extend_selection_start_of_the_lind() { + do_check( + r#" +impl S { +<|> fn foo() { + + } +}"#, + &["fn foo() {\n\n }"] + ); + } + + #[test] + fn test_extend_selection_comments() { + do_check( + r#" +fn bar(){} + +// fn foo() { +// 1 + <|>1 +// } + +// fn foo(){} + "#, + &["// 1 + 1", "// fn foo() {\n// 1 + 1\n// }"] + ); + } +} diff --git a/crates/libeditor/src/lib.rs b/crates/libeditor/src/lib.rs index 34056b3c0..b2e2c4782 100644 --- a/crates/libeditor/src/lib.rs +++ b/crates/libeditor/src/lib.rs @@ -1,6 +1,9 @@ extern crate libsyntax2; extern crate superslice; extern crate itertools; +#[cfg(test)] +#[macro_use] +extern crate test_utils as _test_utils; mod extend_selection; mod symbols; @@ -10,6 +13,8 @@ mod code_actions; mod typing; mod completion; mod scope; +#[cfg(test)] +mod test_utils; use libsyntax2::{ File, TextUnit, TextRange, SyntaxNodeRef, @@ -154,3 +159,68 @@ pub fn find_node_at_offset<'a, N: AstNode<'a>>( .filter_map(N::cast) .next() } + +#[cfg(test)] +mod tests { + use super::*; + use test_utils::{assert_eq_dbg, extract_offset, add_cursor}; + + #[test] + fn test_highlighting() { + let file = File::parse(r#" +// comment +fn main() {} + println!("Hello, {}!", 92); +"#); + let hls = highlight(&file); + assert_eq_dbg( + r#"[HighlightedRange { range: [1; 11), tag: "comment" }, + HighlightedRange { range: [12; 14), tag: "keyword" }, + HighlightedRange { range: [15; 19), tag: "function" }, + HighlightedRange { range: [29; 36), tag: "text" }, + HighlightedRange { range: [38; 50), tag: "string" }, + HighlightedRange { range: [52; 54), tag: "literal" }]"#, + &hls, + ); + } + + #[test] + fn test_runnables() { + let file = File::parse(r#" +fn main() {} + +#[test] +fn test_foo() {} + +#[test] +#[ignore] +fn test_foo() {} +"#); + let runnables = runnables(&file); + assert_eq_dbg( + r#"[Runnable { range: [1; 13), kind: Bin }, + Runnable { range: [15; 39), kind: Test { name: "test_foo" } }, + Runnable { range: [41; 75), kind: Test { name: "test_foo" } }]"#, + &runnables, + ) + } + + #[test] + fn test_matching_brace() { + fn do_check(before: &str, after: &str) { + let (pos, before) = extract_offset(before); + let file = File::parse(&before); + let new_pos = match matching_brace(&file, pos) { + None => pos, + Some(pos) => pos, + }; + let actual = add_cursor(&before, new_pos); + assert_eq_text!(after, &actual); + } + + do_check( + "struct Foo { a: i32, }<|>", + "struct Foo <|>{ a: i32, }", + ); + } +} diff --git a/crates/libeditor/src/symbols.rs b/crates/libeditor/src/symbols.rs index 98a35dcdf..28b86c004 100644 --- a/crates/libeditor/src/symbols.rs +++ b/crates/libeditor/src/symbols.rs @@ -123,3 +123,45 @@ fn structure_node(node: SyntaxNodeRef) -> Option { }) .accept(node)? } + +#[cfg(test)] +mod tests { + use super::*; + use test_utils::assert_eq_dbg; + + #[test] + fn test_file_structure() { + let file = File::parse(r#" +struct Foo { + x: i32 +} + +mod m { + fn bar() {} +} + +enum E { X, Y(i32) } +type T = (); +static S: i32 = 92; +const C: i32 = 92; + +impl E {} + +impl fmt::Debug for E {} +"#); + let symbols = file_structure(&file); + assert_eq_dbg( + r#"[StructureNode { parent: None, label: "Foo", navigation_range: [8; 11), node_range: [1; 26), kind: STRUCT_DEF }, + StructureNode { parent: Some(0), label: "x", navigation_range: [18; 19), node_range: [18; 24), kind: NAMED_FIELD_DEF }, + StructureNode { parent: None, label: "m", navigation_range: [32; 33), node_range: [28; 53), kind: MODULE }, + StructureNode { parent: Some(2), label: "bar", navigation_range: [43; 46), node_range: [40; 51), kind: FN_DEF }, + StructureNode { parent: None, label: "E", navigation_range: [60; 61), node_range: [55; 75), kind: ENUM_DEF }, + StructureNode { parent: None, label: "T", navigation_range: [81; 82), node_range: [76; 88), kind: TYPE_DEF }, + StructureNode { parent: None, label: "S", navigation_range: [96; 97), node_range: [89; 108), kind: STATIC_DEF }, + StructureNode { parent: None, label: "C", navigation_range: [115; 116), node_range: [109; 127), kind: CONST_DEF }, + StructureNode { parent: None, label: "impl E", navigation_range: [134; 135), node_range: [129; 138), kind: IMPL_ITEM }, + StructureNode { parent: None, label: "impl fmt::Debug for E", navigation_range: [160; 161), node_range: [140; 164), kind: IMPL_ITEM }]"#, + &symbols, + ) + } +} diff --git a/crates/libeditor/src/test_utils.rs b/crates/libeditor/src/test_utils.rs new file mode 100644 index 000000000..475f560fa --- /dev/null +++ b/crates/libeditor/src/test_utils.rs @@ -0,0 +1,20 @@ +use libsyntax2::{File, TextUnit}; +pub use _test_utils::*; +use ActionResult; + +pub fn check_action Option> ( + before: &str, + after: &str, + f: F, +) { + let (before_cursor_pos, before) = extract_offset(before); + let file = File::parse(&before); + let result = f(&file, before_cursor_pos).expect("code action is not applicable"); + let actual = result.edit.apply(&before); + let actual_cursor_pos = match result.cursor_position { + None => result.edit.apply_to_offset(before_cursor_pos).unwrap(), + Some(off) => off, + }; + let actual = add_cursor(&actual, actual_cursor_pos); + assert_eq_text!(after, &actual); +} diff --git a/crates/libeditor/src/typing.rs b/crates/libeditor/src/typing.rs index daa57983f..952caf7f6 100644 --- a/crates/libeditor/src/typing.rs +++ b/crates/libeditor/src/typing.rs @@ -163,3 +163,132 @@ fn compute_ws(left: SyntaxNodeRef, right: SyntaxNodeRef) -> &'static str { } " " } + +#[cfg(test)] +mod tests { + use super::*; + use test_utils::{check_action, extract_range, extract_offset}; + + fn check_join_lines(before: &str, after: &str) { + check_action(before, after, |file, offset| { + let range = TextRange::offset_len(offset, 0.into()); + let res = join_lines(file, range); + Some(res) + }) + } + + #[test] + fn test_join_lines_comma() { + check_join_lines(r" +fn foo() { + <|>foo(1, + ) +} +", r" +fn foo() { + <|>foo(1) +} +"); + } + + #[test] + fn test_join_lines_lambda_block() { + check_join_lines(r" +pub fn reparse(&self, edit: &AtomEdit) -> File { + <|>self.incremental_reparse(edit).unwrap_or_else(|| { + self.full_reparse(edit) + }) +} +", r" +pub fn reparse(&self, edit: &AtomEdit) -> File { + <|>self.incremental_reparse(edit).unwrap_or_else(|| self.full_reparse(edit)) +} +"); + } + + #[test] + fn test_join_lines_block() { + check_join_lines(r" +fn foo() { + foo(<|>{ + 92 + }) +}", r" +fn foo() { + foo(<|>92) +}"); + } + + #[test] + fn test_join_lines_selection() { + fn do_check(before: &str, after: &str) { + let (sel, before) = extract_range(before); + let file = File::parse(&before); + let result = join_lines(&file, sel); + let actual = result.edit.apply(&before); + assert_eq_text!(after, &actual); + } + + do_check(r" +fn foo() { + <|>foo(1, + 2, + 3, + <|>) +} + ", r" +fn foo() { + foo(1, 2, 3) +} + "); + + do_check(r" +struct Foo <|>{ + f: u32, +}<|> + ", r" +struct Foo { f: u32 } + "); + } + + #[test] + fn test_on_eq_typed() { + fn do_check(before: &str, after: &str) { + let (offset, before) = extract_offset(before); + let file = File::parse(&before); + let result = on_eq_typed(&file, offset).unwrap(); + let actual = result.edit.apply(&before); + assert_eq_text!(after, &actual); + } + + // do_check(r" + // fn foo() { + // let foo =<|> + // } + // ", r" + // fn foo() { + // let foo =; + // } + // "); + do_check(r" +fn foo() { + let foo =<|> 1 + 1 +} +", r" +fn foo() { + let foo = 1 + 1; +} +"); + // do_check(r" + // fn foo() { + // let foo =<|> + // let bar = 1; + // } + // ", r" + // fn foo() { + // let foo =; + // let bar = 1; + // } + // "); + } +} -- cgit v1.2.3