use std::sync::atomic::{AtomicIsize, ATOMIC_ISIZE_INIT};
use std::sync::atomic::Ordering::SeqCst;
use std::env;
use url::percent_encoding::{percent_encode, PATH_SEGMENT_ENCODE_SET};
use env_logger;
pub use std::sync::Arc;
pub use super::pg::dyn::values::ToValue;
pub use super::pg::dyn::{Value, Type};
pub use super::pg::dyn::values;
pub use super::engine::types::{Fact, Rule, Clause, MatchExpr, Projection};
use super::PgDB;
pub use engine::Result;
pub use tokio_core::reactor::Core;
pub type Engine = super::Engine<super::pg::Error, PgDB>;
static DB_NUM: AtomicIsize = ATOMIC_ISIZE_INIT;
fn url_encode(input: &[u8]) -> String {
percent_encode(input, PATH_SEGMENT_ENCODE_SET).to_string()
}
fn get_db_addr(db_num: isize) -> String {
match env::var("HOLMES_PG_SOCK_DIR") {
Ok(dir) => {
format!("postgresql://holmes@{}/holmes_test{}",
url_encode(&dir.into_bytes()),
db_num)
}
_ => {
panic!("Testing requires HOLMES_PG_SOCK_DIR to be set to \
indicate the directory where it can find the postgres \
database socket.")
}
}
}
static LOGGER: ::std::sync::Once = ::std::sync::ONCE_INIT;
pub fn multi<A>(tests: &[&Fn(&mut Engine, &mut Core) -> Result<A>]) {
LOGGER.call_once(|| env_logger::init().unwrap());
let db_num = DB_NUM.fetch_add(1, SeqCst);
let db_addr = get_db_addr(db_num);
for test in tests {
let mut core = Core::new().unwrap();
let db = PgDB::new(&db_addr).unwrap();
let mut holmes = Engine::new(db, core.handle());
test(&mut holmes, &mut core).unwrap();
}
PgDB::destroy(&db_addr).unwrap();
}
pub fn single<A>(test: &Fn(&mut Engine, &mut Core) -> Result<A>) {
multi(&[test])
}
pub fn should_fail<A, F>(f: F) -> Box<Fn(&mut Engine) -> Result<()>>
where F: 'static + Fn(&mut Engine) -> Result<A>
{
Box::new(move |holmes: &mut Engine| {
match f(holmes) {
Ok(_) => panic!("should_fail"), Err(_) => Ok(()),
}
})
}