use std;
use std::sync::{Arc, Mutex, Condvar, Once};
use {ffi, Fsw, FswSession, FswError, FswMonitorType, FswMonitorFilter, FswFilterType, FswEventFlag,
FswEvent};
cfg_if! {
if #[cfg(not(feature = "fswatch_1_10_0"))] {
use FswStatus;
use std::sync::atomic::Ordering;
} else {}
}
static FSW_INIT: Once = std::sync::ONCE_INIT;
fn initialize() {
FSW_INIT.call_once(|| {
Fsw::init_library().unwrap();
});
}
fn get_default_session() -> FswSession {
FswSession::default().unwrap()
}
fn create_sample_filter() -> FswMonitorFilter {
FswMonitorFilter::new("\\w+\\.txt$", FswFilterType::Include, false, false)
}
#[test]
fn create_and_destroy_session() {
initialize();
let handle = {
let session = get_default_session();
session.handle.clone()
};
assert!(handle != ffi::FSW_INVALID_HANDLE);
#[cfg(not(feature = "fswatch_1_10_0"))]
{ assert!(unsafe { ffi::fsw_destroy_session(handle) } != ffi::FSW_OK); }
}
#[test]
fn create_session_from_builder() {
initialize();
FswSession::builder()
.add_path("./")
.property("test_name", "test_value")
.overflow(Some(true))
.monitor(FswMonitorType::SystemDefault)
.latency(Some(1.0))
.recursive(Some(true))
.directory_only(Some(false))
.follow_symlinks(Some(true))
.add_event_filter(FswEventFlag::Created)
.add_filter(create_sample_filter())
.build_callback(|events| println!("{:#?}", events))
.unwrap();
}
#[test]
fn start_empty() {
initialize();
assert_eq!(Err(FswError::MissingRequiredParameters), get_default_session().start_monitor());
}
#[test]
fn start_without_callback() {
initialize();
let session = get_default_session();
session.add_path("./").unwrap();
assert_eq!(Err(FswError::MissingRequiredParameters), session.start_monitor());
}
#[test]
fn start_without_path() {
initialize();
let session = get_default_session();
session.set_callback(|_| println!("Hello")).unwrap();
assert_eq!(Err(FswError::MissingRequiredParameters), session.start_monitor());
}
#[test]
fn invalid_path() {
initialize();
let session = get_default_session();
unsafe {
assert!(ffi::fsw_add_path(session.handle(), ::std::ptr::null()) == ffi::FSW_ERR_INVALID_PATH);
}
}
#[test]
#[cfg(not(feature = "fswatch_1_10_0"))]
fn invalid_handle_add_path() {
initialize();
let mut session = get_default_session();
session.handle = ffi::FSW_INVALID_HANDLE;
let res = session.add_path("./");
let expected_error = Err(FswError::FromFsw(FswStatus::SessionUnknown));
assert_eq!(expected_error, res);
assert!(!session.path_added.load(Ordering::Relaxed));
}
#[test]
#[cfg(not(feature = "fswatch_1_10_0"))]
fn invalid_handle_set_callback() {
initialize();
let mut session = get_default_session();
session.handle = ffi::FSW_INVALID_HANDLE;
let res = session.set_callback(|_| {});
let expected_error = Err(FswError::FromFsw(FswStatus::SessionUnknown));
assert_eq!(expected_error, res);
assert!(!session.callback_set.load(Ordering::Relaxed));
}
#[test]
fn run_callback() {
initialize();
let dir = std::env::current_dir().unwrap();
let file_name = "fsw_test_file";
let pair = Arc::new((Mutex::new(false), Condvar::new()));
let pair2 = pair.clone();
let dir2 = dir.clone();
let (tx, rx) = std::sync::mpsc::channel();
let handle = std::thread::spawn(move || {
let &(ref lock, ref cvar) = &*pair2;
let session = FswSession::builder_paths(vec![dir2])
.add_filter(FswMonitorFilter::new(file_name, FswFilterType::Include, true, false))
.add_filter(FswMonitorFilter::new(".*", FswFilterType::Exclude, false, false))
.build().unwrap();
tx.send(()).unwrap();
for event in session {
let mut started = lock.lock().unwrap();
*started = true;
cvar.notify_one();
return event;
}
unreachable!();
});
let mut file_path = dir.clone();
file_path.push(file_name);
let _ = rx.recv().unwrap();
std::thread::sleep(std::time::Duration::from_secs(1));
std::fs::File::create(&file_path).unwrap();
let &(ref lock, ref cvar) = &*pair;
let mut started = lock.lock().unwrap();
while !*started {
let (s, timeout) = cvar.wait_timeout(started, std::time::Duration::from_secs(5)).unwrap();
started = s;
assert!(!timeout.timed_out());
}
let event: FswEvent = handle.join().unwrap();
std::fs::remove_file(&file_path).unwrap();
let path = std::path::PathBuf::from(event.path);
let event_file_name = path.file_name().unwrap().to_string_lossy();
assert_eq!(file_name, event_file_name);
}
#[test]
#[cfg(feature = "fswatch_1_10_0")]
fn stop_monitor() {
initialize();
let session = FswSession::builder_paths(vec!["./"])
.build_callback(|_| {})
.unwrap();
let arc = Arc::new(session);
let thread_session = arc.clone();
let handle = std::thread::spawn(move || {
thread_session.start_monitor().unwrap();
});
std::thread::sleep(std::time::Duration::from_secs(3));
arc.stop_monitor().unwrap();
handle.join().unwrap();
}