2014-12-21 23:19:44 +00:00
|
|
|
use std::error::Error;
|
2015-02-06 07:27:53 +00:00
|
|
|
use std::env;
|
2015-01-13 16:41:04 +00:00
|
|
|
use std::fmt;
|
2015-01-30 13:48:43 +00:00
|
|
|
use std::old_io::fs::{self, PathExtensions};
|
|
|
|
use std::old_io::process::{ProcessOutput};
|
|
|
|
use std::old_io;
|
2015-02-06 07:27:53 +00:00
|
|
|
use std::old_path::{Path, BytesContainer};
|
2015-01-04 09:02:16 +00:00
|
|
|
use std::str::{self, Str};
|
2014-12-21 23:19:44 +00:00
|
|
|
|
2014-08-06 16:21:10 +00:00
|
|
|
use url::Url;
|
2014-08-19 04:54:12 +00:00
|
|
|
use hamcrest as ham;
|
2014-06-19 08:21:24 +00:00
|
|
|
use cargo::util::{process,ProcessBuilder};
|
2014-06-19 07:55:17 +00:00
|
|
|
use cargo::util::ProcessError;
|
2014-03-19 01:10:48 +00:00
|
|
|
|
2014-06-27 21:06:50 +00:00
|
|
|
use support::paths::PathExt;
|
|
|
|
|
2014-06-12 22:51:16 +00:00
|
|
|
pub mod paths;
|
2014-09-09 14:23:09 +00:00
|
|
|
pub mod git;
|
2014-10-23 05:05:30 +00:00
|
|
|
pub mod registry;
|
2014-03-19 01:10:48 +00:00
|
|
|
|
2014-03-20 22:17:19 +00:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* ===== Builders =====
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2015-01-04 09:02:16 +00:00
|
|
|
#[derive(PartialEq,Clone)]
|
2014-03-19 01:10:48 +00:00
|
|
|
struct FileBuilder {
|
|
|
|
path: Path,
|
2014-05-27 23:14:34 +00:00
|
|
|
body: String
|
2014-03-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl FileBuilder {
|
|
|
|
pub fn new(path: Path, body: &str) -> FileBuilder {
|
2014-07-09 13:38:10 +00:00
|
|
|
FileBuilder { path: path, body: body.to_string() }
|
2014-03-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
|
2014-05-27 23:14:34 +00:00
|
|
|
fn mk(&self) -> Result<(), String> {
|
2014-03-19 01:10:48 +00:00
|
|
|
try!(mkdir_recursive(&self.dirname()));
|
|
|
|
|
|
|
|
let mut file = try!(
|
|
|
|
fs::File::create(&self.path)
|
2014-06-19 23:45:19 +00:00
|
|
|
.with_err_msg(format!("Could not create file; path={}",
|
|
|
|
self.path.display())));
|
2014-03-19 01:10:48 +00:00
|
|
|
|
|
|
|
file.write_str(self.body.as_slice())
|
2014-06-19 23:45:19 +00:00
|
|
|
.with_err_msg(format!("Could not write to file; path={}",
|
|
|
|
self.path.display()))
|
2014-03-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn dirname(&self) -> Path {
|
|
|
|
Path::new(self.path.dirname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-04 09:02:16 +00:00
|
|
|
#[derive(PartialEq,Clone)]
|
2014-07-07 21:46:03 +00:00
|
|
|
struct SymlinkBuilder {
|
|
|
|
dst: Path,
|
|
|
|
src: Path
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SymlinkBuilder {
|
|
|
|
pub fn new(dst: Path, src: Path) -> SymlinkBuilder {
|
|
|
|
SymlinkBuilder { dst: dst, src: src }
|
|
|
|
}
|
|
|
|
|
|
|
|
fn mk(&self) -> Result<(), String> {
|
|
|
|
try!(mkdir_recursive(&self.dirname()));
|
|
|
|
|
|
|
|
fs::symlink(&self.dst, &self.src)
|
|
|
|
.with_err_msg(format!("Could not create symlink; dst={} src={}",
|
|
|
|
self.dst.display(), self.src.display()))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn dirname(&self) -> Path {
|
|
|
|
Path::new(self.src.dirname())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-04 09:02:16 +00:00
|
|
|
#[derive(PartialEq,Clone)]
|
2014-06-12 22:51:16 +00:00
|
|
|
pub struct ProjectBuilder {
|
2014-05-27 23:14:34 +00:00
|
|
|
name: String,
|
2014-03-19 01:10:48 +00:00
|
|
|
root: Path,
|
2014-07-07 21:46:03 +00:00
|
|
|
files: Vec<FileBuilder>,
|
|
|
|
symlinks: Vec<SymlinkBuilder>
|
2014-03-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ProjectBuilder {
|
|
|
|
pub fn new(name: &str, root: Path) -> ProjectBuilder {
|
|
|
|
ProjectBuilder {
|
2014-07-09 13:38:10 +00:00
|
|
|
name: name.to_string(),
|
2014-03-19 01:10:48 +00:00
|
|
|
root: root,
|
2014-07-07 21:46:03 +00:00
|
|
|
files: vec!(),
|
|
|
|
symlinks: vec!()
|
2014-03-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn root(&self) -> Path {
|
2014-06-25 05:06:11 +00:00
|
|
|
self.root.clone()
|
2014-03-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
|
2014-08-06 16:21:10 +00:00
|
|
|
pub fn url(&self) -> Url { path2url(self.root()) }
|
|
|
|
|
2014-06-25 05:06:11 +00:00
|
|
|
pub fn bin(&self, b: &str) -> Path {
|
2015-02-06 07:27:53 +00:00
|
|
|
self.build_dir().join(format!("{}{}", b, env::consts::EXE_SUFFIX))
|
2014-07-07 08:50:05 +00:00
|
|
|
}
|
|
|
|
|
2014-08-25 14:51:13 +00:00
|
|
|
pub fn release_bin(&self, b: &str) -> Path {
|
2015-02-06 07:27:53 +00:00
|
|
|
self.build_dir().join("release").join(format!("{}{}", b,
|
|
|
|
env::consts::EXE_SUFFIX))
|
2014-08-25 14:51:13 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 16:08:51 +00:00
|
|
|
pub fn target_bin(&self, target: &str, b: &str) -> Path {
|
|
|
|
self.build_dir().join(target).join(format!("{}{}", b,
|
2015-02-06 07:27:53 +00:00
|
|
|
env::consts::EXE_SUFFIX))
|
2014-07-11 16:08:51 +00:00
|
|
|
}
|
|
|
|
|
2014-07-07 08:50:05 +00:00
|
|
|
pub fn build_dir(&self) -> Path {
|
|
|
|
self.root.join("target")
|
2014-06-25 05:06:11 +00:00
|
|
|
}
|
|
|
|
|
2015-01-13 16:41:04 +00:00
|
|
|
pub fn process<T: BytesContainer>(&self, program: T) -> ProcessBuilder {
|
2014-05-09 00:50:28 +00:00
|
|
|
process(program)
|
2014-11-22 10:04:40 +00:00
|
|
|
.unwrap()
|
2014-05-09 00:50:28 +00:00
|
|
|
.cwd(self.root())
|
2014-07-09 13:38:10 +00:00
|
|
|
.env("HOME", Some(paths::home().display().to_string().as_slice()))
|
2014-06-12 22:51:16 +00:00
|
|
|
}
|
|
|
|
|
2014-08-21 16:24:34 +00:00
|
|
|
pub fn cargo_process(&self, cmd: &str) -> ProcessBuilder {
|
2014-06-12 22:51:16 +00:00
|
|
|
self.build();
|
2014-08-21 16:24:34 +00:00
|
|
|
self.process(cargo_dir().join("cargo")).arg(cmd)
|
2014-03-20 22:17:19 +00:00
|
|
|
}
|
|
|
|
|
2014-06-19 23:45:19 +00:00
|
|
|
pub fn file<B: BytesContainer, S: Str>(mut self, path: B,
|
|
|
|
body: S) -> ProjectBuilder {
|
2014-06-12 22:51:16 +00:00
|
|
|
self.files.push(FileBuilder::new(self.root.join(path), body.as_slice()));
|
2014-03-19 01:10:48 +00:00
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2014-07-07 21:46:03 +00:00
|
|
|
pub fn symlink<T: BytesContainer>(mut self, dst: T,
|
|
|
|
src: T) -> ProjectBuilder {
|
|
|
|
self.symlinks.push(SymlinkBuilder::new(self.root.join(dst),
|
|
|
|
self.root.join(src)));
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2014-03-19 01:10:48 +00:00
|
|
|
// TODO: return something different than a ProjectBuilder
|
2014-07-21 21:36:08 +00:00
|
|
|
pub fn build(&self) -> &ProjectBuilder {
|
2014-03-19 01:10:48 +00:00
|
|
|
match self.build_with_result() {
|
2014-10-30 01:59:06 +00:00
|
|
|
Err(e) => panic!(e),
|
2014-03-19 01:10:48 +00:00
|
|
|
_ => return self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-27 23:14:34 +00:00
|
|
|
pub fn build_with_result(&self) -> Result<(), String> {
|
2014-03-19 01:10:48 +00:00
|
|
|
// First, clean the directory if it already exists
|
|
|
|
try!(self.rm_root());
|
|
|
|
|
|
|
|
// Create the empty directory
|
|
|
|
try!(mkdir_recursive(&self.root));
|
|
|
|
|
|
|
|
for file in self.files.iter() {
|
2014-06-27 21:06:50 +00:00
|
|
|
try!(file.mk());
|
2014-03-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
|
2014-07-07 21:46:03 +00:00
|
|
|
for symlink in self.symlinks.iter() {
|
|
|
|
try!(symlink.mk());
|
|
|
|
}
|
|
|
|
|
2014-03-19 01:10:48 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2014-05-27 23:14:34 +00:00
|
|
|
fn rm_root(&self) -> Result<(), String> {
|
2014-03-19 01:10:48 +00:00
|
|
|
if self.root.exists() {
|
|
|
|
rmdir_recursive(&self.root)
|
2014-06-27 21:06:50 +00:00
|
|
|
} else {
|
2014-03-19 01:10:48 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generates a project layout
|
|
|
|
pub fn project(name: &str) -> ProjectBuilder {
|
2014-06-12 22:51:16 +00:00
|
|
|
ProjectBuilder::new(name, paths::root().join(name))
|
2014-03-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// === Helpers ===
|
|
|
|
|
2014-05-27 23:14:34 +00:00
|
|
|
pub fn mkdir_recursive(path: &Path) -> Result<(), String> {
|
2015-01-30 13:48:43 +00:00
|
|
|
fs::mkdir_recursive(path, old_io::USER_DIR)
|
2014-06-19 23:45:19 +00:00
|
|
|
.with_err_msg(format!("could not create directory; path={}",
|
|
|
|
path.display()))
|
2014-03-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
|
2014-05-27 23:14:34 +00:00
|
|
|
pub fn rmdir_recursive(path: &Path) -> Result<(), String> {
|
2014-06-27 21:06:50 +00:00
|
|
|
path.rm_rf()
|
2014-06-19 23:45:19 +00:00
|
|
|
.with_err_msg(format!("could not rm directory; path={}",
|
|
|
|
path.display()))
|
2014-03-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
|
2014-06-12 22:51:16 +00:00
|
|
|
pub fn main_file<T: Str>(println: T, deps: &[&str]) -> String {
|
|
|
|
let mut buf = String::new();
|
|
|
|
|
|
|
|
for dep in deps.iter() {
|
|
|
|
buf.push_str(format!("extern crate {};\n", dep).as_slice());
|
|
|
|
}
|
|
|
|
|
|
|
|
buf.push_str("fn main() { println!(");
|
|
|
|
buf.push_str(println.as_slice());
|
|
|
|
buf.push_str("); }\n");
|
|
|
|
|
2014-07-09 13:38:10 +00:00
|
|
|
buf.to_string()
|
2014-06-12 22:51:16 +00:00
|
|
|
}
|
|
|
|
|
2014-03-19 01:10:48 +00:00
|
|
|
trait ErrMsg<T> {
|
2014-05-27 23:14:34 +00:00
|
|
|
fn with_err_msg(self, val: String) -> Result<T, String>;
|
2014-03-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
|
2015-01-23 18:42:29 +00:00
|
|
|
impl<T, E: fmt::Display> ErrMsg<T> for Result<T, E> {
|
2014-05-27 23:14:34 +00:00
|
|
|
fn with_err_msg(self, val: String) -> Result<T, String> {
|
2014-03-19 01:10:48 +00:00
|
|
|
match self {
|
|
|
|
Ok(val) => Ok(val),
|
2014-05-08 23:49:58 +00:00
|
|
|
Err(err) => Err(format!("{}; original={}", val, err))
|
2014-03-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-03-20 22:17:19 +00:00
|
|
|
|
|
|
|
// Path to cargo executables
|
2014-04-02 23:34:19 +00:00
|
|
|
pub fn cargo_dir() -> Path {
|
2015-02-13 04:10:07 +00:00
|
|
|
env::var("CARGO_BIN_PATH").map(Path::new).ok()
|
2015-02-06 07:27:53 +00:00
|
|
|
.or_else(|| env::current_exe().ok().map(|s| s.dir_path()))
|
2014-06-18 20:14:56 +00:00
|
|
|
.unwrap_or_else(|| {
|
2014-10-30 01:59:06 +00:00
|
|
|
panic!("CARGO_BIN_PATH wasn't set. Cannot continue running test")
|
2014-06-18 20:14:56 +00:00
|
|
|
})
|
2014-03-20 22:17:19 +00:00
|
|
|
}
|
|
|
|
|
2014-06-09 20:08:09 +00:00
|
|
|
/// Returns an absolute path in the filesystem that `path` points to. The
|
|
|
|
/// returned path does not contain any symlinks in its hierarchy.
|
2014-03-20 22:17:19 +00:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* ===== Matchers =====
|
|
|
|
*
|
|
|
|
*/
|
2014-04-02 23:34:19 +00:00
|
|
|
|
2015-01-04 09:02:16 +00:00
|
|
|
#[derive(Clone)]
|
2014-04-02 23:34:19 +00:00
|
|
|
struct Execs {
|
2014-05-27 23:14:34 +00:00
|
|
|
expect_stdout: Option<String>,
|
|
|
|
expect_stdin: Option<String>,
|
|
|
|
expect_stderr: Option<String>,
|
2015-01-13 16:41:04 +00:00
|
|
|
expect_exit_code: Option<i32>
|
2014-04-02 23:34:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Execs {
|
|
|
|
|
2014-07-18 14:40:15 +00:00
|
|
|
pub fn with_stdout<S: ToString>(mut self, expected: S) -> Execs {
|
2014-07-09 13:38:10 +00:00
|
|
|
self.expect_stdout = Some(expected.to_string());
|
2014-06-19 23:45:19 +00:00
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2014-07-18 14:40:15 +00:00
|
|
|
pub fn with_stderr<S: ToString>(mut self, expected: S) -> Execs {
|
2014-07-09 13:38:10 +00:00
|
|
|
self.expect_stderr = Some(expected.to_string());
|
2014-06-19 23:45:19 +00:00
|
|
|
self
|
2014-04-02 23:34:19 +00:00
|
|
|
}
|
2014-06-19 23:45:19 +00:00
|
|
|
|
2015-01-13 16:41:04 +00:00
|
|
|
pub fn with_status(mut self, expected: i32) -> Execs {
|
2014-06-19 23:45:19 +00:00
|
|
|
self.expect_exit_code = Some(expected);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
fn match_output(&self, actual: &ProcessOutput) -> ham::MatchResult {
|
|
|
|
self.match_status(actual)
|
|
|
|
.and(self.match_stdout(actual))
|
|
|
|
.and(self.match_stderr(actual))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn match_status(&self, actual: &ProcessOutput) -> ham::MatchResult {
|
|
|
|
match self.expect_exit_code {
|
|
|
|
None => ham::success(),
|
|
|
|
Some(code) => {
|
|
|
|
ham::expect(
|
2015-01-13 16:41:04 +00:00
|
|
|
actual.status.matches_exit_status(code as isize),
|
2014-06-19 23:45:19 +00:00
|
|
|
format!("exited with {}\n--- stdout\n{}\n--- stderr\n{}",
|
|
|
|
actual.status,
|
2014-07-18 11:49:34 +00:00
|
|
|
String::from_utf8_lossy(actual.output.as_slice()),
|
|
|
|
String::from_utf8_lossy(actual.error.as_slice())))
|
2014-06-19 23:45:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn match_stdout(&self, actual: &ProcessOutput) -> ham::MatchResult {
|
|
|
|
self.match_std(self.expect_stdout.as_ref(), actual.output.as_slice(),
|
2014-09-09 05:26:14 +00:00
|
|
|
"stdout", actual.error.as_slice())
|
2014-06-19 23:45:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn match_stderr(&self, actual: &ProcessOutput) -> ham::MatchResult {
|
|
|
|
self.match_std(self.expect_stderr.as_ref(), actual.error.as_slice(),
|
2014-09-09 05:26:14 +00:00
|
|
|
"stderr", actual.output.as_slice())
|
2014-06-19 23:45:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn match_std(&self, expected: Option<&String>, actual: &[u8],
|
|
|
|
description: &str, extra: &[u8]) -> ham::MatchResult {
|
2014-11-22 10:04:40 +00:00
|
|
|
match expected.map(|s| Str::as_slice(s)) {
|
2014-06-19 23:45:19 +00:00
|
|
|
None => ham::success(),
|
|
|
|
Some(out) => {
|
2014-07-23 19:47:59 +00:00
|
|
|
let actual = match str::from_utf8(actual) {
|
2014-12-24 04:50:01 +00:00
|
|
|
Err(..) => return Err(format!("{} was not utf8 encoded",
|
2014-07-23 19:47:59 +00:00
|
|
|
description)),
|
2014-12-24 04:50:01 +00:00
|
|
|
Ok(actual) => actual,
|
2014-07-23 19:47:59 +00:00
|
|
|
};
|
|
|
|
// Let's not deal with \r\n vs \n on windows...
|
|
|
|
let actual = actual.replace("\r", "");
|
|
|
|
let actual = actual.replace("\t", "<tab>");
|
|
|
|
|
|
|
|
let a = actual.as_slice().lines();
|
|
|
|
let e = out.lines();
|
|
|
|
|
|
|
|
let diffs = zip_all(a, e).enumerate();
|
2014-12-02 03:11:20 +00:00
|
|
|
let diffs = diffs.filter_map(|(i, (a,e))| {
|
2014-07-23 19:47:59 +00:00
|
|
|
match (a, e) {
|
|
|
|
(Some(a), Some(e)) => {
|
|
|
|
if lines_match(e.as_slice(), a.as_slice()) {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(format!("{:3} - |{}|\n + |{}|\n", i, e, a))
|
2014-07-21 19:23:01 +00:00
|
|
|
}
|
2014-07-23 19:47:59 +00:00
|
|
|
},
|
|
|
|
(Some(a), None) => {
|
|
|
|
Some(format!("{:3} -\n + |{}|\n", i, a))
|
|
|
|
},
|
|
|
|
(None, Some(e)) => {
|
|
|
|
Some(format!("{:3} - |{}|\n +\n", i, e))
|
|
|
|
},
|
2014-10-30 01:59:06 +00:00
|
|
|
(None, None) => panic!("Cannot get here")
|
2014-07-23 19:47:59 +00:00
|
|
|
}
|
|
|
|
});
|
2014-07-21 19:23:01 +00:00
|
|
|
|
2014-07-23 19:47:59 +00:00
|
|
|
let diffs = diffs.collect::<Vec<String>>().connect("\n");
|
2014-07-21 19:23:01 +00:00
|
|
|
|
2014-07-23 19:47:59 +00:00
|
|
|
ham::expect(diffs.len() == 0,
|
|
|
|
format!("differences:\n\
|
|
|
|
{}\n\n\
|
|
|
|
other output:\n\
|
|
|
|
`{}`", diffs,
|
|
|
|
String::from_utf8_lossy(extra)))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn lines_match(expected: &str, mut actual: &str) -> bool {
|
|
|
|
for part in expected.split_str("[..]") {
|
|
|
|
match actual.find_str(part) {
|
2015-01-25 06:03:42 +00:00
|
|
|
Some(i) => actual = &actual[i + part.len()..],
|
2014-07-23 19:47:59 +00:00
|
|
|
None => {
|
|
|
|
return false
|
2014-06-19 23:45:19 +00:00
|
|
|
}
|
2014-04-02 23:34:19 +00:00
|
|
|
}
|
|
|
|
}
|
2014-10-31 18:17:29 +00:00
|
|
|
actual.len() == 0 || expected.ends_with("[..]")
|
2014-04-02 23:34:19 +00:00
|
|
|
}
|
|
|
|
|
2015-02-22 23:06:12 +00:00
|
|
|
struct ZipAll<I1: Iterator, I2: Iterator> {
|
2014-07-21 19:23:01 +00:00
|
|
|
first: I1,
|
|
|
|
second: I2,
|
|
|
|
}
|
|
|
|
|
2015-02-22 23:06:12 +00:00
|
|
|
impl<T, I1: Iterator<Item=T>, I2: Iterator<Item=T>> Iterator for ZipAll<I1, I2> {
|
2015-01-04 09:02:16 +00:00
|
|
|
type Item = (Option<T>, Option<T>);
|
2014-07-21 19:23:01 +00:00
|
|
|
fn next(&mut self) -> Option<(Option<T>, Option<T>)> {
|
|
|
|
let first = self.first.next();
|
|
|
|
let second = self.second.next();
|
|
|
|
|
|
|
|
match (first, second) {
|
|
|
|
(None, None) => None,
|
|
|
|
(a, b) => Some((a, b))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-22 23:06:12 +00:00
|
|
|
fn zip_all<T, I1: Iterator<Item=T>, I2: Iterator<Item=T>>(a: I1, b: I2) -> ZipAll<I1, I2> {
|
2014-07-21 19:23:01 +00:00
|
|
|
ZipAll {
|
|
|
|
first: a,
|
2015-02-22 23:06:12 +00:00
|
|
|
second: b,
|
2014-07-21 19:23:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-23 18:42:29 +00:00
|
|
|
impl fmt::Display for Execs {
|
2014-10-17 22:05:54 +00:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(f, "execs")
|
2014-06-19 23:45:19 +00:00
|
|
|
}
|
2014-04-02 23:34:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ham::Matcher<ProcessBuilder> for Execs {
|
2014-06-19 23:45:19 +00:00
|
|
|
fn matches(&self, process: ProcessBuilder) -> ham::MatchResult {
|
|
|
|
let res = process.exec_with_output();
|
|
|
|
|
|
|
|
match res {
|
|
|
|
Ok(out) => self.match_output(&out),
|
|
|
|
Err(ProcessError { output: Some(ref out), .. }) => {
|
|
|
|
self.match_output(out)
|
|
|
|
}
|
2014-08-02 07:08:31 +00:00
|
|
|
Err(e) => {
|
|
|
|
let mut s = format!("could not exec process {}: {}", process, e);
|
2014-12-21 23:19:44 +00:00
|
|
|
match e.cause() {
|
2014-08-02 07:08:31 +00:00
|
|
|
Some(cause) => s.push_str(format!("\ncaused by: {}",
|
2014-12-21 23:19:44 +00:00
|
|
|
cause.description()).as_slice()),
|
2014-08-02 07:08:31 +00:00
|
|
|
None => {}
|
|
|
|
}
|
|
|
|
Err(s)
|
|
|
|
}
|
2014-06-19 23:45:19 +00:00
|
|
|
}
|
2014-04-02 23:34:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-18 14:40:15 +00:00
|
|
|
pub fn execs() -> Execs {
|
|
|
|
Execs {
|
2014-05-09 23:57:13 +00:00
|
|
|
expect_stdout: None,
|
|
|
|
expect_stderr: None,
|
|
|
|
expect_stdin: None,
|
|
|
|
expect_exit_code: None
|
|
|
|
}
|
2014-04-02 23:34:19 +00:00
|
|
|
}
|
2014-05-08 23:49:58 +00:00
|
|
|
|
2015-01-04 09:02:16 +00:00
|
|
|
#[derive(Clone)]
|
2014-05-28 01:33:06 +00:00
|
|
|
struct ShellWrites {
|
|
|
|
expected: String
|
|
|
|
}
|
|
|
|
|
2015-01-23 18:42:29 +00:00
|
|
|
impl fmt::Display for ShellWrites {
|
2014-10-17 22:05:54 +00:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(f, "`{}` written to the shell", self.expected)
|
2014-05-28 01:33:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-22 01:53:07 +00:00
|
|
|
impl<'a> ham::Matcher<&'a [u8]> for ShellWrites {
|
|
|
|
fn matches(&self, actual: &[u8])
|
2014-06-19 23:45:19 +00:00
|
|
|
-> ham::MatchResult
|
|
|
|
{
|
2014-07-17 01:44:30 +00:00
|
|
|
let actual = String::from_utf8_lossy(actual);
|
2014-07-09 13:38:10 +00:00
|
|
|
let actual = actual.to_string();
|
2014-05-28 01:33:06 +00:00
|
|
|
ham::expect(actual == self.expected, actual)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-23 18:42:29 +00:00
|
|
|
pub fn shell_writes<T: fmt::Display>(string: T) -> ShellWrites {
|
2014-07-18 14:40:15 +00:00
|
|
|
ShellWrites { expected: string.to_string() }
|
2014-05-28 01:33:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub trait Tap {
|
2015-01-13 16:41:04 +00:00
|
|
|
fn tap<F: FnOnce(&mut Self)>(mut self, callback: F) -> Self;
|
2014-05-28 01:33:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> Tap for T {
|
2015-01-13 16:41:04 +00:00
|
|
|
fn tap<F: FnOnce(&mut Self)>(mut self, callback: F) -> T {
|
2014-05-28 01:33:06 +00:00
|
|
|
callback(&mut self);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|
2014-06-25 05:06:11 +00:00
|
|
|
|
2014-06-26 22:14:31 +00:00
|
|
|
pub fn basic_bin_manifest(name: &str) -> String {
|
|
|
|
format!(r#"
|
2014-06-27 05:53:05 +00:00
|
|
|
[package]
|
2014-06-26 22:14:31 +00:00
|
|
|
|
|
|
|
name = "{}"
|
|
|
|
version = "0.5.0"
|
|
|
|
authors = ["wycats@example.com"]
|
|
|
|
|
|
|
|
[[bin]]
|
|
|
|
|
|
|
|
name = "{}"
|
|
|
|
"#, name, name)
|
|
|
|
}
|
|
|
|
|
2014-07-21 00:02:09 +00:00
|
|
|
pub fn basic_lib_manifest(name: &str) -> String {
|
|
|
|
format!(r#"
|
|
|
|
[package]
|
|
|
|
|
|
|
|
name = "{}"
|
|
|
|
version = "0.5.0"
|
|
|
|
authors = ["wycats@example.com"]
|
|
|
|
|
2014-08-14 06:08:02 +00:00
|
|
|
[lib]
|
2014-07-21 00:02:09 +00:00
|
|
|
|
|
|
|
name = "{}"
|
|
|
|
"#, name, name)
|
|
|
|
}
|
|
|
|
|
2014-08-06 16:21:10 +00:00
|
|
|
pub fn path2url(p: Path) -> Url {
|
2015-01-25 06:03:42 +00:00
|
|
|
Url::from_file_path(&p).ok().unwrap()
|
2014-08-06 16:21:10 +00:00
|
|
|
}
|
|
|
|
|
2014-09-09 05:26:14 +00:00
|
|
|
pub static RUNNING: &'static str = " Running";
|
|
|
|
pub static COMPILING: &'static str = " Compiling";
|
|
|
|
pub static FRESH: &'static str = " Fresh";
|
|
|
|
pub static UPDATING: &'static str = " Updating";
|
|
|
|
pub static DOCTEST: &'static str = " Doc-tests";
|
|
|
|
pub static PACKAGING: &'static str = " Packaging";
|
|
|
|
pub static DOWNLOADING: &'static str = " Downloading";
|
2014-09-09 14:23:09 +00:00
|
|
|
pub static UPLOADING: &'static str = " Uploading";
|
2014-09-27 04:14:46 +00:00
|
|
|
pub static VERIFYING: &'static str = " Verifying";
|
2014-11-21 20:31:00 +00:00
|
|
|
pub static ARCHIVING: &'static str = " Archiving";
|