summary refs log blame commit diff stats
path: root/src/mock/mod.rs
blob: ed41780f4a585c5ddce1330ee8f23b45bb9250a3 (plain) (tree)



































                                                                            



                                                                 
                    



                             
                               




                  
          
                   

                                               




                               

                                  

 




























                                                                                                                                                                                                        

                              


                              
                                

 



                                                           











                                                                                                                                                        




























                                                                                                                                                            
                                                                                                                         










                                                                              
                                                                                 






                                                                              
                                                                               































































































































































                                                                                                                                                                                                               










                                        
                 
                                                         
                                     




                                            







                                           
                                                              
                                
                                                              































                                           





                                     

                                
















                                                                   


         
// This file is part of Hexchat Plugin API Bindings for Rust
// Copyright (C) 2022 Soni L.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//
// Based on hexchat's plugin.c
//
/* X-Chat
 * Copyright (C) 2002 Peter Zelezny.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

//! Internal mock test framework.
//!
//! This API is not stable. Do not rely on this API to be stable.

use std::cell::Cell;
use std::cell::RefCell;
use std::ffi::CStr;
use std::ffi::CString;
use std::marker::PhantomData;
use std::marker::PhantomPinned;
use std::pin::Pin;
use std::ptr;

use libc::c_char;

#[repr(C)]
struct MockPlugin {
    // NOTE: MUST be first thing in the struct.
    methods: crate::internals::Ph,
    filename: *const c_char,
    plugin_name: *const c_char,
    plugin_desc: *const c_char,
    plugin_vers: *const c_char,
    free_strings: bool,
    env: *const PluginEnvironment,
    _pin: PhantomPinned,
}

enum MockCallback {
    HookCommand {
        help: Option<Box<str>>,
        f: unsafe extern "C" fn(word: *const *const libc::c_char, word_eol: *const *const libc::c_char, user_data: *mut libc::c_void) -> libc::c_int,
    },
    HookServer {
        f: unsafe extern "C" fn(word: *const *const libc::c_char, word_eol: *const *const libc::c_char, user_data: *mut libc::c_void) -> libc::c_int,
    },
    HookServerAttrs {
        f: unsafe extern "C" fn(word: *const *const libc::c_char, word_eol: *const *const libc::c_char, attrs: *const crate::internals::HexchatEventAttrs, user_data: *mut libc::c_void) -> libc::c_int,
    },
    HookPrint {
        f: unsafe extern "C" fn(word: *const *const libc::c_char, user_data: *mut libc::c_void) -> libc::c_int,
    },
    HookPrintAttrs {
        f: unsafe extern "C" fn(word: *const *const libc::c_char, attrs: *const crate::internals::HexchatEventAttrs, user_data: *mut libc::c_void) -> libc::c_int
    },
    HookTimer {
        tag: libc::c_int,
        f: unsafe extern "C" fn(user_data: *mut libc::c_void) -> libc::c_int,
    },
    HookFd {
        tag: libc::c_int,
        f: unsafe extern "C" fn(fd: libc::c_int, flags: libc::c_int, user_data: *mut libc::c_void) -> libc::c_int
    },
    HookDeleted,
}

// This MockHook is deliberately incompatible with hexchat's own hook struct.
struct MockHook<'hook, 'env> {
    pl: &MockPlugin<'env>,
    cb: RefCell<MockCallback>,
    name: Option<Box<str>>,
    pri_or_fd: libc::c_int,
    userdata: *mut libc::c_void,
}

pub struct PluginEnvironment<'env> {
    plugins: Option<Vec<Pin<Box<MockPluginOpaque<'env>>>>>,
    hooks: Option<Vec<Pin<Box<MockHookOpaque<'env>>>>>,
    depth: usize,
}

unsafe extern "C" fn hexchat_hook_command(
    ph: *mut crate::internals::HexchatPlugin,
    name: *const libc::c_char,
    pri: libc::c_int,
    /* CALLBACK */
    callback: unsafe extern "C" fn(word: *const *const libc::c_char, word_eol: *const *const libc::c_char, user_data: *mut libc::c_void) -> libc::c_int,
    help_text: *const libc::c_char,
    userdata: *mut libc::c_void
) -> *const crate::internals::HexchatHook {
    let ph = ph as *mut MockPlugin;
    todo!();
}
unsafe extern "C" fn hexchat_hook_server(ph: *mut crate::internals::HexchatPlugin,
        name: *const libc::c_char,
        pri: libc::c_int,
        /* CALLBACK */
        callback: unsafe extern "C" fn(word: *const *const libc::c_char, word_eol: *const *const libc::c_char, user_data: *mut libc::c_void) -> libc::c_int,
        userdata: *mut libc::c_void) -> *const crate::internals::HexchatHook {
    todo!();
}
unsafe extern "C" fn hexchat_hook_print(ph: *mut crate::internals::HexchatPlugin,
        name: *const libc::c_char,
        pri: libc::c_int,
        /* CALLBACK */
        callback: unsafe extern "C" fn(word: *const *const libc::c_char, user_data: *mut libc::c_void) -> libc::c_int,
        userdata: *mut libc::c_void) -> *const crate::internals::HexchatHook {
    todo!();
}
unsafe extern "C" fn hexchat_hook_timer(ph: *mut crate::internals::HexchatPlugin,
        timeout: libc::c_int,
        /* CALLBACK */
        callback: unsafe extern "C" fn(user_data: *mut libc::c_void) -> libc::c_int,
        userdata: *mut libc::c_void) -> *const crate::internals::HexchatHook {
    todo!();
}
unsafe extern "C" fn hexchat_hook_fd(ph: *mut crate::internals::HexchatPlugin,
        fd: libc::c_int,
        flags: libc::c_int,
        /* CALLBACK */
        callback: unsafe extern "C" fn(fd: libc::c_int, flags: libc::c_int, user_data: *mut libc::c_void) -> libc::c_int,
        userdata: *mut libc::c_void) -> *const crate::internals::HexchatHook {
    todo!();
}
unsafe extern "C" fn hexchat_unhook(ph: *mut crate::internals::HexchatPlugin,
        hook: *const crate::internals::HexchatHook) -> *const libc::c_void {
    todo!();
}
unsafe extern "C" fn hexchat_print(ph: *mut crate::internals::HexchatPlugin,
        text: *const libc::c_char) {
    todo!();
}
pub unsafe extern "C" fn hexchat_printf(ph: *mut crate::internals::HexchatPlugin,
        format: *const libc::c_char, ...) {
    unimplemented!();
}
unsafe extern "C" fn hexchat_command(ph: *mut crate::internals::HexchatPlugin,
        command: *const libc::c_char) {
    todo!();
}
unsafe extern "C" fn hexchat_commandf(ph: *mut crate::internals::HexchatPlugin,
        format: *const libc::c_char, ...) {
    unimplemented!();
}
unsafe extern "C" fn hexchat_nickcmp(ph: *mut crate::internals::HexchatPlugin,
        s1: *const libc::c_char,
        s2: *const libc::c_char) -> libc::c_int {
    todo!();
}
unsafe extern "C" fn hexchat_set_context(ph: *mut crate::internals::HexchatPlugin,
        ctx: *const crate::internals::HexchatContext) -> libc::c_int {
    todo!();
}
unsafe extern "C" fn hexchat_find_context(ph: *mut crate::internals::HexchatPlugin,
        servname: *const libc::c_char,
        channel: *const libc::c_char) -> *const crate::internals::HexchatContext {
    todo!();
}
unsafe extern "C" fn hexchat_get_context(ph: *mut crate::internals::HexchatPlugin) -> *const crate::internals::HexchatContext {
    todo!();
}
unsafe extern "C" fn hexchat_get_info(ph: *mut crate::internals::HexchatPlugin,
        id: *const libc::c_char) -> *const libc::c_char {
    todo!();
}
unsafe extern "C" fn hexchat_get_prefs(ph: *mut crate::internals::HexchatPlugin,
        name: *const libc::c_char,
        string: *mut *const libc::c_char,
        integer: *mut libc::c_int) -> libc::c_int {
    todo!();
}
unsafe extern "C" fn hexchat_list_get(ph: *mut crate::internals::HexchatPlugin,
        name: *const libc::c_char) -> *mut crate::internals::HexchatList {
    todo!();
}
unsafe extern "C" fn hexchat_list_free(ph: *mut crate::internals::HexchatPlugin,
        xlist: *const crate::internals::HexchatList) {
    todo!();
}
unsafe extern "C" fn hexchat_list_fields(ph: *mut crate::internals::HexchatPlugin,
        name: *const libc::c_char) -> *const *const libc::c_char {
    todo!();
}
unsafe extern "C" fn hexchat_list_next(ph: *mut crate::internals::HexchatPlugin,
        xlist: *const crate::internals::HexchatList) -> libc::c_int {
    todo!();
}
unsafe extern "C" fn hexchat_list_str(ph: *mut crate::internals::HexchatPlugin,
        xlist: *const crate::internals::HexchatList,
        name: *const libc::c_char) -> *const libc::c_char {
    todo!();
}
unsafe extern "C" fn hexchat_list_int(ph: *mut crate::internals::HexchatPlugin,
        xlist: *const crate::internals::HexchatList,
        name: *const libc::c_char) -> libc::c_int {
    todo!();
}
unsafe extern "C" fn hexchat_plugingui_add(ph: *mut crate::internals::HexchatPlugin,
        filename: *const libc::c_char,
        name: *const libc::c_char,
        desc: *const libc::c_char,
        version: *const libc::c_char,
        reserved: *mut char) -> *const crate::internals::PluginGuiHandle {
    todo!();
}
unsafe extern "C" fn hexchat_plugingui_remove(ph: *mut crate::internals::HexchatPlugin,
        handle: *const crate::internals::PluginGuiHandle) {
    todo!();
}
unsafe extern "C" fn hexchat_emit_print(ph: *mut crate::internals::HexchatPlugin,
        event_name: *const libc::c_char, ...) -> libc::c_int {
    todo!();
}
unsafe extern "C" fn hexchat_read_fd(ph: *mut crate::internals::HexchatPlugin,
        src: *const libc::c_void,
        buf: *mut char,
        len: *mut libc::c_int) -> libc::c_int {
    todo!();
}
unsafe extern "C" fn hexchat_list_time(ph: *mut crate::internals::HexchatPlugin,
        xlist: *const crate::internals::HexchatList,
        name: *const libc::c_char) -> libc::time_t {
    todo!();
}
unsafe extern "C" fn hexchat_gettext(ph: *mut crate::internals::HexchatPlugin,
        msgid: *const libc::c_char) -> *const libc::c_char {
    todo!();
}
unsafe extern "C" fn hexchat_send_modes(ph: *mut crate::internals::HexchatPlugin,
        targets: *mut *const libc::c_char,
        ntargets: libc::c_int,
        modes_per_line: libc::c_int,
        sign: libc::c_char,
        mode: libc::c_char) {
    todo!();
}
unsafe extern "C" fn hexchat_strip(ph: *mut crate::internals::HexchatPlugin,
        string: *const libc::c_char,
        len: libc::c_int,
        flags: libc::c_int) -> *const libc::c_char {
    todo!();
}
unsafe extern "C" fn hexchat_free(ph: *mut crate::internals::HexchatPlugin,
        ptr: *const libc::c_void) {
    todo!();
}
unsafe extern "C" fn hexchat_pluginpref_set_str(ph: *mut crate::internals::HexchatPlugin,
        var: *const libc::c_char,
        value: *const libc::c_char) -> libc::c_int {
    todo!();
}
unsafe extern "C" fn hexchat_pluginpref_get_str(ph: *mut crate::internals::HexchatPlugin,
        var: *const libc::c_char,
        dest: *mut char) -> libc::c_int {
    todo!();
}
unsafe extern "C" fn hexchat_pluginpref_set_int(ph: *mut crate::internals::HexchatPlugin,
        var: *const libc::c_char,
        value: libc::c_int) -> libc::c_int {
    todo!();
}
unsafe extern "C" fn hexchat_pluginpref_get_int(ph: *mut crate::internals::HexchatPlugin,
        var: *const libc::c_char) -> libc::c_int {
    todo!();
}
unsafe extern "C" fn hexchat_pluginpref_delete(ph: *mut crate::internals::HexchatPlugin,
        var: *const libc::c_char) -> libc::c_int {
    todo!();
}
unsafe extern "C" fn hexchat_pluginpref_list(ph: *mut crate::internals::HexchatPlugin,
        dest: *mut char) -> libc::c_int {
    todo!();
}
unsafe extern "C" fn hexchat_hook_server_attrs(ph: *mut crate::internals::HexchatPlugin,
        name: *const libc::c_char,
        pri: libc::c_int,
        /* CALLBACK */
        callback: unsafe extern "C" fn(word: *const *const libc::c_char, word_eol: *const *const libc::c_char, attrs: *const crate::internals::HexchatEventAttrs, user_data: *mut libc::c_void) -> libc::c_int,
        userdata: *mut libc::c_void) -> *const crate::internals::HexchatHook {
    todo!();
}
unsafe extern "C" fn hexchat_hook_print_attrs(ph: *mut crate::internals::HexchatPlugin,
        name: *const libc::c_char,
        pri: libc::c_int,
        /* CALLBACK */
        callback: unsafe extern "C" fn(word: *const *const libc::c_char, attrs: *const crate::internals::HexchatEventAttrs, user_data: *mut libc::c_void) -> libc::c_int,
        userdata: *mut libc::c_void) -> *const crate::internals::HexchatHook {
    todo!();
}
unsafe extern "C" fn hexchat_emit_print_attrs(ph: *mut crate::internals::HexchatPlugin, attrs: *const crate::internals::HexchatEventAttrs,
        event_name: *const libc::c_char, ...) -> libc::c_int {
    todo!();
}
unsafe extern "C" fn hexchat_event_attrs_create(ph: *mut crate::internals::HexchatPlugin) -> *mut crate::internals::HexchatEventAttrs {
    todo!();
}
unsafe extern "C" fn hexchat_event_attrs_free(ph: *mut crate::internals::HexchatPlugin,
        attrs: *mut crate::internals::HexchatEventAttrs) {
    todo!();
}

