266 lines
8.3 KiB
Rust
266 lines
8.3 KiB
Rust
#![cfg(feature = "nix-store-c")]
|
|
#![cfg(test)]
|
|
|
|
use core::ffi::{c_char, c_uint, c_void};
|
|
use std::ffi::CString;
|
|
use std::{ptr, slice, str};
|
|
|
|
use serial_test::serial;
|
|
|
|
use nixide_sys::*;
|
|
|
|
#[test]
|
|
#[serial]
|
|
fn libstore_init_and_open_free() {
|
|
unsafe {
|
|
let ctx = nix_c_context_create();
|
|
assert!(!ctx.is_null());
|
|
let err = nix_libstore_init(ctx);
|
|
assert_eq!(err, NixErr::Ok);
|
|
|
|
// Open the default store (NULL URI, NULL params)
|
|
let store = nix_store_open(ctx, ptr::null(), ptr::null_mut());
|
|
assert!(!store.is_null());
|
|
|
|
// Free the store and context
|
|
nix_store_free(store);
|
|
nix_c_context_free(ctx);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
#[serial]
|
|
fn parse_and_clone_free_store_path() {
|
|
unsafe {
|
|
let ctx = nix_c_context_create();
|
|
assert!(!ctx.is_null());
|
|
let err = nix_libstore_init(ctx);
|
|
assert_eq!(err, NixErr::Ok);
|
|
|
|
let store = nix_store_open(ctx, ptr::null(), ptr::null_mut());
|
|
assert!(!store.is_null());
|
|
|
|
// Parse a store path (I'm using a dummy path, will likely be invalid but
|
|
// should not segfault) XXX: store_path may be null if path is invalid,
|
|
// but should not crash
|
|
let path_str = CString::new("/nix/store/dummy-path").unwrap();
|
|
let store_path = nix_store_parse_path(ctx, store, path_str.as_ptr());
|
|
|
|
if !store_path.is_null() {
|
|
// Clone and free
|
|
let cloned = nix_store_path_clone(store_path);
|
|
assert!(!cloned.is_null());
|
|
nix_store_path_free(cloned);
|
|
nix_store_path_free(store_path);
|
|
}
|
|
|
|
nix_store_free(store);
|
|
nix_c_context_free(ctx);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
#[serial]
|
|
fn store_get_uri_and_storedir() {
|
|
unsafe extern "C" fn string_callback(start: *const c_char, n: c_uint, user_data: *mut c_void) {
|
|
let s = unsafe { slice::from_raw_parts(start.cast::<u8>(), n as usize) };
|
|
let s = str::from_utf8(s).unwrap();
|
|
let out = user_data.cast::<Option<String>>();
|
|
unsafe { *out = Some(s.to_string()) };
|
|
}
|
|
|
|
unsafe {
|
|
let ctx = nix_c_context_create();
|
|
assert!(!ctx.is_null());
|
|
let err = nix_libstore_init(ctx);
|
|
assert_eq!(err, NixErr::Ok);
|
|
|
|
let store = nix_store_open(ctx, ptr::null(), ptr::null_mut());
|
|
assert!(!store.is_null());
|
|
|
|
let mut uri: Option<String> = None;
|
|
let res = nix_store_get_uri(ctx, store, Some(string_callback), (&raw mut uri).cast());
|
|
assert_eq!(res, NixErr::Ok);
|
|
assert!(uri.is_some());
|
|
|
|
let mut storedir: Option<String> = None;
|
|
let res = nix_store_get_storedir(
|
|
ctx,
|
|
store,
|
|
Some(string_callback),
|
|
(&raw mut storedir).cast(),
|
|
);
|
|
assert_eq!(res, NixErr::Ok);
|
|
assert!(storedir.is_some());
|
|
|
|
nix_store_free(store);
|
|
nix_c_context_free(ctx);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
#[serial]
|
|
fn libstore_init_no_load_config() {
|
|
unsafe {
|
|
let ctx = nix_c_context_create();
|
|
assert!(!ctx.is_null());
|
|
let err = nix_libstore_init_no_load_config(ctx);
|
|
assert_eq!(err, NixErr::Ok);
|
|
nix_c_context_free(ctx);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
#[serial]
|
|
fn store_is_valid_path_and_real_path() {
|
|
unsafe extern "C" fn string_callback(start: *const c_char, n: c_uint, user_data: *mut c_void) {
|
|
let s = unsafe { slice::from_raw_parts(start.cast::<u8>(), n as usize) };
|
|
let s = str::from_utf8(s).unwrap();
|
|
let out = user_data.cast::<Option<String>>();
|
|
unsafe { *out = Some(s.to_string()) };
|
|
}
|
|
|
|
unsafe {
|
|
let ctx = nix_c_context_create();
|
|
assert!(!ctx.is_null());
|
|
let err = nix_libstore_init(ctx);
|
|
assert_eq!(err, NixErr::Ok);
|
|
|
|
let store = nix_store_open(ctx, ptr::null(), ptr::null_mut());
|
|
assert!(!store.is_null());
|
|
|
|
// Use a dummy path (should not be valid, but should not crash)
|
|
let path_str = CString::new("/nix/store/dummy-path").unwrap();
|
|
let store_path = nix_store_parse_path(ctx, store, path_str.as_ptr());
|
|
if !store_path.is_null() {
|
|
let valid = nix_store_is_valid_path(ctx, store, store_path);
|
|
assert!(!valid, "Dummy path should not be valid");
|
|
|
|
let mut real_path: Option<String> = None;
|
|
let res = nix_store_real_path(
|
|
ctx,
|
|
store,
|
|
store_path,
|
|
Some(string_callback),
|
|
(&raw mut real_path).cast(),
|
|
);
|
|
// May fail, but should not crash
|
|
assert!(res == NixErr::Ok || res == NixErr::Unknown);
|
|
nix_store_path_free(store_path);
|
|
}
|
|
|
|
nix_store_free(store);
|
|
nix_c_context_free(ctx);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
#[serial]
|
|
fn store_path_name() {
|
|
unsafe extern "C" fn string_callback(start: *const c_char, n: c_uint, user_data: *mut c_void) {
|
|
let s = unsafe { slice::from_raw_parts(start.cast::<u8>(), n as usize) };
|
|
let s = str::from_utf8(s).unwrap();
|
|
let out = user_data.cast::<Option<String>>();
|
|
unsafe { *out = Some(s.to_string()) };
|
|
}
|
|
|
|
unsafe {
|
|
let ctx = nix_c_context_create();
|
|
assert!(!ctx.is_null());
|
|
let err = nix_libstore_init(ctx);
|
|
assert_eq!(err, NixErr::Ok);
|
|
|
|
let store = nix_store_open(ctx, ptr::null(), ptr::null_mut());
|
|
assert!(!store.is_null());
|
|
|
|
let path_str = CString::new("/nix/store/foo-bar-baz").unwrap();
|
|
let store_path = nix_store_parse_path(ctx, store, path_str.as_ptr());
|
|
if !store_path.is_null() {
|
|
let mut name: Option<String> = None;
|
|
nix_store_path_name(store_path, Some(string_callback), (&raw mut name).cast());
|
|
// Should extract the name part ("foo-bar-baz")
|
|
assert!(name.as_deref().unwrap_or("").contains("foo-bar-baz"));
|
|
nix_store_path_free(store_path);
|
|
}
|
|
|
|
nix_store_free(store);
|
|
nix_c_context_free(ctx);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
#[serial]
|
|
fn store_get_version() {
|
|
unsafe extern "C" fn string_callback(start: *const c_char, n: c_uint, user_data: *mut c_void) {
|
|
let s = unsafe { slice::from_raw_parts(start.cast::<u8>(), n as usize) };
|
|
let s = str::from_utf8(s).unwrap();
|
|
let out = user_data.cast::<Option<String>>();
|
|
unsafe { *out = Some(s.to_string()) };
|
|
}
|
|
|
|
unsafe {
|
|
let ctx = nix_c_context_create();
|
|
assert!(!ctx.is_null());
|
|
let err = nix_libstore_init(ctx);
|
|
assert_eq!(err, NixErr::Ok);
|
|
|
|
let store = nix_store_open(ctx, ptr::null(), ptr::null_mut());
|
|
assert!(!store.is_null());
|
|
|
|
let mut version: Option<String> = None;
|
|
let res =
|
|
nix_store_get_version(ctx, store, Some(string_callback), (&raw mut version).cast());
|
|
assert_eq!(res, NixErr::Ok);
|
|
// Version may be empty for dummy stores, but should not crash
|
|
assert!(version.is_some());
|
|
|
|
nix_store_free(store);
|
|
nix_c_context_free(ctx);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
#[serial]
|
|
fn store_realise_and_copy_closure() {
|
|
unsafe extern "C" fn realise_callback(
|
|
_userdata: *mut c_void,
|
|
outname: *const c_char,
|
|
out: *const StorePath,
|
|
) {
|
|
// Just check that callback is called with non-null pointers
|
|
assert!(!outname.is_null());
|
|
assert!(!out.is_null());
|
|
}
|
|
|
|
unsafe {
|
|
let ctx = nix_c_context_create();
|
|
assert!(!ctx.is_null());
|
|
let err = nix_libstore_init(ctx);
|
|
assert_eq!(err, NixErr::Ok);
|
|
|
|
let store = nix_store_open(ctx, ptr::null(), ptr::null_mut());
|
|
assert!(!store.is_null());
|
|
|
|
// Use a dummy path (should not crash, may not realise)
|
|
let path_str = CString::new("/nix/store/dummy-path").unwrap();
|
|
let store_path = nix_store_parse_path(ctx, store, path_str.as_ptr());
|
|
if !store_path.is_null() {
|
|
// Realise (should fail, but must not crash)
|
|
let _ = nix_store_realise(
|
|
ctx,
|
|
store,
|
|
store_path,
|
|
ptr::null_mut(),
|
|
Some(realise_callback),
|
|
);
|
|
|
|
// Copy closure to same store (should fail, but must not crash)
|
|
let _ = nix_store_copy_closure(ctx, store, store, store_path);
|
|
|
|
nix_store_path_free(store_path);
|
|
}
|
|
|
|
nix_store_free(store);
|
|
nix_c_context_free(ctx);
|
|
}
|
|
}
|