i2pd-sys 0.0.3

Raw FFI bindings to a minimal C shim over libi2pd (PurpleI2P/i2pd).
Documentation
//! Null/invalid-argument safety checks for every shim function that takes a pointer.
//!
//! `shim.cpp` documents that every entry point null-checks its arguments *before* touching any
//! i2pd global state (see the `if (!dest || ...) return ...;` guards at the top of each
//! function) -- these tests hold that contract to account. Deliberately independent of
//! `i2pd_init`/`i2pd_start`: none of these calls should ever reach into i2pd's internals, so
//! there's nothing here that needs the router running, and these are safe to run as ordinary
//! parallel `#[test]` functions (unlike anything that touches i2pd's global router-context state
//! -- see `tests/local_lifecycle.rs` for why that one is a single combined test instead).
#![allow(unsafe_code, clippy::missing_safety_doc)]

use i2pd_sys::*;
use std::os::raw::c_void;
use std::ptr;

#[test]
fn init_null_app_name_is_noop() {
    unsafe {
        i2pd_init(ptr::null());
    }
}

#[test]
fn destroy_destination_null_is_noop() {
    unsafe {
        i2pd_destroy_destination(ptr::null_mut());
    }
}

#[test]
fn destination_b32_address_null_returns_null() {
    unsafe {
        assert!(i2pd_destination_b32_address(ptr::null_mut()).is_null());
    }
}

#[test]
fn destination_ident_hash_null_dest_returns_failure() {
    unsafe {
        let mut out = [0u8; 32];
        assert_eq!(i2pd_destination_ident_hash(ptr::null_mut(), out.as_mut_ptr()), 0);
    }
}

#[test]
fn destination_ident_hash_null_out_returns_failure() {
    unsafe {
        assert_eq!(i2pd_destination_ident_hash(ptr::null_mut(), ptr::null_mut()), 0);
    }
}

#[test]
fn accept_stream_null_dest_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_accept_stream(ptr::null_mut(), Some(cb), ptr::null_mut());
    }
}

#[test]
fn accept_stream_null_callback_is_noop() {
    unsafe {
        i2pd_accept_stream(ptr::null_mut(), None, ptr::null_mut());
    }
}

#[test]
fn create_stream_null_dest_returns_null() {
    unsafe {
        let hash = [0u8; 32];
        assert!(i2pd_create_stream(ptr::null_mut(), hash.as_ptr(), 1).is_null());
    }
}

#[test]
fn create_stream_null_hash_returns_null() {
    unsafe {
        assert!(i2pd_create_stream(ptr::null_mut(), ptr::null(), 1).is_null());
    }
}

#[test]
fn stream_send_null_stream_returns_error() {
    unsafe {
        let payload = b"hello";
        assert_eq!(i2pd_stream_send(ptr::null_mut(), payload.as_ptr(), payload.len()), -1);
    }
}

#[test]
fn stream_receive_null_stream_returns_error() {
    unsafe {
        let mut buf = [0u8; 16];
        assert_eq!(i2pd_stream_receive(ptr::null_mut(), buf.as_mut_ptr(), buf.len(), 1), -1);
    }
}

#[test]
fn stream_is_open_null_stream_returns_false() {
    unsafe {
        assert_eq!(i2pd_stream_is_open(ptr::null_mut()), 0);
    }
}

#[test]
fn stream_close_null_stream_is_noop() {
    unsafe {
        i2pd_stream_close(ptr::null_mut());
    }
}

#[test]
fn destroy_stream_null_is_noop() {
    unsafe {
        i2pd_destroy_stream(ptr::null_mut());
    }
}

#[test]
fn free_buffer_null_is_noop() {
    unsafe {
        i2pd_free_buffer(ptr::null_mut());
    }
}

#[test]
fn free_string_null_is_noop() {
    unsafe {
        i2pd_free_string(ptr::null_mut());
    }
}

#[test]
fn create_persistent_destination_null_buf_returns_null() {
    unsafe {
        assert!(i2pd_create_persistent_destination(ptr::null(), 0, 1).is_null());
    }
}

#[test]
fn create_persistent_destination_zero_len_returns_null() {
    unsafe {
        let buf = [0u8; 4];
        assert!(i2pd_create_persistent_destination(buf.as_ptr(), 0, 1).is_null());
    }
}

#[test]
fn create_persistent_destination_garbage_buf_returns_null() {
    unsafe {
        let garbage = [0xAAu8; 64];
        assert!(i2pd_create_persistent_destination(garbage.as_ptr(), garbage.len(), 1).is_null());
    }
}

#[test]
fn generate_keys_null_out_buf_returns_failure() {
    unsafe {
        let mut out_len: usize = 0;
        assert_eq!(i2pd_generate_keys(7, 4, ptr::null_mut(), &mut out_len), 0);
    }
}

#[test]
fn generate_keys_null_out_len_returns_failure() {
    unsafe {
        let mut out_buf: *mut u8 = ptr::null_mut();
        assert_eq!(i2pd_generate_keys(7, 4, &mut out_buf, ptr::null_mut()), 0);
    }
}