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

Commit 62da6cc

Browse files
committed
Added integration tests, added back test_simple_workspace
1 parent 37cbfc9 commit 62da6cc

File tree

4 files changed

+580
-0
lines changed

4 files changed

+580
-0
lines changed

tests/support/harness.rs

+164
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use std::io::{self, BufRead, BufReader, Read, Write};
12+
use std::mem;
13+
use std::process::{Child, ChildStdin, ChildStdout};
14+
15+
use serde_json;
16+
17+
#[derive(Clone, Debug)]
18+
pub struct ExpectedMessage {
19+
id: Option<u64>,
20+
contains: Vec<String>,
21+
}
22+
23+
impl ExpectedMessage {
24+
pub fn new(id: Option<u64>) -> ExpectedMessage {
25+
ExpectedMessage {
26+
id: id,
27+
contains: vec![],
28+
}
29+
}
30+
31+
pub fn expect_contains(&mut self, s: &str) -> &mut ExpectedMessage {
32+
self.contains.push(s.to_owned());
33+
self
34+
}
35+
}
36+
37+
pub fn read_message<R: Read>(reader: &mut BufReader<R>) -> io::Result<String> {
38+
let mut content_length = None;
39+
// Read the headers
40+
loop {
41+
let mut header = String::new();
42+
reader.read_line(&mut header)?;
43+
if header.len() == 0 {
44+
panic!("eof")
45+
}
46+
if header == "\r\n" {
47+
// This is the end of the headers
48+
break;
49+
}
50+
let parts: Vec<&str> = header.splitn(2, ": ").collect();
51+
if parts[0] == "Content-Length" {
52+
content_length = Some(parts[1].trim().parse::<usize>().unwrap())
53+
}
54+
}
55+
56+
// Read the actual message
57+
let content_length = content_length.expect("did not receive Content-Length header");
58+
let mut msg = vec![0; content_length];
59+
reader.read_exact(&mut msg)?;
60+
let result = String::from_utf8_lossy(&msg).into_owned();
61+
Ok(result)
62+
}
63+
64+
pub fn expect_messages<R: Read>(reader: &mut BufReader<R>, expected: &[&ExpectedMessage]) {
65+
let mut results: Vec<String> = Vec::new();
66+
while results.len() < expected.len() {
67+
results.push(read_message(reader).unwrap());
68+
}
69+
70+
println!(
71+
"expect_messages:\n results: {:#?},\n expected: {:#?}",
72+
results,
73+
expected
74+
);
75+
assert_eq!(results.len(), expected.len());
76+
for (found, expected) in results.iter().zip(expected.iter()) {
77+
let values: serde_json::Value = serde_json::from_str(found).unwrap();
78+
assert!(
79+
values
80+
.get("jsonrpc")
81+
.expect("Missing jsonrpc field")
82+
.as_str()
83+
.unwrap() == "2.0",
84+
"Bad jsonrpc field"
85+
);
86+
if let Some(id) = expected.id {
87+
assert_eq!(
88+
values
89+
.get("id")
90+
.expect("Missing id field")
91+
.as_u64()
92+
.unwrap(),
93+
id,
94+
"Unexpected id"
95+
);
96+
}
97+
for c in expected.contains.iter() {
98+
found
99+
.find(c)
100+
.expect(&format!("Could not find `{}` in `{}`", c, found));
101+
}
102+
}
103+
}
104+
105+
pub struct RlsHandle {
106+
child: Child,
107+
stdin: ChildStdin,
108+
stdout: BufReader<ChildStdout>,
109+
}
110+
111+
impl RlsHandle {
112+
pub fn new(mut child: Child) -> RlsHandle {
113+
let stdin = mem::replace(&mut child.stdin, None).unwrap();
114+
let stdout = mem::replace(&mut child.stdout, None).unwrap();
115+
let stdout = BufReader::new(stdout);
116+
117+
RlsHandle {
118+
child,
119+
stdin,
120+
stdout,
121+
}
122+
}
123+
124+
pub fn send_string(&mut self, s: &str) -> io::Result<usize> {
125+
let full_msg = format!("Content-Length: {}\r\n\r\n{}", s.len(), s);
126+
self.stdin.write(full_msg.as_bytes())
127+
}
128+
pub fn send(&mut self, j: serde_json::Value) -> io::Result<usize> {
129+
self.send_string(&j.to_string())
130+
}
131+
pub fn notify(&mut self, method: &str, params: serde_json::Value) -> io::Result<usize> {
132+
self.send(json!({
133+
"jsonrpc": "2.0",
134+
"method": method,
135+
"params": params,
136+
}))
137+
}
138+
pub fn request(&mut self, id: u64, method: &str, params: serde_json::Value) -> io::Result<usize> {
139+
self.send(json!({
140+
"jsonrpc": "2.0",
141+
"id": id,
142+
"method": method,
143+
"params": params,
144+
}))
145+
}
146+
pub fn shutdown_exit(&mut self) {
147+
self.request(99999, "shutdown", json!({})).unwrap();
148+
149+
self.expect_messages(&[
150+
&ExpectedMessage::new(Some(99999)),
151+
]);
152+
153+
self.notify("exit", json!({})).unwrap();
154+
155+
let ecode = self.child.wait()
156+
.expect("failed to wait on child rls process");
157+
158+
assert!(ecode.success());
159+
}
160+
161+
pub fn expect_messages(&mut self, expected: &[&ExpectedMessage]) {
162+
expect_messages(&mut self.stdout, expected);
163+
}
164+
}

