use crate::resource::*;
use crate::term::NifError;
use crate::testing::mocks::MockResourceManager;
#[cfg(test)]
mod tests {
use super::*;
#[repr(C)]
#[derive(Debug, PartialEq)]
struct TestResource {
id: u32,
name: [u8; 16],
active: bool,
}
impl Default for TestResource {
fn default() -> Self {
Self {
id: 42,
name: *b"test_resource\0\0\0",
active: true,
}
}
}
#[test]
fn test_mock_resource_manager_creation() {
let manager = MockResourceManager::new();
assert_eq!(manager.get_resource_count(), 0);
assert_eq!(manager.get_resource_type_count(), 0);
assert_eq!(manager.get_monitor_count(), 0);
}
#[test]
fn test_resource_type_initialization() {
let mut manager = MockResourceManager::new();
let env = core::ptr::null_mut();
let result = manager.init_resource_type(
env,
"test_resource",
&resource_type_init(),
ErlNifResourceFlags::ERL_NIF_RT_CREATE,
);
assert!(result.is_ok());
assert!(manager.verify_init_called("test_resource"));
assert_eq!(manager.get_resource_type_count(), 1);
}
#[test]
fn test_invalid_resource_name() {
let mut manager = MockResourceManager::new();
let env = core::ptr::null_mut();
let result = manager.init_resource_type(
env,
"",
&resource_type_init(),
ErlNifResourceFlags::ERL_NIF_RT_CREATE,
);
assert_eq!(result.unwrap_err(), ResourceError::InvalidName);
let long_name = "a".repeat(256);
let result = manager.init_resource_type(
env,
&long_name,
&resource_type_init(),
ErlNifResourceFlags::ERL_NIF_RT_CREATE,
);
assert_eq!(result.unwrap_err(), ResourceError::InvalidName);
}
#[test]
fn test_resource_allocation() {
let mut manager = MockResourceManager::new();
let env = core::ptr::null_mut();
let resource_type = manager.init_resource_type(
env,
"test_type",
&resource_type_init(),
ErlNifResourceFlags::ERL_NIF_RT_CREATE,
).unwrap();
let result = manager.alloc_resource(resource_type, 1024);
assert!(result.is_ok());
assert_eq!(manager.get_resource_count(), 1);
let result = manager.alloc_resource(core::ptr::null_mut(), 1024);
assert_eq!(result.unwrap_err(), ResourceError::BadResourceType);
let result = manager.alloc_resource(resource_type, 0);
assert_eq!(result.unwrap_err(), ResourceError::BadArg);
}
#[test]
fn test_resource_reference_counting() {
let mut manager = MockResourceManager::new();
let env = core::ptr::null_mut();
let resource_type = manager.init_resource_type(
env,
"test_type",
&resource_type_init(),
ErlNifResourceFlags::ERL_NIF_RT_CREATE,
).unwrap();
let resource_ptr = manager.alloc_resource(resource_type, 1024).unwrap();
assert_eq!(manager.get_resource_ref_count(resource_ptr), Some(1));
let result = manager.keep_resource(resource_ptr);
assert!(result.is_ok());
assert_eq!(manager.get_resource_ref_count(resource_ptr), Some(2));
let result = manager.release_resource(resource_ptr);
assert!(result.is_ok());
assert_eq!(manager.get_resource_ref_count(resource_ptr), Some(1));
let result = manager.release_resource(resource_ptr);
assert!(result.is_ok());
assert_eq!(manager.get_resource_count(), 0);
let result = manager.keep_resource(core::ptr::null_mut());
assert_eq!(result.unwrap_err(), ResourceError::BadArg);
}
#[test]
fn test_make_and_get_resource() {
let mut manager = MockResourceManager::new();
let env = core::ptr::null_mut();
let resource_type = manager.init_resource_type(
env,
"test_type",
&resource_type_init(),
ErlNifResourceFlags::ERL_NIF_RT_CREATE,
).unwrap();
let resource_ptr = manager.alloc_resource(resource_type, 1024).unwrap();
let term = manager.make_resource(env, resource_ptr).unwrap();
assert!(term != 0);
let retrieved_ptr = manager.get_resource(env, term, resource_type).unwrap();
assert_eq!(retrieved_ptr, resource_ptr);
let other_type = manager.init_resource_type(
env,
"other_type",
&resource_type_init(),
ErlNifResourceFlags::ERL_NIF_RT_CREATE,
).unwrap();
let result = manager.get_resource(env, term, other_type);
assert_eq!(result.unwrap_err(), ResourceError::ResourceNotFound);
}
#[test]
fn test_process_monitoring() {
let mut manager = MockResourceManager::new();
let env = core::ptr::null_mut();
let resource_type = manager.init_resource_type(
env,
"test_type",
&resource_type_init(),
ErlNifResourceFlags::ERL_NIF_RT_CREATE,
).unwrap();
let resource_ptr = manager.alloc_resource(resource_type, 1024).unwrap();
let pid = 12345i32;
let mut monitor = ErlNifMonitor {
resource_type: core::ptr::null_mut(),
ref_ticks: 0,
};
let result = manager.monitor_process(env, resource_ptr, &pid, &mut monitor);
assert!(result.is_ok());
assert_eq!(manager.get_monitor_count(), 1);
let result = manager.demonitor_process(env, resource_ptr, &monitor);
assert!(result.is_ok());
assert_eq!(manager.get_monitor_count(), 0);
}
#[test]
fn test_select_operations() {
let mut manager = MockResourceManager::new();
let env = core::ptr::null_mut();
let resource_type = manager.init_resource_type(
env,
"test_type",
&resource_type_init(),
ErlNifResourceFlags::ERL_NIF_RT_CREATE,
).unwrap();
let resource_ptr = manager.alloc_resource(resource_type, 1024).unwrap();
let pid = 12345i32;
let reference = 0x98765432u64;
let result = manager.select(
env,
5, ErlNifSelectFlags::ERL_NIF_SELECT_READ,
resource_ptr,
&pid,
reference,
);
assert!(result.is_ok());
let state = manager.get_state();
assert_eq!(state.select_calls.len(), 1);
assert_eq!(state.select_calls[0].0, 5); assert_eq!(state.select_calls[0].1, ErlNifSelectFlags::ERL_NIF_SELECT_READ); }
#[test]
fn test_error_injection() {
let mut manager = MockResourceManager::new();
let env = core::ptr::null_mut();
manager.set_fail_init(true);
let result = manager.init_resource_type(
env,
"test_resource",
&resource_type_init(),
ErlNifResourceFlags::ERL_NIF_RT_CREATE,
);
assert_eq!(result.unwrap_err(), ResourceError::InitializationFailed);
manager.set_fail_init(false);
let resource_type = manager.init_resource_type(
env,
"test_resource",
&resource_type_init(),
ErlNifResourceFlags::ERL_NIF_RT_CREATE,
).unwrap();
manager.set_fail_alloc(true);
let result = manager.alloc_resource(resource_type, 1024);
assert_eq!(result.unwrap_err(), ResourceError::OutOfMemory);
}
#[test]
fn test_resource_limits() {
let mut manager = MockResourceManager::new().with_max_resources(1);
let env = core::ptr::null_mut();
let resource_type = manager.init_resource_type(
env,
"test_type",
&resource_type_init(),
ErlNifResourceFlags::ERL_NIF_RT_CREATE,
).unwrap();
let result = manager.alloc_resource(resource_type, 1024);
assert!(result.is_ok());
let result = manager.alloc_resource(resource_type, 1024);
assert_eq!(result.unwrap_err(), ResourceError::OutOfMemory);
}
#[test]
fn test_error_conversion() {
assert_eq!(NifError::from(ResourceError::OutOfMemory), NifError::OutOfMemory);
assert_eq!(NifError::from(ResourceError::BadArg), NifError::BadArg);
assert_eq!(NifError::from(ResourceError::InvalidName), NifError::BadArg);
}
#[test]
fn test_global_manager_integration() {
let manager = MockResourceManager::new();
init_resource_manager(manager);
let _global_manager = get_resource_manager();
}
#[test]
fn test_helper_functions() {
let init = resource_type_init();
assert_eq!(init.members, 0);
assert!(init.dtor.is_none());
assert!(init.stop.is_none());
assert!(init.down.is_none());
unsafe extern "C" fn test_dtor(_env: *mut ErlNifEnv, _obj: *mut core::ffi::c_void) {}
let init_with_dtor = resource_type_init_with_dtor(test_dtor);
assert_eq!(init_with_dtor.members, 1);
assert!(init_with_dtor.dtor.is_some());
let init_full = resource_type_init_full(Some(test_dtor), None, None);
assert_eq!(init_full.members, 1);
assert!(init_full.dtor.is_some());
assert!(init_full.stop.is_none());
assert!(init_full.down.is_none());
}
#[test]
fn test_resource_type_flags() {
assert_eq!(ErlNifResourceFlags::ERL_NIF_RT_CREATE as i32, 1);
assert_eq!(ErlNifSelectFlags::ERL_NIF_SELECT_READ as i32, 1);
assert_eq!(ErlNifSelectFlags::ERL_NIF_SELECT_WRITE as i32, 2);
assert_eq!(ErlNifSelectFlags::ERL_NIF_SELECT_STOP as i32, 4);
let flag1 = ErlNifResourceFlags::ERL_NIF_RT_CREATE;
let flag2 = ErlNifResourceFlags::ERL_NIF_RT_CREATE;
assert_eq!(flag1, flag2);
let _flag3 = flag1; assert_eq!(flag1, flag2); }
#[test]
fn test_concurrent_access_simulation() {
let mut manager = MockResourceManager::new();
let env = core::ptr::null_mut();
let resource_type = manager.init_resource_type(
env,
"concurrent_test",
&resource_type_init(),
ErlNifResourceFlags::ERL_NIF_RT_CREATE,
).unwrap();
let mut resources = alloc::vec::Vec::new();
for i in 0..10 {
let resource = manager.alloc_resource(resource_type, 100 + i).unwrap();
resources.push(resource);
}
assert_eq!(manager.get_resource_count(), 10);
for resource in &resources {
assert!(manager.keep_resource(*resource).is_ok());
}
for resource in &resources {
assert_eq!(manager.get_resource_ref_count(*resource), Some(2));
}
for resource in &resources {
assert!(manager.release_resource(*resource).is_ok());
assert!(manager.release_resource(*resource).is_ok());
}
assert_eq!(manager.get_resource_count(), 0);
}
}