#![allow(unsafe_code, clippy::missing_safety_doc)]
use i2pd_sys::*;
use std::os::raw::c_void;
use std::ptr;
#[test]
fn null_pointer_returns_null() {
let hash = [0u8; 32];
unsafe {
assert!(i2pd_destination_b32_address(ptr::null_mut()).is_null());
assert!(i2pd_create_stream(ptr::null_mut(), hash.as_ptr(), 1).is_null());
assert!(i2pd_create_stream(ptr::null_mut(), ptr::null(), 1).is_null());
assert!(i2pd_create_persistent_destination(ptr::null(), 0, 1, ptr::null()).is_null());
assert!(i2pd_create_persistent_destination(hash.as_ptr(), 0, 1, ptr::null()).is_null());
}
}
#[test]
fn null_pointer_returns_failure() {
let mut out = [0u8; 32];
let mut out_buf: *mut u8 = ptr::null_mut();
let mut out_len: usize = 0;
unsafe {
assert_eq!(i2pd_destination_ident_hash(ptr::null_mut(), out.as_mut_ptr()), 0);
assert_eq!(i2pd_destination_ident_hash(ptr::null_mut(), ptr::null_mut()), 0);
assert_eq!(i2pd_generate_keys(7, 4, ptr::null_mut(), &mut out_len), 0);
assert_eq!(i2pd_generate_keys(7, 4, &mut out_buf, ptr::null_mut()), 0);
assert_eq!(i2pd_stream_is_open(ptr::null_mut()), 0);
}
}
#[test]
fn null_stream_returns_error() {
let payload = b"hello";
let mut buf = [0u8; 16];
unsafe {
assert_eq!(i2pd_stream_send(ptr::null_mut(), payload.as_ptr(), payload.len()), -1);
assert_eq!(i2pd_stream_receive(ptr::null_mut(), buf.as_mut_ptr(), buf.len(), 1), -1);
}
}
#[test]
fn null_pointer_is_noop() {
unsafe extern "C" fn cb(_ctx: *mut c_void, _stream: *mut I2pdStream) {
panic!("callback must never fire for a null destination");
}
unsafe {
i2pd_init(ptr::null());
i2pd_destroy_destination(ptr::null_mut());
i2pd_accept_stream(ptr::null_mut(), Some(cb), ptr::null_mut());
i2pd_accept_stream(ptr::null_mut(), None, ptr::null_mut());
i2pd_stream_close(ptr::null_mut());
i2pd_destroy_stream(ptr::null_mut());
i2pd_free_string(ptr::null_mut());
i2pd_free_buffer(ptr::null_mut(), 0);
i2pd_free_buffer(ptr::null_mut(), 64);
}
}
#[test]
fn malformed_keys_buffer_is_rejected() {
let garbage = [0xAAu8; 64];
unsafe {
assert!(i2pd_create_persistent_destination(garbage.as_ptr(), garbage.len(), 1, ptr::null()).is_null());
}
}
#[test]
fn transit_support_matches_the_selected_feature() {
let reported = unsafe { i2pd_accepts_transit() };
assert_eq!(
reported,
i32::from(cfg!(feature = "transit")),
"i2pd_accepts_transit() reported {reported}, which disagrees with the `transit` feature -- \
the I2PD_SYS_NO_TRANSIT define is not reaching both the shim and libi2pd"
);
}
#[test]
fn participation_setters_before_init_are_noops() {
unsafe {
i2pd_set_accepts_transit(1);
i2pd_set_accepts_transit(0);
i2pd_set_bandwidth_limit(1024);
i2pd_set_bandwidth_limit(0);
i2pd_set_bandwidth_limit(-5);
i2pd_set_share_percent(50);
i2pd_set_share_percent(-10);
i2pd_set_share_percent(1000);
i2pd_set_max_transit_tunnels(64);
i2pd_set_max_transit_tunnels(0);
i2pd_set_max_transit_tunnels(-1);
i2pd_set_floodfill(0);
}
}