tests/support/mod.rs

+168
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use std::env;
12+
use std::fs;
13+
use std::io::prelude::*;
14+
use std::path::{Path, PathBuf};
15+
use std::process::{Command, Stdio};
16+
use std::str;
17+
18+
use support::paths::TestPathExt;
19+
20+
pub mod harness;
21+
pub mod paths;
22+
23+
#[derive(PartialEq,Clone)]
24+
struct FileBuilder {
25+
path: PathBuf,
26+
body: String
27+
}
28+
29+
impl FileBuilder {
30+
pub fn new(path: PathBuf, body: &str) -> FileBuilder {
31+
FileBuilder { path: path, body: body.to_string() }
32+
}
33+
34+
fn mk(&self) {
35+
self.dirname().mkdir_p();
36+
37+
let mut file = fs::File::create(&self.path).unwrap_or_else(|e| {
38+
panic!("could not create file {}: {}", self.path.display(), e)
39+
});
40+
41+
file.write_all(self.body.as_bytes()).unwrap();
42+
}
43+
44+
fn dirname(&self) -> &Path {
45+
self.path.parent().unwrap()
46+
}
47+
}
48+
49+
#[derive(PartialEq,Clone)]
50+
pub struct Project{
51+
root: PathBuf,
52+
}
53+
54+
#[must_use]
55+
#[derive(PartialEq,Clone)]
56+
pub struct ProjectBuilder {
57+
name: String,
58+
root: Project,
59+
files: Vec<FileBuilder>,
60+
}
61+
62+
impl ProjectBuilder {
63+
pub fn new(name: &str, root: PathBuf) -> ProjectBuilder {
64+
ProjectBuilder {
65+
name: name.to_string(),
66+
root: Project{ root },
67+
files: vec![],
68+
}
69+
}
70+
71+
pub fn file<B: AsRef<Path>>(mut self, path: B,
72+
body: &str) -> Self {
73+
self._file(path.as_ref(), body);
74+
self
75+
}
76+
77+
fn _file(&mut self, path: &Path, body: &str) {
78+
self.files.push(FileBuilder::new(self.root.root.join(path), body));
79+
}
80+
81+
pub fn build(self) -> Project {
82+
// First, clean the directory if it already exists
83+
self.rm_root();
84+
85+
// Create the empty directory
86+
self.root.root.mkdir_p();
87+
88+
for file in self.files.iter() {
89+
file.mk();
90+
}
91+
92+
let ProjectBuilder{ name: _, root, files: _, .. } = self;
93+
root
94+
}
95+
96+
fn rm_root(&self) {
97+
self.root.root.rm_rf()
98+
}
99+
}
100+
101+
impl Project {
102+
pub fn root(&self) -> PathBuf {
103+
self.root.clone()
104+
}
105+
106+
pub fn rls(&self) -> Command {
107+
let mut cmd = Command::new(rls_exe());
108+
cmd.stdin(Stdio::piped())
109+
.stdout(Stdio::piped())
110+
.current_dir(self.root());
111+
cmd
112+
}
113+
}
114+
115+
// Generates a project layout
116+
pub fn project(name: &str) -> ProjectBuilder {
117+
ProjectBuilder::new(name, paths::root().join(name))
118+
}
119+
120+
// Path to cargo executables
121+
pub fn target_conf_dir() -> PathBuf {
122+
let mut path = env::current_exe().unwrap();
123+
path.pop();
124+
if path.ends_with("deps") {
125+
path.pop();
126+
}
127+
path
128+
}
129+
130+
pub fn rls_exe() -> PathBuf {
131+
target_conf_dir().join(format!("rls{}", env::consts::EXE_SUFFIX))
132+
}
133+
134+
pub fn main_file(println: &str, deps: &[&str]) -> String {
135+
let mut buf = String::new();
136+
137+
for dep in deps.iter() {
138+
buf.push_str(&format!("extern crate {};\n", dep));
139+
}
140+
141+
buf.push_str("fn main() { println!(");
142+
buf.push_str(&println);
143+
buf.push_str("); }\n");
144+
145+
buf.to_string()
146+
}
147+
148+
pub fn basic_bin_manifest(name: &str) -> String {
149+
format!(r#"
150+
[package]
151+
name = "{}"
152+
version = "0.5.0"
153+
authors = ["[email protected]"]
154+
[[bin]]
155+
name = "{}"
156+
"#, name, name)
157+
}
158+
159+
pub fn basic_lib_manifest(name: &str) -> String {
160+
format!(r#"
161+
[package]
162+
name = "{}"
163+
version = "0.5.0"
164+
authors = ["[email protected]"]
165+
[lib]
166+
name = "{}"
167+
"#, name, name)
168+
}

0 commit comments

Comments
 (0)