aboutsummaryrefslogtreecommitdiff
path: root/crates/server/tests/heavy_tests
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-09-01 18:21:11 +0100
committerAleksey Kladov <[email protected]>2018-09-01 18:21:11 +0100
commit541170420bb6f9a5c0e8d6f56865567fd8ae0f93 (patch)
treea58366d1c9412d3192fc636c7912dcb8514baab3 /crates/server/tests/heavy_tests
parente8515fecd7a42870f2979c7900c94b59d935901c (diff)
Add an integration test
Diffstat (limited to 'crates/server/tests/heavy_tests')
-rw-r--r--crates/server/tests/heavy_tests/main.rs42
-rw-r--r--crates/server/tests/heavy_tests/support.rs169
2 files changed, 211 insertions, 0 deletions
diff --git a/crates/server/tests/heavy_tests/main.rs b/crates/server/tests/heavy_tests/main.rs
new file mode 100644
index 000000000..94c8243b0
--- /dev/null
+++ b/crates/server/tests/heavy_tests/main.rs
@@ -0,0 +1,42 @@
1extern crate tempdir;
2extern crate crossbeam_channel;
3extern crate languageserver_types;
4extern crate serde;
5extern crate serde_json;
6extern crate gen_lsp_server;
7extern crate flexi_logger;
8extern crate m;
9
10mod support;
11
12use m::req::{Runnables, RunnablesParams};
13
14use support::project;
15
16#[test]
17fn test_runnables() {
18 let server = project(r"
19//- lib.rs
20#[test]
21fn foo() {
22}
23");
24 server.request::<Runnables>(
25 RunnablesParams {
26 text_document: server.doc_id("lib.rs"),
27 position: None,
28 },
29 r#"[
30 {
31 "args": [ "test", "--", "foo", "--nocapture" ],
32 "bin": "cargo",
33 "env": { "RUST_BACKTRACE": "short" },
34 "label": "test foo",
35 "range": {
36 "end": { "character": 1, "line": 2 },
37 "start": { "character": 0, "line": 0 }
38 }
39 }
40 ]"#
41 );
42}
diff --git a/crates/server/tests/heavy_tests/support.rs b/crates/server/tests/heavy_tests/support.rs
new file mode 100644
index 000000000..113ef4c54
--- /dev/null
+++ b/crates/server/tests/heavy_tests/support.rs
@@ -0,0 +1,169 @@
1use std::{
2 fs,
3 thread,
4 cell::Cell,
5 path::PathBuf,
6};
7
8use tempdir::TempDir;
9use crossbeam_channel::{bounded, Sender, Receiver};
10use flexi_logger::Logger;
11use languageserver_types::{
12 Url,
13 TextDocumentIdentifier,
14 request::{Request, Shutdown},
15 notification::DidOpenTextDocument,
16 DidOpenTextDocumentParams,
17 TextDocumentItem,
18};
19use serde::Serialize;
20use serde_json::{Value, from_str, to_string_pretty};
21use gen_lsp_server::{RawMessage, RawRequest, RawNotification};
22
23use m::{Result, main_loop};
24
25pub fn project(fixture: &str) -> Server {
26 Logger::with_env_or_str("").start().unwrap();
27
28 let tmp_dir = TempDir::new("test-project")
29 .unwrap();
30 let mut buf = String::new();
31 let mut file_name = None;
32 let mut paths = vec![];
33 macro_rules! flush {
34 () => {
35 if let Some(file_name) = file_name {
36 let path = tmp_dir.path().join(file_name);
37 fs::write(path.as_path(), buf.as_bytes()).unwrap();
38 paths.push((path, buf.clone()));
39 }
40 }
41 };
42 for line in fixture.lines() {
43 if line.starts_with("//-") {
44 flush!();
45 buf.clear();
46 file_name = Some(line["//-".len()..].trim());
47 continue;
48 }
49 buf.push_str(line);
50 buf.push('\n');
51 }
52 flush!();
53
54 Server::new(tmp_dir, paths)
55}
56
57pub struct Server {
58 req_id: Cell<u64>,
59 dir: TempDir,
60 sender: Option<Sender<RawMessage>>,
61 receiver: Receiver<RawMessage>,
62 server: Option<thread::JoinHandle<Result<()>>>,
63}
64
65impl Server {
66 fn new(dir: TempDir, files: Vec<(PathBuf, String)>) -> Server {
67 let path = dir.path().to_path_buf();
68 let (client_sender, mut server_receiver) = bounded(1);
69 let (mut server_sender, client_receiver) = bounded(1);
70 let server = thread::spawn(move || main_loop(path, &mut server_receiver, &mut server_sender));
71 let res = Server {
72 req_id: Cell::new(1),
73 dir,
74 sender: Some(client_sender),
75 receiver: client_receiver,
76 server: Some(server),
77 };
78 for (path, text) in files {
79 res.send_notification(RawNotification::new::<DidOpenTextDocument>(
80 DidOpenTextDocumentParams {
81 text_document: TextDocumentItem {
82 uri: Url::from_file_path(path).unwrap(),
83 language_id: "rust".to_string(),
84 version: 0,
85 text,
86 }
87 }
88 ))
89 }
90 res
91 }
92
93 pub fn doc_id(&self, rel_path: &str) -> TextDocumentIdentifier {
94 let path = self.dir.path().join(rel_path);
95 TextDocumentIdentifier {
96 uri: Url::from_file_path(path).unwrap(),
97 }
98 }
99
100 pub fn request<R>(
101 &self,
102 params: R::Params,
103 expected_resp: &str,
104 )
105 where
106 R: Request,
107 R::Params: Serialize,
108 {
109 let id = self.req_id.get();
110 self.req_id.set(id + 1);
111 let expected_resp: Value = from_str(expected_resp).unwrap();
112 let actual = self.send_request::<R>(id, params);
113 assert_eq!(
114 expected_resp, actual,
115 "Expected:\n{}\n\
116 Actual:\n{}\n",
117 to_string_pretty(&expected_resp).unwrap(),
118 to_string_pretty(&actual).unwrap(),
119 );
120 }
121
122 fn send_request<R>(&self, id: u64, params: R::Params) -> Value
123 where
124 R: Request,
125 R::Params: Serialize,
126 {
127 let r = RawRequest::new::<R>(id, params);
128 self.sender.as_ref()
129 .unwrap()
130 .send(RawMessage::Request(r));
131
132 while let Some(msg) = self.receiver.recv() {
133 match msg {
134 RawMessage::Request(req) => panic!("unexpected request: {:?}", req),
135 RawMessage::Notification(_) => (),
136 RawMessage::Response(res) => {
137 assert_eq!(res.id, id);
138 if let Some(err) = res.error {
139 panic!("error response: {:#?}", err);
140 }
141 return res.result.unwrap();
142 }
143 }
144 }
145 panic!("no response");
146 }
147 fn send_notification(&self, not: RawNotification) {
148
149 self.sender.as_ref()
150 .unwrap()
151 .send(RawMessage::Notification(not));
152 }
153}
154
155impl Drop for Server {
156 fn drop(&mut self) {
157 {
158 self.send_request::<Shutdown>(666, ());
159 drop(self.sender.take().unwrap());
160 while let Some(msg) = self.receiver.recv() {
161 drop(msg);
162 }
163 }
164 eprintln!("joining server");
165 self.server.take()
166 .unwrap()
167 .join().unwrap().unwrap();
168 }
169}