#![allow(dead_code, unused_imports, unused_macros)]
pub mod checks;
pub mod kernel;
mod macros;
pub mod registry;
pub(crate) use macros::assert_type_write_err;
pub use idakit::corpus::{Fixture, WorkingCopy, canonical, display_name, fixtures, working_copy};
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicU32, Ordering};
use idakit::prelude::{Database, Ida};
pub fn with_canonical_db(body: impl FnOnce(&mut Database) + Send + 'static) {
registry::with_warm_kernel(|ida| {
ida.call(move |idb| body(idb))
.unwrap_or_else(|e| e.resume());
})
.expect("with_canonical_db needs the kernel harness; is this a #[kernel_test]?");
}
pub struct TestDb {
scratch: PathBuf,
db: PathBuf,
}
impl TestDb {
pub fn acquire() -> Option<Self> {
Self::source().map(Self::copy_of)
}
pub fn source() -> Option<PathBuf> {
if let Ok(db) = std::env::var("IDAKIT_TEST_DB")
&& !db.is_empty()
{
return Some(PathBuf::from(db));
}
canonical()
}
pub fn copy_of(src: impl AsRef<Path>) -> Self {
let src = src.as_ref();
let file_name = src.file_name().expect("source db has a file name");
let unique = format!(
"idakit-testdb-{}-{}",
std::process::id(),
NEXT.fetch_add(1, Ordering::Relaxed)
);
let mut last_err = None;
for root in scratch_roots() {
let scratch = root.join(&unique);
let db = scratch.join(file_name);
if std::fs::create_dir_all(&scratch).is_err() {
continue;
}
match std::fs::copy(src, &db).and_then(|_| idakit::corpus::make_writable(&db)) {
Ok(()) => return Self { scratch, db },
Err(e) => {
let _ = std::fs::remove_dir_all(&scratch);
last_err = Some(e);
}
}
}
panic!("could not copy test db {src:?} into any scratch dir: {last_err:?}");
}
#[must_use]
pub fn path(&self) -> &str {
self.db.to_str().expect("scratch db path is valid UTF-8")
}
}
impl AsRef<str> for TestDb {
fn as_ref(&self) -> &str {
self.path()
}
}
impl Drop for TestDb {
fn drop(&mut self) {
let _ = std::fs::remove_dir_all(&self.scratch);
}
}
static NEXT: AtomicU32 = AtomicU32::new(0);
fn scratch_roots() -> Vec<PathBuf> {
if let Ok(dir) = std::env::var("IDAKIT_TEST_SCRATCH")
&& !dir.is_empty()
{
return vec![PathBuf::from(dir)];
}
let mut roots = Vec::new();
let shm = PathBuf::from("/dev/shm");
if shm.is_dir() {
roots.push(shm);
}
roots.push(std::env::temp_dir());
roots
}