Skip to content

Commit a3888fd

Browse files
committed
Auto merge of rust-lang#14579 - KatKlo:initialization-bug, r=Veykril
Fix bug with notifications during initialization
2 parents c088958 + 1db2a25 commit a3888fd

File tree

2 files changed

+71
-1
lines changed

2 files changed

+71
-1
lines changed

lib/lsp-server/src/error.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::fmt;
22

33
use crate::{Notification, Request};
44

5-
#[derive(Debug, Clone)]
5+
#[derive(Debug, Clone, PartialEq)]
66
pub struct ProtocolError(pub(crate) String);
77

88
impl std::error::Error for ProtocolError {}

lib/lsp-server/src/lib.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ impl Connection {
126126
self.sender.send(resp.into()).unwrap();
127127
continue;
128128
}
129+
Ok(Message::Notification(n)) if !n.is_exit() => {
130+
continue;
131+
}
129132
Ok(msg) => Err(ProtocolError(format!("expected initialize request, got {msg:?}"))),
130133
Err(e) => {
131134
Err(ProtocolError(format!("expected initialize request, got error: {e}")))
@@ -212,3 +215,70 @@ impl Connection {
212215
Ok(true)
213216
}
214217
}
218+
219+
#[cfg(test)]
220+
mod tests {
221+
use crossbeam_channel::unbounded;
222+
use lsp_types::notification::{Exit, Initialized, Notification};
223+
use lsp_types::request::{Initialize, Request};
224+
use lsp_types::{InitializeParams, InitializedParams};
225+
use serde_json::to_value;
226+
227+
use crate::{Connection, Message, ProtocolError, RequestId};
228+
229+
struct TestCase {
230+
test_messages: Vec<Message>,
231+
expected_resp: Result<(RequestId, serde_json::Value), ProtocolError>,
232+
}
233+
234+
fn initialize_start_test(test_case: TestCase) {
235+
let (reader_sender, reader_receiver) = unbounded::<Message>();
236+
let (writer_sender, writer_receiver) = unbounded::<Message>();
237+
let conn = Connection { sender: writer_sender, receiver: reader_receiver };
238+
239+
for msg in test_case.test_messages {
240+
assert!(reader_sender.send(msg).is_ok());
241+
}
242+
243+
let resp = conn.initialize_start();
244+
assert_eq!(test_case.expected_resp, resp);
245+
246+
assert!(writer_receiver.recv_timeout(std::time::Duration::from_secs(1)).is_err());
247+
}
248+
249+
#[test]
250+
fn not_exit_notification() {
251+
let notification = crate::Notification {
252+
method: Initialized::METHOD.to_string(),
253+
params: to_value(InitializedParams {}).unwrap(),
254+
};
255+
256+
let params_as_value = to_value(InitializeParams::default()).unwrap();
257+
let req_id = RequestId::from(234);
258+
let request = crate::Request {
259+
id: req_id.clone(),
260+
method: Initialize::METHOD.to_string(),
261+
params: params_as_value.clone(),
262+
};
263+
264+
initialize_start_test(TestCase {
265+
test_messages: vec![notification.into(), request.into()],
266+
expected_resp: Ok((req_id, params_as_value)),
267+
});
268+
}
269+
270+
#[test]
271+
fn exit_notification() {
272+
let notification =
273+
crate::Notification { method: Exit::METHOD.to_string(), params: to_value(()).unwrap() };
274+
let notification_msg = Message::from(notification);
275+
276+
initialize_start_test(TestCase {
277+
test_messages: vec![notification_msg.clone()],
278+
expected_resp: Err(ProtocolError(format!(
279+
"expected initialize request, got {:?}",
280+
notification_msg
281+
))),
282+
});
283+
}
284+
}

0 commit comments

Comments
 (0)