]> git.lizzy.rs Git - rust.git/blob - crates/ra_lsp_server/tests/heavy_tests/support.rs
11f94b4abaa8ed950c60417dd4e8ef8a9a5cbac7
[rust.git] / crates / ra_lsp_server / tests / heavy_tests / support.rs
1 use std::{
2     cell::{Cell, RefCell},
3     fs,
4     path::PathBuf,
5     sync::Once,
6     time::Duration,
7 };
8
9 use crossbeam_channel::{after, select, Receiver};
10 use flexi_logger::Logger;
11 use gen_lsp_server::{RawMessage, RawNotification, RawRequest};
12 use lsp_types::{
13     notification::DidOpenTextDocument,
14     request::{Request, Shutdown},
15     DidOpenTextDocumentParams, TextDocumentIdentifier, TextDocumentItem, Url,
16 };
17 use serde::Serialize;
18 use serde_json::{to_string_pretty, Value};
19 use tempfile::TempDir;
20 use thread_worker::Worker;
21 use test_utils::{parse_fixture, find_mismatch};
22
23 use ra_lsp_server::{
24     main_loop, req,
25 };
26
27 pub fn project(fixture: &str) -> Server {
28     static INIT: Once = Once::new();
29     INIT.call_once(|| Logger::with_env_or_str(crate::LOG).start().unwrap());
30
31     let tmp_dir = TempDir::new().unwrap();
32     let mut paths = vec![];
33
34     for entry in parse_fixture(fixture) {
35         let path = tmp_dir.path().join(entry.meta);
36         fs::create_dir_all(path.parent().unwrap()).unwrap();
37         fs::write(path.as_path(), entry.text.as_bytes()).unwrap();
38         paths.push((path, entry.text));
39     }
40     Server::new(tmp_dir, paths)
41 }
42
43 pub struct Server {
44     req_id: Cell<u64>,
45     messages: RefCell<Vec<RawMessage>>,
46     dir: TempDir,
47     worker: Option<Worker<RawMessage, RawMessage>>,
48 }
49
50 impl Server {
51     fn new(dir: TempDir, files: Vec<(PathBuf, String)>) -> Server {
52         let path = dir.path().to_path_buf();
53         let worker = Worker::<RawMessage, RawMessage>::spawn(
54             "test server",
55             128,
56             move |mut msg_receiver, mut msg_sender| {
57                 main_loop(true, path, true, &mut msg_receiver, &mut msg_sender).unwrap()
58             },
59         );
60         let res = Server {
61             req_id: Cell::new(1),
62             dir,
63             messages: Default::default(),
64             worker: Some(worker),
65         };
66
67         for (path, text) in files {
68             res.send_notification(RawNotification::new::<DidOpenTextDocument>(
69                 &DidOpenTextDocumentParams {
70                     text_document: TextDocumentItem {
71                         uri: Url::from_file_path(path).unwrap(),
72                         language_id: "rust".to_string(),
73                         version: 0,
74                         text,
75                     },
76                 },
77             ))
78         }
79         res
80     }
81
82     pub fn doc_id(&self, rel_path: &str) -> TextDocumentIdentifier {
83         let path = self.dir.path().join(rel_path);
84         TextDocumentIdentifier { uri: Url::from_file_path(path).unwrap() }
85     }
86
87     pub fn request<R>(&self, params: R::Params, expected_resp: Value)
88     where
89         R: Request,
90         R::Params: Serialize,
91     {
92         let actual = self.send_request::<R>(params);
93         match find_mismatch(&expected_resp, &actual) {
94             Some((expected_part, actual_part)) => panic!(
95                 "JSON mismatch\nExpected:\n{}\nWas:\n{}\nExpected part:\n{}\nActual part:\n{}\n",
96                 to_string_pretty(&expected_resp).unwrap(),
97                 to_string_pretty(&actual).unwrap(),
98                 to_string_pretty(expected_part).unwrap(),
99                 to_string_pretty(actual_part).unwrap(),
100             ),
101             None => {}
102         }
103     }
104
105     pub fn send_request<R>(&self, params: R::Params) -> Value
106     where
107         R: Request,
108         R::Params: Serialize,
109     {
110         let id = self.req_id.get();
111         self.req_id.set(id + 1);
112
113         let r = RawRequest::new::<R>(id, &params);
114         self.send_request_(r)
115     }
116     fn send_request_(&self, r: RawRequest) -> Value {
117         let id = r.id;
118         self.worker.as_ref().unwrap().sender().send(RawMessage::Request(r)).unwrap();
119         while let Some(msg) = self.recv() {
120             match msg {
121                 RawMessage::Request(req) => panic!("unexpected request: {:?}", req),
122                 RawMessage::Notification(_) => (),
123                 RawMessage::Response(res) => {
124                     assert_eq!(res.id, id);
125                     if let Some(err) = res.error {
126                         panic!("error response: {:#?}", err);
127                     }
128                     return res.result.unwrap();
129                 }
130             }
131         }
132         panic!("no response");
133     }
134     pub fn wait_for_feedback(&self, feedback: &str) {
135         self.wait_for_feedback_n(feedback, 1)
136     }
137     pub fn wait_for_feedback_n(&self, feedback: &str, n: usize) {
138         let f = |msg: &RawMessage| match msg {
139             RawMessage::Notification(n) if n.method == "internalFeedback" => {
140                 return n.clone().cast::<req::InternalFeedback>().unwrap() == feedback;
141             }
142             _ => false,
143         };
144         let mut total = 0;
145         for msg in self.messages.borrow().iter() {
146             if f(msg) {
147                 total += 1
148             }
149         }
150         while total < n {
151             let msg = self.recv().expect("no response");
152             if f(&msg) {
153                 total += 1;
154             }
155         }
156     }
157     fn recv(&self) -> Option<RawMessage> {
158         recv_timeout(&self.worker.as_ref().unwrap().receiver()).map(|msg| {
159             self.messages.borrow_mut().push(msg.clone());
160             msg
161         })
162     }
163     fn send_notification(&self, not: RawNotification) {
164         self.worker.as_ref().unwrap().sender().send(RawMessage::Notification(not)).unwrap();
165     }
166 }
167
168 impl Drop for Server {
169     fn drop(&mut self) {
170         self.send_request::<Shutdown>(());
171     }
172 }
173
174 fn recv_timeout(receiver: &Receiver<RawMessage>) -> Option<RawMessage> {
175     let timeout = Duration::from_secs(50);
176     select! {
177         recv(receiver) -> msg => msg.ok(),
178         recv(after(timeout)) -> _ => panic!("timed out"),
179     }
180 }