Skip to content
This repository was archived by the owner on Dec 29, 2022. It is now read-only.

Commit 3a39ba3

Browse files
committed
Improved tests
1 parent 41e40a0 commit 3a39ba3

File tree

2 files changed

+248
-29
lines changed

2 files changed

+248
-29
lines changed

tests/support/mod.rs

Lines changed: 93 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,29 @@ pub struct ExpectedMessage {
7171
contains: Vec<String>,
7272
}
7373

74+
#[derive(Debug)]
75+
pub enum MsgMatchError {
76+
ParseError,
77+
MissingJsonrpc,
78+
BadJsonrpc,
79+
MissingId,
80+
BadId,
81+
StringNotFound(String, String),
82+
}
83+
84+
impl<'a, 'b> ToString for MsgMatchError {
85+
fn to_string(&self) -> String {
86+
match self {
87+
MsgMatchError::ParseError => "JSON parsing failed".into(),
88+
MsgMatchError::MissingJsonrpc => "Missing jsonrpc field".into(),
89+
MsgMatchError::BadJsonrpc => "Bad jsonrpc field".into(),
90+
MsgMatchError::MissingId => "Missing id field".into(),
91+
MsgMatchError::BadId => "Unexpected id".into(),
92+
MsgMatchError::StringNotFound(n, h) => format!("Could not find `{}` in `{}`", n, h),
93+
}
94+
}
95+
}
96+
7497
impl ExpectedMessage {
7598
pub fn new(id: Option<u64>) -> ExpectedMessage {
7699
ExpectedMessage {
@@ -83,6 +106,36 @@ impl ExpectedMessage {
83106
self.contains.push(s.to_owned());
84107
self
85108
}
109+
110+
// Err is the expected message that was not found in the given string.
111+
pub fn try_match(&self, msg: &str) -> Result<(), MsgMatchError> {
112+
use self::MsgMatchError::*;
113+
114+
let values: serde_json::Value = serde_json::from_str(msg).map_err(|_| ParseError)?;
115+
let jsonrpc = values.get("jsonrpc").ok_or(MissingJsonrpc)?;
116+
if jsonrpc != "2.0" {
117+
return Err(BadJsonrpc);
118+
}
119+
120+
if let Some(id) = self.id {
121+
let values_id = values.get("id").ok_or(MissingId)?;
122+
if id != values_id.as_u64().unwrap() {
123+
return Err(BadId)
124+
};
125+
}
126+
127+
self.try_match_raw(msg)
128+
}
129+
130+
pub fn try_match_raw(&self, s: &str) -> Result<(), MsgMatchError> {
131+
for c in &self.contains {
132+
s
133+
.find(c)
134+
.ok_or(MsgMatchError::StringNotFound(c.to_owned(), s.to_owned()))
135+
.map(|_| ())?;
136+
}
137+
Ok(())
138+
}
86139
}
87140

88141
pub fn read_message<R: Read>(reader: &mut BufReader<R>) -> io::Result<String> {
@@ -112,12 +165,12 @@ pub fn read_message<R: Read>(reader: &mut BufReader<R>) -> io::Result<String> {
112165
Ok(result)
113166
}
114167

168+
pub fn read_messages<R: Read>(reader: &mut BufReader<R>, count: usize) -> Vec<String> {
169+
(0..count).map(|_| read_message(reader).unwrap()).collect()
170+
}
171+
115172
pub fn expect_messages<R: Read>(reader: &mut BufReader<R>, expected: &[&ExpectedMessage]) {
116-
let mut results: Vec<String> = Vec::new();
117-
while results.len() < expected.len() {
118-
let msg = read_message(reader).unwrap();
119-
results.push(msg);
120-
}
173+
let results = read_messages(reader, expected.len());
121174

122175
println!(
123176
"expect_messages:\n results: {:#?},\n expected: {:#?}",
@@ -126,30 +179,38 @@ pub fn expect_messages<R: Read>(reader: &mut BufReader<R>, expected: &[&Expected
126179
);
127180
assert_eq!(results.len(), expected.len());
128181
for (found, expected) in results.iter().zip(expected.iter()) {
129-
let values: serde_json::Value = serde_json::from_str(found).unwrap();
130-
assert!(
131-
values
132-
.get("jsonrpc")
133-
.expect("Missing jsonrpc field")
134-
.as_str()
135-
.unwrap() == "2.0",
136-
"Bad jsonrpc field"
137-
);
138-
if let Some(id) = expected.id {
139-
assert_eq!(
140-
values
141-
.get("id")
142-
.expect("Missing id field")
143-
.as_u64()
144-
.unwrap(),
145-
id,
146-
"Unexpected id"
147-
);
182+
if let Err(err) = expected.try_match(&found) {
183+
panic!(err.to_string());
148184
}
149-
for c in &expected.contains {
150-
found
151-
.find(c)
152-
.expect(&format!("Could not find `{}` in `{}`", c, found));
185+
}
186+
}
187+
188+
pub fn expect_messages_unordered<R: Read>(reader: &mut BufReader<R>, expected: &[&ExpectedMessage]) {
189+
let mut results = read_messages(reader, expected.len());
190+
let mut expected: Vec<&ExpectedMessage> = expected.to_owned();
191+
192+
println!(
193+
"expect_messages_unordered:\n results: {:#?},\n expected: {:#?}",
194+
results,
195+
expected
196+
);
197+
assert_eq!(results.len(), expected.len());
198+
199+
while !results.is_empty() && !expected.is_empty() {
200+
let first = expected[0];
201+
202+
let opt = results.iter()
203+
.map(|r| first.try_match(r))
204+
.enumerate()
205+
.find(|(_, res)| res.is_ok());
206+
207+
match opt {
208+
Some((idx, Ok(()))) => {
209+
expected.remove(0);
210+
results.remove(idx);
211+
},
212+
Some((_, Err(err))) => panic!(err.to_string()),
213+
None => panic!(format!("Could not find `{:?}` among `{:?}", first, results))
153214
}
154215
}
155216
}
@@ -232,6 +293,10 @@ impl RlsHandle {
232293
pub fn expect_messages(&mut self, expected: &[&ExpectedMessage]) {
233294
expect_messages(&mut self.stdout, expected);
234295
}
296+
297+
pub fn expect_messages_unordered(&mut self, expected: &[&ExpectedMessage]) {
298+
expect_messages_unordered(&mut self.stdout, expected);
299+
}
235300
}
236301

237302
#[derive(PartialEq,Clone)]

tests/tests.rs

Lines changed: 155 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ fn cmd_test_infer_bin() {
5858

5959
#[test]
6060
fn cmd_test_simple_workspace() {
61-
timeout(Duration::from_secs(300), ||{
61+
timeout(Duration::from_secs(TIME_LIMIT_SECS), ||{
6262
let p = project("simple_workspace")
6363
.file("Cargo.toml", r#"
6464
[workspace]
@@ -144,3 +144,157 @@ fn cmd_test_simple_workspace() {
144144
rls.shutdown_exit();
145145
});
146146
}
147+
148+
#[test]
149+
fn changing_workspace_lib_retains_bin_diagnostics() {
150+
timeout(Duration::from_secs(TIME_LIMIT_SECS), ||{
151+
let p = project("simple_workspace")
152+
.file("Cargo.toml", r#"
153+
[workspace]
154+
members = [
155+
"library",
156+
"binary",
157+
]
158+
"#)
159+
.file("library/Cargo.toml", r#"
160+
[package]
161+
name = "library"
162+
version = "0.1.0"
163+
authors = ["Example <[email protected]>"]
164+
"#)
165+
.file("library/src/lib.rs", r#"
166+
pub fn fetch_u32() -> u32 {
167+
let unused = ();
168+
42
169+
}
170+
"#)
171+
.file("binary/Cargo.toml", r#"
172+
[package]
173+
name = "binary"
174+
version = "0.1.0"
175+
authors = ["Igor Matuszewski <[email protected]>"]
176+
177+
[dependencies]
178+
library = { path = "../library" }
179+
"#)
180+
.file("binary/src/main.rs", r#"
181+
extern crate library;
182+
183+
fn main() {
184+
let val: u32 = library::fetch_u32();
185+
}
186+
"#)
187+
.build();
188+
189+
let root_path = p.root();
190+
let rls_child = p.rls().spawn().unwrap();
191+
let mut rls = RlsHandle::new(rls_child);
192+
193+
rls.request(0, "initialize", Some(json!({
194+
"rootPath": root_path,
195+
"capabilities": {}
196+
}))).unwrap();
197+
198+
rls.expect_messages(&[
199+
ExpectedMessage::new(Some(0)).expect_contains("capabilities"),
200+
ExpectedMessage::new(None).expect_contains("progress").expect_contains(r#"title":"Building""#),
201+
ExpectedMessage::new(None).expect_contains("progress"),
202+
ExpectedMessage::new(None).expect_contains("progress"),
203+
ExpectedMessage::new(None).expect_contains("progress"),
204+
ExpectedMessage::new(None).expect_contains("progress"),
205+
ExpectedMessage::new(None).expect_contains("progress").expect_contains(r#""done":true"#),
206+
ExpectedMessage::new(None).expect_contains("progress").expect_contains(r#"title":"Indexing""#),
207+
]);
208+
rls.expect_messages_unordered(&[
209+
ExpectedMessage::new(None).expect_contains("publishDiagnostics").expect_contains("library/src/lib.rs")
210+
.expect_contains("unused variable: `unused`"),
211+
ExpectedMessage::new(None).expect_contains("publishDiagnostics").expect_contains("binary/src/main.rs")
212+
.expect_contains("unused variable: `val`"),
213+
]);
214+
rls.expect_messages(&[
215+
ExpectedMessage::new(None).expect_contains("progress").expect_contains(r#""done":true"#),
216+
]);
217+
218+
rls.notify("textDocument/didChange", Some(json!({
219+
"contentChanges": [
220+
{
221+
"range": {
222+
"start": {
223+
"line": 1,
224+
"character": 38,
225+
},
226+
"end": {
227+
"line": 1,
228+
"character": 41,
229+
}
230+
},
231+
"rangeLength": 3,
232+
"text": "invalid_return_type"
233+
}
234+
],
235+
"textDocument": {
236+
"uri": format!("file://{}/library/src/lib.rs", root_path.as_path().display()),
237+
"version": 0
238+
}
239+
}))).unwrap();
240+
241+
rls.expect_messages(&[
242+
ExpectedMessage::new(None).expect_contains("progress").expect_contains(r#"title":"Building""#),
243+
ExpectedMessage::new(None).expect_contains("progress").expect_contains(r#"title":"Building""#),
244+
ExpectedMessage::new(None).expect_contains("progress").expect_contains(r#"title":"Building""#),
245+
ExpectedMessage::new(None).expect_contains("progress").expect_contains(r#"title":"Building""#).expect_contains(r#""done":true"#),
246+
ExpectedMessage::new(None).expect_contains("progress").expect_contains(r#"title":"Indexing""#),
247+
]);
248+
rls.expect_messages_unordered(&[
249+
ExpectedMessage::new(None).expect_contains("publishDiagnostics").expect_contains("library/src/lib.rs")
250+
.expect_contains("cannot find type `invalid_return_type` in this scope"),
251+
ExpectedMessage::new(None).expect_contains("publishDiagnostics").expect_contains("binary/src/main.rs")
252+
.expect_contains("unused variable: `val`"),
253+
]);
254+
rls.expect_messages(&[
255+
ExpectedMessage::new(None).expect_contains("progress").expect_contains(r#"title":"Indexing""#).expect_contains(r#""done":true"#),
256+
]);
257+
258+
rls.notify("textDocument/didChange", Some(json!({
259+
"contentChanges": [
260+
{
261+
"range": {
262+
"start": {
263+
"line": 1,
264+
"character": 38,
265+
},
266+
"end": {
267+
"line": 1,
268+
"character": 57,
269+
}
270+
},
271+
"rangeLength": 19,
272+
"text": "u32"
273+
}
274+
],
275+
"textDocument": {
276+
"uri": format!("file://{}/library/src/lib.rs", root_path.as_path().display()),
277+
"version": 1
278+
}
279+
}))).unwrap();
280+
281+
rls.expect_messages(&[
282+
ExpectedMessage::new(None).expect_contains("progress").expect_contains(r#"title":"Building""#),
283+
ExpectedMessage::new(None).expect_contains("progress").expect_contains(r#"title":"Building""#),
284+
ExpectedMessage::new(None).expect_contains("progress").expect_contains(r#"title":"Building""#),
285+
ExpectedMessage::new(None).expect_contains("progress").expect_contains(r#"title":"Building""#).expect_contains(r#""done":true"#),
286+
ExpectedMessage::new(None).expect_contains("progress").expect_contains(r#"title":"Indexing""#),
287+
]);
288+
rls.expect_messages_unordered(&[
289+
ExpectedMessage::new(None).expect_contains("publishDiagnostics").expect_contains("library/src/lib.rs")
290+
.expect_contains("unused variable: `unused`"),
291+
ExpectedMessage::new(None).expect_contains("publishDiagnostics").expect_contains("binary/src/main.rs")
292+
.expect_contains("unused variable: `val`"),
293+
]);
294+
rls.expect_messages(&[
295+
ExpectedMessage::new(None).expect_contains("progress").expect_contains(r#"title":"Indexing""#).expect_contains(r#""done":true"#),
296+
]);
297+
298+
rls.shutdown_exit();
299+
});
300+
}

0 commit comments

Comments
 (0)