#![cfg(feature = "offline")]
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::sync::{Mutex, OnceLock};
use std::time::{SystemTime, UNIX_EPOCH};
use teamtalk::loader::find_or_download_dll;
fn cwd_lock() -> std::sync::MutexGuard<'static, ()> {
static LOCK: OnceLock<Mutex<()>> = OnceLock::new();
match LOCK.get_or_init(|| Mutex::new(())).lock() {
Ok(guard) => guard,
Err(poisoned) => poisoned.into_inner(),
}
}
fn temp_dir() -> PathBuf {
let nanos = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_nanos();
env::temp_dir().join(format!("teamtalk_test_{}_{}", std::process::id(), nanos))
}
fn with_temp_cwd<F, R>(f: F) -> R
where
F: FnOnce(&Path) -> R + std::panic::UnwindSafe,
{
let _lock = cwd_lock();
let dir = temp_dir();
fs::create_dir_all(&dir).unwrap();
let old = env::current_dir().unwrap();
env::set_current_dir(&dir).unwrap();
let result = std::panic::catch_unwind(|| f(&dir));
env::set_current_dir(old).unwrap();
let _ = fs::remove_dir_all(&dir);
match result {
Ok(value) => value,
Err(err) => std::panic::resume_unwind(err),
}
}
fn dll_name() -> &'static str {
if cfg!(windows) {
"TeamTalk5.dll"
} else {
"libTeamTalk5.so"
}
}
#[test]
fn offline_missing_dll_returns_error() {
with_temp_cwd(|_| {
let result = find_or_download_dll();
assert!(result.is_err());
});
}
#[test]
fn offline_existing_dll_returns_path() {
with_temp_cwd(|dir| {
let sdk_dir = dir.join("TEAMTALK_DLL");
fs::create_dir_all(&sdk_dir).unwrap();
let dll_path = sdk_dir.join(dll_name());
fs::write(&dll_path, vec![0u8; 2048]).unwrap();
let docs_dir = sdk_dir.join("Documentation").join("C-API");
fs::create_dir_all(&docs_dir).unwrap();
fs::write(docs_dir.join("index.html"), b"docs").unwrap();
fs::write(
sdk_dir.join("TEAMTALK_DOCUMENTATION_MANIFEST.txt"),
"C-API/index.html\n",
)
.unwrap();
let result = find_or_download_dll().unwrap();
let abs = env::current_dir().unwrap().join(result);
assert_eq!(abs, dll_path);
});
}