iron_test/
project_builder.rs1use std::fs;
2use std::io::{self, Write};
3use std::env;
4use std::path::{Path, PathBuf};
5use std::fmt::Debug;
6use uuid::Uuid;
7use std::sync::{Mutex, Arc};
8
9static IRON_INTEGRATION_TEST_DIR : &'static str = "iron-integration-tests";
10
11#[derive(Debug, PartialEq, Clone)]
12struct FileBuilder {
13 path: PathBuf,
14 body: Vec<u8>
15}
16
17impl FileBuilder {
18 pub fn new<P: AsRef<Path>, B: Into<Vec<u8>>>(path: P, body: B) -> FileBuilder {
20 FileBuilder { path: path.as_ref().to_path_buf(), body: body.into() }
21 }
22
23 fn mk(&self) -> Result<(), String> {
24 try!(mkdir_recursive(&self.dirname()));
25
26 let mut file = try!(
27 fs::File::create(&self.path)
28 .with_err_msg(format!("Could not create file; path={}",
29 self.path.display())));
30
31 file.write_all(&self.body)
32 .with_err_msg(format!("Could not write to file; path={}",
33 self.path.display()))
34 }
35
36 fn dirname(&self) -> &Path {
38 &self.path.parent().expect("parent directory")
39 }
40}
41
42
43#[derive(Debug, Clone)]
48pub struct ProjectBuilder {
49 name: String,
50 root: PathBuf,
51 files: Vec<FileBuilder>,
52 lock: Arc<Mutex<()>>,
53}
54
55impl ProjectBuilder {
56 pub fn new(name: &str) -> ProjectBuilder {
59 let id = Uuid::new_v4();
60 let path = root(id);
61
62 path.rm_rf().unwrap();
64
65 ProjectBuilder {
66 name: name.to_string(),
67 root: path.join(name),
68 files: vec!(),
69 lock: Arc::new(Mutex::new(())),
70 }
71 }
72
73 pub fn root(&self) -> &Path {
75 &self.root
76 }
77
78 pub fn file<P, B>(mut self, path: P, body: B) -> ProjectBuilder
80 where P: AsRef<Path>, B: Into<Vec<u8>> {
81 self.files.push(FileBuilder::new(self.root.join(&path), body));
82 self
83 }
84
85 pub fn build(&self) -> &ProjectBuilder {
87 self.build_with_result().map(|_| self).unwrap()
88 }
89
90 pub fn build_with_result(&self) -> Result<(), String> {
92 let _lock = self.lock.lock().unwrap();
93 for file in self.files.iter() {
94 try!(file.mk());
95 }
96
97 Ok(())
98 }
99}
100
101impl PartialEq for ProjectBuilder {
102 fn eq(&self, other: &ProjectBuilder) -> bool {
103 self.name.eq(&other.name) &&
104 self.root.eq(&other.root) &&
105 self.files.eq(&other.files)
106 }
107}
108
109impl Drop for ProjectBuilder {
110 fn drop(&mut self) {
111 let _lock = self.lock.lock().unwrap();
112 match self.root().parent().map(BuilderPathExt::rm_rf) {
113 Some(Ok(_)) => debug!("Successfully cleaned up the test directory; path = {:?}", self.root().parent().unwrap()),
114 Some(Err(e)) => debug!("Failed to cleanup the test directory; path = {:?}; {}", self.root().parent().unwrap(), e),
115 None => debug!("Failed to cleanup the test directory; no parent")
116 }
117 }
118}
119
120fn mkdir_recursive(path: &Path) -> Result<(), String> {
122 fs::create_dir_all(path)
123 .with_err_msg(format!("could not create directory; path={}",
124 path.display()))
125}
126
127trait ErrMsg<T> {
129 fn with_err_msg(self, val: String) -> Result<T, String>;
132}
133
134impl<T, E: Debug> ErrMsg<T> for Result<T, E> {
135 fn with_err_msg(self, val: String) -> Result<T, String> {
136 match self {
137 Ok(val) => Ok(val),
138 Err(err) => Err(format!("{}; original={:?}", val, err))
139 }
140 }
141}
142
143fn root(id: Uuid) -> PathBuf {
146 integration_tests_dir().join(&format!("test-{}", id))
147}
148
149fn integration_tests_dir() -> PathBuf {
150 env::current_exe()
151 .map(|mut p| { p.pop(); p.join(IRON_INTEGRATION_TEST_DIR) })
152 .unwrap()
153}
154
155
156pub trait BuilderPathExt {
158 fn rm_rf(&self) -> io::Result<()>;
160}
161
162impl BuilderPathExt for Path {
163 fn rm_rf(&self) -> io::Result<()> {
164 if let Ok(_) = fs::metadata(self) {
165 fs::remove_dir_all(self)
166 } else {
167 Ok(())
168 }
169 }
170}