9 use crossbeam_channel::{after, select, Receiver};
10 use flexi_logger::Logger;
11 use gen_lsp_server::{RawMessage, RawNotification, RawRequest};
13 notification::DidOpenTextDocument,
14 request::{Request, Shutdown},
15 DidOpenTextDocumentParams, TextDocumentIdentifier, TextDocumentItem, Url,
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};
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());
31 let tmp_dir = TempDir::new().unwrap();
32 let mut paths = vec![];
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));
40 Server::new(tmp_dir, paths)
45 messages: RefCell<Vec<RawMessage>>,
47 worker: Option<Worker<RawMessage, RawMessage>>,
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(
56 move |mut msg_receiver, mut msg_sender| {
57 main_loop(true, path, true, &mut msg_receiver, &mut msg_sender).unwrap()
63 messages: Default::default(),
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(),
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() }
87 pub fn request<R>(&self, params: R::Params, expected_resp: Value)
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(),
105 pub fn send_request<R>(&self, params: R::Params) -> Value
108 R::Params: Serialize,
110 let id = self.req_id.get();
111 self.req_id.set(id + 1);
113 let r = RawRequest::new::<R>(id, ¶ms);
114 self.send_request_(r)
116 fn send_request_(&self, r: RawRequest) -> Value {
118 self.worker.as_ref().unwrap().sender().send(RawMessage::Request(r)).unwrap();
119 while let Some(msg) = self.recv() {
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);
128 return res.result.unwrap();
132 panic!("no response");
134 pub fn wait_for_feedback(&self, feedback: &str) {
135 self.wait_for_feedback_n(feedback, 1)
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;
145 for msg in self.messages.borrow().iter() {
151 let msg = self.recv().expect("no response");
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());
163 fn send_notification(&self, not: RawNotification) {
164 self.worker.as_ref().unwrap().sender().send(RawMessage::Notification(not)).unwrap();
168 impl Drop for Server {
170 self.send_request::<Shutdown>(());
174 fn recv_timeout(receiver: &Receiver<RawMessage>) -> Option<RawMessage> {
175 let timeout = Duration::from_secs(50);
177 recv(receiver) -> msg => msg.ok(),
178 recv(after(timeout)) -> _ => panic!("timed out"),