working sys level bindings :yippie:
This commit is contained in:
parent
4508aeab76
commit
e9022e675b
12 changed files with 3091 additions and 45 deletions
639
nixide-sys/tests/primop.rs
Normal file
639
nixide-sys/tests/primop.rs
Normal file
|
|
@ -0,0 +1,639 @@
|
|||
#![cfg(test)]
|
||||
|
||||
use std::{
|
||||
ffi::CString,
|
||||
sync::atomic::{AtomicU32, Ordering},
|
||||
};
|
||||
|
||||
use nixide_sys::*;
|
||||
use serial_test::serial;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct TestPrimOpData {
|
||||
call_count: AtomicU32,
|
||||
last_arg_value: AtomicU32,
|
||||
}
|
||||
|
||||
// Simple PrimOp that adds 1 to an integer argument
|
||||
unsafe extern "C" fn add_one_primop(
|
||||
user_data: *mut ::std::os::raw::c_void,
|
||||
context: *mut nix_c_context,
|
||||
state: *mut EvalState,
|
||||
args: *mut *mut nix_value,
|
||||
ret: *mut nix_value,
|
||||
) {
|
||||
if user_data.is_null()
|
||||
|| context.is_null()
|
||||
|| state.is_null()
|
||||
|| args.is_null()
|
||||
|| ret.is_null()
|
||||
{
|
||||
let _ = unsafe {
|
||||
nix_set_err_msg(
|
||||
context,
|
||||
nix_err_NIX_ERR_UNKNOWN,
|
||||
b"Null pointer in add_one_primop\0".as_ptr() as *const _,
|
||||
)
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
let data = unsafe { &*(user_data as *const TestPrimOpData) };
|
||||
data.call_count.fetch_add(1, Ordering::SeqCst);
|
||||
|
||||
// Get first argument
|
||||
let arg = unsafe { *args.offset(0) };
|
||||
if arg.is_null() {
|
||||
let _ = unsafe {
|
||||
nix_set_err_msg(
|
||||
context,
|
||||
nix_err_NIX_ERR_UNKNOWN,
|
||||
b"Missing argument in add_one_primop\0".as_ptr() as *const _,
|
||||
)
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
// Force evaluation of argument
|
||||
if unsafe { nix_value_force(context, state, arg) } != nix_err_NIX_OK {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if argument is integer
|
||||
if unsafe { nix_get_type(context, arg) } != ValueType_NIX_TYPE_INT {
|
||||
let _ = unsafe {
|
||||
nix_set_err_msg(
|
||||
context,
|
||||
nix_err_NIX_ERR_UNKNOWN,
|
||||
b"Expected integer argument in add_one_primop\0".as_ptr() as *const _,
|
||||
)
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
// Get integer value and add 1
|
||||
let value = unsafe { nix_get_int(context, arg) };
|
||||
data.last_arg_value.store(value as u32, Ordering::SeqCst);
|
||||
|
||||
// Set return value
|
||||
let _ = unsafe { nix_init_int(context, ret, value + 1) };
|
||||
}
|
||||
|
||||
// PrimOp that returns a constant string
|
||||
unsafe extern "C" fn hello_world_primop(
|
||||
_user_data: *mut ::std::os::raw::c_void,
|
||||
context: *mut nix_c_context,
|
||||
_state: *mut EvalState,
|
||||
_args: *mut *mut nix_value,
|
||||
ret: *mut nix_value,
|
||||
) {
|
||||
let hello = CString::new("Hello from Rust PrimOp!").unwrap();
|
||||
let _ = unsafe { nix_init_string(context, ret, hello.as_ptr()) };
|
||||
}
|
||||
|
||||
// PrimOp that takes multiple arguments and concatenates them
|
||||
unsafe extern "C" fn concat_strings_primop(
|
||||
_user_data: *mut ::std::os::raw::c_void,
|
||||
context: *mut nix_c_context,
|
||||
state: *mut EvalState,
|
||||
args: *mut *mut nix_value,
|
||||
ret: *mut nix_value,
|
||||
) {
|
||||
if context.is_null() || state.is_null() || args.is_null() || ret.is_null() {
|
||||
return;
|
||||
}
|
||||
|
||||
// This PrimOp expects exactly 2 string arguments
|
||||
let mut result = String::new();
|
||||
|
||||
for i in 0..2 {
|
||||
let arg = unsafe { *args.offset(i) };
|
||||
if arg.is_null() {
|
||||
let _ = unsafe {
|
||||
nix_set_err_msg(
|
||||
context,
|
||||
nix_err_NIX_ERR_UNKNOWN,
|
||||
b"Missing argument in concat_strings_primop\0".as_ptr() as *const _,
|
||||
)
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
// Force evaluation
|
||||
if unsafe { nix_value_force(context, state, arg) } != nix_err_NIX_OK {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if it's a string
|
||||
if unsafe { nix_get_type(context, arg) } != ValueType_NIX_TYPE_STRING {
|
||||
let _ = unsafe {
|
||||
static ITEMS: &[u8] = b"Expected string argument in concat_strings_primop\0";
|
||||
nix_set_err_msg(context, nix_err_NIX_ERR_UNKNOWN, ITEMS.as_ptr() as *const _)
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
// Get string value using callback
|
||||
unsafe extern "C" fn string_callback(
|
||||
start: *const ::std::os::raw::c_char,
|
||||
n: ::std::os::raw::c_uint,
|
||||
user_data: *mut ::std::os::raw::c_void,
|
||||
) {
|
||||
let s = unsafe { std::slice::from_raw_parts(start.cast::<u8>(), n as usize) };
|
||||
let s = std::str::from_utf8(s).unwrap_or("");
|
||||
let result = unsafe { &mut *(user_data as *mut String) };
|
||||
result.push_str(s);
|
||||
}
|
||||
|
||||
let _ = unsafe {
|
||||
nix_get_string(
|
||||
context,
|
||||
arg,
|
||||
Some(string_callback),
|
||||
&mut result as *mut String as *mut ::std::os::raw::c_void,
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
let result_cstr = CString::new(result).unwrap_or_else(|_| CString::new("").unwrap());
|
||||
let _ = unsafe { nix_init_string(context, ret, result_cstr.as_ptr()) };
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn primop_allocation_and_registration() {
|
||||
unsafe {
|
||||
let ctx = nix_c_context_create();
|
||||
assert!(!ctx.is_null());
|
||||
|
||||
let err = nix_libutil_init(ctx);
|
||||
assert_eq!(err, nix_err_NIX_OK);
|
||||
|
||||
let err = nix_libstore_init(ctx);
|
||||
assert_eq!(err, nix_err_NIX_OK);
|
||||
|
||||
let err = nix_libexpr_init(ctx);
|
||||
assert_eq!(err, nix_err_NIX_OK);
|
||||
|
||||
let store = nix_store_open(ctx, std::ptr::null(), std::ptr::null_mut());
|
||||
assert!(!store.is_null());
|
||||
|
||||
let builder = nix_eval_state_builder_new(ctx, store);
|
||||
assert!(!builder.is_null());
|
||||
|
||||
let load_err = nix_eval_state_builder_load(ctx, builder);
|
||||
assert_eq!(load_err, nix_err_NIX_OK);
|
||||
|
||||
let state = nix_eval_state_build(ctx, builder);
|
||||
assert!(!state.is_null());
|
||||
|
||||
// Create test data
|
||||
let test_data = Box::new(TestPrimOpData {
|
||||
call_count: AtomicU32::new(0),
|
||||
last_arg_value: AtomicU32::new(0),
|
||||
});
|
||||
let test_data_ptr = Box::into_raw(test_data);
|
||||
|
||||
// Create argument names
|
||||
let arg_names = [CString::new("x").unwrap()];
|
||||
let arg_name_ptrs: Vec<*const _> = arg_names.iter().map(|s| s.as_ptr()).collect();
|
||||
let mut arg_name_ptrs_null_terminated = arg_name_ptrs;
|
||||
arg_name_ptrs_null_terminated.push(std::ptr::null());
|
||||
|
||||
let name = CString::new("addOne").unwrap();
|
||||
let doc = CString::new("Add 1 to the argument").unwrap();
|
||||
|
||||
// Allocate PrimOp
|
||||
let primop = nix_alloc_primop(
|
||||
ctx,
|
||||
Some(add_one_primop),
|
||||
1, // arity
|
||||
name.as_ptr(),
|
||||
arg_name_ptrs_null_terminated.as_mut_ptr(),
|
||||
doc.as_ptr(),
|
||||
test_data_ptr as *mut ::std::os::raw::c_void,
|
||||
);
|
||||
|
||||
if !primop.is_null() {
|
||||
// Register the PrimOp globally
|
||||
let register_err = nix_register_primop(ctx, primop);
|
||||
// Registration may fail in some environments, but allocation should work
|
||||
assert!(
|
||||
register_err == nix_err_NIX_OK || register_err == nix_err_NIX_ERR_UNKNOWN,
|
||||
"Unexpected error code: {register_err}"
|
||||
);
|
||||
|
||||
// Test using the PrimOp by creating a value with it
|
||||
let primop_value = nix_alloc_value(ctx, state);
|
||||
assert!(!primop_value.is_null());
|
||||
|
||||
let init_err = nix_init_primop(ctx, primop_value, primop);
|
||||
assert_eq!(init_err, nix_err_NIX_OK);
|
||||
|
||||
// Clean up value
|
||||
nix_value_decref(ctx, primop_value);
|
||||
}
|
||||
|
||||
// Clean up
|
||||
let _ = Box::from_raw(test_data_ptr);
|
||||
nix_state_free(state);
|
||||
nix_eval_state_builder_free(builder);
|
||||
nix_store_free(store);
|
||||
nix_c_context_free(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn primop_function_call() {
|
||||
unsafe {
|
||||
let ctx = nix_c_context_create();
|
||||
assert!(!ctx.is_null());
|
||||
|
||||
let err = nix_libutil_init(ctx);
|
||||
assert_eq!(err, nix_err_NIX_OK);
|
||||
|
||||
let err = nix_libstore_init(ctx);
|
||||
assert_eq!(err, nix_err_NIX_OK);
|
||||
|
||||
let err = nix_libexpr_init(ctx);
|
||||
assert_eq!(err, nix_err_NIX_OK);
|
||||
|
||||
let store = nix_store_open(ctx, std::ptr::null(), std::ptr::null_mut());
|
||||
assert!(!store.is_null());
|
||||
|
||||
let builder = nix_eval_state_builder_new(ctx, store);
|
||||
assert!(!builder.is_null());
|
||||
|
||||
let load_err = nix_eval_state_builder_load(ctx, builder);
|
||||
assert_eq!(load_err, nix_err_NIX_OK);
|
||||
|
||||
let state = nix_eval_state_build(ctx, builder);
|
||||
assert!(!state.is_null());
|
||||
|
||||
// Create test data
|
||||
let test_data = Box::new(TestPrimOpData {
|
||||
call_count: AtomicU32::new(0),
|
||||
last_arg_value: AtomicU32::new(0),
|
||||
});
|
||||
let test_data_ptr = Box::into_raw(test_data);
|
||||
|
||||
// Create simple hello world PrimOp (no arguments)
|
||||
let name = CString::new("helloWorld").unwrap();
|
||||
let doc = CString::new("Returns hello world string").unwrap();
|
||||
let mut empty_args: Vec<*const ::std::os::raw::c_char> = vec![std::ptr::null()];
|
||||
|
||||
let hello_primop = nix_alloc_primop(
|
||||
ctx,
|
||||
Some(hello_world_primop),
|
||||
0, // arity
|
||||
name.as_ptr(),
|
||||
empty_args.as_mut_ptr(),
|
||||
doc.as_ptr(),
|
||||
std::ptr::null_mut(),
|
||||
);
|
||||
|
||||
if !hello_primop.is_null() {
|
||||
// Create a value with the PrimOp
|
||||
let primop_value = nix_alloc_value(ctx, state);
|
||||
assert!(!primop_value.is_null());
|
||||
|
||||
let init_err = nix_init_primop(ctx, primop_value, hello_primop);
|
||||
assert_eq!(init_err, nix_err_NIX_OK);
|
||||
|
||||
// Call the PrimOp (no arguments)
|
||||
let result = nix_alloc_value(ctx, state);
|
||||
assert!(!result.is_null());
|
||||
|
||||
let call_err = nix_value_call(ctx, state, primop_value, std::ptr::null_mut(), result);
|
||||
if call_err == nix_err_NIX_OK {
|
||||
// Force the result
|
||||
let force_err = nix_value_force(ctx, state, result);
|
||||
assert_eq!(force_err, nix_err_NIX_OK);
|
||||
|
||||
// Check if result is a string
|
||||
let result_type = nix_get_type(ctx, result);
|
||||
if result_type == ValueType_NIX_TYPE_STRING {
|
||||
// Get string value
|
||||
unsafe extern "C" fn string_callback(
|
||||
start: *const ::std::os::raw::c_char,
|
||||
n: ::std::os::raw::c_uint,
|
||||
user_data: *mut ::std::os::raw::c_void,
|
||||
) {
|
||||
let s =
|
||||
unsafe { std::slice::from_raw_parts(start.cast::<u8>(), n as usize) };
|
||||
let s = std::str::from_utf8(s).unwrap_or("");
|
||||
let result = unsafe { &mut *(user_data as *mut Option<String>) };
|
||||
*result = Some(s.to_string());
|
||||
}
|
||||
|
||||
let mut string_result: Option<String> = None;
|
||||
let _ = nix_get_string(
|
||||
ctx,
|
||||
result,
|
||||
Some(string_callback),
|
||||
&mut string_result as *mut Option<String> as *mut ::std::os::raw::c_void,
|
||||
);
|
||||
|
||||
// Verify we got the expected string
|
||||
assert!(string_result
|
||||
.as_deref()
|
||||
.unwrap_or("")
|
||||
.contains("Hello from Rust"));
|
||||
}
|
||||
}
|
||||
|
||||
nix_value_decref(ctx, result);
|
||||
nix_value_decref(ctx, primop_value);
|
||||
}
|
||||
|
||||
// Clean up
|
||||
let _ = Box::from_raw(test_data_ptr);
|
||||
nix_state_free(state);
|
||||
nix_eval_state_builder_free(builder);
|
||||
nix_store_free(store);
|
||||
nix_c_context_free(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn primop_with_arguments() {
|
||||
unsafe {
|
||||
let ctx = nix_c_context_create();
|
||||
assert!(!ctx.is_null());
|
||||
|
||||
let err = nix_libutil_init(ctx);
|
||||
assert_eq!(err, nix_err_NIX_OK);
|
||||
|
||||
let err = nix_libstore_init(ctx);
|
||||
assert_eq!(err, nix_err_NIX_OK);
|
||||
|
||||
let err = nix_libexpr_init(ctx);
|
||||
assert_eq!(err, nix_err_NIX_OK);
|
||||
|
||||
let store = nix_store_open(ctx, std::ptr::null(), std::ptr::null_mut());
|
||||
assert!(!store.is_null());
|
||||
|
||||
let builder = nix_eval_state_builder_new(ctx, store);
|
||||
assert!(!builder.is_null());
|
||||
|
||||
let load_err = nix_eval_state_builder_load(ctx, builder);
|
||||
assert_eq!(load_err, nix_err_NIX_OK);
|
||||
|
||||
let state = nix_eval_state_build(ctx, builder);
|
||||
assert!(!state.is_null());
|
||||
|
||||
// Create test data
|
||||
let test_data = Box::new(TestPrimOpData {
|
||||
call_count: AtomicU32::new(0),
|
||||
last_arg_value: AtomicU32::new(0),
|
||||
});
|
||||
let test_data_ptr = Box::into_raw(test_data);
|
||||
|
||||
// Create add one PrimOp
|
||||
let arg_names = [CString::new("x").unwrap()];
|
||||
let arg_name_ptrs: Vec<*const _> = arg_names.iter().map(|s| s.as_ptr()).collect();
|
||||
let mut arg_name_ptrs_null_terminated = arg_name_ptrs;
|
||||
arg_name_ptrs_null_terminated.push(std::ptr::null());
|
||||
|
||||
let name = CString::new("addOne").unwrap();
|
||||
let doc = CString::new("Add 1 to the argument").unwrap();
|
||||
|
||||
let add_primop = nix_alloc_primop(
|
||||
ctx,
|
||||
Some(add_one_primop),
|
||||
1, // arity
|
||||
name.as_ptr(),
|
||||
arg_name_ptrs_null_terminated.as_mut_ptr(),
|
||||
doc.as_ptr(),
|
||||
test_data_ptr as *mut ::std::os::raw::c_void,
|
||||
);
|
||||
|
||||
if !add_primop.is_null() {
|
||||
// Create a value with the PrimOp
|
||||
let primop_value = nix_alloc_value(ctx, state);
|
||||
assert!(!primop_value.is_null());
|
||||
|
||||
let init_err = nix_init_primop(ctx, primop_value, add_primop);
|
||||
assert_eq!(init_err, nix_err_NIX_OK);
|
||||
|
||||
// Create an integer argument
|
||||
let arg_value = nix_alloc_value(ctx, state);
|
||||
assert!(!arg_value.is_null());
|
||||
|
||||
let init_arg_err = nix_init_int(ctx, arg_value, 42);
|
||||
assert_eq!(init_arg_err, nix_err_NIX_OK);
|
||||
|
||||
// Call the PrimOp with the argument
|
||||
let result = nix_alloc_value(ctx, state);
|
||||
assert!(!result.is_null());
|
||||
|
||||
let call_err = nix_value_call(ctx, state, primop_value, arg_value, result);
|
||||
if call_err == nix_err_NIX_OK {
|
||||
// Force the result
|
||||
let force_err = nix_value_force(ctx, state, result);
|
||||
assert_eq!(force_err, nix_err_NIX_OK);
|
||||
|
||||
// Check if result is an integer
|
||||
let result_type = nix_get_type(ctx, result);
|
||||
if result_type == ValueType_NIX_TYPE_INT {
|
||||
let result_value = nix_get_int(ctx, result);
|
||||
assert_eq!(result_value, 43); // 42 + 1
|
||||
|
||||
// Verify callback was called
|
||||
let test_data_ref = &*test_data_ptr;
|
||||
assert_eq!(test_data_ref.call_count.load(Ordering::SeqCst), 1);
|
||||
assert_eq!(test_data_ref.last_arg_value.load(Ordering::SeqCst), 42);
|
||||
}
|
||||
}
|
||||
|
||||
nix_value_decref(ctx, result);
|
||||
nix_value_decref(ctx, arg_value);
|
||||
nix_value_decref(ctx, primop_value);
|
||||
}
|
||||
|
||||
// Clean up
|
||||
let _ = Box::from_raw(test_data_ptr);
|
||||
nix_state_free(state);
|
||||
nix_eval_state_builder_free(builder);
|
||||
nix_store_free(store);
|
||||
nix_c_context_free(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn primop_multi_argument() {
|
||||
unsafe {
|
||||
let ctx = nix_c_context_create();
|
||||
assert!(!ctx.is_null());
|
||||
|
||||
let err = nix_libutil_init(ctx);
|
||||
assert_eq!(err, nix_err_NIX_OK);
|
||||
|
||||
let err = nix_libstore_init(ctx);
|
||||
assert_eq!(err, nix_err_NIX_OK);
|
||||
|
||||
let err = nix_libexpr_init(ctx);
|
||||
assert_eq!(err, nix_err_NIX_OK);
|
||||
|
||||
let store = nix_store_open(ctx, std::ptr::null(), std::ptr::null_mut());
|
||||
assert!(!store.is_null());
|
||||
|
||||
let builder = nix_eval_state_builder_new(ctx, store);
|
||||
assert!(!builder.is_null());
|
||||
|
||||
let load_err = nix_eval_state_builder_load(ctx, builder);
|
||||
assert_eq!(load_err, nix_err_NIX_OK);
|
||||
|
||||
let state = nix_eval_state_build(ctx, builder);
|
||||
assert!(!state.is_null());
|
||||
|
||||
// Create concat strings PrimOp
|
||||
let arg_names = [CString::new("s1").unwrap(), CString::new("s2").unwrap()];
|
||||
let arg_name_ptrs: Vec<*const _> = arg_names.iter().map(|s| s.as_ptr()).collect();
|
||||
let mut arg_name_ptrs_null_terminated = arg_name_ptrs;
|
||||
arg_name_ptrs_null_terminated.push(std::ptr::null());
|
||||
|
||||
let name = CString::new("concatStrings").unwrap();
|
||||
let doc = CString::new("Concatenate two strings").unwrap();
|
||||
|
||||
let concat_primop = nix_alloc_primop(
|
||||
ctx,
|
||||
Some(concat_strings_primop),
|
||||
2, // arity
|
||||
name.as_ptr(),
|
||||
arg_name_ptrs_null_terminated.as_mut_ptr(),
|
||||
doc.as_ptr(),
|
||||
std::ptr::null_mut(),
|
||||
);
|
||||
|
||||
if !concat_primop.is_null() {
|
||||
// Create a value with the PrimOp
|
||||
let primop_value = nix_alloc_value(ctx, state);
|
||||
assert!(!primop_value.is_null());
|
||||
|
||||
let init_err = nix_init_primop(ctx, primop_value, concat_primop);
|
||||
assert_eq!(init_err, nix_err_NIX_OK);
|
||||
|
||||
// Create string arguments
|
||||
let arg1 = nix_alloc_value(ctx, state);
|
||||
let arg2 = nix_alloc_value(ctx, state);
|
||||
assert!(!arg1.is_null() && !arg2.is_null());
|
||||
|
||||
let hello_cstr = CString::new("Hello, ").unwrap();
|
||||
let world_cstr = CString::new("World!").unwrap();
|
||||
|
||||
let init_arg1_err = nix_init_string(ctx, arg1, hello_cstr.as_ptr());
|
||||
let init_arg2_err = nix_init_string(ctx, arg2, world_cstr.as_ptr());
|
||||
assert_eq!(init_arg1_err, nix_err_NIX_OK);
|
||||
assert_eq!(init_arg2_err, nix_err_NIX_OK);
|
||||
|
||||
// Test multi-argument call using nix_value_call_multi
|
||||
let mut args = [arg1, arg2];
|
||||
let result = nix_alloc_value(ctx, state);
|
||||
assert!(!result.is_null());
|
||||
|
||||
let call_err =
|
||||
nix_value_call_multi(ctx, state, primop_value, 2, args.as_mut_ptr(), result);
|
||||
if call_err == nix_err_NIX_OK {
|
||||
// Force the result
|
||||
let force_err = nix_value_force(ctx, state, result);
|
||||
assert_eq!(force_err, nix_err_NIX_OK);
|
||||
|
||||
// Check if result is a string
|
||||
let result_type = nix_get_type(ctx, result);
|
||||
if result_type == ValueType_NIX_TYPE_STRING {
|
||||
unsafe extern "C" fn string_callback(
|
||||
start: *const ::std::os::raw::c_char,
|
||||
n: ::std::os::raw::c_uint,
|
||||
user_data: *mut ::std::os::raw::c_void,
|
||||
) {
|
||||
let s =
|
||||
unsafe { std::slice::from_raw_parts(start.cast::<u8>(), n as usize) };
|
||||
let s = std::str::from_utf8(s).unwrap_or("");
|
||||
let result = unsafe { &mut *(user_data as *mut Option<String>) };
|
||||
*result = Some(s.to_string());
|
||||
}
|
||||
|
||||
let mut string_result: Option<String> = None;
|
||||
let _ = nix_get_string(
|
||||
ctx,
|
||||
result,
|
||||
Some(string_callback),
|
||||
&mut string_result as *mut Option<String> as *mut ::std::os::raw::c_void,
|
||||
);
|
||||
|
||||
// Verify concatenation worked
|
||||
assert_eq!(string_result.as_deref(), Some("Hello, World!"));
|
||||
}
|
||||
}
|
||||
|
||||
nix_value_decref(ctx, result);
|
||||
nix_value_decref(ctx, arg2);
|
||||
nix_value_decref(ctx, arg1);
|
||||
nix_value_decref(ctx, primop_value);
|
||||
}
|
||||
|
||||
nix_state_free(state);
|
||||
nix_eval_state_builder_free(builder);
|
||||
nix_store_free(store);
|
||||
nix_c_context_free(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn primop_error_handling() {
|
||||
unsafe {
|
||||
let ctx = nix_c_context_create();
|
||||
assert!(!ctx.is_null());
|
||||
|
||||
let err = nix_libutil_init(ctx);
|
||||
assert_eq!(err, nix_err_NIX_OK);
|
||||
|
||||
let err = nix_libstore_init(ctx);
|
||||
assert_eq!(err, nix_err_NIX_OK);
|
||||
|
||||
let err = nix_libexpr_init(ctx);
|
||||
assert_eq!(err, nix_err_NIX_OK);
|
||||
|
||||
let store = nix_store_open(ctx, std::ptr::null(), std::ptr::null_mut());
|
||||
assert!(!store.is_null());
|
||||
|
||||
let builder = nix_eval_state_builder_new(ctx, store);
|
||||
assert!(!builder.is_null());
|
||||
|
||||
let load_err = nix_eval_state_builder_load(ctx, builder);
|
||||
assert_eq!(load_err, nix_err_NIX_OK);
|
||||
|
||||
let state = nix_eval_state_build(ctx, builder);
|
||||
assert!(!state.is_null());
|
||||
|
||||
// Test invalid PrimOp allocation (NULL callback)
|
||||
let name = CString::new("invalid").unwrap();
|
||||
let doc = CString::new("Invalid PrimOp").unwrap();
|
||||
let mut empty_args: Vec<*const ::std::os::raw::c_char> = vec![std::ptr::null()];
|
||||
|
||||
let _invalid_primop = nix_alloc_primop(
|
||||
ctx,
|
||||
None, // NULL callback should cause error
|
||||
0,
|
||||
name.as_ptr(),
|
||||
empty_args.as_mut_ptr(),
|
||||
doc.as_ptr(),
|
||||
std::ptr::null_mut(),
|
||||
);
|
||||
|
||||
// Test initializing value with NULL PrimOp (should fail)
|
||||
let test_value = nix_alloc_value(ctx, state);
|
||||
assert!(!test_value.is_null());
|
||||
|
||||
nix_value_decref(ctx, test_value);
|
||||
nix_state_free(state);
|
||||
nix_eval_state_builder_free(builder);
|
||||
nix_store_free(store);
|
||||
nix_c_context_free(ctx);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue