From cd32177a25a98026584a514de46461ce66f3eb56 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 3 Jan 2019 20:15:12 +0300 Subject: don't create many compilation units for tests --- crates/ra_analysis/tests/test/main.rs | 549 +++++++++++++++++++++++++++++ crates/ra_analysis/tests/test/runnables.rs | 109 ++++++ crates/ra_analysis/tests/test/type_of.rs | 77 ++++ 3 files changed, 735 insertions(+) create mode 100644 crates/ra_analysis/tests/test/main.rs create mode 100644 crates/ra_analysis/tests/test/runnables.rs create mode 100644 crates/ra_analysis/tests/test/type_of.rs (limited to 'crates/ra_analysis/tests/test') diff --git a/crates/ra_analysis/tests/test/main.rs b/crates/ra_analysis/tests/test/main.rs new file mode 100644 index 000000000..23a5799b9 --- /dev/null +++ b/crates/ra_analysis/tests/test/main.rs @@ -0,0 +1,549 @@ +mod runnables; +mod type_of; + +use ra_syntax::TextRange; +use test_utils::{assert_eq_dbg, assert_eq_text}; + +use ra_analysis::{ + mock_analysis::{analysis_and_position, single_file, single_file_with_position, MockAnalysis}, + AnalysisChange, CrateGraph, FileId, FnSignatureInfo, +}; + +fn get_signature(text: &str) -> (FnSignatureInfo, Option) { + let (analysis, position) = single_file_with_position(text); + analysis.resolve_callable(position).unwrap().unwrap() +} + +#[test] +fn approximate_resolve_works_in_items() { + let (analysis, pos) = analysis_and_position( + " + //- /lib.rs + struct Foo; + enum E { X(Foo<|>) } + ", + ); + + let symbols = analysis.approximately_resolve_symbol(pos).unwrap().unwrap(); + assert_eq_dbg( + r#"ReferenceResolution { + reference_range: [23; 26), + resolves_to: [NavigationTarget { file_id: FileId(1), name: "Foo", kind: STRUCT_DEF, range: [0; 11), ptr: Some(LocalSyntaxPtr { range: [0; 11), kind: STRUCT_DEF }) }] + }"#, + &symbols, + ); +} + +#[test] +fn test_resolve_module() { + let (analysis, pos) = analysis_and_position( + " + //- /lib.rs + mod <|>foo; + //- /foo.rs + // empty + ", + ); + + let symbols = analysis.approximately_resolve_symbol(pos).unwrap().unwrap(); + assert_eq_dbg( + r#"ReferenceResolution { + reference_range: [4; 7), + resolves_to: [NavigationTarget { file_id: FileId(2), name: "foo", kind: MODULE, range: [0; 0), ptr: None }] + }"#, + &symbols, + ); + + let (analysis, pos) = analysis_and_position( + " + //- /lib.rs + mod <|>foo; + //- /foo/mod.rs + // empty + ", + ); + + let symbols = analysis.approximately_resolve_symbol(pos).unwrap().unwrap(); + assert_eq_dbg( + r#"ReferenceResolution { + reference_range: [4; 7), + resolves_to: [NavigationTarget { file_id: FileId(2), name: "foo", kind: MODULE, range: [0; 0), ptr: None }] + }"#, + &symbols, + ); +} + +#[test] +fn test_unresolved_module_diagnostic() { + let (analysis, file_id) = single_file("mod foo;"); + let diagnostics = analysis.diagnostics(file_id).unwrap(); + assert_eq_dbg( + r#"[Diagnostic { + message: "unresolved module", + range: [4; 7), + fix: Some(SourceChange { + label: "create module", + source_file_edits: [], + file_system_edits: [CreateFile { source_root: SourceRootId(0), path: "foo.rs" }], + cursor_position: None }), + severity: Error }]"#, + &diagnostics, + ); +} + +#[test] +fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() { + let (analysis, file_id) = single_file("mod foo {}"); + let diagnostics = analysis.diagnostics(file_id).unwrap(); + assert_eq_dbg(r#"[]"#, &diagnostics); +} + +#[test] +fn test_resolve_parent_module() { + let (analysis, pos) = analysis_and_position( + " + //- /lib.rs + mod foo; + //- /foo.rs + <|>// empty + ", + ); + let symbols = analysis.parent_module(pos).unwrap(); + assert_eq_dbg( + r#"[NavigationTarget { file_id: FileId(1), name: "foo", kind: MODULE, range: [4; 7), ptr: None }]"#, + &symbols, + ); +} + +#[test] +fn test_resolve_parent_module_for_inline() { + let (analysis, pos) = analysis_and_position( + " + //- /lib.rs + mod foo { + mod bar { + mod baz { <|> } + } + } + ", + ); + let symbols = analysis.parent_module(pos).unwrap(); + assert_eq_dbg( + r#"[NavigationTarget { file_id: FileId(1), name: "bar", kind: MODULE, range: [18; 21), ptr: None }]"#, + &symbols, + ); +} + +#[test] +fn test_resolve_crate_root() { + let mock = MockAnalysis::with_files( + " + //- /lib.rs + mod foo; + //- /foo.rs + // emtpy <|> + ", + ); + let root_file = mock.id_of("/lib.rs"); + let mod_file = mock.id_of("/foo.rs"); + let mut host = mock.analysis_host(); + assert!(host.analysis().crate_for(mod_file).unwrap().is_empty()); + + let mut crate_graph = CrateGraph::default(); + let crate_id = crate_graph.add_crate_root(root_file); + let mut change = AnalysisChange::new(); + change.set_crate_graph(crate_graph); + host.apply_change(change); + + assert_eq!(host.analysis().crate_for(mod_file).unwrap(), vec![crate_id]); +} + +#[test] +fn test_fn_signature_two_args_first() { + let (desc, param) = get_signature( + r#"fn foo(x: u32, y: u32) -> u32 {x + y} +fn bar() { foo(<|>3, ); }"#, + ); + + assert_eq!(desc.name, "foo".to_string()); + assert_eq!(desc.params, vec!("x".to_string(), "y".to_string())); + assert_eq!(desc.ret_type, Some("-> u32".into())); + assert_eq!(param, Some(0)); +} + +#[test] +fn test_fn_signature_two_args_second() { + let (desc, param) = get_signature( + r#"fn foo(x: u32, y: u32) -> u32 {x + y} +fn bar() { foo(3, <|>); }"#, + ); + + assert_eq!(desc.name, "foo".to_string()); + assert_eq!(desc.params, vec!("x".to_string(), "y".to_string())); + assert_eq!(desc.ret_type, Some("-> u32".into())); + assert_eq!(param, Some(1)); +} + +#[test] +fn test_fn_signature_for_impl() { + let (desc, param) = get_signature( + r#"struct F; impl F { pub fn new() { F{}} } +fn bar() {let _ : F = F::new(<|>);}"#, + ); + + assert_eq!(desc.name, "new".to_string()); + assert_eq!(desc.params, Vec::::new()); + assert_eq!(desc.ret_type, None); + assert_eq!(param, None); +} + +#[test] +fn test_fn_signature_for_method_self() { + let (desc, param) = get_signature( + r#"struct F; +impl F { + pub fn new() -> F{ + F{} + } + + pub fn do_it(&self) {} +} + +fn bar() { + let f : F = F::new(); + f.do_it(<|>); +}"#, + ); + + assert_eq!(desc.name, "do_it".to_string()); + assert_eq!(desc.params, vec!["&self".to_string()]); + assert_eq!(desc.ret_type, None); + assert_eq!(param, None); +} + +#[test] +fn test_fn_signature_for_method_with_arg() { + let (desc, param) = get_signature( + r#"struct F; +impl F { + pub fn new() -> F{ + F{} + } + + pub fn do_it(&self, x: i32) {} +} + +fn bar() { + let f : F = F::new(); + f.do_it(<|>); +}"#, + ); + + assert_eq!(desc.name, "do_it".to_string()); + assert_eq!(desc.params, vec!["&self".to_string(), "x".to_string()]); + assert_eq!(desc.ret_type, None); + assert_eq!(param, Some(1)); +} + +#[test] +fn test_fn_signature_with_docs_simple() { + let (desc, param) = get_signature( + r#" +// test +fn foo(j: u32) -> u32 { + j +} + +fn bar() { + let _ = foo(<|>); +} +"#, + ); + + assert_eq!(desc.name, "foo".to_string()); + assert_eq!(desc.params, vec!["j".to_string()]); + assert_eq!(desc.ret_type, Some("-> u32".to_string())); + assert_eq!(param, Some(0)); + assert_eq!(desc.label, "fn foo(j: u32) -> u32".to_string()); + assert_eq!(desc.doc, Some("test".into())); +} + +#[test] +fn test_fn_signature_with_docs() { + let (desc, param) = get_signature( + r#" +/// Adds one to the number given. +/// +/// # Examples +/// +/// ``` +/// let five = 5; +/// +/// assert_eq!(6, my_crate::add_one(5)); +/// ``` +pub fn add_one(x: i32) -> i32 { + x + 1 +} + +pub fn do() { + add_one(<|> +}"#, + ); + + assert_eq!(desc.name, "add_one".to_string()); + assert_eq!(desc.params, vec!["x".to_string()]); + assert_eq!(desc.ret_type, Some("-> i32".to_string())); + assert_eq!(param, Some(0)); + assert_eq!(desc.label, "pub fn add_one(x: i32) -> i32".to_string()); + assert_eq!( + desc.doc, + Some( + r#"Adds one to the number given. + +# Examples + +```rust +let five = 5; + +assert_eq!(6, my_crate::add_one(5)); +```"# + .into() + ) + ); +} + +#[test] +fn test_fn_signature_with_docs_impl() { + let (desc, param) = get_signature( + r#" +struct addr; +impl addr { + /// Adds one to the number given. + /// + /// # Examples + /// + /// ``` + /// let five = 5; + /// + /// assert_eq!(6, my_crate::add_one(5)); + /// ``` + pub fn add_one(x: i32) -> i32 { + x + 1 + } +} + +pub fn do_it() { + addr {}; + addr::add_one(<|>); +}"#, + ); + + assert_eq!(desc.name, "add_one".to_string()); + assert_eq!(desc.params, vec!["x".to_string()]); + assert_eq!(desc.ret_type, Some("-> i32".to_string())); + assert_eq!(param, Some(0)); + assert_eq!(desc.label, "pub fn add_one(x: i32) -> i32".to_string()); + assert_eq!( + desc.doc, + Some( + r#"Adds one to the number given. + +# Examples + +```rust +let five = 5; + +assert_eq!(6, my_crate::add_one(5)); +```"# + .into() + ) + ); +} + +#[test] +fn test_fn_signature_with_docs_from_actix() { + let (desc, param) = get_signature( + r#" +pub trait WriteHandler +where + Self: Actor, + Self::Context: ActorContext, +{ + /// Method is called when writer emits error. + /// + /// If this method returns `ErrorAction::Continue` writer processing + /// continues otherwise stream processing stops. + fn error(&mut self, err: E, ctx: &mut Self::Context) -> Running { + Running::Stop + } + + /// Method is called when writer finishes. + /// + /// By default this method stops actor's `Context`. + fn finished(&mut self, ctx: &mut Self::Context) { + ctx.stop() + } +} + +pub fn foo() { + WriteHandler r; + r.finished(<|>); +} + +"#, + ); + + assert_eq!(desc.name, "finished".to_string()); + assert_eq!( + desc.params, + vec!["&mut self".to_string(), "ctx".to_string()] + ); + assert_eq!(desc.ret_type, None); + assert_eq!(param, Some(1)); + assert_eq!( + desc.doc, + Some( + r#"Method is called when writer finishes. + +By default this method stops actor's `Context`."# + .into() + ) + ); +} + +fn get_all_refs(text: &str) -> Vec<(FileId, TextRange)> { + let (analysis, position) = single_file_with_position(text); + analysis.find_all_refs(position).unwrap() +} + +#[test] +fn test_find_all_refs_for_local() { + let code = r#" + fn main() { + let mut i = 1; + let j = 1; + i = i<|> + j; + + { + i = 0; + } + + i = 5; + }"#; + + let refs = get_all_refs(code); + assert_eq!(refs.len(), 5); +} + +#[test] +fn test_find_all_refs_for_param_inside() { + let code = r#" + fn foo(i : u32) -> u32 { + i<|> + }"#; + + let refs = get_all_refs(code); + assert_eq!(refs.len(), 2); +} + +#[test] +fn test_find_all_refs_for_fn_param() { + let code = r#" + fn foo(i<|> : u32) -> u32 { + i + }"#; + + let refs = get_all_refs(code); + assert_eq!(refs.len(), 2); +} +#[test] +fn test_rename_for_local() { + test_rename( + r#" + fn main() { + let mut i = 1; + let j = 1; + i = i<|> + j; + + { + i = 0; + } + + i = 5; + }"#, + "k", + r#" + fn main() { + let mut k = 1; + let j = 1; + k = k + j; + + { + k = 0; + } + + k = 5; + }"#, + ); +} + +#[test] +fn test_rename_for_param_inside() { + test_rename( + r#" + fn foo(i : u32) -> u32 { + i<|> + }"#, + "j", + r#" + fn foo(j : u32) -> u32 { + j + }"#, + ); +} + +#[test] +fn test_rename_refs_for_fn_param() { + test_rename( + r#" + fn foo(i<|> : u32) -> u32 { + i + }"#, + "new_name", + r#" + fn foo(new_name : u32) -> u32 { + new_name + }"#, + ); +} + +#[test] +fn test_rename_for_mut_param() { + test_rename( + r#" + fn foo(mut i<|> : u32) -> u32 { + i + }"#, + "new_name", + r#" + fn foo(mut new_name : u32) -> u32 { + new_name + }"#, + ); +} +fn test_rename(text: &str, new_name: &str, expected: &str) { + let (analysis, position) = single_file_with_position(text); + let edits = analysis.rename(position, new_name).unwrap(); + let mut text_edit_bulder = ra_text_edit::TextEditBuilder::default(); + let mut file_id: Option = None; + for edit in edits { + file_id = Some(edit.file_id); + for atom in edit.edit.as_atoms() { + text_edit_bulder.replace(atom.delete, atom.insert.clone()); + } + } + let result = text_edit_bulder + .finish() + .apply(&*analysis.file_text(file_id.unwrap())); + assert_eq_text!(expected, &*result); +} diff --git a/crates/ra_analysis/tests/test/runnables.rs b/crates/ra_analysis/tests/test/runnables.rs new file mode 100644 index 000000000..e6e0afbc3 --- /dev/null +++ b/crates/ra_analysis/tests/test/runnables.rs @@ -0,0 +1,109 @@ +use test_utils::assert_eq_dbg; + +use ra_analysis::mock_analysis::analysis_and_position; + +#[test] +fn test_runnables() { + let (analysis, pos) = analysis_and_position( + r#" + //- /lib.rs + <|> //empty + fn main() {} + + #[test] + fn test_foo() {} + + #[test] + #[ignore] + fn test_foo() {} + "#, + ); + let runnables = analysis.runnables(pos.file_id).unwrap(); + assert_eq_dbg( + r#"[Runnable { range: [1; 21), kind: Bin }, + Runnable { range: [22; 46), kind: Test { name: "test_foo" } }, + Runnable { range: [47; 81), kind: Test { name: "test_foo" } }]"#, + &runnables, + ) +} + +#[test] +fn test_runnables_module() { + let (analysis, pos) = analysis_and_position( + r#" + //- /lib.rs + <|> //empty + mod test_mod { + #[test] + fn test_foo1() {} + } + "#, + ); + let runnables = analysis.runnables(pos.file_id).unwrap(); + assert_eq_dbg( + r#"[Runnable { range: [1; 59), kind: TestMod { path: "test_mod" } }, + Runnable { range: [28; 57), kind: Test { name: "test_foo1" } }]"#, + &runnables, + ) +} + +#[test] +fn test_runnables_one_depth_layer_module() { + let (analysis, pos) = analysis_and_position( + r#" + //- /lib.rs + <|> //empty + mod foo { + mod test_mod { + #[test] + fn test_foo1() {} + } + } + "#, + ); + let runnables = analysis.runnables(pos.file_id).unwrap(); + assert_eq_dbg( + r#"[Runnable { range: [23; 85), kind: TestMod { path: "foo::test_mod" } }, + Runnable { range: [46; 79), kind: Test { name: "test_foo1" } }]"#, + &runnables, + ) +} + +#[test] +fn test_runnables_multiple_depth_module() { + let (analysis, pos) = analysis_and_position( + r#" + //- /lib.rs + <|> //empty + mod foo { + mod bar { + mod test_mod { + #[test] + fn test_foo1() {} + } + } + } + "#, + ); + let runnables = analysis.runnables(pos.file_id).unwrap(); + assert_eq_dbg( + r#"[Runnable { range: [41; 115), kind: TestMod { path: "foo::bar::test_mod" } }, + Runnable { range: [68; 105), kind: Test { name: "test_foo1" } }]"#, + &runnables, + ) +} + +#[test] +fn test_runnables_no_test_function_in_module() { + let (analysis, pos) = analysis_and_position( + r#" + //- /lib.rs + <|> //empty + mod test_mod { + fn foo1() {} + } + "#, + ); + let runnables = analysis.runnables(pos.file_id).unwrap(); + assert_eq_dbg(r#"[]"#, &runnables) +} diff --git a/crates/ra_analysis/tests/test/type_of.rs b/crates/ra_analysis/tests/test/type_of.rs new file mode 100644 index 000000000..9d15b52a8 --- /dev/null +++ b/crates/ra_analysis/tests/test/type_of.rs @@ -0,0 +1,77 @@ +use ra_analysis::mock_analysis::single_file_with_range; + +#[test] +fn test_type_of_for_function() { + let (analysis, range) = single_file_with_range( + " + pub fn foo() -> u32 { 1 }; + + fn main() { + let foo_test = <|>foo()<|>; + } + ", + ); + + let type_name = analysis.type_of(range).unwrap().unwrap(); + assert_eq!("u32", &type_name); +} + +// FIXME: improve type_of to make this work +#[test] +fn test_type_of_for_num() { + let (analysis, range) = single_file_with_range( + r#" + fn main() { + let foo_test = <|>"foo"<|>; + } + "#, + ); + + assert!(analysis.type_of(range).unwrap().is_none()); +} +// FIXME: improve type_of to make this work +#[test] +fn test_type_of_for_binding() { + let (analysis, range) = single_file_with_range( + " + pub fn foo() -> u32 { 1 }; + + fn main() { + let <|>foo_test<|> = foo(); + } + ", + ); + + assert!(analysis.type_of(range).unwrap().is_none()); +} + +// FIXME: improve type_of to make this work +#[test] +fn test_type_of_for_expr_1() { + let (analysis, range) = single_file_with_range( + " + fn main() { + let foo = <|>1 + foo_test<|>; + } + ", + ); + + let type_name = analysis.type_of(range).unwrap().unwrap(); + assert_eq!("[unknown]", &type_name); +} + +// FIXME: improve type_of to make this work +#[test] +fn test_type_of_for_expr_2() { + let (analysis, range) = single_file_with_range( + " + fn main() { + let foo: usize = 1; + let bar = <|>1 + foo_test<|>; + } + ", + ); + + let type_name = analysis.type_of(range).unwrap().unwrap(); + assert_eq!("[unknown]", &type_name); +} -- cgit v1.2.3