impl PluginEnvironment {
    pub fn new() -> Pin<Box<Self>> {
        Box::pin(Self {
            plugins: Default::default(),
            hooks: Default::default(),
            depth: Default::default(),
            _pin: PhantomPinned,
        })
    }
}

impl MockPlugin {
    pub fn new<T: for<'ph> crate::Plugin<'ph> + Default>(
        env: Pin<&PluginEnvironment>,
        filename: CString,
        arg: Option<&CStr>,
    ) -> Option<Pin<Box<MockPlugin>>> {
        let filename = filename.into_raw();
        let mut plug = Box::pin(MockPlugin {
            methods: crate::internals::Ph {
                hexchat_hook_command,
                hexchat_hook_server,
                hexchat_hook_print,
                hexchat_hook_timer,
                hexchat_hook_fd,
                hexchat_unhook,
                hexchat_print,
                userdata: hexchat_printf as *mut libc::c_void,
                hexchat_command,
                hexchat_commandf_do_not_use: hexchat_commandf,
                hexchat_nickcmp,
                hexchat_set_context,
                hexchat_find_context,
                hexchat_get_context,
                hexchat_get_info,
                hexchat_get_prefs,
                hexchat_list_get,
                hexchat_list_free,
                hexchat_list_fields,
                hexchat_list_next,
                hexchat_list_str,
                hexchat_list_int,
                hexchat_plugingui_add,
                hexchat_plugingui_remove,
                hexchat_emit_print,
                hexchat_read_fd,
                hexchat_list_time,
                hexchat_gettext,
                hexchat_send_modes,
                hexchat_strip,
                hexchat_free,
                hexchat_pluginpref_set_str,
                hexchat_pluginpref_get_str,
                hexchat_pluginpref_set_int,
                hexchat_pluginpref_get_int,
                hexchat_pluginpref_delete,
                hexchat_pluginpref_list,
                hexchat_hook_server_attrs,
                hexchat_hook_print_attrs,
                hexchat_emit_print_attrs,
                hexchat_event_attrs_create,
                hexchat_event_attrs_free,
            },
            filename: filename,
            plugin_name: filename,
            plugin_desc: ptr::null(),
            plugin_vers: ptr::null(),
            free_strings: false,
            env: &*env,
            _pin: PhantomPinned,
        });
        if unsafe {
            let ptr: *mut MockPlugin = &mut *plug;
            crate::hexchat_plugin_init::<'_, T>(
                crate::LtPhPtr {
                    ph: ptr as *mut crate::internals::Ph,
                    _lt: PhantomData,
                },
                ptr::addr_of_mut!((*ptr).plugin_name),
                ptr::addr_of_mut!((*ptr).plugin_desc),
                ptr::addr_of_mut!((*ptr).plugin_vers),
                arg.map(|arg| arg.as_ptr()).unwrap_or(ptr::null()),
            ) != 0
        } {
            Some(plug)
        } else {
            None
        }
    }
}