From b5021411a84822cb3f1e3aeffad9550dd15bdeb6 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 16 Sep 2018 12:54:24 +0300 Subject: rename all things --- crates/ra_lsp_server/tests/heavy_tests/main.rs | 99 ++++++++++ crates/ra_lsp_server/tests/heavy_tests/support.rs | 217 ++++++++++++++++++++++ 2 files changed, 316 insertions(+) create mode 100644 crates/ra_lsp_server/tests/heavy_tests/main.rs create mode 100644 crates/ra_lsp_server/tests/heavy_tests/support.rs (limited to 'crates/ra_lsp_server/tests') diff --git a/crates/ra_lsp_server/tests/heavy_tests/main.rs b/crates/ra_lsp_server/tests/heavy_tests/main.rs new file mode 100644 index 000000000..dced45f55 --- /dev/null +++ b/crates/ra_lsp_server/tests/heavy_tests/main.rs @@ -0,0 +1,99 @@ +#[macro_use] +extern crate crossbeam_channel; +extern crate tempdir; +extern crate languageserver_types; +extern crate serde; +extern crate serde_json; +extern crate gen_lsp_server; +extern crate flexi_logger; +extern crate ra_lsp_server; + +mod support; + +use ra_lsp_server::req::{Runnables, RunnablesParams}; + +use support::project; + + +const LOG: &'static str = ""; + +#[test] +fn test_runnables_no_project() { + let server = project(r" +//- lib.rs +#[test] +fn foo() { +} +"); + server.request::( + RunnablesParams { + text_document: server.doc_id("lib.rs"), + position: None, + }, + r#"[ + { + "args": [ "test", "--", "foo", "--nocapture" ], + "bin": "cargo", + "env": { "RUST_BACKTRACE": "short" }, + "label": "test foo", + "range": { + "end": { "character": 1, "line": 2 }, + "start": { "character": 0, "line": 0 } + } + } + ]"# + ); +} + +#[test] +fn test_runnables_project() { + let server = project(r#" +//- Cargo.toml +[package] +name = "foo" +version = "0.0.0" + +//- src/lib.rs +pub fn foo() {} + +//- tests/spam.rs +#[test] +fn test_eggs() {} +"#); + server.wait_for_feedback("workspace loaded"); + server.request::( + RunnablesParams { + text_document: server.doc_id("tests/spam.rs"), + position: None, + }, + r#"[ + { + "args": [ "test", "--package", "foo", "--test", "spam", "--", "test_eggs", "--nocapture" ], + "bin": "cargo", + "env": { "RUST_BACKTRACE": "short" }, + "label": "test test_eggs", + "range": { + "end": { "character": 17, "line": 1 }, + "start": { "character": 0, "line": 0 } + } + } + ]"# + ); +} + +// #[test] +// fn test_deps() { +// let server = project(r#" +// //- Cargo.toml +// [package] +// name = "foo" +// version = "0.0.0" +// [dependencies] +// regex = "=1.0.4" + +// //- src/lib.rs +// extern crate regex; +// "#); +// server.wait_for_feedback("workspace loaded"); +// server.wait_for_feedback_n("library loaded", 9); +// } diff --git a/crates/ra_lsp_server/tests/heavy_tests/support.rs b/crates/ra_lsp_server/tests/heavy_tests/support.rs new file mode 100644 index 000000000..8fe2aa816 --- /dev/null +++ b/crates/ra_lsp_server/tests/heavy_tests/support.rs @@ -0,0 +1,217 @@ +use std::{ + fs, + cell::{Cell, RefCell}, + path::PathBuf, + time::Duration, + sync::Once, +}; + +use tempdir::TempDir; +use crossbeam_channel::{after, Receiver}; +use flexi_logger::Logger; +use languageserver_types::{ + Url, + TextDocumentIdentifier, + request::{Request, Shutdown}, + notification::DidOpenTextDocument, + DidOpenTextDocumentParams, + TextDocumentItem, +}; +use serde::Serialize; +use serde_json::{Value, from_str, to_string_pretty}; +use gen_lsp_server::{RawMessage, RawRequest, RawNotification}; + +use ra_lsp_server::{main_loop, req, thread_watcher::{ThreadWatcher, Worker}}; + +pub fn project(fixture: &str) -> Server { + static INIT: Once = Once::new(); + INIT.call_once(|| Logger::with_env_or_str(::LOG).start().unwrap()); + + let tmp_dir = TempDir::new("test-project") + .unwrap(); + let mut buf = String::new(); + let mut file_name = None; + let mut paths = vec![]; + macro_rules! flush { + () => { + if let Some(file_name) = file_name { + let path = tmp_dir.path().join(file_name); + fs::create_dir_all(path.parent().unwrap()).unwrap(); + fs::write(path.as_path(), buf.as_bytes()).unwrap(); + paths.push((path, buf.clone())); + } + } + }; + for line in fixture.lines() { + if line.starts_with("//-") { + flush!(); + buf.clear(); + file_name = Some(line["//-".len()..].trim()); + continue; + } + buf.push_str(line); + buf.push('\n'); + } + flush!(); + Server::new(tmp_dir, paths) +} + +pub struct Server { + req_id: Cell, + messages: RefCell>, + dir: TempDir, + worker: Option>, + watcher: Option, +} + +impl Server { + fn new(dir: TempDir, files: Vec<(PathBuf, String)>) -> Server { + let path = dir.path().to_path_buf(); + let (worker, watcher) = Worker::::spawn( + "test server", + 128, + move |mut msg_receiver, mut msg_sender| { + main_loop(true, path, &mut msg_receiver, &mut msg_sender) + .unwrap() + } + ); + let res = Server { + req_id: Cell::new(1), + dir, + messages: Default::default(), + worker: Some(worker), + watcher: Some(watcher), + }; + + for (path, text) in files { + res.send_notification(RawNotification::new::( + &DidOpenTextDocumentParams { + text_document: TextDocumentItem { + uri: Url::from_file_path(path).unwrap(), + language_id: "rust".to_string(), + version: 0, + text, + } + } + )) + } + res + } + + pub fn doc_id(&self, rel_path: &str) -> TextDocumentIdentifier { + let path = self.dir.path().join(rel_path); + TextDocumentIdentifier { + uri: Url::from_file_path(path).unwrap(), + } + } + + pub fn request( + &self, + params: R::Params, + expected_resp: &str, + ) + where + R: Request, + R::Params: Serialize, + { + let id = self.req_id.get(); + self.req_id.set(id + 1); + let expected_resp: Value = from_str(expected_resp).unwrap(); + let actual = self.send_request::(id, params); + assert_eq!( + expected_resp, actual, + "Expected:\n{}\n\ + Actual:\n{}\n", + to_string_pretty(&expected_resp).unwrap(), + to_string_pretty(&actual).unwrap(), + ); + } + + fn send_request(&self, id: u64, params: R::Params) -> Value + where + R: Request, + R::Params: Serialize, + { + let r = RawRequest::new::(id, ¶ms); + self.send_request_(r) + } + fn send_request_(&self, r: RawRequest) -> Value + { + let id = r.id; + self.worker.as_ref() + .unwrap() + .send(RawMessage::Request(r)); + while let Some(msg) = self.recv() { + match msg { + RawMessage::Request(req) => panic!("unexpected request: {:?}", req), + RawMessage::Notification(_) => (), + RawMessage::Response(res) => { + assert_eq!(res.id, id); + if let Some(err) = res.error { + panic!("error response: {:#?}", err); + } + return res.result.unwrap(); + } + } + } + panic!("no response"); + } + pub fn wait_for_feedback(&self, feedback: &str) { + self.wait_for_feedback_n(feedback, 1) + } + pub fn wait_for_feedback_n(&self, feedback: &str, n: usize) { + let f = |msg: &RawMessage| match msg { + RawMessage::Notification(n) if n.method == "internalFeedback" => { + return n.clone().cast::() + .unwrap() == feedback + } + _ => false, + }; + let mut total = 0; + for msg in self.messages.borrow().iter() { + if f(msg) { + total += 1 + } + } + while total < n { + let msg = self.recv().expect("no response"); + if f(&msg) { + total += 1; + } + } + } + fn recv(&self) -> Option { + recv_timeout(&self.worker.as_ref().unwrap().out) + .map(|msg| { + self.messages.borrow_mut().push(msg.clone()); + msg + }) + } + fn send_notification(&self, not: RawNotification) { + self.worker.as_ref() + .unwrap() + .send(RawMessage::Notification(not)); + } +} + +impl Drop for Server { + fn drop(&mut self) { + self.send_request::(666, ()); + let receiver = self.worker.take().unwrap().stop(); + while let Some(msg) = recv_timeout(&receiver) { + drop(msg); + } + self.watcher.take() + .unwrap() + .stop() + .unwrap(); + } +} + +fn recv_timeout(receiver: &Receiver) -> Option { + let timeout = Duration::from_secs(5); + select! { + recv(receiver, msg) => msg, + recv(after(timeout)) => panic!("timed out"), + } +} -- cgit v1.2.3